Code viewer for World: 3D Platformer
AB.clockTick       = 100;    
AB.maxSteps        = 10000;    
AB.screenshotStep  = 100;   
AB.drawRunControls = false;

    const show3d = true;						
    const GRID_BLANK 	= 0;
    const GRID_WALL 	= 1;
    const GRID_MAZE 	= 2;
    const gridsize = 25;	   
    const squaresize = 500;	
    const MAXPOS = gridsize * squaresize;
	const OBJPATH = "/uploads/linr2/";
	const PLAYER1OBJ = "Quigon.obj";
	const PLAYER1MTL = "Quigon.mtl";
	const SCALE_PLAYERS = 40;
	const SKYCOLOR 		= 0xffffcc;	
    const LIGHTCOLOR 	= 0xffffff ;
    const startRadiusConst	 	= MAXPOS ;
    const maxRadiusConst 		= MAXPOS * 10 ;
    const PLAYER_STEP = 1000;
    const FOLLOW_Y = SCALE_PLAYERS * 10 ;
    const LOOKAT_Y = SCALE_PLAYERS * 10;
    const CAMERASHIFT 	= - SCALE_PLAYERS * 3 ;
    ABHandler.MAXCAMERAPOS 	= maxRadiusConst ;
    ABHandler.GROUNDZERO		= true;	
    const ROTATE_AMOUNT      =  Math.PI / 4 ;
    const BLANKCOLOR 	= SKYCOLOR;
    const SKYBOX_ARRAY = [										 
                "/uploads/linr2/posx.jpg",
                "/uploads/linr2/negx.jpg",
                "/uploads/linr2/posy.jpg",
                "/uploads/linr2/negy.jpg",
                "/uploads/linr2/posz.jpg",
                "/uploads/linr2/negz.jpg"
                ];
    var player;
    var playerRotation = 0 ; 
    var player_texture; 
    var BOXHEIGHT;
    var GRID 	= new Array(gridsize);
    var FLOORGRID = new Array(gridsize);
    var WALLS 	= new Array ( 4 * gridsize );
    var FLOORS   = new Array(gridsize);
    var MAZE 	= new Array ( 1 );

    var theEnd;
    var ai, aj, pi, pj, ei, ej, ei2, ej2;
    var ya =  0;
    
    startTime=performance.now();
function randomfloatAtoB ( A, B )			 
{
 return ( A + ( Math.random() * (B-A) ) );
}

function randomintAtoB ( A, B )			 
{
 return  ( Math.round ( randomfloatAtoB ( A, B ) ) );
}


function initGrid()
{
 for (var i = 0; i < gridsize ; i++) 
 {
  GRID[i] = new Array(gridsize);

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

function initGrid2()
{
 for (var i = 0; i < gridsize ; i++) 
 {
  FLOORGRID[i] = new Array(gridsize);

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

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

function loadResources()
{
        
    var loader2 = new THREE.TextureLoader();
         loader2.load ('/uploads/linr2/wall.jpg', function (thetexture) 
         {			 
            thetexture.minFilter = THREE.LinearFilter;
        	paintMaze ( new THREE.MeshBasicMaterial( { map: thetexture } ) );
         }); 
        
    var loader5 = new THREE.TextureLoader();
         loader5.load ( '/uploads/linr2/ground.jpg', function (thetexture) 
         {			 
        	thetexture.minFilter = THREE.LinearFilter;
        	paintFloor ( new THREE.MeshBasicMaterial( { map: thetexture } ) );
        }); 


    THREE.DefaultLoadingManager.addHandler ( /\.tga$/i, new THREE.TGALoader() );
	var m = new THREE.MTLLoader();
	m.setResourcePath ( OBJPATH );
	m.setPath         ( OBJPATH );
	
	m.load ( PLAYER1MTL, function ( materials ) 
	{
		materials.preload();
		var o = new THREE.OBJLoader();
		o.setMaterials ( materials );
		o.setPath ( OBJPATH );
		
		o.load ( PLAYER1OBJ, function ( object ) 
		{
			player = object;
			if ( asynchFinished() )	initScene();		 
		});
	});
}


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


function initFloorWalls()
{
 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 );
    	 thecube.position.z = translate ( j * squaresize );   	
    	 thecube.position.y =  -50;	
 
 	 threeworld.scene.add(thecube);
	 FLOORS[t] = thecube;
	 t++; 
   }
}

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

function initLogicalMaze()
{
    for (var b = 0; b < 25; b+=1){
        var x = randomintAtoB(1,25);
        GRID[b][x] = GRID_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( 1700, BOXHEIGHT, 1000 );			 
  	var thecube  = new THREE.Mesh( shape );
	thecube.material.color.setHex( BLANKCOLOR  );			  

  	thecube.position.x = translate ( i * 450 );   	
  	thecube.position.z = translate ( j * 450 );   	
  	thecube.position.y =  0;	
 
 	threeworld.scene.add(thecube);
	MAZE[t] = thecube;
	t++; 
   }
}

function player1()
{
// start in random location:
 var i = 11;
 var j = 24;
 while ( collision(i,j) );

 pi = i;
 pj = j;
}


function collision ( i, j )
{
 if ( ( ei == i ) && ( ej == j ) ) return true;	
 if ( ( ei2 == i ) && ( ej2 == j ) ) return true;	
 if ( ( ai == i ) && ( aj == j ) ) return true;

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

function collisionEnd ( i, j )	
{
 if ( ( fi == i ) && ( fj == j ) ) return true;	 
	 
 return false;
}

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



function asynchFinished()
{
	if ( player )   return true;  
	else return false;
}	

function initScene() 
{
    var x = translate ( pi * squaresize );   	
    var z = translate ( pj * squaresize );   	
    var y =  ya;	
 	player.position.y = y;
	player.position.x = x;
	player.position.z = z;
	
	player.scale.multiplyScalar ( 13 );
	ABWorld.scene.add( player ); 
	var finishL    = new THREE.BoxGeometry( 50, 1200, 50 );			 
  	var FinishLine  = new THREE.Mesh( finishL );
	FinishLine.material.color.setHex( 'red'  );			  

  	FinishLine.position.x = -6000;   	
  	FinishLine.position.z = -6000;   	
  	FinishLine.position.y = 0;	
	ABWorld.scene.add( FinishLine );
	setLookatFollow(player);
	ABWorld.scene.background = new THREE.CubeTextureLoader().load ( SKYBOX_ARRAY,	function() 
	 { 
		ABWorld.render(); 
		AB.removeLoading();
		AB.runReady = true; 		
	 });
}

function 	setLookatFollow(User)
{	
	 ABWorld.follow.copy ( User.position );		 
	 ABWorld.follow.y = FOLLOW_Y ;    					 
	 ABWorld.follow.x = ABWorld.follow.x + ( CAMERASHIFT * Math.sin(playerRotation) );
	 ABWorld.follow.z = ABWorld.follow.z + ( CAMERASHIFT * Math.cos(playerRotation) );
	 ABWorld.lookat.copy ( User.position );
	 ABWorld.lookat.y = LOOKAT_Y ;     	
	 ABWorld.lookat.x = ABWorld.lookat.x + ( (startRadiusConst * 4) * Math.sin(playerRotation) );
	 ABWorld.lookat.z = ABWorld.lookat.z + ( (startRadiusConst * 4) * Math.cos(playerRotation) );
}

AB.world.newRun = function() 
{
 	initGrid();
 	initGrid2();
 	initFloor();
	initLogicalMaze();
	AB.loadingScreen();
	AB.runReady = false;  
	ABWorld.init3d ( startRadiusConst, maxRadiusConst, SKYCOLOR  ); 
	loadResources();
	player1();
	BOXHEIGHT = squaresize;
	ABWorld.init3d ( startRadiusConst, maxRadiusConst, SKYCOLOR  ); 	
	var ambient = new THREE.AmbientLight();
    ABWorld.scene.add( ambient );
    AB.msg ( ` <hr> <p> Multi-user game. Capture the Flag. Click buttons to move on all users' machines. <p>
  	        <button onclick='Left();'  class=ab-largenormbutton > Left </button>
  	        <button onclick='Forward();'  class=ab-largenormbutton > Forward </button>  
            <button onclick='Right();'  class=ab-largenormbutton > Right </button> <p>` );

	initFloorWalls();
	initThreeMaze();
};

function checkLocation(){
    if(player.position.z <= -6000 && player.position.x <= -6000)
    {
        AB.msg("<br><B>Congratulations!</B>",2)
        AB.abortRun=!0;
        const e=Math.floor((performance.now()-startTime)/1e3);
        AB.newSplash()
        AB.splashHtml(`<h1>It took ${e} to capture to flag</h1>`)
        AB.world.endRun=function(){};
        }
}
AB.socketStart();


function Forward()  {    moveforward();    AB.socketOut (); }
function Left() {    turnleft();    AB.socketOut (); }
function Right() {    turnright();    AB.socketOut (); }

function moveforward()
{
    player.position.x = player.position.x + ( PLAYER_STEP *  Math.sin(playerRotation) );
	player.position.z = player.position.z + ( PLAYER_STEP *  Math.cos(playerRotation) );
	checkLocation();
}

function turnleft()
{
    playerRotation = playerRotation + ROTATE_AMOUNT;
	player.rotation.set ( 0, playerRotation, 0 );
	checkLocation();
}

function turnright()
{
 	playerRotation = playerRotation - ROTATE_AMOUNT;
	player.rotation.set ( 0, playerRotation, 0 );
	checkLocation();
}

AB.socketIn = function()       // incoming data on socket, i.e. clicks of other player 
{
    if ( ! AB.runReady ) return;
    moveforward();
    turnleft();
    turnright();
    checkLocation();
};