Spiral Game System Prototype
2020-10-12Description
A prototype console app for designing games for the Spiral Game System.
Business Purpose
I’ve always used spreadsheets to design games. I often feel it necessary to be able to compare apples to apples on game components, especially when balance is important.
But sometimes, a spreadsheet is just not enough. On Oubliette, I pushed the limits of lookups and object-oriented data in google sheets. After that, I decided that my next data-driven game would need a more robust object system.
It took a few games and several years, but we landed on The Spiral Game System, which would be the basis for our next big phase of games.
And with SGS, I my plan for a robust data system began to see the light.
This command-line app was my first attempt to build a tool that could manipulate the kinds of data structures I had in my head for the project. It later morphed into the Spiral Game System Website, but at the time, this is what I had, and it influenced the design of SGS.
At its core, the SGS console app allows you to take a document of game elements, such as stats, items, and creatures, and perform operations on them that would change their XP values.
Structure
the SGS console app was originally envisaged as a multi-platform, single user system composed of a core SGS library, and a number of Xamarin-based frontends. The pilot frontend was a simple command-line interface for the library itself, and in the end that’s all I built before deciding to upgrade to a website.
Process
The console app was designed to run in two modes: compile or interactive. In compile mode, all options were selected on the initial call, and the app would perform its actions and compile a document for you. In interactive mode, the console app stayed open on a while loop and allowed you to perform commands on an opened SGS document.
In either mode, the program would load a document of human-readable game rule content, perform some math for each element, and write that information back to the document. In interactive mode, you could select and manipulate individual game objects, and the app would automatically refresh the UI so that you could keep track of the XP values of things and use new stats as you created them.
This was implemented as a loop of commands. Each command was composed of:
- main name, such as
add
- an array of alias, such as “add”, “a”, “+”, “new”
- A description string, which appeared in the in-app
help
command - an array of possible subcommands, which further specified the user’s intent
Each command had its own custom handler, and depending on the subcommand and parameters given, it would perform actions on the SGS document held in memory.
The advantage here was that objects could be referenced in multiple other objects, without needing to update the same object in multiple places. Change the stats on the longsword
and it would automatically populate out to knight
, veteran
, and fighter
instantly.
As the stats and objects were changed, the XP values of each affected item would automatically update.
In interactive mode, the command loop continued indefinitely until the user entered a quit
command.
Challenges
Points of Interest
Set command
The set
command allowed the user to change values on entities. Depending on the subcommand, it would set different kinds of values. Generally you would set skill, tactical stat, or primary stat.
An example of use would be
set agility d4
Which would set the active entity’s agility score to a d4.
List command
list
List all entities:
longsword 14 xp
dagger 7 xp easily hidden
flame wand 21 xp conjure flames small and large
earth staff 19 xp Manipulate dirt & earth
longbow 11 xp
mace 14 xp good against armor
fire bolt 23 xp
Fireball 28 xp
assassinate 30 xp
buckler 6 xp
kite shield 21 xp
plate armor 82 xp impressive to common folk
chainmail 48 xp
leather armor 12 xp
mage robes 30 xp impressive to the common folk
battle axe 14 xp
medicine bag 10 xp
holy symbol 7 xp
thieves tools 14 xp disarm traps & unlock doors
crossbow 23 xp
darts 4 xp easily hidden
healing spell 14 xp instant healing
invisibility spell 56 xp
Rapier 14 xp Agile & Precise
Weak Poison 5 xp Increases Damage When Applied
dragon leather armor 33 xp
Posh clothes 16 xp impressive to common folk
Meteor Swarm 98 xp
compass spell 11 xp
disguise spell 4 xp
Lesser Nature Magic 7 xp alter or create small natural aspects
Burglar's Kit 13 xp rope and climbing equipment, disarming tools and gadgets
Alchemist's Kit 13 xp bottles and tools for potionmaking, chemical testing tools
Craftsman's Kit 14 xp metalworking tools, woodworking tools
Generic Rogue 289 xp cunning and quick-witted, friends in low places
Generic Mage 273 xp wise and kindly old father figure, well versed in the ancient lore
Generic Soldier 282 xp Brave and Strong Willed, Monster Slayer
Petty Criminal 55 xp
petty criminal hero 54 xp
Criminal Thug 104 xp
Swarm of Rabble 200 xp Whole Crowd of Angry People
Epic Character 2,592 xp
Epic2 2,585 xp
Banesword 63 xp
Advanced Assasinate 122 xp
skeleton 70 xp
orc warrior 189 xp
shambler 402 xp plant camouflage
warlord 1,372 xp wily and brave, high pain tolerance
Generic dragon 5,548 xp magic-resistant hide, can fly
The list
command showed a table of all entities in the document, their XP value, and a summary of its aspects. This quickly allowed the user to get an overview.
Object Math
Object Math is a module in the SGS core library that allows the app to perform mathematical operations on dice pools. This was one of the most complex parts of the app, as it involved string parsing and some very elaborate domain-specific rules.
In roleplaying games, dice are rolled during gameplay to produce outcome numbers. On the character sheet, a string like 2d6
or 1d20+5
represents an operation, not a specific number. Therefore, adding the two together doesn’t come out to a single number, but another dice pool, 1d20+2d6+5
. The object math module covered as many of these operations as I could forsee at the time, by breaking each string up into its component parts and applying well-defined operatons to those parts.
For each operand of an operation, the system created a dictionary of die sizes (d4, d6, d8, and so on), and placed the number of dice in the value for its respective key. Another key was used for flat numerical bonuses. Dictionaries of this type were used for each of the operations. If the pools were added together, for example, the values from one dictionary would be added to the other.
In the event that the app couldn’t find a simplification for an operation (1d6 / 4
for example) the app would simply return that value as the most simplified value for the operation. When possible, it would perform the actual math and return the result.
The app provided the following operations, organized by the number of operands:
- Array
- Average
- Max
- Min
- Sum
- Binary
- Add
- Divide
- Multiply
- Subtract
- Unary
- Best: the best value of a stat by name on the entity or any of its equipment
- Integer: just a single integer value
- RealNumber: a float value
- StatRef: finds an entity’s stat value by name
With these operations and references, you could build complex formulae for generated statistics, such as adding up an entity’s toughness, size, and armor to get its overall health.
Critiques
Usability
It’s a command line app. It’s not exactly user friendly. A lot of people wouldn’t even know how to open it. Not exactly a good situation for adoption of the system.
Collaboration
Most of the time, people work on games in a group, and this had no mechanism for that. In the process of trying to solve that problem (by integrating Dropbox or Onedrive) I ended up on a research rabbit hole to investigating real-time communication web technologies, and ended up deciding that a server running a socket system would be better in the long run than a console app.
What I learned
Console App Design
Before this, the only console apps I’d worked on were utilities that did exactly one thing. This was the first time I got to write an interactive console loop, and it was actually a lot of fun. A lot simpler to deal with than all the stuff between the user and the code in something like Unity. But ultimately, only useful for niche use cases.
Prototyping is valuable
Though this app is consigned to the depths of history and a blog post, it did really help me organize how I wanted SGS to work. Designing this app forced me to really consider the rules to the game in a way that I don’t usually get to do, and almost never see: at a level where a machine could understand the rules. That means being extremely literal and very careful. Additionally, while none of the code was transferred, almost all of the ideas translated directly over and I was able to make very fast progress on the initial versions of the SGS Website because of the prototype console app.