Code viewer for World: v0.9 Pool Predictor Prototype

// Cloned by Ian Gilligan on 20 Feb 2019 from World "v0.8 Pool Predictor Prototype" by lillisl2 
// Please leave this clone trail here.
 


// Cloned by lillisl2 on 19 Feb 2019 from World "v0.7 Pool Predictor Prototype" by Ian Gilligan 
// Please leave this clone trail here.
 


// Cloned by Ian Gilligan on 18 Feb 2019 from World "v0.6 Pool Predictor Prototype" by Ian Gilligan 
// Please leave this clone trail here.
 


// Cloned by Ian Gilligan on 16 Feb 2019 from World "v0.5 Pool Predictor Prototype" by Ian Gilligan 
// Please leave this clone trail here.
 


// Cloned by Ian Gilligan on 14 Feb 2019 from World "v0.44 Pool Predictor Prototype" by Ian Gilligan 
// Please leave this clone trail here.
 


// Cloned by Ian Gilligan on 12 Feb 2019 from World "v0.43 Pool Predictor Prototype" by Ian Gilligan 
// Please leave this clone trail here.
 


// Cloned by Ian Gilligan on 5 Feb 2019 from World "v0.3 Pool Predictor Prototype" by lillisl2 
// Please leave this clone trail here.
 


// Cloned by lillisl2 on 4 Feb 2019 from World "v0.2 Pool Predictor Prototype" by Ian Gilligan 
// Please leave this clone trail here.
 


// Cloned by Ian Gilligan on 1 Feb 2019 from World "lillisl2 0.2 Pool Predictor Prototype" by lillisl2 
// Please leave this clone trail here.
 


// Cloned by lillisl2 on 1 Feb 2019 from World "0.1 Pool Predictor Prototype" by Ian Gilligan 
// Please leave this clone trail here.
 
// Cloned by Ian Gilligan on 30 Jan 2019 from World "Pool Predictor Prototype" by lillisl2 
// Please leave this clone trail here.
 
// Cloned by lillisl2 on 28 Jan 2019 from World "Cloned Bouncy Balls" by Ian Gilligan 
// Please leave this clone trail here.
 
// Cloned by Ian Gilligan on 28 Jan 2019 from World "Bouncy Balls" by Starter user 
// Please leave this clone trail here.

// ==== Starter World ===============================================================================================
// (c) Ancient Brain Ltd. All rights reserved.
// This code is only for use on the Ancient Brain site.
// This code may be freely copied and edited by anyone on the Ancient Brain site.
// This code may not be copied, re-published or used on any other website.
// To include a run of this code on another website, see the "Embed code" links provided on the Ancient Brain site.
// ==================================================================================================================

// Physijs based World
// Bouncy balls 

// ===================================================================================================================
// === Start of tweaker's box ======================================================================================== 
// ===================================================================================================================

// The easiest things to modify are in this box.
// You should be able to change things in this box without being a JavaScript programmer.
// Go ahead and change some of these. What's the worst that could happen?

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


// ===================================================================================================================
// === Variables & Constants =========================================================================================
// ===================================================================================================================

const OBJPATH = "/uploads/gilligi2/";	// path of OBJ and MTL 
const OBJNAME = "PoolTable.obj";
const MTLNAME = "pooltable.mtl";

const MODELLENGTH 			= 11054;							
const MODELWIDTH			= 6279; 
const SCALE                 = 0.009;

const BALLSIZE              = 2;                   // size of each ball
const BALLPOS               = BALLSIZE * 100; 		// x,z start position of balls is random in this interval
const BALLHEIGHT            = BALLSIZE * 2; 		// y start position of balls 
const HEAVYIMPACT           = 10;     			// heavy impacts have y velocity greater than this 

const GROUNDSIZE            = 150;                  // size of table
const startRadius           = MODELWIDTH * 0.02;       // camera start distance
const maxRadius             = MODELLENGTH * 0.03;      // camera max distance
	
const TEXTURE_FLOOR         = "/uploads/gilligi2/floor.jpg";
const TEXTURE_GROUND 	    = "/uploads/gilligi2/8451323128.png";   //colour of ground (green)
const TEXTURE_WALL          = "/uploads/lillisl2/8451232143.png";   //colour of walls (brown)
const SKYCOLOR              = 0xffffff;    //colour of sky / background (white)

// friction and restitution between 0 and 1: 
var   GROUND_FRICTION 		= 1;      // friction of ground
const GROUND_RESTITUTION 	= 0.5;     // restitution of ground
const WALL_FRICTION 		= 1;      // friction of wall
const WALL_RESTITUTION  	= 0.5;      // restitution of wall
const BALL_FRICTION 		= 0.9;      // friction of ball
const BALL_RESTITUTION 		= 0.8;      // restitution of ball

var   LIMIT                 = [7,7,1,1];    // limit values of each type of balls [yellow, red, black, white]
var   BALL_CHOICE           = 0;            // the ball that the user has currently selected
const BALL_TYPE             = [             // what each value of ball choice (0-3) represent
                            "Yellow",
                            "Red", 
                            "Black",
                            "White"];
                            
// define gravity along x,y,z dimensions:
var   gravity               = new THREE.Vector3 (0, -100, 0);
const BALL_MASS             = 10;        // mass of ball

const FILE_ARRAY            = [               // colours of each ball [yellow, red, black, white]
                            "/uploads/gilligi2/8451323595.png",
                            "/uploads/gilligi2/8451323612.png",
                            "/uploads/gilligi2/8451147306.png",
                            "/uploads/gilligi2/8451147292.png"];

const BASE_POWER            = 10000;
var   MIN_POWER             = 1;
var   MAX_POWER             = 5;

var   difficulty            = "Easy";
var   YOURCOLOR             = "None";

var   CALCULATED            = false;

var   BALL_COUNT            = 0;
var   BALLS                 = [0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0];
var   BALL_COLORS           = {};
var   WHITE                 = -1;
ABWorld.drawCameraControls  = false; 

var PAGE_SELECT = 1;
var CURRENT_PAGE = 0;
var line4_1 = ("<p align=\"center\"><button id='yellowButton'>Yellow</button> <button id='redButton'>Red</button> <button id='blackButton'>Black</button> <button id='whiteButton'>White</button></p>");
var line4_2 = ("<p align=\"center\"><button id='decreaseFrictionButton'>-</button> <button id='increaseFrictionButton'>+</button></p> ");
var line4_3 = ("<p align=\"center\"><button id='easyButton'>Easy</button> <button id='mediumButton'>Medium</button> <button id='hardButton'>Hard</button></p>");
var line6_1 = ("<p align=\"center\"><button id='yourNButton'>None</button> <button id='yourYButton'>Yellow</button> <button id='yourRButton'>Red</button></p>");
var line6_2 = ("<p align=\"center\"><button id='decreasePowerMinButton'>- Min</button> <button id='increasePowerMinButton'>+ Min</button> <button id='decreasePowerMaxButton'>- Max</button> <button id='increasePowerMaxButton'>+ Max</button></p> ");
var line6_3 = ("<p align=\"center\"><button id='cameraFlatButton'>Flat Down View</button> <button id='cameraCornerButton'>Pocket View</button></p> ");

var cameraPocketCounter = 0
// ===================================================================================================================
// === End of tweaker's box ==========================================================================================
// ===================================================================================================================

// You will need to be some sort of JavaScript programmer to change things below the tweaker's box.


var resourcesLoaded = false;
var splashClicked = false;

function World() 
{ 
	var textureArray = new Array ( FILE_ARRAY.length );
	var ground_texture;
	var self = this;
	var GROUND;
	var table;
	var p_height = 25;
	
function loadResources()		// asynchronous file loads - call initScene() when all finished 
{
    var m = new THREE.MTLLoader();
	m.setTexturePath (OBJPATH);
	m.setPath        (OBJPATH);
	
	m.load ( MTLNAME, function ( materials ) 
	{
		materials.preload(); 
		var o = new THREE.OBJLoader();
		o.setMaterials ( materials );
		o.setPath ( OBJPATH );
		
		o.load ( OBJNAME, function ( object ) 
		{
			table = object;
			if ( asynchFinished() )	initScene();		 
		});
	});
	for (var j = 0; j < FILE_ARRAY.length; j++){ 
	    startFileLoad (j);}}

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 
{
	if (! table){
	    return false;}
	return true;}
	
function initScene()			// all file loads have returned 
{
	// --- Light ------------------------------------------------------------------
	var light = new THREE.DirectionalLight(0xFFFFFF, 0.4);
	// close to origin, high up, works best for shadows
	light.position.set(0, 40, 0);
	light.target.position.copy(ABWorld.scene.position);
	light.castShadow = true;
	// how far away to draw shadows:
	light.shadow.camera.left    = -20;
	light.shadow.camera.right   =  20;
	light.shadow.camera.bottom  = -20;
	light.shadow.camera.top     =  20;
    // higher quality shadows at expense of computation time:
	light.shadow.mapSize.width  = 2048;
	light.shadow.mapSize.height = 2048;
	light.shadow.bias           = -0.1;
	ABWorld.scene.add(light);
	var light1 = new THREE.DirectionalLight(0xFFFFFF, 0.4);
	var light2 = new THREE.DirectionalLight(0xFFFFFF, 0.4);
	var light3 = new THREE.DirectionalLight(0xFFFFFF, 0.4);
	var light4 = new THREE.DirectionalLight(0xFFFFFF, 0.4);
	light1.position.set(100, 30, 0);
	light2.position.set(-100, 30, 0);
	light3.position.set(0, 30, 100);
	light4.position.set(0, 30, -100);
	ABWorld.scene.add(light1);
	ABWorld.scene.add(light2);
	ABWorld.scene.add(light3);
	ABWorld.scene.add(light4);

    // --- Floor -------------------------------------------------------------------
    //var floor_material = Physijs.createMaterial(new THREE.MeshLambertMaterial({map: TEXTURE_GROUND}), 0.1, 0.1);
    //floor_material.map.wrapS = THREE.RepeatWrapping;
	//floor_material.map.wrapT = THREE.RepeatWrapping;
	//floor_material.map.repeat.set(3, 3);
	//var floor = new Physijs.PlaneMesh(new THREE.PlaneGeometry(1000, 1000), floor_material);
    //floor.rotation.x = (Math.PI / 2) * 3;
    //floor.receiveShadow = true;

	//ABWorld.scene.add(floor);

	// --- Table -------------------------------------------------------------------
	table.position.y = 0;
    table.position.x = -15;
    table.position.z = 0; 
    ABWorld.scene.add(table);

	// --- Ground ------------------------------------------------------------------
	var ground_material = Physijs.createMaterial(new THREE.MeshStandardMaterial(), GROUND_FRICTION, GROUND_RESTITUTION);
	// ground as plane allows bounces but seems to be infinite plane
	var ground = new Physijs.BoxMesh(new THREE.BoxGeometry(MODELLENGTH * SCALE, 1, MODELWIDTH * SCALE), ground_material, 0);
	ground.position.y = p_height;
	ground.collisions = 0;
	ground.receiveShadow = true;
	//ABWorld.scene.add(ground);
	
	GROUND = ground;
	
	// --- Wall --------------------------------------------------------------------
	var wall_material = Physijs.createMaterial(new THREE.MeshStandardMaterial(), WALL_FRICTION, WALL_RESTITUTION);
	var wall1 = new Physijs.BoxMesh(new THREE.BoxGeometry(MODELLENGTH * SCALE, 6, MODELWIDTH * SCALE * 0.075), wall_material, 0);
	wall1.position.z = 28;
    wall1.collisions = 0;
	wall1.receiveShadow = true;
	var wall2 = new Physijs.BoxMesh(new THREE.BoxGeometry(MODELLENGTH * SCALE, 6, MODELWIDTH * SCALE * 0.075), wall_material, 0);
	wall2.position.z = -28;
    wall2.collisions = 0;
	wall2.receiveShadow = true;
	var wall3 = new Physijs.BoxMesh(new THREE.BoxGeometry(MODELLENGTH * SCALE * 0.05, 6, MODELWIDTH * SCALE), wall_material, 0);
	wall3.position.x = 52;
	wall3.collisions = 0;
	wall3.receiveShadow = true;
	var wall4 = new Physijs.BoxMesh(new THREE.BoxGeometry(MODELLENGTH * SCALE * 0.05, 6, MODELWIDTH * SCALE), wall_material, 0);
	wall4.position.x = -52;
    wall4.collisions = 0;
	wall4.receiveShadow = true;

    // --- Bumper --------------------------------------------------------------------
    var bumper1 = new Physijs.BoxMesh(new THREE.BoxGeometry(MODELLENGTH * SCALE * 0.35, 6, MODELWIDTH * SCALE * 0.075 * 1.5), wall_material, 0);
	bumper1.position.z = 23.5;
	bumper1.position.x = 23.5;
	bumper1.position.y = -0.1;
	bumper1.collisions = 0;
	bumper1.receiveShadow = true;
    var bumper2 = new Physijs.BoxMesh(new THREE.BoxGeometry(MODELLENGTH * SCALE * 0.35, 6, MODELWIDTH * SCALE * 0.075 * 1.5), wall_material, 0);
	bumper2.position.z = 23.5;
	bumper2.position.x = -23.5;
	bumper2.collisions = 0;
	bumper2.receiveShadow = true;
	var bumper3 = new Physijs.BoxMesh(new THREE.BoxGeometry(MODELLENGTH * SCALE * 0.35, 6, MODELWIDTH * SCALE * 0.075 * 1.5), wall_material, 0);
	bumper3.position.z = -23.5;
	bumper3.position.x = 23.5;
	bumper3.position.y = -0.1;
	bumper3.collisions = 0;
	bumper3.receiveShadow = true;
	var bumper4 = new Physijs.BoxMesh(new THREE.BoxGeometry(MODELLENGTH * SCALE * 0.35, 6, MODELWIDTH * SCALE * 0.075 * 1.5), wall_material, 0);
	bumper4.position.z = -23.5;
	bumper4.position.x = -23.5;
	bumper4.collisions = 0;
	bumper4.receiveShadow = true;
	var bumper5 = new Physijs.BoxMesh(new THREE.BoxGeometry(MODELLENGTH * SCALE * 0.03, 6, MODELWIDTH * SCALE * 0.55), wall_material, 0);
	bumper5.position.z = 0;
	bumper5.position.x = 48;
	bumper5.receiveShadow = true;
	var bumper6 = new Physijs.BoxMesh(new THREE.BoxGeometry(MODELLENGTH * SCALE * 0.03, 6, MODELWIDTH * SCALE * 0.55), wall_material, 0);
	bumper6.position.z = 0;
	bumper6.position.x = -48;
	bumper6.receiveShadow = true;
	ground.add(wall1);
	ground.add(wall2);
	ground.add(wall3);
	ground.add(wall4);
	ground.add(bumper1);
	ground.add(bumper2);
	ground.add(bumper3);
	ground.add(bumper4);
	ground.add(bumper5);
	ground.add(bumper6);
	//ground.visible = false;
	ABWorld.scene.add(ground);
	GROUND = ground;

    // --- Pocket --------------------------------------------------------------------
	var pocket_material = Physijs.createMaterial(new THREE.MeshStandardMaterial());
    var pocket = new Physijs.SphereMesh(new THREE.SphereGeometry(1), pocket_material, 0);
    var pocket1 = new Physijs.SphereMesh(new THREE.SphereGeometry(3, 15, 15), pocket_material, 0);
    pocket1.position.y = p_height;
    pocket1.position.z = 21.5;
    pocket1.position.x = 47;
    var pocket2 = new Physijs.SphereMesh(new THREE.SphereGeometry(3, 15, 15), pocket_material, 0);
    pocket2.position.y = p_height;
    pocket2.position.z = -21.5;
    pocket2.position.x = 47;
    var pocket3 = new Physijs.SphereMesh(new THREE.SphereGeometry(3, 15, 15), pocket_material, 0);
    pocket3.position.y = p_height;
    pocket3.position.z = 24;
    var pocket4 = new Physijs.SphereMesh(new THREE.SphereGeometry(3, 15, 15), pocket_material, 0);
    pocket4.position.y = p_height;
    pocket4.position.z = 21.5;
    pocket4.position.x = -47;
    var pocket5 = new Physijs.SphereMesh(new THREE.SphereGeometry(3, 15, 15), pocket_material, 0);
    pocket5.position.y = p_height;
    pocket5.position.z = -21.5;
    pocket5.position.x = -47;
    var pocket6 = new Physijs.SphereMesh(new THREE.SphereGeometry(3, 15, 15), pocket_material, 0);
    pocket6.position.y = p_height;
    pocket6.position.z = -24;
    pocket.add(pocket1);
    pocket.add(pocket2);
    pocket.add(pocket3);
    pocket.add(pocket4);
    pocket.add(pocket5);
    pocket.add(pocket6);
    pocket.addEventListener('collision', function(other_object, relative_velocity, relative_rotation, contact_normal) 
	{
        removeBall(other_object);
	});
	pocket.visible = false;
    ABWorld.scene.add(pocket);
	ABWorld.render();
	console.log("Resources loaded.");
	resourcesLoaded = true;}

function increaseFriction(){
    if (GROUND_FRICTION + 0.05 < 1.0){
        GROUND_FRICTION += 0.05;}
    else    {GROUND_FRICTION = 1.0;}
    }

function decreaseFriction(){
    if (GROUND_FRICTION - 0.05 > 0.0){
        GROUND_FRICTION -= 0.05;}
    else    {GROUND_FRICTION = 0.0;}
    }

function decreasePowerMin(){
    if (MIN_POWER > 1) {MIN_POWER -= 1;}}

function increasePowerMin(){
    if (MIN_POWER < MAX_POWER) {MIN_POWER += 1;}}

function decreasePowerMax(){
    if (MIN_POWER < MAX_POWER) {MAX_POWER -= 1;}}
    
function increasePowerMax(){
    if (MAX_POWER < 5) {MAX_POWER += 1;}}

function selectBall(x)
{
    BALL_CHOICE = x;}
    
function setDifficulty(x){
    difficulty = x;
}

function setColor(x){
    YOURCOLOR = x;
}

function hitBall()
{
    if (WHITE != -1){
        var white_b = (BALLS[WHITE][0]);
        white_b.applyCentralForce(new THREE.Vector3 (BASE_POWER * (MIN_POWER * 2), 0, 0));
    }
}

function basicSetUp()
{
    if (BALL_COUNT === 0){
        var tmp_choice = BALL_CHOICE;
        BALL_CHOICE = 3;
        createBall(-30, p_height + 0.5, 0);
        
        BALL_CHOICE = 2;
        createBall(30, p_height + 0.5, 0);
        
        BALL_CHOICE = 1;
        createBall(23, p_height + 0.5, 0); //red
        createBall(26.5, p_height + 0.5, -2); //red
        createBall(30, p_height + 0.5, 4); //red
        createBall(33.5, p_height + 0.5, 2); //red
        createBall(33.5, p_height + 0.5, -6); // red
        createBall(37, p_height + 0.5, -4); //red
        createBall(37, p_height + 0.5, 8); //red

        BALL_CHOICE = 0;
        createBall(26.5, p_height + 0.5, 2); //yellow
        createBall(30, p_height + 0.5, -4); //yellow
        createBall(33.5, p_height + 0.5, -2); //yellow
        createBall(33.5, p_height + 0.5, 6); //yellow
        createBall(37, p_height + 0.5, 0); //yellow
        createBall(37, p_height + 0.5, 4); //yellow
        createBall(37, p_height + 0.5, -8); //yellow
        
        BALL_CHOICE = tmp_choice;
    }
}

function createBall(x, y, z) 	 
{
	
 if ( resourcesLoaded && splashClicked && LIMIT[BALL_CHOICE] !== 0) 		  
 {
    var ball_material = Physijs.createMaterial(new THREE.MeshLambertMaterial({map: textureArray[BALL_CHOICE]}), BALL_FRICTION, BALL_RESTITUTION);
	var ball_geometry = new THREE.SphereGeometry(BALLSIZE, 100, 100);
    var ball = new Physijs.SphereMesh(ball_geometry, ball_material, BALL_MASS);
	ball.collisions = 0;
	ball.castShadow = true;
	//ball.position.set(1, 40, 1);
	ball.position.set(x, y + 2, z);
	ball.addEventListener('collision', function(other_object, relative_velocity, relative_rotation, contact_normal) 
	{
	    if (ball == BALLS[WHITE][0] && other_object != GROUND){
	        console.log("BOOM", BALL_COLORS[other_object]);}
		var mainImpact = relative_velocity.y;		// impact in direction of gravity
		//console.log(Math.abs(mainImpact));
 		if (Math.abs(mainImpact) > HEAVYIMPACT)			// main impact, not lesser ones as it settles  
		{
			//soundCollision();
		}
	});
	BALLS[BALL_COUNT] = [ball];
	BALL_COLORS[ball] = BALL_CHOICE;
	if (BALL_CHOICE == 3){
	    WHITE = BALL_COUNT;
	}
	BALL_COUNT += 1;
	ABWorld.scene.add(ball);
	LIMIT[BALL_CHOICE] -= 1;
 }
}

function removeBall(ball)
{
    
    ABWorld.scene.remove(ball);
}

var OURKEYS = [49, 50, 51, 52];
function ourKeys(event) {return(OURKEYS.includes(event.keyCode));}
function keyHandler(event)           
{
    if      (! ABRun.runReady)          {return true;}            // not ready yet 
    // if not handling this key, send it to default: 
    if      (! ourKeys(event))          {return true;}
    // else handle it and prevent default:
    if      ( event.keyCode == 49 )     {selectBall(0);}
    else if ( event.keyCode == 50 )     {selectBall(1);} 
    else if ( event.keyCode == 51 )     {selectBall(2);}
    else if ( event.keyCode == 52 )     {selectBall(3);} 
    event.stopPropagation(); event.preventDefault(); return false;
}

var startX, startY; 
var dragevents;         // number of events in the current drag 

function click(event)
{
    var object = (ABWorld.hitsObjectPoint(event.x, event.y, GROUND));  // returns null if no hit
    if (object !== null){
        createBall(object.x, object.y, object.z);}}

//for future drag functionality
//function initDrag (x, y)
//{}
//function drag (x, y)
//{}

function pageChange(x){
    PAGE_SELECT = x;
}
    //A corner view
    // moveCamera(50,40,200) // moveCamera(50,40,-200) // moveCamera(-50,40,-200) //moveCamera(-50,40, 200)
    //ABWorld.camera.position.set(x,y,z);
    //ABWorld.camera.up = new THREE.Vector3(0,0,1);
    //ABWorld.camera.lookAt(new THREE.Vector3(0,0,0));
    
    //look flat down
    //moveCamera(0,350,0)
    //ABWorld.camera.position.set(x,y,z);
    //ABWorld.camera.up = new THREE.Vector3(0,0,1);
    //ABWorld.camera.lookAt(new THREE.Vector3(0,0,0));
    
    //template code
    //camera.position.set(30,0,0);
    //camera.up = new THREE.Vector3(0,0,1);
    //camera.lookAt(new THREE.Vector3(0,0,0));
    //scene.add( camera ); 


function cameraFlatDown(){
    ABWorld.camera.position.set(0,100,0);
    //ABWorld.camera.up = new THREE.Vector3(0,0,1);
    //ABWorld.camera.lookAt(new THREE.Vector3(0,0,0));
}

function cameraSomeCornerPocket(){
    //ABWorld.camera.up = new THREE.Vector3(0,0,1);
    //ABWorld.camera.lookAt(new THREE.Vector3(0,0,0));
    if (cameraPocketCounter % 4 === 0){
        ABWorld.camera.position.set(50,50,30);
    }
    else if (cameraPocketCounter % 4 == 1){
        ABWorld.camera.position.set(50,50,-30);
    }
    else if(cameraPocketCounter % 4 == 2){
        ABWorld.camera.position.set(-50,50,-30);
    }
    else if(cameraPocketCounter % 4 == 3){
       ABWorld.camera.position.set(-50,50, 30); 
    }
    cameraPocketCounter = cameraPocketCounter + 1;
}



function initPreOptions()
{
    $("#user_span1").html("<p align=\"center\">Page: <b>"+ PAGE_SELECT + "</b></p>");
    $("#user_span2").html("<p align=\"center\"><button id='page1'>Page 1</button> <button id='page2'>Page 2</button> <button id='page3'>Page 3</button></p>");
    $("#user_span4").html(line4_1);
    $("#user_span6").html(line6_1);
    s = "<p align=\"center\"><button id='basicSetUp'>Basic Set Up</button></p>";
    $("#user_span9").html(s);
    s = "<p align=\"center\"><button id='hitBall'>GO!</button></p>";
    $("#user_span10").html(s);
    $(document).ready(function(){
        $("#page1").click(function(){pageChange(1);});
        $("#page2").click(function(){pageChange(2);});
        $("#page3").click(function(){pageChange(3);});
    });
    //place holders
    document.getElementById("basicSetUp").addEventListener("click", function() { basicSetUp();}, false);
    document.getElementById("hitBall").addEventListener("click", function() { hitBall();}, false);
}

function initPostOptions()
{
    
}

function updatePreHUD()
{

    $("#user_span1").html("<p align=\"center\">Page: <b>"+ PAGE_SELECT + "</b></p>");
    if (PAGE_SELECT == 1){
        $("#user_span3").html("<p align=\"center\">Ball Selected: <b>"+ BALL_TYPE[BALL_CHOICE] + "</b></p>");
        $("#user_span5").html("<p align=\"center\">The Colour you are playing as is set to: <b>" + YOURCOLOR + "</b></p>");
        if (CURRENT_PAGE !== PAGE_SELECT){
            $("#user_span4").html(line4_1);
            $("#user_span6").html(line6_1);
            
            $(document).ready(function(){
                $("#yellowButton").click(function(){selectBall(0);});
                $("#redButton").click(function(){selectBall(1);});
                $("#blackButton").click(function(){selectBall(2);});
                $("#whiteButton").click(function(){selectBall(3);});
                $("#yourNButton").click(function(){setDifficulty(setColor("None"));});
                $("#yourYButton").click(function(){setDifficulty(setColor("Yellow"));});
                $("#yourRButton").click(function(){setDifficulty(setColor("Red"));});
            });   
        }
    }
    
    else if (PAGE_SELECT == 2){
        $("#user_span3").html("<p align=\"center\">Ground Friction: <b>" + Number.parseFloat(GROUND_FRICTION).toFixed(2) + "</b></p>");
        $("#user_span5").html("<p align=\"center\">Power: <b>" + MIN_POWER + " to " + MAX_POWER + "</b></p>");
        if (CURRENT_PAGE !== PAGE_SELECT){
            $("#user_span4").html(line4_2);
            $("#user_span6").html(line6_2);
            $(document).ready(function(){
                $("#decreaseFrictionButton").click(function(){decreaseFriction();});
                $("#increaseFrictionButton").click(function(){increaseFriction();});
                $("#decreasePowerMinButton").click(function(){decreasePowerMin();});
                $("#increasePowerMinButton").click(function(){increasePowerMin();});
                $("#decreasePowerMaxButton").click(function(){decreasePowerMax();});
                $("#increasePowerMaxButton").click(function(){increasePowerMax();});
            });   
        }
    }
    
    else {
        $("#user_span3").html("<p align=\"center\">The Difficultly is set to: <b>" + difficulty + "</b></p>");
        $("#user_span5").html("<p align=\"center\">The Camera Settings :</p>");
        if (CURRENT_PAGE !== PAGE_SELECT){
            $("#user_span4").html(line4_3);
            $("#user_span6").html(line6_3);
            $(document).ready(function(){
                $("#easyButton").click(function(){setDifficulty("Easy");});
                $("#mediumButton").click(function(){setDifficulty("Medium");});
                $("#hardButton").click(function(){setDifficulty("Hard");});
                $("#cameraFlatButton").click(function(){cameraFlatDown();});
                $("#cameraCornerButton").click(function(){cameraSomeCornerPocket();});
            });   
        }
    }
    CURRENT_PAGE = PAGE_SELECT;
}

// --- public interface ----------------------------------------------------------------------

	
this.newRun = function() 
{
	ABWorld.init3d(startRadius, maxRadius, SKYCOLOR); 			// sets up renderer, scene, camera
	initPreOptions();
 // can adjust renderer:
	ABWorld.renderer.shadowMap.enabled = true;
 // scene is Physijs.Scene, not THREE.Scene
 // can adjust scene - change gravity from default:
	ABWorld.scene.setGravity ( gravity );
	loadResources();	// asynchronous file loads 
						// calls initScene() when all done 
	ABWorld.lookat.copy ( ABWorld.scene.position );  
	ABWorld.scene.simulate();		// Physics simulate - runs on independent timer to AB nextStep
	// user actions
    document.onkeydown          = keyHandler;
    document.ondblclick         = click;
    //ABHandler.initTouchDrag   = initDrag;
    //ABHandler.touchDrag       = drag
    //ABHandler.initMouseDrag   = initDrag;
    //ABHandler.mouseDrag       = drag
};

this.nextStep = function()		// not used 
{
    if (CALCULATED === false){
        updatePreHUD();}
    else {
        initPostOptions();
        updatePostHUD();}
};

}

	
// --- Splash screen --------------------------------------------------------------

	AB.newSplash ("Pool Predictor");	
	// when user clicks/touches button on splash screen, audio starts and run starts:
	$("#splashbutton").click (function()        
	{
		AB.removeSplash();			// remove splash screen 
		splashClicked = true;
	});