Code viewer for World: Blackjack Multiplayer
AB.clockTick = 100; // Speed of run: Step every n milliseconds. Default 100.
	
AB.maxSteps = 100000; // Length of run: Maximum length of run in steps. Default 1000.

AB.screenshotStep  = 100; 	// Take screenshot on this step. (All resources should have finished loading.) Default 50.

 const FILE_ARRAY = [
		"/uploads/starter/earth.1.jpg",  // array 0 to 4 are the earths 
		"/uploads/starter/earth.2.jpg",
		"/uploads/starter/earth.3.jpg",
		"/uploads/starter/earth.4.jpg",
		"/uploads/starter/earth.5.jpg",
		"/uploads/starter/baby.1.png",  // array 5
		"/uploads/starter/ghost.3.png"  // array 6 
		];
	
const SKYCOLOR = 0xFFE4E1; // very light pink 

// a number, not a string
// 0xFFB6C1;    // light pink   
// 0xccffcc;	// light green 			 

const ARMYSIZE = 1; // how many boxes that generate

const objectsize = 500 ;

const WALKSTEP = 200;       // bounds of the random move per timestep 
                            // try 50 (vibrating sheet) versus 1000 (cloud)
         
const MAXPOS                = 4000 ;            // start things within these bounds                    
const startRadiusConst	 	= MAXPOS * 1.5 ;	// distance from centre to start the camera at
const maxRadiusConst 		= MAXPOS * 5 ;		// maximum distance from camera we will render things  

ABHandler.MAXCAMERAPOS 		= MAXPOS * 10 ;			// allow camera go far away 

ABWorld.drawCameraControls 	= false; 

AB.drawRunControls 			= false;


    var THEARMY 	= new Array( ARMYSIZE );	

	var textureArray = new Array ( FILE_ARRAY.length );

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() ) initArmy();
	});	
}
 
 
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++; 
 }
  // can start the run loop
	ABWorld.render();		
  	AB.runReady = true;
  	AB.msg ( ` <hr> <p> Multi-user game. Pick a side. Click buttons to change boxes on all users' machines. Drag the camera. <p>
  	        <button onclick='baby();'  class=ab-largenormbutton > Baby </button>  
            <button onclick='skull();'  class=ab-largenormbutton > Skull </button> <p> ` );						
}


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] );
   }
 }
}

AB.world.newRun = function() 
{
  AB.newSplash();                   
  
  AB.splashHtml (  ` 
    <h1> Password only Websocket boxes </h1>  
    A version of Websocket boxes that only certain users can join.  <br>
    You enter a password. You only join with users who enter the same password (not with all users of the World).  <br>
    The first user to run the World can enter any password! But other users must know what password they will use.
    <p>
	Enter password: 
	<input    style='width:25vw;'    maxlength='2000'   NAME="p"    id="p"       VALUE='' >  
	<button onclick='start();'  class=ab-normbutton >Start</button>
	<p>  
	<div id=errordiv name=errordiv> </div> ` );  
	
	AB.runReady = false;  

	ABWorld.init3d ( startRadiusConst, maxRadiusConst, SKYCOLOR  ); 

	loadResources();		// aynch file loads		
							// calls initArmy() when it returns 
};

AB.world.nextStep = function()
{
 	moveArmy();

};




//--- start Socket -----------------------------------------------------
	
function start()        // user has entered a password 
{
	var  password =  jQuery("input#p").val();
	password = password.trim();
	if ( ! alphanumeric ( password ) )
	{
	    $("#errordiv").html( "<font color=red> <B> Error: Password must be alphanumeric. </b></font> " );
	    return;
	}
	// else we have a password, start the socket run with this password 
    AB.socketStart ( password );  
    AB.removeSplash();   
}


  
function alphanumeric ( str ) 				// return if string is just alphanumeric   
{
	var rc = str.match(/^[0-9a-zA-Z]+$/); 			// start of line  "[0-9a-zA-Z]+"  end of line 
	if ( rc ) return true;
	else      return false; 
}




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

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

function baby()  {    changeBox(5);    AB.socketOut (5); }
function skull() {    changeBox(6);    AB.socketOut (6); }
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 
{
    if ( ! AB.runReady ) return;
    changeBox(n);
};

hit.addEventListener('click', hitPlayer)
pass.addEventListener('click', hitDealer)
nextHand.addEventListener('click', play)


shuffleDecks(3)
play()