A saved game should let you continue making questionable decisions from where you left off. It shouldn’t give you a fresh board and pretend those decisions never happened.

In my Goblin Slayer work in Tabletop Simulator, setting up the cave and loading a game in progress have different jobs. Setup can arrange the cave tiles; loading needs to preserve the saved arrangement and progress while restoring the protection that keeps those tiles from being picked up. Both operations touch the same objects, which makes sharing a setup routine tempting.

A fictional example: a game starts with six map tiles, two figures and three counters. You move a figure across the map, spend a counter and save. When you return, all six tiles are present, both figures are on the table and the counters look tidy. Unfortunately, the figure is back at its starting position and you have three counters again. The components survived; your turn didn’t.

Before writing the shared code, I’d write down what each action is allowed to change:

ActionExpected result
Confirm a new gameReplace the current game with its starting state.
Load an in-progress gamePreserve saved positions, spent resources and active effects; restore the controls and protection needed to continue.
Cancel a new-game requestKeep the current game, including its positions, resources and effects.

Loading doesn’t have to mean doing nothing. Controls may need their handlers reconnected, references may need rebuilding, and fixed tiles may need their protection restored. Those are useful things to share between setup and loading, provided they don’t also replenish a resource or move a figure back home. A function called initialize doesn’t tell us which of those jobs it does.

A saved game restores the same figure position and two remaining counters.

Cancellation puts the order of operations under scrutiny. If the application clears an effect or starts collecting pieces before asking whether you want a new game, Cancel already has something to undo. Ask first, then recheck that the requested reset can proceed before changing the board. A confirmed reset can still fail partway through, so it needs its own recovery behavior; the confirmation dialog hasn’t solved that problem.

Older saves make the distinction less convenient. A missing “game started” value could mean an older version never recorded it. Treating that absence as “no game in progress” turns incomplete information into permission to discard something. Preserve what can be interpreted safely and make the uncertainty visible when it prevents an action.

I’d test this with a deliberately untidy game. Move a figure away from its starting position, spend a counter and leave an effect active. Save and reload, then check those particular facts. Separately, request a new game and cancel it; check them again. Finally, confirm a new game and check the starting conditions. Loading a pristine starting board wouldn’t expose the mistake in our fictional example, because the wrong result would look right.

The same question comes up outside games. Creating a document from a template can supply default text; reopening yesterday’s document should preserve the text you wrote. Shared code is useful, but its caller still needs to say which operation the user requested.

Before calling setup from a load routine, ask what it will reset. Then save something worth preserving and see whether it’s still there.

—jhunterj

Join the conversation

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