Random table roller is getting weirdly powerful, and I’m loving that.
With the recent changes I now have the ability to manipulate table entries.
Hmm… I haven’t touched on modifying an entry, or inserting in arbitrary locations. Maybe later.
Anyway, what I do now have is the ability to treat a ‘table’ something like a deck of cards. That is, so each entry can be selected no more than one time.
This gives me the ability to connect this to one of my favorite project: Polyhedral Pantheons.
To whit:
- Randomly select domains and append them to a table in order of selection. When a domain is chosen, remove it from the list of domains available. Continue until gone. (I could be clever and select only as many as needed, but eh, can’t be bothered, ‘shuffle all’ is simple.)
- Choose a pantheon polyhedron (d4, d6, d8, d8 alt, d10, d12, d20) and connect it to a more convenient table. Easier than doing a lookup each time. This table has an entry for each deity, and list of domain look ups for that site on the polyhedron.
- For each deity (I can iterate over tables! I didn’t know until recently that I can! … but the facility has been there since 1998)
- Generate a name and epithet (using an existing dictionary,
toadSmallGods.dict
). - Output the list of domains for that deity (look up each domain index in the deity entry)
- Generate a name and epithet (using an existing dictionary,
What does this look like in code?
Input Dictionary
!PolypanDefault
?toadSmallGods.dict
&PolypanDefault
|1 &polypanInit\
&polypanPick\
&polypanDump
&&polypanInit
|1 `@resetTable{ppDomainIndexes}`\
`=i{1}`\
@iter{@addResolved{ppDomainIndexes}{1}{$i}}{@weight{ppDomainList}}{`=i{$i+1}`}\
@for{}{%{@weight{ppDomainIndexes}}}{@addResolved{ppDomains}{1}{&ppDomainIndexes}@removeEntry{ppDomainIndexes}{$ppDomainIndexes}}
&&polypanPick
|1 Generating d4 Pantheon:\n\n`@replaceTable{polypan}{polypanD4}`
&&polypanDump
|1 `=polypan{0}`@iter{%{$polypan+1}\t&toadSmallGod\n\tDomains: &polypan{$polypan+1}}{@weight{polypan}}{\n\n}\n
&&polypan
&&polypanD4
|1 &ppDomainList{&ppDomains{1}}, &ppDomainList{&ppDomains{5}}, ...
|1 &ppDomainList{&ppDomains{2}}, &ppDomainList{&ppDomains{5}}, ...
|1 &ppDomainList{&ppDomains{3}}, &ppDomainList{&ppDomains{5}}, ...
|1 &ppDomainList{&ppDomains{4}}, &ppDomainList{&ppDomains{6}}, ...
|1 &ppDomainList{&ppDomains{5}}, &ppDomainList{&ppDomains{1}}, ...
|1 &ppDomainList{&ppDomains{6}}, &ppDomainList{&ppDomains{1}}, ...
|1 &ppDomainList{&ppDomains{7}}, &ppDomainList{&ppDomains{1}}, ...
|1 &ppDomainList{&ppDomains{8}}, &ppDomainList{&ppDomains{2}}, ...
&&ppDomainIndexes
&&ppDomainList
|1 Air
|1 Animal
|1 Artifice
|1 Chaos
|1 Charm
# ... etc
Breaking Down the Code
Taken from the top, I see
!PolypanDefault
Call the PolypanDefault
table, if no table specified on input.
?toadSmallGods.dict
Import file for names and epithets.
&PolypanDefault
|1 &polypanInit\
&polypanPick\
&polypanDump
Default is to initialize the pantheon generator (shuffle and select domains), pick a polyhedron, then dump the output.
&&polypanInit
|1 `@resetTable{ppDomainIndexes}`\
`=i{1}`\
@iter{@addResolved{ppDomainIndexes}{1}{$i}}{@weight{ppDomainList}}{`=i{$i+1}`}\
@for{}{%{@weight{ppDomainIndexes}}}{@addResolved{ppDomains}{1}{&ppDomainIndexes}@removeEntry{ppDomainIndexes}{$ppDomainIndexes}}
This is busier. [Hidden table, does not show up in ‘usage’.]
- Reset the
ppDomainIndexes
table. - Repopulate
ppDomainIndexes
based on size ofppDomainList
(originally hard codedppDomainIndexes
). - Untl
ppDomainIndexes
is empty, grab an entry and append it toppDomains
, then remove fromppDomainIndexes
.
&&polypanPick
|1 Generating d4 Pantheon:\n\n`@replaceTable{polypan}{polypanD4}`
Pick a polyhedron template. Hard coded to a single entry in this example, the full file ranges from d4 to d20. [Hidden table, does not show up in ‘usage’.]
&&polypanDump
|1 `=polypan{0}`@iter{%{$polypan+1}\t&toadSmallGod\n\tDomains: &polypan{$polypan+1}}{@weight{polypan}}{\n\n}\n
For each deity in polypan
(as established in polypanPick
), generate a name and output that deity’s domains. [Hidden table, does not show up in ‘usage’.]
&&polypanD4
|1 &ppDomainList{&ppDomains{1}}, &ppDomainList{&ppDomains{5}}, ...
|1 &ppDomainList{&ppDomains{2}}, &ppDomainList{&ppDomains{5}}, ...
|1 &ppDomainList{&ppDomains{3}}, &ppDomainList{&ppDomains{5}}, ...
|1 &ppDomainList{&ppDomains{4}}, &ppDomainList{&ppDomains{6}}, ...
|1 &ppDomainList{&ppDomains{5}}, &ppDomainList{&ppDomains{1}}, ...
|1 &ppDomainList{&ppDomains{6}}, &ppDomainList{&ppDomains{1}}, ...
|1 &ppDomainList{&ppDomains{7}}, &ppDomainList{&ppDomains{1}}, ...
|1 &ppDomainList{&ppDomains{8}}, &ppDomainList{&ppDomains{2}}, ...
Output the names of the deity’s domains. I’ve abbreviated the lists for clarity, so they look okay on the screen. The full mappings are in the dictionary for all deities of all pantheon shapes. [Hidden table, does not show up in ‘usage’.]
&&ppDomainIndexes
Placeholder to have the domain indexes as they’re selected. Originally this was hard coded, but that would need me to maintain it as new domains are added. [Hidden table, does not show up in ‘usage’.]
&&ppDomainList
|1 Air
|1 Animal
|1 Artifice
|1 Chaos
|1 Charm
# ... etc
List of domains, abbreviated. [Hidden table, does not show up in ‘usage’.]
Okay, yeah, that’s great. But what’s it do?
Output
Gives me output like this.
1 Phask, Hunter of Mercy
Domains: Death, Destruction, Sun, Luck
2 Thul, Angel who Slithers in the Night
Domains: Knowledge, Destruction, Sun, Protection
3 Zyr-Paron, Messenger of Nightmares
Domains: Fire, Destruction, Luck, Luck
4 Ishttalaa-at, Slayer of the Abyss
Domains: Trickery, Sun, Luck, Protection
5 Questron, Queen of Destiny
Domains: Destruction, Death, Knowledge, Fire
6 Lotul, Servant of Fear
Domains: Sun, Death, Knowledge, Trickery
7 Broth, Queen of Bitterness
Domains: Luck, Death, Fire, Trickery
8 Kirza, Judge of Memory
Domains: Protection, Knowledge, Fire, Trickery
This is equivalent to this clip from the Polyhedral Pantheons workbook… though with added names and epithets.
Site | Primary | Secondary Domain List | Secondary | Secondary | Secondary |
---|---|---|---|---|---|
1 | Death | Destruction, Sun, Luck | Destruction | Sun | Luck |
2 | Knowledge | Destruction, Sun, Protection | Destruction | Sun | Protection |
3 | Fire | Destruction, Luck, Protection | Destruction | Luck | Protection |
4 | Trickery | Sun, Luck, Protection | Sun | Luck | Protection |
A | Destruction | Death, Knowledge, Fire | Death | Knowledge | Fire |
B | Sun | Death, Knowledge, Trickery | Death | Knowledge | Trickery |
C | Luck | Death, Fire, Trickery | Death | Fire | Trickery |
D | Protection | Knowledge, Fire, Trickery | Knowledge | Fire | Trickery |
What’s Next?
This little exercise proved the random table roller can do it. I have a working proof of concept.
It needs to be refactored, though. This would be a pain to apply across all the trappings.
Instead, I think I will…
- Replace the polyhedron tables with ones that have instructions to build the list of domains for each deity.
- For each deity,
- Use the previous table to build the ‘deity domain list’ table.
- For each trapping
- Reset the relevant source table.
- For each of the deity’s domains
- Append the relevant domain trapping tables to the general tables. For Phask, Hunter of Mercy , append the (Death, Destruction, Sun, Luck domains) epithet tables to the general tables.
- Generate the trapping details and store in an appropriate table.
- Revise output template.
The coding shouldn’t take all that long, actually. The domain-specific content is the real time sink.
I really don’t have a facility built in for ‘objects’, per se. I basically will need to have ‘tables’ I’m treating as arrays for the various trappings. That is, a ‘deity names’ table, and a ‘deity epithets’ table, and a ‘deity motifs’ table, and so on. The algorithm above pretty much keeps things in step. ‘Deity 4’ would be details for Ishttalaa-at, Slayer of the Abyss, across all the tables.
Closing Comments
This syntax is more convoluted than I care for, to be honest. I really should look into making this all easier.
Then again, this is almost certainly the most complex dictionary I’ve worked on, and these are new features. I can almost certainly find easier and simpler ways… but if these are facilities I rarely need, do I really need to do that?
As Larry Wall says, “make the easy things easy, and the hard things possible”. I’ll refine this later… if I need to.