Skip to content
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
23 changes: 18 additions & 5 deletions docs/DESIGN.md
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,7 @@ The world grid is dynamically generated at runtime — `build_world()` creates a

`game_state.gd` exposes `save_game()`, `load_game()`, `save_settings()`, `load_settings()`, and `clear_game()`. Desktop builds write JSON to `user://windowstead.save` and `user://windowstead.settings`. Web builds use `localStorage` via `JavaScriptBridge`.

Save format is a single JSON dictionary with keys: `tick`, `harvested`, `resources`, `priority_order`, `dock_anchor`, `workers`, `tiles`, `builds`, `next_build_id`, `events`, `active_goal`, `completed_goal_ids`, `save_version`.
Save format is a single JSON dictionary. `validate_save_schema()` in `scripts/game_state.gd` is the source of truth for the validated fields. Persisted keys: `tick`, `harvested`, `resources`, `priority_order`, `colony_stance`, `dock_anchor`, `workers`, `tiles`, `builds`, `next_build_id`, `reserved_resources`, `events`, `active_goal`, `completed_goal_ids`, `active_rewards`, `current_milestone_id`, `completed_milestone_ids`, `save_version`, plus `migration_log` on saves upgraded from version 1.

### Grid dimensions

Expand All @@ -73,6 +73,7 @@ The window is borderless + always-on-top by default. Transparent window mode is
"harvested": {"wood": int, "stone": int, "food": int},
"resources": {"wood": int, "stone": int, "food": int},
"priority_order": ["build", "haul", "gather"],
"colony_stance": String,
"dock_anchor": "bottom" | "left" | "right",
"workers": [
{
Expand All @@ -82,7 +83,7 @@ The window is borderless + always-on-top by default. Transparent window mode is
"carrying": {"<resource>": int},
"task": {"kind": String, "target": {"x": int, "y": int}, "resource": String, "build_id": int},
"break_ticks": int,
"spawn_tick": int
"spawn_tick": int // optional; set on recruit, backfilled by the v1 → 2 migration
}
],
"tiles": [
Expand All @@ -103,6 +104,16 @@ The window is borderless + always-on-top by default. Transparent window mode is
"reward": String // Optional reward label
},
"completed_goal_ids": [String],
"active_rewards": [
{"type": String, "remaining": int, "duration": int,
"label": String, "trickle_ticks": int, "resource": String} // "resource" only on trickle rewards
],
"current_milestone_id": String,
"completed_milestone_ids": [String],
"reserved_resources": {"<resource>": int},
"migration_log": [
{"from_version": int, "to_version": int, "step": String}
],
"save_version": int
}
```
Expand All @@ -129,8 +140,10 @@ Each structure has build costs in wood and stone. Workers must haul resources to

## Save format

- Versioned with `save_version` (currently 2).
- On load, version mismatch triggers a colony reset.
- Versioned with `save_version` (currently 2). A save with no `save_version` key is treated as the current version.
- On load, every save passes through `validate_save_schema()` and then `migrate_save()` (shared by the desktop and web paths).
- Version 1 saves are migrated in place to version 2 by `migrate_v1_to_v2()` and load normally — nothing is reset.
- Future or unknown versions (greater than the current `SAVE_VERSION`) and version 0 are rejected: `migrate_save()` returns an empty dictionary, the load fails with an error message, and the running colony is left untouched. No reset happens on any load path.
- `migrate_v1_to_v2()` writes `migration_log` (appending a step entry) and backfills `spawn_tick` on workers that lack it. The other newer fields (`active_goal`, `completed_goal_ids`, `active_rewards`, `current_milestone_id`, `completed_milestone_ids`, `colony_stance`, `reserved_resources`) are backfilled separately by `ColonySim.ensure_defaults()` after load, not by the migration.
- Layout compatibility is checked: tile array size must match current grid, worker/build positions must be in bounds.
- Settings are stored separately from game state.
- Save version 1 → 2 migration adds `active_goal`, `completed_goal_ids`, and `spawn_tick` fields.
Loading