diff --git a/js/game.js b/js/game.js
index b86fdea..5c2445f 100644
--- a/js/game.js
+++ b/js/game.js
@@ -259,9 +259,17 @@ function makeGameObject(dom_object)
}
let check = child.getAttribute("ck");
if (!check) {
- check = "";
+ let check = child.getAttribute("check");
+ if (!check) {
+ check = "";
+ }
+ }
+ let stage = child.getAttribute("stage");
+ if (!stage) {
+ stage = "";
}
- game_object[attribute_name].push([check, child.innerHTML]);
+ game_object[attribute_name].push([check, stage,
+ child.innerHTML]);
} else {
game_object[attribute_name] = child.innerHTML;
}
@@ -305,9 +313,6 @@ function toggleMainNav()
{
let game_content = elt('game-content');
let nav_obj = elt('main-nav');
- if (!nav_obj) {
- return;
- }
if ((!nav_obj.style.left && !nav_obj.style.right) ||
nav_obj.style.left == '0px' || nav_obj.style.right == '0px') {
game_content.style.width = "calc(100% - 40px)";
@@ -500,12 +505,12 @@ class Location
game_content.scrollTop = 0;
game_content.scrollLeft = 0;
for (let section of this.present) {
- if (!section[1]) {
+ if (!section[2]) {
continue;
}
let [check_result, proceed, pause] =
- this.evaluateCheckCondition(section[0]);
- let prepared_section = this.prepareSection(section[1]);
+ this.evaluateCheckConditionStaging(section[0], section[1]);
+ let prepared_section = this.prepareSection(section[2]);
if (check_result) {
if (proceed) {
let old_inner_html = game_content.innerHTML;
@@ -581,48 +586,49 @@ class Location
/**
* Evaluates the condition from a ck attribute ofan x-present tag.
*
- * @param {string} condition contents from a ck attribute.
- * Conditions can be boolean conditions on game variable, delay conditions,
- * or clickProceed condition.
+ * @param {string} condition contents from a ck or check attribute.
+ * Conditions can be boolean conditions on game variable.
+ * @param {string} staging contents from a stage attribute.
+ * If none empty, such an attribute could have a sequence of
+ * pause(some_millisecond); and clickProceed(some_string) commands
* @return {Array} [check_result, proceed, pause] if the condition involved
* a boolean expression, then check_result will hold the result of
* the expression (so the caller then could prevent the the display of
* an x-present tag if false), proceed is the link text (if any) for a
- * link if the condition involved a clickProceed (which is supposed to
- * delay the presentation of the x-present tag until after the user
- * clicks the link), pause (if non zero) is the number of miliseconds
- * to sleep before presenting the x-pressent tag according to the condition
+ * link for the first clickProceed (which is supposed to delay the
+ * presentation of the x-present tag until after the user clicks the
+ * link) if found (else ""), pause (if non zero) is the number of
+ * miliseconds to sleep before presenting the x-pressent tag according to
+ * the condition
*/
- evaluateCheckCondition(condition)
+ evaluateCheckConditionStaging(condition, staging)
{
- let check;
let proceed = "";
let pause = 0;
- if (condition == "") {
- check = "";
- } else {
- check = condition;
- let old_check = "";
- while (old_check != check) {
- old_check = check;
- let click_pattern =
- /clickProceed\([\'\"]([^)]+)[\'\"]\);?/;
- let click_match = check.match(click_pattern);
- if (click_match) {
- proceed = click_match[1];
- check = "";
- break;
- }
- let pause_pattern = /sleep\(([^)]+)\);?/;
- let pause_match = check.match(pause_pattern);
- if (pause_match) {
- pause += parseInt(pause_match[1]);
- }
- check = check.replace(pause_pattern, "");
+ condition = (typeof condition == "string") ? condition : "";
+ let check_result = (condition.replace(/\s+/, "") != "") ?
+ eval(condition) : true;
+ if (typeof check_result != "boolean") {
+ check_result = false;
+ console.log(condition + " didn't evaluate to a boolean");
+ }
+ let staging_remainder = staging;
+ let old_staging = "";
+ while (check_result && old_staging != staging_remainder) {
+ old_staging = staging_remainder;
+ let click_pattern = /clickProceed\([\'\"]([^)]+)[\'\"]\);?/;
+ let click_match = staging_remainder.match(click_pattern);
+ if (click_match) {
+ proceed = click_match[1];
+ break;
+ }
+ let pause_pattern = /pause\(([^)]+)\);?/;
+ let pause_match = staging_remainder.match(pause_pattern);
+ if (pause_match) {
+ pause += parseInt(pause_match[1]);
}
+ staging_remainder = staging_remainder.replace(pause_pattern, "");
}
- let check_result = (check.replace(/\s+/, "") != "") ? eval(check)
- : true;
return [check_result, proceed, pause];
}
/**
@@ -688,6 +694,13 @@ class Location
*/
class Game
{
+ /**
+ * A semi-unique identifier for this particular game to try to ensure
+ * two different games hosted in the same folder don't collide in
+ * sessionStorage.
+ * @type {string}
+ */
+ id;
/**
* Current date followed by a space followedby the current time of
* the most recent game capture. Used in providing a description of
@@ -757,6 +770,18 @@ class Game
*/
constructor()
{
+ let game_elt = tag('x-game')[0];
+ let doc_length = 0;
+ let middle_five = "";
+ if (game_elt) {
+ doc_length = game_elt.innerHTML.length;
+ if (doc_length > 8) {
+ middle_five = game_elt.innerHTML.slice(
+ Math.floor(doc_length/2), 5);
+ }
+ }
+ // a semi-unique code for this particular game
+ this.id = encodeURI(middle_five + doc_length);
this.reset();
}
/**
@@ -1005,7 +1030,7 @@ class Game
this.future_history.push(current_state);
let previous_game_state = this.history.pop();
this.restoreState(previous_game_state);
- sessionStorage.current = previous_game_state;
+ sessionStorage["current" + this.id] = previous_game_state;
this.describeMainCharacterLocation();
if (this.history.length == 0) {
elt('previous-history').disabled = true;
@@ -1028,7 +1053,7 @@ class Game
this.history.push(current_state);
let next_game_state = this.future_history.pop();
this.restoreState(next_game_state);
- sessionStorage.current = next_game_state;
+ sessionStorage["current" + this.id] = next_game_state;
this.describeMainCharacterLocation();
if (this.future_history.length == 0) {
elt('next-history').disabled = true;
@@ -1048,7 +1073,8 @@ class Game
let slot_matches = field.match(/^slot(\d+)/);
if (slot_matches && slot_matches[1]) {
let slot_number = parseInt(slot_matches[1]);
- let game_save = sessionStorage.getItem("slot" + slot_number);
+ let game_save = sessionStorage.getItem("slot" + game.id
+ + slot_number);
if (game_save) {
let game_state = JSON.parse(game_save);
saves_location["slot" + slot_number] =
@@ -1080,17 +1106,17 @@ class Game
{
slot_number = parseInt(slot_number);
let saves_location = game.locations['saves'];
- let game_state = sessionStorage.getItem("slot" + slot_number);
+ let game_state = sessionStorage.getItem("slot" + game.id + slot_number);
if (game_state) {
this.clearHistory();
- sessionStorage.current = game_state;
+ sessionStorage["current" + game.id] = game_state;
this.restoreState(game_state);
} else {
let save_state = this.captureState();
game_state = this.history[this.history.length - 1];
this.restoreState(game_state);
saves_location['filename' + slot_number] = this.timestamp;
- sessionStorage.setItem("slot" + slot_number, game_state);
+ sessionStorage.setItem("slot" + game.id + slot_number, game_state);
this.restoreState(save_state);
this.evaluateAction(saves_location['default-action']);
}
@@ -1108,7 +1134,7 @@ class Game
{
slot_number = parseInt(slot_number);
let saves_location = game.locations['saves'];
- sessionStorage.removeItem("slot" + slot_number);
+ sessionStorage.removeItem("slot" + game.id + slot_number);
saves_location['filled' + slot_number] = "not-filled";
saves_location['delete' + slot_number] = "disabled";
saves_location['slot' + slot_number] = "Save";
@@ -1146,7 +1172,7 @@ class Game
file_reader.addEventListener('load', (load_event) => {
let game_state = load_event.target.result;
this.clearHistory();
- sessionStorage.current = game_state;
+ sessionStorage["current" + this.id] = game_state;
this.restoreState(game_state);
game.describeMainCharacterLocation();
});
@@ -1203,8 +1229,8 @@ class Game
}
}
let new_game_state;
- if (sessionStorage.current) {
- new_game_state = sessionStorage.current;
+ if (sessionStorage["current" + game.id]) {
+ new_game_state = sessionStorage["current" + game.id];
}
if (!this.moveMainCharacter(hash)) {
return;
@@ -1213,12 +1239,12 @@ class Game
if (this.hasNavBar) {
elt('next-history').disabled = true;
}
- if (sessionStorage.current) {
+ if (sessionStorage["current" + game.id]) {
this.history.push(new_game_state);
}
this.evaluateDefaultActions(this.objects);
this.evaluateDefaultActions(this.locations);
- sessionStorage.current = this.captureState();
+ sessionStorage["current" + game.id] = this.captureState();
this.describeMainCharacterLocation();
if (this.hasNavBar) {
if (this.history.length == 0) {
@@ -1353,8 +1379,8 @@ class Game
async function initGame()
{
game = new Game();
- if (sessionStorage.current) {
- game.restoreState(sessionStorage.current);
+ if (sessionStorage["current" + game.id]) {
+ game.restoreState(sessionStorage["current" + game.id]);
}
game.takeTurn("");
game.clearHistory();