diff --git a/.gitignore b/.gitignore
index 1fcd153..3e5979f 100644
--- a/.gitignore
+++ b/.gitignore
@@ -8,7 +8,6 @@ test.dot
*.toc
*.pdf
test.rtf
-*.png
*.out
test.html
.lein*
diff --git a/examples/.gitignore b/examples/.gitignore
index c76759c..5e8b2fb 100644
--- a/examples/.gitignore
+++ b/examples/.gitignore
@@ -3,4 +3,6 @@
*.html
*.dot
*.debug
-*.txt
\ No newline at end of file
+*.txt
+*.png
+!testimage.png
\ No newline at end of file
diff --git a/examples/format.gamebook b/examples/format.gamebook
index cb6b042..f358487 100644
--- a/examples/format.gamebook
+++ b/examples/format.gamebook
@@ -1,12 +1,27 @@
title = Format
+starttext = Adventure begins in section 1.
+hideintrotext = HIDE THE INTRO
+showintrotext = SHOW THE INTRO
+
+= 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.
+
* 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
or &boom;.
+There should be an image below as well.
If something broke, turn to [[bad]],
otherwise turn to [[good]].
+[img]testimage.png[/img]
* dum :dummy:
Sections tagged as dummy will not be
diff --git a/examples/references.gamebook b/examples/references.gamebook
index 746b33a..6159932 100644
--- a/examples/references.gamebook
+++ b/examples/references.gamebook
@@ -1,4 +1,11 @@
max = 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 [[start]] or the next
+section at [[next]].
+
* 1 start
This is where the adventure begins. You can go on to the
next section, see [[next]] or try the other instead, see [[other]].
diff --git a/examples/testimage.png b/examples/testimage.png
new file mode 100644
index 0000000..41e39ae
Binary files /dev/null and b/examples/testimage.png differ
diff --git a/formatgamebook.py b/formatgamebook.py
index b177193..f474c03 100755
--- a/formatgamebook.py
+++ b/formatgamebook.py
@@ -28,6 +28,7 @@ THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
"""
+import re
import os
import os.path
import sys
@@ -41,6 +42,8 @@ from output import OutputFormat
USAGE = "usage: %prog [options] inputfile(s)... outputfile"
+SECTION_NAME_RE = re.compile("^[a-z][a-z_0-9]*$")
+
def of(extension, name, quote):
return {'extension' : extension,
'name' : name,
@@ -81,17 +84,15 @@ def parse_file_to_book(inputfile, book):
number = None
text = ""
tags = None
+ intro_section = False
for line in inputfile.readlines():
- if before_first_section:
- if '=' in line:
- config = line.split('=')
- book.configure(config[0].strip(), config[1].strip())
if line.startswith('*'):
before_first_section = False
if name:
- add_section_to_book(book, name, text, number)
+ add_section_to_book(book, name, text, intro_section, number)
number = None
text = ""
+ intro_section = False
heading = [h.strip() for h in line[1:].strip().split()]
if len(heading) > 1 and heading[-1].startswith(':'):
if not heading[-1].endswith(':'):
@@ -106,20 +107,34 @@ def parse_file_to_book(inputfile, book):
elif len(heading) == 2:
number = int(heading[0])
name = heading[1]
- else:
- raise Exception("bad section heading %s" % str(heading))
- else:
+ if not name or not SECTION_NAME_RE.match(name):
+ raise Exception("bad section heading: %s" % str(heading))
+ elif line.startswith('='):
+ if name:
+ add_section_to_book(book, name, text, intro_section, number)
+ name = line[1:].strip()
+ intro_section = True
+ text = ""
+ elif before_first_section and '=' in line:
+ config = line.split('=')
+ book.configure(config[0].strip(), config[1].strip())
+ elif name:
text = text + " " + line.strip()
+ elif len(line.strip()):
+ raise Exception("unknown content before sections: %s" % line.strip())
if name:
- add_section_to_book(book, name, text, number, tags)
+ add_section_to_book(book, name, text, intro_section, number, tags)
-def add_section_to_book(book, name, text, number=None, tags=None):
+def add_section_to_book(book, name, text, intro_section=False, number=None, tags=None):
section = sections.Section(name, text)
if tags:
section.add_tags(tags)
- book.add(section)
- if number:
- book.force_section_nr(name, number)
+ if intro_section:
+ book.addintro(section)
+ else:
+ book.add(section)
+ if number:
+ book.force_section_nr(name, number)
def make_output(outputfilename, templatedirs):
for of in OUTPUT_FORMATS:
@@ -134,6 +149,8 @@ def write_book(book, output_format, outputfilename):
shuffled_sections = book.shuffle()
output = open(outputfilename, 'w')
output_format.write_begin(book, output)
+ output_format.write_intro_sections(book, shuffled_sections, output)
+ output_format.write_sections_begin(book, output)
output_format.write_shuffled_sections(shuffled_sections, output)
output_format.write_end(book, output)
save_section_mapping(shuffled_sections, outputfilename)
diff --git a/output.py b/output.py
index 15ef76e..46cfbad 100644
--- a/output.py
+++ b/output.py
@@ -12,6 +12,27 @@ class OutputFormat (object):
# FIXME make sure book config is properly quoted
print >> output, self.format_with_template("begin", book.config)
+ def write_intro_sections(self, book, shuffled_sections, output):
+ for s in book.introsections:
+ if not s.hastag('dummy'):
+ self.write_intro_section(s, shuffled_sections, output)
+
+ def write_intro_section(self, section, shuffled_sections, output):
+ # FIXME some serious code-duplication here
+ refs = []
+ refsdict = ReferenceFormatter(section, shuffled_sections,
+ self.format_with_template("section_ref"),
+ self.quote)
+ formatted_text = self.format_section(section, refsdict)
+ print >> output, self.format_with_template("introsection", {
+ 'name' : section.name,
+ 'text' : formatted_text,
+ 'refs' : '\n'.join(refsdict.getfound()) # hack for DOT output
+ }),
+
+ def write_sections_begin(self, book, output):
+ print >> output, self.format_with_template("sections_begin", book.config);
+
def write_shuffled_sections(self, shuffled_sections, output):
for i, p in enumerate(shuffled_sections.as_list):
if p and not p.hastag('dummy'):
@@ -26,7 +47,7 @@ class OutputFormat (object):
self.quote)
formatted_text = self.format_section(section, refsdict)
print >> output, self.format_with_template("section", {
- 'nr' : shuffled_sections.to_nr[section],
+ 'nr' : section.nr,
'name' : section.name,
'text' : formatted_text,
'refs' : '\n'.join(refsdict.getfound()) # hack for DOT output
@@ -92,7 +113,7 @@ class OutputFormat (object):
}),
def write_end(self, book, output):
- print >> output, self.format_with_template("end"),
+ print >> output, self.format_with_template("end", book.config),
def format_with_template(self, name, values=None):
template = self.templates.get(name)
@@ -108,7 +129,7 @@ class ReferenceFormatter (object):
self.shuffled_sections = shuffled_sections
self.found = set()
self.ref_template = ref_template
- self.items = {'nr' : shuffled_sections.to_nr[section]}
+ self.items = {'nr' : section.nr}
self.quote = quote
def __getitem__(self, key):
@@ -116,8 +137,8 @@ class ReferenceFormatter (object):
return self.quote(self.items[key])
to_section = self.shuffled_sections.from_name[key]
res = self.ref_template % {
- 'nr' : self.shuffled_sections.to_nr[to_section],
- 'from_nr' : self.shuffled_sections.to_nr[self.section]
+ 'nr' : to_section.nr,
+ 'from_nr' : self.section.nr
}
if key in self.shuffled_sections.name_to_nr:
self.found.add(res)
diff --git a/sections.py b/sections.py
index c8a1b0c..6eeb7ef 100644
--- a/sections.py
+++ b/sections.py
@@ -17,30 +17,57 @@ class Section:
return "Section(%s, %s, %s)" % (repr(self.name), repr(self.text),
repr(self.tags))
+class ShuffledSection (Section):
+ def __init__(self, nr, section):
+ self.nr = nr
+ self.name = section.name
+ self.text = section.text
+ self.tags = section.tags.copy()
+
+ def __repr__(self):
+ return "ShuffledSection(%d, %s, %s, %s)" % (self.nr,
+ repr(self.name), repr(self.text),
+ repr(self.tags))
+
+class IntroSection (Section):
+ def __init__(self, section):
+ self.nr = -1
+ self.name = section.name
+ self.text = section.text
+ self.tags = section.tags.copy()
+
+ def __repr__(self):
+ return "IntroSection(%d, %s, %s, %s)" % (repr(self.name), repr(self.text),
+ repr(self.tags))
+
class ShuffledSections:
- def __init__(self, as_list, from_nr, to_nr, from_name, nr_sections):
+ def __init__(self, as_list, from_nr, from_name, nr_sections):
self.as_list = as_list
self.from_nr = from_nr
- self.to_nr = to_nr
self.from_name = from_name
self.name_to_nr = {}
for n in from_name:
- self.name_to_nr[n] = to_nr[from_name[n]]
+ self.name_to_nr[n] = from_name[n].nr
for nr in nr_sections:
self.name_to_nr[nr_sections[nr]] = nr
-STR_BOOK_CONFIG = set(['title', 'author'])
+STR_BOOK_CONFIG = set(['title', 'author', 'starttext', 'hideintrotext',
+ 'showintrotext'])
INT_BOOK_CONFIG = set(['max'])
class Book:
def __init__(self):
self.sections = []
+ self.introsections = []
self.from_name = {}
self.nr_sections = {}
self.codewords = set()
self.config = {'max' : 0,
'title' : 'Gamebook',
- 'author' : ''}
+ 'author' : '',
+ 'starttext' : 'Turn to 1 to begin.',
+ 'hideintrotext' : '(hide instructions)',
+ 'showintrotext' : '(show instructions)'}
def configure(self, name, value):
if name in INT_BOOK_CONFIG:
@@ -59,6 +86,9 @@ class Book:
if len(self.sections) > self.config['max']:
self.config['max'] = len(self.sections)
+ def addintro(self, section):
+ self.introsections.append(IntroSection(section))
+
def add_codeword(self, word):
self.codewords.add(word)
@@ -70,8 +100,8 @@ class Book:
def shuffle(self):
as_list = [None]
from_nr = {}
- to_nr = {}
shuffled = self.sections[:]
+ shuffled_from_name = {}
while len(shuffled) < self.config['max']:
dummy = Section('Dummy', '')
dummy.add_tags(['dummy'])
@@ -83,16 +113,16 @@ class Book:
for nr in range(1, self.config['max'] + 1):
if (self.nr_sections.has_key(nr)
and self.nr_sections[nr] in self.from_name):
- section = self.from_name[self.nr_sections[nr]]
+ section = ShuffledSection(nr, self.from_name[self.nr_sections[nr]])
elif len(shuffled):
- section = shuffled.pop()
+ section = ShuffledSection(nr, shuffled.pop())
else:
section = None
as_list.append(section)
from_nr[nr] = section
if section:
- to_nr[section] = nr
- return ShuffledSections(as_list, from_nr, to_nr, self.from_name.copy(),
+ shuffled_from_name[section.name] = section
+ return ShuffledSections(as_list, from_nr, shuffled_from_name,
self.nr_sections)
class Item (object):
diff --git a/templates/DEFAULT/img.txt b/templates/DEFAULT/img.txt
new file mode 100644
index 0000000..e69de29
diff --git a/templates/DEFAULT/introsection.txt b/templates/DEFAULT/introsection.txt
new file mode 100644
index 0000000..91bb99f
--- /dev/null
+++ b/templates/DEFAULT/introsection.txt
@@ -0,0 +1,2 @@
+#include "introsectionheading"
+#include "sectionbody"
diff --git a/templates/DEFAULT/sections_begin.txt b/templates/DEFAULT/sections_begin.txt
new file mode 100644
index 0000000..dd41cff
--- /dev/null
+++ b/templates/DEFAULT/sections_begin.txt
@@ -0,0 +1,2 @@
+
+%(starttext)s
diff --git a/templates/debug/img.debug b/templates/debug/img.debug
new file mode 100644
index 0000000..15974fd
--- /dev/null
+++ b/templates/debug/img.debug
@@ -0,0 +1 @@
+[IMG]%(inner)s[/IMG]
\ No newline at end of file
diff --git a/templates/debug/introsection.debug b/templates/debug/introsection.debug
new file mode 100644
index 0000000..530d132
--- /dev/null
+++ b/templates/debug/introsection.debug
@@ -0,0 +1,2 @@
+%(name)s
+%(text)s
diff --git a/templates/dot/introsection.dot b/templates/dot/introsection.dot
new file mode 100644
index 0000000..e69de29
diff --git a/templates/dot/sections_begin.dot b/templates/dot/sections_begin.dot
new file mode 100644
index 0000000..e69de29
diff --git a/templates/html/begin.html b/templates/html/begin.html
index ee03fe2..ea6d929 100644
--- a/templates/html/begin.html
+++ b/templates/html/begin.html
@@ -12,5 +12,5 @@
-#include "intro"
+#include "hideintro"
diff --git a/templates/html/end.html b/templates/html/end.html
index c3cc145..e1ed820 100644
--- a/templates/html/end.html
+++ b/templates/html/end.html
@@ -3,5 +3,6 @@
+#include "showintro"