lychees's picture
Upload 569 files
87b3b3a
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();
}
}
}
}