diff --git a/2016 - diamond run/images/sprites.png b/2016 - diamond run/images/sprites.png new file mode 100644 index 0000000..66b61d3 Binary files /dev/null and b/2016 - diamond run/images/sprites.png differ diff --git a/2016 - diamond run/images/sprites.xcf b/2016 - diamond run/images/sprites.xcf new file mode 100644 index 0000000..b90a7e3 Binary files /dev/null and b/2016 - diamond run/images/sprites.xcf differ diff --git a/2016 - diamond run/images/sprites32-min.png b/2016 - diamond run/images/sprites32-min.png new file mode 100644 index 0000000..206adc8 Binary files /dev/null and b/2016 - diamond run/images/sprites32-min.png differ diff --git a/2016 - diamond run/index.html b/2016 - diamond run/index.html new file mode 100644 index 0000000..a636dab --- /dev/null +++ b/2016 - diamond run/index.html @@ -0,0 +1,55 @@ + + + + Diamond Run + + + +
+ + +
.
+ +
+ + + + + + + + + \ No newline at end of file diff --git a/2016 - diamond run/js/controls.js b/2016 - diamond run/js/controls.js new file mode 100644 index 0000000..551fcbf --- /dev/null +++ b/2016 - diamond run/js/controls.js @@ -0,0 +1,196 @@ +/** + * @constructor + */ +function Controls() +{ + this.mouseX = 0; + this.mouseY = 0; + this.windowLayout = false; // default initialization, will be set to actual value by onLayoutChange() + this.mouseInPlayArea = false; // true everywhere but the control bar + this.mouseInBullsEye = false; // true in the top-left view, in hacking mode + this.keyBelowMouse = -1; + this.dropTargetBelowMouse = -1; + this.mouseLeftButton=false; + this.totalClear(); +} + +Controls.prototype = { + + totalClear : function() { + this.menuClicked=-1; + this.controlUp=false; + this.controlDown=false; + this.controlEscape=false; + this.controlFire=false; + this.worldDX=0; + this.worldDY=0; + }, + + /** + * Handler for key up events + */ + onKeyUp : function(event) { + return !this.keyControl(event, false); + }, + + /** + * Handler for key down events + */ + onKeyDown : function(event) { + return !this.keyControl(event, true); + }, + + /** + * Delegated handler for keyboard events + * Records key presses and releases, for both standard keys (arrows, enter, escape) + * and configurable controls (through the controls menu) + * Returns true if the event is handled, false otherwise. + */ + keyControl : function(event, value) { + var handled = true; + var key = 0; + if (window.event) { // IE + key = window.event.keyCode; + } else { // FF, Opera,... + key = event.which; + } + + // test against static, non-redefinable keys (arrows for menu navigation, escape) + switch (key) { + case 38 : // top arrow + this.controlUp = value; + break; + case 40 : // down arrow + this.controlDown = value; + break; + case 32 : // space bar + case 13 : // enter + this.controlFire = value; + break; + case 27 : // escape + this.controlEscape = value; + break; + + default : + handled = false; + } + + return handled; + }, + + /** + * Handler for mouse up events + */ + onMouseUp : function(event) { + // main menu : select the clicked line + if (this.windowLayout) { + this.menuClicked = Math.floor(10*this.mouseY/(this.windowLayout.playArea[0]+2*this.windowLayout.playArea[2])-3); + } + + this.mouseLeftButton=false; + return true; + }, + + /** + * Handler for mouse down events + */ + onMouseDown : function(event) { + this.mouseLeftButton=true; + return true; + }, + + /** + * Handler for touch start / touch enter events + * Call onMouseMove (pointer motion handler) first to record position as the event chain begins with onTouchStart + * and there is no permanent tracking of the cursor position (unlike mouse event) + */ + onTouchStart : function(event) + { + this.onMouseMove(event); + return this.onMouseDown(event); + }, + + /** + * Handler for touch end / touch leave events + */ + onTouchEnd : function(event) + { + event.preventDefault(); + return this.onMouseUp(event); + }, + + /** + * Handler for touch move events + */ + onTouchMove : function(event) + { + event.preventDefault(); + var result = this.onMouseMove(event); + return result; + }, + + /** + * Consume a mouse click, so that the icon will not + * be activated again the next frame, until the user clicks again + * (used for double-click requirement on reset / menu icons) + */ + acknowledgeMouseClick : function() { + this.mouseLeftButton=false; + this.menuClicked = -1; + }, + + /** + * Handler for mouse/touch move events + */ + onMouseMove : function(event) { + var clientX = 0, clientY = 0; + if ('changedTouches' in event && event.changedTouches.length > 0) + { //touchmove event + clientX = event.changedTouches[0].clientX; + clientY = event.changedTouches[0].clientY; + } + if ('clientX' in event && 'clientY' in event) + { // mousemove event + clientX = event.clientX; + clientY = event.clientY; + } + if (this.windowLayout) // has been set + { + this.mouseX=clientX; + this.mouseY=clientY; + this.worldDX=(this.mouseX-this.windowLayout.playArea[1]) / this.windowLayout.playArea[0]; + this.worldDY=-(this.mouseY-this.windowLayout.playArea[2]) / this.windowLayout.playArea[0]; + + this.keyBelowMouse = -1; + this.dropTargetBelowMouse = -1; + this.mouseInPlayArea = this.mouseY < this.windowLayout.controlBar[0]; + this.mouseInBullsEye = this.mouseY < 4*this.windowLayout.playArea[0] && this.mouseX < 4*this.windowLayout.playArea[0]; + if (!this.mouseInPlayArea) { + this.keyBelowMouse = Math.floor(this.mouseX / this.windowLayout.playArea[0]); + } else { + // in game : check if above a drop point + var dz = .5 * this.windowLayout.hackingArea[0]; + for (var i=0;i<8;++i) { + var dx = this.mouseX - this.windowLayout.hackingArea[i*2+1]; + var dy = this.mouseY - this.windowLayout.hackingArea[i*2+2]; + if (dx*dx+dy*dy <= dz*dz) { + this.dropTargetBelowMouse = i; + } + } + } + } + return true; + }, + + + + /** + * Second-level handler for window resize / layout change. Called by Game. + * Keeps track of the new layout with the click areas + * @param windowLayout Object containing the layout of the different panels and toolbars + */ + onLayoutChange : function(windowLayout) { + this.windowLayout = windowLayout; + } + +} diff --git a/2016 - diamond run/js/game.js b/2016 - diamond run/js/game.js new file mode 100644 index 0000000..f15c28b --- /dev/null +++ b/2016 - diamond run/js/game.js @@ -0,0 +1,170 @@ +/** + * Main application class + * + * The state member variable defines the current screen : + * 0 : main menu + * 1 : tutorial + * 2 : game in progress + * 3 : tutorial ends + * + * @constructor + */ +function Game(controls, savedData) +{ + this.controls = controls; + this.mainMenu = new MenuDriver(3, controls); + + this.persistentData = { + }; + + this.world = new World(controls); + if (savedData.hasOwnProperty('gameProgress')) { + this.world.loadGame(savedData.gameProgress); + } + this.mainMenu.setMinLine(this.world.gameInProgress ? 0 : 1); + this.world.addSaveGameListener(this); + this.state = -1; +} + +Game.prototype = { + + + /** + * Launch the game : set the state to main menu and start the timers (main loop and rendering loop) + */ + launch : function() { + this.changeState(0); // initialize and show main menu + this.intervalId = setInterval (function() { game.mainLoop(); }, 40); + //requestAnimationFrame = requestAnimationFrame || webkitRequestAnimationFrame; + requestAnimationFrame(function() {game.renderLoop();}); + }, + + + /** + * Change the current state to the new one + * Set the transition timer to the default value (20) + * Reinitialize menus (selected item, keypresses) + */ + changeState : function(newState) { + this.controls.totalClear(); // do not forward mouse or keyboard actions to the new state + + if (newState == 0) { // entering menu + this.mainMenu.initialize(); + this.mainMenu.setMinLine(this.world.gameInProgress ? 0 : 1); + if (!this.world.gameInProgress) { + // enter the menu after ending a game : clear all progress in saved game (local storage) + delete this.persistentData.gameProgress; + this.storeData(); + } + } + /* + if (newState == 1) { // entering tutorial + this.world.startTutorial(); + }*/ + this.state = newState; + + }, + + + /** + * Main loop, actions only, no rendering + * Performs all the model edition + controls effect + */ + mainLoop : function() { + if (this.state == 0) // main menu + { + this.mainMenu.processEvents(); + if (this.mainMenu.done) { + switch(this.mainMenu.selectedLine) { + case 1 :// new game + this.world.startNewGame(); + // no break : we start the game by changing state + case 0 : // resume game + this.changeState(2); + break; + /* + case 2 : // tutorial + this.changeState(1); + break; + */ + case 2 : // save and quit + this.world.saveGame(); + //window.close(); + // already saved : quit + break; + } + } + } + + + + if (this.state == 1 || this.state == 2) { + this.world.processControls(); + + if (this.controls.controlEscape) { + // escape pressed : invoke main menu + this.changeState(0); + } + + this.world.animateItems(); + + if (!this.world.gameInProgress) { + // game ended, won or lost : return to main menu + this.changeState(0); + } + + } + + }, + + /** + * Performs all the rendering (view) with no alteration of the model + * + controls related to the view only + */ + renderLoop : function() { + + this.renderer.drawMessage(this.state>0); + this.renderer.drawMain(); + if (this.state == 0) { + this.renderer.drawMainMenu(this.mainMenu); + } + requestAnimationFrame(function() {game.renderLoop();}); + }, + + /** + * Define the renderer in charge (one does both overlay canvas and scenery canvas) + */ + setRenderer : function(renderer) { + this.renderer = renderer; + }, + + /** + * Private method to synchronize local storage with current data + */ + storeData : function() { + localStorage.setItem("GlitchData", JSON.stringify(this.persistentData)); + }, + + + /** + * Called when a manual or auto save of the game in progress is requested + */ + notifySave : function(posX, posY, floor, keysAcquired, doors, ground, timer) { + this.persistentData.gameProgress = { + posX : posX, + posY : posY, + floor : floor, + keysAcquired : keysAcquired, + doors : doors, + ground : ground, + timer : timer}; + this.storeData(); + }, + + /** + * Called when the window is resized and the window layout changes + */ + layoutChanged : function(windowLayout) { + this.controls.onLayoutChange(windowLayout); + } +} diff --git a/2016 - diamond run/js/levelLoader.js b/2016 - diamond run/js/levelLoader.js new file mode 100644 index 0000000..bbda2e2 --- /dev/null +++ b/2016 - diamond run/js/levelLoader.js @@ -0,0 +1,680 @@ +/** + * @constructor + */ + +function LevelLoader() { + +} + +LevelLoader.prototype = { + + loadLevel : function(floors, levelWidth, levelHeight, ground, wallsH, wallsV, roomNumber, terminals){ + var data = [0, 0, 14, 4, 2, // rooms + 0, 0, 12, 4, 2, + 0, 0, 8, 2, 4, + 0, 4, 12, 10, 4, + 0, 2, 8, 6, 4, + 0, 14, 10, 2, 4, + 0, 8, 10, 6, 2, + 0, 8, 8, 8, 2, + 0, 0, 0, 4, 8, + 0, 4, 5, 6, 3, + 0, 10, 5, 3, 3, + 0, 13, 5, 3, 3, + 0, 4, 0, 12, 5, + 1, 0, 0, 3, 3, + 1, 3, 0, 3, 3, + 1, 6, 0, 7, 3, + 1, 13, 0, 3, 3, + 1, 0, 3, 6, 2, + 1, 6, 3, 7, 2, + 1, 13, 3, 3, 2, + 1, 0, 5, 10, 3, + 1, 10, 5, 3, 3, + 1, 13, 5, 3, 3, + 1, 0, 8, 2, 8, + 1, 2, 8, 7, 2, + 1, 2, 10, 3, 5, + 1, 5, 10, 2, 5, + 1, 7, 10, 2, 3, + 1, 7, 13, 2, 2, + 1, 2, 15, 8, 1, + 1, 9, 8, 1, 7, + 1, 10, 9, 2, 4, + 1, 12, 8, 2, 6, + 1, 14, 10, 2, 4, + 1, 10, 14, 6, 2, + 2, 0, 0, 3, 3, + 2, 3, 0, 4, 3, + 2, 7, 0, 3, 3, + 2, 10, 0, 3, 3, + 2, 13, 0, 3, 3, + 2, 0, 3, 3, 1, + 2, 3, 3, 4, 2, + 2, 7, 3, 3, 4, + 2, 10, 3, 2, 4, + 2, 12, 3, 2, 7, + 2, 14, 3, 2, 7, + 2, 0, 4, 1, 5, + 2, 1, 4, 2, 5, + 2, 3, 5, 4, 4, + 2, 0, 9, 7, 1, + 2, 0, 10, 3, 3, + 2, 0, 13, 3, 3, + 2, 3, 10, 4, 6, + 2, 7, 7, 1, 9, + 2, 8, 7, 2, 2, + 2, 10, 9, 2, 4, + 2, 8, 9, 2, 4, + 2, 8, 13, 4, 1, + 2, 8, 14, 4, 2, + 2, 12, 10, 2, 4, + 2, 14, 10, 2, 4, + 2, 12, 14, 2, 2, + 2, 14, 14, 2, 2, + 2, 10, 7, 2, 2, + 0, 14, 14, 2, 2, + 1, 14, 8, 2, 2, + 1, 10, 13, 2, 1, + 1, 10, 8, 2, 1, + 3, 0, 0, 2, 2, + 3, 2, 0, 2, 2, + 3, 0, 2, 2, 2, + 3, 2, 2, 2, 2, + 3, 0, 4, 2, 3, + 3, 2, 4, 2, 3, + 3, 4, 0, 3, 3, + 3, 7, 0, 3, 3, + 3, 0, 7, 3, 3, + 3, 0, 10, 3, 3, + 3, 0, 13, 3, 3, + 3, 4, 3, 4, 2, + 3, 4, 5, 2, 2, + 3, 10, 0, 4, 2, + 3, 14, 0, 2, 4, + 3, 3, 7, 3, 6, + 3, 6, 5, 2, 8, + 3, 8, 3, 2, 5, + 3, 10, 2, 3, 6, + 3, 13, 2, 1, 6, + 3, 3, 13, 7, 3, + 3, 10, 14, 6, 2, + 3, 10, 9, 2, 5, + 3, 8, 9, 2, 4, + 3, 8, 8, 4, 1, + 3, 12, 8, 2, 2, + 3, 12, 10, 2, 4, + 3, 14, 4, 2, 4, + 3, 14, 8, 2, 2, + 3, 14, 10, 2, 4, + 4, 0, 0, 4, 4, + 4, 0, 4, 3, 3, + 4, 0, 7, 3, 3, + 4, 4, 0, 3, 3, + 4, 4, 3, 3, 1, + 4, 7, 0, 5, 4, + 4, 12, 0, 4, 3, + 4, 12, 3, 2, 5, + 4, 14, 3, 2, 1, + 4, 14, 4, 2, 4, + 4, 12, 8, 4, 8, + 4, 3, 13, 9, 3, + 4, 0, 10, 3, 6, + 4, 3, 4, 1, 3, + 4, 4, 4, 8, 1, + 4, 11, 5, 1, 3, + 4, 4, 12, 3, 1, + 4, 4, 5, 7, 7, + 4, 3, 7, 1, 3, + 4, 3, 10, 1, 3, + 4, 11, 8, 1, 2, + 4, 11, 10, 1, 2, + 4, 7, 12, 3, 1, + 4, 10, 12, 2, 1 + ]; + var levelSize = levelWidth*levelHeight; + this.levelWidth = levelWidth; + this.levelSize = levelSize; + + + this.roomCount = 1; + for (var i=0; i