Code viewer for World: 2PVEPong
// Cloned by Enhanced on 18 Jun 2018 from World "Revamped Space Pong" by SinfulSalad 
// Please leave this clone trail here.
 

// Cloned by SinfulSalad on 12 Jun 2018 from World "Space Pong" by Igor Strelkov 
// Please leave this clone trail here.


//-------------------------- TWEAKER'S BOX: ------------------------------------

AB.drawRunControls = false;
threeworld.drawCameraControls = false;
AB.clockTick = 33;                     // speed of run - move things every n milliseconds

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 gridsize = 190;					// number of squares along side of world	   

const squaresize = 100;					// size of square in pixels
const playersize = 3000;				// size of player in pixels
const SPEED_MULTIPLIER = 2.3;           //speed of the ball
const TIME_BEFORE_END = 80;            //number of seconds before the time mode ends
const SCORE_NEEDED = 5;                 //number of points needed to win the score mode

//difficulty multiplicators for each difficulty :
//this multiplicator affect the speed of the enemy's paddle
//as well as how random the direction of it's shots is
const EASY_MODE = 1.1;
const MEDIUM_MODE = 1.5;
const HARD_MODE = 1.9;

//change the files in this array to change the background displayed by the program
const skyboxTexture = ["uploads/yanni/1668695814.png", "uploads/yanni/1668695814.png", "/uploads/yanni/1668695636.png", "/uploads/yanni/1668695963.png", "uploads/yanni/1668695814.png", "uploads/yanni/1668695814.png"];

const SKYCOLOR = 0xffffcc;				// a number, not a string 
const BLANKCOLOR = SKYCOLOR ;			// make objects this color until texture arrives (from asynchronous file read)

const MAXPOS = gridsize * squaresize;
const startRadiusConst = MAXPOS * 0.7 ;		// distance from centre to start the camera at
const skyboxConst = MAXPOS * 3;
const maxRadiusConst = MAXPOS * 100 ;		// maximum distance from camera we will render things 

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 World() {
	this.endCondition = false;				  
    var edges = [];
    var fileArray = [];
    var textureArray = [];
    var player;
    var player2;
    var enemy;
    var ball;
    
    var difficulty = "EASY";
    var gameMode = "SCORE";
    var ready = "set";
    var readyr = false;
    var timer = AB.clockTick*TIME_BEFORE_END;
    
    //is used to display the final score, or the start button, or the timer
    var str7 = "<p align=\"center\"><button id='leftButton', style=\"height:50px;width:100px\"><b>Move Left</b></button><button id='rightButton', style=\"height:50px;width:100px\"><b>Move Right</b></button></p>"
    var str8 = "<p align=\"center\"><button id='stopButton', style=\"height:50px;width:100px\"><b>Stop Moving</b></button></p>"
    var str9 = "<p align=\"center\"><button id='left2Button', style=\"height:50px;width:100px\"><b>Move Left</b></button><button id='right2Button', style=\"height:50px;width:100px\"><b>Move Right</b></button></p>"    
    var str10 = "<p align=\"center\"><button id='stop2Button', style=\"height:50px;width:100px\"><b>Stop Moving</b></button></p>"
    var str11 = "<p align=\"center\"><button id='startButton', style=\"height:30px;width:100px;background-color:#FF0000\"><b>START</b></button></p>"
    
    function initSkybox() 
    {
        var materialArray = [
     	( new THREE.MeshBasicMaterial ( { map: textureArray[1], side: THREE.BackSide } ) ),
     	( new THREE.MeshBasicMaterial ( { map: textureArray[2], side: THREE.BackSide } ) ),
     	( new THREE.MeshBasicMaterial ( { map: textureArray[3], side: THREE.BackSide } ) ),
     	( new THREE.MeshBasicMaterial ( { map: textureArray[4], side: THREE.BackSide } ) ),
     	( new THREE.MeshBasicMaterial ( { map: textureArray[5], side: THREE.BackSide } ) ),
     	( new THREE.MeshBasicMaterial ( { map: textureArray[6], 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 );						// We are inside a giant cube
    }
    
    function initTextures()
    {
        fileArray.push('/uploads/yanni/1669226832.png');
        fileArray.push(skyboxTexture[0]);
        fileArray.push(skyboxTexture[1]);
        fileArray.push(skyboxTexture[2]);
        fileArray.push(skyboxTexture[3]);
        fileArray.push(skyboxTexture[4]);
        fileArray.push(skyboxTexture[5]);
        fileArray.push("/uploads/yanni/1669224906.png");
        fileArray.push("/uploads/yanni/1668695636.png");
        fileArray.push("/uploads/yanni/1664098041.png");
        fileArray.push("/uploads/yanni/1669227184.png");
        
        textureArray = [fileArray.length];
        for (let i = 0; i < fileArray.length; i++)
        {
            textureArray[i] = new THREE.ImageUtils.loadTexture( fileArray[i] );
        }
    	for ( let i = 0; i < textureArray.length; i++ )    // for all textures 
    	{ 
         textureArray[i].minFilter = THREE.LinearFilter;
    	}
    }
    
    function initEdges()
    {
      for (var i = -gridsize*squaresize/2 ; i <= gridsize*squaresize/2; i += squaresize )
      {
        buildCube(i,-gridsize*squaresize/2);
        buildCube(i, gridsize*squaresize/2);
        buildCube(-gridsize*squaresize/2, i);
        buildCube(gridsize*squaresize/2, i);
      }
        threeworld.camera.position.set(0,14000,0);
        threeworld.camera.rotation.set(0,0,0);
    }

    function buildCube(x, z)
    {
        var shape = new THREE.BoxGeometry( squaresize, squaresize, squaresize );       
        var cube = new THREE.Mesh( shape );
        cube.position.x = x;
        cube.position.z = z;
        threeworld.scene.add(cube);
        cube.material = new THREE.MeshBasicMaterial({ map: textureArray[0] });
        edges.push(cube);
    }

	function initBall()
	{
	    var sphereMaterial = new THREE.MeshLambertMaterial({color: 0xD43001});
        ball = new THREE.Mesh(new THREE.SphereGeometry(200,100,100), sphereMaterial);
	    ball.material =  new THREE.MeshBasicMaterial( { map: textureArray[7] } );  
	    
	    ball.position.x = 0;
        ball.position.y = 0;
        ball.position.z = 0;
        
        //angle (radian), zero meaning it moves towards the players side
        ball.direction = Math.PI;
        
        //is increased each time there is contact with the ball
        ball.velocity = SPEED_MULTIPLIER;
        threeworld.scene.add(ball);
	}

		function resetBall()
	{
	    ball.position.x = 0;
	    ball.position.z = 0;
	    ball.direction = Math.PI;
	    ball.velocity = SPEED_MULTIPLIER;
	}
	
	function initPaddles()
	{
	    var shape = new THREE.BoxGeometry( playersize, squaresize, 200);			 
        player = new THREE.Mesh( shape );
        player2 = new THREE.Mesh( shape );
        enemy = new THREE.Mesh( shape );
        
        player.material =  new THREE.MeshBasicMaterial( { map: textureArray[8] } );
        player2.material =  new THREE.MeshBasicMaterial( { map: textureArray[9] } );
        enemy.material =  new THREE.MeshBasicMaterial( { map: textureArray[10] } );
        
        player.position.x = -5000;
        player.position.y = 0;
        player.position.z = gridsize*squaresize/2-squaresize;
        player.movement = 0;
        player.score = 0;

        player2.position.x = 5000;
        player2.position.y = 0;
        player2.position.z = gridsize*squaresize/2-squaresize;
        player2.movement = 0;
        
        enemy.position.x = 0;
        enemy.position.y = 0;
        enemy.position.z = -gridsize*squaresize/2+squaresize;
        enemy.movement = 0;
        enemy.score = 0;
        enemy.speed = 1;
        
        threeworld.scene.add(player);
        threeworld.scene.add(player2);
        threeworld.scene.add(enemy);
	}
	
	function enemyMind()
	{
	    if (enemy.position.x > ball.position.x+playersize/10) enemy.movement = -1;
	    else if (enemy.position.x < ball.position.x-playersize/10) enemy.movement = 1;
	    else enemy.movement = 0;
	}
	
	function processOpponentsMovement()
	{
	    player.position.x += player.movement*squaresize;
	    if (player.position.x > gridsize*squaresize/2-playersize/2) player.position.x = gridsize*squaresize/2-playersize/2;
	    else if (player.position.x < -gridsize*squaresize/2+playersize/2) player.position.x = -gridsize*squaresize/2+playersize/2;
	    
	    player2.position.x += player2.movement*squaresize;
	    if (player2.position.x > gridsize*squaresize/2-playersize/2) player2.position.x = gridsize*squaresize/2-playersize/2;
	    else if (player2.position.x < -gridsize*squaresize/2+playersize/2) player2.position.x = -gridsize*squaresize/2+playersize/2;

	    enemy.position.x += enemy.speed*enemy.movement*squaresize;
	    if (enemy.position.x > gridsize*squaresize/2-playersize/2) enemy.position.x = gridsize*squaresize/2-playersize/2;
	    else if (enemy.position.x < -gridsize*squaresize/2+playersize/2) enemy.position.x = -gridsize*squaresize/2+playersize/2;
	}
	
	function processBallMovement()
	{
	    newX = ball.position.x + squaresize*ball.velocity*Math.sin(ball.direction);
	    newZ = ball.position.z + squaresize*ball.velocity*Math.cos(ball.direction);
	    
	    //collision bottom side
	    if (newZ > gridsize*squaresize/2-squaresize)
	    {
	        ball.velocity += 0.1;
	        ball.direction = Math.PI-ball.direction;
	        processLoss(player, player2);
	    }
	    //collision top side
	    else if (newZ < -gridsize*squaresize/2+squaresize)
	    {
	        ball.velocity += 0.1;
	        ball.direction = -Math.PI-ball.direction;
	        processLoss(enemy, enemy);
	    }
	    //collision left and right
	    else if (newX > gridsize*squaresize/2-squaresize || newX < -gridsize*squaresize/2+squaresize)
	    {
	        ball.velocity += 0.1;
	        ball.direction = -ball.direction;
	    }
	    ball.position.x += squaresize*ball.velocity*Math.sin(ball.direction);
	    ball.position.z += squaresize*ball.velocity*Math.cos(ball.direction);
	}
	
	function processLoss(opponent, opponent2)
	{
	    if ((opponent.position.x > ball.position.x+playersize/2 || opponent.position.x < ball.position.x-playersize/2) && (opponent2.position.x > ball.position.x+playersize/2 || opponent2.position.x < ball.position.x-playersize/2))
	    {
	        opponent.score -= 1;
	        resetBall();
	    }
	    else
	    {
	        if (opponent.speed !== undefined)
	        {
	            ball.direction += (opponent.speed/1.5+0.5)*0;
	            ball.velocity += 0.1;
	        }
	        else if (opponent.position.x > ball.position.x+playersize/8)
	        {
	            ball.direction += Math.PI/8;
	            ball.velocity += 0.1;
	        }
	        
	        else if (opponent.position.x < ball.position.x-playersize/8)
	        {
	            ball.direction -= Math.PI/8;
	            ball.velocity += 0.1;
	        }
	    }
	}
	
	function updateScore()
	{
	    var playerScore = -enemy.score;
	    var enemyScore = -player.score;
	    var str = "<p align=\"center\"><font size=\"+2\"><b>Player(s)    "+playerScore+" - "+enemyScore+"    Enemy</b></font></p>";
	    $("#user_span5").html( str );
	}
	
	function initOptions()
	{
	    $("#user_span1").html( str9 );
     	$("#user_span2").html( str10 );
	    $("#user_span3").html( "<p align=\"center\">Difficulty settings : <b>EASY</b></p>" );
	    var s = "<p align=\"center\"><button onclick='skull();'id='easyButton'>Easy</button> <button id='mediumButton'>Medium</button> <button id='hardButton'>Hard</button></p>";
     	$("#user_span4").html( s );
     	$("#user_span7").html( str11 );
     	$("#user_span8").html( "<p align=\"center\"><font color=\"#C9C9C9\"><b>"+timer/AB.clockTick+" seconds remaining</b></font><p></b></p>" );
     	$("#user_span9").html( str7 );
     	$("#user_span10").html( str8 );
     	
        document.getElementById("easyButton").addEventListener("click", setToEasy);
        document.getElementById("mediumButton").addEventListener("click", setToMedium);
        document.getElementById("hardButton").addEventListener("click", setToHard);
        document.getElementById("leftButton").addEventListener("click", moveLeft);
        document.getElementById("rightButton").addEventListener("click", moveRight);
        document.getElementById("stopButton").addEventListener("click", moveStop);
        document.getElementById("left2Button").addEventListener("click", moveLeft2);
        document.getElementById("right2Button").addEventListener("click", moveRight2);
        document.getElementById("stop2Button").addEventListener("click", moveStop2);
        document.getElementById("startButton").addEventListener("click", start);
	}
	
	function updateHUD()
	{
	    $("#user_span3").html( "<p align=\"center\">Difficulty settings : <b>"+difficulty+"</b></p>" );
	    updateScore();
	    if (gameMode === "TIME")
	    {
	        $("#user_span8").html( "<p align=\"center\"><b>"+Math.floor(timer/AB.clockTick)+" seconds remaining</b><p></b></p>" );
	    }
	    else
	    {
	        $("#user_span8").html("<p align=\"center\"><b>"+Math.floor(timer/AB.clockTick)+" seconds remaining</b><p></b></p>");
	    }
	}
    
    function endGame()
    {
        if (timer === 0)
        {
            ready = "end";
            updateHUD();
            if (player.score < enemy.score) str6 = "<p align=\"center\"><font color=\"red\"><b>YOU LOSE!</b></font><p>";
            else if (player.score > enemy.score) str6 = "<p align=\"center\"><font color=\"green\"><b>YOU WIN!</b></font><p>";
            else str6 = "<p align=\"center\"><b>IT'S A DRAW!</b><p>";
            $("#user_span7").html( str6 );
        }
    }
    
	this.newRun = function()
	{
	    threeworld.init3d ( startRadiusConst, maxRadiusConst, SKYCOLOR  );
	    initTextures();
	    initSkybox();
	    initEdges();
	    initPaddles();
	    initBall();
	    initOptions();
	};

	this.nextStep = function()		 
	{
	    if (ready !== "end") updateHUD();
	    if (ready === "start") 
	    {
	        processBallMovement();
            enemyMind();
            processOpponentsMovement();
            endGame();
            timer--;
	    }
	};
	
	//-----------------------------------------------------------------------------------------
	
	AB.socketStart();
	
	function setToEasy()
    {
        enemy.speed = EASY_MODE;
        difficulty = "EASY";
        send(difficulty, player.position.x, player.movement, player2.position.x, player2.movement, enemy.movement, enemy.position.x, ball.direction, ball.velocity, ball.position.x, ball.position.y, ball.position.z, timer, player.score, enemy.score);
    }
    
    function setToMedium()
    {
        enemy.speed = MEDIUM_MODE;
        difficulty = "MEDIUM";
        send(difficulty, player.position.x, player.movement, player2.position.x, player2.movement, enemy.movement, enemy.position.x, ball.direction, ball.velocity, ball.position.x, ball.position.y, ball.position.z, timer, player.score, enemy.score);
    }
    
    function setToHard()
    {
        enemy.speed = HARD_MODE;
        difficulty = "HARD";
        send(difficulty, player.position.x, player.movement, player2.position.x, player2.movement, enemy.movement, enemy.position.x, ball.direction, ball.velocity, ball.position.x, ball.position.y, ball.position.z, timer, player.score, enemy.score);
    }
    
    function moveRight()
    {
        player.movement = 1;
        player.position.x += player.movement*squaresize;
	    if (player.position.x > gridsize*squaresize/2-playersize/2) player.position.x = gridsize*squaresize/2-playersize/2;
	    else if (player.position.x < -gridsize*squaresize/2+playersize/2) player.position.x = -gridsize*squaresize/2+playersize/2;
	    
	    send(difficulty, player.position.x, player.movement, player2.position.x, player2.movement, enemy.movement, enemy.position.x, ball.direction, ball.velocity, ball.position.x, ball.position.y, ball.position.z, timer, player.score, enemy.score);
    }
    
    function moveRight2()
    {	    
	    player2.movement = 1;
        player2.position.x += player2.movement*squaresize;
	    if (player2.position.x > gridsize*squaresize/2-playersize/2) player2.position.x = gridsize*squaresize/2-playersize/2;
	    else if (player2.position.x < -gridsize*squaresize/2+playersize/2) player2.position.x = -gridsize*squaresize/2+playersize/2;
	    
	    send(difficulty, player.position.x, player.movement, player2.position.x, player2.movement, enemy.movement, enemy.position.x, ball.direction, ball.velocity, ball.position.x, ball.position.y, ball.position.z, timer, player.score, enemy.score);
    }
    
    function moveLeft()
    {
        player.movement = -1;
        player.position.x += player.movement*squaresize;
	    if (player.position.x > gridsize*squaresize/2-playersize/2) player.position.x = gridsize*squaresize/2-playersize/2;
	    else if (player.position.x < -gridsize*squaresize/2+playersize/2) player.position.x = -gridsize*squaresize/2+playersize/2;
	    
	    send(difficulty, player.position.x, player.movement, player2.position.x, player2.movement, enemy.movement, enemy.position.x, ball.direction, ball.velocity, ball.position.x, ball.position.y, ball.position.z, timer, player.score, enemy.score);
    }
    
	function moveLeft2()
    {    
	    player2.movement = -1;
        player2.position.x += player2.movement*squaresize;
	    if (player2.position.x > gridsize*squaresize/2-playersize/2) player2.position.x = gridsize*squaresize/2-playersize/2;
	    else if (player2.position.x < -gridsize*squaresize/2+playersize/2) player2.position.x = -gridsize*squaresize/2+playersize/2;
	    
	    send(difficulty, player.position.x, player.movement, player2.position.x, player2.movement, enemy.movement, enemy.position.x, ball.direction, ball.velocity, ball.position.x, ball.position.y, ball.position.z, timer, player.score, enemy.score);
    }
    
    function moveStop()
    {
        player.movement = 0;
        send(difficulty, player.position.x, player.movement, player2.position.x, player2.movement, enemy.movement, enemy.position.x, ball.direction, ball.velocity, ball.position.x, ball.position.y, ball.position.z, timer, player.score, enemy.score);
    }
    
    function moveStop2()
    {
        player2.movement = 0;
        send(difficulty, player.position.x, player.movement, player2.position.x, player2.movement, enemy.movement, enemy.position.x, ball.direction, ball.velocity, ball.position.x, ball.position.y, ball.position.z, timer, player.score, enemy.score);
    }
    
    function start()
    {
        readyr = true;
        ready = "start";
        send(difficulty, player.position.x, player.movement, player2.position.x, player2.movement, enemy.movement, enemy.position.x, ball.direction, ball.velocity, ball.position.x, ball.position.y, ball.position.z, timer, player.score, enemy.score);
    }
    
    
	function send()
	{
	    const data = {difficulty: difficulty, playerposition: player.position.x, playermovement: player.movement, player2position: player2.position.x, player2movement: player2.movement, enemymovement: enemy.movement, enemyposition: enemy.position.x, balldirection: ball.direction, ballvelocity: ball.velocity, ballx: ball.position.x, bally: ball.position.y, ballz: ball.position.z, time: timer, playerscore: player.score, enemyscore: enemy.score};
        AB.socketOut ( data );        // server gets this, and sends the data to all clients running this World
	}
	
	AB.socketIn = function(data)
    {
        if ( ! readyr ) {
            location.reload();
            readyr = true;
            ready = "start";
            return;
        }
        difficulty = data.difficulty;
        player.position.x = data.playerposition;
        player.movement = data.playermovement
        player2.position.x = data.player2position;
        player2.movement = data.player2movement;
        enemy.movement = data.enemymovement;
        enemy.position.x = data.enemyposition;
        ball.direction = data.balldirection;
        ball.velocity = data.ballvelocity;
        ball.position.x = data.ballx;
        ball.position.y = data.bally;
        ball.position.z = data.ballz;
        timer = data.time
        player.score = data.playerscore;
        enemy.score = data.enemyscore;
    };
	
	this.endRun = function() {};
}

//-------------------------END OF TWEAKER'S BOX---------------------------------