var lastX = 0;
var lastY = 0;
var lastZ = 0;

var lastXdir = 0;
var lastYdir = 0;
var lastZdir = 0;
var dirCounter = 0;

var genMode = false;
var genModeSize = 1;
var genModeType = "cave";

var str = "";
var incaveCanyonCounter = 0;

function modTick()
{
       //clientMessage(random2(-1,1));
}
function newLevel(hasLevel)
{
        ModPE.setItem (500, 6, 12, "cave creator");
        
        if(getTile(1,1,2) == 80){return false;}
        setTile(1,1,2, 80);

        //placeCaveSystemAt(100,  150, 2);
        print("generating caves will take 2 - 5 minutes");
        genCaves();
        genLakes();
        genCanyons();
}

function useItem(x,y,z, itemId, blockId, size){
        if(!genMode){return false;}
        if(itemId == 292)//iron hoe
        {
               if(genModeType == "cave")
               {
                     genCaveSystem2(x,y,z,genModeSize,0);
                }
               if(genModeType == "canyon")
               {
                    //genCaveSystem2(x,y,z,genModeSize,0);
                }
         }
}

function genCaves(){
        var caveNum = random(1, 4);
        var lastX = random(32,216);
        var lastZ = random(32,216) ;
        for(var i = 0; i < caveNum; i = i + 1)
        {
                var x = (lastX + random (72, 160)) % 256;
                var z = (lastZ + random (72, 160)) % 256
                placeCaveSystemAt( random(32,216), random(32,216) , random(2,3));
                lastX = x; lastZ = z;
                print("generated " + (i+1) + "/" + caveNum + " caves");
         }
}

function genCanyons(){
        var caveNum =1;// random(2, 4);
        for(var i = 0; i < caveNum; i = i + 1)
        {
                str = (i+1) + "/" + caveNum;
                placeCanyonAt(random(32, 216), random(32, 216), random(40, 60), random(45, 60), 2.8, 1.8);
                print("generated " + (i+1) + "/" + caveNum + " canyons");
                
         }
}

function genLakes(){
        var caveNum = random(18, 24);
        for(var i = 0; i < caveNum; i = i + 1)
        {
                var id = 9;var y = random(20, 50);
                
                placeLake(random(32, 216), y, random(32, 216), random(1,4), id);
                print("generated " + (i+1) + "/" + caveNum + " lakes");
                
         }
         var caveNum = random(24, 32);
        y = random(10, 12);id = 11;
        for(var i = 0; i < caveNum; i = i + 1)
        {
                
                
                placeLake(random(32, 216), y, random(32, 216), random(1,4), id);
                print("generated " + (i+1) + "/" + caveNum + " lava lakes");
                
         }
}


//Place structures
function placeCaveSystemAt(x, z, size)
{
        var y = 0;
         for(var yg = 80; yg > 0; yg --)
         {
                   if ( getTile(x,yg, z) == 1 ||getTile(x,yg, z) == 2 || getTile(x,yg, z) == 3 || getTile(x,yg, z) == 12 || getTile(x,yg, z) == 13){y = yg;break;}

          }
          if(y == 0){return false;}
          //print(y);
         
          genCaveSystem2(x, y, z, size, 0);
}


function placeCanyonAt(x, z, lenght, height, r1, r2)
{
         var y = 0;
         for(var yg = 80; yg > 0; yg --)
         {
                   if ( getTile(x,yg, z) == 1 ||getTile(x,yg, z) == 2 || getTile(x,yg, z) == 3 || getTile(x,yg, z) == 12 || getTile(x,yg, z) == 13){y = yg;break;}

          }
          if(y == 0){return false;}
          print(y);
          genCanyon(x, y, z , lenght, height, r1, r2 );
}

function placeLake(x,y,z,size,id){
       while(getTile(x,y,z) == 0){
          if(getTile(x,y,z) == id){y += size / 2.5;}
          y--;
       }
       genLake(x,y,z ,size,id);
}
/*
// generate cave systems
function genCaveSystem(x, y, z, size, recNum)
{
         if(size < 1){return false;}
         var ykof = 1-random(-1, 1)*2;
         if(y < 18){ykof = random(-1, 1) *;}
         if(y >  54){ ykof = -1;}
         genCavePassage(x,y,z, random(64, 128), getRandomPassageSize(recNum));
         if(random(0, 4) == 1){genLake( lastX, lastY, lastZ, 2.5, 0);}
         for(var i = 0; i <= random(1,3); i ++){
                genCaveSystem(lastX, lastY, lastZ, size - 1, recNum + 1);
         }
}*/

function genCaveSystem2(x, y, z, size, recNum)
{
         if(size < 1){
               //genLake(x,y,z,2.5, 9);
               return false;
         }
         if(recNum == 0 && random(0, 3) == 1 && incaveCanyonCounter == 0){
               var h = random(15, 20) * 2;
               var sizecanyon = random2(3.5, 5);
               var ycanyon = h / 2 + 10 + sizecanyon/3*2;
               var clenght = random(30, 50);
               str = " in cave system"
               genCanyon(x,ycanyon, z, clenght, h, sizecanyon, sizecanyon/3*2);
               incaveCanyonCounter ++;
         }
         var ykof = 1 - random(-1, 1);
         if(y < 18){ ykof = 1 - random(-1, 1) * 2;}
         if(y >  54){ ykof = -1;}
         if(recNum == 0){
               genCavePassage(x,y,z, random(64, 96), getRandomPassageSize(recNum));
         }
         else{
                updateDir();
                genSmoothPassageWithDir(x,y,z, random(96, 192), getRandomPassageSize(recNum), lastXdir, lastYdir, lastZdir);
                 var xdir = lastXdir;
                 var ydir = lastYdir;
                 var zdir = lastZdir;
                 var counter = dirCounter;
         }
         //if(random(0, 4) == 1){genLake( lastX, lastY, lastZ, 2.5, 0);}
         print("genPassage " + recNum);
         
         for(var i = 0; i <= random(2,3); i ++){
                genCaveSystem2(lastX, lastY, lastZ, size - 1, recNum + 1)
         }
         lastXdir = xdir;
         lastYdir = ydir;
         lastZdir = zdir;
         dirCounter = counter;
}
/*
function genCavePassageSystem(x, y, z, rec, recCounter)
{
    if(rec < 1){return false;}
    
    var forkNum = random(1,3);

    var size = getRandomPassageSize(recCounter);
    var lenght = random(128,192);
    var xdir = 1 - random(-1,1) * 2;
    var ydir = random2(1, 0) * yk;
    var zdir = 1 - random(-1,1) * 2;
    
    for(var i = 0; i < lenght; i = i + 1)
     {
           var rf = (i - lenght - 1) / forkNum;
           if(random(0,  rf) == 1){ genCavePassageSystem(x,y,z,rec - 1, recNum + 1);
forkNum--;}
           if(random(0, 8) == 1)}{
                 ydir += random2(1, 0) * yk;
           }
           if(random(0, 16) == 1)
           {
                 xdir += 1 - random(-1,1) * 2;
                 zdir += 1 - random(-1,1) * 2;
           }
           var xadd = xdir + random(-2, 1);
           var yadd = ydir;
           var zadd = zdir + random(-2, 1);
           
           if(xadd > 1){xadd = 1;}
           if(xadd<-1){xadd=-1;}
           if(yadd > 1){yadd = 1;}
           if(yadd<-1){yadd=-1;}
           if(zadd > 1){zadd = 1;}
           if(zadd<-1){zadd=-1;}

           if(xdir > 1){xdir = 1;}
           if(xdir<-1){xdir=-1;}
           if(ydir > 1){ydir = 1;}
           if(ydir<-1){ydir=-1;}
           if(zdir > 1){zdir = 1;}
           if(zdir<-1){zdir=-1;}

           x = x +  xadd;
           y = y +  yadd;
           z = z +  zadd;

           if(y < 14){return false;}
           genCaveElement(x, y, z, size);
      }
      lastX = x;
      lastY = y;
      lastZ = z;
}
*/
//generate passages
function genCavePassage(x,y,z,l,s){
    var xdir = 1 - random(-1,1) * 2;
    var ydir = getRandomYdirForY(y);
    var zdir = 1 - random(-1,1) * 2;
    genSmoothPassageWithDir(x, y, z, l, s, xdir, ydir, zdir);
}

function genCavePassageWithDir(x, y, z, lenght, size, xdir, ydir, zdir)
{
    for(var i = 0; i < lenght; i = i + 1)
     {
           if(random(0, 8) == 1){
                 ydir = getRandomYdirForY(y);
           }
           if(random(0, 16) == 1)
           {
                 xdir += 1 - random(-1,1) * 2;
                 zdir += 1 - random(-1,1) * 2;
           }
           
           var xadd = xdir + random(-2, 1);
           var yadd = ydir;
           var zadd = zdir + random(-2, 1);
           
           if(xdir > 1){xdir = 1;}
           if(xdir<-1){xdir=-1;}
           if(ydir > 1){ydir = 1;}
           if(ydir<-1){ydir=-1;}
           if(zdir > 1){zdir = 1;}
           if(zdir<-1){zdir=-1;}
           
           if(xadd > 1){xadd = 1;}
           if(xadd<-1){xadd=-1;}
           if(yadd > 1){yadd = 1;}
           if(yadd<-1){yadd=-1;}
           if(zadd > 1){zadd = 1;}
           if(zadd<-1){zadd=-1;}

           x = x +  xadd;
           y = y +  yadd;
           z = z +  zadd;

           if(y < 10 + size){ ydir = getRandomYdirForY(y); }
           genCaveElement(x, y, z, size);
      }
      lastX = x;
      lastY = y;
      lastZ = z;
      
      lastXdir = xdir;
      lastYdir = ydir;
      lastZdir = zdir;
}





function genSmoothPassageWithDir(x, y, z, lenght, size, xadd, yadd, zadd)
{
    
    var xtarget = random2(-1, 1);
    var ytarget = random2(-1, 1);
    var ztarget = random2(-1, 1);
    
    var xspeed = random2(0.01, 0.09);
    var yspeed = random2(0.01, 0.09);
    var zspeed = random2(0.01, 0.09);
    
    for(var i = 0; i < lenght; i = i + 1)
     {
           xadd = addToTarget(xadd, xtarget, xspeed);
           yadd = addToTarget(yadd, ytarget, yspeed);
           zadd = addToTarget(zadd, ztarget, zspeed);
           
           if(xadd == xtarget && i > 10){xtarget = random2(-1,1);xspeed = random2(0.01, 0.09); }
           if(yadd == ytarget && i > 10){ytarget = getRandomYdirForY(y) ;yspeed = random2(0.01, 0.09); }
           if(zadd == ztarget && i > 10){ztarget = random2(-1,1);zspeed = random2(0.01, 0.09); }
           
           if(xadd > 1){xadd = 1;}
           if(xadd<-1){xadd=-1;}
           if(yadd > 1){yadd = 1;}
           if(yadd<-1){yadd=-1;}
           if(zadd > 1){zadd = 1;}
           if(zadd<-1){zadd=-1;}

           x = x +  xadd;
           y = y +  yadd;
           z = z +  zadd;

           genCaveElement(x, y, z, size);
      }
      lastX = x;
      lastY = y;
      lastZ = z;
      
      lastXdir = xtarget;
      lastYdir = ytarget;
      lastZdir = ztarget;

}





// generate underground lake
function genLake(x, y, z, size, id){
     for(var i = 0; i <= size; i ++){
     
     var xdir = 1 - random(-1,1) * 2;
     var zdir = 1 - random(-1,1) * 2;

     for(var k = 0; k < size * 1.5; k = k + 1)
     {
           if(random(0, 16) == 1)
           {
                 xdir = 1 - random(-1,1) * 2;
                 zdir = 1 - random(-1,1) * 2;
           }
           var xadd = xdir + random(-2, 1);
           var zadd = zdir + random(-2, 1);
           
           if(xdir > 1){xdir = 1;}
           if(xdir<-1){xdir=-1;}
           if(zdir > 1){zdir = 1;}
           if(zdir<-1){zdir=-1;}
           
           if(xadd > 1){xadd = 1;}
           if(xadd<-1){xadd=-1;}
           if(zadd > 1){zadd = 1;}
           if(zadd<-1){zadd=-1;}

           x = x +  xadd;
           z = z +  zadd;

           genLakeElement(x, y, z, size, y - size / 2.5, id);
      }
      }
}

//generate cave element
function genCaveElement(x, y, z, size)
{
           for(var xs = x - size; xs <= x + size; xs ++)
           {
            for(var ys = y - size; ys <= y + size; ys ++)
           {
            for(var zs = z - size; zs <= z + size; zs ++)
           {
                     var dis = Math.sqrt(Math.pow(xs - x, 2) + Math.pow(ys - y, 2) + Math.pow(zs - z, 2));
                     if(dis < size && getTile(xs, ys, zs) != 9 && getTile(xs, ys, zs) != 11){
                           setTile(xs, ys, zs, 0);
                     }
            }
            }
            }
}

//generate cave element filled with water
function genLakeElement(x, y, z, size, yw, id)
{
           for(var xs = x - size; xs <= x + size; xs ++)
           {
            for(var ys = y - size; ys <= y + size; ys ++)
           {
            for(var zs = z - size; zs <= z + size; zs ++)
           {
                     var dis = Math.sqrt(Math.pow(xs - x, 2) + Math.pow(ys - y, 2) + Math.pow(zs - z, 2));
                     if(dis < size && getTile(xs, ys, zs) != 9 && getTile(xs, ys, zs) != 11){
                           var Idblock = 0;
                           if(ys <= yw){var Idblock = id;}
                           if(Idblock != 0){setLiquid(xs, ys, zs, Idblock);}
                           else{ setTile(xs, ys, zs, Idblock);}
                     }
            }
            }
            }
}
function genCaveElement(x, y, z, size)
{
           for(var xs = x - size; xs <= x + size; xs ++)
           {
            for(var ys = y - size; ys <= y + size; ys ++)
           {
            for(var zs = z - size; zs <= z + size; zs ++)
           {
                     var dis = Math.sqrt(Math.pow(xs - x, 2) + Math.pow(ys - y, 2) + Math.pow(zs - z, 2));
                     if(dis < size && getTile(xs, ys, zs) != 9 && getTile(xs, ys, zs) != 11){
                           setTile(xs, ys, zs, 0);
                     }
            }
            }
            }
}

//generate cave element without liquid check
function genCanyonElement(x, y, z, size, yw, id)
{
           for(var xs = x - size; xs <= x + size; xs ++)
           {
            for(var ys = y - size; ys <= y + size; ys ++)
           {
            for(var zs = z - size; zs <= z + size; zs ++)
           {
                     var dis = Math.sqrt(Math.pow(xs - x, 2) + Math.pow(ys - y, 2) + Math.pow(zs - z, 2));
                     if(dis < size){
                           setTile(xs, ys, zs, 0);
                     }
            }
            }
            }
}

function setLiquid(x,y,z, id){
           setTile(x,y,z, id);
           if(getTile(x,y-1,z) == 0){setTile(x, y-1,z, 1);}
           if(getTile(x-1,y,z) == 0){setTile(x-1, y,z, 1);}
           if(getTile(x+1,y,z) == 0){setTile(x+1, y,z, 1);}
           if(getTile(x,y,z-1) == 0){setTile(x, y,z-1, 1);}
           if(getTile(x,y,z+1) == 0){setTile(x, y,z+1, 1);}
}

// generate canyon segment
function genCanyonSegment2(x,y,z,r, r2,h)
{
           var rd = (r - r2)/ h * 2;
           for(var yg= 0; yg <= h / 2; yg++){
                   genCanyonElement(x, y + yg, z, r);
                   genCanyonElement(x, y - yg, z, r);
                   r -= rd;
           }
}

//generate canyon size r1 in middle and r2 on bottom.
function genCanyon(x, y, z, lenght, height, r1, r2)
{
       
    var xdir = 1 - random(-1,1) * 2;
    var zdir = 1 - random(-1,1) * 2;
    
    for(var i = 0; i < lenght; i = i + 1)
     {
           if(random(0, 16) == 1)
           {
                 xdir += 1 - random(-1,1) * 2;
                 zdir += 1 - random(-1,1) * 2;
           }
           var xadd = xdir + random(-2, 1);
           var zadd = zdir + random(-2, 1);
           
           if(xadd > 1){xadd = 1;}
           if(xadd<-1){xadd=-1;}
           if(zadd > 1){zadd = 1;}
           if(zadd<-1){zadd=-1;}

           if(xdir > 1){xdir = 1;}
           if(xdir<-1){xdir=-1;}
           if(zdir > 1){zdir = 1;}
           if(zdir<-1){zdir=-1;}

           x = x +  xadd;
           z = z +  zadd;

           if(y < 14){return false;}
           genCanyonSegment2(x, y, z,r1,r2, height);
           print("canyon generation progress: " + parseInt(i / lenght * 100) + "% " + str);
      }
       
}
// returns random integer
function random(num1, num2){
	var start = Math.max(num1, num2);
	var end = Math.min(num1, num2);
	
	end -= start;
	return parseInt(Math.random() * end) + start;
}

//returns random float
function random2(num1, num2){
	var start = Math.max(num1, num2);
	var end = Math.min(num1, num2);
	
	end -= start;
	return Math.random() * end + start;
}

//returns random passage size for recursion num
function getRandomPassageSize(recNum){
   if(random(0, 3) != 1){return 2.4;}
   if(random(-2, recNum - 1) == -1){return 3;}
   return 2;
}


function procCmd(cmd)
{
	var cmd = cmd.split(" ");
   if(cmd[0] == "gen"){
   if(cmd[1] == "cave"){
        if(cmd[2] < 5 && cmd[2] > 0){
             genModeSize = cmd[2];
             genMode = true;
             genModeType = "cave";
             clientMessage("tap on the block with iron hoe to make cave ");
        }
        else{ clientMessage("use /gen cave <size 1-4>");}
   }
   if(cmd[1] == "canyon"){
        if(cmd[2] < 6 && cmd[2] > 1){
             genModeSize = cmd[2];
             genMode = true;
             genModeType = "canyon";
             clientMessage("tap on the block with iron to make canyon");
        }
        else{ clientMessage("use /gen canyon <size 2-5>");}
   }
   if(cmd[1] == "reset"){
        genMode = false;
        genModeSize = 1;
   }
   
   if(cmd[1] == "help"){
        clientMessage("cave mod by ©zheka2304");
        clientMessage("use /gen cave <size 1-4>");
        clientMessage("use /gen canyon <size 2-5>");
        clientMessage("next tap on block with cave creator to make cave/canyon.");
        clientMessage("use /gen reset to reset past commands");
   }
   }
}

// updates direction for advanced cave system generation
function updateDir(){
    var xdir = lastXdir;
    var ydir = lastYdir;
    var zdir = lastZdir;
     
    if(dirCounter == 1){
        lastXdir = zdir;
        lastZdir = xdir;
    }
   
    if(dirCounter == 2){
        lastXdir = -xdir;
        lastZdir = -zdir;
    }
   dirCounter++;
   if(dirCounter > 2){dirCounter = 0;}
} 

function getRandomYdirForY(y){
   if(y > 54){return -1*random2(0.5,1);}
   if(random(0, 3) == 1){return random2(0,0.6);}
   if(y < 30 && y > 12){
      if(random(0, 2) != 1){return random2(0,0.6);}
      else{return random2(0, 1);}
   }
   return random2(-0.7,0.7);
}

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

