Newer
Older
/********************************************************************************
metodLD
committed
This file contains the variables and functions that forms the core of the game.
Anything that is needed game-wide is kept here.
********************************************************************************/
/**********************************************************************
* Game Wide Constants
**********************************************************************/
/* General Constants */
var EPILOGUES_ENABLED = true;
var EPILOGUE_BADGES_ENABLED = true;
var BASE_FONT_SIZE = 14;
var BASE_SCREEN_WIDTH = 100;
/* Game Wide Constants */
var HUMAN_PLAYER = 0;
/* Directory Constants */
var IMG = 'img/';

ReformCopyright
committed
var backgroundImage;
/*var OPP = 'opponents/';
#The "OPP" folder abbreviation was used to slightly shorten a few lines in spniSelect that looked for opponents in the opponents folder.
#Now that opponents can be specified in any folder, this is no longer required.*/
/* Gender Images */
var MALE_SYMBOL = IMG + 'male.png';
var FEMALE_SYMBOL = IMG + 'female.png';
var includedOpponentStatuses = {};
/* game table */
var tableOpacity = 1;
$gameTable = $('#game-table');
/* useful variables */
var BLANK_PLAYER_IMAGE = "opponents/blank.png";
/* player array */

ReformCopyright
committed
var players = Array(5);

ReformCopyright
committed
/* Current timeout ID, so we can cancel it when restarting the game in order to avoid trouble. */
var timeoutID;
/**********************************************************************
* Game Wide Global Variables
**********************************************************************/
var table = new Table();
/**********************************************************************
* Screens & Modals
**********************************************************************/
/* Screens */
$titleScreen = $('#title-screen');
$selectScreen = $('#main-select-screen');
$individualSelectScreen = $('#individual-select-screen');
$groupSelectScreen = $('#group-select-screen');
$gameScreen = $('#game-screen');
$epilogueScreen = $('#epilogue-screen');
metodLD
committed
$galleryScreen = $('#gallery-screen');
/* Modals */
$searchModal = $('#search-modal');
$groupSearchModal = $('#group-search-modal');
$creditModal = $('#credit-modal');
$versionModal = $('#version-modal');
$gameSettingsModal = $('#game-settings-modal');
/* Screen State */
$previousScreen = null;
/********************************************************************************
* Game Wide Utility Functions
********************************************************************************/
/**********************************************************************
***** Player Object Specification *****
**********************************************************************/
metodLD
committed
/************************************************************
metodLD
committed
* Creates and returns a new player object based on the
* supplied information.
*
* folder (string), the path to their folder
* first (string), their first name.
* last (string), their last name.
ReformCopyright
committed
* labels (string or XML element), what's shown on screen and what other players refer to them as.
* Can vary by stage.
* size (string): Their level of endowment
* intelligence (string or XML element), the name of their AI algorithm.
* Can vary by stage.
* gender (constant), their gender.
* clothing (array of Clothing objects), their clothing.
* timer (integer), time until forfeit is finished.
* state (array of PlayerState objects), their sequential states.
* xml (jQuery object), the player's loaded XML file.
************************************************************/

ReformCopyright
committed
function createNewPlayer (id, first, last, labels, gender, size, intelligence, timer, scale, tags, xml) {
var newPlayerObject = {id:id,
folder:'opponents/'+id+'/',
first:first,
ReformCopyright
committed
labels:labels,

ReformCopyright
committed
scale:scale,
xml:xml,
getImagesForStage: function(stage) {
if(!this.xml) return [];
var imageSet = {};
var folder = this.folder;
this.xml.find('stage[id="'+stage+'"] state').each(function () {
imageSet[folder+$(this).attr('img')] = true;
});
return Object.keys(imageSet);
},
ReformCopyright
committed
getByStage: function (arr) {
if (typeof(arr) === "string") {
return arr;
}
var bestFitStage = -1;
var bestFit = null;
ReformCopyright
committed
for (var i = 0; i < arr.length; i++) {
var startStage = arr[i].getAttribute('stage');
startStage = parseInt(startStage, 10) || 0;
ReformCopyright
committed
if (startStage > bestFitStage && startStage <= this.stage) {
bestFit = $(arr[i]).text();
bestFitStage = startStage;
}
}
ReformCopyright
committed
return bestFit;
},
getIntelligence: function () {
return this.getByStage(this.intelligence) || eIntelligence.AVERAGE;
ReformCopyright
committed
updateLabel: function () {
if (this.labels) this.label = this.getByStage(this.labels);
}
ReformCopyright
committed
initPlayerState(newPlayerObject);
/*******************************************************************
* (Re)Initialize the player properties that change during a game
*******************************************************************/
function initPlayerState(player) {
player.out = player.finished = player.exposed = false;
player.forfeit = "";

ReformCopyright
committed
player.stage = player.current = player.consecutiveLosses = 0;
player.timeInStage = -1;
player.markers = {};
if (player.xml !== null) {
/* Load in the legacy "start" lines, and also
* initialize player.chosenState to the first listed line.
* This may be overridden by later updateBehaviour calls if
* the player has (new-style) selected or game start case lines.
*/
player.allStates = parseDialogue(player.xml.find('start'), player);
player.chosenState = player.allStates[0];
loadOpponentWardrobe(player);
}
ReformCopyright
committed
player.updateLabel();
/**********************************************************************
***** Overarching Game Flow Functions *****
**********************************************************************/
/************************************************************
* Loads the initial content of the game.
************************************************************/
function initialSetup () {
/* start by creating the human player object */

ReformCopyright
committed
var humanPlayer = createNewPlayer("human", "", "", "", eGender.MALE, eSize.MEDIUM, eIntelligence.AVERAGE, 20, undefined, [], null);
/* enable table opacity */
tableOpacity = 1;
$gameTable.css({opacity:1});
/* load the all content */
loadTitleScreen();
selectTitleCandy();
/* Make sure that the config file is loaded before processing the
opponent list, so that includedOpponentStatuses is populated. */
loadConfigFile().always(loadSelectScreen);
save.loadCookie();
return $.ajax({
type: "GET",
url: "config.xml",
dataType: "text",
success: function(xml) {
var _epilogues = $(xml).find('epilogues').text();
if(_epilogues.toLowerCase() === 'false') {
EPILOGUES_ENABLED = false;
console.log("Epilogues are disabled.");
$("#title-gallery-edge").hide();
} else {
console.log("Epilogues are enabled.");
EPILOGUES_ENABLED = true;
}
var _epilogue_badges = $(xml).find('epilogue_badges').text();
if(_epilogue_badges.toLowerCase() === 'false') {
EPILOGUE_BADGES_ENABLED = false;
console.log("Epilogue badges are disabled.");
} else {
console.log("Epilogue badges are enabled.");
EPILOGUE_BADGES_ENABLED = true;
}
var _debug = $(xml).find('debug').text();
if (_debug === "true") {
DEBUG = true;
console.log("Debugging is enabled");
}
else {
DEBUG = false;
console.log("Debugging is disabled");
}
$(xml).find('include-status').each(function() {
includedOpponentStatuses[$(this).text()] = true;
console.log("Including", $(this).text(), "opponents");
});
function enterTitleScreen() {
$warningScreen.hide();
$titleScreen.show();
}
/************************************************************
* Transitions between two screens.
************************************************************/
function screenTransition (first, second) {
first.hide();
second.show();
}
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
/************************************************************
* Switches to the next screen based on the screen provided.
************************************************************/
function advanceToNextScreen (screen) {
if (screen == $titleScreen) {
/* advance to the select screen */
screenTransition($titleScreen, $selectScreen);
} else if (screen == $selectScreen) {
/* advance to the main game screen */
$selectScreen.hide();
loadGameScreen();
$gameScreen.show();
}
}
/************************************************************
* Switches to the last screen based on the screen provided.
************************************************************/
function returnToPreviousScreen (screen) {
if (screen == $selectScreen) {
/* return to the title screen */
$selectScreen.hide();
$titleScreen.show();
}
}
/************************************************************
* Resets the game state so that the game can be restarted.
************************************************************/
function resetPlayers () {
for (var i = 0; i < players.length; i++) {
if (players[i] != null) {
initPlayerState(players[i]);
}

ReformCopyright
committed
timers[i] = 0;
updateAllBehaviours(null, SELECTED);
}
/************************************************************
* Restarts the game.
************************************************************/
function restartGame () {
KEYBINDINGS_ENABLED = false;

ReformCopyright
committed
clearTimeout(timeoutID); // No error if undefined or no longer valid
timeoutID = autoForfeitTimeoutID = undefined;
stopCardAnimations();
/* enable table opacity */
tableOpacity = 1;
$gameTable.css({opacity:1});
$gamePlayerClothingArea.show();
$gamePlayerCardArea.show();
/* trigger screen refreshes */
updateSelectionVisuals();
updateAllGameVisuals();
selectTitleCandy();
/* there is only one call to this right now */
$epilogueSelectionModal.hide();
$gameScreen.hide();
$epilogueScreen.hide();

ReformCopyright
committed
loadClothing();
$titleScreen.show();
}
/**********************************************************************
***** Interaction Functions *****
**********************************************************************/
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
/************************************************************
* The player clicked the credits button. Shows the credits modal.
************************************************************/
function showCreditModal () {
$creditModal.modal('show');
}
/************************************************************
* The player clicked the version button. Shows the version modal.
************************************************************/
function showVersionModal () {
$versionModal.modal('show');
}
/************************************************************
* The player clicked on a table opacity button.
************************************************************/
function toggleTableVisibility () {
if (tableOpacity > 0) {
$gameTable.fadeOut();
tableOpacity = 0;
} else {
$gameTable.fadeIn();
tableOpacity = 1;
}
}
function forceTableVisibility(state) {
if (!state) {
$gameTable.fadeOut();
tableOpacity = 0;
} else {
$gameTable.fadeIn();
tableOpacity = 1;
}
}
/**********************************************************************
***** Utility Functions *****
**********************************************************************/
/************************************************************
* Returns a random number in a range.
************************************************************/
function getRandomNumber (min, max) {
return Math.floor(Math.random() * (max - min) + min);
}
ReformCopyright
committed
/************************************************************
* Changes the first letter in a string to upper case.
************************************************************/
String.prototype.initCap = function() {
return this.substr(0, 1).toUpperCase() + this.substr(1);
}
/**********************************************************************
* Returns the width of the visible screen in pixels.
**/
{
/* fetch all game screens */
var screens = document.getElementsByClassName('screen');
/* figure out which screen is visible */
{
/* this screen is currently visible */
return screens[i].offsetWidth;
}
}
}
/**********************************************************************
* Automatically adjusts the size of all font based on screen width.
**/
{
/* resize font */
var screenWidth = getScreenWidth();
document.body.style.fontSize = (14*(screenWidth/1000))+'px';

ReformCopyright
committed
if (backgroundImage && backgroundImage.height && backgroundImage.width) {
var w = window.innerWidth, h = window.innerHeight;
if (h > (3/4) * w) {
h = (3/4) * w;
} else {

ReformCopyright
committed
}
var ar = backgroundImage.width / backgroundImage.height;
if (ar > 4/3) {
var scale = Math.sqrt(16/9 / ar);
$("body").css("background-size", "auto " + Math.round(scale * h) + "px");

ReformCopyright
committed
} else {
var scale = Math.sqrt(ar);
$("body").css("background-size", Math.round(scale * w) + "px auto");

ReformCopyright
committed
}
}
/* set up future resizing */
window.onresize = autoResizeFont;
/* Get the number of players loaded, including the human player.*/
function countLoadedOpponents() {
return players.reduce(function (a, v) { return a + (v ? 1 : 0); }, 0);
}