feat: deliver emergent Jajce commitments

This commit is contained in:
Rijad Zuzo
2026-08-12 21:15:58 +02:00
parent dc0f59fcf0
commit 6b50580598
28 changed files with 2145 additions and 206 deletions
+129 -120
View File
@@ -2,154 +2,163 @@
## Purpose
Stable IDs and immutable definitions now form the vocabulary shared by
simulation state, systems, world adapters, scenes, tests, and future save
migrations.
Stable IDs and immutable definitions form the vocabulary shared by simulation
state, systems, world adapters, scenes, tests, and save migrations.
`SimulationIds` is the canonical source for code-facing `StringName` IDs.
`ActionDefinition` and `ProfessionDefinition` are editor-readable custom
resources. `SimulationDefinitions` loads, resolves, and validates the complete
prototype set.
`SimulationIds` remains the append-only source for code-facing compatibility
IDs. `SimulationContentPack` is the no-code authoring manifest and
`ContentCatalog` transactionally validates and publishes typed definitions in
stable-ID order. The current core pack contains actions, professions,
capability tags, items, resources, storage policies, and enemies. A failed pack
publishes nothing: duplicate IDs, unknown references, unsupported handlers, or
missing presentation cues are authoring errors rather than silent overrides.
## Current action contract
Simulation code resolves definitions through the catalog. Presentation cue IDs
remain headless strings and are mapped separately to scenes, materials, icons,
or animation hooks. Runtime quantities and ownership stay in state records;
saves do not contain `.tres` paths or copied definition balance.
Each executable action definition contains:
## Content-pack contract
- stable `action_id`;
- display name;
- default duration;
- optional preferred profession ID;
- target type: resource, activity, animal, or free movement;
- resource action ID when the action targets a ResourceNode;
- optional completion-cost resource ID and amount.
Each pack has a stable `pack_id`, display name, explicit pack dependencies,
required handler IDs, and typed definition arrays. Pack and definition IDs are
unique across the whole catalog. Packs cannot override each other in the first
version, and enumeration is sorted independently of resource load order.
Adding data-only content is:
1. create a typed `.tres` definition;
2. add it to an explicit pack;
3. optionally register its stable presentation cue in the presentation layer;
4. place or spawn an instance with its own canonical runtime ID.
Adding a fundamentally new mechanic still requires one bounded reusable
handler. The pack declares that dependency so missing runtime support fails
validation rather than becoming a partially functioning object.
## Action contract
Each executable `ActionDefinition` contains:
- stable action ID and display name;
- duration and optional preferred profession;
- target family and resource-action metadata;
- optional completion cost;
- actor and target capability tags;
- selection, target, and completion handler IDs;
- reusable typed effects;
- event and presentation cue IDs.
Reusable `ActionEffect` definitions cover metric/need change, exact inventory
transfer, damage/healing, relationship-dimension change, scheduling an ordinary
action, and site-condition change. `ActionCommand` carries stable actor/action/
target/item IDs, amount, and expected revision; `ActionOffer` and `ActionResult`
are copy-only values. `ActionCommandService` is the authority boundary and must
revalidate range, capabilities, reservation, permission, cost, and target state
at execution time for either a player or NPC caller.
The current actions are gather food, gather wood, feed animal, deposit food,
deposit wood, withdraw food, patrol, study, eat, rest, sleep, wander, and
defend. Idle and dead are stable state sentinels, not executable action
definitions.
defend. Idle and dead are state sentinels, not executable definitions. The
two-leg animal-feeding transaction remains a custom completion handler because
it has a real compound pickup/delivery contract and no second shared consumer
yet.
`defend` is the raid-response action: eligible strong villagers and guards
prefer it during an active raid, travel to the guard post, and raise village
safety while they work. Patrol activity sites accept it as a rally point.
## Items, resources, and storage
SimNPC reads default duration and preferred-profession metadata from these
definitions. WorldViewManager reads target type and resource-action metadata
instead of maintaining a separate gather-action map. ActionSelectionSystem and
SimulationManager share the same completion-cost metadata, so patrol and study
both require one stored wood without duplicating that rule.
`ItemDefinition` validates fields by category. Weapons require damage, reach,
cooldown, and an equip slot; materials and consumables do not carry fake weapon
fields. The core pack contains food, wood, herb, sword, and claw. Herb proves a
new non-weapon item and route without a manager branch.
`feed_animal` is the first animal-targeted action. Its definition prefers the
farmer profession and declares an exact one-food completion cost. Selection,
animal target reservation, supply pickup, and completion remain separate. NPC
care pays that definition cost from carried inventory after a real pantry
pickup; player care pays it directly from the pantry while player inventory is
deferred. Both paths use `AnimalCareSystem` and mutate only the exact target.
`SimulationIds` names Dunja and Zora, their private shelter anchors, and the
shared pasture anchor. These IDs are saved routine vocabulary; their loaded
positions and private/shared ownership come from `AnimalRoutineSite` rather
than entering an action definition or resource registry.
`ResourceDefinition` owns yielded item, gather action, capability tags, base
capacity/yield/regrowth, access policy, and presentation cue. Placement/state
records retain unique contextual IDs and overrides such as safety risk,
comfort, and discovery priority. Berry patches, trees, and herb patches share
this contract.
## Current profession contract
`StorageDefinition` declares accepted item IDs/tags, policy priority, capacity,
settlement scope, deposit/withdraw actions, and presentation cue.
`StorageRoutingPolicy` ranks compatible destinations deterministically by
priority then stable target ID. Food-to-pantry and wood-to-woodpile remain
covered; herb-to-apothecary proves data-only routing beyond those legacy cases.
Each profession definition contains a stable `profession_id`, display name,
body color, and prop color. The current professions are farmer, woodcutter,
guard, scholar, and wanderer.
## Professions and capabilities
NPC generation chooses from the registry's stable IDs. NPC state stores and
restores those IDs as `StringName`, and rejects records that reference an
unknown profession or executable action.
Each `ProfessionDefinition` contains a stable ID, display name, body color, and
prop color. Farmer, woodcutter, guard, scholar, and wanderer are registered in
the core pack. NPC state saves only the ID and rejects unknown definitions.
## Opportunity vocabulary
`CapabilityTagDefinition` gives actions and targets a validated shared
vocabulary. Tags express composable affordances; they do not mutate state or
replace concrete authority checks.
`SimulationIds` defines the four proven opportunity types,
`restock_empty_pantry`, `supply_missing_wood`, `feed_weak_villager`, and
`repair_home_roof`, plus the stable `open`, `resolved`, and `invalidated`
statuses. Invalidation reasons currently distinguish `interested_died` from
`evidence_stale`. These are serialized vocabulary, not editor-authored quest
definitions. Dynamic trigger, interested NPC, storage/resource goal, progress,
exact resolution-event identity, and close reason belong to
`OpportunityStateRecord` and `VillageOpportunitySystem`.
## Enemies and combat
The shared record and lifecycle collaborator was extracted only after the
food and wood consumers proved those fields. Their evidence, care, resolution,
and invalidation rules remain explicit branches. `feed_weak_villager` opens on
a `villager_weak` fact when a starving low-energy villager cannot eat and
resolves only when that same villager actually consumes food; `repair_home_roof`
opens on a `home_damaged` fact when a villager sleeps through low safety and
resolves through the real wood-deposit path. Do not add a generic quest-
definition registry until real acceptance, assignment, reward, or dialogue
consumers establish a second shared contract.
`EnemyDefinition` carries a behavior profile, combatant ID prefix, faction,
hostility, weapon, health, movement, and visual parameters.
`CombatantFactory` creates/restores every hostile and rebuilds collision-free
per-prefix allocators. The core boar reuses the wolf-hunt behavior without a
new manager or combat switch; raider and wolf compatibility spawn APIs delegate
to the same factory.
## Player actor vocabulary
Combatant and faction state use stable IDs. NPC combatants point to their
person ID; hostile records persist `enemy_definition_id`. Weapons resolve
through the same item catalog used by inventory rather than a parallel combat
item table.
`SimulationIds.PLAYER_ACTOR_ID` (`-1`) is the stable event actor for
player-performed actions, and `SimulationIds.PLAYER_INVENTORY_ID` names the
carried-inventory holder in economic events. Player-performed pantry food
supply is witnessed by nearby villagers and can raise their directed trust
toward the player, with the player as a relationship subject.
## Animals
## Item and weapon vocabulary
`AnimalDefinition` + `AnimalCatalog` + `AnimalFactory` apply the same
definition-instance-state-presentation contract to domestic animals. Goat and
sheep reuse the `grazer_routine`, feeding capability, generic CozyGrazer scene,
state migration, and care system; definition and visual parameters are the only
type-specific pieces. The animal catalog remains isolated until the next
shared content-pack migration adds that record family without destabilizing
the already validated core pack.
`ItemDefinition` is the editor-readable resource contract for items, and
`SimulationItems` is the current registry. Weapons carry `damage`, `reach`,
and `attack_cooldown` and fill the `hand` equip slot, so the same contract can
later host non-weapon items (food sacks, tools, armour) in a full inventory.
The current weapons are `item_sword` (the player's equipped blade) and
`item_claw` (wolf bites and unarmed defenders). NPC guards are equipped with
swords; other villagers fight with claws, which feeds the village-defense
derivation.
## Situations and dialogue
## Conflict vocabulary
Legacy `OpportunityStateRecord` vocabulary remains for save compatibility.
New emergent content uses typed `SituationDefinition` resources: reusable
predicates, evidence requirements, dedupe fields, priority/severity,
alternative objectives, exact ordinary resolution patterns, expiry/cooldown,
and dialogue topic IDs. Situation state saves the definition ID and causal
facts; progress is re-derived from authoritative state and `WorldEventStore`.
`CombatantStateRecord` and `FactionStateRecord` use stable IDs. Combatant kinds
are `npc`, `raider`, `wolf`, and `player`; NPC combatants reference their
`SimNPC` by stable ID. Factions are `faction_village` and `faction_tribe`, with
`neutral`/`hostile` stances and `none`/`planned`/`raiding`/`aborted` war plans.
Combat, raid, and war narrative facts use the stable event types
`combatant_hurt`, `combatant_killed`, `raid_started`, `war_resolved`,
`war_aborted`, and `wolf_hunt`.
`DialogueIntentDefinition` owns semantic preconditions, score, response intent
IDs, template variants, and optional action metadata. Stable hashing selects a
variant from conversation/turn/intent/topics without consuming shared RNG.
Rendered prose and Dialogue Manager resources are presentation and never
authoritative state.
## Enemy vocabulary
## Validation and authoring report
`EnemyDefinition` is the data contract for hostile creatures and
`SimulationEnemies` is the current registry. Each enemy carries a `kind`
(raider/wolf), equipped weapon, health, move speed, body/accent colors, and a
visual scale, so a new bear, bandit, or boar is mostly one definition plus a
small `_build_*` visual hook on the shared `CreatureVisual` root. The current
enemies are `enemy_raider` (sword) and `enemy_wolf` (claw).
The catalog rejects:
## Validation
The registry rejects:
- missing or duplicate IDs;
- empty display names;
- non-positive action durations;
- invalid target types;
- resource actions without a resource-action ID;
- incomplete, non-positive, or unknown completion-cost resources;
- references to unknown professions or resource actions;
- missing, empty, or duplicate pack/definition IDs;
- silent cross-pack overrides;
- unknown pack, handler, capability, item, profession, action, storage,
behavior-profile, or presentation-cue references;
- category-invalid item fields;
- incomplete or non-positive costs/effects;
- resources or storage routes with inconsistent item/action contracts;
- definition resources that fail to load.
`tests/simulation_definitions_test.gd` verifies registry integrity,
definition-backed behavior, unknown-ID rejection, and serialization
round-tripping.
`ContentCatalog.get_authoring_report()` exposes validity, sorted published IDs,
and exact errors for CLI/editor tooling. Tests prove transactional failure,
deterministic enumeration, core cross-references, boar behavior reuse, shared
goat/sheep behavior, and herb routing.
## Deliberate boundary
Definitions currently own identity and the static metadata already proven by
the prototype, including the patrol/study completion-cost contract. They do not
yet own:
Definitions own reusable static metadata, not mutable inventory, reservations,
relationships, situation progress, entity ownership, or presentation nodes.
Handler implementations remain bounded typed strategies. A universal
reflection DSL, arbitrary scripts embedded in saves, and a full ECS are outside
the contract.
- utility thresholds and consideration curves;
- general preconditions beyond stored-resource completion costs;
- completion effects;
- interruption and failure policy;
- reservation strategy;
- detailed target-selection policy beyond current resource/activity/free
metadata;
- richer presentation hints beyond the current profession palette.
Selection, execution, target resolution, and visual travel are now separate
responsibilities. The remaining concerns should move into definitions only
when the action-system implementations prove a stable, reusable contract.
Selection, execution, target resolution, simulation authority, and visual
travel remain separate responsibilities. Extend definitions only after a real
consumer proves a stable shared field; extend a handler when the mechanic itself
is genuinely new.