ProfessionDefinition gains schedule_offset (-0.12 to +0.12 fraction of day). ActionSelectionSystem shifts each NPC's effective time_of_day by their profession offset before determining sleep/meal/work periods. Farmers wake earliest (-0.04h = ~2:38am), woodcutters slightly early (-0.02h), guards slightly late (+0.02h), scholars latest (+0.05h = ~5:45am). Wanderers have no offset. The village now has naturally staggered rhythms instead of everyone doing the same thing at the same time.
NPCs whose home positions are within 4m of each other gain mutual familiarity at baseline 0.5. Stored per NPC as a Dictionary keyed by other npc_id, serialized through NPCStateRecord with backward-compatible fallback for old saves. Household pairs form naturally from the home_positions configuration in main.tscn. Includes save/load round-trip test verifying familiarity persists.
Add narrative event types (task_started, npc_slept, npc_died, resource_depleted) alongside economic transfers. EconomicEventRecord gains create_narrative factory and human-readable description method. SimulationManager records task-start and sleep/death events, exposes get_npc_events() for per-NPC history queries. Inspector now shows a Recent timeline of the last 5 events for the selected NPC, plus displays carried wood count. Relax EconomicEventRecord validation to accept non-economic events. Update roadmap with completed milestones.
Wood now follows the same gather-carry-deposit pattern as food. NPCs put harvested wood into inventory, walk to the VillageWoodpile StorageNode, and deposit it. Village wood syncs from storage. Player harvesting also routes wood to the woodpile. ActiveWorldAdapter exposes woodpile routing for DEPOSIT_WOOD action targeting. WorldViewManager recognizes wood inventory changes. Tests verify woodpile node existence, storage ID, navigation reachability, and adapter routing.
Add ACTION_SLEEP with home-position targeting and energy restoration. Embed schedule periods (SLEEP/MEAL/WORK/DISCRETIONARY) in ActionSelectionSystem with TimeOfDay from SimulationClock. NPCs sleep at night when energy is low, eat during meal periods when hungry, and work/discretionary the rest of the cycle. Home position stored per NPC and serialized through NPCStateRecord with backward-compatible fallback. Cycle duration persisted through save/restore. Includes headless test for sleep period, work period, meal hunger, energy restoration, serialization round-trip, and home targeting without world adapter.
Adds Elma, Mirza, and Lejla to the village alongside Amina, Tarik, and Jasmin. Profession assignment is deterministic per-NPC-id RNG so the original three retain their seeded professions. jajce_runtime_integration_test updated to expect six villagers. All 10 scenarios pass.
Auto-format all GDScript files using gdformat from gdtoolkit.
This is a baseline formatting pass to ensure consistent style:
- Normalizes indentation and spacing
- Wraps long lines to 100 characters
- Removes trailing whitespace
- Standardizes blank lines between functions
68 files reformatted, 8 files left unchanged (3rd-party addon files
with parse errors excluded).
- Add 3 Terrain3D texture assets (limestone, valley grass, warm soil)
- Sculpt initial Terrain3D heightmap with ridge, valley, waterfall drop
- Replace plain water with emissive-tinged material
- Add foam mesh, mist spheres, and procedural sky with valley fog
- Add 10 StylizedTree instances around village perimeter
- Enable directional light shadows with extended cascade range
- Add tree height snapping to terrain surface
- Add refined scaffold tests for material count, terrain height, foliage, sky, fog
- Add terrain texture PNGs and StylizedTree.tscn scene
- Add generate_jajce_terrain.gd tool
- NpcVisual emits position_changed signal during _physics_process
- SimulationManager.synchronize_npc_position() writes active position
into SimNPC state on movement, arrival, and navigation failure
- WorldViewManager forwards position_changed and syncs before
despawn/reload
- SimNPC stores travel_target_position and has_travel_target as
versioned state; NPCStateRecord v2 persists them with v1 migration
- WorldViewManager.spawn_npc_visual() resumes travel for traveling NPCs
via SimulationManager.request_current_travel()
- WorldViewManager.despawn_npc_visual() syncs position before removal
- WorldViewManager.reload_npc_visual() spawns a visual from persisted
state without rerolling target selection
- tests/npc_visual_lifecycle_test.gd proves unload/reload preserves
action, target, reservation, position, RNG state, and checksum
- simulation_state_serialization_test adds legacy v1 NPC migration test
that does not invent an active travel target
Replace implicit randomness with seeded per-NPC RandomNumberGenerator
streams so the same seed always produces the same scenario outcome.
- Add SimulationClock (RefCounted): explicit fixed-step clock that
converts frame delta into simulation ticks while preserving sub-tick
remainder; replaces raw _process tick_timer accumulation
- Add simulation_seed export (int=1337) to SimulationManager; drive
per-NPC RNG streams via seed + npc_id + stream_id derivation
(stream 0=init, stream 1=wander)
- Add get_wander_offset(npc_id) to SimulationManager so wander targets
are deterministic per seed; WorldViewManager calls it instead of
local randf_range()
- Add get_state_snapshot() and get_state_checksum() to SimulationManager
for headless verification and future save/load
- Convert SimNPC/SimVillage const DEBUG_LOGS to instance var debug_logs
so headless tests can silence output without recompilation
- Pass RandomNumberGenerator through SimNPC._init() instead of using
global randf_range() for hunger/energy/position/scoring noise
- Remove obsolete farm_zone and forest_zone exports from
WorldViewManager and their marker/tree scene children from main.tscn;
NPC gather tasks use ResourceNode exclusively
- Rename TaskZone container to ActivityMarkers in main.tscn and update
all scene paths (player, WVM, tests) to match
- Add headless deterministic_simulation_test.gd: verifies clock
accuracy, same-seed equality, different-seed divergence, and
24-tick scenario checksum without loading main.tscn