1
0
Fork 0
mirror of https://github.com/Oreolek/gamebookformat.git synced 2024-05-16 16:08:20 +03:00

Counters.

This commit is contained in:
Pelle Nilsson 2013-06-18 22:21:29 +02:00
parent 4928bd0f14
commit 4cfcc4888f
38 changed files with 551 additions and 21 deletions

View file

@ -17,10 +17,10 @@ uploadto=$(shell cat .uploadto)
readme.html: readme.org
emacs -Q --batch --visit=readme.org --funcall org-export-as-html-batch
examples/gamebookformatplay.js:
examples/gamebookformatplay.js: gamebookformatplay.js
cp gamebookformatplay.js $@
examples/gamebookformat.css:
examples/gamebookformat.css: gamebookformat.css
cp gamebookformat.css $@
%.rtf: %.gamebook *.py templates/rtf/*.rtf
@ -57,7 +57,7 @@ expected: all
checkexpected: clean rtf tex html debug dot txt
diff -r -x "*.aux" -x "*.gamebook" -x "*.log" -x "*.out" -x "*.png" \
-x "*.pdf" -x .gitignore -x "*.js" -x "*.css" \
-q examples expected
-x "*.options" -q examples expected
unittests=$(wildcard test_*.py)

View file

@ -0,0 +1,24 @@
title = Counters Example
= Introduction
This example gamebook shows how to use counters.
* 1 start
This is where the gamebook starts.
We have counters for [count life]Life Points[/count] and for
[count gold]Gold[/count]. You start the adventure with
[set life]10[/set] and [set gold]12[/set].
You can never have less than [min gold]0[/min]. FIXME need to
figure out best syntax for death when life points go below 1.
Go to [[getgold]] to get more Gold or [[dangerous]] to lose some Life Points.
* getgold
Congratulations, you found [inc gold]2[/gold].
You can go to [[dangerous]] to lose some life or to [[losegold]] to drop
some gold.
* dangerous
You lose [dec life]1[/dec].
You can go to [[getgold]] to get some Gold.
* losegold
You drop [dec gold]5[/dec]. It should not be possible to
go below 0. Then go on to get gold at [[getgold]] or lose life at [[dangerous]].

View file

@ -123,7 +123,14 @@ if (this.gamebook) {
if (this.gamebook) {
gamebook.addSection(9, document.getElementById('section9'));
}
</script> <div id="collections" class="collections">
</script> <div id="counters" class="counters">
</div>
<div id="counterTemplate" class="counterTemplate">
<span class="counterheading"></span>
<span class="countercontents"></span>
</div>
</div>
<div id="collections" class="collections">
</div>
<div id="collectionTemplate" class="collectionTemplate">
<span class="collectionheading"></span>

19
expected/counters.debug Normal file
View file

@ -0,0 +1,19 @@
BEGIN DEBUG OUTPUT
Book title: Counters Example
Number of sections: 4
Introduction
This example gamebook shows how to use counters.
Turn to 1 to begin.
1 (start) - This is where the gamebook starts. We have counters for Life Points and for Gold. You start the adventure with 10 Life Points
and 12 Gold
. You can never have less than 0 Gold
. FIXME need to figure out best syntax for death when life points go below 1. Go to 4 to get more Gold or 3 to lose some Life Points.
2 (losegold) - You drop 5 Gold
. It should not be possible to go below 0. Then go on to get gold at 4 or lose life at 3.
3 (dangerous) - You lose 1 Life Points
. You can go to 4 to get some Gold.
4 (getgold) - Congratulations, you found 2 Gold
. You can go to 3 to lose some life or to 2 to drop some gold.
END DEBUG OUTPUT

13
expected/counters.dot Normal file
View file

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

111
expected/counters.html Normal file
View file

@ -0,0 +1,111 @@
<!DOCTYPE html>
<html>
<head>
<meta charset='utf-8'>
<meta name="viewport"
content="width=device-width, initial-scale=1, maximum-scale=1">
<title>Counters Example</title>
<script type="text/javascript" src="gamebookformatplay.js"></script>
<link rel="stylesheet" href="gamebookformat.css"
type="text/css" />
<script>
gamebook.id = 'counters';
</script>
</head>
<body>
<div class="hideintrolink nodisplay"
onclick="gamebook.hideIntroSections()">(hide instructions)</div>
<div class="gamebook">
<div class="introsection">
<div class="introsectionheading">Introduction</div>
<div class="introsectionbody">
This example gamebook shows how to use counters.
</div>
</div>
<div class="resumelink nodisplay"
onclick="gamebook.loadGame()">Resume saved game.</div>
<div class="startlink"
onclick="gamebook.turnTo(1)">Turn to 1 to begin.</div>
<script>
if (gamebook.hasSavedGame()) {
var resumeLinks = document.getElementsByClassName('resumelink');
Array.prototype.forEach.call(resumeLinks, function(e) {
e.classList.remove('nodisplay');
});
}
</script>
<div class="section" id="section1">
<div class="sectionnumber" id="para1">1</div>
<div class="sectiontext">
This is where the gamebook starts. We have counters for <span class="count counterChange" data-type="life"
data-name="Life Points">Life Points</span> and for <span class="count counterChange" data-type="gold"
data-name="Gold">Gold</span>. You start the adventure with <span class="set counterChange" data-type="life"
data-amount="10">10 Life Points</span> and <span class="set counterChange" data-type="gold"
data-amount="12">12 Gold</span>. You can never have less than <span class="min counterChange" data-type="gold"
data-limit="0">0 Gold</span>
. FIXME need to figure out best syntax for death when life points go below 1. Go to <a class="sectionref enabledlink" data-ref="4">4</a> to get more Gold or <a class="sectionref enabledlink" data-ref="3">3</a> to lose some Life Points.
</div>
</div>
<script>
if (this.gamebook) {
gamebook.addSection(1, document.getElementById('section1'));
}
</script><div class="section" id="section2">
<div class="sectionnumber" id="para2">2</div>
<div class="sectiontext">
You drop <span class="dec counterChange" data-type="gold"
data-amount="5">5 Gold</span>. It should not be possible to go below 0. Then go on to get gold at <a class="sectionref enabledlink" data-ref="4">4</a> or lose life at <a class="sectionref enabledlink" data-ref="3">3</a>.
</div>
</div>
<script>
if (this.gamebook) {
gamebook.addSection(2, document.getElementById('section2'));
}
</script><div class="section" id="section3">
<div class="sectionnumber" id="para3">3</div>
<div class="sectiontext">
You lose <span class="dec counterChange" data-type="life"
data-amount="1">1 Life Points</span>. You can go to <a class="sectionref enabledlink" data-ref="4">4</a> to get some Gold.
</div>
</div>
<script>
if (this.gamebook) {
gamebook.addSection(3, document.getElementById('section3'));
}
</script><div class="section" id="section4">
<div class="sectionnumber" id="para4">4</div>
<div class="sectiontext">
Congratulations, you found <span class="inc counterChange" data-type="gold"
data-amount="2">2 Gold</span>. You can go to <a class="sectionref enabledlink" data-ref="3">3</a> to lose some life or to <a class="sectionref enabledlink" data-ref="2">2</a> to drop some gold.
</div>
</div>
<script>
if (this.gamebook) {
gamebook.addSection(4, document.getElementById('section4'));
}
</script> <div id="counters" class="counters">
</div>
<div id="counterTemplate" class="counterTemplate">
<span class="counterheading"></span>
<span class="countercontents"></span>
</div>
</div>
<div id="collections" class="collections">
</div>
<div id="collectionTemplate" class="collectionTemplate">
<span class="collectionheading"></span>
<span class="collectioncontents"></span>
</div>
</div>
<script>
if (this.gamebook) {
gamebook.runActionsInIntroSections();
}
</script>
<div class="displayintrolink nodisplay"
onclick="gamebook.showIntroSections()">(show instructions)</div>
</div>
</body>
</html>

62
expected/counters.rtf Normal file
View file

@ -0,0 +1,62 @@
{\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 Counters Example
\b0\
\b \qc Introduction
\b0\
\ql This example gamebook shows how to use counters. \
\
\b Turn to 1 to begin.
\b0\
\
\b \qc 1
\b0\
\ql This is where the gamebook starts. We have counters for Life Points and for Gold. You start the adventure with 10 Life Points
and 12 Gold
. You can never have less than 0 Gold
. FIXME need to figure out best syntax for death when life points go below 1. Go to \b 4
\b0
to get more Gold or \b 3
\b0
to lose some Life Points. \
\
\b \qc 2
\b0\
\ql You drop 5 Gold
. It should not be possible to go below 0. Then go on to get gold at \b 4
\b0
or lose life at \b 3
\b0
. \
\
\b \qc 3
\b0\
\ql You lose 1 Life Points
. You can go to \b 4
\b0
to get some Gold. \
\
\b \qc 4
\b0\
\ql Congratulations, you found 2 Gold
. You can go to \b 3
\b0
to lose some life or to \b 2
\b0
to drop some gold. \
\
}

83
expected/counters.tex Normal file
View file

@ -0,0 +1,83 @@
\documentclass[a5paper,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{Counters Example}
\author{}
\date{}
\newcounter{sectionnr}
\begin{document}
\maketitle
\thispagestyle{empty}
\pagestyle{empty}
\clearpage
\subsection*{\begin{center} \textbf{Introduction} \end{center}}
\noindent
This example gamebook shows how to use counters.
\vspace{1em}
Turn to 1 to begin.
\phantomsection
\refstepcounter{sectionnr}
\label{section1}
\subsection*{\begin{center} \textbf{1} \end{center}}
\noindent
This is where the gamebook starts. We have counters for Life Points and for Gold. You start the adventure with 10 Life Points
and 12 Gold
. You can never have less than 0 Gold
. FIXME need to figure out best syntax for death when life points go below 1. Go to \textbf{\autoref{section4}} to get more Gold or \textbf{\autoref{section3}} to lose some Life Points.
\vspace{1em}
\phantomsection
\refstepcounter{sectionnr}
\label{section2}
\subsection*{\begin{center} \textbf{2} \end{center}}
\noindent
You drop 5 Gold
. It should not be possible to go below 0. Then go on to get gold at \textbf{\autoref{section4}} or lose life at \textbf{\autoref{section3}}.
\vspace{1em}
\phantomsection
\refstepcounter{sectionnr}
\label{section3}
\subsection*{\begin{center} \textbf{3} \end{center}}
\noindent
You lose 1 Life Points
. You can go to \textbf{\autoref{section4}} to get some Gold.
\vspace{1em}
\phantomsection
\refstepcounter{sectionnr}
\label{section4}
\subsection*{\begin{center} \textbf{4} \end{center}}
\noindent
Congratulations, you found 2 Gold
. You can go to \textbf{\autoref{section3}} to lose some life or to \textbf{\autoref{section2}} to drop some gold.
\vspace{1em}
\end{document}

26
expected/counters.txt Normal file
View file

@ -0,0 +1,26 @@
Counters Example
Introduction
This example gamebook shows how to use counters.
Turn to 1 to begin.
1
This is where the gamebook starts. We have counters for Life Points and for Gold. You start the adventure with 10 Life Points
and 12 Gold
. You can never have less than 0 Gold
. FIXME need to figure out best syntax for death when life points go below 1. Go to 4 to get more Gold or 3 to lose some Life Points.
2
You drop 5 Gold
. It should not be possible to go below 0. Then go on to get gold at 4 or lose life at 3.
3
You lose 1 Life Points
. You can go to 4 to get some Gold.
4
Congratulations, you found 2 Gold
. You can go to 3 to lose some life or to 2 to drop some gold.

View file

@ -72,7 +72,14 @@ if (this.gamebook) {
if (this.gamebook) {
gamebook.addSection(3, document.getElementById('section3'));
}
</script> <div id="collections" class="collections">
</script> <div id="counters" class="counters">
</div>
<div id="counterTemplate" class="counterTemplate">
<span class="counterheading"></span>
<span class="countercontents"></span>
</div>
</div>
<div id="collections" class="collections">
</div>
<div id="collectionTemplate" class="collectionTemplate">
<span class="collectionheading"></span>

View file

@ -158,7 +158,14 @@ if (this.gamebook) {
if (this.gamebook) {
gamebook.addSection(11, document.getElementById('section11'));
}
</script> <div id="collections" class="collections">
</script> <div id="counters" class="counters">
</div>
<div id="counterTemplate" class="counterTemplate">
<span class="counterheading"></span>
<span class="countercontents"></span>
</div>
</div>
<div id="collections" class="collections">
</div>
<div id="collectionTemplate" class="collectionTemplate">
<span class="collectionheading"></span>

View file

@ -86,7 +86,14 @@ if (this.gamebook) {
if (this.gamebook) {
gamebook.addSection(400, document.getElementById('section400'));
}
</script> <div id="collections" class="collections">
</script> <div id="counters" class="counters">
</div>
<div id="counterTemplate" class="counterTemplate">
<span class="counterheading"></span>
<span class="countercontents"></span>
</div>
</div>
<div id="collections" class="collections">
</div>
<div id="collectionTemplate" class="collectionTemplate">
<span class="collectionheading"></span>

View file

@ -80,7 +80,14 @@ if (this.gamebook) {
if (this.gamebook) {
gamebook.addSection(6, document.getElementById('section6'));
}
</script> <div id="collections" class="collections">
</script> <div id="counters" class="counters">
</div>
<div id="counterTemplate" class="counterTemplate">
<span class="counterheading"></span>
<span class="countercontents"></span>
</div>
</div>
<div id="collections" class="collections">
</div>
<div id="collectionTemplate" class="collectionTemplate">
<span class="collectionheading"></span>

View file

@ -80,7 +80,14 @@ if (this.gamebook) {
if (this.gamebook) {
gamebook.addSection(5, document.getElementById('section5'));
}
</script> <div id="collections" class="collections">
</script> <div id="counters" class="counters">
</div>
<div id="counterTemplate" class="counterTemplate">
<span class="counterheading"></span>
<span class="countercontents"></span>
</div>
</div>
<div id="collections" class="collections">
</div>
<div id="collectionTemplate" class="collectionTemplate">
<span class="collectionheading"></span>

View file

@ -110,7 +110,14 @@ if (this.gamebook) {
if (this.gamebook) {
gamebook.addSection(8, document.getElementById('section8'));
}
</script> <div id="collections" class="collections">
</script> <div id="counters" class="counters">
</div>
<div id="counterTemplate" class="counterTemplate">
<span class="counterheading"></span>
<span class="countercontents"></span>
</div>
</div>
<div id="collections" class="collections">
</div>
<div id="collectionTemplate" class="collectionTemplate">
<span class="collectionheading"></span>

View file

@ -32,12 +32,19 @@
.collectionheading {}
.collectionheading::after {content: ": ";}
.collectioncontents {}
.counters {margin-top: 4em;}
.counter {background: #eee;}
.counterheading {}
.counterheading::after {content: ": ";}
.countercontents {}
.collect {}
.add {font-weight: bold;}
.drop {font-style: italic;}
.has {font-style: italic;}
.hasnot {font-style: italic;}
.collectionTemplate {display: none;}
.counterTemplate {display: none;}
.sectionimage {width: 100%; padding: 1em;}
.nodisplay {display: none;}
.resumenr {font-weight: bold;}
.counterChange {font-weight: bold;}

View file

@ -3,6 +3,7 @@ var gamebook = {
'started' : false,
'currentSection' : -1,
'collections' : {},
counters : {},
'collect' : function(type, name) {
if (type in this.collections) {
@ -33,6 +34,37 @@ var gamebook = {
gamebook.addCollectionView(type, name);
},
count : function(type, name) {
if (type in this.counters) {
return;
};
this.counters[type] = {
name : name,
value : 0,
minValue : null, //no minimum set
inc : function(amount) {
this.value += amount;
},
dec : function(amount) {
this.value -= amount;
this.ensureNotBelowMin();
},
set : function(value) {
this.value = value;
this.ensureNotBelowMin();
},
min : function(limit) {
this.minValue = limit;
},
ensureNotBelowMin : function() {
if (this.minValue !== null && this.value < this.minValue) {
this.value = this.minValue;
}
}
};
gamebook.addCounterView(type, name);
},
'add' : function(type, what) {
this.collections[type].add(what);
gamebook.updateCollectionsView();
@ -47,10 +79,30 @@ var gamebook = {
return this.collections[type].has(what);
},
inc : function(type, amount) {
this.counters[type].inc(amount);
gamebook.updateCountersView();
},
dec : function(type, amount) {
this.counters[type].dec(amount);
gamebook.updateCountersView();
},
min : function(type, limit) {
this.counters[type].min(limit);
},
set : function(type, amount) {
this.counters[type].set(amount);
gamebook.updateCountersView();
},
'getState' : function() {
return JSON.stringify({
'collections' : this.collections,
'currentSection' : this.currentSection
'currentSection' : this.currentSection,
'counters' : this.counters
});
},
@ -67,6 +119,16 @@ var gamebook = {
this.collections[c].contents = collection.contents;
this.collections[c].dropped = collection.dropped;
}
for (var c in parsedState.counters) {
var counter = parsedState.counters[c];
if (c in this.counters) {
this.counters[c].name = counter.name;
} else {
this.count(c, counter.name);
}
this.counters[c].minValue = counter.minValue;
this.counters[c].value = counter.value;
}
}
},
@ -102,11 +164,11 @@ var gamebook = {
var section = this.sections[this.player.currentSection];
section.element.style.display = 'none';
}
this.player.currentSection = nr;
this.saveGame();
var e = this.sections[nr].element;
this.runActions(e.getElementsByClassName('sectiontext')[0]);
e.style.display = 'block';
this.player.currentSection = nr;
this.saveGame();
},
//FIXME move out from gamebook object
@ -204,6 +266,20 @@ var gamebook = {
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('count')) {
gamebook.player.count(c.dataset.type, c.dataset.name);
} else if (c.classList.contains('set')) {
gamebook.player.set(c.dataset.type,
parseInt(c.dataset.amount));
} else if (c.classList.contains('inc')) {
gamebook.player.inc(c.dataset.type,
parseInt(c.dataset.amount));
} else if (c.classList.contains('dec')) {
gamebook.player.dec(c.dataset.type,
parseInt(c.dataset.amount));
} else if (c.classList.contains('min')) {
gamebook.player.min(c.dataset.type,
parseInt(c.dataset.limit));
} else if (c.classList.contains('has')) {
enableNextLink = gamebook.player.has(c.dataset.type,
c.dataset.what);
@ -260,11 +336,19 @@ var gamebook = {
},
'addCollectionView' : function(type, name) {
var ce = document.getElementById('collections');
var template = document.getElementById('collectionTemplate');
this.addView('collection', type, name);
},
addCounterView : function(type, name) {
this.addView('counter', type, name);
},
addView : function(view, type, name) {
var ce = document.getElementById(view + 's');
var template = document.getElementById(view + 'Template');
var e = template.cloneNode(true);
e.className = "collection";
e.getElementsByClassName('collectionheading')[0].innerHTML = name;
e.className = view;
e.getElementsByClassName(view + 'heading')[0].innerHTML = name;
e.dataset.type = type;
ce.appendChild(e);
},
@ -281,6 +365,18 @@ var gamebook = {
});
},
'updateCountersView' : function() {
var ce = document.getElementById('counters');
Array.prototype.forEach.call(ce.childNodes, function(c) {
if (c.className === 'counter') {
var type = c.dataset.type;
var counter = gamebook.player.counters[type];
var cc = c.getElementsByClassName('countercontents')[0];
cc.innerHTML = counter.value;
}
});
},
'getTurnToFunction' : function(nr) {
if (nr in this.turnToFunctions) {
return this.turnToFunctions[nr];

View file

@ -2,11 +2,15 @@ import os
import os.path
import sys
COUNTER_CREATE_TAG = 'count'
COUNTER_USE_TAGS = set(['set', 'inc', 'dec', 'min'])
class OutputFormat (object):
"Handles book output. Big FIXME required to make sense."
def __init__(self, templates, quote):
self.templates = templates
self.quote = quote
self.counter_names = {}
def format_begin(self, bookconfig):
# FIXME make sure book config is properly quoted
@ -99,9 +103,15 @@ class OutputFormat (object):
tag, self.name))
inner = section.text[tag_end+1:end_tag_start]
# FIXME this pollutes the mutable references object
references['inner'] = self.quote(self.quote(inner))
references['inner'] = self.quote(inner)
for i, arg in enumerate(tagparts[1:]):
references['arg%d' % (i+1)] = self.quote(arg)
if tagname == COUNTER_CREATE_TAG and len(tagparts) > 1:
self.counter_names[tagparts[1]] = self.quote(inner)
references['counter'] = self.quote(inner)
elif tagname in COUNTER_USE_TAGS and len(tagparts) > 1:
if tagparts[1] in self.counter_names:
references['counter'] = self.counter_names[tagparts[1]]
f = self.format_with_template(tagname,
references)
if len(f) > 0:

View file

@ -0,0 +1 @@
%(inner)s %(counter)s

View file

@ -0,0 +1 @@
%(inner)s %(counter)s

View file

@ -0,0 +1 @@
%(inner)s %(counter)s

View file

@ -0,0 +1 @@
%(inner)s %(counter)s

View file

@ -0,0 +1 @@
%(inner)s %(counter)s

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

@ -0,0 +1,2 @@
<div id="counters" class="counters">
</div>

View file

@ -0,0 +1,5 @@
<div id="counterTemplate" class="counterTemplate">
<span class="counterheading"></span>
<span class="countercontents"></span>
</div>
</div>

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

@ -0,0 +1,2 @@
<span class="dec counterChange" data-type="%(arg1)s"
data-amount="%(inner)s">%(inner)s %(counter)s</span>

View file

@ -1,3 +1,5 @@
#include "counters"
#include "countertemplate"
#include "collections"
#include "collectiontemplate"
<script>

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

@ -0,0 +1,2 @@
<span class="inc counterChange" data-type="%(arg1)s"
data-amount="%(inner)s">%(inner)s %(counter)s</span>

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

@ -0,0 +1,2 @@
<span class="min counterChange" data-type="%(arg1)s"
data-limit="%(inner)s">%(inner)s %(counter)s</span>

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

@ -0,0 +1,2 @@
<span class="set counterChange" data-type="%(arg1)s"
data-amount="%(inner)s">%(inner)s %(counter)s</span>

View file

@ -1,3 +1,4 @@
\
\b \qc %(name)s
\b0\

View file

@ -1,4 +1,4 @@
* TODO [45/72] [62%]
* TODO [47/72] [65%]
- [X] Debug output
- [X] DOT output
- [X] LaTeX output
@ -53,11 +53,11 @@
Allow sections with same name as long as only one is included.
Add book config for what section to use for references to excluded sections
(eg links to outside of demo version can lead to section explaining that)
- [ ] Counters (life, money, whatever) create and set
- [X] 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
display somewhere on page (in HTML output)
- [ ] Counters increase/decrease
- [X] Counters increase/decrease
- [ ] Counters check
- [ ] Make sure HTML output works with javascript disabled
and in inferior browsers