1
0
Fork 0
mirror of https://github.com/Oreolek/gamebookformat.git synced 2024-06-26 03:41:04 +03:00

Checking generated examples against saved expected outputs.

This commit is contained in:
Pelle Nilsson 2013-06-13 23:21:34 +02:00
parent d99ca50fa2
commit ca4b8389a8
33 changed files with 3938 additions and 2 deletions

View file

@ -35,6 +35,14 @@ uploadto=$(shell cat .uploadto)
%.png: %.dot
dot -Tpng $< > $@
expected: all
$(RM) expected/* && cp examples/*.{rtf,tex,html,debug,txt,dot,map} \
expected
checkexpected: all
diff -r -x "*.aux" -x "*.gamebook" -x "*.log" -x "*.out" -x "*.png" \
-x "*.pdf" -x .gitignore -q examples expected
upload: html png pdf rtf
if [ -n "$(uploadto)" ]; then \
scp examples/*.html examples/*.png examples/*.pdf examples/*.rtf $(uploadto);\

0
expected/.gitignore vendored Normal file
View file

17
expected/codewords.debug Normal file
View file

@ -0,0 +1,17 @@
BEGIN DEBUG OUTPUT
Book title: Gamebook
Number of sections: 9
Turn to 1 to begin.
1 (start) - Demonstrating how [COLLECT code]Codewords[/COLLECT] (AKA sightings) can be used. Go to 2.
2 (second) - Got codeword [ADD code]warrior[/ADD]. Simple enough to set a codeword. Turn to 5.
3 (xortest) - OK, if you have the codeword [HAS code]warrior[/HAS], you may turn to 4 otherwise you may go back to 2. Although we both know you have that codeword. If you have the codeword [HAS code]fun[/HAS] you may turn to 6, without it you can go to 8.
4 (the_end) - That was easy.
5 (choice) - If you have the codeword [HAS code]warrior[/HAS] you may turn to 4. If you do not have the codeword [HAS NOT code]fun[/HAS NOT], you may turn to 8. If you have the codeword [HAS code]fun[/HAS], you may instead turn to 6. Otherwise see 3.
6 (cheater) - Cheater! There is no way you can have codeword fun.
7 (noautotest) - If you have the codeword [HAS code]fun[/HAS] turn to ((automatic))6. Otherwise you can go to the end at 4 or to the xortest at 3.
8 (notsofun) - This is just to demonstrate choices allowed when not having a codeword. Now go on to 9 (autotest) or 3 (xor test).
9 (autotest) - If you have codeword [HAS code]warrior[/HAS] turn to ((automatic))7. Otherwise you can go to the end at 4 or back to 1.
END DEBUG OUTPUT

33
expected/codewords.dot Normal file
View file

@ -0,0 +1,33 @@
digraph gamebook {
1->2
2->5
3->4
3->2
3->8
3->6
5->4
5->6
5->3
5->8
7->6
7->3
7->4
8->9
8->3
9->1
9->7
9->4
}

411
expected/codewords.html Normal file
View file

@ -0,0 +1,411 @@
<!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 = {
'player' : {
'started' : false,
'currentSection' : null,
'collections' : {},
'collect' : function(type, name) {
this.collections[type] = {
'name' : name,
'contents' : [],
'add' : function(what) {
if (this.contents.indexOf(what) === -1
&& !(what in gamebook.dropped[type])) {
this.contents.push(what);
this.contents.sort();
}
},
'drop' : function(what) {
var i = this.contents.indexOf(what);
if (i >= 0) {
this.contents.splice(i, 1);
gamebook.dropped[type][what] = true;
}
},
'has' : function(what) {
return this.contents.indexOf(what) >= 0;
}
};
gamebook.dropped[type] = {};
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);
}
},
'sections' : {},
'turnToFunctions' : {},
'dropped' : {},
'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');
gamebook.player.started = true;
},
'displaySection' : function(nr) {
if (this.player.currentSection) {
this.player.currentSection.element.style.display = 'none';
}
var e = this.sections[nr].element;
this.runActions(e.getElementsByClassName('sectiontext')[0]);
e.style.display = 'block';
this.player.currentSection = gamebook.sections[nr];
},
'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;
}
}
};
</script>
<style>
.startlink,.sectionref,.displayintrolink,.hideintrolink,.found,.add,.random {
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 {
cursor: pointer;}
.startlink,.enabledlink,.displayintrolink,.hideintrolink,.found,
.random {background: #eef;
}
.startlink:hover,.enabledlink:hover,.displayintrolink:hover,
.hideintrolink:hover {background: #a9f;}
.disabledlink {color: #bbb; cursor: not-allowed; background: inherit;}
.disabledlink:hover {background: inherit;}
.sectionnumber {font-weight: bolder;
margin-left: 50%;
margin-right: 50%;}
.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;}
</style>
</head>
<body>
<div class="hideintrolink nodisplay"
onclick="gamebook.hideIntroSections()">(hide instructions)</div>
<div class="gamebook">
<div class="startlink"
onclick="gamebook.turnTo(1)">Turn to 1 to begin.</div>
<div class="section" id="section1">
<span class="sectionnumber" id="para1">1</span>
<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">
<span class="sectionnumber" id="para2">2</span>
<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="5">5</a>.
</div>
</div>
<script>
if (this.gamebook) {
gamebook.addSection(2, document.getElementById('section2'));
}
</script> <div class="section" id="section3">
<span class="sectionnumber" id="para3">3</span>
<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="4">4</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="6">6</a>, without it you can go to <a class="sectionref enabledlink" data-ref="8">8</a>.
</div>
</div>
<script>
if (this.gamebook) {
gamebook.addSection(3, document.getElementById('section3'));
}
</script> <div class="section" id="section4">
<span class="sectionnumber" id="para4">4</span>
<div class="sectiontext">
That was easy.
</div>
</div>
<script>
if (this.gamebook) {
gamebook.addSection(4, document.getElementById('section4'));
}
</script> <div class="section" id="section5">
<span class="sectionnumber" id="para5">5</span>
<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="4">4</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="6">6</a>. Otherwise see <a class="sectionref enabledlink" data-ref="3">3</a>.
</div>
</div>
<script>
if (this.gamebook) {
gamebook.addSection(5, document.getElementById('section5'));
}
</script> <div class="section" id="section6">
<span class="sectionnumber" id="para6">6</span>
<div class="sectiontext">
Cheater! There is no way you can have codeword fun.
</div>
</div>
<script>
if (this.gamebook) {
gamebook.addSection(6, document.getElementById('section6'));
}
</script> <div class="section" id="section7">
<span class="sectionnumber" id="para7">7</span>
<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="6">6</a>. Otherwise you can go to the end at <a class="sectionref enabledlink" data-ref="4">4</a> or to the xortest at <a class="sectionref enabledlink" data-ref="3">3</a>.
</div>
</div>
<script>
if (this.gamebook) {
gamebook.addSection(7, document.getElementById('section7'));
}
</script> <div class="section" id="section8">
<span class="sectionnumber" id="para8">8</span>
<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="9">9</a> (autotest) or <a class="sectionref enabledlink" data-ref="3">3</a> (xor test).
</div>
</div>
<script>
if (this.gamebook) {
gamebook.addSection(8, document.getElementById('section8'));
}
</script> <div class="section" id="section9">
<span class="sectionnumber" id="para9">9</span>
<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="7">7</a>. Otherwise you can go to the end at <a class="sectionref enabledlink" data-ref="4">4</a> or back to <a class="sectionref enabledlink" data-ref="1">1</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>
</body>
</html>

97
expected/codewords.rtf Normal file
View file

@ -0,0 +1,97 @@
{\rtf1\ansi\ansicpg1252\cocoartf1038\cocoasubrtf360
{\fonttbl\f0\fswiss\fcharset0 Helvetica;}
{\colortbl;\red255\green255\blue255;}
\paperw11900\paperh16840\margl1440\margr1440\vieww14140\viewh14860\viewkind0
\pard\tx566\tx1133\tx1700\tx2267\tx2834\tx3401\tx3968\tx4535\tx5102\tx5669\tx6236\tx6803\ql\qnatural\pardirnatural
\f0\b\fs24 \cf0
\b \qc Gamebook
\b0\
\b Turn to 1 to begin.
\b0\
\
\b \qc 1
\b0\
\ql Demonstrating how Codewords (AKA sightings) can be used. Go to \b 2
\b0
. \
\
\b \qc 2
\b0\
\ql Got codeword warrior. Simple enough to set a codeword. Turn to \b 5
\b0
. \
\
\b \qc 3
\b0\
\ql OK, if you have the codeword warrior, you may turn to \b 4
\b0
otherwise you may go back to \b 2
\b0
. Although we both know you have that codeword. If you have the codeword fun you may turn to \b 6
\b0
, without it you can go to \b 8
\b0
. \
\
\b \qc 4
\b0\
\ql That was easy. \
\
\b \qc 5
\b0\
\ql If you have the codeword warrior you may turn to \b 4
\b0
. If you do not have the codeword fun, you may turn to \b 8
\b0
. If you have the codeword fun, you may instead turn to \b 6
\b0
. Otherwise see \b 3
\b0
. \
\
\b \qc 6
\b0\
\ql Cheater! There is no way you can have codeword fun. \
\
\b \qc 7
\b0\
\ql If you have the codeword fun turn to \b 6
\b0
. Otherwise you can go to the end at \b 4
\b0
or to the xortest at \b 3
\b0
. \
\
\b \qc 8
\b0\
\ql This is just to demonstrate choices allowed when not having a codeword. Now go on to \b 9
\b0
(autotest) or \b 3
\b0
(xor test). \
\
\b \qc 9
\b0\
\ql If you have codeword warrior turn to \b 7
\b0
. Otherwise you can go to the end at \b 4
\b0
or back to \b 1
\b0
. \
\
}

112
expected/codewords.tex Normal file
View file

@ -0,0 +1,112 @@
\documentclass[a5,onecolumn]{book}
\usepackage[utf8]{inputenc}
\usepackage[T1]{fontenc}
\usepackage[hidelinks]{hyperref}
\usepackage{graphicx}
\usepackage[top=3.3cm, bottom=3.3cm, left=2cm, right=2cm]{geometry}
\newif\ifpdf
\ifx\pdfoutput\undefined
\pdffalse
\else
\ifnum\pdfoutput=1
\pdftrue
\else
\pdffalse
\fi
\fi
\title{Gamebook}
\author{}
\date{}
\newcounter{sectionnr}
\begin{document}
\maketitle
\thispagestyle{empty}
\pagestyle{empty}
\clearpage
Turn to 1 to begin.
\phantomsection
\refstepcounter{sectionnr}
\label{section1}
\subsection*{\begin{center} \textbf{1} \end{center}}
\noindent
Demonstrating how Codewords (AKA sightings) can be used. Go to \textbf{\autoref{section2}}.
\vspace{1em}
\phantomsection
\refstepcounter{sectionnr}
\label{section2}
\subsection*{\begin{center} \textbf{2} \end{center}}
\noindent
Got codeword \textbf{warrior}. Simple enough to set a codeword. Turn to \textbf{\autoref{section5}}.
\vspace{1em}
\phantomsection
\refstepcounter{sectionnr}
\label{section3}
\subsection*{\begin{center} \textbf{3} \end{center}}
\noindent
OK, if you have the codeword \textit{warrior}, you may turn to \textbf{\autoref{section4}} otherwise you may go back to \textbf{\autoref{section2}}. Although we both know you have that codeword. If you have the codeword \textit{fun} you may turn to \textbf{\autoref{section6}}, without it you can go to \textbf{\autoref{section8}}.
\vspace{1em}
\phantomsection
\refstepcounter{sectionnr}
\label{section4}
\subsection*{\begin{center} \textbf{4} \end{center}}
\noindent
That was easy.
\vspace{1em}
\phantomsection
\refstepcounter{sectionnr}
\label{section5}
\subsection*{\begin{center} \textbf{5} \end{center}}
\noindent
If you have the codeword \textit{warrior} you may turn to \textbf{\autoref{section4}}. If you do not have the codeword \textit{fun}, you may turn to \textbf{\autoref{section8}}. If you have the codeword \textit{fun}, you may instead turn to \textbf{\autoref{section6}}. Otherwise see \textbf{\autoref{section3}}.
\vspace{1em}
\phantomsection
\refstepcounter{sectionnr}
\label{section6}
\subsection*{\begin{center} \textbf{6} \end{center}}
\noindent
Cheater! There is no way you can have codeword fun.
\vspace{1em}
\phantomsection
\refstepcounter{sectionnr}
\label{section7}
\subsection*{\begin{center} \textbf{7} \end{center}}
\noindent
If you have the codeword \textit{fun} turn to \textbf{\autoref{section6}}. Otherwise you can go to the end at \textbf{\autoref{section4}} or to the xortest at \textbf{\autoref{section3}}.
\vspace{1em}
\phantomsection
\refstepcounter{sectionnr}
\label{section8}
\subsection*{\begin{center} \textbf{8} \end{center}}
\noindent
This is just to demonstrate choices allowed when not having a codeword. Now go on to \textbf{\autoref{section9}} (autotest) or \textbf{\autoref{section3}} (xor test).
\vspace{1em}
\phantomsection
\refstepcounter{sectionnr}
\label{section9}
\subsection*{\begin{center} \textbf{9} \end{center}}
\noindent
If you have codeword \textit{warrior} turn to \textbf{\autoref{section7}}. Otherwise you can go to the end at \textbf{\autoref{section4}} or back to \textbf{\autoref{section1}}.
\vspace{1em}
\end{document}

33
expected/codewords.txt Normal file
View file

@ -0,0 +1,33 @@
Gamebook
Turn to 1 to begin.
1
Demonstrating how Codewords (AKA sightings) can be used. Go to 2.
2
Got codeword warrior. Simple enough to set a codeword. Turn to 5.
3
OK, if you have the codeword warrior, you may turn to 4 otherwise you may go back to 2. Although we both know you have that codeword. If you have the codeword fun you may turn to 6, without it you can go to 8.
4
That was easy.
5
If you have the codeword warrior you may turn to 4. If you do not have the codeword fun, you may turn to 8. If you have the codeword fun, you may instead turn to 6. Otherwise see 3.
6
Cheater! There is no way you can have codeword fun.
7
If you have the codeword fun turn to 6. Otherwise you can go to the end at 4 or to the xortest at 3.
8
This is just to demonstrate choices allowed when not having a codeword. Now go on to 9 (autotest) or 3 (xor test).
9
If you have codeword warrior turn to 7. Otherwise you can go to the end at 4 or back to 1.

16
expected/format.debug Normal file
View file

@ -0,0 +1,16 @@
BEGIN DEBUG OUTPUT
Book title: Format
Number of sections: 4
Introduction
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.
Another Heading
This starts another non-shuffled section.
Adventure begins in section 1.
1 (start) - 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 <div> or &boom;. There should be an image below as well. If something broke, turn to 2, otherwise turn to 4. [IMG]testimage.png[/IMG]
2 (bad) - Bad.
3 (dum) - Sections tagged as dummy will not be visible in output at all.
4 (good) - Good!
END DEBUG OUTPUT

7
expected/format.dot Normal file
View file

@ -0,0 +1,7 @@
digraph gamebook {
1->2
1->4
}

370
expected/format.html Normal file
View file

@ -0,0 +1,370 @@
<!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>
var gamebook = {
'player' : {
'started' : false,
'currentSection' : null,
'collections' : {},
'collect' : function(type, name) {
this.collections[type] = {
'name' : name,
'contents' : [],
'add' : function(what) {
if (this.contents.indexOf(what) === -1
&& !(what in gamebook.dropped[type])) {
this.contents.push(what);
this.contents.sort();
}
},
'drop' : function(what) {
var i = this.contents.indexOf(what);
if (i >= 0) {
this.contents.splice(i, 1);
gamebook.dropped[type][what] = true;
}
},
'has' : function(what) {
return this.contents.indexOf(what) >= 0;
}
};
gamebook.dropped[type] = {};
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);
}
},
'sections' : {},
'turnToFunctions' : {},
'dropped' : {},
'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');
gamebook.player.started = true;
},
'displaySection' : function(nr) {
if (this.player.currentSection) {
this.player.currentSection.element.style.display = 'none';
}
var e = this.sections[nr].element;
this.runActions(e.getElementsByClassName('sectiontext')[0]);
e.style.display = 'block';
this.player.currentSection = gamebook.sections[nr];
},
'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;
}
}
};
</script>
<style>
.startlink,.sectionref,.displayintrolink,.hideintrolink,.found,.add,.random {
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 {
cursor: pointer;}
.startlink,.enabledlink,.displayintrolink,.hideintrolink,.found,
.random {background: #eef;
}
.startlink:hover,.enabledlink:hover,.displayintrolink:hover,
.hideintrolink:hover {background: #a9f;}
.disabledlink {color: #bbb; cursor: not-allowed; background: inherit;}
.disabledlink:hover {background: inherit;}
.sectionnumber {font-weight: bolder;
margin-left: 50%;
margin-right: 50%;}
.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;}
</style>
</head>
<body>
<div class="hideintrolink nodisplay"
onclick="gamebook.hideIntroSections()">HIDE THE INTRO</div>
<div class="gamebook">
<div class="introsection">
<span class="introsectionheading">Introduction</span>
<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">
<span class="introsectionheading">Another Heading</span>
<div class="introsectionbody">
This starts another non-shuffled section.
</div>
</div>
<div class="startlink"
onclick="gamebook.turnTo(1)">Adventure begins in section 1.</div>
<div class="section" id="section1">
<span class="sectionnumber" id="para1">1</span>
<div class="sectiontext">
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="4">4</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">
<span class="sectionnumber" id="para2">2</span>
<div class="sectiontext">
Bad.
</div>
</div>
<script>
if (this.gamebook) {
gamebook.addSection(2, document.getElementById('section2'));
}
</script> <div class="section" id="section3">
<span class="sectionnumber" id="para3">3</span>
<div class="sectiontext">
Sections tagged as dummy will not be visible in output at all.
</div>
</div>
<script>
if (this.gamebook) {
gamebook.addSection(3, document.getElementById('section3'));
}
</script> <div class="section" id="section4">
<span class="sectionnumber" id="para4">4</span>
<div class="sectiontext">
Good!
</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>
</body>
</html>

54
expected/format.rtf Normal file
View file

@ -0,0 +1,54 @@
{\rtf1\ansi\ansicpg1252\cocoartf1038\cocoasubrtf360
{\fonttbl\f0\fswiss\fcharset0 Helvetica;}
{\colortbl;\red255\green255\blue255;}
\paperw11900\paperh16840\margl1440\margr1440\vieww14140\viewh14860\viewkind0
\pard\tx566\tx1133\tx1700\tx2267\tx2834\tx3401\tx3968\tx4535\tx5102\tx5669\tx6236\tx6803\ql\qnatural\pardirnatural
\f0\b\fs24 \cf0
\b \qc Format
\b0\
\b \qc Introduction
\b0\
\ql 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. \
\
\b \qc Another Heading
\b0\
\ql This starts another non-shuffled section. \
\
\b Adventure begins in section 1.
\b0\
\
\b \qc 1
\b0\
\ql 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 <div> or &boom;. There should be an image below as well. If something broke, turn to \b 2
\b0
, otherwise turn to \b 4
\b0
. testimage.png \
\
\b \qc 2
\b0\
\ql Bad. \
\
\b \qc 3
\b0\
\ql Sections tagged as dummy will not be visible in output at all. \
\
\b \qc 4
\b0\
\ql Good! \
\
}

88
expected/format.tex Normal file
View file

@ -0,0 +1,88 @@
\documentclass[a5,onecolumn]{book}
\usepackage[utf8]{inputenc}
\usepackage[T1]{fontenc}
\usepackage[hidelinks]{hyperref}
\usepackage{graphicx}
\usepackage[top=3.3cm, bottom=3.3cm, left=2cm, right=2cm]{geometry}
\newif\ifpdf
\ifx\pdfoutput\undefined
\pdffalse
\else
\ifnum\pdfoutput=1
\pdftrue
\else
\pdffalse
\fi
\fi
\title{Format}
\author{}
\date{}
\newcounter{sectionnr}
\begin{document}
\maketitle
\thispagestyle{empty}
\pagestyle{empty}
\clearpage
\subsection*{\begin{center} \textbf{Introduction} \end{center}}
\noindent
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.
\vspace{1em}
\subsection*{\begin{center} \textbf{Another Heading} \end{center}}
\noindent
This starts another non-shuffled section.
\vspace{1em}
Adventure begins in section 1.
\phantomsection
\refstepcounter{sectionnr}
\label{section1}
\subsection*{\begin{center} \textbf{1} \end{center}}
\noindent
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 \textbackslash. HTML will probably not like <div> or \&boom;. There should be an image below as well. If something broke, turn to \textbf{\autoref{section2}}, otherwise turn to \textbf{\autoref{section4}}. \begin{center}
\includegraphics[width=.9\textwidth]{testimage.png}
\end{center}
\vspace{1em}
\phantomsection
\refstepcounter{sectionnr}
\label{section2}
\subsection*{\begin{center} \textbf{2} \end{center}}
\noindent
Bad.
\vspace{1em}
\phantomsection
\refstepcounter{sectionnr}
\label{section3}
\subsection*{\begin{center} \textbf{3} \end{center}}
\noindent
Sections tagged as dummy will not be visible in output at all.
\vspace{1em}
\phantomsection
\refstepcounter{sectionnr}
\label{section4}
\subsection*{\begin{center} \textbf{4} \end{center}}
\noindent
Good!
\vspace{1em}
\end{document}

24
expected/format.txt Normal file
View file

@ -0,0 +1,24 @@
Format
Introduction
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.
Another Heading
This starts another non-shuffled section.
Adventure begins in section 1.
1
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 <div> or &boom;. There should be an image below as well. If something broke, turn to 2, otherwise turn to 4. testimage.png
2
Bad.
3
Sections tagged as dummy will not be visible in output at all.
4
Good!

19
expected/items.debug Normal file
View file

@ -0,0 +1,19 @@
BEGIN DEBUG OUTPUT
Book title: Items
Number of sections: 11
Turn to 1 to begin.
1 (start) - Demonstrating how to manage player [COLLECT item]Inventory[/COLLECT]. You start the book carrying a [ADD item]sword[/ADD] and a [ADD item]shield[/ADD]. Turn to 2.
2 (tjunction) - You have reached a t-junction. Here you find a [FOUND item]key[/FOUND] and a [FOUND item]stick[/FOUND]. You can go west to 7, or east to 4.
3 (cut_rope) - OK. That was fun. Turn to 10.
4 (curse) - There is a [FOUND item]cursed bracelet[/FOUND] here. You can go on to 6 or go back to 2. You can also drop the [HAS item]stick[/HAS] for no particular reason if you have it, see 11.
5 (treasure) - You found [FOUND item]something valuable[/FOUND], but there is no way forward, so you head back to 2.
6 (portal) - A magic portal ahead will only allow you to pass if you did not pick up the [HAS NOT item]cursed bracelet[/HAS NOT], leading you to 5. If you have the [HAS item]cursed bracelet[/HAS] you have to go back to 2 instead. Actually feel free to head back to 2 either way.
7 (door) - There is a locked door here.eh If you have a [HAS item]key[/HAS] you can use that to open the door, see 8. Being right before the link should be enough for the formatter to figure out that the key is required to be allowed to follow the link. Else you can try to open with the [HAS item]sword[/HAS], if you have it, see 9. Hopefully the magic is good enough to pair pre-conditions to links, or more markup must be added later. You could also try to go back to pick up the key, see 2.
8 (inside) - There is a rope here that can be cut using a [HAS item]sword[/HAS]. If you have one and want to do that, see 3. Otherwise turn to 10.
9 (attempt_break_door_with_sword) - OK. The door is broken, but so is the [DROP item]sword[/DROP]. Turn to 8.
10 (won) - Congratulations, you won.
11 (drop_stick) - OK [DROP item]stick[/DROP] dropped. Turn back to 2 to confirm stick can not be picked up again even if the text says it is there (books work that way, although ideally this dynamic version should provide some hints that it is no longer there).
END DEBUG OUTPUT

28
expected/items.dot Normal file
View file

@ -0,0 +1,28 @@
digraph gamebook {
1->2
2->7
2->4
3->10
4->2
4->6
4->11
5->2
6->5
6->2
7->8
7->9
7->2
8->10
8->3
9->8
11->2
}

446
expected/items.html Normal file
View file

@ -0,0 +1,446 @@
<!DOCTYPE html>
<html>
<head>
<meta charset='utf-8'>
<meta name="viewport"
content="width=device-width, initial-scale=1, maximum-scale=1">
<title>Items</title>
<script>
var gamebook = {
'player' : {
'started' : false,
'currentSection' : null,
'collections' : {},
'collect' : function(type, name) {
this.collections[type] = {
'name' : name,
'contents' : [],
'add' : function(what) {
if (this.contents.indexOf(what) === -1
&& !(what in gamebook.dropped[type])) {
this.contents.push(what);
this.contents.sort();
}
},
'drop' : function(what) {
var i = this.contents.indexOf(what);
if (i >= 0) {
this.contents.splice(i, 1);
gamebook.dropped[type][what] = true;
}
},
'has' : function(what) {
return this.contents.indexOf(what) >= 0;
}
};
gamebook.dropped[type] = {};
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);
}
},
'sections' : {},
'turnToFunctions' : {},
'dropped' : {},
'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');
gamebook.player.started = true;
},
'displaySection' : function(nr) {
if (this.player.currentSection) {
this.player.currentSection.element.style.display = 'none';
}
var e = this.sections[nr].element;
this.runActions(e.getElementsByClassName('sectiontext')[0]);
e.style.display = 'block';
this.player.currentSection = gamebook.sections[nr];
},
'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;
}
}
};
</script>
<style>
.startlink,.sectionref,.displayintrolink,.hideintrolink,.found,.add,.random {
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 {
cursor: pointer;}
.startlink,.enabledlink,.displayintrolink,.hideintrolink,.found,
.random {background: #eef;
}
.startlink:hover,.enabledlink:hover,.displayintrolink:hover,
.hideintrolink:hover {background: #a9f;}
.disabledlink {color: #bbb; cursor: not-allowed; background: inherit;}
.disabledlink:hover {background: inherit;}
.sectionnumber {font-weight: bolder;
margin-left: 50%;
margin-right: 50%;}
.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;}
</style>
</head>
<body>
<div class="hideintrolink nodisplay"
onclick="gamebook.hideIntroSections()">(hide instructions)</div>
<div class="gamebook">
<div class="startlink"
onclick="gamebook.turnTo(1)">Turn to 1 to begin.</div>
<div class="section" id="section1">
<span class="sectionnumber" id="para1">1</span>
<div class="sectiontext">
Demonstrating how to manage player <span class="collect" data-type="item"
data-name="Inventory">Inventory</span>. You start the book carrying a <span class="add" data-type="item"
data-what="sword">sword</span> and a <span class="add" data-type="item"
data-what="shield">shield</span>. Turn 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">
<span class="sectionnumber" id="para2">2</span>
<div class="sectiontext">
You have reached a t-junction. Here you find a <span class="found enabledlink"
onclick="gamebook.player.add('item', 'key')"
>key</span>
and a <span class="found enabledlink"
onclick="gamebook.player.add('item', 'stick')"
>stick</span>
. You can go west to <a class="sectionref enabledlink" data-ref="7">7</a>, or east to <a class="sectionref enabledlink" data-ref="4">4</a>.
</div>
</div>
<script>
if (this.gamebook) {
gamebook.addSection(2, document.getElementById('section2'));
}
</script> <div class="section" id="section3">
<span class="sectionnumber" id="para3">3</span>
<div class="sectiontext">
OK. That was fun. Turn to <a class="sectionref enabledlink" data-ref="10">10</a>.
</div>
</div>
<script>
if (this.gamebook) {
gamebook.addSection(3, document.getElementById('section3'));
}
</script> <div class="section" id="section4">
<span class="sectionnumber" id="para4">4</span>
<div class="sectiontext">
There is a <span class="found enabledlink"
onclick="gamebook.player.add('item', 'cursed bracelet')"
>cursed bracelet</span>
here. You can go on to <a class="sectionref enabledlink" data-ref="6">6</a> or go back to <a class="sectionref enabledlink" data-ref="2">2</a>. You can also drop the <span class="has" data-type="item" data-what="stick">stick</span> for no particular reason if you have it, see <a class="sectionref enabledlink" data-ref="11">11</a>.
</div>
</div>
<script>
if (this.gamebook) {
gamebook.addSection(4, document.getElementById('section4'));
}
</script> <div class="section" id="section5">
<span class="sectionnumber" id="para5">5</span>
<div class="sectiontext">
You found <span class="found enabledlink"
onclick="gamebook.player.add('item', 'something valuable')"
>something valuable</span>
, but there is no way forward, so you head back to <a class="sectionref enabledlink" data-ref="2">2</a>.
</div>
</div>
<script>
if (this.gamebook) {
gamebook.addSection(5, document.getElementById('section5'));
}
</script> <div class="section" id="section6">
<span class="sectionnumber" id="para6">6</span>
<div class="sectiontext">
A magic portal ahead will only allow you to pass if you did not pick up the <span class="hasnot" data-type="item"
data-what="cursed bracelet">cursed bracelet</span>, leading you to <a class="sectionref enabledlink" data-ref="5">5</a>. If you have the <span class="has" data-type="item" data-what="cursed bracelet">cursed bracelet</span> you have to go back to <a class="sectionref enabledlink" data-ref="2">2</a> instead. Actually feel free to head back to <a class="sectionref enabledlink" data-ref="2">2</a> either way.
</div>
</div>
<script>
if (this.gamebook) {
gamebook.addSection(6, document.getElementById('section6'));
}
</script> <div class="section" id="section7">
<span class="sectionnumber" id="para7">7</span>
<div class="sectiontext">
There is a locked door here.eh If you have a <span class="has" data-type="item" data-what="key">key</span> you can use that to open the door, see <a class="sectionref enabledlink" data-ref="8">8</a>. Being right before the link should be enough for the formatter to figure out that the key is required to be allowed to follow the link. Else you can try to open with the <span class="has" data-type="item" data-what="sword">sword</span>, if you have it, see <a class="sectionref enabledlink" data-ref="9">9</a>. Hopefully the magic is good enough to pair pre-conditions to links, or more markup must be added later. You could also try to go back to pick up the key, see <a class="sectionref enabledlink" data-ref="2">2</a>.
</div>
</div>
<script>
if (this.gamebook) {
gamebook.addSection(7, document.getElementById('section7'));
}
</script> <div class="section" id="section8">
<span class="sectionnumber" id="para8">8</span>
<div class="sectiontext">
There is a rope here that can be cut using a <span class="has" data-type="item" data-what="sword">sword</span>. If you have one and want to do that, see <a class="sectionref enabledlink" data-ref="3">3</a>. Otherwise turn to <a class="sectionref enabledlink" data-ref="10">10</a>.
</div>
</div>
<script>
if (this.gamebook) {
gamebook.addSection(8, document.getElementById('section8'));
}
</script> <div class="section" id="section9">
<span class="sectionnumber" id="para9">9</span>
<div class="sectiontext">
OK. The door is broken, but so is the <span class="drop" data-type="item"
data-what="sword">sword</span>. Turn to <a class="sectionref enabledlink" data-ref="8">8</a>.
</div>
</div>
<script>
if (this.gamebook) {
gamebook.addSection(9, document.getElementById('section9'));
}
</script> <div class="section" id="section10">
<span class="sectionnumber" id="para10">10</span>
<div class="sectiontext">
Congratulations, you won.
</div>
</div>
<script>
if (this.gamebook) {
gamebook.addSection(10, document.getElementById('section10'));
}
</script> <div class="section" id="section11">
<span class="sectionnumber" id="para11">11</span>
<div class="sectiontext">
OK <span class="drop" data-type="item"
data-what="stick">stick</span> dropped. Turn back to <a class="sectionref enabledlink" data-ref="2">2</a> to confirm stick can not be picked up again even if the text says it is there (books work that way, although ideally this dynamic version should provide some hints that it is no longer there).
</div>
</div>
<script>
if (this.gamebook) {
gamebook.addSection(11, document.getElementById('section11'));
}
</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>
</body>
</html>

107
expected/items.rtf Normal file
View file

@ -0,0 +1,107 @@
{\rtf1\ansi\ansicpg1252\cocoartf1038\cocoasubrtf360
{\fonttbl\f0\fswiss\fcharset0 Helvetica;}
{\colortbl;\red255\green255\blue255;}
\paperw11900\paperh16840\margl1440\margr1440\vieww14140\viewh14860\viewkind0
\pard\tx566\tx1133\tx1700\tx2267\tx2834\tx3401\tx3968\tx4535\tx5102\tx5669\tx6236\tx6803\ql\qnatural\pardirnatural
\f0\b\fs24 \cf0
\b \qc Items
\b0\
\b Turn to 1 to begin.
\b0\
\
\b \qc 1
\b0\
\ql Demonstrating how to manage player Inventory. You start the book carrying a sword and a shield. Turn to \b 2
\b0
. \
\
\b \qc 2
\b0\
\ql You have reached a t-junction. Here you find a key and a stick. You can go west to \b 7
\b0
, or east to \b 4
\b0
. \
\
\b \qc 3
\b0\
\ql OK. That was fun. Turn to \b 10
\b0
. \
\
\b \qc 4
\b0\
\ql There is a cursed bracelet here. You can go on to \b 6
\b0
or go back to \b 2
\b0
. You can also drop the stick for no particular reason if you have it, see \b 11
\b0
. \
\
\b \qc 5
\b0\
\ql You found something valuable, but there is no way forward, so you head back to \b 2
\b0
. \
\
\b \qc 6
\b0\
\ql A magic portal ahead will only allow you to pass if you did not pick up the cursed bracelet, leading you to \b 5
\b0
. If you have the cursed bracelet you have to go back to \b 2
\b0
instead. Actually feel free to head back to \b 2
\b0
either way. \
\
\b \qc 7
\b0\
\ql There is a locked door here.eh If you have a key you can use that to open the door, see \b 8
\b0
. Being right before the link should be enough for the formatter to figure out that the key is required to be allowed to follow the link. Else you can try to open with the sword, if you have it, see \b 9
\b0
. Hopefully the magic is good enough to pair pre-conditions to links, or more markup must be added later. You could also try to go back to pick up the key, see \b 2
\b0
. \
\
\b \qc 8
\b0\
\ql There is a rope here that can be cut using a sword. If you have one and want to do that, see \b 3
\b0
. Otherwise turn to \b 10
\b0
. \
\
\b \qc 9
\b0\
\ql OK. The door is broken, but so is the sword. Turn to \b 8
\b0
. \
\
\b \qc 10
\b0\
\ql Congratulations, you won. \
\
\b \qc 11
\b0\
\ql OK stick dropped. Turn back to \b 2
\b0
to confirm stick can not be picked up again even if the text says it is there (books work that way, although ideally this dynamic version should provide some hints that it is no longer there). \
\
}

130
expected/items.tex Normal file
View file

@ -0,0 +1,130 @@
\documentclass[a5,onecolumn]{book}
\usepackage[utf8]{inputenc}
\usepackage[T1]{fontenc}
\usepackage[hidelinks]{hyperref}
\usepackage{graphicx}
\usepackage[top=3.3cm, bottom=3.3cm, left=2cm, right=2cm]{geometry}
\newif\ifpdf
\ifx\pdfoutput\undefined
\pdffalse
\else
\ifnum\pdfoutput=1
\pdftrue
\else
\pdffalse
\fi
\fi
\title{Items}
\author{Pelle Nilsson}
\date{}
\newcounter{sectionnr}
\begin{document}
\maketitle
\thispagestyle{empty}
\pagestyle{empty}
\clearpage
Turn to 1 to begin.
\phantomsection
\refstepcounter{sectionnr}
\label{section1}
\subsection*{\begin{center} \textbf{1} \end{center}}
\noindent
Demonstrating how to manage player Inventory. You start the book carrying a \textbf{sword} and a \textbf{shield}. Turn to \textbf{\autoref{section2}}.
\vspace{1em}
\phantomsection
\refstepcounter{sectionnr}
\label{section2}
\subsection*{\begin{center} \textbf{2} \end{center}}
\noindent
You have reached a t-junction. Here you find a \textbf{key} and a \textbf{stick}. You can go west to \textbf{\autoref{section7}}, or east to \textbf{\autoref{section4}}.
\vspace{1em}
\phantomsection
\refstepcounter{sectionnr}
\label{section3}
\subsection*{\begin{center} \textbf{3} \end{center}}
\noindent
OK. That was fun. Turn to \textbf{\autoref{section10}}.
\vspace{1em}
\phantomsection
\refstepcounter{sectionnr}
\label{section4}
\subsection*{\begin{center} \textbf{4} \end{center}}
\noindent
There is a \textbf{cursed bracelet} here. You can go on to \textbf{\autoref{section6}} or go back to \textbf{\autoref{section2}}. You can also drop the \textit{stick} for no particular reason if you have it, see \textbf{\autoref{section11}}.
\vspace{1em}
\phantomsection
\refstepcounter{sectionnr}
\label{section5}
\subsection*{\begin{center} \textbf{5} \end{center}}
\noindent
You found \textbf{something valuable}, but there is no way forward, so you head back to \textbf{\autoref{section2}}.
\vspace{1em}
\phantomsection
\refstepcounter{sectionnr}
\label{section6}
\subsection*{\begin{center} \textbf{6} \end{center}}
\noindent
A magic portal ahead will only allow you to pass if you did not pick up the \textit{cursed bracelet}, leading you to \textbf{\autoref{section5}}. If you have the \textit{cursed bracelet} you have to go back to \textbf{\autoref{section2}} instead. Actually feel free to head back to \textbf{\autoref{section2}} either way.
\vspace{1em}
\phantomsection
\refstepcounter{sectionnr}
\label{section7}
\subsection*{\begin{center} \textbf{7} \end{center}}
\noindent
There is a locked door here.eh If you have a \textit{key} you can use that to open the door, see \textbf{\autoref{section8}}. Being right before the link should be enough for the formatter to figure out that the key is required to be allowed to follow the link. Else you can try to open with the \textit{sword}, if you have it, see \textbf{\autoref{section9}}. Hopefully the magic is good enough to pair pre-conditions to links, or more markup must be added later. You could also try to go back to pick up the key, see \textbf{\autoref{section2}}.
\vspace{1em}
\phantomsection
\refstepcounter{sectionnr}
\label{section8}
\subsection*{\begin{center} \textbf{8} \end{center}}
\noindent
There is a rope here that can be cut using a \textit{sword}. If you have one and want to do that, see \textbf{\autoref{section3}}. Otherwise turn to \textbf{\autoref{section10}}.
\vspace{1em}
\phantomsection
\refstepcounter{sectionnr}
\label{section9}
\subsection*{\begin{center} \textbf{9} \end{center}}
\noindent
OK. The door is broken, but so is the \textit{sword}
. Turn to \textbf{\autoref{section8}}.
\vspace{1em}
\phantomsection
\refstepcounter{sectionnr}
\label{section10}
\subsection*{\begin{center} \textbf{10} \end{center}}
\noindent
Congratulations, you won.
\vspace{1em}
\phantomsection
\refstepcounter{sectionnr}
\label{section11}
\subsection*{\begin{center} \textbf{11} \end{center}}
\noindent
OK \textit{stick}
dropped. Turn back to \textbf{\autoref{section2}} to confirm stick can not be picked up again even if the text says it is there (books work that way, although ideally this dynamic version should provide some hints that it is no longer there).
\vspace{1em}
\end{document}

39
expected/items.txt Normal file
View file

@ -0,0 +1,39 @@
Items
Turn to 1 to begin.
1
Demonstrating how to manage player Inventory. You start the book carrying a sword and a shield. Turn to 2.
2
You have reached a t-junction. Here you find a key and a stick. You can go west to 7, or east to 4.
3
OK. That was fun. Turn to 10.
4
There is a cursed bracelet here. You can go on to 6 or go back to 2. You can also drop the stick for no particular reason if you have it, see 11.
5
You found something valuable, but there is no way forward, so you head back to 2.
6
A magic portal ahead will only allow you to pass if you did not pick up the cursed bracelet, leading you to 5. If you have the cursed bracelet you have to go back to 2 instead. Actually feel free to head back to 2 either way.
7
There is a locked door here.eh If you have a key you can use that to open the door, see 8. Being right before the link should be enough for the formatter to figure out that the key is required to be allowed to follow the link. Else you can try to open with the sword, if you have it, see 9. Hopefully the magic is good enough to pair pre-conditions to links, or more markup must be added later. You could also try to go back to pick up the key, see 2.
8
There is a rope here that can be cut using a sword. If you have one and want to do that, see 3. Otherwise turn to 10.
9
OK. The door is broken, but so is the sword. Turn to 8.
10
Congratulations, you won.
11
OK stick dropped. Turn back to 2 to confirm stick can not be picked up again even if the text says it is there (books work that way, although ideally this dynamic version should provide some hints that it is no longer there).

410
expected/references.debug Normal file
View file

@ -0,0 +1,410 @@
BEGIN DEBUG OUTPUT
Book title: Gamebook
Number of sections: 400
Introduction
This gamebook demonstrates simple references between sections. Also notice that an intro section like this one can reference sections, like the start at 1 or the next section at 202.
Turn to 1 to begin.
1 (start) - This is where the adventure begins. You can go on to the next section, see 202 or try the random selection feature at 76.
2 () - (EMPTY)
3 () - (EMPTY)
4 () - (EMPTY)
5 () - (EMPTY)
6 () - (EMPTY)
7 () - (EMPTY)
8 () - (EMPTY)
9 () - (EMPTY)
10 () - (EMPTY)
11 () - (EMPTY)
12 () - (EMPTY)
13 () - (EMPTY)
14 () - (EMPTY)
15 () - (EMPTY)
16 () - (EMPTY)
17 () - (EMPTY)
18 () - (EMPTY)
19 () - (EMPTY)
20 () - (EMPTY)
21 () - (EMPTY)
22 () - (EMPTY)
23 () - (EMPTY)
24 () - (EMPTY)
25 () - (EMPTY)
26 () - (EMPTY)
27 () - (EMPTY)
28 () - (EMPTY)
29 () - (EMPTY)
30 () - (EMPTY)
31 () - (EMPTY)
32 () - (EMPTY)
33 () - (EMPTY)
34 () - (EMPTY)
35 () - (EMPTY)
36 () - (EMPTY)
37 () - (EMPTY)
38 () - (EMPTY)
39 () - (EMPTY)
40 () - (EMPTY)
41 () - (EMPTY)
42 () - (EMPTY)
43 () - (EMPTY)
44 () - (EMPTY)
45 () - (EMPTY)
46 () - (EMPTY)
47 () - (EMPTY)
48 () - (EMPTY)
49 () - (EMPTY)
50 () - (EMPTY)
51 () - (EMPTY)
52 () - (EMPTY)
53 () - (EMPTY)
54 () - (EMPTY)
55 () - (EMPTY)
56 () - (EMPTY)
57 () - (EMPTY)
58 () - (EMPTY)
59 () - (EMPTY)
60 () - (EMPTY)
61 () - (EMPTY)
62 () - (EMPTY)
63 () - (EMPTY)
64 () - (EMPTY)
65 () - (EMPTY)
66 () - (EMPTY)
67 (altend) - Alternative ending.
68 () - (EMPTY)
69 () - (EMPTY)
70 () - (EMPTY)
71 () - (EMPTY)
72 () - (EMPTY)
73 () - (EMPTY)
74 () - (EMPTY)
75 () - (EMPTY)
76 (random) - [RANDOM]Pick a destination at random[/RANDOM] from 202 or 345 or 67.
77 () - (EMPTY)
78 () - (EMPTY)
79 () - (EMPTY)
80 () - (EMPTY)
81 () - (EMPTY)
82 () - (EMPTY)
83 () - (EMPTY)
84 () - (EMPTY)
85 () - (EMPTY)
86 () - (EMPTY)
87 () - (EMPTY)
88 () - (EMPTY)
89 () - (EMPTY)
90 () - (EMPTY)
91 () - (EMPTY)
92 () - (EMPTY)
93 () - (EMPTY)
94 () - (EMPTY)
95 () - (EMPTY)
96 () - (EMPTY)
97 () - (EMPTY)
98 () - (EMPTY)
99 () - (EMPTY)
100 () - (EMPTY)
101 () - (EMPTY)
102 () - (EMPTY)
103 () - (EMPTY)
104 () - (EMPTY)
105 () - (EMPTY)
106 () - (EMPTY)
107 () - (EMPTY)
108 () - (EMPTY)
109 () - (EMPTY)
110 () - (EMPTY)
111 () - (EMPTY)
112 () - (EMPTY)
113 () - (EMPTY)
114 () - (EMPTY)
115 () - (EMPTY)
116 () - (EMPTY)
117 () - (EMPTY)
118 () - (EMPTY)
119 () - (EMPTY)
120 () - (EMPTY)
121 () - (EMPTY)
122 () - (EMPTY)
123 () - (EMPTY)
124 () - (EMPTY)
125 () - (EMPTY)
126 () - (EMPTY)
127 () - (EMPTY)
128 () - (EMPTY)
129 () - (EMPTY)
130 () - (EMPTY)
131 () - (EMPTY)
132 () - (EMPTY)
133 () - (EMPTY)
134 () - (EMPTY)
135 () - (EMPTY)
136 () - (EMPTY)
137 () - (EMPTY)
138 () - (EMPTY)
139 () - (EMPTY)
140 () - (EMPTY)
141 () - (EMPTY)
142 () - (EMPTY)
143 () - (EMPTY)
144 () - (EMPTY)
145 () - (EMPTY)
146 () - (EMPTY)
147 () - (EMPTY)
148 () - (EMPTY)
149 () - (EMPTY)
150 () - (EMPTY)
151 () - (EMPTY)
152 () - (EMPTY)
153 () - (EMPTY)
154 () - (EMPTY)
155 () - (EMPTY)
156 () - (EMPTY)
157 () - (EMPTY)
158 () - (EMPTY)
159 () - (EMPTY)
160 () - (EMPTY)
161 () - (EMPTY)
162 () - (EMPTY)
163 () - (EMPTY)
164 () - (EMPTY)
165 () - (EMPTY)
166 () - (EMPTY)
167 () - (EMPTY)
168 () - (EMPTY)
169 () - (EMPTY)
170 () - (EMPTY)
171 () - (EMPTY)
172 () - (EMPTY)
173 () - (EMPTY)
174 () - (EMPTY)
175 () - (EMPTY)
176 () - (EMPTY)
177 () - (EMPTY)
178 () - (EMPTY)
179 () - (EMPTY)
180 () - (EMPTY)
181 () - (EMPTY)
182 () - (EMPTY)
183 () - (EMPTY)
184 () - (EMPTY)
185 () - (EMPTY)
186 () - (EMPTY)
187 () - (EMPTY)
188 () - (EMPTY)
189 () - (EMPTY)
190 () - (EMPTY)
191 () - (EMPTY)
192 () - (EMPTY)
193 () - (EMPTY)
194 () - (EMPTY)
195 () - (EMPTY)
196 () - (EMPTY)
197 () - (EMPTY)
198 () - (EMPTY)
199 () - (EMPTY)
200 () - (EMPTY)
201 () - (EMPTY)
202 (next) - This is the next section. Go on to the end at 345.
203 () - (EMPTY)
204 () - (EMPTY)
205 () - (EMPTY)
206 () - (EMPTY)
207 () - (EMPTY)
208 () - (EMPTY)
209 () - (EMPTY)
210 () - (EMPTY)
211 () - (EMPTY)
212 () - (EMPTY)
213 () - (EMPTY)
214 () - (EMPTY)
215 () - (EMPTY)
216 () - (EMPTY)
217 () - (EMPTY)
218 () - (EMPTY)
219 () - (EMPTY)
220 () - (EMPTY)
221 () - (EMPTY)
222 () - (EMPTY)
223 () - (EMPTY)
224 () - (EMPTY)
225 () - (EMPTY)
226 () - (EMPTY)
227 () - (EMPTY)
228 () - (EMPTY)
229 () - (EMPTY)
230 () - (EMPTY)
231 () - (EMPTY)
232 () - (EMPTY)
233 () - (EMPTY)
234 () - (EMPTY)
235 () - (EMPTY)
236 () - (EMPTY)
237 () - (EMPTY)
238 () - (EMPTY)
239 () - (EMPTY)
240 () - (EMPTY)
241 () - (EMPTY)
242 () - (EMPTY)
243 () - (EMPTY)
244 () - (EMPTY)
245 () - (EMPTY)
246 () - (EMPTY)
247 () - (EMPTY)
248 () - (EMPTY)
249 () - (EMPTY)
250 () - (EMPTY)
251 () - (EMPTY)
252 () - (EMPTY)
253 () - (EMPTY)
254 () - (EMPTY)
255 () - (EMPTY)
256 () - (EMPTY)
257 () - (EMPTY)
258 () - (EMPTY)
259 () - (EMPTY)
260 () - (EMPTY)
261 () - (EMPTY)
262 () - (EMPTY)
263 () - (EMPTY)
264 () - (EMPTY)
265 () - (EMPTY)
266 () - (EMPTY)
267 () - (EMPTY)
268 () - (EMPTY)
269 () - (EMPTY)
270 () - (EMPTY)
271 () - (EMPTY)
272 () - (EMPTY)
273 () - (EMPTY)
274 () - (EMPTY)
275 () - (EMPTY)
276 () - (EMPTY)
277 () - (EMPTY)
278 () - (EMPTY)
279 () - (EMPTY)
280 () - (EMPTY)
281 () - (EMPTY)
282 () - (EMPTY)
283 () - (EMPTY)
284 () - (EMPTY)
285 () - (EMPTY)
286 () - (EMPTY)
287 () - (EMPTY)
288 () - (EMPTY)
289 () - (EMPTY)
290 () - (EMPTY)
291 () - (EMPTY)
292 () - (EMPTY)
293 () - (EMPTY)
294 () - (EMPTY)
295 () - (EMPTY)
296 () - (EMPTY)
297 () - (EMPTY)
298 () - (EMPTY)
299 () - (EMPTY)
300 () - (EMPTY)
301 () - (EMPTY)
302 () - (EMPTY)
303 () - (EMPTY)
304 () - (EMPTY)
305 () - (EMPTY)
306 () - (EMPTY)
307 () - (EMPTY)
308 () - (EMPTY)
309 () - (EMPTY)
310 () - (EMPTY)
311 () - (EMPTY)
312 () - (EMPTY)
313 () - (EMPTY)
314 () - (EMPTY)
315 () - (EMPTY)
316 () - (EMPTY)
317 () - (EMPTY)
318 () - (EMPTY)
319 () - (EMPTY)
320 () - (EMPTY)
321 () - (EMPTY)
322 () - (EMPTY)
323 () - (EMPTY)
324 () - (EMPTY)
325 () - (EMPTY)
326 () - (EMPTY)
327 () - (EMPTY)
328 () - (EMPTY)
329 () - (EMPTY)
330 () - (EMPTY)
331 () - (EMPTY)
332 () - (EMPTY)
333 () - (EMPTY)
334 () - (EMPTY)
335 () - (EMPTY)
336 () - (EMPTY)
337 () - (EMPTY)
338 () - (EMPTY)
339 () - (EMPTY)
340 () - (EMPTY)
341 () - (EMPTY)
342 () - (EMPTY)
343 () - (EMPTY)
344 () - (EMPTY)
345 (end) - The end.
346 () - (EMPTY)
347 () - (EMPTY)
348 () - (EMPTY)
349 () - (EMPTY)
350 () - (EMPTY)
351 () - (EMPTY)
352 () - (EMPTY)
353 () - (EMPTY)
354 () - (EMPTY)
355 () - (EMPTY)
356 () - (EMPTY)
357 () - (EMPTY)
358 () - (EMPTY)
359 () - (EMPTY)
360 () - (EMPTY)
361 () - (EMPTY)
362 () - (EMPTY)
363 () - (EMPTY)
364 () - (EMPTY)
365 () - (EMPTY)
366 () - (EMPTY)
367 () - (EMPTY)
368 () - (EMPTY)
369 () - (EMPTY)
370 () - (EMPTY)
371 () - (EMPTY)
372 () - (EMPTY)
373 () - (EMPTY)
374 () - (EMPTY)
375 () - (EMPTY)
376 () - (EMPTY)
377 () - (EMPTY)
378 () - (EMPTY)
379 () - (EMPTY)
380 () - (EMPTY)
381 () - (EMPTY)
382 () - (EMPTY)
383 () - (EMPTY)
384 () - (EMPTY)
385 () - (EMPTY)
386 () - (EMPTY)
387 () - (EMPTY)
388 () - (EMPTY)
389 () - (EMPTY)
390 () - (EMPTY)
391 () - (EMPTY)
392 () - (EMPTY)
393 () - (EMPTY)
394 () - (EMPTY)
395 () - (EMPTY)
396 () - (EMPTY)
397 () - (EMPTY)
398 () - (EMPTY)
399 () - (EMPTY)
400 () - (EMPTY)
END DEBUG OUTPUT

13
expected/references.dot Normal file
View file

@ -0,0 +1,13 @@
digraph gamebook {
1->202
1->76
76->202
76->67
76->345
202->345
}

374
expected/references.html Normal file
View file

@ -0,0 +1,374 @@
<!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 = {
'player' : {
'started' : false,
'currentSection' : null,
'collections' : {},
'collect' : function(type, name) {
this.collections[type] = {
'name' : name,
'contents' : [],
'add' : function(what) {
if (this.contents.indexOf(what) === -1
&& !(what in gamebook.dropped[type])) {
this.contents.push(what);
this.contents.sort();
}
},
'drop' : function(what) {
var i = this.contents.indexOf(what);
if (i >= 0) {
this.contents.splice(i, 1);
gamebook.dropped[type][what] = true;
}
},
'has' : function(what) {
return this.contents.indexOf(what) >= 0;
}
};
gamebook.dropped[type] = {};
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);
}
},
'sections' : {},
'turnToFunctions' : {},
'dropped' : {},
'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');
gamebook.player.started = true;
},
'displaySection' : function(nr) {
if (this.player.currentSection) {
this.player.currentSection.element.style.display = 'none';
}
var e = this.sections[nr].element;
this.runActions(e.getElementsByClassName('sectiontext')[0]);
e.style.display = 'block';
this.player.currentSection = gamebook.sections[nr];
},
'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;
}
}
};
</script>
<style>
.startlink,.sectionref,.displayintrolink,.hideintrolink,.found,.add,.random {
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 {
cursor: pointer;}
.startlink,.enabledlink,.displayintrolink,.hideintrolink,.found,
.random {background: #eef;
}
.startlink:hover,.enabledlink:hover,.displayintrolink:hover,
.hideintrolink:hover {background: #a9f;}
.disabledlink {color: #bbb; cursor: not-allowed; background: inherit;}
.disabledlink:hover {background: inherit;}
.sectionnumber {font-weight: bolder;
margin-left: 50%;
margin-right: 50%;}
.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;}
</style>
</head>
<body>
<div class="hideintrolink nodisplay"
onclick="gamebook.hideIntroSections()">(hide instructions)</div>
<div class="gamebook">
<div class="introsection">
<span class="introsectionheading">Introduction</span>
<div class="introsectionbody">
This gamebook demonstrates simple references between sections. Also notice that an intro section like this one can reference sections, like the start at <a class="sectionref enabledlink" data-ref="1">1</a> or the next section at <a class="sectionref enabledlink" data-ref="202">202</a>.
</div>
</div>
<div class="startlink"
onclick="gamebook.turnTo(1)">Turn to 1 to begin.</div>
<div class="section" id="section1">
<span class="sectionnumber" id="para1">1</span>
<div class="sectiontext">
This is where the adventure begins. You can go on to the next section, see <a class="sectionref enabledlink" data-ref="202">202</a> or try the random selection feature at <a class="sectionref enabledlink" data-ref="76">76</a>.
</div>
</div>
<script>
if (this.gamebook) {
gamebook.addSection(1, document.getElementById('section1'));
}
</script> <div class="section" id="section67">
<span class="sectionnumber" id="para67">67</span>
<div class="sectiontext">
Alternative ending.
</div>
</div>
<script>
if (this.gamebook) {
gamebook.addSection(67, document.getElementById('section67'));
}
</script> <div class="section" id="section76">
<span class="sectionnumber" id="para76">76</span>
<div class="sectiontext">
<span class="random enabledlink">Pick a destination at random</span> from <a class="sectionref enabledlink" data-ref="202">202</a> or <a class="sectionref enabledlink" data-ref="345">345</a> or <a class="sectionref enabledlink" data-ref="67">67</a>.
</div>
</div>
<script>
if (this.gamebook) {
gamebook.addSection(76, document.getElementById('section76'));
}
</script> <div class="section" id="section202">
<span class="sectionnumber" id="para202">202</span>
<div class="sectiontext">
This is the next section. Go on to the end at <a class="sectionref enabledlink" data-ref="345">345</a>.
</div>
</div>
<script>
if (this.gamebook) {
gamebook.addSection(202, document.getElementById('section202'));
}
</script> <div class="section" id="section345">
<span class="sectionnumber" id="para345">345</span>
<div class="sectiontext">
The end.
</div>
</div>
<script>
if (this.gamebook) {
gamebook.addSection(345, document.getElementById('section345'));
}
</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>
</body>
</html>

64
expected/references.rtf Normal file
View file

@ -0,0 +1,64 @@
{\rtf1\ansi\ansicpg1252\cocoartf1038\cocoasubrtf360
{\fonttbl\f0\fswiss\fcharset0 Helvetica;}
{\colortbl;\red255\green255\blue255;}
\paperw11900\paperh16840\margl1440\margr1440\vieww14140\viewh14860\viewkind0
\pard\tx566\tx1133\tx1700\tx2267\tx2834\tx3401\tx3968\tx4535\tx5102\tx5669\tx6236\tx6803\ql\qnatural\pardirnatural
\f0\b\fs24 \cf0
\b \qc Gamebook
\b0\
\b \qc Introduction
\b0\
\ql This gamebook demonstrates simple references between sections. Also notice that an intro section like this one can reference sections, like the start at \b 1
\b0
or the next section at \b 202
\b0
. \
\
\b Turn to 1 to begin.
\b0\
\
\b \qc 1
\b0\
\ql This is where the adventure begins. You can go on to the next section, see \b 202
\b0
or try the random selection feature at \b 76
\b0
. \
\
\b \qc 67
\b0\
\ql Alternative ending. \
\
\b \qc 76
\b0\
\ql Pick a destination at random from \b 202
\b0
or \b 345
\b0
or \b 67
\b0
. \
\
\b \qc 202
\b0\
\ql This is the next section. Go on to the end at \b 345
\b0
. \
\
\b \qc 345
\b0\
\ql The end. \
\
}

481
expected/references.tex Normal file
View file

@ -0,0 +1,481 @@
\documentclass[a5,onecolumn]{book}
\usepackage[utf8]{inputenc}
\usepackage[T1]{fontenc}
\usepackage[hidelinks]{hyperref}
\usepackage{graphicx}
\usepackage[top=3.3cm, bottom=3.3cm, left=2cm, right=2cm]{geometry}
\newif\ifpdf
\ifx\pdfoutput\undefined
\pdffalse
\else
\ifnum\pdfoutput=1
\pdftrue
\else
\pdffalse
\fi
\fi
\title{Gamebook}
\author{}
\date{}
\newcounter{sectionnr}
\begin{document}
\maketitle
\thispagestyle{empty}
\pagestyle{empty}
\clearpage
\subsection*{\begin{center} \textbf{Introduction} \end{center}}
\noindent
This gamebook demonstrates simple references between sections. Also notice that an intro section like this one can reference sections, like the start at \textbf{\autoref{section1}} or the next section at \textbf{\autoref{section202}}.
\vspace{1em}
Turn to 1 to begin.
\phantomsection
\refstepcounter{sectionnr}
\label{section1}
\subsection*{\begin{center} \textbf{1} \end{center}}
\noindent
This is where the adventure begins. You can go on to the next section, see \textbf{\autoref{section202}} or try the random selection feature at \textbf{\autoref{section76}}.
\vspace{1em}
\refstepcounter{sectionnr}
\refstepcounter{sectionnr}
\refstepcounter{sectionnr}
\refstepcounter{sectionnr}
\refstepcounter{sectionnr}
\refstepcounter{sectionnr}
\refstepcounter{sectionnr}
\refstepcounter{sectionnr}
\refstepcounter{sectionnr}
\refstepcounter{sectionnr}
\refstepcounter{sectionnr}
\refstepcounter{sectionnr}
\refstepcounter{sectionnr}
\refstepcounter{sectionnr}
\refstepcounter{sectionnr}
\refstepcounter{sectionnr}
\refstepcounter{sectionnr}
\refstepcounter{sectionnr}
\refstepcounter{sectionnr}
\refstepcounter{sectionnr}
\refstepcounter{sectionnr}
\refstepcounter{sectionnr}
\refstepcounter{sectionnr}
\refstepcounter{sectionnr}
\refstepcounter{sectionnr}
\refstepcounter{sectionnr}
\refstepcounter{sectionnr}
\refstepcounter{sectionnr}
\refstepcounter{sectionnr}
\refstepcounter{sectionnr}
\refstepcounter{sectionnr}
\refstepcounter{sectionnr}
\refstepcounter{sectionnr}
\refstepcounter{sectionnr}
\refstepcounter{sectionnr}
\refstepcounter{sectionnr}
\refstepcounter{sectionnr}
\refstepcounter{sectionnr}
\refstepcounter{sectionnr}
\refstepcounter{sectionnr}
\refstepcounter{sectionnr}
\refstepcounter{sectionnr}
\refstepcounter{sectionnr}
\refstepcounter{sectionnr}
\refstepcounter{sectionnr}
\refstepcounter{sectionnr}
\refstepcounter{sectionnr}
\refstepcounter{sectionnr}
\refstepcounter{sectionnr}
\refstepcounter{sectionnr}
\refstepcounter{sectionnr}
\refstepcounter{sectionnr}
\refstepcounter{sectionnr}
\refstepcounter{sectionnr}
\refstepcounter{sectionnr}
\refstepcounter{sectionnr}
\refstepcounter{sectionnr}
\refstepcounter{sectionnr}
\refstepcounter{sectionnr}
\refstepcounter{sectionnr}
\refstepcounter{sectionnr}
\refstepcounter{sectionnr}
\refstepcounter{sectionnr}
\refstepcounter{sectionnr}
\refstepcounter{sectionnr}
\phantomsection
\refstepcounter{sectionnr}
\label{section67}
\subsection*{\begin{center} \textbf{67} \end{center}}
\noindent
Alternative ending.
\vspace{1em}
\refstepcounter{sectionnr}
\refstepcounter{sectionnr}
\refstepcounter{sectionnr}
\refstepcounter{sectionnr}
\refstepcounter{sectionnr}
\refstepcounter{sectionnr}
\refstepcounter{sectionnr}
\refstepcounter{sectionnr}
\phantomsection
\refstepcounter{sectionnr}
\label{section76}
\subsection*{\begin{center} \textbf{76} \end{center}}
\noindent
Pick a destination at random from \textbf{\autoref{section202}} or \textbf{\autoref{section345}} or \textbf{\autoref{section67}}.
\vspace{1em}
\refstepcounter{sectionnr}
\refstepcounter{sectionnr}
\refstepcounter{sectionnr}
\refstepcounter{sectionnr}
\refstepcounter{sectionnr}
\refstepcounter{sectionnr}
\refstepcounter{sectionnr}
\refstepcounter{sectionnr}
\refstepcounter{sectionnr}
\refstepcounter{sectionnr}
\refstepcounter{sectionnr}
\refstepcounter{sectionnr}
\refstepcounter{sectionnr}
\refstepcounter{sectionnr}
\refstepcounter{sectionnr}
\refstepcounter{sectionnr}
\refstepcounter{sectionnr}
\refstepcounter{sectionnr}
\refstepcounter{sectionnr}
\refstepcounter{sectionnr}
\refstepcounter{sectionnr}
\refstepcounter{sectionnr}
\refstepcounter{sectionnr}
\refstepcounter{sectionnr}
\refstepcounter{sectionnr}
\refstepcounter{sectionnr}
\refstepcounter{sectionnr}
\refstepcounter{sectionnr}
\refstepcounter{sectionnr}
\refstepcounter{sectionnr}
\refstepcounter{sectionnr}
\refstepcounter{sectionnr}
\refstepcounter{sectionnr}
\refstepcounter{sectionnr}
\refstepcounter{sectionnr}
\refstepcounter{sectionnr}
\refstepcounter{sectionnr}
\refstepcounter{sectionnr}
\refstepcounter{sectionnr}
\refstepcounter{sectionnr}
\refstepcounter{sectionnr}
\refstepcounter{sectionnr}
\refstepcounter{sectionnr}
\refstepcounter{sectionnr}
\refstepcounter{sectionnr}
\refstepcounter{sectionnr}
\refstepcounter{sectionnr}
\refstepcounter{sectionnr}
\refstepcounter{sectionnr}
\refstepcounter{sectionnr}
\refstepcounter{sectionnr}
\refstepcounter{sectionnr}
\refstepcounter{sectionnr}
\refstepcounter{sectionnr}
\refstepcounter{sectionnr}
\refstepcounter{sectionnr}
\refstepcounter{sectionnr}
\refstepcounter{sectionnr}
\refstepcounter{sectionnr}
\refstepcounter{sectionnr}
\refstepcounter{sectionnr}
\refstepcounter{sectionnr}
\refstepcounter{sectionnr}
\refstepcounter{sectionnr}
\refstepcounter{sectionnr}
\refstepcounter{sectionnr}
\refstepcounter{sectionnr}
\refstepcounter{sectionnr}
\refstepcounter{sectionnr}
\refstepcounter{sectionnr}
\refstepcounter{sectionnr}
\refstepcounter{sectionnr}
\refstepcounter{sectionnr}
\refstepcounter{sectionnr}
\refstepcounter{sectionnr}
\refstepcounter{sectionnr}
\refstepcounter{sectionnr}
\refstepcounter{sectionnr}
\refstepcounter{sectionnr}
\refstepcounter{sectionnr}
\refstepcounter{sectionnr}
\refstepcounter{sectionnr}
\refstepcounter{sectionnr}
\refstepcounter{sectionnr}
\refstepcounter{sectionnr}
\refstepcounter{sectionnr}
\refstepcounter{sectionnr}
\refstepcounter{sectionnr}
\refstepcounter{sectionnr}
\refstepcounter{sectionnr}
\refstepcounter{sectionnr}
\refstepcounter{sectionnr}
\refstepcounter{sectionnr}
\refstepcounter{sectionnr}
\refstepcounter{sectionnr}
\refstepcounter{sectionnr}
\refstepcounter{sectionnr}
\refstepcounter{sectionnr}
\refstepcounter{sectionnr}
\refstepcounter{sectionnr}
\refstepcounter{sectionnr}
\refstepcounter{sectionnr}
\refstepcounter{sectionnr}
\refstepcounter{sectionnr}
\refstepcounter{sectionnr}
\refstepcounter{sectionnr}
\refstepcounter{sectionnr}
\refstepcounter{sectionnr}
\refstepcounter{sectionnr}
\refstepcounter{sectionnr}
\refstepcounter{sectionnr}
\refstepcounter{sectionnr}
\refstepcounter{sectionnr}
\refstepcounter{sectionnr}
\refstepcounter{sectionnr}
\refstepcounter{sectionnr}
\refstepcounter{sectionnr}
\refstepcounter{sectionnr}
\refstepcounter{sectionnr}
\refstepcounter{sectionnr}
\refstepcounter{sectionnr}
\refstepcounter{sectionnr}
\refstepcounter{sectionnr}
\refstepcounter{sectionnr}
\refstepcounter{sectionnr}
\phantomsection
\refstepcounter{sectionnr}
\label{section202}
\subsection*{\begin{center} \textbf{202} \end{center}}
\noindent
This is the next section. Go on to the end at \textbf{\autoref{section345}}.
\vspace{1em}
\refstepcounter{sectionnr}
\refstepcounter{sectionnr}
\refstepcounter{sectionnr}
\refstepcounter{sectionnr}
\refstepcounter{sectionnr}
\refstepcounter{sectionnr}
\refstepcounter{sectionnr}
\refstepcounter{sectionnr}
\refstepcounter{sectionnr}
\refstepcounter{sectionnr}
\refstepcounter{sectionnr}
\refstepcounter{sectionnr}
\refstepcounter{sectionnr}
\refstepcounter{sectionnr}
\refstepcounter{sectionnr}
\refstepcounter{sectionnr}
\refstepcounter{sectionnr}
\refstepcounter{sectionnr}
\refstepcounter{sectionnr}
\refstepcounter{sectionnr}
\refstepcounter{sectionnr}
\refstepcounter{sectionnr}
\refstepcounter{sectionnr}
\refstepcounter{sectionnr}
\refstepcounter{sectionnr}
\refstepcounter{sectionnr}
\refstepcounter{sectionnr}
\refstepcounter{sectionnr}
\refstepcounter{sectionnr}
\refstepcounter{sectionnr}
\refstepcounter{sectionnr}
\refstepcounter{sectionnr}
\refstepcounter{sectionnr}
\refstepcounter{sectionnr}
\refstepcounter{sectionnr}
\refstepcounter{sectionnr}
\refstepcounter{sectionnr}
\refstepcounter{sectionnr}
\refstepcounter{sectionnr}
\refstepcounter{sectionnr}
\refstepcounter{sectionnr}
\refstepcounter{sectionnr}
\refstepcounter{sectionnr}
\refstepcounter{sectionnr}
\refstepcounter{sectionnr}
\refstepcounter{sectionnr}
\refstepcounter{sectionnr}
\refstepcounter{sectionnr}
\refstepcounter{sectionnr}
\refstepcounter{sectionnr}
\refstepcounter{sectionnr}
\refstepcounter{sectionnr}
\refstepcounter{sectionnr}
\refstepcounter{sectionnr}
\refstepcounter{sectionnr}
\refstepcounter{sectionnr}
\refstepcounter{sectionnr}
\refstepcounter{sectionnr}
\refstepcounter{sectionnr}
\refstepcounter{sectionnr}
\refstepcounter{sectionnr}
\refstepcounter{sectionnr}
\refstepcounter{sectionnr}
\refstepcounter{sectionnr}
\refstepcounter{sectionnr}
\refstepcounter{sectionnr}
\refstepcounter{sectionnr}
\refstepcounter{sectionnr}
\refstepcounter{sectionnr}
\refstepcounter{sectionnr}
\refstepcounter{sectionnr}
\refstepcounter{sectionnr}
\refstepcounter{sectionnr}
\refstepcounter{sectionnr}
\refstepcounter{sectionnr}
\refstepcounter{sectionnr}
\refstepcounter{sectionnr}
\refstepcounter{sectionnr}
\refstepcounter{sectionnr}
\refstepcounter{sectionnr}
\refstepcounter{sectionnr}
\refstepcounter{sectionnr}
\refstepcounter{sectionnr}
\refstepcounter{sectionnr}
\refstepcounter{sectionnr}
\refstepcounter{sectionnr}
\refstepcounter{sectionnr}
\refstepcounter{sectionnr}
\refstepcounter{sectionnr}
\refstepcounter{sectionnr}
\refstepcounter{sectionnr}
\refstepcounter{sectionnr}
\refstepcounter{sectionnr}
\refstepcounter{sectionnr}
\refstepcounter{sectionnr}
\refstepcounter{sectionnr}
\refstepcounter{sectionnr}
\refstepcounter{sectionnr}
\refstepcounter{sectionnr}
\refstepcounter{sectionnr}
\refstepcounter{sectionnr}
\refstepcounter{sectionnr}
\refstepcounter{sectionnr}
\refstepcounter{sectionnr}
\refstepcounter{sectionnr}
\refstepcounter{sectionnr}
\refstepcounter{sectionnr}
\refstepcounter{sectionnr}
\refstepcounter{sectionnr}
\refstepcounter{sectionnr}
\refstepcounter{sectionnr}
\refstepcounter{sectionnr}
\refstepcounter{sectionnr}
\refstepcounter{sectionnr}
\refstepcounter{sectionnr}
\refstepcounter{sectionnr}
\refstepcounter{sectionnr}
\refstepcounter{sectionnr}
\refstepcounter{sectionnr}
\refstepcounter{sectionnr}
\refstepcounter{sectionnr}
\refstepcounter{sectionnr}
\refstepcounter{sectionnr}
\refstepcounter{sectionnr}
\refstepcounter{sectionnr}
\refstepcounter{sectionnr}
\refstepcounter{sectionnr}
\refstepcounter{sectionnr}
\refstepcounter{sectionnr}
\refstepcounter{sectionnr}
\refstepcounter{sectionnr}
\refstepcounter{sectionnr}
\refstepcounter{sectionnr}
\refstepcounter{sectionnr}
\refstepcounter{sectionnr}
\refstepcounter{sectionnr}
\refstepcounter{sectionnr}
\refstepcounter{sectionnr}
\refstepcounter{sectionnr}
\refstepcounter{sectionnr}
\refstepcounter{sectionnr}
\refstepcounter{sectionnr}
\phantomsection
\refstepcounter{sectionnr}
\label{section345}
\subsection*{\begin{center} \textbf{345} \end{center}}
\noindent
The end.
\vspace{1em}
\refstepcounter{sectionnr}
\refstepcounter{sectionnr}
\refstepcounter{sectionnr}
\refstepcounter{sectionnr}
\refstepcounter{sectionnr}
\refstepcounter{sectionnr}
\refstepcounter{sectionnr}
\refstepcounter{sectionnr}
\refstepcounter{sectionnr}
\refstepcounter{sectionnr}
\refstepcounter{sectionnr}
\refstepcounter{sectionnr}
\refstepcounter{sectionnr}
\refstepcounter{sectionnr}
\refstepcounter{sectionnr}
\refstepcounter{sectionnr}
\refstepcounter{sectionnr}
\refstepcounter{sectionnr}
\refstepcounter{sectionnr}
\refstepcounter{sectionnr}
\refstepcounter{sectionnr}
\refstepcounter{sectionnr}
\refstepcounter{sectionnr}
\refstepcounter{sectionnr}
\refstepcounter{sectionnr}
\refstepcounter{sectionnr}
\refstepcounter{sectionnr}
\refstepcounter{sectionnr}
\refstepcounter{sectionnr}
\refstepcounter{sectionnr}
\refstepcounter{sectionnr}
\refstepcounter{sectionnr}
\refstepcounter{sectionnr}
\refstepcounter{sectionnr}
\refstepcounter{sectionnr}
\refstepcounter{sectionnr}
\refstepcounter{sectionnr}
\refstepcounter{sectionnr}
\refstepcounter{sectionnr}
\refstepcounter{sectionnr}
\refstepcounter{sectionnr}
\refstepcounter{sectionnr}
\refstepcounter{sectionnr}
\refstepcounter{sectionnr}
\refstepcounter{sectionnr}
\refstepcounter{sectionnr}
\refstepcounter{sectionnr}
\refstepcounter{sectionnr}
\refstepcounter{sectionnr}
\refstepcounter{sectionnr}
\refstepcounter{sectionnr}
\refstepcounter{sectionnr}
\refstepcounter{sectionnr}
\refstepcounter{sectionnr}
\refstepcounter{sectionnr}
\end{document}

25
expected/references.txt Normal file
View file

@ -0,0 +1,25 @@
Gamebook
Introduction
This gamebook demonstrates simple references between sections. Also notice that an intro section like this one can reference sections, like the start at 1 or the next section at 202.
Turn to 1 to begin.
1
This is where the adventure begins. You can go on to the next section, see 202 or try the random selection feature at 76.
67
Alternative ending.
76
Pick a destination at random from 202 or 345 or 67.
202
This is the next section. Go on to the end at 345.
345
The end.

View file

@ -0,0 +1,13 @@
BEGIN DEBUG OUTPUT
Book title: Gamebook
Number of sections: 5
Turn to 1 to begin.
1 (start) - It starts here. You can get to 4.
2 (seconddummy) - Another fake section that is also ignored.
3 (nothereeither) - You can not get here either, but because it is tagged as fake there will be no warning generated.
4 (here) - You can get here. Congratulations!
5 (nothere) - You can not get here. Verification should warn you about that, if enabled (with the --verify option).
END DEBUG OUTPUT

5
expected/unreachable.dot Normal file
View file

@ -0,0 +1,5 @@
digraph gamebook {
1->4
}

368
expected/unreachable.html Normal file
View file

@ -0,0 +1,368 @@
<!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 = {
'player' : {
'started' : false,
'currentSection' : null,
'collections' : {},
'collect' : function(type, name) {
this.collections[type] = {
'name' : name,
'contents' : [],
'add' : function(what) {
if (this.contents.indexOf(what) === -1
&& !(what in gamebook.dropped[type])) {
this.contents.push(what);
this.contents.sort();
}
},
'drop' : function(what) {
var i = this.contents.indexOf(what);
if (i >= 0) {
this.contents.splice(i, 1);
gamebook.dropped[type][what] = true;
}
},
'has' : function(what) {
return this.contents.indexOf(what) >= 0;
}
};
gamebook.dropped[type] = {};
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);
}
},
'sections' : {},
'turnToFunctions' : {},
'dropped' : {},
'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');
gamebook.player.started = true;
},
'displaySection' : function(nr) {
if (this.player.currentSection) {
this.player.currentSection.element.style.display = 'none';
}
var e = this.sections[nr].element;
this.runActions(e.getElementsByClassName('sectiontext')[0]);
e.style.display = 'block';
this.player.currentSection = gamebook.sections[nr];
},
'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;
}
}
};
</script>
<style>
.startlink,.sectionref,.displayintrolink,.hideintrolink,.found,.add,.random {
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 {
cursor: pointer;}
.startlink,.enabledlink,.displayintrolink,.hideintrolink,.found,
.random {background: #eef;
}
.startlink:hover,.enabledlink:hover,.displayintrolink:hover,
.hideintrolink:hover {background: #a9f;}
.disabledlink {color: #bbb; cursor: not-allowed; background: inherit;}
.disabledlink:hover {background: inherit;}
.sectionnumber {font-weight: bolder;
margin-left: 50%;
margin-right: 50%;}
.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;}
</style>
</head>
<body>
<div class="hideintrolink nodisplay"
onclick="gamebook.hideIntroSections()">(hide instructions)</div>
<div class="gamebook">
<div class="startlink"
onclick="gamebook.turnTo(1)">Turn to 1 to begin.</div>
<div class="section" id="section1">
<span class="sectionnumber" id="para1">1</span>
<div class="sectiontext">
It starts here. You can get to <a class="sectionref enabledlink" data-ref="4">4</a>.
</div>
</div>
<script>
if (this.gamebook) {
gamebook.addSection(1, document.getElementById('section1'));
}
</script> <div class="section" id="section2">
<span class="sectionnumber" id="para2">2</span>
<div class="sectiontext">
Another fake section that is also ignored.
</div>
</div>
<script>
if (this.gamebook) {
gamebook.addSection(2, document.getElementById('section2'));
}
</script> <div class="section" id="section3">
<span class="sectionnumber" id="para3">3</span>
<div class="sectiontext">
You can not get here either, but because it is tagged as fake there will be no warning generated.
</div>
</div>
<script>
if (this.gamebook) {
gamebook.addSection(3, document.getElementById('section3'));
}
</script> <div class="section" id="section4">
<span class="sectionnumber" id="para4">4</span>
<div class="sectiontext">
You can get here. Congratulations!
</div>
</div>
<script>
if (this.gamebook) {
gamebook.addSection(4, document.getElementById('section4'));
}
</script> <div class="section" id="section5">
<span class="sectionnumber" id="para5">5</span>
<div class="sectiontext">
You can not get here. Verification should warn you about that, if enabled (with the --verify option).
</div>
</div>
<script>
if (this.gamebook) {
gamebook.addSection(5, document.getElementById('section5'));
}
</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>
</body>
</html>

43
expected/unreachable.rtf Normal file
View file

@ -0,0 +1,43 @@
{\rtf1\ansi\ansicpg1252\cocoartf1038\cocoasubrtf360
{\fonttbl\f0\fswiss\fcharset0 Helvetica;}
{\colortbl;\red255\green255\blue255;}
\paperw11900\paperh16840\margl1440\margr1440\vieww14140\viewh14860\viewkind0
\pard\tx566\tx1133\tx1700\tx2267\tx2834\tx3401\tx3968\tx4535\tx5102\tx5669\tx6236\tx6803\ql\qnatural\pardirnatural
\f0\b\fs24 \cf0
\b \qc Gamebook
\b0\
\b Turn to 1 to begin.
\b0\
\
\b \qc 1
\b0\
\ql It starts here. You can get to \b 4
\b0
. \
\
\b \qc 2
\b0\
\ql Another fake section that is also ignored. \
\
\b \qc 3
\b0\
\ql You can not get here either, but because it is tagged as fake there will be no warning generated. \
\
\b \qc 4
\b0\
\ql You can get here. Congratulations! \
\
\b \qc 5
\b0\
\ql You can not get here. Verification should warn you about that, if enabled (with the --verify option). \
\
}

80
expected/unreachable.tex Normal file
View file

@ -0,0 +1,80 @@
\documentclass[a5,onecolumn]{book}
\usepackage[utf8]{inputenc}
\usepackage[T1]{fontenc}
\usepackage[hidelinks]{hyperref}
\usepackage{graphicx}
\usepackage[top=3.3cm, bottom=3.3cm, left=2cm, right=2cm]{geometry}
\newif\ifpdf
\ifx\pdfoutput\undefined
\pdffalse
\else
\ifnum\pdfoutput=1
\pdftrue
\else
\pdffalse
\fi
\fi
\title{Gamebook}
\author{}
\date{}
\newcounter{sectionnr}
\begin{document}
\maketitle
\thispagestyle{empty}
\pagestyle{empty}
\clearpage
Turn to 1 to begin.
\phantomsection
\refstepcounter{sectionnr}
\label{section1}
\subsection*{\begin{center} \textbf{1} \end{center}}
\noindent
It starts here. You can get to \textbf{\autoref{section4}}.
\vspace{1em}
\phantomsection
\refstepcounter{sectionnr}
\label{section2}
\subsection*{\begin{center} \textbf{2} \end{center}}
\noindent
Another fake section that is also ignored.
\vspace{1em}
\phantomsection
\refstepcounter{sectionnr}
\label{section3}
\subsection*{\begin{center} \textbf{3} \end{center}}
\noindent
You can not get here either, but because it is tagged as fake there will be no warning generated.
\vspace{1em}
\phantomsection
\refstepcounter{sectionnr}
\label{section4}
\subsection*{\begin{center} \textbf{4} \end{center}}
\noindent
You can get here. Congratulations!
\vspace{1em}
\phantomsection
\refstepcounter{sectionnr}
\label{section5}
\subsection*{\begin{center} \textbf{5} \end{center}}
\noindent
You can not get here. Verification should warn you about that, if enabled (with the --verify option).
\vspace{1em}
\end{document}

21
expected/unreachable.txt Normal file
View file

@ -0,0 +1,21 @@
Gamebook
Turn to 1 to begin.
1
It starts here. You can get to 4.
2
Another fake section that is also ignored.
3
You can not get here either, but because it is tagged as fake there will be no warning generated.
4
You can get here. Congratulations!
5
You can not get here. Verification should warn you about that, if enabled (with the --verify option).

View file

@ -1,4 +1,4 @@
* TODO [39/67] [58%]
* TODO [40/67] [59%]
- [X] Debug output
- [X] DOT output
- [X] LaTeX output
@ -45,7 +45,7 @@
eg [a-z][a-z_0-9]+
- [X] Random pick of link to follow from a section.
- [X] Possibility to make predictable random numbers and shuffling for testing
- [ ] Test generate examples and compare to expected output in all formats
- [X] Test generate examples and compare to expected output in all formats
- [ ] Unit tests (finally...)
- [ ] Verify gamebook (always; drop the --verify option)
- [ ] Dummy and fake sections (handle properly when verifying)