Code viewer for World: Platinum Hell

// Cloned by Rishab Sidhu on 20 Nov 2022 from World "Super Mario Maze" by Cathal Neary 
// Please leave this clone trail here.

/*This is a 3D, 2 player game where both players are against each other, player 1 controls the tank and player 2 releases enemy aircrafts and 
if even one gets through player 2 wins, otherwise if the time is up then player 1 wins*/

/*Websockets did not go as planned, cannot even get the <button onclick="function()" to work properly*/


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


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

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

const squaresize = 100;					// size of square in pixels
const MAXPOS = gridsize * squaresize;		// length of one side in pixels 
	
const SKYCOLOR 	= 0x000000;				// 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_SHOOT      = 5;

// 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 -------------------------------------------------------------------------------------------------------------------------------

AB.runReady = false;


AB.newSplash(opening())        //A start screen with an introduction to the game
{
    var bg = document.getElementById("splash");
    bg.style.backgroundImage = "url('/uploads/sidhur2/ca318_5.jpg')";
    bg.style.backgroundRepeat = "no-repeat";
    bg.style.backgroundSize = "cover";
    
    var button = document.getElementById("splashbutton");
    button.style.background = "red";
}

$("#splashbutton").click (function ()
{
    AB.removeSplash();
    AB.socketStart();      //Start the multiplayer web-socket
    AB.runReady = true;    //The world starts to run after closing the start screen
});

//function to output text onto the start screen
function opening() {
        var html = "<style>" +
		"p {" +
		    "color: white;" +
			"font-size: 20px;}" +
        "</style>" +
        "<p>PLAYER 1: LEFT KEY || RIGHT KEY to move. SPACE to shoot</p>" +
        "<p>Shoot down the enemy aircrafts, do not let a single one pass</p>" +
        "<p>PLAYER 2: PRESS BUTTON [1] / [2] /.../ [7]" +
		"<p>Send one aircraft towards the end to win</p>";
		
    	return (html);
}
 
function World() { 
    

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 theagent, theenemy1, theenemy2, theenemy3, theenemy4, theenemy5, theenemy6, theenemy7, bullet;   //define player 1, 7 aircrafts for player 2 and the bullet

var ai, aj, ei, ej, ei2, ej2, ei3, ej3, ei4, ej4, ei5, ej5, ei6, ej6, ei7, ej7, ei8, ej8, bi, bj;    //define co-ordinates for player 1, co-ordinates of all 7 aircrafts for player 2 and co-ordinates of the bullet
var ya =  0;
var score = 0;

var step;
var self = this;	
var mvenem = false;

function moveEnemyVar(n)
{
    //Not working, Uncaught ReferenceError: moveEnemyVar is not defined
    console.log("test");
    
    /*switch (n) {
    case 1:
    moveLogicalEnemy1();
    break;
    case 2:
    moveLogicalEnemy2();
    break;
    case 3:
    moveLogicalEnemy3();
    break;
    case 4:
    moveLogicalEnemy4();
    break;
    case 5:
    moveLogicalEnemy5();
    break;
    case 6:
    moveLogicalEnemy6();
    break;
    case 7:
    moveLogicalEnemy7();
    break;
  
    }*/
}


function message() {
    AB.msg ( ` <hr> <p> Player 2. Pick an aircraft to send.<p>
  	        <button onclick='moveEnemyVar(1)'  class=ab-altbutton > [1] </button>  
  	        <button onclick='moveEnemyVar(2)'  class=ab-altbutton > [2] </button> 
  	        <button onclick='moveEnemyVar(3)'  class=ab-altbutton > [3] </button> 
  	        <button onclick='moveEnemyVar(4)'  class=ab-altbutton > [4] </button> 
  	        <button onclick='moveEnemyVar(5)'  class=ab-altbutton > [5] </button> 
  	        <button onclick='moveEnemyVar(6)'  class=ab-altbutton > [6] </button> 
  	        <button onclick='moveEnemyVar(7)'  class=ab-altbutton > [7] </button>
  	        <audio  id=theaudio  src=/uploads/sidhur2/doometernal.mp3   autoplay loop> </audio>` );
  	        // Main Theme: https://downloads.khinsider.com/game-soundtracks/album/doom-eternal-original-game-soundtrack
}
 

//creating grid of squares
function initGrid()
{
 for (var i = 0; i < gridwidth ; 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 < gridwidth ; 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+1 ) && ( ej == j+1 ) ) return true;		// variable objects 
 if ( ( ei2 == i+1 ) && ( ej2 == j+1 ) ) return true;
 if ( ( ei3 == i+1 ) && ( ej3 == j+1 ) ) return true;
 if ( ( ei4 == i+1 ) && ( ej4 == j+1 ) ) return true;
 if ( ( ei5 == i+1 ) && ( ej5 == j+1 ) ) return true;
 if ( ( ei6 == i+1 ) && ( ej6 == j+1 ) ) return true;
 if ( ( ei7 == i+1 ) && ( ej7 == j+1 ) ) return true;
 if ( ( ai == i-1 ) && ( aj == j+1 ) ) return true;

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

 


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





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


function initSkybox() 
{
  var materialArray = [
    ( new THREE.MeshBasicMaterial ( { map: THREE.ImageUtils.loadTexture( "/uploads/sidhur2/ca318_1.jpg" ), side: THREE.BackSide } ) ),
    ( new THREE.MeshBasicMaterial ( { map: THREE.ImageUtils.loadTexture( "/uploads/sidhur2/ca318_1.jpg" ), side: THREE.BackSide } ) ),
    ( new THREE.MeshBasicMaterial ( { map: THREE.ImageUtils.loadTexture( "/uploads/sidhur2/ca318_4.jpg" ), side: THREE.BackSide } ) ),
    ( new THREE.MeshBasicMaterial ( { map: THREE.ImageUtils.loadTexture( "/uploads/sidhur2/ca318_3.jpg" ), side: THREE.BackSide } ) ),
    ( new THREE.MeshBasicMaterial ( { map: THREE.ImageUtils.loadTexture( "/uploads/sidhur2/ca318_1.jpg" ), side: THREE.BackSide } ) ),
    ( new THREE.MeshBasicMaterial ( { map: THREE.ImageUtils.loadTexture( "/uploads/sidhur2/ca318_1.jpg" ), 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 loadBullet()
{
    var shell = new THREE.TextureLoader();
    shell.load ( '/uploads/sidhur2/ca318_6.jpg',	function (thetexture) { 
		thetexture.minFilter = THREE.LinearFilter;
		bullet.material =  new THREE.MeshBasicMaterial( { map: thetexture } );
	}); 
}

// Objects Downloaded from https://free3d.com/3d-models/plane
function loadTextures()
{
    /*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 );
    		} );
    	} );*/
    	
    var m = new THREE.MTLLoader();
    	m.setTexturePath ( "/uploads/sidhur2/" );
    	m.setPath( "/uploads/sidhur2/" );
    	m.load( "tiger.mtl", function( materials ) {
     
    		materials.preload();
    		var o = new THREE.OBJLoader();
    		o.setMaterials ( materials );
    		o.setPath ( "/uploads/sidhur2/" );
    		o.load( "tiger.obj", function ( object ) {
    			object.scale.multiplyScalar ( 20 );    	   
	            theagent = object;
	            threeworld.scene.add( theagent );
    		} );
    	} );
    
    var n1 = new THREE.MTLLoader();
    	n1.setTexturePath ( "/uploads/sidhur2/" );
    	n1.setPath( "/uploads/sidhur2/" );
    	n1.load( "plane3.mtl", function( materials ) {
     
    		materials.preload();
    		var o1 = new THREE.OBJLoader();
    		o1.setMaterials ( materials );
    		o1.setPath ( "/uploads/sidhur2/" );
    		o1.load( "plane4.obj", function ( object ) {
    			object.scale.multiplyScalar ( 0.1 );    	   
	            theenemy1 = object;
	            threeworld.scene.add( theenemy1 );
    		} );
    	} );
    	
    var n3 = new THREE.MTLLoader();
    	n3.setTexturePath ( "/uploads/sidhur2/" );
    	n3.setPath( "/uploads/sidhur2/" );
    	n3.load( "plane3.mtl", function( materials ) {
     
    		materials.preload();
    		var o3 = new THREE.OBJLoader();
    		o3.setMaterials ( materials );
    		o3.setPath ( "/uploads/sidhur2/" );
    		o3.load( "plane4.obj", function ( object ) {
    			object.scale.multiplyScalar ( 0.1 );    	   
	            theenemy3 = object;
	            threeworld.scene.add( theenemy3 );
    		} );
    	} );
    	
    var n5 = new THREE.MTLLoader();
    	n5.setTexturePath ( "/uploads/sidhur2/" );
    	n5.setPath( "/uploads/sidhur2/" );
    	n5.load( "plane3.mtl", function( materials ) {
     
    		materials.preload();
    		var o5 = new THREE.OBJLoader();
    		o5.setMaterials ( materials );
    		o5.setPath ( "/uploads/sidhur2/" );
    		o5.load( "plane4.obj", function ( object ) {
    			object.scale.multiplyScalar ( 0.1 );    	   
	            theenemy5 = object;
	            threeworld.scene.add( theenemy5 );
    		} );
    	} );
    	
    var n7 = new THREE.MTLLoader();
    	n7.setTexturePath ( "/uploads/sidhur2/" );
    	n7.setPath( "/uploads/sidhur2/" );
    	n7.load( "plane3.mtl", function( materials ) {
     
    		materials.preload();
    		var o7 = new THREE.OBJLoader();
    		o7.setMaterials ( materials );
    		o7.setPath ( "/uploads/sidhur2/" );
    		o7.load( "plane4.obj", function ( object ) {
    			object.scale.multiplyScalar ( 0.1 );    	   
	            theenemy7 = object;
	            threeworld.scene.add( theenemy7 );
    		} );
    	} );
    	
    var n2 = new THREE.MTLLoader();
    	n2.setTexturePath ( "/uploads/sidhur2/" );
    	n2.setPath( "/uploads/sidhur2/" );
    	n2.load( "Seahawk.mtl", function( materials ) {
     
    		materials.preload();
    		var o2 = new THREE.OBJLoader();
    		o2.setMaterials ( materials );
    		o2.setPath ( "/uploads/sidhur2/" );
    		o2.load( "Seahawk.obj", function ( object ) {
    			object.scale.multiplyScalar ( 0.8 );    	   
	            theenemy2 = object;
	            threeworld.scene.add( theenemy2 );
    		} );
    	} );
    	
    var n4 = new THREE.MTLLoader();
    	n4.setTexturePath ( "/uploads/sidhur2/" );
    	n4.setPath( "/uploads/sidhur2/" );
    	n4.load( "Seahawk.mtl", function( materials ) {
     
    		materials.preload();
    		var o4 = new THREE.OBJLoader();
    		o4.setMaterials ( materials );
    		o4.setPath ( "/uploads/sidhur2/" );
    		o4.load( "Seahawk.obj", function ( object ) {
    			object.scale.multiplyScalar ( 0.8 );    	   
	            theenemy4 = object;
	            threeworld.scene.add( theenemy4 );
    		} );
    	} );
    	
    var n6 = new THREE.MTLLoader();
    	n6.setTexturePath ( "/uploads/sidhur2/" );
    	n6.setPath( "/uploads/sidhur2/" );
    	n6.load( "Seahawk.mtl", function( materials ) {
     
    		materials.preload();
    		var o6 = new THREE.OBJLoader();
    		o6.setMaterials ( materials );
    		o6.setPath ( "/uploads/sidhur2/" );
    		o6.load( "Seahawk.obj", function ( object ) {
    			object.scale.multiplyScalar ( 0.8 );    	   
	            theenemy6 = object;
	            threeworld.scene.add( theenemy6 );
    		} );
    	} );
        
        //materials for floor, maze, walls
        var loader1 = new THREE.TextureLoader();
        loader1.load ( '/uploads/sidhur2/wall.jpg',		function ( thetexture ) {			 
        		thetexture.minFilter = THREE.LinearFilter;
        		paintWalls ( new THREE.MeshBasicMaterial( { map: thetexture } ) );
        	} ); 
        var loader5 = new THREE.TextureLoader();
        loader5.load ( '/uploads/sidhur2/floor.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 < gridwidth ; i++) 
  for (var j = 0; j < gridsize ; j++) 
   if ( ( i==0 ) || ( i==gridwidth-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 < gridwidth ; 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 < gridwidth ; 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 < gridwidth ; 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;
 }
}



// --- bullet functions ------------------------------------------------------------------------------------------------------------------------------------


function drawbullet() 
{
  const	CLOCKTICK = 10;	
  var x = translate ( bi * squaresize );   
  var z = translate ( bj * squaresize );   	
  var y =  80;	

  bullet.position.x = x;
  bullet.position.y = y;
  bullet.position.z = z;
  threeworld.scene.add(bullet);

  threeworld.lookat.copy ( bullet.position );
}


function initLogicalbullet()  // setting the bullet on to the world.
{
  var i, j;
  do
  {
    i = ai;                  // starting at the same coordanites as the agent.
    j = aj;
  }
  while (occupied(i,j));  	  // search for empty square 

  bi = i;
  bj = j;
}

function moveLogicalbullet()
{ 
  var i, j;
  i = bi;
  j = bj - 1;

  bi = i;                   
  bj = j;
}

function initThreeBullet()
{
  var shape = new THREE.BoxGeometry( 15, 15, 15 );	 
  bullet = new THREE.Mesh(shape);
  bullet.material.color.setHex(BLANKCOLOR);	
  drawbullet();		  
}




// --- 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 = 100;	

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

function initLogicalEnemy()
{
 var i, j;
 do
 {
  i = 2;
  j = 1;
 }
 while ( occupied(i,j) );  	  // search for empty square 

 ei = i;
 ej = j;
}

function moveLogicalEnemy1()
{ 
 var i = ei;
 var j = ej;		 
 j++;
 
 if ( j < 17 )  	// if no obstacle then move, else just miss a turn
 {
  ei = i;
  ej = j;
 }
}


//--- enemy 2 functions------------------------------------------------------------------------------------------------------------------------------------
function drawEnemy2()	// given ei2, ej2, draw it 
{
  var x = translate ( ei2 * squaresize );   	
  var z = translate ( ej2 * squaresize );   	
  var y = 50;	

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

function initLogicalEnemy2()
{
 var i, j;
 do
 {
  i = 1;
  j = 1;
 }
 while ( occupied(i,j) );  	  // search for empty square 

 ei2 = i;
 ej2 = j;
}

function moveLogicalEnemy2()
{ 
 var i = ei2;
 var j = ej2;		 
 j++;
 
 if ( j < 17 )  	// if no obstacle then move, else just miss a turn
 {
  ei2 = i;
  ej2 = j;
 }
}


//--- enemy 3 functions------------------------------------------------------------------------------------------------------------------------------------
function drawEnemy3()	// given ei3, ej3, draw it 
{
  var x = translate ( ei3 * squaresize );   	
  var z = translate ( ej3 * squaresize );   	
  var y = 100;	

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

function initLogicalEnemy3()
{
 var i, j;
 do
 {
  i = 4;
  j = 1;
 }
 while ( occupied(i,j) );  	  // search for empty square 

 ei3 = i;
 ej3 = j;
}

function moveLogicalEnemy3()
{ 
 var i = ei3;
 var j = ej3;		 
 j++;
 
 if ( j < 17 )  	// if no obstacle then move, else just miss a turn
 {
  ei3 = i;
  ej3 = j;
 }
}


//--- enemy 4 functions------------------------------------------------------------------------------------------------------------------------------------
function drawEnemy4()	// given ei4, ej4, draw it 
{
  var x = translate ( ei4 * squaresize );   	
  var z = translate ( ej4 * squaresize );   	
  var y = 50;	

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

function initLogicalEnemy4()
{
 var i, j;
 do
 {
  i = 3;
  j = 1;
 }
 while ( occupied(i,j) );  	  // search for empty square 

 ei4 = i;
 ej4 = j;
}

function moveLogicalEnemy4()
{ 
 var i = ei4;
 var j = ej4;		 
 j++;
 
 if ( j < 17 )  	// if no obstacle then move, else just miss a turn
 {
  ei4 = i;
  ej4 = j;
 }
}


//--- enemy 5 functions------------------------------------------------------------------------------------------------------------------------------------
function drawEnemy5()	// given ei5, ej5, draw it 
{
  var x = translate ( ei5 * squaresize );   	
  var z = translate ( ej5 * squaresize );   	
  var y = 100;	

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

function initLogicalEnemy5()
{
 var i, j;
 do
 {
  i = 6;
  j = 1;
 }
 while ( occupied(i,j) );  	  // search for empty square 

 ei5 = i;
 ej5 = j;
}

function moveLogicalEnemy5()
{ 
 var i = ei5;
 var j = ej5;		 
 j++;
 
 if ( j < 17 )  	// if no obstacle then move, else just miss a turn
 {
  ei5 = i;
  ej5 = j;
 }
}


//--- enemy 6 functions------------------------------------------------------------------------------------------------------------------------------------
function drawEnemy6()	// given ei6, ej6, draw it 
{
  var x = translate ( ei6 * squaresize );   	
  var z = translate ( ej6 * squaresize );   	
  var y = 50;	

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

function initLogicalEnemy6()
{
 var i, j;
 do
 {
  i = 5;
  j = 1;
 }
 while ( occupied(i,j) );  	  // search for empty square 

 ei6 = i;
 ej6 = j;
}

function moveLogicalEnemy6()
{ 
 var i = ei6;
 var j = ej6;		 
 j++;
 
 if ( j < 17 )  	// if no obstacle then move, else just miss a turn
 {
  ei6 = i;
  ej6 = j;
 }
}


//--- enemy 5 functions------------------------------------------------------------------------------------------------------------------------------------
function drawEnemy7()	// given ei7, ej7, draw it 
{
  var x = translate ( ei7 * squaresize );   	
  var z = translate ( ej7 * squaresize );   	
  var y = 100;	

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

function initLogicalEnemy7()
{
 var i, j;
 do
 {
  i = 7;
  j = 1;
 }
 while ( occupied(i,j) );  	  // search for empty square 

 ei7 = i;
 ej7 = j;
}

function moveLogicalEnemy7()
{ 
 var i = ei7;
 var j = ej7;		 
 j++;
 
 if ( j < 17 )  	// if no obstacle then move, else just miss a turn
 {
  ei7 = i;
  ej7 = j;
 }
}


// --- [] -------------------------------------------------------------------------------------------------------------------------------------------------

function enemyHit()
{
    if ( (bi == ei && bj == ej) || (bi == ei2 && bj == ej2) || (bi == ei3 && bj == ej3) || (bi == ei4 && bj == ej4) || (bi == ei5 && bj == ej5) || (bi == ei6 && bj == ej6) || (bi == ei7 && bj == ej7))
    {
        return true;
    }
    return false;
}


// --- 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()
{
 var i = 1;
 var j = 18;
 while (occupied(i,j));  

 ai = i;
 aj = j;
}


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_SHOOT ){
    dbullet = true;
    if (true)
    {
        initThreeBullet();
        initLogicalbullet();
        soundGunShot();
        loadBullet();
    }
 }
 
 if ( ! occupied(i,j) ) 
 {
  if ( true  )
  {
	      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;

}


var dbullet = false;
function keyHandler(e)		
// user control 
{
    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_SHOOT	    ); e.preventDefault(); }
}


//print out time
function updateStatusBefore(a)
{
 var x = self.getState();
 var status = " Time in seconds: <b> " + step + "\nScore = " + score; 

 $("#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
    message();
 	initGrid();
 	initGrid2();
 	initFloor();
 	initLogicalAgent();
	initLogicalWalls(); 
	initLogicalEnemy();
	initLogicalEnemy2();
	initLogicalEnemy3();
	initLogicalEnemy4();
	initLogicalEnemy5();
	initLogicalEnemy6();
	initLogicalEnemy7();


 // 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();

	// Set up objects first:
	initThreeWalls(); 
	initFloorWalls();

	loadTextures();	

	document.onkeydown = keyHandler;	 
  }

};




this.getState = function()
{
 var x = [ ai, aj, ei, ej, ei2, ej2, ei3, ej3, ei4, ej4, ei5, ej5, ei6, ej6, ei7, ej7];
  return ( x );  
};



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

  step++;

  if ( true  )
   updateStatusBefore(a);			// show status line before moves 
   
  if(AB.socket){
	if(AB.socket.connected){
	  AB.socketOut(ai);
	}
  }

  moveLogicalAgent(a);
    if ( ( step / 1) == step)
    {
        moveLogicalbullet();   // moving the bullet at speed.
    }
    
  if (enemyHit())
  {
      score += 1;
      soundDead();
  }
 
  if ( true  )
  {
   drawAgent();
   if (dbullet == true)
      drawbullet();
   drawEnemy();
   drawEnemy2();
   drawEnemy3();
   drawEnemy4();
   drawEnemy5();
   drawEnemy6();
   drawEnemy7();
  }
};


//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>   "  );
  }
 }
};


/*function sendEnemy1()  {  moveEnemyVar(1);    AB.socketOut(1);  }
function sendEnemy2()  {  moveEnemyVar(2);    AB.socketOut(2);  }
function sendEnemy3()  {  moveEnemyVar(3);    AB.socketOut(3);  }
function sendEnemy4()  {  moveEnemyVar(4);    AB.socketOut(4);  }
function sendEnemy5()  {  moveEnemyVar(5);    AB.socketOut(5);  }
function sendEnemy6()  {  moveEnemyVar(6);    AB.socketOut(6);  }
function sendEnemy7()  {  moveEnemyVar(7);    AB.socketOut(7);  }*/

}

//--- music -----------------------------------------------------------------------------------------------------------------------------------------------

//play music, other sound functions
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 soundDead()
// https://pixabay.com/sound-effects/search/death/
{
 	var x = "<audio    src=/uploads/sidhur2/goresplat.mp3   autoplay  > </audio>";
  	$("#user_span2").html( x );
}
function soundSoldierDeath()
// https://pixabay.com/sound-effects/search/splat/
{
 	var x = "<audio    src=/uploads/sidhur2/male_extreme_scream.mp3   autoplay  > </audio>";
  	$("#user_span2").html( x );
}
function soundGunShot()
// https://pixabay.com/sound-effects/search/shot/?manual_search=1&order=None
{
 	var x = "<audio    src=/uploads/sidhur2/9mm_pistol_shoot.mp3   autoplay  > </audio>";
  	$("#user_span2").html( x );
}