1
0
Fork 0
mirror of https://github.com/Oreolek/gamebookformat.git synced 2024-07-02 22:55:09 +03:00
gamebookformat/expected/codewords.html
Pelle Nilsson 1fac366e19 Gamebook id to allow saved games from different games in browser.
Default id is basename of file without extension.
Override id by setting book config, as seen in format.gamebook.
2013-06-16 21:54:18 +02:00

494 lines
19 KiB
HTML

<!DOCTYPE html>
<html>
<head>
<meta charset='utf-8'>
<meta name="viewport"
content="width=device-width, initial-scale=1, maximum-scale=1">
<title>Gamebook</title>
<script>
var gamebook = {
'id' : 'codewords',
'player' : {
'started' : false,
'currentSection' : -1,
'collections' : {},
'collect' : function(type, name) {
if (type in this.collections) {
return;
}
this.collections[type] = {
'name' : name,
'contents' : [],
'dropped' : {},
'add' : function(what) {
if (this.contents.indexOf(what) === -1
&& !(what in this.dropped)) {
this.contents.push(what);
this.contents.sort();
}
},
'drop' : function(what) {
var i = this.contents.indexOf(what);
if (i >= 0) {
this.contents.splice(i, 1);
this.dropped[what] = true;
}
},
'has' : function(what) {
return this.contents.indexOf(what) >= 0;
}
};
gamebook.addCollectionView(type, name);
},
'add' : function(type, what) {
this.collections[type].add(what);
gamebook.updateCollectionsView();
},
'drop' : function(type, what) {
this.collections[type].drop(what);
gamebook.updateCollectionsView();
},
'has' : function(type, what) {
return this.collections[type].has(what);
},
'getState' : function() {
return JSON.stringify({
'collections' : this.collections,
'currentSection' : this.currentSection
});
},
'setState' : function(state) {
var parsedState = JSON.parse(state);
this.currentSection = parsedState.currentSection;
for (var c in parsedState.collections) {
var collection = parsedState.collections[c];
if (!(c in this.collections)) {
this.collect(c, collection.name);
} else {
this.collections[c].name = collection.name;
}
this.collections[c].contents = collection.contents;
this.collections[c].dropped = collection.dropped;
}
}
},
'sections' : {},
'turnToFunctions' : {},
'addSection' : function(nr, element) {
var section = {'element' : element, 'nr' : nr};
this.sections[nr] = section;
},
'turnTo' : function(nr) {
if (!gamebook.player.started) {
gamebook.start();
}
if (!nr in this.sections) {
throw new Exception("Can not turn to non-existing section "
+ nr + ".");
}
this.displaySection(nr);
},
'start' : function() {
this.hideIntroSections();
this.addClassToClass('startlink', 'nodisplay');
this.addClassToClass('resumelink', 'nodisplay');
gamebook.player.started = true;
},
'displaySection' : function(nr) {
if (this.player.currentSection > 0) {
var section = this.sections[this.player.currentSection];
section.element.style.display = 'none';
}
var e = this.sections[nr].element;
this.runActions(e.getElementsByClassName('sectiontext')[0]);
e.style.display = 'block';
this.player.currentSection = nr;
this.saveGame();
},
//FIXME move out from gamebook object
'saveGame' : function() {
if (typeof window !== 'undefined' && 'localStorage' in window) {
window.localStorage.setItem(this.getSavedGameName(),
this.player.getState());
}
},
//FIXME move out from gamebook object
'hasSavedGame' : function() {
if (typeof window !== 'undefined' && 'localStorage' in window) {
return window.localStorage.getItem(this.getSavedGameName());
} else {
return false;
}
},
//FIXME move out from gamebook object
'loadGame' : function() {
if (typeof window !== 'undefined' && 'localStorage' in window) {
var state = window.localStorage.getItem(this.getSavedGameName());
this.player.setState(state);
this.turnTo(this.player.currentSection);
this.updateCollectionsView();
} else {
//FIXME some kind of error, because we should never get here
}
},
'getSavedGameName' : function() {
return 'savedGamebookPlayer-' + this.id;
},
'hideIntroSections' : function() {
this.addClassToClass('introsection', 'nodisplay');
this.removeClassFromClass('displayintrolink', 'nodisplay');
this.addClassToClass('hideintrolink', 'nodisplay');
},
'showIntroSections' : function() {
this.runActionsInIntroSections();
this.removeClassFromClass('introsection', 'nodisplay');
this.addClassToClass('displayintrolink', 'nodisplay');
this.removeClassFromClass('hideintrolink', 'nodisplay');
document.body.scrollIntoView();
},
'runActionsInIntroSections' : function() {
Array.prototype.forEach.call(
document.getElementsByClassName('introsectionbody'),
gamebook.runActions);
},
'addClassToClass' : function(className, addClass) {
Array.prototype.forEach.call(
document.getElementsByClassName(className),
function(e) {
e.classList.add(addClass);
});
},
'removeClassFromClass' : function(className, removeClass) {
Array.prototype.forEach.call(
document.getElementsByClassName(className),
function(e) {
e.classList.remove(removeClass);
});
},
'runActions' : function(e) {
var enableNextLink = true;
var hasXorScope = false;
var hasAutoScope = false;
var xorEnableNext = false;
var autoDisableAllRemainingLinks = (
gamebook.player.started && e.classList.contains('introsectionbody'));
Array.prototype.forEach.call(e.childNodes, function(c) {
if (!c.classList) {
return;
}
if (c.classList.contains('sectionref')) {
if (enableNextLink && !autoDisableAllRemainingLinks) {
gamebook.enableLink(c);
if (hasAutoScope) {
autoDisableAllRemainingLinks = true;
}
} else {
gamebook.disableLink(c);
}
enableNextLink = !(hasXorScope && !xorEnableNext);
hasAutoScope = false;
hasXorScope = false;
} else if (c.classList.contains('collect')) {
gamebook.player.collect(c.dataset.type, c.dataset.name);
} else if (c.classList.contains('add')) {
gamebook.player.add(c.dataset.type, c.dataset.what);
} else if (c.classList.contains('drop')) {
gamebook.player.drop(c.dataset.type, c.dataset.what);
} else if (c.classList.contains('has')) {
enableNextLink = gamebook.player.has(c.dataset.type,
c.dataset.what);
} else if (c.classList.contains('hasnot')) {
enableNextLink = !gamebook.player.has(c.dataset.type,
c.dataset.what);
} else if (c.classList.contains('xor')) {
hasXorScope = true;
xorEnableNext = !enableNextLink;
} else if (c.classList.contains('auto')) {
hasAutoScope = true;
} else if (c.classList.contains('random')) {
c.addEventListener('click',
gamebook.enableRandomLinkAfter);
c.classList.add("enabledlink");
c.classList.remove("disabledlink");
autoDisableAllRemainingLinks = true;
}
});
},
'enableLink' : function(e) {
e.addEventListener('click',
gamebook.getTurnToFunction(e.dataset.ref));
e.classList.add("enabledlink");
e.classList.remove("disabledlink");
},
'disableLink' : function(e) {
e.removeEventListener('click',
gamebook.getTurnToFunction(e.dataset.ref));
e.classList.remove("enabledlink");
e.classList.add("disabledlink");
},
'enableRandomLinkAfter' : function(event) {
this.classList.remove("enabledlink");
this.classList.add("disabledlink");
var links = [];
var e = this.nextSibling;
while (e) {
if (e.classList && e.classList.contains('sectionref')) {
links.push(e);
}
e = e.nextSibling;
}
if (links.length > 0) {
var selected = links[Math.floor(Math.random()*links.length)]
gamebook.enableLink(selected);
} else {
console.log("Random with nothing to select?");
}
event.preventDefault();
},
'addCollectionView' : function(type, name) {
var ce = document.getElementById('collections');
var template = document.getElementById('collectionTemplate');
var e = template.cloneNode(true);
e.className = "collection";
e.getElementsByClassName('collectionheading')[0].innerHTML = name;
e.dataset.type = type;
ce.appendChild(e);
},
'updateCollectionsView' : function() {
var ce = document.getElementById('collections');
Array.prototype.forEach.call(ce.childNodes, function(c) {
if (c.className === 'collection') {
var type = c.dataset.type;
var collection = gamebook.player.collections[type];
var cc = c.getElementsByClassName('collectioncontents')[0];
cc.innerHTML = collection.contents.join(', ');
}
});
},
'getTurnToFunction' : function(nr) {
if (nr in this.turnToFunctions) {
return this.turnToFunctions[nr];
} else {
var f = function () {
gamebook.turnTo(nr);
};
this.turnToFunctions[nr] = f;
return f;
}
}
};
// little hack to make easy to test from node.js
if (typeof exports !== 'undefined') {
exports.gamebook = gamebook;
}
</script>
<style>
.startlink,.sectionref,.displayintrolink,.hideintrolink,.found,.add,.random,
.resumelink{
font-weight: bold;
margin: 0.2em;
vertical-align: middle;
white-space: nowrap;
}
.sectionref.enabledlink {
padding-left: 1.5em;
padding-right: 1.5em;
}
.startlink,.enabledlink,.displayintrolink,.hideintrolink,.found,.random,
.resumelink {cursor: pointer;}
.startlink,.enabledlink,.displayintrolink,.hideintrolink,.found,
.random,.resumelink {background: #eef;
}
.startlink:hover,.enabledlink:hover,.displayintrolink:hover,
.hideintrolink:hover,.resumelink:hover {background: #a9f;}
.disabledlink {color: #bbb; cursor: not-allowed; background: inherit;}
.disabledlink:hover {background: inherit;}
.sectionnumber,.introsectionheading {font-weight: bolder;
width: 100%;
text-align: center;}
.section {display: none; width: 90%; margin-left: 5%; margin-right: 5%;}
.sectiontext {margin-top: 0.5em;}
.gamebook {max-width: 30em; padding: 1em; width: 100%; font-size: 133%;}
.collections {margin-top: 4em;}
.collection {background: #ddd; margin-top: 1em;}
.collectionheading {}
.collectionheading::after {content: ": ";}
.collectioncontents {}
.collect {}
.add {font-weight: bold;}
.drop {font-style: italic;}
.has {font-style: italic;}
.hasnot {font-style: italic;}
.collectionTemplate {display: none;}
.sectionimage {width: 100%; padding: 1em;}
.nodisplay {display: none;}
.resumenr {font-weight: bold;}
</style>
</head>
<body>
<div class="hideintrolink nodisplay"
onclick="gamebook.hideIntroSections()">(hide instructions)</div>
<div class="gamebook">
<div class="resumelink nodisplay"
onclick="gamebook.loadGame()">Resume saved game.</div>
<div class="startlink"
onclick="gamebook.turnTo(1)">Turn to 1 to begin.</div>
<script>
if (gamebook.hasSavedGame()) {
var resumeLinks = document.getElementsByClassName('resumelink');
Array.prototype.forEach.call(resumeLinks, function(e) {
e.classList.remove('nodisplay');
});
}
</script>
<div class="section" id="section1">
<div class="sectionnumber" id="para1">1</div>
<div class="sectiontext">
Demonstrating how <span class="collect" data-type="code"
data-name="Codewords">Codewords</span> (AKA sightings) can be used. Go to <a class="sectionref enabledlink" data-ref="2">2</a>.
</div>
</div>
<script>
if (this.gamebook) {
gamebook.addSection(1, document.getElementById('section1'));
}
</script><div class="section" id="section2">
<div class="sectionnumber" id="para2">2</div>
<div class="sectiontext">
Got codeword <span class="add" data-type="code"
data-what="warrior">warrior</span>. Simple enough to set a codeword. Turn to <a class="sectionref enabledlink" data-ref="9">9</a>.
</div>
</div>
<script>
if (this.gamebook) {
gamebook.addSection(2, document.getElementById('section2'));
}
</script><div class="section" id="section3">
<div class="sectionnumber" id="para3">3</div>
<div class="sectiontext">
That was easy.
</div>
</div>
<script>
if (this.gamebook) {
gamebook.addSection(3, document.getElementById('section3'));
}
</script><div class="section" id="section4">
<div class="sectionnumber" id="para4">4</div>
<div class="sectiontext">
OK, if you have the codeword <span class="has" data-type="code" data-what="warrior">warrior</span>, you may turn to <span class="xor"></span><a class="sectionref enabledlink" data-ref="3">3</a> otherwise you may go back to <a class="sectionref enabledlink" data-ref="2">2</a>. Although we both know you have that codeword. If you have the codeword <span class="has" data-type="code" data-what="fun">fun</span> you may turn to <span class="xor"></span><a class="sectionref enabledlink" data-ref="5">5</a>, without it you can go to <a class="sectionref enabledlink" data-ref="8">8</a>.
</div>
</div>
<script>
if (this.gamebook) {
gamebook.addSection(4, document.getElementById('section4'));
}
</script><div class="section" id="section5">
<div class="sectionnumber" id="para5">5</div>
<div class="sectiontext">
Cheater! There is no way you can have codeword fun.
</div>
</div>
<script>
if (this.gamebook) {
gamebook.addSection(5, document.getElementById('section5'));
}
</script><div class="section" id="section6">
<div class="sectionnumber" id="para6">6</div>
<div class="sectiontext">
If you have the codeword <span class="has" data-type="code" data-what="fun">fun</span> turn to <span class="auto"></span><a class="sectionref enabledlink" data-ref="5">5</a>. Otherwise you can go to the end at <a class="sectionref enabledlink" data-ref="3">3</a> or to the xortest at <a class="sectionref enabledlink" data-ref="4">4</a>.
</div>
</div>
<script>
if (this.gamebook) {
gamebook.addSection(6, document.getElementById('section6'));
}
</script><div class="section" id="section7">
<div class="sectionnumber" id="para7">7</div>
<div class="sectiontext">
If you have codeword <span class="has" data-type="code" data-what="warrior">warrior</span> turn to <span class="auto"></span><a class="sectionref enabledlink" data-ref="6">6</a>. Otherwise you can go to the end at <a class="sectionref enabledlink" data-ref="3">3</a> or back to <a class="sectionref enabledlink" data-ref="1">1</a>.
</div>
</div>
<script>
if (this.gamebook) {
gamebook.addSection(7, document.getElementById('section7'));
}
</script><div class="section" id="section8">
<div class="sectionnumber" id="para8">8</div>
<div class="sectiontext">
This is just to demonstrate choices allowed when not having a codeword. Now go on to <a class="sectionref enabledlink" data-ref="7">7</a> (autotest) or <a class="sectionref enabledlink" data-ref="4">4</a> (xor test).
</div>
</div>
<script>
if (this.gamebook) {
gamebook.addSection(8, document.getElementById('section8'));
}
</script><div class="section" id="section9">
<div class="sectionnumber" id="para9">9</div>
<div class="sectiontext">
If you have the codeword <span class="has" data-type="code" data-what="warrior">warrior</span> you may turn to <a class="sectionref enabledlink" data-ref="3">3</a>. If you do not have the codeword <span class="hasnot" data-type="code"
data-what="fun">fun</span>, you may turn to <a class="sectionref enabledlink" data-ref="8">8</a>. If you have the codeword <span class="has" data-type="code" data-what="fun">fun</span>, you may instead turn to <a class="sectionref enabledlink" data-ref="5">5</a>. Otherwise see <a class="sectionref enabledlink" data-ref="4">4</a>.
</div>
</div>
<script>
if (this.gamebook) {
gamebook.addSection(9, document.getElementById('section9'));
}
</script> <div id="collections" class="collections">
</div>
<div id="collectionTemplate" class="collectionTemplate">
<span class="collectionheading"></span>
<span class="collectioncontents"></span>
</div>
</div>
<script>
if (this.gamebook) {
gamebook.runActionsInIntroSections();
}
</script>
<div class="displayintrolink nodisplay"
onclick="gamebook.showIntroSections()">(show instructions)</div>
</div>
</body>
</html>