Code viewer for World: Super Mario Maze
/* Aim ofr the game is to rescue the princess before time runs out, while also avoiding touching the goombas.
You will lose the game if you touch the goombas or run out of time.
The controls are the arrowpad to move and space to jump. Mario can not jump over the walls, but can jump over the individual blocks.
Jump on the goombas to kill them.*/


// World must define these:
 
const	 	CLOCKTICK 	= 100;					// speed of run - move things every n milliseconds
const		MAXSTEPS 	= 400;					// length of a run before final score

const  SCREENSHOT_STEP = 50;    


//---- global constants: -------------------------------------------------------

const gridsize = 20;						// number of squares along side of world	   

const squaresize = 100;					// size of square in pixels
const MAXPOS = gridsize * squaresize;		// length of one side in pixels 
	
const SKYCOLOR 	= 0xddffdd;				// a number, not a string 
const BLANKCOLOR 	= SKYCOLOR ;			// make objects this color until texture arrives (from asynchronous file read)

const  LIGHTCOLOR 	= 0xffffff ;


const show3d = true;						// Switch between 3d and 2d view (both using Three.js) 
 
const startRadiusConst	 	= MAXPOS * 0.8 ;		// distance from centre to start the camera at
const skyboxConst			= MAXPOS * 3 ;		// where to put skybox 
const maxRadiusConst 		= MAXPOS * 10  ;		// maximum distance from camera we will render things  





//--- Mind can pick one of these actions -----------------

const ACTION_LEFT 		= 0;		   
const ACTION_RIGHT 		= 1;
const ACTION_UP 			= 2;		 
const ACTION_DOWN 		= 3;
const ACTION_JUMP       = 5;

// in initial view, (smaller-larger) on i axis is aligned with (left-right)
// in initial view, (smaller-larger) on j axis is aligned with (away from you - towards you)



// contents of a grid square

const GRID_BLANK 	= 0;
const GRID_WALL 	= 1;
const GRID_MAZE 	= 2;
 
 




 
// --- some useful random functions  -------------------------------------------


function randomfloatAtoB ( A, B )			 
{
 return ( A + ( Math.random() * (B-A) ) );
}

function randomintAtoB ( A, B )			 
{
 return  ( Math.round ( randomfloatAtoB ( A, B ) ) );
}
  
function randomBoolean()			 
{
 if ( Math.random() < 0.5 ) { return false; }
 else { return true; }
}



function randomPick ( a, b )
{
 if ( randomBoolean() ) 
  return a;
 else
  return b;
}



//---- start of World class -------------------------------------------------------
 
function World() { 


// most of World can be private 
// regular "var" syntax means private variables:


var BOXHEIGHT;		// 3d or 2d box height 


var GRID 	= new Array(gridsize);			// can query GRID about whether squares are occupied, will in fact be initialised as a 2D array   
var FLOORGRID = new Array(gridsize);        // Floor
var WALLS 	= new Array ( 4 * gridsize );   // need to keep handles to wall and maze objects so can find them later to paint them 
var FLOORS   = new Array(gridsize);
var MAZE 	= new Array ( 1 );
//noboxes
var theagent, theenemy, theflag;

// enemies, agent, flag position on squares
var ei, ej, ai, aj, fi, fj, ei2, ej2;
var ya =  0;
//booleans for jump method
var inJump = false;
var jumpMar = true;
var moveMar = false;
var landMar = false;

var  step;

var self = this;				

 

//creating grid of squares
function initGrid()
{
 for (var i = 0; i < gridsize ; i++) 
 {
  GRID[i] = new Array(gridsize);		// each element is an array 

  for (var j = 0; j < gridsize ; j++) 
  {
   GRID[i][j] = GRID_BLANK ;
  }
 }
}

//Another grid for the floor of the maze
function initGrid2()
{
 for (var i = 0; i < gridsize ; i++) 
 {
  FLOORGRID[i] = new Array(gridsize);		// each element is an array 

  for (var j = 0; j < gridsize ; j++) 
  {
   FLOORGRID[i][j] = GRID_BLANK ;
  }
 }
}

//check is the square occupied
function occupied ( i, j )		// is this square occupied
{
 if ( ( ei == i ) && ( ej == j ) ) return true;		// variable objects 
 if ( ( ei2 == i ) && ( ej2 == j ) ) return true;	
 if ( ( ai == i ) && ( aj == j ) ) return true;

 if ( GRID[i][j] == GRID_WALL ) return true;		// fixed objects	 
 if ( GRID[i][j] == GRID_MAZE ) return true;		 
	 
 return false;
}

//check is the square occupied with an enemy
function occupiedEnemy ( i, j )	
{
 if ( ( ei == i ) && ( ej == j ) ) return true;	 
 if ( ( ei2 == i ) && ( ej2 == j ) ) return true;		 
 return false;
}

//check is the square occupied with the flag
function occupiedFlag ( i, j )	
{
 if ( ( fi == i ) && ( fj == j ) ) return true;	 
	 
 return false;
}

 


function translate ( x ) 
{
 return ( x - ( MAXPOS/2 ) );
}





//--- skybox ----------------------------------------------------------------------------------------------


function initSkybox() 
{
  var materialArray = [
 	( new THREE.MeshBasicMaterial ( { map: THREE.ImageUtils.loadTexture( "/uploads/cathaln/mario-background.png" ), side: THREE.BackSide } ) ),
 	( new THREE.MeshBasicMaterial ( { map: THREE.ImageUtils.loadTexture( "/uploads/cathaln/mario-background.png" ), side: THREE.BackSide } ) ),
 	( new THREE.MeshBasicMaterial ( { map: THREE.ImageUtils.loadTexture( "/uploads/cathaln/mario-background.png" ), side: THREE.BackSide } ) ),
 	( new THREE.MeshBasicMaterial ( { map: THREE.ImageUtils.loadTexture( "/uploads/cathaln/mario-background.png" ), side: THREE.BackSide } ) ),
 	( new THREE.MeshBasicMaterial ( { map: THREE.ImageUtils.loadTexture( "/uploads/cathaln/mario-background.png" ), side: THREE.BackSide } ) ),
 	( new THREE.MeshBasicMaterial ( { map: THREE.ImageUtils.loadTexture( "/uploads/cathaln/mario-background.png" ), side: THREE.BackSide } ) )
 	];

  var skyGeometry = new THREE.CubeGeometry ( skyboxConst, skyboxConst, skyboxConst );	
  var skyMaterial = new THREE.MeshFaceMaterial ( materialArray );
  var theskybox = new THREE.Mesh ( skyGeometry, skyMaterial );
  threeworld.scene.add( theskybox );				
}



function loadTextures()
{
    //object and mtl for mario
    var m = new THREE.MTLLoader();
    	m.setTexturePath ( "/uploads/cathaln/" );
    	m.setPath( "/uploads/cathaln/" );
    	m.load( "mario.mtl", function( materials ) {
     
    		materials.preload();
    		var o = new THREE.OBJLoader();
    		o.setMaterials ( materials );
    		o.setPath ( "/uploads/cathaln/" );
    		o.load( "mario.obj", function ( object ) {
    			object.scale.multiplyScalar ( 20 );    	   
	            theagent = object;
	            threeworld.scene.add( theagent );
    		} );
    	} );
    	
    	//object and materials for goombas
    	var n = new THREE.MTLLoader();
    	n.setTexturePath ( "/uploads/cathaln/" );
    	n.setPath( "/uploads/cathaln/" );
    	n.load( "goomba.mtl", function( materials ) {
     
    		materials.preload();
    		var o2 = new THREE.OBJLoader();
    		o2.setMaterials ( materials );
    		o2.setPath ( "/uploads/cathaln/" );
    		o2.load( "goomba.obj", function ( object ) {
    			object.scale.multiplyScalar ( 1.3 );    	   
	            theenemy = object;
	            threeworld.scene.add( theenemy );
    		} );
    	} );
    	
    	var n2 = new THREE.MTLLoader();
    	n2.setTexturePath ( "/uploads/cathaln/" );
    	n2.setPath( "/uploads/cathaln/" );
    	n2.load( "goomba.mtl", function( materials ) {
     
    		materials.preload();
    		var o22 = new THREE.OBJLoader();
    		o22.setMaterials ( materials );
    		o22.setPath ( "/uploads/cathaln/" );
    		o22.load( "goomba.obj", function ( object ) {
    			object.scale.multiplyScalar ( 1.3 );    	   
	            theenemy2 = object;
	            threeworld.scene.add( theenemy2 );
    		} );
    	} );
    	
    	//object and materials for princess 
	    var f = new THREE.MTLLoader();
    	f.setTexturePath ( "/uploads/cathaln/" );
    	f.setPath( "/uploads/cathaln/" );
    	f.load( "princesspeach.mtl", function( materials ) {
     
    		materials.preload();
    		var of = new THREE.OBJLoader();
    		of.setMaterials ( materials );
    		of.setPath ( "/uploads/cathaln/" );
    		of.load( "princesspeach.obj", function ( object ) {
    			object.scale.multiplyScalar ( 4 );    	   
	            theflag = object;
	            threeworld.scene.add( theflag );
    		} );
    	} );
        
        //materials for floor, maze, walls
         var loader1 = new THREE.TextureLoader();
         loader1.load ( '/uploads/cathaln/floor.jpg',		function ( thetexture ) {			 
        		thetexture.minFilter = THREE.LinearFilter;
        		paintWalls ( new THREE.MeshBasicMaterial( { map: thetexture } ) );
        	} ); 
        
         var loader2 = new THREE.TextureLoader();
         loader2.load ( '/uploads/cathaln/question.jpg',		function ( thetexture ) {			 
        		thetexture.minFilter = THREE.LinearFilter;
        		paintMaze ( new THREE.MeshBasicMaterial( { map: thetexture } ) );
         	} ); 
        
        	var loader5 = new THREE.TextureLoader();
         loader5.load ( '/uploads/cathaln/grass2.jpg',		function ( thetexture ) {			 
        		thetexture.minFilter = THREE.LinearFilter;
        		paintFloor ( new THREE.MeshBasicMaterial( { map: thetexture } ) );
        	} ); 

	

}

 


// --- add fixed objects ---------------------------------------- 
   
 
function initLogicalWalls()		// set up logical walls in data structure
{
 for (var i = 0; i < gridsize ; i++) 
  for (var j = 0; j < gridsize ; j++) 
   if ( ( i==0 ) || ( i==gridsize-1 ) || ( j==0 ) || ( j==gridsize-1 ) )
   {
    	GRID[i][j] = GRID_WALL ;		 
   }
}


function initThreeWalls()		// graphical run only, set up blank boxes, painted later 	
{
 var t = 0;
 for (var i = 0; i < gridsize ; i++) 
  for (var j = 0; j < gridsize ; j++) 
   if ( GRID[i][j] == GRID_WALL )
   {
 	 var shape    = new THREE.BoxGeometry( squaresize, BOXHEIGHT, squaresize );			 
 	 var thecube  = new THREE.Mesh( shape );
	 thecube.material.color.setHex( BLANKCOLOR  );			  
 
    	 thecube.position.x = translate ( i * squaresize );   		// translate my simple (i,j) block-numbering coordinates to three.js (x,y,z) coordinates 
    	 thecube.position.z = translate ( j * squaresize );   	
    	 thecube.position.y =  0;	
 
 	 threeworld.scene.add(thecube);
	 WALLS[t] = thecube;				// save it for later
	 t++; 
   }
}

//paint walls of maze
function paintWalls ( material )		 
{
 for ( var i = 0; i < WALLS.length; i++ )
 { 
   if ( WALLS[i] )  WALLS[i].material = material;
 }
}


function initFloor()		// set up logical floor in data structure
{
 for (var i = 0; i < gridsize ; i++) 
  for (var j = 0; j < gridsize ; j++) 
   {
    	FLOORGRID[i][j] = GRID_WALL ;		 
   }
}


function initFloorWalls()		//Setting up Floor	
{
 var t = 0;
 for (var i = 0; i < gridsize ; i++) 
  for (var j = 0; j < gridsize ; j++) 
   if ( FLOORGRID[i][j] == GRID_WALL )
   {
 	 var shape    = new THREE.BoxGeometry( squaresize, 10, squaresize );			 
 	 var thecube  = new THREE.Mesh( shape );
	 thecube.material.color.setHex( BLANKCOLOR  );			  
 
    	 thecube.position.x = translate ( i * squaresize );   		// translate my simple (i,j) block-numbering coordinates to three.js (x,y,z) coordinates 
    	 thecube.position.z = translate ( j * squaresize );   	
    	 thecube.position.y =  -50;	
 
 	 threeworld.scene.add(thecube);
	 FLOORS[t] = thecube;				// save it for later
	 t++; 
   }
}

//painting the floor
function paintFloor ( material )		 
{
 for ( var i = 0; i < FLOORS.length; i++ )
 { 
   if ( FLOORS[i] )  FLOORS[i].material = material;
 }
}

//setting up the maze, leaving gaps so mario can run through the map, randomly place one box in empty rows as an obstacle
function initLogicalMaze()
{
    for (var b = 2; b < gridsize - 1; b+=2){
        var x = randomintAtoB(4,gridsize-4);
        GRID[b-1][x] = GRID_MAZE;
      for (var j = 2; j < gridsize -2 ; j++) 
      {
       GRID[b][j] =  GRID_MAZE;
      }
    }
     for (var b = 2; b < gridsize-1 ; b+=4) 
      {
       GRID[b][18] =  GRID_MAZE;
      }
      for (var b = 4; b < gridsize -1 ; b+=4) 
      {
       GRID[b][1] =  GRID_MAZE;
      }

}

// make cubes out of the maze
function initThreeMaze()		  	
{
 var t = 0;
 for (var i = 0; i < gridsize ; i++) 
  for (var j = 0; j < gridsize ; j++) 
   if ( GRID[i][j] == GRID_MAZE )
   {
   	var shape    = new THREE.BoxGeometry( squaresize, BOXHEIGHT, squaresize );			 
  	var thecube  = new THREE.Mesh( shape );
	thecube.material.color.setHex( BLANKCOLOR  );			  

  	thecube.position.x = translate ( i * squaresize );   	
  	thecube.position.z = translate ( j * squaresize );   	
  	thecube.position.y =  0;	
 
 	threeworld.scene.add(thecube);
	MAZE[t] = thecube;		// save it for later
	t++; 
   }
}

//paint the maze
function paintMaze ( material )		 
{
 for ( var i = 0; i < MAZE.length; i++ )
 { 
   if ( MAZE[i] )  MAZE[i].material = material;
 }
}







// --- enemy functions -----------------------------------

//function to set enemy position on the map
function drawEnemy()	// given ei, ej, draw it 
{
  var x = translate ( ei * squaresize );   	
  var z = translate ( ej * squaresize );   	
  var y =  0;	

 theenemy.position.x = x;
 theenemy.position.y = y;
 theenemy.position.z = z;
}


function initLogicalEnemy()
{
// start in random location:
 var i, j;
 do
 {
  i = randomintAtoB(1,gridsize-2);
  j = randomintAtoB(1,gridsize-2);
 }
 while ( occupied(i,j) );  	  // search for empty square 

 ei = i;
 ej = j;
}




function moveLogicalEnemy(a)
{ 
// move towards agent 

 var i = ei;
 var j = ej;		 

      if ( a == ACTION_LEFT ) 	i--;
 else if ( a == ACTION_RIGHT ) 	i++;
 else if ( a == ACTION_UP ) 	j++;
 else if ( a == ACTION_DOWN ) 	j--;
 
 if ( ! occupied(i,j) )  	// if no obstacle then move, else just miss a turn
 {
     if ( true  )
  {
	// if going to actually move, then turn body towards move
	// rotate by some amount of radians from the normal position 
	// in degrees: +0, +90, +180, +270

	      if ( a == ACTION_LEFT ) 	{  rotateEnemyLeft (); }
	 else if ( a == ACTION_RIGHT ) 	{  rotateEnemyRight (); }
	 else if ( a == ACTION_UP ) 		{  rotateEnemyUp (); }
	 else if ( a == ACTION_DOWN ) 	{  rotateEnemyDown (); }
  }   
     
  ei = i;
  ej = j;
 }
}

//fnctions to allow the enemy to rotate
function rotateEnemyLeft ( )		
{
 theenemy.rotation.set ( 0, 4.71239, 0 );

}
function rotateEnemyDown(){
    theenemy.rotation.set ( 0, 3.14159, 0 );

}
function rotateEnemyUp(){
    theenemy.rotation.set ( 0, 0, 0 );

}
function rotateEnemyRight(){
    theenemy.rotation.set ( 0, 1.5708, 0 );

}


//---------enemy 2 functions------


//same functions as above, but for enemy 2
function drawEnemy2()	// given ei, ej, draw it 
{
  var x = translate ( ei2 * squaresize );   	
  var z = translate ( ej2 * squaresize );   	
  var y =  0;	

 theenemy2.position.x = x;
 theenemy2.position.y = y;
 theenemy2.position.z = z;
 
}


function initLogicalEnemy2()
{
// start in random location:
 var i, j;
 do
 {
  i = randomintAtoB(1,gridsize-2);
  j = randomintAtoB(1,gridsize-2);
 }
 while ( occupied(i,j) );  	  // search for empty square 

 ei2 = i;
 ej2 = j;
}




function moveLogicalEnemy2(a)
{ 
// move towards agent 

 var i = ei2;
 var j = ej2;		 

      if ( a == ACTION_LEFT ) 	i--;
 else if ( a == ACTION_RIGHT ) 	i++;
 else if ( a == ACTION_UP ) 	j++;
 else if ( a == ACTION_DOWN ) 	j--;
 
 if ( ! occupied(i,j) )  	// if no obstacle then move, else just miss a turn
 {
     if ( true  )
  {
	// if going to actually move, then turn body towards move
	// rotate by some amount of radians from the normal position 
	// in degrees: +0, +90, +180, +270

	      if ( a == ACTION_LEFT ) 	{  rotateEnemyLeft2 (); }
	 else if ( a == ACTION_RIGHT ) 	{  rotateEnemyRight2 (); }
	 else if ( a == ACTION_UP ) 		{  rotateEnemyUp2 (); }
	 else if ( a == ACTION_DOWN ) 	{  rotateEnemyDown2 (); }
  }   
     
  ei2 = i;
  ej2 = j;
 }
}

function rotateEnemyLeft2 ( )		
{
 theenemy2.rotation.set ( 0, 4.71239, 0 );

}
function rotateEnemyDown2(){
    theenemy2.rotation.set ( 0, 3.14159, 0 );

}
function rotateEnemyUp2(){
    theenemy2.rotation.set ( 0, 0, 0 );

}
function rotateEnemyRight2(){
    theenemy2.rotation.set ( 0, 1.5708, 0 );

}





// --- agent functions -----------------------------------

//same as above but for agen, move function different
function drawAgent()	// given ai, aj, draw it 
{
 if(theagent){
  var x = translate ( ai * squaresize );   	
  var z = translate ( aj * squaresize );   	
  var y =  ya;	

 theagent.position.x = x;
 theagent.position.y = y;
 theagent.position.z = z;

 threeworld.follow.copy ( theagent.position );		// follow vector = agent position (for camera following agent)
 }
}




function initLogicalAgent()
{
// start in random location:
 var i = 18;
 var j = 1;
 while ( occupied(i,j) );  	  // search for empty square 

 ai = i;
 aj = j;
}

//mario is user controlled, jump lift mario and moves him forward or backwards 5 spaces depending on where he is facing
//mario is not allowed jump out of the grid
function moveLogicalAgent( a )		
{ 
 var i = ai;
 var j = aj;		 

      if ( a == ACTION_LEFT ) 	i--;
 else if ( a == ACTION_RIGHT ) 	i++;
 else if ( a == ACTION_UP ) 		j++;
 else if ( a == ACTION_DOWN ) 	j--;
 else if ( a == ACTION_JUMP ){
    if(inJump == true){
        $("#user_span6").html( " &nbsp; <font color=red> <B> Already In Jump. </B> </font>   "  );
    }
    else if(isFacingDown(theagent)){
      if(aj >5)
        inJump = true;
    }
    else if(isFacingUp(theagent)){
      if(aj <14)
        inJump = true;
    }
 }


 if ( ! occupied(i,j) ) 
 {
  if ( true  )
  {
	// if going to actually move, then turn body towards move
	// rotate by some amount of radians from the normal position 
	// in degrees: +0, +90, +180, +270

	      if ( a == ACTION_LEFT ) 	{  rotateAgentLeft (); }
	 else if ( a == ACTION_RIGHT ) 	{  rotateAgentRight (); }
	 else if ( a == ACTION_UP ) 		{  rotateAgentUp (); }
	 else if ( a == ACTION_DOWN ) 	{  rotateAgentDown (); }
  }   
  ai = i;
  aj = j;
 }
}
function rotateAgentLeft ( )		
{
 theagent.rotation.y = 4.71239;

}
function rotateAgentDown(){
    theagent.rotation.y  = 3.14159;

}
function rotateAgentUp(){
    theagent.rotation.y = 0;

}
function rotateAgentRight(){
    theagent.rotation.y =1.5708;

}

//functions to check which way mario is facing
function isFacingDown(obj){
	if (obj.rotation.y == 3.14159) return true;
	else return false;
}
function isFacingUp(obj){
	if (obj.rotation.y == 0) return true;
	else return false;
}

//function for mario to jump, uses booleans created earlier
//has 3 steps: jump, move forward/backwards 5 spaces, land
function jumpMario(){
    var y = ya;
    var j = aj;
    if(isFacingUp(theagent) == true){
        if(aj <14 && jumpMar == true){
          if(jumpMar == true){
            soundWooHoo();
            ya += 100;
            jumpMar = false;
            moveMar = true;
          }
        }
          else if(moveMar == true){
            aj += 5;
            moveMar = false;
            landMar = true;
          }
          else if(landMar == true){
            
            ya -= 100;
            jumpMar = true;
            landMar = false;
            inJump = false;
    
          }

    }
    else if(isFacingDown(theagent) == true){
        if(aj >5 && jumpMar == true){
            if(jumpMar == true){
                soundWooHoo();
                ya += 100;
                jumpMar = false;
                moveMar = true;
            }
        }
        else if(moveMar == true){
            aj -= 5;
            moveMar = false;
            landMar = true;
            
        }
        else if(landMar == true){
            ya -= 100;
            jumpMar = true;
            landMar = false;
            inJump = false;
    
        }
    }
}



// -------Flag definitions--------

//functions to create princess, was originally a flag hence the name. Last minute change to a  princess
function drawFlag()	// given ai, aj, draw it 
{
  var x = translate ( fi * squaresize );   	
  var z = translate ( fj * squaresize );   	
  var y =  0;	

 theflag.position.x = x;
 theflag.position.y = y;
 theflag.position.z = z;
 theflag.rotation.y = 3.14159;
}


function initLogicalFlag()
{
 var i = 1;
 var j = 18;
 while ( occupied(i,j) );  	  // search for empty square 

 fi = i;
 fj = j;
}



function keyHandler(e)		
// user control 
// Note that this.takeAction(a) is constantly running at same time, redrawing the screen.
{
    if (e.keyCode == 37)  { moveLogicalAgent ( ACTION_LEFT  	); e.preventDefault(); }
    if (e.keyCode == 38)  { moveLogicalAgent ( ACTION_DOWN  	); e.preventDefault(); }
    if (e.keyCode == 39)  { moveLogicalAgent ( ACTION_RIGHT 	); e.preventDefault(); }
    if (e.keyCode == 40)  { moveLogicalAgent ( ACTION_UP	    ); e.preventDefault(); }
    if (e.keyCode == 32)  { moveLogicalAgent ( ACTION_JUMP	    ); e.preventDefault(); }
}


//function to check if mario is touching goomba
function agentBlocked()
{
 return ( 	(occupied (ai-1,aj) 		&& 
		occupied (ai+1,aj)		&&
		occupied (  ai,aj+1)		&&
		occupied (  ai,aj-1)) || 
		( 	occupiedEnemy (ai-1,aj) 		|| 
		occupiedEnemy (ai+1,aj)		||
		occupiedEnemy (  ai,aj+1)		||
		occupiedEnemy (  ai,aj-1)));		
} 

//function to check if mario is touching the flag
function flagFound(){
    return ( 	occupiedFlag (ai,aj) 		);
}

//print out time
function updateStatusBefore(a)
{
 var x = self.getState();
 var status = " Time(Ends at 400): <b> " + step; 

 $("#user_span3").html( status );
}

//--- public functions / interface / API ----------------------------------------------------------


	this.endCondition;			// If set to true, run will end. 



this.newRun = function() 
{
  this.endCondition = false;
	step = 0;


 // for all runs:

 	initGrid();
 	initGrid2();
 	initFloor();
 	initLogicalAgent();
 	initLogicalFlag();
	initLogicalWalls(); 
	initLogicalMaze();
	initLogicalEnemy();
	initLogicalEnemy2();


 // for graphical runs only:

  if ( true  )
  {
      //game can be played in both 2d and 3d by changing show3d boolean
	if ( show3d )
	{
	 BOXHEIGHT = squaresize;
	 threeworld.init3d ( startRadiusConst, maxRadiusConst, SKYCOLOR  ); 	
	}	     
	else
	{
	 BOXHEIGHT = 1;
	 threeworld.init2d ( startRadiusConst, maxRadiusConst, SKYCOLOR  ); 		     
	}
	var ambient = new THREE.AmbientLight();
    		threeworld.scene.add( ambient );

		
	   	 var thelight = new THREE.DirectionalLight ( LIGHTCOLOR, 3 );
	  	 thelight.position.set ( startRadiusConst, startRadiusConst, startRadiusConst );
	   	 threeworld.scene.add(thelight);

	initSkybox();
 	initMusic();

	// Set up objects first:

	initThreeWalls(); 
	initFloorWalls();
	initThreeMaze();

	loadTextures();	

	document.onkeydown = keyHandler;	 
  }

};




this.getState = function()
{
 var x = [ ai, aj, ei, ej];
  return ( x );  
};



this.nextStep = function()		 
{
 var a = 4;

  step++;

  if ( true  )
   updateStatusBefore(a);			// show status line before moves 

  moveLogicalAgent(a);
  
  //if mario jumps on goomba, remove it
  if(ai == ei && aj == ej){
        threeworld.scene.remove(theenemy);
        ei = -5;
        ej = -5;
        var x = "<audio    src=/uploads/cathaln/stomp.mp3   autoplay  > </audio>";
  	    $("#user_span2").html( x );
        $("#user_span6").html( " &nbsp; <font color=red> <B> Enemy Killed!  </B> </font>   "  );
    }
  if(ai == ei2 && aj == ej2){
        threeworld.scene.remove(theenemy2);
        ei2 = -5;
        ej2 =-5;
        var x = "<audio    src=/uploads/cathaln/stomp.mp3   autoplay  > </audio>";
  	    $("#user_span2").html( x );
        $("#user_span6").html( " &nbsp; <font color=red> <B> Enemy Killed!  </B> </font>   "  );
    }
    
    
 var i,jj;
 //movements for goombas to chase mario
 if ( ej < aj ) i = ACTION_UP; 
 else if ( ej > aj ) i = ACTION_DOWN; 
 else ACTION_RIGHT;

 if ( ej2 < aj ) jj = ACTION_UP; 
 else if ( ej2 > aj ) jj = ACTION_DOWN; 
 else ACTION_RIGHT;
 
 //goombas only move every 6 steps
  if ( ( step % 6 ) == 0 ){		
    moveLogicalEnemy(i);
    moveLogicalEnemy2(jj);
  }
    
    //if boolean is true, user has chosen to jump
  if(inJump == true){
      jumpMario();
  }

    //redraw objects
  if ( true  )
  {
   drawAgent();
   drawFlag();
   drawEnemy();
   drawEnemy2();
  }

    //function for ending game
  if ( agentBlocked() || flagFound() )			// if agent blocked in, run over 
  {
	this.endCondition = true;
	goodsteps = 0;			// you score zero as far as database is concerned 			 
  	if ( true  )
  	{
	 musicPause();
	 //play mario died music
	 if(agentBlocked()){
	        soundAlarm();
	    }
	    //play level complete music
	 else if(flagFound()){
		    soundFlagAlarm();
		}
	}
  }

};


//print message depending on what happened
this.endRun = function()
{
 if ( true  )
 {
  musicPause(); 
  if ( this.endCondition ){
    $("#user_span6").html( " &nbsp; <font color=red> <B> Game Over. </B> </font>   "  );
  }
  else
    $("#user_span6").html( " &nbsp; <font color=red> <B> Times Up! </B> </font>   "  );
 }
};


}

//---- end of World class -------------------------------------------------------

//play music, other sound functions
function initMusic()
{
	// put music element in one of the spans
  	var x = "<audio  id=theaudio  src=/uploads/cathaln/mariothemetune.mp3   autoplay loop> </audio>" ;
  	$("#user_span1").html( x );
} 
 

function musicPlay()  
{
	// jQuery does not seem to parse pause() etc. so find the element the old way:
 	document.getElementById('theaudio').play();
}


function musicPause() 
{
 	document.getElementById('theaudio').pause();
}


function soundAlarm()
{
 	var x = "<audio    src=/uploads/cathaln/gameover.mp3   autoplay  > </audio>";
  	$("#user_span2").html( x );
}
function soundFlagAlarm()
{
 	var x = "<audio    src=/uploads/cathaln/levelcomplete.mp3   autoplay  > </audio>";
  	$("#user_span2").html( x );
}
//play a woohoo when mario jumps
function soundWooHoo()
{
 	var x = "<audio    src=/uploads/cathaln/woohoo.mp3   autoplay  > </audio>";
  	$("#user_span2").html( x );
}