From 41bfc8d90a5d79e83a92eda81df8fa4eb02e9c23 Mon Sep 17 00:00:00 2001 From: Rijad Zuzo Date: Fri, 3 Jul 2026 18:51:13 +0200 Subject: [PATCH] fix: empty-path re-entrancy, retry_count reset, := to = for Variant --- docs/BUILD_IN_PUBLIC_PLAN.md | 563 +++++++++++++++++++++++++ docs/LEARNING_ROADMAP.md | 590 ++++++++++++++++++++++++++ docs/PROJECT_CONTEXT.md | 721 ++++++++++++++++++++++++++++++++ docs/RESOURCE_NODE_MIGRATION.md | 517 +++++++++++++++++++++++ player/npc/NpcVisual.gd | 20 +- player/npc/NpcVisual.tscn | 2 + simulation/SimNPC.gd | 6 + simulation/SimulationManager.gd | 12 + world/world_view_manager.gd | 22 +- 9 files changed, 2449 insertions(+), 4 deletions(-) create mode 100644 docs/BUILD_IN_PUBLIC_PLAN.md create mode 100644 docs/LEARNING_ROADMAP.md create mode 100644 docs/PROJECT_CONTEXT.md create mode 100644 docs/RESOURCE_NODE_MIGRATION.md diff --git a/docs/BUILD_IN_PUBLIC_PLAN.md b/docs/BUILD_IN_PUBLIC_PLAN.md new file mode 100644 index 0000000..e943906 --- /dev/null +++ b/docs/BUILD_IN_PUBLIC_PLAN.md @@ -0,0 +1,563 @@ +# The Steward — Build-in-Public Visual Slice Plan + +## Purpose + +This plan adapts the proposed “Jajce simulation garden” to the repository as it +exists now. It does not assume a blank project. + +The immediate visual goal is to replace the flat prototype presentation with a +small, attractive, watchable environment while preserving the working NPC +simulation, player controls, UI, task lifecycle, and navigation behavior. + +Before runtime terrain integration, food and wood should migrate from abstract +zones to actual finite world objects according to +[the ResourceNode migration plan](RESOURCE_NODE_MIGRATION.md). This prevents the +new environment from being authored around a zone model already marked for +removal. + +The slice should make a viewer understand this promise quickly: + +> A cozy Bosnian-inspired world where autonomous people visibly make decisions, +> work, struggle, and create stories. + +This is not a plan to build the full city of Jajce. It is a plan to create one +strong visual composition that can host the current simulation and grow with +future systems. + +## What already exists + +Do not redo these tasks: + +- Godot 4.7 project configuration; +- Terrain3D 1.0.2 installed and enabled; +- cross-platform Git configuration; +- working `main.tscn`; +- camera-relative player movement and elevated follow camera; +- three autonomous simulated NPCs; +- hunger, energy, starvation, death, task scoring, and task duration; +- task-change and village-change signals; +- visual NPC navigation and arrival reporting; +- farm, forest, food, guard, study, and rest markers; +- aggregate village UI; +- initial tree assets; +- a baked navigation region for the current flat test area. + +Terrain3D's bundled `demo/` directory and most of `addons/terrain_3d/` are +plugin content. They are references, not the game. + +## Current architectural constraint + +`main.tscn` currently owns several different concerns: + +```text +Main +├── current flat World and NavigationRegion3D +├── Player +├── CameraRig +├── SimulationManager +├── WorldViewManager +├── ActiveNPCs +├── TaskZone markers +├── WorldEnvironment +└── UI +``` + +The player and `WorldViewManager` reference the task markers through exported +`NodePath` values. `NpcVisual` relies on the navigation map to reach those +markers. + +Replacing the ground without respecting those references would break behavior +that already works. + +## Adjusted scene strategy + +Create a reusable environment scene and instance it into the existing runtime. +Keep game orchestration in `main.tscn`. + +Target structure: + +```text +Main +├── JajceWorld instanced environment +│ ├── TerrainRoot +│ │ └── Terrain3D +│ ├── WaterRoot +│ ├── VillageRoot +│ ├── FoliageRoot +│ ├── NavigationRegion3D +│ ├── WorldObjects +│ │ └── ResourceNodes +│ │ ├── BerryBush instances +│ │ └── Tree instances +│ ├── LegacyTaskMarkers temporary migration fallback +│ │ ├── FarmZone fallback only +│ │ ├── ForestZone fallback only +│ │ ├── FoodZone +│ │ ├── GuardZone +│ │ ├── StudyZone +│ │ └── RestZone +│ ├── DirectionalLight3D +│ └── WorldEnvironment +├── Player +├── CameraRig +├── SimulationManager +├── WorldViewManager +├── ActiveNPCs +└── UI +``` + +`JajceWorld` should contain geography, world-object presentations, and temporary +legacy interaction locations. It should not own `SimulationManager`, simulated +NPC data, player state, or UI. + +Create a small look-development wrapper that instances the same world: + +```text +JajceLookdev +├── JajceWorld +└── BeautyCameraRig +``` + +This provides a cinematic workbench without creating a second environment that +later has to be rebuilt for gameplay. + +## Adjusted file structure + +Follow the repository's existing feature-oriented layout. Do not create six +empty sub-scenes merely to match a theoretical architecture. + +Start with: + +```text +world/ +└── jajce/ + ├── JajceWorld.tscn + ├── JajceLookdev.tscn + └── beauty_camera.gd + +terrain/ +└── jajce/ + ├── data/ + ├── materials/ + ├── textures/ + └── source/ + +assets/ +└── jajce/ + ├── buildings/ + ├── foliage/ + ├── rocks/ + ├── props/ + ├── water/ + └── vfx/ +``` + +Extract `JajceWater`, `JajceVillageBlockout`, or other components into their own +scenes only when they have meaningful internal behavior or are reused. Avoid +scaffolding an elaborate directory tree before assets exist. + +## Visual target + +Build a compressed, game-readable Jajce-inspired valley: + +| Inspiration | First-slice interpretation | +| --- | --- | +| Hilltop fortress | One strong blockout silhouette on the ridge | +| Old town slope | Four to six house blocks following two terraces | +| Pliva/Vrbas water | One main river and a suggested secondary channel | +| Waterfall | Hero mesh/VFX feature visible from the main camera | +| Watermills | One working mill silhouette, with room for later expansion | +| Forested hills | Terrain3D foliage clusters and background tree masses | +| Agricultural outskirts | Existing farm and forest jobs integrated into terrain | +| Regional roads | One readable loop connecting world objects and legacy targets | + +The fortress, waterfall, roofs, player, and at least two working NPCs should be +readable in one strong composition. + +## Scope + +### First terrain size + +Start around **512 m × 512 m**. The playable and polished area can be smaller +inside it. + +Do not begin at 1024 m simply because Terrain3D supports it. Expand only when +the current camera, navigation routes, and composition need more space. + +### First material set + +Use at most six terrain surfaces: + +1. soft grass; +2. dirt path; +3. warm cliff stone; +4. wet riverbank stone; +5. forest floor; +6. compacted village ground. + +The material set should establish large readable areas. Avoid high-frequency +photorealistic noise. + +### First architecture set + +Use: + +- one fortress silhouette; +- four to six house blockouts; +- one mill; +- one bridge; +- a few fences, carts, sacks, logs, and work props. + +Do not begin with 12–20 finished houses. The first shot needs composition, not +an asset catalog. + +## Art direction rules + +Translate the desired animated-film warmth into an original style: + +| Element | Direction | +| --- | --- | +| Terrain | Broad painterly color regions and exaggerated silhouettes | +| Grass | Soft masses and restrained sway, not dense visual noise | +| Trees | Rounded canopies, varied scale, simple readable trunks | +| Rocks | Chunky warm-gray forms with low-frequency detail | +| Buildings | Light plaster/stone, warm roofs, dark timber accents | +| Water | Turquoise/emerald body, strong foam shapes, soft reflection | +| Lighting | Warm sun, cool shadows, mild atmospheric haze | +| Characters | Simple proportions, clear profession colors and props | +| Motion | Wind, water, smoke, leaves, cloth, birds, and purposeful NPC travel | + +Cozy presentation does not remove scarcity, death, conflict, or ambition. It +makes the world pleasant to inhabit and the people pleasant to watch. + +## Implementation phases + +### Phase 0 — Preserve and capture the baseline + +Before replacing anything: + +- run the current prototype; +- record a short baseline clip or screenshots; +- record the development machine's frame time and obvious scene statistics; +- verify all six task locations can be reached; +- verify starvation, work completion, and death still function; +- note current camera framing and movement feel. + +This becomes both a regression reference and excellent before/after material. + +### Exit condition + +There is a reproducible baseline showing the existing flat prototype and its +working behaviors. + +### Systems prerequisite — Migrate food and wood targets + +Implement and validate the first ResourceNodes on the current flat map before +moving the playable runtime onto Terrain3D: + +- berry bushes for `gather_food`; +- trees for `gather_wood`; +- stable target IDs; +- nearest-available selection; +- single-user reservation; +- extraction after work completion; +- depletion and replanning; +- actual extracted amount applied to the village; +- zone fallback with visible warnings. + +Keep the other task zones temporarily. Rest, eating, study, and patrol will +eventually use activity, storage, or workstation targets rather than pretending +to be resource sources. + +### Exit condition + +Food and wood work without their zones during normal play, resource conservation +holds, and target failure does not leave a permanent reservation. + +### Phase 1 — Create the reusable world scaffold + +Create `world/jajce/JajceWorld.tscn` with: + +- Terrain3D and dedicated terrain data; +- placeholder `WaterRoot`; +- placeholder `VillageRoot`; +- placeholder `FoliageRoot`; +- a navigation region; +- resource-node containers plus temporary fallback markers; +- lighting and environment. + +Create `JajceLookdev.tscn` that instances `JajceWorld` and adds a temporary +beauty camera. + +Do not migrate `main.tscn` yet. Do not duplicate simulation scripts inside the +look-development scene. + +### Exit condition + +The same `JajceWorld` instance can open in the lookdev scene and can be instanced +under a temporary runtime test without errors. + +### Phase 2 — Greybox the hero composition + +Sculpt by hand before attempting GIS/DEM import: + +- one dominant ridge; +- descending town terraces; +- main river valley; +- waterfall drop; +- lower pool; +- farm shelf; +- forest work area; +- a walkable road loop connecting world objects and remaining legacy locations. + +Block out the fortress, houses, mill, bridge, and waterfall with primitives or +simple meshes. + +Place the beauty camera early. Terrain should be judged through the intended +game and video cameras, not only from the editor's free camera. + +### Navigation spike + +Do an early rough navigation bake now. Do not wait until final art. + +The purpose is to detect: + +- slopes that are too steep; +- terraces that cannot connect; +- paths too narrow for agents; +- waterfall or river barriers that split required routes; +- terrain collision or navigation incompatibilities. + +The final navigation bake still happens after terrain and props stabilize. + +### Exit condition + +One static frame contains the ridge landmark, roofs, river/waterfall, and +village work area. A test agent can traverse the intended task loop. + +### Phase 3 — Establish the beauty baseline + +Add only the highest-value presentation: + +- six terrain materials; +- warm `WorldEnvironment`; +- directional light and atmospheric haze; +- simple river surface; +- waterfall body, foam, and mist; +- first foliage clusters using Terrain3D instancing where appropriate; +- restrained grass/tree motion; +- chimney smoke; +- slow beauty-camera drift. + +Avoid expensive water, dense individual grass nodes, and elaborate weather at +this stage. + +### Exit condition + +The lookdev scene can produce a compelling 10–20 second clip with no gameplay. +The environment remains within the recorded prototype's agreed performance +budget. + +### Phase 4 — Integrate the existing game + +Once the world composition is stable: + +1. Instance `JajceWorld` into `main.tscn`. +2. Disable or remove the old flat world only after the new instance is present. +3. Place or move bushes and trees under + `JajceWorld/WorldObjects/ResourceNodes` while preserving stable IDs. +4. Reconnect remaining player and `WorldViewManager` fallbacks to markers under + `JajceWorld/LegacyTaskMarkers`. +5. Bake navigation for the new walkable area. +6. Test each existing task from multiple spawn positions. +7. Verify task arrival still transitions from traveling to working. +8. Verify task completion still changes village state. +9. Verify depletion and reservations survive the scene migration. +10. Verify player interaction ranges still make sense at the new scale. +11. Verify dead NPC visuals do not block routes or retain reservations. +12. Compare performance and behavior against the Phase 0 baseline. + +Do not move simulation ownership into `JajceWorld` to make wiring convenient. + +### Exit condition + +The current three NPCs and player can perform all existing prototype behaviors +inside the new terrain without regression. + +### Phase 5 — Make the simulation readable on video + +Add presentation for systems that already exist: + +- simple stylized NPC placeholder instead of capsules; +- profession color/prop distinctions; +- compact task/need icon above selected or relevant NPCs; +- name labels when useful; +- an NPC reason inspector for development footage; +- visible food, logs, guard, study, rest, and eating props; +- cinematic/debug UI toggle; +- a scenario reset and fixed seed for repeatable clips. + +Do not fake activity that contradicts simulation state. A farmer icon should +represent a real chosen task. + +### Exit condition + +A viewer can distinguish at least three professions and understand one NPC's +need, destination, and consequence without reading console output. + +### Phase 6 — Produce the first public demo sequence + +Capture a short sequence with a clear story: + +1. establish the valley and waterfall; +2. introduce one named NPC; +3. show the NPC choosing and traveling to work; +4. reveal the reason through a concise overlay; +5. show the work changing a real village resource; +6. end on either recovery or a visible shortage consequence. + +The best first character is one of the existing named NPCs—Amina, Tarik, or +Jasmin—rather than an unnamed cinematic extra. + +### Exit condition + +The clip has an understandable beginning, decision, and consequence. It does not +depend on a voiceover to prove that the simulation is real. + +## Build-in-public content pillars + +Rotate between four types of updates. + +### 1. Transformation + +Show visible before/after progress: + +- flat test ground to Jajce-inspired valley; +- blockout waterfall to mist and foam; +- capsules to readable professions; +- empty paths to visible work traffic. + +### 2. Tiny autonomous stories + +Use one named NPC and one question: + +- Why did Amina stop guarding? +- Can Tarik gather food before starvation? +- Why is Jasmin resting while the village is short on wood? +- What happens when the food route is blocked? + +### 3. System under the beauty + +Show a beautiful shot, then reveal the debug reason trace, event, or resource +flow that drives it. + +### 4. Learning Godot publicly + +Frame honest engineering lessons: + +- Terrain3D sculpting and material mistakes; +- navigation problems caused by terrain; +- making NPC simulation deterministic; +- profiling foliage versus agent cost; +- separating simulation data from visual scenes. + +## Short-form video template + +For TikTok, Shorts, or brief social posts: + +```text +0–2 s Show the outcome or surprising NPC behavior +2–5 s State one question +5–15 s Show the cause unfolding +15–25 s Reveal the systemic consequence +End Show the next unresolved problem +``` + +Use captions and strong visual causality. Avoid opening with a long editor tour. + +## Initial video backlog + +1. **“I replaced my programmer map with a Bosnian-inspired valley.”** +2. **“This villager chose food over their profession—and here is why.”** +3. **“The village can starve without a scripted quest.”** +4. **“Every NPC physically walks to the work they selected.”** +5. **“One blocked path broke the village economy.”** +6. **“Making a Jajce-inspired waterfall in Godot Terrain3D.”** +7. **“The same scene in cinematic mode and simulation-debug mode.”** +8. **“Can three autonomous villagers survive this shortage?”** + +Each video should correspond to real repository progress. Do not build isolated +visual tricks solely for a post unless they also support the intended game. + +## Performance guardrails + +- Record frame time before adding terrain. +- Treat Terrain3D instancing as the default for broad foliage where suitable. +- Avoid physics and navigation obstacles on distant decorative vegetation. +- Keep waterfall mist and smoke particle counts bounded. +- Use simple water before adding screen-space reflection or refraction. +- Test the gameplay camera, not only the beauty camera. +- Profile editor and exported builds separately when export work begins. +- Recheck navigation cost after every meaningful terrain expansion. +- Do not increase NPC population while diagnosing environment cost. + +## Source-control guardrails + +- Commit Terrain3D data and game-authored terrain assets. +- Continue ignoring `.godot/` and other imported caches. +- Keep Godot `.import` and `.uid` sidecars tracked. +- Do not modify or reformat the third-party Terrain3D addon incidentally. +- Keep lookdev assets under game-owned paths, not inside the addon. +- Make environment, integration, and simulation changes separate commits where + practical. + +## Definition of “Jajce Lookdev 01” + +The adjusted first milestone is complete when: + +- Terrain3D is used by `JajceWorld`; installation itself is already complete. +- One approximately 512 m terrain exists. +- Fortress ridge, town terraces, river valley, and waterfall drop are readable. +- Six or fewer terrain materials establish the major surfaces. +- One fortress, four to six houses, one mill, and one bridge are blocked out. +- River, waterfall foam, mist, warm lighting, and first foliage are present. +- A beauty camera produces a strong 10–20 second shot. +- A rough navigation test proves the main route is viable. +- The existing simulation has not yet been duplicated or moved. + +## Definition of “Simulation Garden 01” + +The follow-up milestone is complete when: + +- `JajceWorld` is instanced in `main.tscn`; +- food and wood ResourceNodes work in the terrain; +- remaining legacy task markers are reconnected; +- player movement and all existing interactions work; +- all three current NPCs navigate, work, eat, rest, starve, and die correctly; +- one NPC's decision is readable through in-game presentation; +- cinematic and debug views can show the same real scenario; +- a repeatable public-demo clip shows an autonomous cause and consequence; +- performance and navigation regressions are measured and documented. + +## Immediate implementation order + +1. Capture the current flat-map baseline. +2. Implement and validate ResourceNodes on the flat map. +3. Migrate food and wood; keep remaining zones as logged fallbacks. +4. Create `JajceWorld.tscn`. +5. Create dedicated Terrain3D data under `terrain/jajce/`. +6. Create `JajceLookdev.tscn` and its beauty camera. +7. Sculpt the ridge, river valley, terraces, and waterfall drop. +8. Place ResourceNodes and only the still-required legacy markers. +9. Block out the fortress, houses, mill, and bridge. +10. Run the early navigation spike. +11. Establish terrain materials, lighting, water, mist, and foliage. +12. Capture “Jajce Lookdev 01.” +13. Instance `JajceWorld` into `main.tscn`. +14. Reconnect fallbacks, rebake navigation, and regression-test the simulation. +15. Add profession/readability presentation. +16. Capture “Simulation Garden 01.” + +Do not start with GIS data, a full city, a large asset pack, or more NPC +mechanics. The next proof is a beautiful stage for the systems that already +exist. diff --git a/docs/LEARNING_ROADMAP.md b/docs/LEARNING_ROADMAP.md new file mode 100644 index 0000000..7ee3dc3 --- /dev/null +++ b/docs/LEARNING_ROADMAP.md @@ -0,0 +1,590 @@ +# The Steward — Learning and Reusable-Systems Roadmap + +## Purpose + +This project is both a playable prototype and an advanced Godot curriculum. +The goal is not merely to accumulate features. It is to understand, implement, +measure, and document systems that can form the foundation of a later +production game. + +The roadmap prioritizes: + +- learning through complete vertical behaviors; +- separating simulation from presentation; +- repeatable experiments and measurements; +- systems that survive save/load and scale changes; +- visible results suitable for building in public; +- avoiding premature architecture that has not been tested by gameplay. + +## How to use this roadmap + +Each milestone should produce five outcomes: + +1. **Concept learned** — the Godot or simulation topic being studied. +2. **Playable proof** — behavior a player can observe or influence. +3. **Reusable artifact** — a system, pattern, benchmark, or tool. +4. **Exit test** — an objective condition for calling the milestone complete. +5. **Retrospective** — what worked, what failed, and what should change. + +Do not advance because files exist. Advance when the exit test passes. + +## Three vertical slices + +The long-term vision contains three major risks. Validate them separately before +trying to combine the full game. + +### A. Simulation slice + +A small village runs autonomously, exposes understandable decisions, creates +history, and produces interesting failures without scripted quests. + +### B. Action slice + +Movement, interaction, melee combat, companions, and small-group commands are +fun in an isolated test environment. + +### C. World slice + +One village, one route, and part of a town exchange people, goods, information, +and conflict while the player moves between simulation fidelity levels. + +The simulation garden is the first slice. A combat sandbox should begin before +the simulation is “finished,” because combat feel is a separate high-risk +problem. + +## Continuous learning practices + +### Keep a decision record + +For meaningful architectural choices, record: + +- problem; +- constraints; +- options considered; +- decision; +- consequences; +- conditions that would justify revisiting it. + +This can later become a `docs/decisions/` collection. Do not create records for +trivial edits. + +### Maintain reproducible scenarios + +Important behaviors should have fixed seeds and known initial state: + +- normal village day; +- food shortage; +- blocked workplace; +- exhausted worker; +- path failure; +- NPC death; +- relationship conflict; +- migration or faction pressure. + +Scenarios make debugging, videos, balancing, and performance comparisons easier. + +### Measure before optimizing + +Maintain a small benchmark ledger: + +| Measurement | Example | +| --- | --- | +| Population | 10, 100, 1,000, 10,000 data-only agents | +| Simulated duration | one day, season, or year | +| Wall-clock runtime | total and per simulated tick | +| Update count | decisions and scheduled events processed | +| Memory | state and history footprint | +| Active visuals | navigation/animation cost | +| Determinism | final-state checksum for a known seed | + +### Pair systems with presentation + +Every systems milestone should answer: “How can a viewer see this happening?” +Every visual milestone should answer: “Which real state does this represent?” + +## Milestone 0 — Baseline and observability + +### Learn + +- Godot project execution and scene-tree inspection; +- debugger, profiler, monitors, and remote scene tree; +- structured logging and debug overlays; +- establishing behavioral and performance baselines. + +### Build + +- a simulation pause, single-step, speed control, and reset; +- selectable NPC debug panel; +- current need, task, task state, target, and task score display; +- deterministic scenario seed entry; +- concise event feed separate from verbose console logging; +- baseline performance capture for the existing three-NPC prototype. + +### Reusable artifact + +A simulation debug console/overlay and scenario runner. + +### Exit test + +From the running game, a developer can select any NPC and explain: + +- what it is doing; +- why it selected that task; +- where it is going; +- when the task should complete; +- what state will change on completion. + +The same seed and commands produce the same early simulation result. + +## Milestone 1 — Simulation/presentation boundaries + +### Learn + +- `Node`, `RefCounted`, and `Resource` responsibilities; +- signals versus direct calls; +- dependency direction; +- scene composition; +- typed GDScript and stable identifiers. + +### Build + +- explicit simulation clock outside frame-dependent rules; +- stable IDs for NPCs and locations; +- serializable state records separated from immutable definitions; +- an adapter interface between simulation and active visual NPCs; +- smaller managers with focused responsibilities; +- removal of direct task-string-to-marker coupling from the core. + +### Reusable artifact + +A minimal headless-capable simulation kernel with a Godot presentation adapter. + +### Exit test + +The village can advance without instantiating `NpcVisual` scenes. Loading or +unloading an NPC visual does not change the authoritative NPC state. + +## Milestone 2 — Data-driven needs, professions, and actions + +### Learn + +- custom `Resource` definitions; +- utility AI and consideration curves; +- action preconditions, effects, duration, and interruption; +- dependency injection through definitions; +- debugging decision scores. + +### Build + +- need definitions; +- profession definitions; +- action definitions for eat, rest, gather food, gather wood, patrol, and study; +- target discovery independent of hard-coded scene paths; +- utility considerations with full reason traces; +- reservations so multiple NPCs do not unrealistically claim one resource or + workstation; +- explicit task failure and replanning behavior. + +### Reusable artifact + +A generic action-selection system that can evaluate defined actions against +agent and world state. + +### Exit test + +A new profession and action can be added primarily through definitions and a +small effect implementation. The inspector shows the winning score and rejected +alternatives. NPCs recover from invalid or unavailable targets. + +## Milestone 3 — One complete material economy + +The staged replacement of abstract task zones begins with +[the ResourceNode migration plan](RESOURCE_NODE_MIGRATION.md). + +### Learn + +- inventories and item stacks; +- ownership, storage, reservations, and transactions; +- production recipes; +- world interaction points; +- consistency and invariant testing. + +### Build + +Implement one honest food chain: + +```text +source -> gather/harvest -> carry -> store -> retrieve -> prepare/eat +``` + +Include: + +- item definitions; +- personal and building inventories; +- location-based storage; +- physical carrying for active NPCs; +- abstract transfer for distant agents; +- reservation and cancellation; +- spoilage only if it improves the initial loop; +- player participation in the same resource rules. + +Add wood only after the food chain is coherent. + +### Reusable artifact + +Inventory, reservation, transaction, and production primitives. + +### Exit test + +Every consumed unit of food can be traced to a source and a sequence of actions. +No resource is created or destroyed except through an explicit, inspectable +rule. A shortage is visible before the aggregate UI reports it. + +## Milestone 4 — Attractive simulation garden + +The detailed environment and public-demo sequence is maintained in +[the build-in-public visual slice plan](BUILD_IN_PUBLIC_PLAN.md). + +### Learn + +- Terrain3D regions, sculpting, texturing, LOD, and instancing; +- environment lighting, fog, sky, and post-processing; +- modular scene construction; +- navigation generation and validation; +- water and vegetation presentation; +- performance budgets for environment art. + +### Build + +- a compact Jajce-inspired valley composition; +- ridge landmark, river/waterfall feature, bridge, mill area, farm, forest, + homes, and workplaces; +- warm painterly environment treatment; +- replace capsules with simple stylized, animation-ready characters; +- readable profession props/colors; +- day/night presentation; +- cinematic/debug display toggle; +- stable navigation across all required work routes. + +### Reusable artifact + +A terrain/world-building pipeline and environment performance checklist. + +### Exit test + +A short clip communicates the setting, player perspective, NPC professions, and +one production loop without narration or console output. The environment stays +inside the agreed frame-time and memory budget on the development machine. + +## Milestone 5 — Time, schedules, and persistence + +### Learn + +- authoritative game time; +- calendar and scheduled events; +- serialization and schema versioning; +- save migration; +- restoring active scenes from data; +- deterministic random streams. + +### Build + +- time-of-day and calendar; +- work, meal, sleep, and discretionary schedule blocks; +- simulation event queue; +- versioned save format; +- save/load for people, inventories, tasks, locations, and village state; +- state validation after loading; +- separate random streams where useful. + +### Reusable artifact + +A versioned world-state persistence layer and simulation scheduler. + +### Exit test + +Save during travel, work, eating, and sleep; reload each save; then verify that +the simulation resumes coherently. A deterministic headless scenario retains +the same checksum across repeated runs. + +## Milestone 6 — Events, memories, and relationships + +### Learn + +- event sourcing concepts without overcommitting to full event sourcing; +- relationship graphs; +- knowledge versus objective truth; +- memory selection and decay; +- social utility considerations; +- tooling for history inspection. + +### Build + +- structured world event records; +- actor, target, witness, location, cause, and consequence links; +- relationship dimensions such as familiarity, affection, trust, fear, + obligation, and hostility; +- NPC knowledge of witnessed or communicated events; +- memory importance and retention rules; +- visible social reactions; +- person and settlement history views. + +### Reusable artifact + +An event/history store and relationship system with query APIs. + +### Exit test + +Two NPCs exposed to different evidence can hold different beliefs about the +same event. Their future choices visibly differ because of those memories and +relationships. + +## Milestone 7 — Rumours and emergent opportunities + +### Learn + +- information propagation; +- query systems; +- narrative framing from structured facts; +- objective generation; +- consequence-aware quest state; +- natural-language presentation separated from authoritative state. + +### Build + +- rumour creation and transmission; +- information accuracy, secrecy, and distortion rules; +- detection of unresolved conditions; +- interested-party and capable-helper queries; +- opportunity/quest records that reference real entities and events; +- multiple valid resolution paths; +- consequence application to the source systems; +- concise dialogue/event text templates. + +### Reusable artifact + +An emergent opportunity generator built over world-state queries. + +### Exit test + +A shortage, theft, injury, debt, or disappearance creates an opportunity only +when someone knows and cares about it. Resolving it changes the originating +people, resources, relationships, and history without spawning quest-only +duplicates. + +## Milestone 8 — Scalable spatial simulation and LOD + +### Learn + +- spatial partitioning; +- relevance and interest management; +- scheduled/batched updates; +- data layout and allocation profiling; +- active/abstract entity transitions; +- statistical aggregation boundaries. + +### Build + +- spatial index for people, buildings, and events; +- active, local-abstract, distant-individual, and settlement-aggregate modes; +- promotion/demotion between modes; +- abstract travel and work resolution; +- background settlement updates; +- performance harness for increasing population and history; +- safeguards preserving named people and unresolved events. + +### Reusable artifact + +A simulation-LOD framework with measured transition invariants. + +### Exit test + +The benchmark can simulate a target large population faster than real time while +a smaller active population remains fully represented. Moving an NPC between +fidelity levels preserves identity, inventory, task, relationships, and +important history. + +Set the target population only after collecting baseline measurements. + +## Milestone 9 — Player interaction and social agency + +### Learn + +- interaction targeting; +- context actions; +- UI state machines; +- dialogue presentation; +- reputation and permission systems; +- accessibility and feedback. + +### Build + +- inspect people, storage, workplaces, and events; +- talk, trade, help, request, employ, threaten, or report where appropriate; +- priority influence through plausible institutions rather than omniscient + sliders; +- reputation, authority, and social access; +- player participation in professions; +- feedback showing likely and actual consequences. + +### Reusable artifact + +A context interaction framework connected to simulation actions and authority. + +### Exit test + +The player can understand and resolve the simulation garden's food crisis in +multiple systemic ways without using a developer menu. + +## Milestone 10 — Combat and companion sandbox + +Begin this as a focused prototype before Milestones 6–9 are fully complete. +Integrate it only after its fundamentals feel good. + +### Learn + +- animation state machines and blending; +- hit detection and hurtboxes; +- root motion versus code-driven motion; +- input buffering; +- camera feedback; +- AI combat behavior; +- group commands and formations; +- combat profiling. + +### Build + +- isolated combat test scene; +- responsive locomotion, attacks, defense, stagger, and recovery; +- clear targeting without excessive lock-on dependence; +- one companion with understandable autonomous behavior; +- a small command vocabulary; +- morale and retreat prototype; +- simulation consequences for injury, death, witnesses, and reputation. + +### Reusable artifact + +A combatant state model, animation interface, damage/event model, and companion +command layer. + +### Exit test + +A short encounter is enjoyable when repeated without progression rewards. One +companion can be directed without constant micromanagement, and combat outcomes +produce valid world events. + +## Milestone 11 — Multiple settlements, factions, and mobility + +### Learn + +- hierarchical simulation; +- settlement economies; +- faction goals and diplomacy; +- trade routes and migration; +- authority and governance; +- large-group command abstraction. + +### Build + +- one village, one travel route, and one district or edge of the city; +- movement of goods, people, rumours, and threats; +- household and workplace membership; +- faction membership and offices; +- migration and recruitment; +- small-scale leadership progression; +- settlement and faction decision processes. + +### Reusable artifact + +A regional simulation layer connecting local economies and social structures. + +### Exit test + +An event in one settlement creates measurable consequences elsewhere through +real movement or communication. The player can gain responsibility through +systemic relationships and actions rather than a fixed promotion quest. + +## Milestone 12 — Integrated world slice + +### Learn + +- production hardening; +- content pipelines; +- onboarding complex systems; +- balancing and telemetry; +- regression testing; +- profiling representative gameplay. + +### Build + +- the simulation, action, and world slices connected; +- one coherent regional scenario; +- polished onboarding for observation, work, social interaction, and combat; +- save compatibility tests; +- performance budgets and regression scenarios; +- build-in-public demo mode; +- documented extraction boundaries for reusable systems. + +### Reusable artifact + +A proven architecture and a set of tested subsystems ready to migrate or evolve +into the production game. + +### Exit test + +The player can begin as an ordinary person, form relationships, participate in +the economy, encounter an emergent problem, fight or negotiate through it, and +leave persistent consequences in another settlement. + +## Reuse checkpoints + +At the end of each milestone, evaluate the system against this checklist: + +- Does it run without the prototype's main scene? +- Are definitions separate from mutable state? +- Is state serializable and versioned where appropriate? +- Can it be tested with a fixed seed? +- Can presentation be replaced without rewriting its rules? +- Does it expose reason/debug information? +- Do measurements justify its complexity? +- Has at least one real gameplay feature exercised the API? + +Do not extract a plugin solely because a system might be reusable. Prefer a +clear internal module until multiple real consumers establish a stable API. + +## Recommended implementation order from the current repository + +The practical next sequence is: + +1. Add simulation controls and an NPC reason inspector. +2. Add finite berry bushes and trees through the first `ResourceNode`. +3. Migrate food target selection, reservation, depletion, and actual yield. +4. Introduce an explicit deterministic simulation clock and seed. +5. Replace remaining free-form task strings with action IDs/definitions. +6. Separate action selection, action execution, and visual travel. +7. Migrate wood and give the player the same extraction contract. +8. Build the first location-based food storage/inventory. +9. Make one NPC visibly gather, carry, store, retrieve, and eat food. +10. Build the first attractive Terrain3D simulation-garden layout. +11. Add simple stylized characters and profession readability. +12. Add save/load before the mutable world state becomes substantially larger. + +This order strengthens the simulation while regularly producing visible +progress suitable for public development updates. + +## Subjects intentionally deferred + +These are valuable future learning areas but should not distract from the first +complete slices: + +- multiplayer authority and replication; +- procedural terrain generation; +- machine-generated freeform dialogue; +- full historical demography; +- hundreds of item recipes; +- siege-scale combat; +- sophisticated market speculation; +- native GDExtension optimization; +- custom rendering technology. + +Revisit them when a completed slice demonstrates a concrete need. diff --git a/docs/PROJECT_CONTEXT.md b/docs/PROJECT_CONTEXT.md new file mode 100644 index 0000000..f612ece --- /dev/null +++ b/docs/PROJECT_CONTEXT.md @@ -0,0 +1,721 @@ +# The Steward — Project Context + +> Agent-facing context for understanding the project quickly. +> +> Snapshot basis: repository state after commit `e30d208`, July 2026. Treat the +> code as the source of truth when this document and the implementation differ. + +## Quick orientation + +**The Steward** is currently a small Godot prototype for an embodied village +simulation. Its larger purpose is to become a learning laboratory for a +performant, large-scale NPC simulation that can later power a systemic +open-world RPG. + +The current village is not intended to be the final game's scale. It is a +controlled environment in which to learn and validate: + +- NPC needs and decision-making; +- professions, work, inventories, and economic dependencies; +- actions, consequences, and world events; +- relationships, memories, rumours, and persistent history; +- emergent situations that can be surfaced as quests; +- simulation level of detail for a much larger population; +- readable world presentation and satisfying embodied play. + +The desired game is not an omniscient city builder and not primarily a scripted +quest RPG. The player exists physically inside the simulated society. + +## North-star vision + +> A systemic open-world RPG set around a city inspired by Jajce, Bosnia and +> Herzegovina, and its surrounding villages. Every important NPC participates +> in a simulated society, forms relationships, remembers events, and can affect +> history. The player can remain an ordinary citizen, pursue a profession, +> become a trader, criminal, warrior, or companion leader, command armies, and +> eventually lead a faction. + +The world should generate situations. Quests should primarily communicate, +frame, and track those situations rather than manufacture disconnected content. + +Example: + +1. A harvest fails or a trade route becomes unsafe. +2. Food scarcity raises pressure on households and professions. +3. An NPC steals, migrates, changes work, joins a criminal group, or asks a + relative for help. +4. Witnesses form memories and spread partial information. +5. Relationships, prices, safety, and faction attitudes change. +6. The player learns about the situation through observation, conversation, + rumours, employment, or authority. +7. Any intervention changes the same world state that produced the problem. + +The quest is therefore a view onto the simulation, not a parallel scripted +reality. + +## Product pillars + +### 1. Simulated lives + +NPCs should be people rather than production modifiers. Their needs, +professions, possessions, schedules, abilities, ambitions, and circumstances +drive their choices. + +### 2. Persistent history + +Important actions create structured events. Events can become memories, +knowledge, rumours, relationships, reputations, grudges, obligations, and +political consequences. + +### 3. Emergent narrative + +Authored content should provide rules, cultures, locations, characters, +archetypes, and exceptional story beats. Ordinary quests and conflicts should +preferably emerge from unresolved world conditions. + +### 4. Embodied freedom + +The player walks through the same spaces, uses the same resources, and +participates in the same institutions as NPCs. They can play at different +social scales without being forced toward rulership. + +### 5. Legible autonomy + +Complexity is valuable only when players can understand its consequences. The +game should expose why an NPC chose an action and show resources moving through +the world. + +### 6. Small stories inside a large world + +The eventual map may be large, but emotional attachment comes from recognizable +people and local consequences. Simulation scale must not turn everyone into an +anonymous number. + +### 7. Enjoyable action + +Movement and combat should be satisfying independently of the simulation. +Companions and armies should offer expressive, enjoyable control rather than +only statistical resolution. + +### 8. A recognizable setting + +The core region is inspired by Jajce: dramatic elevation, a fortified urban +center, rivers, a waterfall, wooded slopes, lakes, watermills, roads, farms, +and surrounding villages. This is an inspiration rather than a requirement for +a literal historical reconstruction. + +### 9. Cozy presentation with real stakes + +The presentation should feel warm, painterly, pastoral, and inviting while the +simulation remains capable of scarcity, conflict, death, political ambition, +and social change. + +## Build-in-public goals + +Visual appeal and watchability are prototype requirements, not final polish. +Each simulation feature should have a visible expression: + +| Simulation state | Visible expression | +| --- | --- | +| Hunger | Looking for food, checking storage, eating, asking, stealing, or weakening | +| Profession | Recognizable tools, clothing, workplace, route, and animation | +| Task choice | Purposeful movement plus optional task/thought icon | +| Production | Items visibly gathered, carried, stored, processed, and consumed | +| Relationship | Greeting, helping, arguing, avoiding, mourning, or celebrating | +| World event | Visible consequences and a concise event/history feed | +| Settlement change | Construction, depletion, prosperity, damage, migration, or recovery | + +Development clips should communicate cause and effect without requiring viewers +to read console logs. A cinematic/debug toggle should eventually allow the same +scenario to be shown both beautifully and analytically. + +## Visual direction + +The target is an original stylized look characterized by: + +- painterly natural colors and soft, warm lighting; +- readable, exaggerated terrain and building silhouettes; +- lush vegetation with restrained environmental motion; +- expressive, animation-friendly characters; +- appealing water, mist, smoke, weather, and seasonal variation; +- cozy settlements contrasted with a world capable of hardship; +- a clear elevated third-person view that makes NPC activity readable. + +Avoid generic high-fantasy spectacle and avoid treating visual style as a +reason to hide the underlying simulation. + +### Initial environment composition + +The first public-facing environment should be a compressed simulation garden, +not the complete region: + +- a fortress or fortified landmark on an upper ridge; +- a small settlement descending toward water; +- a river, bridge, and waterfall or strong vertical water feature; +- a mill channel and a small cluster of watermills; +- farm terraces and a wooded work area; +- a trade road and distant silhouettes that imply a larger world. + +Terrain3D should own broad landforms, ground surfaces, distant landscape, and +large-scale vegetation placement. Roads, river surfaces, waterfalls, cliffs +that require overhangs, bridges, walls, buildings, and other authored landmarks +should use dedicated meshes or appropriate spline/modular tooling. + +## Core player loop + +The intended loop is: + +1. **Observe** people, places, stores, and local problems. +2. **Understand** needs, causes, relationships, and competing priorities. +3. **Influence** people through work, trade, conversation, policy, reputation, + leadership, or force. +4. **Act** personally through movement, interaction, production, exploration, + and combat. +5. **Witness consequences** in the same people and systems. +6. **Adapt** to new opportunities and problems created by those consequences. + +The current prototype implements a very early version of observe, autonomous +task choice, physical travel, work completion, resource change, and direct +player assistance. Its abstract task zones are explicitly transitional; the +next world-object migration is documented in +[the ResourceNode plan](RESOURCE_NODE_MIGRATION.md). + +## Current technology + +- **Engine:** Godot 4.7 project configuration +- **Renderer feature:** Forward Plus +- **Language:** GDScript +- **Main scene:** `res://main.tscn` +- **Terrain:** Terrain3D 1.0.2 is installed and enabled +- **Terrain compatibility floor:** Godot 4.4 according to the bundled extension +- **Version control:** Git +- **Primary branch:** `main` +- **Commit convention:** Conventional Commits + +Terrain3D includes binaries, source, editor tooling, examples, and a `demo/` +directory. Most files under `addons/terrain_3d/` and `demo/` are third-party +plugin content, not game architecture. + +## Current playable state + +### World and player + +- `main.tscn` contains a flat approximately 30×30 prototype ground. +- The player is a `CharacterBody3D` represented by placeholder primitive + geometry. +- 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. +- `Escape` releases captured mouse input. + +### Village simulation + +The simulation currently creates three NPCs: + +- Amina +- Tarik +- Jasmin + +Each receives a random profession from: + +- farmer; +- woodcutter; +- guard; +- scholar; +- wanderer. + +Each simulated NPC currently stores: + +- stable integer ID for the session; +- name and profession; +- hunger and energy; +- strength and intelligence; +- current task and task state; +- task duration and progress; +- simulated position; +- starvation state and duration; +- death state. + +The village currently tracks: + +- food, initially `20`; +- wood, initially `10`; +- safety, initially `50`; +- knowledge, initially `0`; +- per-resource modifiers; +- per-resource priorities. + +### NPC task lifecycle + +Task states are: + +```text +idle -> traveling -> working -> complete -> idle +``` + +NPCs currently choose among: + +- gather food; +- gather wood; +- patrol; +- study; +- eat; +- rest; +- wander. + +Needs override ordinary work. Otherwise a utility-like score combines: + +- village priority; +- critical and low resource thresholds; +- profession preference; +- a small random contribution. + +The visual NPC walks toward the task's marker. Arrival tells the simulation to +start work. Work progresses on simulation ticks. The village receives the +result only when the task duration completes. + +Starvation can reduce productivity and eventually kill an NPC. Dead visuals +stop moving, change appearance, and no longer collide. + +### Current task zones + +The main scene contains placeholder zones for: + +- farm; +- forest; +- guard duty; +- study; +- rest; +- food. + +The farm, forest, guard, study, rest, and food locations are represented by +primitive geometry and a few tree assets. + +These markers are not the intended long-term work model. Food and wood should +first migrate to finite world `ResourceNode` instances. 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. + +### Current UI + +A small village panel displays: + +- food; +- wood; +- safety; +- knowledge; +- starving NPC count; +- selected village modifiers. + +Most deeper reasoning is currently visible only through verbose debug output. + +## Runtime architecture + +### `simulation/SimNPC.gd` + +`SimNPC` is a `RefCounted` simulation model. It owns needs, task selection, +task progression, profession affinity, starvation, and death. + +This separation from the visual node is an important architectural seed and +should be preserved. + +### `simulation/SimVillage.gd` + +`SimVillage` is a `RefCounted` aggregate for shared resources, modifiers, +priorities, and applying completed NPC work. + +### `simulation/SimulationManager.gd` + +`SimulationManager` is currently a scene-tree `Node` that: + +- owns the village and NPC array; +- advances a tick approximately every 1.2 seconds; +- creates NPCs; +- coordinates task completion; +- emits village, task, and death signals; +- exposes direct resource-changing methods to the player. + +It currently combines clock, orchestration, event publication, population +creation, and some gameplay API responsibilities. + +### `world/world_view_manager.gd` + +`WorldViewManager` bridges simulation data to visible NPC nodes. It: + +- instantiates `NpcVisual` scenes; +- maps task strings to world markers; +- sends targets to visuals; +- reports arrival back to `SimulationManager`; +- applies visual death state. + +### `player/npc/NpcVisual.gd` + +`NpcVisual` is the active-world representation of an NPC. It currently: + +- owns a `NavigationAgent3D`; +- obtains a navigation path; +- moves and rotates toward path points; +- reports arrival; +- applies a simple death presentation. + +### `player/player.gd` and `player/camera_rig.gd` + +These implement camera-relative character movement, physical interaction +proximity checks, mouse capture, and the elevated follow camera. + +### `world/ui/ui.gd` + +The UI subscribes to village changes and formats aggregate village state. + +## Current runtime flow + +```text +SimulationManager tick + | + v +SimNPC updates needs and chooses/advances a task + | + v +npc_task_changed signal + | + v +WorldViewManager selects a task-zone marker + | + v +NpcVisual navigates through the active world + | + v +arrived_at_target signal + | + v +SimulationManager marks the NPC as working + | + v +Later ticks complete work + | + v +SimVillage applies production/consumption + | + v +village_changed signal updates the UI +``` + +## Repository map + +```text +. +├── addons/terrain_3d/ Third-party Terrain3D plugin +├── assets/foliage/ Early tree assets +├── demo/ Terrain3D's bundled demo, not the game +├── docs/ Project context and plans +├── player/ +│ ├── camera_rig.gd +│ ├── player.gd +│ ├── PlayerInteraction.gd Currently an empty placeholder +│ └── npc/ +│ ├── NpcVisual.gd +│ └── NpcVisual.tscn +├── simulation/ +│ ├── SimNPC.gd +│ ├── SimVillage.gd +│ └── SimulationManager.gd +├── world/ +│ ├── world_view_manager.gd +│ └── ui/ui.gd +├── main.tscn +└── project.godot +``` + +## Important limitations and technical debt + +These are expected prototype constraints, not necessarily isolated bugs: + +- Task names and task-to-zone mappings are duplicated strings. +- Task zones are abstract destinations rather than real usable world objects. +- 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. +- Resources are global floating-point counters rather than items in locations + and inventories. +- NPCs do not have homes, schedules, possessions, memories, relationships, + goals, or social knowledge. +- NPC reasoning is logged but not presented through an in-game inspector. +- Active navigation is used as if all agents are local; no simulation LOD exists. +- There is no spatial query/index layer for large populations. +- Simulation, orchestration, and player-facing mutation APIs are concentrated + in `SimulationManager`. +- Path failure and interruption behavior is minimal. +- Terrain3D is enabled but not yet used by the main game scene. +- Combat, companions, factions, politics, trade, rumours, quests, persistence, + and regional travel do not yet exist. +- Placeholder geometry is sufficient for debugging but not for build-in-public + presentation. + +## Target simulation architecture + +### Separate definitions, state, systems, and presentation + +Use four conceptual layers: + +1. **Definitions** — immutable data for needs, actions, professions, items, + traits, event types, and locations. +2. **State** — serializable runtime records for NPCs, inventories, + relationships, settlements, factions, and history. +3. **Systems** — clocks, scoring, action resolution, economy, relationships, + events, rumours, and persistence. +4. **Presentation adapters** — Godot nodes that render nearby state, accept + player input, play animation, and provide UI. + +Do not make the simulation core depend on `Node3D`, scene paths, animation, +physics frames, or a currently loaded map. + +### Stable identity + +Every persistent entity should eventually have a stable ID: + +- person; +- household; +- item stack or significant item; +- building; +- workplace; +- settlement; +- faction; +- location; +- event. + +References between simulation records should use IDs rather than live node +references. + +### Fixed and deterministic time + +The simulation should advance with an explicit clock and controlled random +source. Given the same starting state, seed, and player commands, a headless +run should be reproducible. + +This enables: + +- debugging; +- automated scenario tests; +- balancing; +- replaying build-in-public demonstrations; +- comparing performance before and after optimization. + +### Scheduled work rather than per-frame thinking + +At scale, agents should wake for relevant decisions or scheduled updates rather +than running full reasoning every frame. Examples include: + +- need threshold crossed; +- action completed or interrupted; +- new information received; +- path or workplace became unavailable; +- daily schedule boundary; +- relationship or faction event; +- periodic low-frequency maintenance. + +### Simulation fidelity levels + +The eventual world needs multiple representations: + +1. **Active:** full node, physics, navigation, perception, animation, and combat. +2. **Local abstract:** individual position and scheduled actions without + continuous physics. +3. **Distant individual:** data-only people resolving travel and work by time. +4. **Settlement aggregate:** carefully chosen economic or demographic + aggregation for populations that do not currently need individual detail. + +Moving between levels must preserve identity and important state. Aggregation +must not erase named relationships or unresolved history. + +### Action model + +Actions should become data-driven definitions with: + +- preconditions; +- candidate targets; +- utility considerations; +- expected duration; +- reservations; +- resource costs; +- effects; +- interruption rules; +- visible presentation hints; +- reason tracing. + +The first implementation can remain utility-based. Do not add a complex +planner until current action scoring and sequencing demonstrate a concrete need. + +### Events and history + +Important outcomes should create structured facts rather than prose-only logs. +A future event record might contain: + +```text +event_id +event_type +simulation_time +location_id +actor_ids +target_ids +witness_ids +cause_event_ids +resource_changes +relationship_changes +visibility/secrecy +tags +``` + +Memories, rumours, reputation, and quests should reference or transform these +facts. Generated text is presentation; structured state remains authoritative. + +### Emergent quest principle + +A quest candidate should normally require: + +- a real unresolved condition; +- an NPC or institution that knows or cares about it; +- a plausible way to communicate it; +- one or more achievable interventions; +- consequences that update the source simulation. + +Avoid creating a duplicate quest-only bandit, item, victim, or relationship +when an existing simulated entity can provide the situation. + +### Performance principle + +Design for scale, but optimize measured bottlenecks: + +- keep headless benchmarks; +- record agent count, simulated duration, tick cost, and allocations; +- prefer event-driven/scheduled updates; +- use spatial partitioning for local queries; +- batch homogeneous work when profiling justifies it; +- avoid premature native extensions or data-oriented rewrites before the + behavior model stabilizes. + +## Development strategy + +The project has two interleaved tracks. + +### Living simulation + +- deterministic clock and state; +- data-driven needs, professions, and actions; +- inventories and economic flow; +- events, history, relationships, and rumours; +- simulation LOD and performance; +- emergent opportunities and quests. + +### Living presentation + +- Jajce-inspired terrain composition; +- attractive lighting, water, foliage, and weather; +- readable characters and professions; +- visible work, transport, and consequences; +- interaction UI and simulation inspection; +- combat feel, companions, and command feedback. + +Every major systems milestone should produce a shareable visual behavior. Every +visual milestone should support or reveal actual simulation state. + +## Immediate milestone: the simulation garden + +Before integrating Terrain3D into the playable runtime, migrate food and wood +from abstract zones to finite resource nodes on the current flat test map. This +keeps target-selection and resource-conservation debugging separate from terrain +and navigation changes. + +The next coherent visual slice should then aim for: + +- one attractive valley section; +- six named villagers; +- three visibly distinct workplaces; +- food and wood as location-based resources; +- visible gathering, carrying, storing, and consuming; +- hunger and energy; +- one understandable shortage crisis; +- direct player assistance and priority influence; +- day/night presentation; +- an in-game reason inspector; +- deterministic replay or scenario reset; +- save/load for the slice; +- a stable 20–30 minute session. + +Safety and knowledge can remain present, but their deeper production chains +should follow a complete food loop rather than grow in parallel. + +## Out of scope until the simulation garden works + +- full regional map; +- large city population; +- multiplayer; +- procedural world generation; +- generations and inheritance; +- complete market simulation; +- kingdom-scale diplomacy; +- large battles; +- broad crafting catalog; +- fully generated dialogue; +- multiple large production chains; +- production-quality character customization. + +These remain part of the vision, not the next implementation target. + +## Agent working guidelines + +1. Read this document, [the learning roadmap](LEARNING_ROADMAP.md), + [the ResourceNode migration](RESOURCE_NODE_MIGRATION.md), and + [the build-in-public plan](BUILD_IN_PUBLIC_PLAN.md) before proposing a large + architectural or world-production change. +2. Inspect `git status` and preserve unrelated user changes. +3. Treat `addons/terrain_3d/` and `demo/` as third-party code unless a task + explicitly concerns the plugin. +4. Preserve Godot `.uid` and asset `.import` sidecars. They are tracked project + metadata; `.godot/` is the disposable cache. +5. Keep simulation rules independent of visuals and loaded scenes. +6. Prefer small vertical behavior slices over broad scaffolding. +7. When adding a decision, add a way to inspect why it occurred. +8. When adding persistent state, define how it saves and migrates. +9. When optimizing, include a reproducible benchmark or measurement. +10. Keep new systems data-driven only where it improves reuse or iteration; + avoid abstraction without a demonstrated consumer. +11. Use Conventional Commits. +12. Update these documents when a decision materially changes the vision, + architecture, milestones, or current-state description. + +## Definition of “reusable for the future game” + +A system is reusable when: + +- it has no dependency on this prototype's scene paths or placeholder zones; +- definitions can be supplied as data; +- mutable state is serializable; +- behavior can be exercised headlessly; +- presentation communicates through an adapter or events; +- performance characteristics are measured; +- its public API is documented by real use, not speculative abstraction. + +Reusable does not necessarily mean a separate Godot plugin. Extract a library +only after the API has stabilized through use. + +## Glossary + +- **Active NPC:** A fully represented nearby character with a Godot scene node. +- **Agent:** A simulated decision-making entity, usually an NPC. +- **Event:** A structured fact that something happened in world time. +- **History:** Persisted events and their enduring consequences. +- **Memory:** An NPC's retained interpretation or knowledge of events. +- **Presentation adapter:** Code that translates simulation state into scenes, + animation, audio, UI, and player input. +- **Quest:** A player-facing framing and tracking mechanism for an opportunity + or unresolved condition. +- **Reason trace:** Data explaining the inputs and scores behind a decision. +- **Simulation garden:** A small, attractive, controlled world used to validate + deep systems and make them watchable. +- **Simulation LOD:** Changing computational fidelity based on relevance while + preserving important identity and state. +- **World event:** A consequential state transition that may be witnessed, + remembered, communicated, and acted upon. diff --git a/docs/RESOURCE_NODE_MIGRATION.md b/docs/RESOURCE_NODE_MIGRATION.md new file mode 100644 index 0000000..5de991f --- /dev/null +++ b/docs/RESOURCE_NODE_MIGRATION.md @@ -0,0 +1,517 @@ +# The Steward — ResourceNode Migration Plan + +## Decision + +The current task zones are temporary prototype scaffolding. + +NPCs and the player should ultimately interact with actual world objects rather +than travel to one abstract marker per task: + +```text +Current: +gather_food -> FarmZone -> village food increases + +First migration: +gather_food -> choose BerryBush_01 -> travel to its interaction point + -> extract berries -> bush amount decreases + -> village food increases by the extracted amount +``` + +This migration should happen on the current flat map before the Jajce +environment is integrated. It is easier to debug target selection, reservation, +depletion, and task completion without terrain and navigation changes happening +at the same time. + +The old zones remain only as a temporary fallback while actions are migrated. +They are not part of the target architecture. + +## Why this is the next systems step + +Resource nodes provide the first concrete bridge between: + +- abstract simulation decisions; +- spatial target selection; +- active-world navigation; +- finite world state; +- visible cause and effect; +- player and NPC use of the same objects; +- future inventories, ownership, regeneration, and persistence. + +They also make build-in-public footage more legible. A viewer can understand a +villager walking to a specific berry bush and depleting it more easily than a +villager entering an invisible “food zone.” + +## Scope the first version correctly + +The first `ResourceNode` supports only depletable material sources: + +- berry bush or crop source -> food; +- tree or wood pile -> wood. + +Do not initially use `ResourceNode` for: + +- beds or campfires; +- guard posts; +- study locations; +- food storage; +- homes; +- generic workstations. + +Those objects share target-selection behavior but not resource-extraction +semantics. + +The likely family of world targets is: + +```text +WorldActionTarget +├── ResourceNode finite extraction: bush, tree, ore +├── ActivitySite rest, patrol, study, socialize +├── StorageNode deposit and withdraw items +└── Workstation transform inputs into outputs +``` + +Do not implement this complete inheritance tree now. Build `ResourceNode` from +real requirements, then extract shared target behavior when a second target +type proves what is actually common. + +## Fit with the current code + +The existing flow is: + +```text +SimNPC chooses a task string + -> SimulationManager emits npc_task_changed + -> WorldViewManager maps the task to one Marker3D + -> NpcVisual travels to that marker + -> arrival tells SimulationManager to start work + -> task duration completes + -> SimVillage applies a hard-coded task result +``` + +The migrated flow should become: + +```text +SimNPC chooses an action + -> target resolver finds available matching ResourceNodes + -> one target is reserved for the NPC + -> NPC simulation stores the target's stable ID + -> NpcVisual travels to the target interaction point + -> arrival begins work + -> completion extracts the actual available amount + -> village receives exactly that amount + -> target updates or becomes depleted + -> reservation is released +``` + +During migration: + +```text +gather_food -> prefer matching ResourceNode -> fallback FarmZone +gather_wood -> prefer matching ResourceNode -> fallback ForestZone +other tasks -> existing zones +``` + +Fallbacks should log clearly so accidental reliance on zones is visible. + +## Repository-specific file layout + +Keep scripts beside their feature scenes, matching the repository's existing +feature-oriented structure: + +```text +world/ +└── resource_nodes/ + ├── ResourceNode.gd + ├── ResourceNode.gd.uid + └── ResourceNode.tscn +``` + +Add instances under the current `main.tscn` while developing: + +```text +Main +├── ResourceNodes +│ ├── BerryBush_01 +│ ├── BerryBush_02 +│ ├── Tree_01 +│ └── Tree_02 +└── TaskZone temporary fallback +``` + +When `JajceWorld` is integrated, move or recreate the world-object instances +under: + +```text +JajceWorld +└── WorldObjects + └── ResourceNodes +``` + +Target discovery must not depend on that exact scene path. Resource nodes should +register through a group or a small registry. + +## First ResourceNode contract + +The first node should answer: + +- What is my stable world-object ID? +- Which action can use me? +- Which resource do I yield? +- How much remains? +- How much can one completed action extract? +- Am I enabled and usable? +- Who, if anyone, has reserved me? +- Where should an active character stand? +- Did extraction change or deplete me? + +Recommended initial data: + +```gdscript +class_name ResourceNode +extends Node3D + +signal amount_changed(node_id: StringName, amount_remaining: float) +signal depleted(node_id: StringName) +signal reservation_changed(node_id: StringName, agent_id: int) + +@export var node_id: StringName +@export var action_id: StringName = &"gather_food" +@export var resource_id: StringName = &"food" +@export var amount_remaining: float = 10.0 +@export var yield_per_action: float = 2.0 +@export var enabled: bool = true +@export var can_npcs_use: bool = true +@export var can_player_use: bool = true +@export var hide_visual_when_depleted: bool = false + +@onready var interaction_point: Marker3D = $InteractionPoint +``` + +Use `StringName` IDs as a small migration step away from duplicated free-form +`String` values. Later, action and resource definitions can become custom +`Resource` assets without changing every world node's conceptual contract. + +### Avoid duplicated state + +Do not store a separately mutable `is_depleted` flag in the first version. +Derive it: + +```gdscript +func is_depleted() -> bool: + return amount_remaining <= 0.0 +``` + +If regeneration or non-depleting sources later require more states, introduce +them deliberately. + +### Extraction result is authoritative + +Extraction must return the amount actually removed: + +```gdscript +func extract(requested_amount: float = yield_per_action) -> float: + if not can_extract(): + return 0.0 + + var extracted := minf(requested_amount, amount_remaining) + amount_remaining -= extracted + # Emit signals and update presentation. + return extracted +``` + +The village receives this returned amount. Do not let both `ResourceNode` and +`SimVillage.apply_npc_task()` independently award the configured yield. + +### Stable IDs + +`node_id` must be: + +- non-empty; +- unique inside the world; +- stable across save/load; +- independent of display name and scene path. + +For the first hand-authored nodes, explicit IDs such as +`&"berry_bush_01"` are acceptable. Add startup validation for duplicates. + +## Scene structure + +The first reusable scene can remain small: + +```text +ResourceNode (Node3D) +├── Visual (Node3D) +├── InteractionPoint (Marker3D) +└── DebugLabel (Label3D) +``` + +Use `Node3D` for `Visual` rather than requiring `MeshInstance3D`; this permits a +mesh, imported model, particles, or multiple visual children later. + +The debug label should be controlled by a project/debug setting or inspector +toggle rather than a compile-time constant. It should show: + +- node ID; +- resource; +- remaining amount; +- reservation owner; +- depleted/disabled state. + +## Reservation rules + +Without reservations, several NPCs can choose one nearly depleted bush and all +walk toward it. + +The first version needs a single-user reservation: + +```text +available -> reserved by agent -> in use -> released +``` + +A reservation must be released when: + +- the task completes; +- the NPC dies; +- the target depletes; +- travel fails; +- the action is interrupted or replaced; +- the target is disabled; +- the NPC or visual is removed. + +Reservation is not ownership. Ownership, permission, crime, and social +consequences belong to later systems. + +## Target selection + +The first resolver may choose the nearest available matching node. It must still +return a reason trace: + +```text +candidate BerryBush_01: accepted, distance 8.2 +candidate BerryBush_02: rejected, reserved by NPC 2 +candidate BerryBush_03: rejected, depleted +selected BerryBush_01 +``` + +Future scoring can include: + +- travel cost; +- remaining yield; +- danger; +- tool requirements; +- ownership and permission; +- crowding; +- profession; +- expected completion time; +- knowledge of the target. + +Do not implement those before the nearest-available version works. + +## Simulation-state boundary + +The first `ResourceNode` is a Godot world node and may temporarily own its +remaining amount. That is acceptable for the migration prototype, but it is not +the final persistence boundary. + +Preserve these rules now: + +- `SimNPC` stores a target ID, not a `Node` reference; +- simulation decisions do not store `NodePath`; +- visual movement receives only a resolved position; +- target extraction is coordinated through one adapter/registry; +- node state has an obvious serialization representation. + +Later, authoritative resource state can move into serializable simulation +records while `ResourceNode` becomes its active-world presentation. + +## Required changes by existing file + +### `simulation/SimNPC.gd` + +- add a selected target ID; +- clear it when returning to idle or changing actions; +- do not store `ResourceNode` references; +- preserve current task lifecycle during the first migration. + +### `world/world_view_manager.gd` + +- query available resource nodes for `gather_food` and `gather_wood`; +- reserve the selected target; +- send its interaction position to `NpcVisual`; +- use the old marker only when no valid node exists; +- distinguish arrival at a specific target from arrival at a generic task zone. + +Target discovery can begin here, but should move into a focused resolver or +registry once selection has meaningful rules. + +### `simulation/SimulationManager.gd` + +- coordinate target completion and reservation release; +- extract from the selected node once; +- give `SimVillage` the actual result; +- handle interruption, death, and failure cleanup; +- prevent old hard-coded production from also firing. + +### `simulation/SimVillage.gd` + +- add an explicit resource-delta method; +- separate generic resource application from task-name matching; +- retain current action effects for non-migrated tasks. + +### `player/player.gd` + +- eventually resolve and use the same world targets as NPCs; +- do not add a second player-only harvest path with different rules. + +Player use can follow NPC migration rather than block its first test. + +## Migration phases + +### Phase 1 — ResourceNode scene and registration + +- create `ResourceNode.gd` and `ResourceNode.tscn`; +- create a `ResourceNodes` parent in `main.tscn`; +- place two bushes and two trees; +- give every node a stable unique ID; +- show debug state; +- expose group/registry discovery. + +**Exit:** nodes register, validate IDs, change amount, deplete, and update debug +presentation without involving NPC logic. + +### Phase 2 — Food target selection and reservation + +- migrate only `gather_food`; +- find nearest available bush; +- reserve it; +- store its ID on the NPC; +- navigate to its interaction point; +- release on interruption and death; +- retain `FarmZone` fallback with a visible warning. + +**Exit:** two NPCs do not select the same single-user bush, and an NPC can +replan when its chosen bush becomes unavailable. + +### Phase 3 — Authoritative completion + +- extract only after work duration completes; +- return actual extracted amount; +- apply that amount to village food; +- prevent double production; +- deplete and hide/alter the source as configured; +- choose a new source for later tasks. + +**Exit:** resource conservation holds: + +```text +total bush decrease == total village food increase +``` + +for the initial gather-food scenario. + +### Phase 4 — Wood and player parity + +- migrate `gather_wood`; +- configure tree visuals and yields; +- route player interaction through the same extraction contract; +- add clear feedback for unavailable or depleted targets. + +**Exit:** food and wood no longer require their abstract zones during normal +play. NPC and player extraction obey the same availability and depletion rules. + +### Phase 5 — Jajce world placement + +- place bushes and trees as real world objects in `JajceWorld`; +- keep their IDs stable; +- validate interaction points against terrain and navigation; +- use the old task zones only for rest, eat, patrol, and study; +- verify target discovery does not rely on parent scene paths. + +**Exit:** the existing food and wood loops work after moving from the flat map +to Terrain3D. + +### Phase 6 — Remove the remaining zone model + +This is not part of the first ResourceNode implementation. + +Introduce the next concrete target types: + +- storage for eating and item transfer; +- activity sites for rest, study, and guard work; +- workstations when production recipes begin. + +Remove each old zone only when its replacement has: + +- target selection; +- active interaction position; +- reservation/capacity; +- completion or ongoing-use behavior; +- failure/interruption handling; +- debug visibility; +- save representation. + +**Exit:** `TaskZone` and task-to-marker mapping are deleted, not merely unused. + +## Test scenarios + +At minimum, exercise: + +1. one NPC and one bush; +2. two NPCs and one bush; +3. one NPC and two bushes at different distances; +4. selected bush depletes before arrival; +5. selected bush depletes exactly on completion; +6. NPC dies while traveling; +7. NPC dies while working; +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; +12. duplicate node IDs are detected. + +Use a fixed seed and concise reason tracing where possible. + +## Video opportunities + +The migration naturally creates strong short-form demonstrations: + +- “My NPCs stopped walking to invisible work zones.” +- “Two hungry villagers want the same berry bush.” +- “This bush contains the food—the UI counter no longer creates it.” +- “What happens when the closest resource is already reserved?” +- “A depleted forest changes what every woodcutter decides.” + +Show the beautiful result first, then reveal target selection, reservation, and +resource conservation through debug presentation. + +## Immediate implementation order + +1. Create `world/resource_nodes/ResourceNode.gd`. +2. Create `world/resource_nodes/ResourceNode.tscn`. +3. Add `Main/ResourceNodes`. +4. Place `BerryBush_01`, `BerryBush_02`, `Tree_01`, and `Tree_02`. +5. Add stable IDs and registration validation. +6. Verify extraction and depletion manually. +7. Add target ID to `SimNPC`. +8. Migrate `gather_food` target selection. +9. Add reservation and cleanup. +10. Apply actual extracted yield on completion. +11. Add fixed-seed regression scenarios. +12. Migrate wood. +13. Give the player the same extraction path. +14. Continue with the Jajce world scaffold. + +## Definition of done for the first migration + +- 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. +- Work duration completes before extraction. +- Village resources increase only by the amount actually extracted. +- Depletion changes availability and presentation. +- Failure, interruption, and death release reservations. +- Old food and forest zones remain only as logged fallbacks. +- The player and NPCs can use the same extraction contract. +- Behavior is inspectable and covered by reproducible scenarios. + diff --git a/player/npc/NpcVisual.gd b/player/npc/NpcVisual.gd index 28adc3f..2367314 100644 --- a/player/npc/NpcVisual.gd +++ b/player/npc/NpcVisual.gd @@ -18,7 +18,8 @@ var profession: String = "" var current_path: PackedVector3Array = [] var path_index := 0 var current_target := Vector3.INF -var arrival_distance := 0.6 +var arrival_distance := 1.5 +var stuck_counter := 0 var is_dead_visual := false var dead_material := StandardMaterial3D.new() @@ -60,7 +61,8 @@ func set_target_position(pos: Vector3) -> void: path_index = 0 if current_path.is_empty(): - debug_log("Path is empty. Will report arrival/failure fallback.") + debug_log("Path is empty, stuck counter will handle fallback.") + nav_agent.target_position = global_position else: debug_log("New target: %s Path points: %s" % [pos, current_path.size()]) @@ -84,6 +86,10 @@ func _physics_process(delta: float) -> void: if current_path.is_empty() or path_index >= current_path.size(): velocity = Vector3.ZERO move_and_slide() + stuck_counter += 1 + if stuck_counter > 90: + debug_log("Stuck with no valid path, reporting arrival") + _report_arrival_once() return var next_pos := current_path[path_index] @@ -95,6 +101,7 @@ func _physics_process(delta: float) -> void: return var direction := to_next.normalized() + var prev_pos := global_position velocity.x = direction.x * move_speed velocity.z = direction.z * move_speed @@ -102,6 +109,15 @@ func _physics_process(delta: float) -> void: move_and_slide() + if global_position.distance_squared_to(prev_pos) < 0.001: + stuck_counter += 1 + if stuck_counter > 90: + debug_log("Stuck while navigating, reporting arrival") + _report_arrival_once() + return + else: + stuck_counter = 0 + var target_angle := atan2(direction.x, direction.z) rotation.y = lerp_angle(rotation.y, target_angle, rotation_speed * delta) diff --git a/player/npc/NpcVisual.tscn b/player/npc/NpcVisual.tscn index 85484f3..9b9f9d0 100644 --- a/player/npc/NpcVisual.tscn +++ b/player/npc/NpcVisual.tscn @@ -13,6 +13,8 @@ albedo_color = Color(1, 0.22352941, 1, 1) material = SubResource("StandardMaterial3D_d844k") [node name="NpcVisual" type="CharacterBody3D"] +collision_layer = 2 +collision_mask = 1 script = ExtResource("1_ixfoq") [node name="CollisionShape3D" type="CollisionShape3D" parent="."] diff --git a/simulation/SimNPC.gd b/simulation/SimNPC.gd index dc36816..c570ae3 100644 --- a/simulation/SimNPC.gd +++ b/simulation/SimNPC.gd @@ -28,6 +28,8 @@ var task_duration := 0.0 var task_progress := 0.0 var task_complete := true var target_id: StringName = &"" +var retry_count := 0 +var last_task := "" func _init( _id: int, @@ -227,6 +229,9 @@ func calculate_task_score( if profession == preferred_profession: score += 2.0 + if task_name == last_task: + score -= 1.5 + score += randf_range(0.0, 0.5) if DEBUG_LOGS: @@ -242,6 +247,7 @@ func calculate_task_score( return score func set_task(task: String, duration: float) -> void: + last_task = current_task current_task = task task_duration = duration task_progress = 0.0 diff --git a/simulation/SimulationManager.gd b/simulation/SimulationManager.gd index 11fa421..1cc68d3 100644 --- a/simulation/SimulationManager.gd +++ b/simulation/SimulationManager.gd @@ -98,6 +98,7 @@ func simulate_tick() -> void: village.apply_npc_task(npc) village_was_changed = true + npc.retry_count = 0 npc.task_complete = true npc.task_state = SimNPC.TASK_STATE_IDLE @@ -110,6 +111,15 @@ func simulate_tick() -> void: if DEBUG_LOGS: print("[SimulationManager] ", npc.npc_name, " gathered food while starving and is going to eat immediately.") + if npc.task_state == SimNPC.TASK_STATE_TRAVELING and npc.target_id == &"": + npc.retry_count += 1 + if npc.retry_count >= 5: + if DEBUG_LOGS: + print("[SimulationManager] ", npc.npc_name, " stuck traveling without target for ", npc.retry_count, " attempts, replanning") + npc.task_state = SimNPC.TASK_STATE_IDLE + npc.current_task = "" + npc.retry_count = 0 + if DEBUG_LOGS: print( npc.npc_name, @@ -176,6 +186,8 @@ func notify_npc_arrived(npc_id: int) -> void: print("[SimulationManager] ", npc.npc_name, " arrived but target ", npc.target_id, " is unavailable, replanning") release_npc_reservation(npc.id) npc.task_state = SimNPC.TASK_STATE_IDLE + npc.current_task = "" + npc.retry_count += 1 return npc.start_working() diff --git a/world/world_view_manager.gd b/world/world_view_manager.gd index 24c63a8..9afcf0c 100644 --- a/world/world_view_manager.gd +++ b/world/world_view_manager.gd @@ -88,10 +88,19 @@ func update_npc_targets() -> void: visual.set_target_position(resource_pos) continue - var target = get_target_for_task(npc.current_task) + var task = npc.current_task + if task == "wander": + var offset = Vector3(randf_range(-6.0, 6.0), 0.0, randf_range(-6.0, 6.0)) + visual.set_target_position(visual.global_position + offset) + continue + + if task in ["gather_food", "gather_wood"]: + continue + + var target = get_target_for_task(task) if target == null: - debug_log("No target for task: %s" % npc.current_task) + debug_log("No target for task: %s" % task) continue visual.set_target_position(target.global_position) @@ -136,6 +145,7 @@ func _try_get_resource_target(npc: SimNPC, task: String) -> Variant: return null npc.target_id = node.node_id + npc.retry_count = 0 debug_log("%s reserved %s for %s" % [npc.npc_name, node.node_id, task]) return node.interaction_point.global_position @@ -152,6 +162,14 @@ func _on_npc_task_changed(npc: SimNPC, old_task: String, new_task: String) -> vo visual.set_target_position(resource_pos) return + if new_task == "wander": + var offset := Vector3(randf_range(-6.0, 6.0), 0.0, randf_range(-6.0, 6.0)) + visual.set_target_position(visual.global_position + offset) + return + + if new_task in ["gather_food", "gather_wood"]: + return + var target := get_target_for_task(new_task) if target != null: