Imagination Helper

… sounds like some kind of weird meal preparation product.

I haven’t completely stalled on #lore24, but it’s close. I started looking at my random table resolver, and got sidetracked.

For a command line tool I wrote more than 25 years ago — in the late 1900s — it does a pretty decent job. However, I see a few things I’d do differently now. Probably.

  • First, I’d probably reimplement in a scripting language, rather than in C++. I’m leaning toward Python, partly to get more practice with the language, but also because I’m thinking of moving my sites from WordPress to Django. Python clearly will integrate more easily with Django than other languages.
  • Second, I’d replace the file format. The current format for the tables is very much a declarative format inspired by a ‘BNF’ program I stumbled on in 1994. I’m leaning toward JSON, which literally wasn’t a thing when I wrote this but is eminently suitable for my purpose. Also, is trivially usable in many languages.
    • The hierarchical structure and multiple types makes it easy for me to add facilities that really were feasible to me (or at least, more trouble than I cared to deal with) when I first wrote this tool
  • Third, change the content syntax. Text will still be text, but I might change how some aspects are formatted. For instance,
    • Old code, tables were invoked as &tablename, and functions as @functionname.
    • New code, I might get rid of the prefixes and just use the raw name: TableName{} and functionName{} respectively, with the braces indicating that this is calling a thing and a convention of ‘tables start with uppercase and functions with lowercase’. I think this will be more readable. I expect to still use braces to mark ‘parameter lists’, partly because I use LaTeX so much for publishing but also because parentheses are legitimate text.
    • Old code, rolls were indicated by %: “%{2d6}” would roll 2d6 and output the result.
    • New code, could treat the % as implied in this case.
    • Old code used backticks to ‘escape’ code in the text so it would be run but not presented. For instance, `=gp{%{2d6}}` would assign the result of 2d6 to a variable named ‘gp’, without presenting it in the output. I could then use the value of $gp in other formulas or formatting: “you find $gp gold @plural{piece}{$gp}”. I’m strongly considering allowing a ‘code’ block in each result that does the various assignments like this, to later be consumed in the ‘content’ block.
    • All of the content syntax changes above are more or less off the top of my head. I might decide to do something else as I get to it and see what it’s like when I use it.
    • Also, I’ve been reading the syntax used by Chartopia, and might choose to do something consistent with their syntax.
  • Fourth, give thought to multi-column tables. My original approach allowed only single-column tables, which was sufficient for purpose at the time.
    • The treasury-of-tables that is Tome of Adventure Design has multi-column tables, but most of the multi-column tables are reasonably modeled as groups of single-column tables. For instance, Table 1-1a: Locations consists of four columns, each of which is rolled independently of the other three to give you one of 100,000,000 possible outcomes. Because they are all thematically and purposefully grouped they’re in one table, but it’s totally reasonable to model them as independent tables that happen to be used together.
    • There is a smaller number of multi-column tables in Tome of Adventure Design that behave more like the wondrous item tables in the DMG (of whatever edition): range column showing what die roll values apply to the row, the actual content, and then ‘supplementary information’ such as how to interpret the actual content or the wondrous item market price.
    • D&D 3.x DMG has at least one table (random magic items) with multiple range columns: roll d% and compare to the range column for minor/moderate/major items, then find the result in the result column. I feel these situations are infrequent enough they might be better handled by splitting them into multiple tables: what makes sense for publishing does not necessarily make sense for data modeling.
    • Multi-value lookup tables such as a ‘nobility rank’ table showing what different noble ranks might be called in different cultures. For instance, in a game with 11 ranks from ‘0’ to ’10’ you might see ‘serf’ in ‘row 0’ of two columns, but ‘king’ and ‘roi’ in the English and French columns respectively. This totally makes sense (as much as feudal ranks make sense) for presentation in a book, but again could be reasonably modeled as multiple tables.
    • I don’t think I’ve found multicolumn tables that don’t fit into one of the three cases above. However, I can think of three relatively generic uses.
      • Plural tables: first result column is singular, second result column is plural (and if empty, follows normal rules for pluralization). That is, you might see (‘cat’,”) because the plural of ‘cat’ is ‘cats’ (easy one!), but (‘man’,’men’) and (‘deer’,’deer’) because they are nonstandard pluralizations. I would think for this to work it would be necessary to indicate how many objects are involved… or it could be a more generic lookup table used by the plural{} function.
      • Gender tables: first result column is agender, second result column is female, third result is male (mostly, I grant, because like it or not most gendered nouns use the same text for male and agender). A blank entry in ‘female’ and ‘male’ columns indicates you use the agender version. Thus, you might see (‘actor’,’actress’,”) because ‘actress’ is used only for female actors but ‘actor’ is used for males and when the gender is unknown (or in group). On the other hand, you’d see (‘doctor’,”,”) because we don’t have ‘doctrice’: everyone is a ‘doctor’.
      • Lookup tables: as with the rank tables above, it might be helpful to be able to have a single table containing multiple columns for lookups, then index the column respond from. That is, Rank{$rank}{$cultureIndex} would find the column that matches $cultureIndex and return the value in the row indicated by $rank. I don’t know if this is better or worse than using multiple single-column tables and deciding through other means, or if it’s a wash.

(This post is mostly so I don’t lose my thoughts on the topic, it’s all subject to change.)


  1. Tom H.

    This sounds cool, and tempts me to consider something similar myself for a future project.

    If I can make one critical comment: JSON is easy to read / write by a program, but hard to read / write by a human. If you intend to edit your files directly, instead of building a tool with a UI to do it for you, you might want to consider other options.

    (I don’t know that there are any good ones, but this is a mistake that a former employer made that cost surprisingly many person-years: replacing a human-friendly format with JSON, then rewriting the JSON format to be a worse match to the humans’ mental model because it made better programming sense.)

    Reading over your planned syntax, maybe I’m misunderstanding? It’s not clear to me how that’d be JSONic.

    • You’re not wrong, but… my background is in programming. I write a lot of code, and one of my primary projects uses XSLT heavily, and before that DSSSL (i.e. Schema, i.e. LISP). JSON is child’s play in comparison that.

      That said, I can easily imagine using JSON as my storage format and using something other than a text editor for managing it. One possibility could be to build a new program (not my first choice, if I can reasonably use something else).

      Another, more likely possibility, would be to use Word or Excel, and extract the table definitions from there. Excel is an obvious choice (one table per tab, etc.) but Word has some other benefits that make it attractive to me. I’ve spent a lot of time extracting content from Office files programmatically, this gives me powerful text editing and not-hard data extraction, to package into JSON for consumption by a more specialized tool.

      Then it’s just a matter of encoding the special bits (calls to other tables, etc.) as above. I don’t readily see a way to fix that… though I suppose if I use Word, creating a ‘callTable’ or ‘callFunction’ style could do it. To be considered, I suppose.

Leave a Reply

Your email address will not be published. Required fields are marked *

This site uses Akismet to reduce spam. Learn how your comment data is processed.

Back to Top