diff --git a/docs/PROJECT_CONTEXT.md b/docs/PROJECT_CONTEXT.md index 377a890..4c0d1c5 100644 --- a/docs/PROJECT_CONTEXT.md +++ b/docs/PROJECT_CONTEXT.md @@ -208,8 +208,9 @@ plugin content, not game architecture. - WASD movement is camera-relative. - The elevated third-person camera rotates with the mouse and uses smoothed follow/focus behavior. -- Pressing `E` near a task zone directly contributes food, wood, safety, or - knowledge, or consumes village food. +- Pressing `E` near a berry bush or tree extracts its configured yield into the + village through the same `ResourceNode` contract used by NPCs. +- Guard, study, and food interactions still use their temporary task zones. - `Escape` releases captured mouse input. ### Village simulation @@ -300,9 +301,12 @@ primitive geometry and a few tree assets. **Migration status:** NPC `gather_food` and `gather_wood` no longer use the farm and forest zones. They target `ResourceNode` instances (berry bushes and trees) instead. The zone markers remain for: -- Player interaction (pressing E near farm/forest zones adds resources) - Non-resource NPC tasks (patrol → guard_zone, study → study_zone, rest → rest_zone, eat → food_zone) +The player also harvests food and wood directly from nearby `ResourceNode` +instances. Extraction returns the actual amount removed, updates the village by +that amount, and releases an NPC reservation if the source is depleted. + Storage, rest, study, and guard behavior should later migrate to target types that match their actual semantics rather than treating every usable object as a resource source. @@ -437,6 +441,8 @@ NpcVisual navigates through the active world │ ├── SimNPC.gd │ ├── SimVillage.gd │ └── SimulationManager.gd +├── tests/ +│ └── resource_node_player_parity_test.gd ├── world/ │ ├── resource_nodes/ │ │ ├── ResourceNode.gd @@ -453,11 +459,13 @@ NpcVisual navigates through the active world These are expected prototype constraints, not necessarily isolated bugs: - Task names and task-to-zone mappings are duplicated strings. -- Task zones remain for non-resource tasks and player interaction; gather food/wood NPCs use ResourceNode instances instead. +- Task zones remain for non-resource activities; NPC and player food/wood + gathering use `ResourceNode` instances. - Mutable simulation state is not serializable through a defined save schema. - Randomness is not seeded for deterministic replay. - Simulation time depends on `_process` and a scene-tree node. -- There is no automated test or headless simulation harness. +- Automated coverage currently contains one headless player-parity and + resource-contention scenario; broader simulation coverage is still missing. - Resources are global floating-point counters rather than items in locations and inventories. - NPCs do not have homes, schedules, possessions, memories, relationships, diff --git a/docs/RESOURCE_NODE_MIGRATION.md b/docs/RESOURCE_NODE_MIGRATION.md index deaa00e..5883fd2 100644 --- a/docs/RESOURCE_NODE_MIGRATION.md +++ b/docs/RESOURCE_NODE_MIGRATION.md @@ -8,13 +8,13 @@ | **2** | Food target selection + reservation | ✅ Complete | | **3** | Authoritative extraction on completion | ✅ Complete | | **4a** | Wood target selection (NPC) | ✅ Complete | -| **4b** | Player parity (extraction contract) | ⏳ Not started | +| **4b** | Player parity (extraction contract) | ✅ Complete | | **5** | Jajce world placement | ❌ Not started | | **6** | Remove remaining zone model | ❌ Not started | ### Key divergences from the original plan -- **Zone fallback removed** (Phase 3): `gather_food`/`gather_wood` no longer fall back to `FarmZone`/`ForestZone` markers when no resource node is available. The original plan called for a logged fallback; instead, the NPC goes idle (via `navigation_failed` → wander) to guarantee resource conservation. The zone markers are still available for player interaction. +- **Zone fallback removed** (Phase 3): `gather_food`/`gather_wood` no longer fall back to `FarmZone`/`ForestZone` markers when no resource node is available. The original plan called for a logged fallback; instead, the NPC goes idle (via `navigation_failed` → wander) to guarantee resource conservation. Player harvesting also uses resource nodes; remaining zones serve only non-resource activities. - **`navigation_failed` signal** (discovered during Phase 4): Added a separate signal pathway to distinguish genuine arrival from navigation failure. The original plan treated all "arrivals" uniformly. - **Stale-path prevention** (discovered during Phase 4): Added `path_request_id` + `path_pending` to reject async path results that arrive after a new target was set or the NPC died. - **Duplicate node_id detection** (discovered during Phase 4): Added startup validation that disables nodes with duplicate IDs and pushes an error. @@ -34,6 +34,7 @@ | 9 | Empty-path re-entrancy: immediate arrival report caused re-entrant signal chain | Phase 4 | Defer to `stuck_counter`/`stuck_time` in `_physics_process` instead | | 10 | Stale async path: `await physics_frame` result used after target or death changed | Phase 4 | `path_request_id`/`path_pending` guard | | 11 | Stolen extraction: NPC extracted from node after reservation was lost | Phase 4 | Guard extraction with `node.reserved_by == npc.id` | +| 12 | Depleted target retained an NPC reservation after player harvesting | Phase 4 | `ResourceNode.extract()` now releases its reservation on depletion | ## Decision @@ -445,7 +446,7 @@ total bush decrease == total village food increase for the initial gather-food scenario. -### 🔶 Phase 4 — Wood and player parity *(partially complete)* +### ✅ Phase 4 — Wood and player parity *[complete]* **Wood migration** ✅ complete: - `gather_wood` uses `ResourceNode.find_available("gather_wood")` in WVM @@ -453,14 +454,21 @@ for the initial gather-food scenario. - Extraction follows same path as food (reserve → travel → work → extract → village resource delta) - Zone fallback removed; NPC goes idle if no tree available -**Player parity** ⏳ not started: -- Player currently still uses zone-marker interaction in `player.gd` -- Player should use `ResourceNode.extract()` via proximity detection or raycast -- Player interaction bypasses reservation (player presses E at a node → extract if available) -- `PlayerInteraction.gd` exists as an empty stub +**Player parity** ✅ complete: +- Player interaction resolves the nearest player-usable resource node by its + interaction point. +- `SimulationManager.harvest_resource_node()` uses the same authoritative + `ResourceNode.extract()` contract and applies exactly the returned amount. +- Player harvesting can contend with an NPC reservation; depletion releases + that reservation so the NPC can recover cleanly. +- Depleted and disabled targets provide explicit feedback. +- Food and forest zone bindings were removed from the player. +- `tests/resource_node_player_parity_test.gd` verifies food conservation, wood + conservation, depletion, and player/NPC contention. -**Updated exit:** food and wood no longer require their abstract zones during -normal play *for NPCs*. Player parity is required to fully exit this phase. +**Exit:** food and wood no longer require their abstract zones during normal +play. NPC and player extraction obey the same availability, depletion, and +authoritative-yield rules. ### Phase 5 — Jajce world placement @@ -509,7 +517,7 @@ At minimum, exercise: 8. navigation fails; 9. node is disabled while reserved; 10. fallback zone is used because no matching node exists; -11. player and NPC contend for the same source; +11. player and NPC contend for the same source; ✅ automated 12. duplicate node IDs are detected. Use a fixed seed and concise reason tracing where possible. @@ -542,14 +550,14 @@ resource conservation through debug presentation. | 9 | Apply actual extracted yield on completion | ✅ Done | `c6033b6` | | 10 | Add navigation failure handling (replaces regression scenarios) | ✅ Done | `b8752f8` | | 11 | Migrate wood | ✅ Done | `c6033b6`, `8049c52` | -| 12 | Give the player the same extraction path | ⏳ Not started | — | +| 12 | Give the player the same extraction path | ✅ Done | `326df51` | | 13 | Continue with the Jajce world scaffold | ❌ Not started | — | ## Definition of done for the first migration | Criterion | Status | |-----------|--------| -| Food and wood use actual finite world objects | ✅ (NPCs) / ⏳ (player) | +| Food and wood use actual finite world objects | ✅ | | NPCs select available targets and reserve them | ✅ | | NPC state stores stable target IDs rather than nodes or scene paths | ✅ | | Active visuals navigate to explicit interaction points | ✅ | @@ -558,6 +566,5 @@ resource conservation through debug presentation. | Depletion changes availability and presentation | ✅ | | Failure, interruption, and death release reservations | ✅ | | Old food and forest zone fallbacks are no longer used by NPCs | ✅ (fallback removed by design) | -| The player and NPCs can use the same extraction contract | ⏳ (player side not started) | -| Behavior is inspectable and covered by reproducible scenarios | ✅ (debug logging, debug overlay on nodes) | - +| The player and NPCs can use the same extraction contract | ✅ | +| Behavior is inspectable and covered by reproducible scenarios | ✅ (debug logging, node overlay, headless player-parity test) |