// Cloned by Enhanced on 2 Aug 2018 from World "Rythm of the night" by SinfulSalad // Please leave this clone trail here.// ==== Rythm of the night ===============================================================================================// (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.// ==================================================================================================================// ===================================================================================================================// === 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.clockTick =20;// many frames per second, with small moves, looks best
AB.screenshotStep =1500;
AB.maxSteps =100000;const SKYCOLOR ="#000000";//the three images that represents the player (in this version it's three smileys)var PLAYER_IMG =['/uploads/sinfulsalad/neutralplayer.png','/uploads/sinfulsalad/okplayer.png','/uploads/sinfulsalad/badplayer.png'];//the layers that constitute the background const BACKGROUND_IMG =['/uploads/sinfulsalad/neoncity.jpg','/uploads/sinfulsalad/citycropped.png','/uploads/sinfulsalad/neonground.png'];//the scrolling speed of each layer.//For more on how the background works, check out the "Scrolling Background"//world of Enhancedconst BACKGROUND_SPEED =[1,2,4];//the images for the 4 arrowsvar OBSTACLES_IMG =['/uploads/sinfulsalad/left.png','/uploads/sinfulsalad/up.png','/uploads/sinfulsalad/right.png','/uploads/sinfulsalad/down.png',];//the image of the heart var LIFE_IMG =['/uploads/sinfulsalad/heart.png'];// ===================================================================================================================// === End of tweaker's box ==========================================================================================// ===================================================================================================================// You will need to be some sort of JavaScript programmer to change things below the tweaker's box.//generate a random float between [ A ; B [function randomfloatAtoB ( A, B ){return( A +(Math.random()*(B-A)));}//returns a whole number in from the [A,B[ rangefunction randomintAtoB ( A, B ){return(Math.floor ( randomfloatAtoB ( A, B )));}functionWorld(){//------------------------ GLOBAL VARIABLES --------------------------------//will contain the context of the canvasvar ctx;//will keep track of how to draw the backgroundvar backgroundPos =[];var positionOffset;//here is stored the sequence of arrows of the levelvar obstacles =[];//the length of the sequencevar nbObstacles;//the variable level is always worth 5 more than the level the player//is actually playing. For exemple, when he is playing level 1, this variable//contains the number 6.var level;//the movement speed of the levelvar speedMult;//describes which type of arrows will be present in the level.//it can take the values 38 to 41. The html keycode of the arrow keys goes//from 37 to 40. 'actionsPossible = 38' means that only the arrowkey 37 will//be present, 'actionsPossible = 39' means that both 37 and 38 will be present//'actionsPossible = 40' means that 37 38 and 39 will be present, etc...var actionsPossible;//used to code what happens when the game ends.//It can take the values 'going' and 'end'var gameState;//keep track of what input is needed from the player at any given momentvar actionRequired;//keep track of wether the player did what was expected from himvar success;//number of lives of the playervar life;//serves only to keep track of when to display the sad smiley.//unhappy is a whole number that is decremented at each step, down to zero.//whenever 'unhappy > 0', the sad face is displayedvar unhappy;//------------------------- INIT FUNCTIONS ---------------------------------//properly load all the imagesfunction initIMG(){var img;//backgroundfor(var i =0; i<BACKGROUND_IMG.length ; i++){
img =newImage();
img.src = BACKGROUND_IMG[i];
BACKGROUND_IMG[i]= img;
backgroundPos.push(0);}//arrowsfor(i =0; i<OBSTACLES_IMG.length ; i++){
img =newImage();
img.src = OBSTACLES_IMG[i];
OBSTACLES_IMG[i]= img;}//player's smileyfor(i =0; i<PLAYER_IMG.length ; i++){
img =newImage();
img.src = PLAYER_IMG[i];
PLAYER_IMG[i]= img;}//heart
img =newImage();
img.src = LIFE_IMG;
LIFE_IMG = img;}//setup the program so it listens to the player's input on the arrow keysfunction keyDownHandler(e){if(e.keyCode ==37|| e.keyCode ==38|| e.keyCode ==39|| e.keyCode ==40){if(actionRequired !==undefined&& e.keyCode == obstacles[actionRequired])
success =true;else unhappy =10;}}//-------------------------- ENGINE FUNCTIONS ------------------------------function setupLevel(){
life =3;//resets the drawing position of the obstacles
positionOffset =0;
level++;var speedDown =0;//on level 1, allows 2 types of arrows to be displayedif(level >=6){
actionsPossible =39;}//on level 10, slows the game a little bit, and allows 3 types of arrows//to be displayedif(level >=15){
speedDown =-0.6;
actionsPossible =40;}//on level 20, slows the game a little bit, and allows the 4 types of arrows//to be displayedif(level >=25){
speedDown =-1.2;
actionsPossible =41;}//sets the right speed for the current level
speedMult =(1+level/8)+speedDown;//generate the obstacles that will be part of this level
generateLevel();}//generate the obstacles that will be part of this level, and store them into//obstacles[].//the levels are generated procedurally.function generateLevel(){//calculate the length of the sequence depending on the level
nbObstacles =10+Math.floor(level/3);//resets the array
obstacles =[];//link each step of the sequence to either a specific arrow (represented//by the keycode of that arrow)(70% of the time) either nothing (represented//by the number -1)(30% of the time)for(var i =0; i<nbObstacles ; i++){if(randomintAtoB(0,10)>2)
obstacles.push(randomintAtoB(37, actionsPossible));else obstacles.push(-1);//this additional -1 push is here to put a little bit of space between//each obstacle
obstacles.push(-1);}}function drawBackground(){//skyscrapers
backgroundPos[0]-= speedMult*BACKGROUND_SPEED[0]*AB.clockTick/30;if(backgroundPos[0]<-threeworld.canvas.width)
backgroundPos[0]=0;
ctx.drawImage( BACKGROUND_IMG[0], backgroundPos[0],0, threeworld.canvas.width,400);
ctx.drawImage( BACKGROUND_IMG[0], threeworld.canvas.width+backgroundPos[0],0, threeworld.canvas.width,400);//low city
backgroundPos[1]-= speedMult*BACKGROUND_SPEED[1]*AB.clockTick/30;if(backgroundPos[1]<-threeworld.canvas.width)
backgroundPos[1]=0;
ctx.drawImage( BACKGROUND_IMG[1], backgroundPos[1], threeworld.canvas.height-500, threeworld.canvas.width,280);
ctx.drawImage( BACKGROUND_IMG[1], threeworld.canvas.width+backgroundPos[1], threeworld.canvas.height-500, threeworld.canvas.width,280);//floor
backgroundPos[2]-= speedMult*BACKGROUND_SPEED[2]*AB.clockTick/30;if(backgroundPos[2]<-threeworld.canvas.width)
backgroundPos[2]=0;
ctx.drawImage( BACKGROUND_IMG[2], backgroundPos[2], threeworld.canvas.height-250, threeworld.canvas.width,250);
ctx.drawImage( BACKGROUND_IMG[2], threeworld.canvas.width+backgroundPos[2], threeworld.canvas.height-250, threeworld.canvas.width,250);}function drawPlayer(){var image;//if the player did what whas expected of him, display the happy smileyif(success)
image = PLAYER_IMG[1];//display the sad face whenever the player does an unexpected inputelseif(unhappy >0)
image = PLAYER_IMG[2];//display the neutral smileyelse
image = PLAYER_IMG[0];
ctx.drawImage( image,220, threeworld.canvas.height-210,100,100);
ctx.fillRect(430, threeworld.canvas.height-195,5,70);}//draw the arrows AND calculate new positionfunction drawObstacles(){for(var i =0; i < obstacles.length ; i++){//if that step of the sequence corresponds to an arrowif(obstacles[i]>=0){
ctx.drawImage(OBSTACLES_IMG[obstacles[i]-37], threeworld.canvas.width-positionOffset+50*i-10, threeworld.canvas.height-180,70,50);//if that step is finishedif(threeworld.canvas.width-positionOffset+50*i+10<430-50){//if that step was the 'current step' at the previous frameif(actionRequired == i){//since this step just ended, the action expected from the//player is reseted, so is the fact that he did what was needed.//Plus he looses a heart if he missed the arrowif(!success)
loseLife();else success =false;
actionRequired =undefined;}}//else if this is the current stepelseif(threeworld.canvas.width-positionOffset+50*i <435)
actionRequired = i;}//the value of an obstacle is set to -2 if the player got it wrong//if that value is -2, replace the arrow by a red squareif(obstacles[i]==-2){
ctx.fillRect(threeworld.canvas.width-positionOffset+50*i, threeworld.canvas.height-180,50,50);}}}function drawLife(){for(var i =0; i < life ; i++)
ctx.drawImage(LIFE_IMG,150, threeworld.canvas.height-140-50*i,50,50);}function loseLife(){
life--;
obstacles[actionRequired]=-2;//draws a red splash screen for a frame
ctx.fillRect(0,0, canvas.width, canvas.height);if(life ===0)
gameState ='end';}//---------------------------- RUN FUNCTIONS -------------------------------this.newRun =function(){//init world and context
threeworld.init ( SKYCOLOR );
ctx = threeworld.getContext ("2d");
initIMG();//initialisation of the global variables
gameState ='going';
unhappy =0;
positionOffset =0;
actionRequired =undefined;
success =false;
life =3;//since the id of the level played by the player is always the value of the level variable//minus 5, and since the level variable is incremented at the start of generateLevel(),//initialising this variable with the value of 4 means that the first level played//will be level 0
level =4;
speed =0;
actionsPossible =38;
setupLevel();//initialisation of the font
ctx.fillStyle ='#FF2222';
ctx.textAlign ='center';
ctx.font ='bold 70px Arial';
document.onkeydown = keyDownHandler;//initialisation of the save&load featureif( AB.runloggedin ){// Definitely can save, not sure if can restore:
$("#user_span2").html (" <button onclick='AB.saveData();' >Save your work</button> ");// Check if any data exists, if so make restore button:
AB.queryDataExists();// will call World.queryDataExists when done }else
$("#user_span2").html(" <p align=\"center\"> <b> To save your work, go to <br>the World page and run this \"logged in\". </b> </p> ");};this.nextStep =function(){
$("#user_span3").html("<p align=\"center\">hit the correct arrow key when <br> the arrow reaches the red line</p>");if(gameState =='going'){
drawBackground();
drawObstacles();if(positionOffset > threeworld.canvas.width-430+100+nbObstacles*100){
setupLevel();}
drawPlayer();
drawLife();if(unhappy >0)
unhappy -=1;
positionOffset += speedMult*BACKGROUND_SPEED[BACKGROUND_SPEED.length-1]*AB.clockTick/30;
ctx.fillText('level '+(level-5),500,100);}elseif(gameState =='end'){
drawBackground();
ctx.fillText('GAME OVER', threeworld.canvas.width/2+100,180);}};//----------------------- SAVE AND LOAD FUNCTIONS --------------------------//this function saves the more advanced level you reached.//Since the saveDate don't seem to work with single digit numbers, I add 10//to the level, and then substract 10 when I load the data from the server.//Finally, I substract 1, because the level variable is incremented at the start//of the generateLevel() functionthis.saveData =function(){// if no restore button, can make one now
$("#user_span1").html (" <button onclick='AB.restoreData();' >Restore your work</button> ");// console.log ( "Saving " + BLOCKARRAY.length + " blocks to server" );return( level+10);};this.restoreData =function( a ){
level = a-11;
setupLevel();};this.queryDataExists =function( exists ){if( exists )
$("#user_span1").html (" <button onclick='AB.restoreData();' >Restore your work</button> ");};}