mirror of
https://github.com/Oreolek/gamebookformat.git
synced 2024-06-26 03:41:04 +03:00
Use term section instead of paragraph.
Because it will become confusing later when there is support for sections split up in several paragraphs otherwise.
This commit is contained in:
parent
81f27d0648
commit
5d42472385
|
@ -33,7 +33,7 @@ import os.path
|
||||||
import sys
|
import sys
|
||||||
import json
|
import json
|
||||||
|
|
||||||
import paragraphs
|
import sections
|
||||||
|
|
||||||
from output import OutputFormat
|
from output import OutputFormat
|
||||||
from latex import LatexFormat
|
from latex import LatexFormat
|
||||||
|
@ -57,7 +57,7 @@ def make_supported_formats_list_string():
|
||||||
|
|
||||||
def format_gamebook(inputfilenames, outputfilename):
|
def format_gamebook(inputfilenames, outputfilename):
|
||||||
output_format = find_output_format(outputfilename)
|
output_format = find_output_format(outputfilename)
|
||||||
book = paragraphs.Book()
|
book = sections.Book()
|
||||||
for inputfilename in inputfilenames:
|
for inputfilename in inputfilenames:
|
||||||
parse_file_to_book(open(inputfilename, 'r'), book)
|
parse_file_to_book(open(inputfilename, 'r'), book)
|
||||||
output_format.write(book, open(outputfilename, 'w'))
|
output_format.write(book, open(outputfilename, 'w'))
|
||||||
|
@ -69,7 +69,7 @@ def parse_file_to_book(inputfile, book):
|
||||||
for line in inputfile.readlines():
|
for line in inputfile.readlines():
|
||||||
if line.startswith('*'):
|
if line.startswith('*'):
|
||||||
if name:
|
if name:
|
||||||
book.add(paragraphs.Paragraph(name, text), number)
|
book.add(sections.Section(name, text), number)
|
||||||
number = None
|
number = None
|
||||||
text = ""
|
text = ""
|
||||||
heading = line[1:].strip().split(' ')
|
heading = line[1:].strip().split(' ')
|
||||||
|
@ -79,11 +79,11 @@ def parse_file_to_book(inputfile, book):
|
||||||
number = int(heading[0])
|
number = int(heading[0])
|
||||||
name = heading[1]
|
name = heading[1]
|
||||||
else:
|
else:
|
||||||
raise Exception("bad paragraph heading %s" % str(heading))
|
raise Exception("bad section heading %s" % str(heading))
|
||||||
else:
|
else:
|
||||||
text = text + " " + line.strip()
|
text = text + " " + line.strip()
|
||||||
if name:
|
if name:
|
||||||
book.add(paragraphs.Paragraph(name, text), number)
|
book.add(sections.Section(name, text), number)
|
||||||
|
|
||||||
def find_output_format(outputfilename):
|
def find_output_format(outputfilename):
|
||||||
for of in OUTPUT_FORMATS:
|
for of in OUTPUT_FORMATS:
|
||||||
|
|
34
output.py
34
output.py
|
@ -13,7 +13,7 @@ class OutputFormat (object):
|
||||||
|
|
||||||
def write(self, book, output):
|
def write(self, book, output):
|
||||||
self.write_begin(book, output)
|
self.write_begin(book, output)
|
||||||
self.write_shuffled_paragraphs(book.shuffle(), output)
|
self.write_shuffled_sections(book.shuffle(), output)
|
||||||
self.write_end(book, output)
|
self.write_end(book, output)
|
||||||
|
|
||||||
def write_begin(self, book, output):
|
def write_begin(self, book, output):
|
||||||
|
@ -21,17 +21,17 @@ class OutputFormat (object):
|
||||||
'max' : book.max
|
'max' : book.max
|
||||||
},
|
},
|
||||||
|
|
||||||
def write_shuffled_paragraphs(self, shuffled_paragraphs, output):
|
def write_shuffled_sections(self, shuffled_sections, output):
|
||||||
for p in shuffled_paragraphs.as_list[1:]:
|
for p in shuffled_sections.as_list[1:]:
|
||||||
self.write_paragraph(p, shuffled_paragraphs, output)
|
self.write_section(p, shuffled_sections, output)
|
||||||
|
|
||||||
def write_paragraph(self, paragraph, shuffled_paragraphs, output):
|
def write_section(self, section, shuffled_sections, output):
|
||||||
refs = []
|
refs = []
|
||||||
refsdict = ReferenceFormatter(paragraph, shuffled_paragraphs,
|
refsdict = ReferenceFormatter(section, shuffled_sections,
|
||||||
self.load_template("paragraph_ref"))
|
self.load_template("section_ref"))
|
||||||
formatted_text = paragraph.format(refsdict)
|
formatted_text = section.format(refsdict)
|
||||||
print >> output, self.load_template("paragraph") % {
|
print >> output, self.load_template("section") % {
|
||||||
'nr' : shuffled_paragraphs.to_nr[paragraph],
|
'nr' : shuffled_sections.to_nr[section],
|
||||||
'text' : formatted_text,
|
'text' : formatted_text,
|
||||||
'refs' : '\n'.join(refsdict.getfound()) # hack for DOT output
|
'refs' : '\n'.join(refsdict.getfound()) # hack for DOT output
|
||||||
},
|
},
|
||||||
|
@ -58,19 +58,19 @@ class OutputFormat (object):
|
||||||
|
|
||||||
class ReferenceFormatter (object):
|
class ReferenceFormatter (object):
|
||||||
"There is probably a better way, but this hack seems to work."
|
"There is probably a better way, but this hack seems to work."
|
||||||
def __init__(self, paragraph, shuffled_paragraphs, ref_template):
|
def __init__(self, section, shuffled_sections, ref_template):
|
||||||
self.paragraph = paragraph
|
self.section = section
|
||||||
self.shuffled_paragraphs = shuffled_paragraphs
|
self.shuffled_sections = shuffled_sections
|
||||||
self.found = set()
|
self.found = set()
|
||||||
self.ref_template = ref_template
|
self.ref_template = ref_template
|
||||||
|
|
||||||
def __getitem__(self, key):
|
def __getitem__(self, key):
|
||||||
to_paragraph = self.shuffled_paragraphs.from_name[key]
|
to_section = self.shuffled_sections.from_name[key]
|
||||||
res = self.ref_template % {
|
res = self.ref_template % {
|
||||||
'nr' : self.shuffled_paragraphs.to_nr[to_paragraph],
|
'nr' : self.shuffled_sections.to_nr[to_section],
|
||||||
'from_nr' : self.shuffled_paragraphs.to_nr[self.paragraph]
|
'from_nr' : self.shuffled_sections.to_nr[self.section]
|
||||||
}
|
}
|
||||||
if key in self.shuffled_paragraphs.name_to_nr:
|
if key in self.shuffled_sections.name_to_nr:
|
||||||
self.found.add(res)
|
self.found.add(res)
|
||||||
return res
|
return res
|
||||||
|
|
||||||
|
|
|
@ -1,61 +0,0 @@
|
||||||
import random
|
|
||||||
import sys
|
|
||||||
|
|
||||||
class Paragraph:
|
|
||||||
def __init__(self, name, text):
|
|
||||||
self.name = name
|
|
||||||
self.text = text
|
|
||||||
|
|
||||||
def __repr__(self):
|
|
||||||
return "Paragraph(%s, %s)" % (repr(self.name), repr(self.text))
|
|
||||||
|
|
||||||
def format(self, references):
|
|
||||||
return self.text % references
|
|
||||||
|
|
||||||
class ShuffledParagraphs:
|
|
||||||
def __init__(self, as_list, from_nr, to_nr, from_name):
|
|
||||||
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]]
|
|
||||||
|
|
||||||
class Book:
|
|
||||||
def __init__(self):
|
|
||||||
self.paragraphs = []
|
|
||||||
self.nr_paragraphs = {}
|
|
||||||
self.max = 0
|
|
||||||
|
|
||||||
def add(self, paragraph, nr=None):
|
|
||||||
self.paragraphs.append(paragraph)
|
|
||||||
if len(self.paragraphs) > self.max:
|
|
||||||
self.max = len(self.paragraphs)
|
|
||||||
if nr:
|
|
||||||
self.nr_paragraphs[nr] = paragraph
|
|
||||||
if nr > self.max:
|
|
||||||
self.max = nr
|
|
||||||
|
|
||||||
def shuffle(self):
|
|
||||||
as_list = [None]
|
|
||||||
from_nr = {}
|
|
||||||
to_nr = {}
|
|
||||||
from_name = {}
|
|
||||||
shuffled = self.paragraphs[:]
|
|
||||||
for p in self.nr_paragraphs.values():
|
|
||||||
shuffled.remove(p)
|
|
||||||
random.shuffle(shuffled)
|
|
||||||
for nr in range(1, self.max + 1):
|
|
||||||
if self.nr_paragraphs.has_key(nr):
|
|
||||||
paragraph = self.nr_paragraphs[nr]
|
|
||||||
elif len(shuffled):
|
|
||||||
paragraph = shuffled.pop()
|
|
||||||
else:
|
|
||||||
paragraph = None
|
|
||||||
as_list.append(paragraph)
|
|
||||||
from_nr[nr] = paragraph
|
|
||||||
if paragraph:
|
|
||||||
to_nr[paragraph] = nr
|
|
||||||
from_name[paragraph.name] = paragraph
|
|
||||||
return ShuffledParagraphs(as_list, from_nr, to_nr, from_name)
|
|
|
@ -9,7 +9,7 @@ gamebook on paper or a screen (or for debugging it).
|
||||||
|------------------+-----------+-------------------------------------------------------------------------------------------------|
|
|------------------+-----------+-------------------------------------------------------------------------------------------------|
|
||||||
| LaTeX | .tex | Useful to generate PDFs using pdflatex or whatever LaTeX tools you prefer. |
|
| LaTeX | .tex | Useful to generate PDFs using pdflatex or whatever LaTeX tools you prefer. |
|
||||||
| Rich Text Format | .rtf | Supported because the Windhammer Prize requires it. |
|
| Rich Text Format | .rtf | Supported because the Windhammer Prize requires it. |
|
||||||
| Graphviz DOT | .dot | Use with the Graphviz dot tool to generate a flowchart graph of all paragraphs in the gamebook. |
|
| Graphviz DOT | .dot | Use with the Graphviz dot tool to generate a flowchart graph of all sections in the gamebook. |
|
||||||
| HTML | .html | Play gamebook in browser. |
|
| HTML | .html | Play gamebook in browser. |
|
||||||
| Debug Plain Text | .debug | Plain text debug output of gamebook contents. |
|
| Debug Plain Text | .debug | Plain text debug output of gamebook contents. |
|
||||||
|
|
||||||
|
@ -18,7 +18,7 @@ More to be added.
|
||||||
** Gamebook Format
|
** Gamebook Format
|
||||||
|
|
||||||
The input file expected by the formatgamebook.py script must be in a
|
The input file expected by the formatgamebook.py script must be in a
|
||||||
format containing information about all paragraphs in the book
|
format containing information about all sections in the book
|
||||||
plus some optional metadata. The format should (when TBD) be documented
|
plus some optional metadata. The format should (when TBD) be documented
|
||||||
here, but it is not expected that most users would ever have to look
|
here, but it is not expected that most users would ever have to look
|
||||||
at the gamebook file, but rather use a higher level format or a
|
at the gamebook file, but rather use a higher level format or a
|
||||||
|
|
61
sections.py
Normal file
61
sections.py
Normal file
|
@ -0,0 +1,61 @@
|
||||||
|
import random
|
||||||
|
import sys
|
||||||
|
|
||||||
|
class Section:
|
||||||
|
def __init__(self, name, text):
|
||||||
|
self.name = name
|
||||||
|
self.text = text
|
||||||
|
|
||||||
|
def __repr__(self):
|
||||||
|
return "Section(%s, %s)" % (repr(self.name), repr(self.text))
|
||||||
|
|
||||||
|
def format(self, references):
|
||||||
|
return self.text % references
|
||||||
|
|
||||||
|
class ShuffledSections:
|
||||||
|
def __init__(self, as_list, from_nr, to_nr, from_name):
|
||||||
|
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]]
|
||||||
|
|
||||||
|
class Book:
|
||||||
|
def __init__(self):
|
||||||
|
self.sections = []
|
||||||
|
self.nr_sections = {}
|
||||||
|
self.max = 0
|
||||||
|
|
||||||
|
def add(self, section, nr=None):
|
||||||
|
self.sections.append(section)
|
||||||
|
if len(self.sections) > self.max:
|
||||||
|
self.max = len(self.sections)
|
||||||
|
if nr:
|
||||||
|
self.nr_sections[nr] = section
|
||||||
|
if nr > self.max:
|
||||||
|
self.max = nr
|
||||||
|
|
||||||
|
def shuffle(self):
|
||||||
|
as_list = [None]
|
||||||
|
from_nr = {}
|
||||||
|
to_nr = {}
|
||||||
|
from_name = {}
|
||||||
|
shuffled = self.sections[:]
|
||||||
|
for p in self.nr_sections.values():
|
||||||
|
shuffled.remove(p)
|
||||||
|
random.shuffle(shuffled)
|
||||||
|
for nr in range(1, self.max + 1):
|
||||||
|
if self.nr_sections.has_key(nr):
|
||||||
|
section = self.nr_sections[nr]
|
||||||
|
elif len(shuffled):
|
||||||
|
section = shuffled.pop()
|
||||||
|
else:
|
||||||
|
section = None
|
||||||
|
as_list.append(section)
|
||||||
|
from_nr[nr] = section
|
||||||
|
if section:
|
||||||
|
to_nr[section] = nr
|
||||||
|
from_name[section.name] = section
|
||||||
|
return ShuffledSections(as_list, from_nr, to_nr, from_name)
|
|
@ -1,2 +1,2 @@
|
||||||
BEGIN DEBUG OUTPUT
|
BEGIN DEBUG OUTPUT
|
||||||
Number of paragraphs: %(max)d
|
Number of sections: %(max)d
|
||||||
|
|
|
@ -1,12 +1,12 @@
|
||||||
*1 start
|
*1 start
|
||||||
This is where the adventure begins. You can go on to the
|
This is where the adventure begins. You can go on to the
|
||||||
next paragraph, see %(next)s or try the other instead, see %(other)s.
|
next section, see %(next)s or try the other instead, see %(other)s.
|
||||||
|
|
||||||
*next
|
*next
|
||||||
This is the next paragraph. Go on to the end at %(end)s.
|
This is the next section. Go on to the end at %(end)s.
|
||||||
|
|
||||||
*other
|
*other
|
||||||
This is another paragraph. You can try the next paragraph now,
|
This is another section. You can try the next section now,
|
||||||
see %(next)s, or go on to the end, see %(end)s.
|
see %(next)s, or go on to the end, see %(end)s.
|
||||||
|
|
||||||
*end
|
*end
|
||||||
|
|
|
@ -1,76 +0,0 @@
|
||||||
#!/usr/bin/env python2.5
|
|
||||||
|
|
||||||
import unittest
|
|
||||||
from unittest import TestCase
|
|
||||||
|
|
||||||
import paragraphs
|
|
||||||
|
|
||||||
class TestParagraph(TestCase):
|
|
||||||
def setUp(self):
|
|
||||||
pass
|
|
||||||
|
|
||||||
def test_create(self):
|
|
||||||
p = paragraphs.Paragraph("foo")
|
|
||||||
self.assertEqual(p.name, "foo")
|
|
||||||
|
|
||||||
class TestBook(TestCase):
|
|
||||||
def setUp(self):
|
|
||||||
pass
|
|
||||||
|
|
||||||
def test_create(self):
|
|
||||||
g = paragraphs.Book()
|
|
||||||
self.assertEqual(g.paragraphs, [])
|
|
||||||
self.assertEqual(g.nr_paragraphs, {})
|
|
||||||
self.assertEqual(g.max, 0)
|
|
||||||
|
|
||||||
def test_old_big_mess(self):
|
|
||||||
"""This was tested using print statements in the old
|
|
||||||
paragraphs __main__. Not pretty. Keeping it here anyway
|
|
||||||
as long as it doesn't cause too many problems to update."""
|
|
||||||
from paragraphs import paragraph_refs_format
|
|
||||||
g = paragraphs.Book()
|
|
||||||
c = paragraphs.Paragraph("c", "aaac")
|
|
||||||
g.add(paragraphs.Paragraph("a", "aaa"))
|
|
||||||
g.add(paragraphs.Paragraph("b", "aaab"))
|
|
||||||
g.add(c)
|
|
||||||
g.add(paragraphs.Paragraph("d", "aaad"), 22)
|
|
||||||
g.add(paragraphs.Paragraph("e", "aaae"), 1)
|
|
||||||
g.add(paragraphs.Paragraph("f", "aaaf",
|
|
||||||
[paragraphs.ParagraphItem("fff")]))
|
|
||||||
g.add(paragraphs.Paragraph("g", "aaag",
|
|
||||||
[paragraphs.ParagraphItem("ggg", "G")]))
|
|
||||||
m = paragraphs.Paragraph("m")
|
|
||||||
m.addtext("m")
|
|
||||||
m.addtext("t")
|
|
||||||
g.add(m)
|
|
||||||
shuffled = g.shuffle()
|
|
||||||
|
|
||||||
self.assertEqual(len(shuffled.as_list), 23)
|
|
||||||
self.assertEqual(paragraph_refs_format('abc', []), 'abc')
|
|
||||||
self.assertEqual(paragraph_refs_format('abc%%z', []), 'abc%z')
|
|
||||||
self.assertEqual(paragraph_refs_format(
|
|
||||||
'abc%sx',
|
|
||||||
[paragraphs.Paragraph("p1", "111")]),
|
|
||||||
'abcp1x')
|
|
||||||
self.assertEqual(paragraph_refs_format(
|
|
||||||
'abc%ry', [paragraphs.Paragraph("p2", "222")]),
|
|
||||||
"abc'p2'y")
|
|
||||||
self.assertEqual(paragraph_refs_format('%%a%nbc%su', ["f", c],
|
|
||||||
shuffled),
|
|
||||||
'%%a%dbccu' % shuffled.name_to_nr["f"])
|
|
||||||
self.assertEqual(paragraph_refs_format('abc%nu', ["c"], shuffled),
|
|
||||||
'abc%du' % shuffled.name_to_nr["c"])
|
|
||||||
self.assertEqual(paragraph_refs_format('%s', [m]),
|
|
||||||
'm')
|
|
||||||
self.assertEqual(m.text, 'mt')
|
|
||||||
|
|
||||||
def test_name_replace(self):
|
|
||||||
game = paragraphs.Book()
|
|
||||||
game.add(paragraphs.Paragraph('foo'))
|
|
||||||
shuffled = game.shuffle()
|
|
||||||
self.assertEqual(
|
|
||||||
'a1b',
|
|
||||||
paragraphs.paragraph_refs_format('a%(foo)nb', [], shuffled))
|
|
||||||
|
|
||||||
if __name__ == '__main__':
|
|
||||||
unittest.main()
|
|
76
test_sections.py
Executable file
76
test_sections.py
Executable file
|
@ -0,0 +1,76 @@
|
||||||
|
#!/usr/bin/env python2.5
|
||||||
|
|
||||||
|
import unittest
|
||||||
|
from unittest import TestCase
|
||||||
|
|
||||||
|
import sections
|
||||||
|
|
||||||
|
class TestSection(TestCase):
|
||||||
|
def setUp(self):
|
||||||
|
pass
|
||||||
|
|
||||||
|
def test_create(self):
|
||||||
|
p = sections.Section("foo")
|
||||||
|
self.assertEqual(p.name, "foo")
|
||||||
|
|
||||||
|
class TestBook(TestCase):
|
||||||
|
def setUp(self):
|
||||||
|
pass
|
||||||
|
|
||||||
|
def test_create(self):
|
||||||
|
g = sections.Book()
|
||||||
|
self.assertEqual(g.sections, [])
|
||||||
|
self.assertEqual(g.nr_sections, {})
|
||||||
|
self.assertEqual(g.max, 0)
|
||||||
|
|
||||||
|
def test_old_big_mess(self):
|
||||||
|
"""This was tested using print statements in the old
|
||||||
|
sections __main__. Not pretty. Keeping it here anyway
|
||||||
|
as long as it doesn't cause too many problems to update."""
|
||||||
|
from sections import section_refs_format
|
||||||
|
g = sections.Book()
|
||||||
|
c = sections.Section("c", "aaac")
|
||||||
|
g.add(sections.Section("a", "aaa"))
|
||||||
|
g.add(sections.Section("b", "aaab"))
|
||||||
|
g.add(c)
|
||||||
|
g.add(sections.Section("d", "aaad"), 22)
|
||||||
|
g.add(sections.Section("e", "aaae"), 1)
|
||||||
|
g.add(sections.Section("f", "aaaf",
|
||||||
|
[sections.SectionItem("fff")]))
|
||||||
|
g.add(sections.Section("g", "aaag",
|
||||||
|
[sections.SectionItem("ggg", "G")]))
|
||||||
|
m = sections.Section("m")
|
||||||
|
m.addtext("m")
|
||||||
|
m.addtext("t")
|
||||||
|
g.add(m)
|
||||||
|
shuffled = g.shuffle()
|
||||||
|
|
||||||
|
self.assertEqual(len(shuffled.as_list), 23)
|
||||||
|
self.assertEqual(section_refs_format('abc', []), 'abc')
|
||||||
|
self.assertEqual(section_refs_format('abc%%z', []), 'abc%z')
|
||||||
|
self.assertEqual(section_refs_format(
|
||||||
|
'abc%sx',
|
||||||
|
[sections.Section("p1", "111")]),
|
||||||
|
'abcp1x')
|
||||||
|
self.assertEqual(section_refs_format(
|
||||||
|
'abc%ry', [sections.Section("p2", "222")]),
|
||||||
|
"abc'p2'y")
|
||||||
|
self.assertEqual(section_refs_format('%%a%nbc%su', ["f", c],
|
||||||
|
shuffled),
|
||||||
|
'%%a%dbccu' % shuffled.name_to_nr["f"])
|
||||||
|
self.assertEqual(section_refs_format('abc%nu', ["c"], shuffled),
|
||||||
|
'abc%du' % shuffled.name_to_nr["c"])
|
||||||
|
self.assertEqual(section_refs_format('%s', [m]),
|
||||||
|
'm')
|
||||||
|
self.assertEqual(m.text, 'mt')
|
||||||
|
|
||||||
|
def test_name_replace(self):
|
||||||
|
game = sections.Book()
|
||||||
|
game.add(sections.Section('foo'))
|
||||||
|
shuffled = game.shuffle()
|
||||||
|
self.assertEqual(
|
||||||
|
'a1b',
|
||||||
|
sections.section_refs_format('a%(foo)nb', [], shuffled))
|
||||||
|
|
||||||
|
if __name__ == '__main__':
|
||||||
|
unittest.main()
|
13
todo.org
13
todo.org
|
@ -4,20 +4,19 @@
|
||||||
- [X] LaTeX output
|
- [X] LaTeX output
|
||||||
- [X] RTF output
|
- [X] RTF output
|
||||||
- [X] HTML output
|
- [X] HTML output
|
||||||
- [ ] Save paragraph-number mapping and reuse automatically
|
- [ ] Save section-number mapping and reuse automatically
|
||||||
- [ ] Add support for custom begin/end document templates.
|
- [ ] Add support for custom document templates.
|
||||||
Fixed names and/or command-line options.
|
Fixed names and/or command-line options.
|
||||||
- [ ] Add paragraph links in LaTeX output.
|
- [ ] Add section links in LaTeX output.
|
||||||
- [ ] Debug HTML output
|
- [ ] Debug HTML output
|
||||||
- [ ] Inventory (take, drop, check)
|
- [ ] Inventory (take, drop, check)
|
||||||
- [ ] Codewords/Sightings (set, check, clean)
|
- [ ] Codewords/Sightings (set, check, clean)
|
||||||
- [ ] Skill checks? Or is this higher level? No?
|
- [ ] More formatting possibilities in sections
|
||||||
- [ ] More formatting possibilities in paragraphs
|
|
||||||
Look at existing gamebooks to get ideas.
|
Look at existing gamebooks to get ideas.
|
||||||
- [ ] Prettier LaTeX output
|
- [ ] Prettier LaTeX output
|
||||||
Look at how some existing gamebooks are formatted.
|
Look at how some existing gamebooks are formatted.
|
||||||
- [ ] Command-line flag to set max paragraph number to use
|
- [ ] Command-line flag to set max section number to use
|
||||||
- [ ] Dummy paragraphs
|
- [ ] Dummy sections
|
||||||
- [ ] Combat? Or is this higher level?
|
- [ ] Combat? Or is this higher level?
|
||||||
- [ ] Document Gamebook JSON format.
|
- [ ] Document Gamebook JSON format.
|
||||||
- [ ] Higher level text-language for Gamebooks
|
- [ ] Higher level text-language for Gamebooks
|
||||||
|
|
Loading…
Reference in a new issue