
var freeCoordsList = [];


function newLevel(hasLevel){
  //   preInitFreeCoordsList();
//    generateKust(128,64,110);
//    generateBigTree(128,64,128);
 //   generateHugeTree(128,64,142);
   // generateNormalTree(128,64,152);
   // generateRandomBiomeShape(128,128, 64, 64);
   generateJungle();
}

function preInitFreeCoordsList(){
   for(x = 0; x < 256; x++){
   freeCoordsList[x] = [];
   for(z = 0; z < 256; z++){
       freeCoordsList[x][z] = true;
   }
   }
}

function initFreeCoordsList(){
   for(x = 0; x < 256; x++){
   freeCoordsList[x] = [];
   for(z = 0; z < 256; z++){
       if(scanList[x][z][2] != 17 && !snowBiomes[x][z] && !oceanBiomes[x][z] && !desertBiomes[x][z] && !scanList[x][z][0] < 86){freeCoordsList[x][z] = true;}
       else{freeCoordsList[x][z] = false;}
   }
   }
}

function generateJungle(){
   scanWorld();
   calculateForestBiomes();
   fillBiomeLists();
   initFreeCoordsList();
   var xs = 56 + randInt(56);var x = randInt(192) + 32;
   var zs = 56 + randInt(56);var z = randInt(192) + 32;
   biomemap=generateRandomBiomeMap(x,z,xs,zs);
   
   /*
   xg = parseInt(x - xs / 2) + 1;
   print("generating lakes...");
   while(biomemap.hasOwnProperty(xg) || xg < x + xs / 2){ if(!biomemap.hasOwnProperty(xg)){xg++;continue;}
  for(zg=biomemap[xg][0];zg<biomemap[xg][1];zg++)
   {
     if(xg%2==0 && parseInt(zg) %2==0&&randInt(1024)==0 && xg> 0 && xg < 256 && zg>0&& zg<256)
     {
        rand = randInt(100);
        yg = scanList[xg][zg][0];
        if(rand < 30){generateBigLake(xg, yg,zg);}
        else{generateSmallLake(xg,yg,zg);}
     }
   }
   xg++;
   }*/
   
   xg = parseInt(x - xs / 2) + 1;
   print("generating trees...");
   while(biomemap.hasOwnProperty(xg) || xg < x + xs / 2){
  
    if(!biomemap.hasOwnProperty(xg)){xg++;continue;}
  for(zg=biomemap[xg][0];zg<biomemap[xg][1];zg++)
   {
     if(xg%2==0 && parseInt(zg) %2==0&&randInt(3)==0 && xg> 0 && xg < 256 && zg>0&& zg<256)
     {
        rand = randInt(100);
        yg = scanList[xg][zg][0];
        if(rand < 3){generateHugeTree(xg, yg,zg);}
        else if(rand < 7){generateBigTree(xg,yg,zg);}
       else if(rand<40){generateNorm2Tree(xg,yg,zg);}
       else{generateKust(xg,yg,zg);}
     }
   }
   xg++;
   }
}



function generateKust(x,y,z){
     if(!checkFreeRegion(x,z,x, z)){return;}
     genTree(x,y,z, 1, 0, 17, 15, 80, 0, 0, true, 2 + randInt(2), 0, true, 2 + randInt(2));
}

function generateNormalTree(x,y,z){
    genTree(x,y,z, 4 + randInt(3), 0, 17, 15, 100, 2, 0.1, true, 3, 0, true, 3);
}

function generateNorm2Tree(x,y,z){
    if(!checkFreeRegion(x-1,z-1,x + 1, z + 1)){return;}
    h = 6+ randInt(3);
    for(i = 0; i < 4;i+= 2){genTree(x,y,z, h + i, 0, 17, 15, 0, 4 + randInt(2), 0.1, true, 3, 0, true, 3 - i);}
}

function generateBigTree(x,y,z){
    if(!checkFreeRegion(x-1,z-1,x + 1, z + 1)){return;}
    setUnfreeRegion(x,z,x,z);
    genTree(x,y,z, 16 + randInt(8), 0, 17, 15, 80, 5, 0.3, true, 3, -2, true, 2);
}

function generateHugeTree(x,y,z){
    if(!checkFreeRegion(x-1,z-1,x + 2, z + 2)){return;}
    setUnfreeRegion(x,z,x+1,z+1);
    genTree(x,y,z, 32 + randInt(16), 1, 17, 15, 20, 10, 0.1, true, 2, 0, true, 4);
}









function genTree(x,y,z, h,t,id,d, b, bs, bk, l, lt, lb,c,cr){
    if(y + h > 124){h = 125 - y;}
    for(var ys = y; ys < y + h; ys++){
        if(t == 1){ setTile(x,ys,z, id, d); setTile(x + 1,ys,z, id, d); setTile(x,ys,z +1, id, d); setTile(x + 1,ys,z + 1, id, d);}
        else{ setTile(x,ys,z, id, d);}
        
        if(randInt(100) < b && ys >= bs + y){genBranch(x, ys , z, Math.abs((h - bs) / 2 - Math.abs((y + (h - bs) / 2 + bs) - ys)) * bk + 2, id, d, l, lt, lb) ;}
    }
    
    if(c){genCronePart(x,y + h - 1,z,cr,3, 0,d % 4);}
}

function genBranch(x,y,z,l, id, d, ls, lt, lb){
    
    var xa = 1 - randInt(3);
    var za = 0;
    if(xa == 0){za = 1 - randInt(2) * 2;}
    lr = l;
    if(lr < 2){lr = 2;}
    
    for(var i = 1; i < l + 1; i ++){
         setTile(x + xa * i, y, z + za * i, id , d);
         if(randInt(l * 2) == 0 && l > 4){genBranch(x + xa * i,y,z + za * i,(l - i) * 2, id, d, ls, lt, lb);}
         if(ls){genCronePart( x + xa * i, y, z + za * i, l, lt ,lb ,d % 4);}
    }
}

function genCronePart(x,y,z, radius, top, bottom, m){
    for(var ys = y + bottom; ys < y + top; ys++){
         for(var xs = x - radius; xs < x + radius; xs++){
         for(var zs = z - radius; zs < z + radius; zs++){
             r = radius - Math.abs(ys - y);
             dis = Math.sqrt((x-xs)*(x-xs)+(z-zs)*(z-zs));
             if(dis <= r && getTile(xs,ys,zs)== 0)      
             {setTile(xs,ys,zs,18,m);}
         }
         }
    }
}

function setUnfreeRegion(x1, z1, x2, z2){
    for(x = x1; x <= x2; x++){
    for(z = z1; z <= z2; z++){
        if(x > 0 && x < 256 && z > 0 && z < 256) {freeCoordsList[x][z] = false;}
    }
    }
}

function checkFreeRegion(x1,z1,x2,z2){
    for(x = x1; x <= x2; x++){
    for(z = z1; z <= z2; z++){
        if(x < 0 || x > 255 || z < 0 || z > 255){continue;}
        if(!freeCoordsList[x][z]){return false;}
    }
    }
    return true;
}














function generateRandomBiomeMap(x,z, xs, zs){
    var biome = [];
    var randZstart = z - zs / 2 + randInt(zs)
    var lastCol = [randZstart, randZstart];
    var flact1 = -randFloat(1);
    var flactTarget1 = -randFloat(3);
    var flact2 = randFloat(1);
    var flactTarget2 = randFloat(3);
    var xc = parseInt(x - xs / 2)
    while(true){
         col = [parseInt(lastCol[0] + flact1), parseInt(lastCol[1] + flact2)];
         if(col[0] > col[1]){break;}
         
         flact1 = addToTarget(flact1, flactTarget1, 0.2);
         flact2 = addToTarget(flact2, flactTarget2, 0.2);
         if(flact1==flactTarget1){
             if(xc > x || col[0] < z - zs / 2)
             {var flactTarget1=randFloat(3);}
             else{var flactTarget1=-randFloat(3);}
         }
         if(flact2==flactTarget2){
             if(xc > x || col[1] > z + zs / 2)
             {var flactTarget2=-randFloat(3);}
             else{var flactTarget2=randFloat(3);}
         }
         
         xc++;
         biome[xc] = col;
         lastCol = col;
          /*
for(var zt=col[0];zt<col[1];zt++){setTile(xc,127,zt,5)}
*/
    }
    return biome;
}










function randInt(x){
    return parseInt(randFloat(x))
}

function randFloat(x){
    return Math.random() * x;
}
function addToTarget(num, target, speed){
   var add = target - num;
   if(add > speed){add = speed;}
   if(add < -1* speed){add = -1*speed;}
   return num + add;
}
















function generateLakeMap(x,z,s){
    zs = s / 2; xs = zs;
  var biome = [];
    var randZstart = z - zs / 2 + randInt(zs)
    var lastCol = [randZstart, randZstart];
    var flact1 = -randFloat(0.2);
    var flactTarget1 = -randFloat(0.6);
    var flact2 = randFloat(0.2);
    var flactTarget2 = randFloat(0.6);
    var xc = parseInt(x - xs / 2)
    while(true){
         col = [parseInt(lastCol[0] + flact1), parseInt(lastCol[1] + flact2)];
         if(col[0] > col[1]){break;}
         
         flact1 = addToTarget(flact1, flactTarget1, 0.2);
         flact2 = addToTarget(flact2, flactTarget2, 0.2);
         if(flact1==flactTarget1){
             if(xc > x || col[0] < z - zs / 2)
             {var flactTarget1=randFloat(3);}
             else{var flactTarget1=-randFloat(0.6);}
         }
         if(flact2==flactTarget2){
             if(xc > x || col[1] > z + zs / 2)
             {var flactTarget2=-randFloat(3);}
             else{var flactTarget2=randFloat(0.6);}
         }
         
         xc++;
         biome[xc] = col;
         lastCol = col;
          /*
for(var zt=col[0];zt<col[1];zt++){setTile(xc,127,zt,5)}
*/
    }
    return biome;
}

function generateLake(x,y,z,size,depth){
//generateLakeSegment(x,y,z,5,3)
   segmentsize = 5;
   var map = generateLakeMap(x,z,size);print(map);
   xg = parseInt(x - size / 2) + 1;
   while(map.hasOwnProperty(xg) || xg < x +size / 2){ if(!map.hasOwnProperty(xg)){xg++;continue;}
  for(zg=map[xg][0];zg<map[xg][1];zg++)
   { generateLakeSegment(xg,y,zg,segmentsize,depth - randInt(4))
// setTile(xg,y,zg,12);
   }
   xg++;
   }
}

function generateLakeSegment(x,y,z, size,depth){
   waterlevel = y;
   w = 2;
   for(xs = x - size - w -1; xs < x + size + w + 1; xs++){
   for(zs = z - size - w -1; zs < z + size + w + 1; zs++){
       if(xs > 255 || xs < 0 || zs > 255 || zs < 0){continue;}
       
       dis = Math.sqrt((x-xs)*(x-xs)+(z-zs)*(z-zs));
       if(dis > size + w){continue;}
       freeCoordsList[xs][zs] = false;
       bottom = y;
       for(ys = y; ys >= y - depth;ys--){
           xd = size - depth;
           
        dis2=Math.sqrt((xd-dis)*(xd-dis)+(y-ys)*(y-ys))
           if(dis2 > depth && dis > xd){continue;}
           
           if(ys > waterlevel && !( getTile (xs,ys,zs) == 9 || getTile (xs,ys,zs) == 8 ))     
           {setTile(xs,ys,zs,0);}
           else{setTile(xs,ys,zs,9);}
           bottom = ys;
       }
       for(ys = bottom; ys >= bottom - 2 - randInt(3);ys--){if(! (getTile (xs,ys,zs) == 9 || getTile (xs,ys,zs) == 8)){setTile(xs, ys, zs, 12);}}
   }
   }
}


function generateSmallLake(x,y,z){
    generateLakeSegment(x,y,z, 5 + randInt(5), 3 + randInt(3));
}

function generateBigLake(x,y,z){
    generateLake(x,y,z, 10 + randInt(10),3+randInt(4));
}


















////////////WORLD SCANER CODES///////_/

var scanList = [];
var biomeList = [];

var snowBiomes = [];
var hillBiomes = [];
var oceanBiomes = [];
var desertBiomes = [];
var plainsBiomes = [];
var forestBiomes = [];


function useItem(x,y,z,id,b,s){
    //clientMessage(scanList[x][z]);
    // clientMessage(" snow - " + snowBiomes[x][z] + " hill - " + hillBiomes[x][z] + " ocean - " + oceanBiomes[x][z] + " desert - " + desertBiomes[x][z] + " forest- " + forestBiomes[x][z] + " plains - " + plainsBiomes[x][z] );
   // print(getBiome(x,z));
    //setTile(x,y,z,106,2);
   if(id == 276){generateLake(x,y,z, 20,3);}
}









function scanBlock(x,z){
     var y = 70;
     var block = getTile(x,y,z);
     var lterrainb = (block == 1 || block == 2 || block == 3 || block == 8 || block == 9 || block == 12 || block == 13 || block == 82 || block == 24 || block == 14 || block == 15 || block == 16 || block == 56 || block == 73 || block == 74 || block == 21 );
     while(true){
          var block = getTile(x,y,z);
          var terrainb = (block == 1 || block == 2 || block == 3 || block == 8 || block == 9 || block == 12 || block == 13 || block == 82 || block == 24 || block == 14 || block == 15 || block == 16 || block == 56 || block == 73 || block == 74 || block == 21 );
          
          if(terrainb != lterrainb){
               return [y,block,getTile(x,y+1,z)];
          }
          if(lterrainb){y++;}
          else{y--;}
          
      }
}

function scanWorld(){
    var lprc = 0;
    for(var x = 0; x < 256; x++){
    for(var z = 0; z < 256; z++){
        if(!scanList.hasOwnProperty(x)){scanList[x] =[];}
        scanList[x][z] = scanBlock(x,z);
        prc = parseInt(((x * 256 + z)/65356) * 10);
        if(prc != lprc){print(prc * 10 + "%"); lprc = prc;}
    }
    }
}









function fillBiomeLists(){
    print("calculating biomes...");
    for(var x = 0; x < 256; x++){
    for(var z = 0; z < 256; z++){
        var data = scanList[x][z];
        var y = data[0];
        var block = data[1];
        var upper = data[2];
if(!hillBiomes.hasOwnProperty(x)){hillBiomes[x]=[];}
if(!snowBiomes.hasOwnProperty(x)){snowBiomes[x]=[];}
if(!desertBiomes.hasOwnProperty(x)){desertBiomes[x]=[];}
if(!oceanBiomes.hasOwnProperty(x)){oceanBiomes[x]=[];}
if(!plainsBiomes.hasOwnProperty(x)){plainsBiomes[x] = [];}
        
        if(y > 80){hillBiomes[x][z] = true;}
        else{hillBiomes[x][z] = false;}
        if(upper==79||upper==78){snowBiomes[x][z] = true;}
        else{snowBiomes[x][z] = false;}
        if(block == 12){desertBiomes[x][z] = true;}
        else{desertBiomes[x][z] = false;}
        if(block == 8 || block==9){oceanBiomes[x][z] = true;}
        else{oceanBiomes[x][z] = false;}
        if(x%16==0&&z%16==0){setForestBiomes(x, z);}
        if(!forestBiomes[x][z] && !desertBiomes[x][z] && !oceanBiomes[x][z] && !hillBiomes[x][z] ){plainsBiomes[x][z] = true;}
        else{plainsBiomes[x][z] = false;}
    }
    }
}


function setForestBiomes(x,z){
   
}

function calculateForestBiomes(){
    print("calculating forest biomes...");
    var lastTreeZ = -1;
    for(var x = 0; x < 256; x++){
    lastTreeZ = -1;
    for(var z = 0; z < 256; z++){
        var data = scanList[x][z];
        var y = data[0];
        var block = data[1];
        var upper = data[2];
        if(!forestBiomes.hasOwnProperty(x)) 
        {forestBiomes[x] = [];}
        if(!forestBiomes[x].hasOwnProperty(z)) 
        {forestBiomes[x][z] = false;}
        
        if(scanForestPart(x,z)){
            if(lastTreeZ + 16 >= z){zs = lastTreeZ;ze=z+3;}
            else{zs = z - 3; ze = z + 3;}
            for(var zc = zs ; zc < ze; zc++){
                 for(var xc = x - 3; xc < x + 3; xc++){
                    if(!forestBiomes.hasOwnProperty(xc))
                    {forestBiomes[xc]=[];}
                    forestBiomes[xc][zc] = true;
                 }
            }
            lastTreeZ = z;
        }
   }
   }
}
function scanForestPart(x,z){
   for(var xc = x - 3;xc < x + 3; xc++){
       if(xc < 0 || xc > 255){continue;}
       if(scanList[xc][z][2] == 17){return true;}
   }
   return false;
}



function getBiome(x, z){
   isForest = forestBiomes[x][z];
   isHills = hillBiomes[x][z];
   isDesert = desertBiomes[x][z];
   isSnow = snowBiomes[x][z];
   isOcean = oceanBiomes[x][z];
   isPlains = plainsBiomes[x][z];
   biome = "";
   
   if(isOcean){
      if(isSnow){return "frozen ocean";}
      else{return "ocean";}
   }
   
   if(isForest){
      if(isSnow){biome = "taiga";}
      else{biome = "forest";}
   }
   
   if(isSnow && biome == ""){
      biome = "snow ";
   }
   
   if(isPlains){
     biome += "plains";
   }

   if(isDesert){
     biome += "desert";
   }
   
   if(isHills){
     biome += " hills";
   }
   
   if(biome == " hills"){
     biome = "extrime hills";
   }
   
   if(biome == "snow  hills"){
     biome = "snow hills";
   }
   
   return biome;
}

