Quitting Mid-Fight Was a Free Retry, and a Player Found It

At the end of July a player sent me a short message. Quit to the main menu in the middle of a fight, press Continue Run, and the fight hasn’t happened yet: the game puts you back to the moment before you picked it. Pick it a second time and a different enemy is waiting. It reproduced exactly as described.
Soul Strip is a roguelike deckbuilder: your deck is built out of character cards, one girl each, and it’s what you fight with. A run walks you across a map of nodes, some holding a fight and some an event with a choice, and between them you pick which branch to take next. It takes a bit over twenty minutes and ends either with your death or with the last boss, and death sends you back to the start.
Those twenty minutes are worth something precisely because you can lose them. The bug was quietly handing them back.
A Node Spent Before the Fight, Unspent on Load
There was nothing wrong with the save itself. The file was written the moment you left, and nothing was ever lost or corrupted.
The break sat in the seam between two pieces of code that were each correct on their own.
Clicking a node decides what’s inside it first: which enemy you’ll face. Only after that does the node get marked as visited, and only then does the battle screen open. By the time you’re looking at the enemy, the map already counts that node as spent.
Loading had a rule of its own for interrupted runs. The game checks which screen the run stopped on. If it wasn’t the map, you clearly walked away in the middle of something, so the node rolls back: the visited mark comes off, and you step back to the node you came from to choose again.

The rollback was written as a courtesy. What it handed out was a free retry.
Three Things the Rollback Broke
The fight. A lost fight stopped being lost. Quit while you’re losing, continue, and you’re standing on the map in front of the same choice again. Pick the same node a second time and a different enemy comes up. The one that was about to end your run isn’t there any more.
The promise. A promise is a condition you take on for the run: deal this much damage with a chosen card in a single turn, say. Some of those conditions are scored on your best result across the whole run, and the run kept that best result on itself rather than on the node, so rolling the node back never touched it. You could restart the same fight until the turn finally came together, and whatever had already been scored stayed scored.
The event. Which event you got wasn’t decided when you clicked the node. It was decided when the event screen opened, so quitting and coming back rolled the pick again: the Clearwater Fountain came up, you left, you walked in a second time, and now it’s the Potion Peddler.
None of the three is minor. A run is a chain of decisions you can’t take back, and all of the tension comes from exactly that. A free retry turns every hard fight into an optional one. And a player who has found the retry can’t un-find it: from then on it sits in every run, used or not.
Blocking the Quit Punishes the Wrong Person
The first fix that comes to mind is to forbid it: don’t let the player leave a fight, or refuse to load a save written mid-battle. It’s the wrong fix.
Closing a laptop isn’t cheating. A run takes twenty-odd minutes, and in twenty minutes a phone rings, a train arrives, a child wakes up. A rule like that catches everyone who walked away for an ordinary reason, and those are most of the people it would reach.
So the thing to repair wasn’t the quit. It was the information the save threw away. The save knew which node you were standing on. It didn’t know who was waiting inside it.
The Snapshot at the Node Entrance
Now the run takes a snapshot of itself at the moment the node is chosen and the fight hasn’t started. The snapshot holds everything a save normally holds, plus two labels: which screen you went into, and who or what was waiting for you there.
While the battle or the event is on screen, the save writes that snapshot instead of the live state: the HP you walked in with, the random number generator in the position it was in at the door, and whatever the run had credited toward your promise by then.

Storing the seed the generator started from is not enough. The seed rewinds the stream of random numbers to the start of the run, and everything the run has already drawn from that stream gets drawn again: the same shop stock, the same events, the same cards offered as rewards. The snapshot stores the position in the stream, not the seed.
Continue Run reads the two labels. If they’re set, the button doesn’t go to the map: it puts you back inside the same fight against the same enemy, or reopens the same event with the same options. If they aren’t set, it behaves the way it always did. The moment you step out onto any safe screen the snapshot is discarded, so quitting between nodes still costs you nothing.
Quitting a second time, out of the resumed fight, lands in the same place: Continue Run takes the snapshot again before it hands you back to the fight.
One place in the code had to move for this. The snapshot has to write down what is waiting inside the node, and the event used to be picked later: not when you clicked the node, but when the event screen opened. There was nothing to write down. Now the event is picked on the click, and its name goes into the snapshot.
Same Golem, Same Fountain
Quit in the middle of a fight, press Continue Run, and the same Bone Golem is standing there, with the HP you walked in with. Quit in the middle of an event and it’s the same Clearwater Fountain with the same three options: drink from it, bathe in it for 8 HP to gain 5 max HP, or walk away. The old build gave back something different in both cases.
The rollback was written for the player who walks away and comes back, and it was tested that way. Nobody tested what happens when you walk away on purpose. Holes like that get found by the people who play the game, not by the person who writes it.
Soul Strip is on 0.9.93. Release is close, and the date isn’t announced. The Steam page takes wishlists.

Soul Strip: Waifu Card Battler
A deckbuilding roguelike where every card is a waifu with her own element and personality. Battle through dark fantasy, craft combos, collect and level up your favorites.
Wishlist on Steam