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

Inventory and codewords now both generic collections.

Some new code to handle tags with arguments.
This commit is contained in:
Pelle Nilsson 2013-06-09 00:55:24 +02:00
parent d10177efd6
commit 98b2583f68
20 changed files with 138 additions and 151 deletions

View file

@ -1,16 +1,17 @@
* 1 start
Demonstrating how codewords (AKA sightings) can be used.
Demonstrating how [collect code]Codewords[/collect]
(AKA sightings) can be used.
Go to [[second]].
* 2 second
[set]warrior[/set]
Got codeword [add code]warrior[/add].
Simple enough to set a codeword. Turn to [[choice]].
* choice
If you have the codeword [has]warrior[/has] you may
If you have the codeword [has code]warrior[/has] you may
turn to [[the_end]]. If you do not have the codeword
[hasnot]fun[/hasnot], you may turn to [[notsofun]].
If you have the codeword [has]fun[/has], you may instead
[hasnot code]fun[/hasnot], you may turn to [[notsofun]].
If you have the codeword [has code]fun[/has], you may instead
turn to [[cheater]].
Otherwise see [[forced]].
@ -22,7 +23,7 @@ having a codeword. Now go on to [[forced]].
Cheater! There is no way you can have codeword fun.
* forced
OK, if you have the codeword [has]warrior[/has], turn to
OK, if you have the codeword [has code]warrior[/has], turn to
[[auto the_end]] otherwise go back to [[second]]. Although
we both know you have that codeword.

View file

@ -1,54 +1,58 @@
* 1 start
Demonstrating how to manage player inventory. You start
the book carrying a [take]sword[/take] and a [take]shield[/take].
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 [[tjunction]].
* tjunction
You have reached a t-junction.
Here you find a [found]key[/found] and a [found]stick[/found].
Here you find a [found item]key[/found]
and a [found item]stick[/found].
You can go west to [[door]], or
east to [[curse]].
* door
There is a locked door here.
If you have a [carries]key[/carries] you can use that to
If you have a [has item]key[/has] you can use that to
open the door, see [[inside]]. 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 [carries]sword[/carries],
Else you can try to open with the [has item]sword[/has],
if you have it, see [[attempt_break_door_with_sword]].
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 [[tjunction]].
* attempt_break_door_with_sword
OK. The door is broken, but so is the [drop]sword[/drop].
OK. The door is broken, but so is the [drop item]sword[/drop].
Turn to [[inside]].
* curse
There is a [found]cursed bracelet[/found] here. You can go on to
There is a [found item]cursed bracelet[/found] here. You can go on to
[[portal]] or go back to [[tjunction]]. You can also drop the
stick for no particular reason, see [[drop_stick]].
[has item]stick[/has] for no particular reason if you have it,
see [[drop_stick]].
* drop_stick
OK [drop]stick[/drop] dropped. Turn back to [[tjunction]] to confirm
OK [drop item]stick[/drop] dropped. Turn back to [[tjunction]] 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).
* portal
A magic portal ahead will only allow you to pass if you did not pick up the
[notcarries]cursed bracelet[/notcarries], leading you to [[treasure]].
If you have the [carries]cursed bracelet[/carries]
[hasnot item]cursed bracelet[/hasnot], leading you to [[treasure]].
If you have the [has item]cursed bracelet[/has]
you have to go back to [[tjunction]] instead.
Actually feel free to head back to [[tjunction]] either way.
* treasure
You found [found]something valuable[/found], but there is no way forward,
You found [found item]something valuable[/found], but there is no way forward,
so you head back to [[tjunction]].
* inside
There is a rope here that can be cut using a [carries]sword[/carries].
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 [[cut_rope]].
Otherwise turn to [[won]].

View file

@ -59,7 +59,8 @@ class OutputFormat (object):
raise Exception('Mismatched tag start [ in section %s' %
self.name)
tag = section.text[tag_start+1:tag_end].strip()
tagname = tag.split()[0].strip()
tagparts = tag.split()
tagname = tagparts[0]
end_tag_start = section.text.find('[', tag_end)
if (not end_tag_start > tag_end
and section.text[end_tag_start].startswith('[/' + tagname
@ -69,8 +70,10 @@ class OutputFormat (object):
inner = section.text[tag_end+1:end_tag_start]
# FIXME this pollutes the mutable references object
references['inner'] = inner
f = self.format_with_template(tag.replace(' ', '_'),
references)
for i, arg in enumerate(tagparts[1:]):
references['arg%d' % (i+1)] = arg
f = self.format_with_template(tagname,
references)
if len(f) > 0:
res += f
else:

View file

@ -1 +0,0 @@
[CARRIES]%(inner)s[/CARRIES]

View file

@ -1 +0,0 @@
SET CODEWORD %(inner)s.

2
templates/html/add.html Normal file
View file

@ -0,0 +1,2 @@
<span class="add" data-type="%(arg1)s"
data-what="%(inner)s">%(inner)s</span>

View file

@ -9,38 +9,46 @@
var gamebook = {
'player' : {
'currentSection' : null,
'inventory' : [],
'codewords' : {},
'collections' : {},
'take' : function(item) {
if (this.inventory.indexOf(item) === -1
&& !(item in gamebook.droppedItems)) {
this.inventory.push(item);
this.inventory.sort();
gamebook.updateInventory();
}
'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);
},
'drop' : function(item) {
var i = this.inventory.indexOf(item);
if (i >= 0) {
this.inventory.splice(i, 1);
gamebook.droppedItems[item] = true;
gamebook.updateInventory();
}
'add' : function(type, what) {
this.collections[type].add(what);
gamebook.updateCollectionsView();
},
'carries' : function(item) {
return this.inventory.indexOf(item) >= 0;
'drop' : function(type, what) {
this.collections[type].drop(what);
gamebook.updateCollectionsView();
},
'set' : function(codeword) {
this.codewords[codeword] = true;
gamebook.updateCodewords();
},
'has' : function(codeword) {
return codeword in this.codewords;
'has' : function(type, what) {
return this.collections[type].has(what);
}
},
@ -48,49 +56,13 @@
'turnToFunctions' : {},
'autoRun' : {},
'droppedItems' : {},
'addAutoRun' : function(nr, f) {
if (nr in this.autoRun) {
this.autoRun[nr].push(f);
} else {
this.autoRun[nr] = [f];
}
},
'runAutoRuns' : function(nr) {
if (nr in gamebook.autoRun) {
gamebook.autoRun[nr].forEach(function (f) {
f();
});
}
},
'dropped' : {},
'addSection' : function(nr, element) {
var section = {'element' : element, 'nr' : nr};
this.sections[nr] = section;
},
'takeItem' : function(nr, item) {
this.addAutoRun(nr, function() {
gamebook.player.take(item);
});
},
'dropItem' : function(nr, item) {
this.addAutoRun(nr, function() {
gamebook.player.drop(item);
});
},
'setCodeword' : function(nr, codeword) {
this.addAutoRun(nr, function() {
gamebook.player.set(codeword);
});
},
'turnTo' : function(nr) {
console.log("Turning to " + nr + ".");
if (!nr in this.sections) {
@ -105,14 +77,12 @@
this.player.currentSection.element.style.display = 'none';
}
var e = this.sections[nr].element;
this.enableDisableSectionLinks(
e.getElementsByClassName('sectiontext')[0]);
this.runActions(e.getElementsByClassName('sectiontext')[0]);
e.style.display = 'block';
this.player.currentSection = gamebook.sections[nr];
gamebook.runAutoRuns(nr);
},
'enableDisableSectionLinks' : function(e) {
'runActions' : function(e) {
// FIXME handle auto links that must be followed if possible
var enableNextLink = true;
Array.prototype.forEach.call(e.childNodes, function(c) {
@ -123,18 +93,22 @@
gamebook.disableLink(c);
}
enableNextLink = true;
} else if (c.className === 'itemcarried') {
var item = c.dataset.carried;
enableNextLink = gamebook.player.carries(item);
} else if (c.className === 'itemnotcarried') {
var item = c.dataset.carried;
enableNextLink = !gamebook.player.carries(item);
} else if (c.className === 'hascodeword') {
var codeword = c.dataset.has;
enableNextLink = gamebook.player.has(codeword);
} else if (c.className === 'hasnotcodeword') {
var codeword = c.dataset.has;
enableNextLink = !gamebook.player.has(codeword);
} else if (c.className === 'collect') {
gamebook.player.collect(c.dataset.type, c.dataset.name);
} else if (c.className === 'add') {
gamebook.player.add(c.dataset.type, c.dataset.what);
} else if (c.className === 'drop') {
gamebook.player.drop(c.dataset.type, c.dataset.what);
} else if (c.className === 'has') {
enableNextLink = gamebook.player.has(c.dataset.type,
c.dataset.what);
console.log("has " + c.dataset.type +
" " + c.dataset.what + " " + enableNextLink);
} else if (c.className === 'hasnot') {
enableNextLink = !gamebook.player.has(c.dataset.type,
c.dataset.what);
console.log("has not " + c.dataset.type +
" " + c.dataset.what + " " + enableNextLink);
}
});
},
@ -151,17 +125,26 @@
e.className = "disabledsectionref";
},
'updateInventory' : function() {
// FIXME obviously, this should be better written and do more
var e = document.getElementById('inventoryitems');
e.innerHTML = gamebook.player.inventory.join(', ');
'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);
},
'updateCodewords' : function() {
// FIXME obviously, this should be better written and do more
var e = document.getElementById('codewordslist');
e.innerHTML = Object.keys(gamebook.player.codewords
).sort().join(', ');
'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) {
@ -182,21 +165,24 @@
<style>
.enabledsectionref {font-weight: bold; cursor: pointer;}
.disabledsectionref {font-weight: bold; color: #aaa; cursor: not-allowed;}
.itemfound {font-weight: bold; cursor: pointer;}
.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%%;}
.inventory {background: #cfc; margin-top: 5em;}
.inventoryheading {}
.inventoryitems {}
.codewords {background: #fcc; margin-top: 0.5em;}
.codewordsheading {}
.codewordslist {}
.setcodeword {color: #f55;}
.hascodeword {color: #f55;}
.collections {margin-top: 4em;}
.collection {background: #ddd; margin-top: 1em;}
.collectionheading {}
.collectionheading::after {content: ": ";}
.collectioncontents {}
.collect {}
.add {font-weight: bold;}
.found {font-weight: bold; cursor: pointer;}
.drop {font-style: italic;}
.has {font-style: italic;}
.hasnot {font-style: italic;}
.collectionTemplate {display: none;}
</style>
</head>
<body>

View file

@ -1 +0,0 @@
<span class="itemcarried" data-carried="%(inner)s">%(inner)s</span>

View file

@ -0,0 +1,2 @@
<span class="collect" data-type="%(arg1)s"
data-name="%(inner)s">%(inner)s</span>

View file

@ -1,6 +1,2 @@
<span class="itemdrop">%(inner)s</span>
<script>
if (this.gamebook) {
gamebook.dropItem(%(nr)d, "%(inner)s");
}
</script>
<span class="drop" data-type="%(arg1)s"
data-what="%(inner)s">%(inner)s</span>

View file

@ -1,15 +1,12 @@
<div class="inventory">
<span class="inventoryheading">Carrying: </span>
<span class="inventoryitems" id="inventoryitems"></span>
<div id="collections" class="collections">
</div>
<div class="codewords">
<span class="codewordsheading">Codewords: </span>
<span class="codewordslist" id="codewordslist"></span>
<div id="collectionTemplate" class="collectionTemplate">
<span class="collectionheading"></span>
<span class="collectioncontents"></span>
</div>
</div>
<script>
if (this.gamebook) {
gamebook.updateInventory();
gamebook.turnTo(1);
}
</script>

View file

@ -1,3 +1,3 @@
<span class="itemfound"
onclick="gamebook.player.take('%(inner)s')"
<span class="found"
onclick="gamebook.player.add('%(arg1)s', '%(inner)s')"
>%(inner)s</span>

View file

@ -1 +1 @@
<span class="hascodeword" data-has="%(inner)s">%(inner)s</span>
<span class="has" data-type="%(arg1)s" data-what="%(inner)s">%(inner)s</span>

View file

@ -1 +1,2 @@
<span class="hasnotcodeword" data-has="%(inner)s">%(inner)s</span>
<span class="hasnot" data-type="%(arg1)s"
data-what="%(inner)s">%(inner)s</span>

View file

@ -1 +0,0 @@
<span class="itemnotcarried" data-carried="%(inner)s">%(inner)s</span>

View file

@ -1,7 +0,0 @@
<div class="setcodeword">codeword %(inner)s</div>
<script>
if (this.gamebook) {
console.log("set %(nr)d %(inner)s");
gamebook.setCodeword(%(nr)d, "%(inner)s");
}
</script>

1
templates/tex/add.tex Normal file
View file

@ -0,0 +1 @@
\textbf{%(inner)s}

1
templates/tex/drop.tex Normal file
View file

@ -0,0 +1 @@
\textit{%(inner)s}

View file

@ -1 +0,0 @@
Codeword \textit{%(inner)s}.

View file

@ -1,4 +1,4 @@
* TODO [23/47] [48%]
* TODO [24/48] [50%]
- [X] Debug output
- [X] DOT output
- [X] LaTeX output
@ -24,8 +24,12 @@
- [X] Make sure dropped items can not be picked up again
- [X] Fix problem with map file from other book sometimes crashing formatter
- [X] Keys from formatted book should be added to map file, not replace it
- [X] Make inventory and codewords generic
They are the same, sort of, and it might be good to be able to
add other similar entities as well, like skills or spells or whatever.
- [ ] More formatting possibilities in sections
Look at existing gamebooks to get ideas.
- [ ] Otherwise/else handling for has (or has not).
- [ ] Book option to set max section number to use
- [ ] Book option to set pdf layout (page size and number of columns)
- [ ] Book option to set title
@ -33,6 +37,8 @@
- [ ] Book option to set date
- [ ] Quote strings to not break formatting.
- [ ] Template for book introduction (including rules etc)
Sections with some markup (has number 0?) are added as chapters
of introduction, otherwise formatted identical to other sections.
- [ ] Some way to insert character sheet in book introduction
- [ ] Some way to insert dice at bottom of pages for LaTeX
- [ ] Some way to insert optional random numbers table at end of book
@ -43,11 +49,10 @@
- [ ] Verify gamebook for debug and dot outputs
- [ ] Dummy sections (handle properly when verifying)
- [ ] Counters (life, money, whatever) create and set
count tag to declare new counter, text in tag is display name
optional argument sets the starting value of the tag
- [ ] Counters increase/decrease
- [ ] Counters check
- [ ] Document Gamebook format
- [ ] HTML CSS
- [ ] Higher level text-language for Gamebooks
- [ ] Make inventory and codewords generic
They are the same, sort of, and it might be good to be able to
add other similar entities as well, like skills or spells or whatever.