1
0
Fork 0
mirror of https://github.com/Oreolek/gamebookformat.git synced 2024-07-03 07:05:09 +03:00
gamebookformat/expected/format.html

453 lines
16 KiB
HTML
Raw Normal View History

<!DOCTYPE html>
<html>
<head>
<meta charset='utf-8'>
<meta name="viewport"
content="width=device-width, initial-scale=1, maximum-scale=1">
<title>Format</title>
<script>
2013-06-16 20:43:04 +03:00
var gamebook = {
'id' : 'format2',
'player' : {
'started' : false,
2013-06-16 20:43:04 +03:00
'currentSection' : -1,
'collections' : {},
'collect' : function(type, name) {
2013-06-16 22:18:28 +03:00
if (type in this.collections) {
return;
}
this.collections[type] = {
'name' : name,
'contents' : [],
2013-06-16 20:43:04 +03:00
'dropped' : {},
'add' : function(what) {
if (this.contents.indexOf(what) === -1
2013-06-16 20:43:04 +03:00
&& !(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);
2013-06-16 20:43:04 +03:00
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);
2013-06-16 20:43:04 +03:00
},
'getState' : function() {
return JSON.stringify({
'collections' : this.collections,
2013-06-16 22:18:28 +03:00
'currentSection' : this.currentSection
2013-06-16 20:43:04 +03:00
});
},
'setState' : function(state) {
2013-06-16 22:18:28 +03:00
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');
2013-06-16 22:18:28 +03:00
this.addClassToClass('resumelink', 'nodisplay');
gamebook.player.started = true;
},
'displaySection' : function(nr) {
2013-06-16 20:43:04 +03:00
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';
2013-06-16 20:43:04 +03:00
this.player.currentSection = nr;
2013-06-16 22:18:28 +03:00
this.saveGame();
},
//FIXME move out from gamebook object
'saveGame' : function() {
if (typeof window !== 'undefined' && 'localStorage' in window) {
window.localStorage.setItem(this.getSavedGameName(),
2013-06-16 22:18:28 +03:00
this.player.getState());
}
},
//FIXME move out from gamebook object
'hasSavedGame' : function() {
if (typeof window !== 'undefined' && 'localStorage' in window) {
return window.localStorage.getItem(this.getSavedGameName());
2013-06-16 22:18:28 +03:00
} 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());
2013-06-16 22:18:28 +03:00
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;
}
}
};
2013-06-16 20:43:04 +03:00
// little hack to make easy to test from node.js
if (typeof exports !== 'undefined') {
exports.gamebook = gamebook;
}
</script>
<style>
2013-06-16 22:18:28 +03:00
.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;
}
2013-06-16 22:18:28 +03:00
.startlink,.enabledlink,.displayintrolink,.hideintrolink,.found,.random,
.resumelink {cursor: pointer;}
.startlink,.enabledlink,.displayintrolink,.hideintrolink,.found,
2013-06-16 22:18:28 +03:00
.random,.resumelink {background: #eef;
}
.startlink:hover,.enabledlink:hover,.displayintrolink:hover,
2013-06-16 22:18:28 +03:00
.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;}
2013-06-16 22:18:28 +03:00
.resumenr {font-weight: bold;}
</style>
</head>
<body>
<div class="hideintrolink nodisplay"
onclick="gamebook.hideIntroSections()">HIDE THE INTRO</div>
<div class="gamebook">
<div class="introsection">
<div class="introsectionheading">Introduction</div>
<div class="introsectionbody">
Adding an introduction to the gamebook here. This will create a section, but it will not be shuffled nor numbered with the gamebook sections below.
</div>
</div>
<div class="introsection">
<div class="introsectionheading">Another Heading</div>
<div class="introsectionbody">
This starts another non-shuffled section.
</div>
</div>
2013-06-16 22:18:28 +03:00
<div class="resumelink nodisplay"
onclick="gamebook.loadGame()">Resume saved game.</div>
<div class="startlink"
onclick="gamebook.turnTo(1)">Adventure begins in section 1.</div>
2013-06-16 22:18:28 +03:00
<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">
2013-06-16 22:18:28 +03:00
This examples tests gamebook formatting, not so much game mechanics or references. Currently there is nothing here really. This section contains some tricky characters to quote, like } and { and " and ' and \. HTML will probably not like &lt;div&gt; or &amp;boom;. There should be an image below as well. If something broke, turn to <a class="sectionref enabledlink" data-ref="2">2</a>, otherwise turn to <a class="sectionref enabledlink" data-ref="3">3</a>. <img src="testimage.png" class="sectionimage"></img>
</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">
2013-06-16 22:18:28 +03:00
Bad.
</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">
2013-06-16 22:18:28 +03:00
Good!
</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">
2013-06-16 22:18:28 +03:00
Sections tagged as dummy will not be visible in output at all.
</div>
</div>
<script>
if (this.gamebook) {
gamebook.addSection(4, document.getElementById('section4'));
}
</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 THE INTRO</div>
2013-06-14 23:24:56 +03:00
</div>
</body>
</html>