Spaces:
Running
Running
| function Game(debugMode, startLevel) { | |
| /* private properties */ | |
| var __currentCode = ''; | |
| var __commands = []; | |
| var __playerCodeRunning = false; | |
| /* unexposed properties */ | |
| this._dimensions = { | |
| width: 50, | |
| height: 25 | |
| }; | |
| this._levelFileNames = [ | |
| //%LEVELS% | |
| ]; | |
| this._bonusLevels = [ | |
| //%BONUS% | |
| ].filter(function (lvl) { return (lvl.indexOf('_') != 0); }); // filter out bonus levels that start with '_' | |
| this._mod = '//%MOD%'; | |
| this._viewableScripts = [ | |
| 'codeEditor.js', | |
| 'display.js', | |
| 'dynamicObject.js', | |
| 'game.js', | |
| 'inventory.js', | |
| 'map.js', | |
| 'objects.js', | |
| 'player.js', | |
| 'reference.js', | |
| 'sound.js', | |
| 'ui.js', | |
| 'util.js', | |
| 'validate.js' | |
| ]; | |
| this._editableScripts = [ | |
| 'map.js', | |
| 'objects.js', | |
| 'player.js' | |
| ]; | |
| this._resetTimeout = null; | |
| this._currentLevel = 0; | |
| this._currentFile = null; | |
| this._currentBonusLevel = null; | |
| this._levelReached = 1; | |
| this._displayedChapters = []; | |
| this._playerPrototype = Player; // to allow messing with map.js and player.js later | |
| this._nextBonusLevel = null; | |
| /* unexposed getters */ | |
| this._getHelpCommands = function () { return __commands; }; | |
| this._isPlayerCodeRunning = function () { return __playerCodeRunning; }; | |
| this._getLocalKey = function (key) { return (this._mod.length == 0 ? '' : this._mod + '.') + key; }; | |
| /* unexposed setters */ | |
| this._setPlayerCodeRunning = function (pcr) { __playerCodeRunning = pcr; }; | |
| /* unexposed methods */ | |
| this._initialize = function () { | |
| // Get last level reached from localStorage (if any) | |
| var levelKey = this._mod.length == 0 ? 'levelReached' : this._mod + '.levelReached'; | |
| this._levelReached = parseInt(localStorage.getItem(levelKey)) || 1; | |
| // Fix potential corruption | |
| // levelReached may be "81111" instead of "8" due to bug | |
| if (this._levelReached > this._levelFileNames.length) { | |
| for (var l = 1; l <= this._levelFileNames.length; l++) { | |
| if (!localStorage[this._getLocalKey("level" + l + ".lastGoodState")]) { | |
| this._levelReached = l - 1; | |
| break; | |
| } | |
| } | |
| } | |
| // Initialize sound | |
| this.sound = new Sound('local'); | |
| // this.sound = new Sound(debugMode ? 'local' : 'cloudfront'); | |
| // Initialize map display | |
| this.display = ROT.Display.create(this, { | |
| width: this._dimensions.width, | |
| height: this._dimensions.height, | |
| fontSize: 20 | |
| }); | |
| this.display.setupEventHandlers(); | |
| var display = this.display; | |
| $('#screen').append(this.display.getContainer()); | |
| $('#drawingCanvas, #dummyDom, #dummyDom *').click(function () { | |
| display.focus(); | |
| }); | |
| // Initialize editor, map, and objects | |
| this.editor = new CodeEditor("editor", 600, 500, this); | |
| this.map = new Map(this.display, this); | |
| this.objects = this.getListOfObjects(); | |
| // Enable controls | |
| this.enableShortcutKeys(); | |
| this.enableButtons(); | |
| this.setUpNotepad(); | |
| // Load help commands from local storage (if possible) | |
| if (localStorage.getItem(this._getLocalKey('helpCommands'))) { | |
| __commands = localStorage.getItem(this._getLocalKey('helpCommands')).split(';'); | |
| } | |
| // Enable debug features | |
| if (debugMode) { | |
| this._debugMode = true; | |
| this._levelReached = 999; // make all levels accessible | |
| __commands = Object.keys(this.reference); // display all help | |
| this.sound.toggleSound(); // mute sound by default in debug mode | |
| } | |
| // Lights, camera, action | |
| if (startLevel) { | |
| this._currentLevel = startLevel - 1; | |
| this._getLevel(startLevel, debugMode); | |
| } else if (!debugMode && this._levelReached != 1) { | |
| // load last level reached (unless it's the credits) | |
| this._getLevel(Math.min(this._levelReached, 21)); | |
| } else { | |
| this._intro(); | |
| } | |
| }; | |
| this._intro = function () { | |
| this.display.focus(); | |
| this.display.playIntro(this.map); | |
| }; | |
| this._start = function (lvl) { | |
| this._getLevel(lvl ? lvl : 1); | |
| }; | |
| this._moveToNextLevel = function () { | |
| // is the player permitted to exit? | |
| if (typeof this.onExit === 'function') { | |
| var game = this; | |
| var canExit = this.validateCallback(function () { | |
| return game.onExit(game.map); | |
| }); | |
| if (!canExit) { | |
| this.sound.playSound('blip'); | |
| return; | |
| } | |
| } | |
| this.sound.playSound('complete'); | |
| //we disable moving so the player can't move during the fadeout | |
| this.map.getPlayer()._canMove = false; | |
| if (this._currentLevel == 'bonus') { | |
| if (this._nextBonusLevel) { | |
| this._getLevelByPath("levels/bonus/" + this._nextBonusLevel); | |
| } else { | |
| // open main menu | |
| $('#helpPane, #notepadPane').hide(); | |
| $('#menuPane').show(); | |
| } | |
| } else { | |
| this._getLevel(this._currentLevel + 1, false, true); | |
| } | |
| }; | |
| this._jumpToNthLevel = function (levelNum) { | |
| this._currentFile = null; | |
| this._getLevel(levelNum, false, false); | |
| this.display.focus(); | |
| this.sound.playSound('blip'); | |
| }; | |
| // makes an ajax request to get the level text file and | |
| // then loads it into the game | |
| this._getLevel = function (levelNum, isResetting, movingToNextLevel) { | |
| var game = this; | |
| var editor = this.editor; | |
| if (levelNum > this._levelFileNames.length) { | |
| return; | |
| } | |
| this._levelReached = Math.max(levelNum, this._levelReached); | |
| if (!debugMode) { | |
| localStorage.setItem(this._getLocalKey('levelReached'), this._levelReached); | |
| } | |
| var fileName = this._levelFileNames[levelNum - 1]; | |
| lvlCode = this._levels['levels/' + fileName]; | |
| if (movingToNextLevel) { | |
| // save level state and create a gist | |
| editor.saveGoodState(); | |
| editor.createGist(); | |
| } | |
| game._currentLevel = levelNum; | |
| game._currentBonusLevel = null; | |
| game._currentFile = null; | |
| // load level code in editor | |
| editor.loadCode(lvlCode); | |
| // restored saved state for this level? | |
| if (!isResetting && editor.getGoodState(levelNum)) { | |
| // unless the current level is a newer version | |
| var newVer = editor.getProperties().version; | |
| var savedVer = editor.getGoodState(levelNum).version; | |
| if (!(newVer && (!savedVer || isNewerVersion(newVer, savedVer)))) { | |
| // restore saved line/section/endOfStartLevel state if possible | |
| if (editor.getGoodState(levelNum).endOfStartLevel) { | |
| editor.setEndOfStartLevel(editor.getGoodState(levelNum).endOfStartLevel); | |
| } | |
| if (editor.getGoodState(levelNum).editableLines) { | |
| editor.setEditableLines(editor.getGoodState(levelNum).editableLines); | |
| } | |
| if (editor.getGoodState(levelNum).editableSections) { | |
| editor.setEditableSections(editor.getGoodState(levelNum).editableSections); | |
| } | |
| // restore saved code | |
| editor.setCode(editor.getGoodState(levelNum).code); | |
| } | |
| } | |
| // start the level and fade in | |
| game._evalLevelCode(null, null, true); | |
| game.display.focus(); | |
| // store the commands introduced in this level (for api reference) | |
| __commands = __commands.concat(editor.getProperties().commandsIntroduced).unique(); | |
| localStorage.setItem(this._getLocalKey('helpCommands'), __commands.join(';')); | |
| }; | |
| this._getLevelByPath = function (filePath) { | |
| var game = this; | |
| var editor = this.editor; | |
| $.get(filePath, function (lvlCode) { | |
| game._currentLevel = 'bonus'; | |
| game._currentBonusLevel = filePath.split("levels/")[1]; | |
| game._currentFile = null; | |
| // load level code in editor | |
| editor.loadCode(lvlCode); | |
| // save next bonus level | |
| game._nextBonusLevel = editor.getProperties()["nextBonusLevel"]; | |
| // start the level and fade in | |
| game._evalLevelCode(null, null, true); | |
| game.display.focus(); | |
| // store the commands introduced in this level (for api reference) | |
| __commands = __commands.concat(editor.getProperties().commandsIntroduced).unique(); | |
| localStorage.setItem(this._getLocalKey('helpCommands'), __commands.join(';')); | |
| }, 'text'); | |
| }; | |
| // how meta can we go? | |
| this._editFile = function (filePath) { | |
| var game = this; | |
| var fileName = filePath.split('/')[filePath.split('/').length - 1]; | |
| game._currentFile = filePath; | |
| $.get(filePath, function (code) { | |
| // load level code in editor | |
| if (game._editableScripts.indexOf(fileName) > -1) { | |
| game.editor.loadCode('#BEGIN_EDITABLE#\n' + code + '\n#END_EDITABLE#'); | |
| } else { | |
| game.editor.loadCode(code); | |
| } | |
| }, 'text'); | |
| }; | |
| this._resetLevel = function( level ) { | |
| var game = this; | |
| var resetTimeout_msec = 2500; | |
| var reset_game_msg = "To reset this level press ^4 again."; | |
| if ( this._resetTimeout != null ) { | |
| $('body, #buttons').css('background-color', '#000'); | |
| window.clearTimeout( this._resetTimeout ); | |
| this._resetTimeout = null; | |
| if (game._currentBonusLevel) { | |
| game._getLevelByPath('levels/' + game._currentBonusLevel); | |
| } else { | |
| this._getLevel(level, true); | |
| } | |
| if(game.map._status == reset_game_msg) { | |
| game.map.writeStatus(""); | |
| } | |
| } else { | |
| this.map.writeStatus(reset_game_msg); | |
| $('body, #buttons').css('background-color', '#900'); | |
| this._resetTimeout = setTimeout(function () { | |
| game._resetTimeout = null; | |
| if(game.map._status == reset_game_msg) { | |
| game.map.writeStatus(""); | |
| } | |
| $('body, #buttons').css('background-color', '#000'); | |
| }, resetTimeout_msec ); | |
| } | |
| }; | |
| // restart level with currently loaded code | |
| this._restartLevel = function () { | |
| this.editor.setCode(__currentCode); | |
| this._evalLevelCode(); | |
| }; | |
| this._evalLevelCode = function (allCode, playerCode, isNewLevel, restartingLevelFromScript) { | |
| this.map._clearIntervals(); | |
| var game = this; | |
| // by default, get code from the editor | |
| var loadedFromEditor = false; | |
| if (!allCode) { | |
| allCode = this.editor.getCode(); | |
| playerCode = this.editor.getPlayerCode(); | |
| loadedFromEditor = true; | |
| } | |
| // if we're editing a script file, do something completely different | |
| if (this._currentFile !== null && !restartingLevelFromScript) { | |
| __currentCode = allCode; | |
| this.validateAndRunScript(allCode); | |
| return; | |
| } | |
| // save current display state (for scrolling up later) | |
| this.display.saveGrid(this.map); | |
| // validate the code | |
| // if it passes validation, returns the startLevel function if it pass | |
| // if it fails validation, returns false | |
| var validatedStartLevel = this.validate(allCode, playerCode, restartingLevelFromScript); | |
| if (validatedStartLevel) { // code is valid | |
| // reset the map | |
| this.map._reset(); // for cleanup | |
| this.map = new Map(this.display, this); | |
| this.map._reset(); | |
| this.map._setProperties(this.editor.getProperties()['mapProperties']); | |
| // save editor state | |
| if (!restartingLevelFromScript) { | |
| __currentCode = allCode; | |
| } | |
| if (loadedFromEditor && !restartingLevelFromScript) { | |
| this.editor.saveGoodState(); | |
| } | |
| // clear drawing canvas and hide it until level loads | |
| var screenCanvas = $('#screen canvas')[0]; | |
| $('#drawingCanvas')[0].width = screenCanvas.width; | |
| $('#drawingCanvas')[0].height = screenCanvas.height; | |
| $('#drawingCanvas').hide(); | |
| $('#dummyDom').hide(); | |
| // set correct inventory state | |
| this.setInventoryStateByLevel(this._currentLevel); | |
| // start the level | |
| validatedStartLevel(this.map); | |
| // Add the computer to bonus levels that lack it | |
| if (this._currentLevel == "bonus" && this.map.countObjects("computer") == 0) { | |
| this.addToInventory("computer") | |
| $('#editorPane, #savedLevelMsg').show(); | |
| this.editor.refresh(); | |
| } | |
| // draw the map | |
| this.display.fadeIn(this.map, isNewLevel ? 100 : 10, function () { | |
| game.map.refresh(); // refresh inventory display | |
| // show map overlays if necessary | |
| if (game.map._properties.showDrawingCanvas) { | |
| $('#drawingCanvas').show(); | |
| } else if (game.map._properties.showDummyDom) { | |
| $('#dummyDom').show(); | |
| } | |
| // workaround because we can't use writeStatus() in startLevel() | |
| // (due to the text getting overwritten by the fade-in) | |
| if (game.editor.getProperties().startingMessage) { | |
| game.map.writeStatus(game.editor.getProperties().startingMessage); | |
| } | |
| }); | |
| this.map._ready(); | |
| // start bg music for this level | |
| if (this.editor.getProperties().music) { | |
| this.sound.playTrackByName(this.editor.getProperties().music); | |
| } | |
| // activate super menu if 21_endOfTheLine has been reached | |
| if (this._levelReached >= 21) { | |
| this.activateSuperMenu(); | |
| } | |
| // finally, allow player movement | |
| if (this.map.getPlayer()) { | |
| this.map.getPlayer()._canMove = true; | |
| game.display.focus(); | |
| } | |
| } else { // code is invalid | |
| // play error sound | |
| this.sound.playSound('static'); | |
| // disable player movement | |
| this.map.getPlayer()._canMove = false; | |
| } | |
| }; | |
| this._callUnexposedMethod = function(f) { | |
| if (__playerCodeRunning) { | |
| __playerCodeRunning = false; | |
| try { | |
| res = f(); | |
| } finally { | |
| __playerCodeRunning = true; | |
| } | |
| return res; | |
| } else { | |
| return f(); | |
| } | |
| }; | |
| this._checkObjective = function() { | |
| if (typeof(this.objective) === 'function') { | |
| var game = this; | |
| var objectiveIsMet = this.validateCallback(function() { | |
| return game.objective(game.map); | |
| }); | |
| if (objectiveIsMet) { | |
| this._moveToNextLevel(); | |
| } | |
| } | |
| } | |
| } | |