/****************************************************************
 ******                 LV Level Generator                 ******
 ******                    Version 1.0                     ******
 ******                   July 08, 2007                    ******
 ****************************************************************
 ******  The one, single reason I chose to write this in   ******
 ******  Javascript, rather than PHP or a compiled lang-   ******
 ******  uage, is that anyone can open up JS code in       ******
 ******  notepad, write a function, and run it in a web    ******
 ******  browser. I'm not trying to say I picked JS so I   ******
 ******  could write it more easily. What I'm saying is    ******
 ******  that I chose Javascript so -you- could write      ******
 ******  more easily. No matter how well I think I know N  ******
 ******  levels, there's no way I could ever please        ******
 ******  everybody by myself. So I've tried to make this   ******
 ******  generator as easy to mod as possible. Basically,  ******
 ******  you can code a function (read: copy/paste, then   ******
 ******  edit a function), tell the program it's there,    ******
 ******  and begin using it right away. I imagine tile     ******
 ******  code files specifically aimed at making jumper    ******
 ******  puzzles, object sets aimed at doing survival      ******
 ******  maps, so on and so on. I have included 23 func-   ******
 ******  tions (some tile, some object) that work for      ******
 ******  all-around action maps, with kind of an avant     ******
 ******  garde feel. In any case, they should be a good    ******
 ******  starting point if you choose to add to the gene-  ******
 ******  rator library. Even if you don't, enjoy the       ******
 ******  outputs, and thank you for reading.               ******
 ******                               -LittleViking        ******
 ****************************************************************/




/*************************************
 *****      Global Defines       *****
 *************************************/

	var arrayTiles = new Array();		// Stores the 31*23 tile array (30*22 when 0-indexed)

	var arrayTileTypes = new Array();	// Stores the tile functions. This is defined in N_Tiles.js

	var arrayTileProb = new Array();	// Stores the probability of each tile function. Defined here, and
						// the probabilities are defined in N_Tiles, in each indiv. function

	var arrayObjects = new Array();		// Stores the objects. Objects are added when they are created.

	var arrayObjTypes = new Array();	// Stored the different object functions. Defined in N_Objects.js

	var arrayObjProb = new Array();		// Stores probabilities. Defined here, probabilities are in obj. functions

	var arrayTileGroups = [['2','3','4','5'],['6','7','8','9'],[':',';','<','='],['>','?','@','A'],
		['B','C','D','E'],['F','G','H','I'],['J','K','L','M'],['N','O','P','Q']];
						// http://i5.photobucket.com/albums/y187/littleviking001/tilenumbers.gif
						// Each group of 4 is a WASD set of one tile shape.

	var tileGroup;				// This picks which group of tiles in arrayTileGroups to use.
						// Only one group is used per map in the LV 1.0 Default release.

	var decoration;				// This decides how likely tile forms are to have decorative tiles added.
						// Decorative tiles are rounded corners, shapes on the ends of lines, etc.

	var objOpenness;			// High numbers mean crowded objects, low numbers mean less objects.

	var tileOpenness;			// High numbers mean more tile functions are used and the map is more filled.

	var tempFuncChoice;
	var tempFuncChoose;
	var presetTiles;


/*************************************
 *****      Main Functions       *****
 *************************************/

function buildMap(arg1) {
  arrayTileTypes = new Array();
  arrayTileProb = new Array();
  arrayObjTypes = new Array();
  arrayObjProb = new Array();
		// Main function. This is what the HTML page calls. It steps through the whole program.


        for ( keyVar in arrayTileTypes_predefined ) {
          tempFuncChoose = arrayTileTypes_predefined[keyVar];
          tempFuncChoice = document.forms["main_form"].elements["tile_" + tempFuncChoose].checked;
          if(tempFuncChoice == true) {
            arrayTileTypes.push(tempFuncChoose);
          }
        }


        for ( keyVar in arrayObjTypes_predefined ) {
          tempFuncChoose = arrayObjTypes_predefined[keyVar];
          tempFuncChoice = document.forms["main_form"].elements["obj_" + tempFuncChoose].checked;
          if(tempFuncChoice == true) {
            arrayObjTypes.push(tempFuncChoose);
          }
        }

	setVars();
	if(arrayTileTypes.length > 0 && arg1 != 2) {
	  buildTiles();
	} else if(arg1 == 2) {
          var countVar = -1;
          presetTiles = document.forms["main_form"].elements["output"].value;
          presetTiles = presetTiles.substring(0,713);
          for (var i=0;i<=30;i++) {
            for (var j=0;j<=22;j++) {
              countVar++;
              arrayTiles[i][j] = presetTiles[countVar];
            }
          }          
        }

        if(arrayObjTypes.length > 0) {
  	  buildObjects();
        }
	output(arg1);
}


function setVars() {
		// Set the variable values for this particular map.

	popArrayTiles();				// Fill with tile array with zeros and clear the object array
	arrayObjects = new Array();

	popObjProb();					// Populate object and tile probability arrays
	popTileProb();

	tileGroup = Math.floor(Math.random()*8);
	decoration = 1-(Math.random()*Math.random());	// Squared random means lower numbers (0.25 avg), so tiles have 
							// about a 75% chance of being decorated. (0.75 out of 1.0)
	tileOpenness = Math.ceil(Math.random()*12)+4;	// Random number of tile forms from 5-16
	objOpenness = Math.ceil(Math.random()*18)+6;	// Random number of objects from 7-24
}


function popArrayTiles() {
		// Two-dimensional for-loop fills the tile array with zeros.

	for (i=0;i<=30;i++) {

	arrayTiles[i] = new Array();

		for (j=0;j<=22;j++) {
			arrayTiles[i][j] = 0;
		}
	}
}


function popObjProb() {
		// The probability of each object function is called, and the function's name is added to the prob array
		// a number of times equal to its probability. So an object with 20 probability is more likely to be
		// pulled out than an object with 10 entries.

	for (var i=arrayObjTypes.length-1;i>=0;i--) {

		var objType = arrayObjTypes[i];

		var activeObj = eval("new "+objType+"()");	// eval() turns a string into a function. "new mine()" etc

		for (var j=activeObj.Prob();j>0;j--) {

			arrayObjProb.push(objType);
		}
	}
}


function popTileProb() {
		// Same as above but with tiles

	for (var i=arrayTileTypes.length-1;i>=0;i--) {

		var tileType = arrayTileTypes[i];

		var activeTile = eval("new "+tileType+"()");

		for (var j=activeTile.Prob();j>0;j--) {

			arrayTileProb.push(tileType);
		}
	}
}


/*************************************
 *****       Tile Functions      *****
 *************************************/

function buildTiles() {
		// Tile functions are called a number of times equal to tileOpenness, then the outer corners
		// function (since it never needs to be called more than once).

	for (;tileOpenness>0;tileOpenness--) {

		var activeTile = eval("new "+tilePick()+"()");
		activeTile.Create();
	}

	activeTile = new outerCorners();
	activeTile.Create();

}


function tilePick() {
		// Picks a tile from the probability array

	var iTile = Math.floor(Math.random()*arrayTileProb.length);
	return arrayTileProb[iTile];

}


/*************************************
 *****     Object Functions      *****
 *************************************/

function buildObjects() {
		// Object functions are called a number of times equal to objOpenness, with the ninja and exit door
		// functions called outside (since they never need to be called more than once).

        if(arrayObjTypes.length > 0) {
  	  activeObj = new ninja();
	  activeObj.Create();
        }

	for (;objOpenness>0;objOpenness--) {

		var activeObj = eval("new "+objPick()+"()");
		activeObj.Create();

	}

        if(arrayObjTypes.length > 0) {
	  activeObj = new exit();
  	  activeObj.Create();
        }

}


function objPick() {
		// Picks an object from the probability array

	var iObj = Math.floor(Math.random()*arrayObjProb.length);
	return arrayObjProb[iObj];
}


function tileToObjXY(location,quarter) {
		// Convert from a tile coordinate (the 31x23 grid) to the object grid.
		// Quarter defines how many quarter-snaps in from the top/left it is (0-3).

	var objCoor = 24 + location*24 + quarter*6;
	return objCoor;
}


/*************************************
 *****     Output Functions      *****
 *************************************/

function output(arg1) {
		// Tiles are added to a buffer, then objects, then it's all output to the HTML form textbox


      	var buffer = '';

        for (var i=0;i<=30;i++) {
        	for (var j=0;j<=22;j++) {
        		buffer += arrayTiles[i][j];
        	}
        }
	buffer += '|';

	buffer += arrayObjects.join("!");

	outputBox = document.getElementById("output");
	//outputBox.setAttribute("value",buffer);
	outputBox.value = buffer;

	document.getElementById("ref1").style.display = 'block';
}

function generatePreview() {
  document.getElementById("map_preview").src = 'quickrender.php?output=' + document.forms["main_form"].elements["output"].value;
  document.getElementById("ref2").style.display = "block";
}

/*************************************
 *****     Misc Functions        *****
 *************************************/
 
function invCheck(type) {
  if(type == 1) {
    var prefix = "tile_";
    var arrayUsed = arrayTileTypes_predefined;
  } else if(type == 2) {
    var prefix = "obj_";
    var arrayUsed = arrayObjTypes_predefined;
  }
  for ( keyVar in arrayUsed ) {
    tempFuncChoose = arrayUsed[keyVar];
    if(document.forms["main_form"].elements[prefix + tempFuncChoose].checked == true) {
      document.forms["main_form"].elements[prefix  + tempFuncChoose].checked = false;
    } else {
      document.forms["main_form"].elements[prefix  + tempFuncChoose].checked = true;
    }
  }
  updateKey();
}

function updateKey() {
  var keybuffer = '';
  for(i = 1;i <= 2;i++) {
    if(i == 1) {
      var prefix = "tile_";
      var arrayUsed = arrayTileTypes_predefined;
    } else if(i == 2) {
      var prefix = "obj_";
      var arrayUsed = arrayObjTypes_predefined;
    }
    for ( keyVar in arrayUsed ) {
      tempFuncChoose = arrayUsed[keyVar];
      if(document.forms["main_form"].elements[prefix + tempFuncChoose].checked == true) {
        keybuffer = keybuffer + '1';
      } else {
        keybuffer = keybuffer + '0';
      }
    }
  }
  document.getElementById('keyref').value = keybuffer;
  if(document.URL.indexOf('?') == -1) {
    var url = document.URL.length;
  } else {
    var url = document.URL.indexOf('?');
  }
  url = document.URL.substring(0, url);
  document.getElementById('keylink').href = url + '?key=' + keybuffer;
}

function loadKey(keybuffer) {
  //Mostly rehashing the above to start.
  var object_reference = new Array();
  var k = -1;
  for(i = 1;i <= 2;i++) {
    if(i == 1) {
      var prefix = "tile_";
      var arrayUsed = arrayTileTypes_predefined;
    } else if(i == 2) {
      var prefix = "obj_";
      var arrayUsed = arrayObjTypes_predefined;
    }
    for ( keyVar in arrayUsed ) {
      tempFuncChoose = arrayUsed[keyVar];
      k = k + 1;
      object_reference[k] = document.forms["main_form"].elements[prefix + tempFuncChoose];
    }
  }
  stringLength = keybuffer.length - 1;
  for(i = 0; i <= stringLength; i++) {
    if(keybuffer[i] == 1) {
      object_reference[i].checked = true;
    } else {
      object_reference[i].checked = false;
    }
  }
}

function pageLoad() {
  //Code from http://www.codeave.com/javascript/code.asp?u_log=7046 and some other place.
  // Create variable is_input to see if there is a ? in the url
  var is_input = document.URL.indexOf('?');

  // Check the position of the ? in the url
  if (is_input != -1) {
    // Create variable from ? in the url to the end of the string
    addr_str = document.URL.substring(is_input+1, document.URL.length);
    
    var list2 = addr_str.split ("=");
    //split at "=";
    list2[0] = list2[1];
    
    if(list2[0].length == 24) {
      document.forms["key_form"].elements["keyref"].value = list2[0];
      loadKey(list2[0]);
    } else {
      updateKey();
    }


  } else {
    updateKey();
  }
}
