Dev Log: 2026-07-03¶
"Your queued units now know where their friends are going, and your save file is no longer one badly-timed browser refresh away from oblivion."
Queue-aware pathfinding¶
Queue mode has been in the game for a while now, letting you chain multiple unit commands before the enemy gets to react. It is a powerful tool for executing multi-unit plays without the turn-based stop-and-go. But it had a blind spot: each unit planned its route in isolation, ignoring what the other queued units were about to do.
Katyusha queues a move to position A. Nadeshiko queues a move through the cell Katyusha is currently standing on. The pathfinding happily draws Nadeshiko's route through that cell, because right now it is empty. But when the queue executes, Katyusha moves first, vacating A, and Nadeshiko's path suddenly has to reroute around... wait, no, there is no dynamic rerouting during execution. The path is already baked. So Nadeshiko walks into a cell that Katyusha just left, which is fine in this example, but what if Nadeshiko needed to path through a cell that Katyusha was arriving at? That would be a collision.
The fix: pathfinding now accounts for previously queued units' planned movements. When you add Nadeshiko to the queue, the grid treats Katyusha's current position as free (she will leave it) and Katyusha's target as blocked (she will arrive there). The reachable-cells overlay updates accordingly, and A-star routes around the blockage or through the vacated space naturally.
Ghost previews¶
Every queued item now shows its ghost preview on the map simultaneously. Previously you could only see one ghost at a time (the one you were browsing in the queue bar), which made it hard to check whether your first unit's route was about to pin your second unit against a wall. Now every queued path renders at once, in the same amber ghost style. The active route preview sits on top at z-index 100; the ghosts sit below at 99. No z-fighting, no confusion.
Save data safety¶
The itch.io web export has been shipping builds for a while now. Since publishing a new version to itch involves uploading a fresh set of files, and Godot's web export stores persistent data in IndexedDB, I have seen reports of save games going missing after an update. The browser's IndexedDB is generally reliable, but there are edge cases where things go wrong, and the game's save code handled none of them gracefully.
I went through the save path end-to-end and addressed every failure mode I could find.
Atomic writes¶
The old save code opened savegame.json with the WRITE flag, wrote the JSON string, and closed the file. The WRITE flag truncates the file on open. If the tab closed between the open and the write, the save was silently destroyed. On the next visit, the game checked FileAccess.file_exists, saw an empty file, and started a new game.
The fix uses a write-to-temp-then-rename pattern:
var tmp_path := "user://savegame.json.tmp"
var file := FileAccess.open(tmp_path, FileAccess.WRITE)
# ... write to tmp ...
file.close()
DirAccess.remove_absolute(ud + "/savegame.json")
DirAccess.rename_absolute(ud + "/savegame.json.tmp", ud + "/savegame.json")
If the tab closes during the write, only the temp file is corrupted. The real save remains intact. The rename is atomic on most filesystems and indexedDB-backed enough on web to be safe.
Backup save¶
After the primary save is written and read back for validation, a copy is made to savegame.json.bak. If a future write corrupts the primary, the loader falls back to the backup and repairs the primary automatically:
Primary corrupt --> try backup --> backup valid --> copy backup over primary --> continue
The backup is only updated after the primary passes read-back validation, so it always contains the last known-good state. If the primary write itself succeeds but the read-back fails (a rare IndexedDB consistency issue), the backup stays at the previous version untouched.
beforeunload guard (web)¶
When save_game() runs on the web export, it sets a JavaScript flag via JavaScriptBridge.eval(). The custom shell registers a beforeunload handler that checks this flag. If the user tries to close the tab while a save is in flight, the browser shows a confirmation dialog, giving the IndexedDB transaction time to complete.
Corruption detection¶
load_game() now validates that the parsed JSON is a dictionary with a schema_version key before accepting it. Corrupt or truncated data is detected and reported. If both the primary and backup are invalid, _smart_boot() starts a fresh game with a warning logged to the console. Previously it would silently load partial state and behave unpredictably.
Steam Cloud¶
The cloud save path was also hardened: corrupt cloud data (parse failure, missing schema version) is discarded instead of silently overwriting the local save. The _pick_save comparison still favors the cloud on equal timestamps, but it now checks validity first.
UI polish¶
Stage banners suppressed on restart¶
When restarting a stage from the pause menu, the chapter title, sector label, and objective banners no longer replay. These banners were designed to welcome the player at the start of a fresh run, not to stall them when they just want to retry a failed sector. The GameManager.restarting_stage transient flag is set before re-entering _launch_stage, and the banner coroutines skip their animation when the flag is detected.
Cutscene Previous button¶
The cutscene player now has a Previous button alongside the existing Next button. You can navigate back to re-read earlier dialogue without restarting the entire cutscene. The button reconnects the text reveal timer so you do not have to wait for the typewriter animation to complete on the already-seen line -- it snaps back instantly.
Bug fixes¶
- Iron Curtain restored on undo: Undoing a unit action now correctly restores the Iron Curtain state. Previously, if a unit activated IC and you undid the move, the IC charge was consumed but the shield was gone, effectively wasting the ability. The undo checkpoint now snapshots
iron_curtain_activealongside position and HP. - Undo disabled during tutorials: The undo button in the HUD was clickable during tutorial popups, which could let players bypass teaching sequences. The button is now disabled while any tutorial layer is active.
- Achievements dialog overflow: The achievements panel no longer overflows on narrower screens (phones in landscape, smaller browser windows). The scroll container respects the viewport height.
Miscellaneous¶
- Changelog updated, version bumped to 0.1.5.65
- GDScript test suite: 828/828 passing
- Python solver tests: 525/525 passing (18 skipped)
- All carry states compatible -- no solver refresh needed for any chapter
Build 65 is mostly about making the game feel more responsive and less fragile. The queue pathfinding fix changes how tactical planning works in a subtle but meaningful way: you can now chain multi-unit maneuvers with confidence that the paths mean what they look like they mean. And the save safety work means the web demo should stop eating people's progress when they upgrade to a new version -- which was the single biggest source of support messages for the itch.io build.