Code viewer for World: New World
const NOBOXES = Math.trunc (((gridsize*gridsize)/100)*7); //around 7% of the level will be walls, seems to give favourable results   
const squaresize = 100;					// size of square in pixels
const MAXPOS = gridsize * squaresize;		// length of one side in pixels 
	
const SKYCOLOR 	= 0xffffcc;				// a number, not a string 
const BLANKCOLOR 	= SKYCOLOR ;			// make objects this color until texture arrives (from asynchronous file read)


const startRadiusConst	 	= MAXPOS * 0.8 ;		// distance from centre to start the camera at
const skyboxConst			= MAXPOS * 100 ;		// where to put skybox 
const maxRadiusConst 		= MAXPOS * 100 ;		// maximum distance from camera we will render things  

const show3d = true;						// Switch between 3d and 2d view (both using Three.js) 


function World(){
    
    
    var THEARMY 	= new Array( ARMYSIZE );	
	var textureArray = new Array ( FILE_ARRAY.length );
	
    
    
    function initSkybox() 
    {

// x,y,z positive and negative faces have to be in certain order in the array 

      var materialArray = [
     	( new THREE.MeshBasicMaterial ( { map: THREE.ImageUtils.loadTexture( "/uploads/kikisanni/pexels-posx.jpg" ), side: THREE.BackSide } ) ),
     	( new THREE.MeshBasicMaterial ( { map: THREE.ImageUtils.loadTexture( "/uploads/kikisanni/pexels-negx.jpg" ), side: THREE.BackSide } ) ),
     	( new THREE.MeshBasicMaterial ( { map: THREE.ImageUtils.loadTexture( "/uploads/kikisanni/pexels-posy.jpg"),side: THREE.BackSide } ) ),
     	( new THREE.MeshBasicMaterial ( { map: THREE.ImageUtils.loadTexture( "/uploads/kikisanni/pexels-negy.jpg" ), side: THREE.BackSide } ) ),
     	( new THREE.MeshBasicMaterial ( { map: THREE.ImageUtils.loadTexture( "/uploads/kikisanni/pexels-posz.jpg" ), side: THREE.BackSide } ) ),
     	( new THREE.MeshBasicMaterial ( { map: THREE.ImageUtils.loadTexture( "/uploads/kikisanni/pexels-negz.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 initThreeLights()
    {
    	//this acts like a sun
    	var dirLight = new THREE.DirectionalLight(0xffffff, 1); //white light
    	dirLight.position.set((gridsize*squaresize)*2,(gridsize*squaresize)*3,(gridsize*squaresize)); //this will put our light in the bottom corner
    	dirLight.CameraLightHelper = true;
    	threeworld.scene.add(dirLight);
    	
    	//give us some light everywhere to make sure we have no 100% black
    	var ambiLight = new THREE.AmbientLight(0x1a1a1a);
    	threeworld.scene.add(ambiLight);
    	
    	//THIS GIVES US BEAUTIFUL SHADOWS
    	//SHADOWS ARE A BIT PIXELATED BUT THIS IS AS GOOD AS YOU'LL GET WITH JUST THE ONE LIGHT COVERING EVERYTHING
    	var spotLight = new THREE.SpotLight(0xffffff, 0, (gridsize*squaresize)*3, 75, 10);
    	spotLight.position.set((gridsize*squaresize),(gridsize*squaresize),(gridsize*squaresize));
    	spotLight.castShadow = true;
    	var spotTarget = new THREE.Object3D();
    	threeworld.scene.add(spotLight);
    	spotTarget.position.set(0,0,0);
    	spotLight.target = spotTarget;
    	threeworld.scene.add(spotLight);
    }


    function loadResources()		// asynchronous file loads - call initScene() when all finished 
    {
    	for ( var i = 0; i < FILE_ARRAY.length; i++ ) 
    	  startFileLoad ( i );						// launch n asynchronous file loads
    }
    
    	
    function startFileLoad ( n )				// asynchronous file load of texture n 
    {
    	var loader = new THREE.TextureLoader();
    
    	loader.load ( FILE_ARRAY[n], function ( thetexture )  	 
    	{
    		thetexture.minFilter  = THREE.LinearFilter;
    		textureArray[n] = thetexture;
    		if ( asynchFinished() ) initScene();
    	});	
    }
     
     
    function asynchFinished()		// all file loads returned 
    {
    	for ( var i = 0; i < FILE_ARRAY.length; i++ ) 
    		if ( ! textureArray[i] ) 
    			return false;
    		
    	  return true;
    }
    
    
    
    function initArmy()		 // called when all textures ready 
    {
     var t = 0;
     
     for ( var c=1 ; c <= ARMYSIZE ; c++ )
     {
        //    var shape = new THREE.SphereGeometry ( objectsize, 30, 30 ); 
       var shape = new THREE.BoxGeometry( objectsize, objectsize, objectsize );
      
      	var theobject  = new THREE.Mesh( shape );
    
      	theobject.position.x = AB.randomIntAtoB ( -MAXPOS, MAXPOS );   	
      	theobject.position.z = AB.randomIntAtoB ( -MAXPOS, MAXPOS );   	
      	theobject.position.y =  0;	
    	
    // 	var r = AB.randomIntAtoB ( 0, textureArray.length - 1 );    // random texture 
     	var r = AB.randomIntAtoB ( 0, 4 );    			            // random one of the earths
        theobject.material =  new THREE.MeshBasicMaterial ( { map: textureArray[r] } );   
    
     	ABWorld.scene.add(theobject);
    	THEARMY[t] = theobject;	            	// save it for later
    	t++; 
     }
     
    } 
      
    	ABWorld.render();		
      
    	AB.removeLoading();
    	
      	AB.runReady = true; 
      	
      	let listElement = document.createElement("li");
      	listElement.innerHTML
      	
      	AB.msg ( `<hr> <p> Multiplayer game. Click buttons to change boxes on all users' machines. Drag the camera. <p>\n  \t
      	        <button onclick='red();'  class=ab-largenormbutton > Red </button>\n 
                <button onclick='yellow();'  class=ab-largenormbutton > Yellow </button>\n
                <button onclick='blue();'  class=ab-largenormbutton > Blue </button>\n
                <button onclick='green();'  class=ab-largenormbutton > Green </button> <p>\n
                
                
                `
                
                
    );


    function moveArmy()		    // move all the objects 
    {
     for ( var i = 0; i < THEARMY.length; i++ )
     { 
       if ( THEARMY[i] )		// in case initArmy() not called yet 
       { 
            THEARMY[i].position.x =  THEARMY[i].position.x + AB.randomIntAtoB(-WALKSTEP,WALKSTEP) ;        
            THEARMY[i].position.z =  THEARMY[i].position.z + AB.randomIntAtoB(-WALKSTEP,WALKSTEP) ;
            THEARMY[i].position.y =  THEARMY[i].position.y + AB.randomIntAtoB(-WALKSTEP,WALKSTEP) ;
            ABWorld.scene.add( THEARMY[i] );
       }
     }
     
     
     
     this.newRun = function() 
    {
      
    
      // if Three.js graphical representation:
    
      if ( true  )
      {
    	  if ( show3d )
    	  {
    	        BOXHEIGHT = squaresize;
    	        threeworld.init3d ( startRadiusConst, maxRadiusConst, SKYCOLOR  ); 	
    	  }	     
    	  else
    	  {
    	        BOXHEIGHT = 1;
    	        threeworld.init2d ( startRadiusConst, maxRadiusConst, SKYCOLOR  ); 		     
    	  } 
    	  initSkybox();
    
    	// Set up blank objects first:
    
    	  threeworld.renderer.shadowMap.enabled = true;
    	  threeworld.renderer.shadowMapSoft = false; //soft shadows is nice in theory but their anti-aliasing is shite so don't bother
    	  //console.log(threeworld.renderer);
    	  initThreeLights();
    	  
    
    	// Then paint them with textures - asynchronous load of textures from files. 
    	// The texture file loads return at some unknown future time in some unknown order.
    	// Because of the unknown order, it is probably best to make objects first and later paint them, rather than have the objects made when the file reads return.
    	// It is safe to paint objects in random order, but might not be safe to create objects in random order. 
    
    	  loadTextures();			// will return sometime later, but can go ahead and render now	
    	  
      }		
};
    
    
    
    AB.world.nextStep = function()
{
 	moveArmy();
};







//--- Socket functionality -----------------------------------------------------

// start socket

AB.socketStart();



// functions called by buttons
// baby and skull are textures 5 and 6 in the array:

function red()  {    changeBox(5);    AB.socketOut (5); }
function yellow() {    changeBox(6);    AB.socketOut (6); }
function blue()  {    changeBox(7);    AB.socketOut (7); }
function green()  {    changeBox(8);    AB.socketOut (8); }


function changeBox(n)   // change a random box to texture n (5 or 6) 
{
    var i = AB.randomIntAtoB ( 0, THEARMY.length - 1 );     // pick a random box to change 
    THEARMY[i].material =  new THREE.MeshBasicMaterial ( { map: textureArray[n] } );   
}

AB.socketIn = function(n)       // incoming data on socket, i.e. clicks of other player 
{
    changeBox(n);
};






}
}