worldbox-observer-mod/docs/event-prose-audit.md

7.6 KiB
Raw Permalink Blame History

Event prose audit (vs game call sites)

Authored IdleSpectator sentences must match what the game actually does when an id fires. Source of truth: Assembly-CSharp apply sites (changeHappiness, relationship patches, status receive), not English guesses from the id string.

Audit date: 2026-07-16. Scope: Happiness (all authored), Relationship (all), Status/WorldLog/Plot/etc. sampled.

Fixed this pass

Id Was Actual Now
just_born "is born into the world" / "first breath" Actor.newCreature spawn; may precede egg form "appears in the world" / "is brought into existence"; strength 48; no hatch strength floor
just_kissed "shares a kiss" Mating afterglow (BehCheckForBabiesFromSexualReproduction) "mates with …" / "shares intimacy …"
just_killed "takes a life" Only with trait bloodlust Explicit bloodlust wording
add_child / EventReason.NewChild "{a} and {b} have a new child" {b} is the child "{a} gains a child, {b}"
baby_created / EventReason.BabyBorn "{a} welcomes a baby" {a} is the baby "{a} is created as a baby"
just_had_child Named newborn {related} Related newborn not wired "has a child" / parenthood only
just_started_war Anyone cheers war Culture trait happiness_from_war "is glad war has started" / culture-loves-war
just_talked Always warm Talk can be good or bad Neutral "finishes talking"
just_inspired Onset of inspiration Status inspired end "comes down from inspiration"
slept_outside Rough night over Sleep start, no house "has to sleep without a house"
just_rebelled Joins / rises Whole city units swept "is swept up as the city rebels"
just_forced_power Vague forced power God force shove "is flung by a god power"
got_caught Shady catch Signal No game caller found Ambient, weak strength
lost_fight Decisive loss Yield / submit mid-fight "is forced to yield"
just_talked_gossip Generic juicy gossip gossip_lovers culture Lover-gossip wording
become_king "crowned king" Any sex ruler "takes the crown" / "becomes ruler"
become_alpha Fight for alpha Oldest living family unit "becomes the family alpha"
Dreams "wakes from …" Dream status on receive "has a … dream"

Policy notes

  • Hatch camera floor (Max(strength, 88)) applies only to just_got_out_of_egg / just_hatched, not just_born.
  • True hatch prose (just_got_out_of_egg → "hatches from an egg") matches Actor.eventHatchFromEgg.
  • Live parent beat is just_had_child, not just_born.

Still clean (sample)

Grief deaths, fallen_in_love, gifts, house find/lose, just_got_out_of_egg, just_became_adult, WorldLog king_new template roles, Status egg / drowning prose.

A/B camera policy (2026-07-16)

Interesting = interest candidate. Director ranks by strength.

Happiness Ambient only for true FX: poke, caught stub, tax, ate, pooped. Status CreatesInterest false only for brief FX/cooldowns + egg gain.

Gate helper: EventCatalog.IsCameraWorthy. Drops: InterestDropLog.

Hatch camera path (fixed)

Hatch was Activity-only for many units:

  • Status egg has CreatesInterest=false (becoming an egg is not a camera beat).
  • OnStatusChange previously ignored losses, so "Hatches from an egg" never became interest.
  • Happiness just_got_out_of_egg is often suppressed (!hasEmotions()).
  • Even when a hatch Label existed, dossier identity filter dropped verbs without is (e.g. "Name hatches …").

Fix:

  • Egg status lossInterestFeeds.EmitHatch + EventReason.Hatch, key hatch:{id} shared with happiness.
  • Keep Name verb … EventReason sentences in UnitDossier.OwnedEventReason.

Reasons

EventLed camera candidates always get a Label (orange reason) when ownership + sentence filters pass. Sources: EventReason.*, happiness catalog PlainClause, or discrete catalog templates. Character fill / ambient may show empty reason. Not every Activity line is a camera event (Ambient happiness, status gains with CreatesInterest=false, status losses except egg).

Happiness trigger pass (2026-07-16)

Full 67-id call-site audit vs decompile + BehaviourTask / StatusLibrary / City civic force.

Id Finding Keep-on fix
just_laughed / just_swore Fire at end of emotion tasks Prose → finishes laughing / swearing
just_ate Fires on consumeFoodResource Prose → eats / enjoys a meal
just_felt_the_divine Divine light clears bad traits Prose → cleansed by divine light
just_played Child play task end Prose → finishes playing around
got_caught Library asset, no caller Stay Ambient; honest prose
got_robbed / gifts / kiss / talk / kill Related optional but bag missing Context bags on steal/gift/kiss/talk/kill
fallen_in_love Status fell_in_love receive + bridge Keep bridge for no-emotions
Civic aggregates / BehAddHappiness Live via forceUnits / Beh* Marked accurate

Worksheet: docs/event-trigger-audit.tsv (happiness domain done).

Status trigger pass (2026-07-16)

Full 58-id audit vs StatusLibrary + apply sites. Universal Activity hook: ActorStatusPatchesaddNewStatusEffect / Status.finish (egg loss also InterestFeeds.EmitHatch).

Id Finding Keep-on fix
angry addAggro, not the rage combat buff Prose → flies into a fury
possessed_follower Possession talk converts target Prose → converted into possessed follower
pregnant / pregnant_parthenogenesis Finish → BabyMaker birth Loss prose → gives birth (/ alone)
taking_roots Finish → vegetative offspring Loss prose → sprouts offspring
budding Finish → bud offspring Loss prose → splits off a bud offspring
uprooting Plant babies emerging Prose → emerges as a young plant
Dreams / inspired / combat FX Sleep pot, finish→happiness, CombatActionLibrary Already accurate

Worksheet: docs/event-trigger-audit.tsv (status domain done).

WorldLog / plot / trait pass (2026-07-16)

Phases 47 worksheet complete (all audit rows done).

Area Finding Keep-on fix
WorldLog {a}/{b} special1/special2 match game replacers (kingdom/king, war kingdoms) Accurate
Disasters Policy rows; camera via paired disaster_* WorldLog Accurate (no DisasterManager patch)
Wars / eras WarManager + WarInterestFeed; WorldAgeManager.startNextAge Accurate
Plots Same label for new/complete/cancel EventReason.Plot phase rewrite
Traits JSON said Trait: {id} ({a}); live was gains/loses Catalog labels → {a} gains {id}
Boat/meta harness Crumb strings ≠ EventReason Harness uses EventReason.Boat / MetaNew
Building / combat Already EventReason.BuildingEat / Fight Accurate

Worksheet: docs/event-trigger-audit.tsv (all domains done).

Family pack join false positive (2026-07-16)

BehFamilyGroupJoin returns Continue even when getNearbyFamily is null (no setFamily). IdleSpectator used to Emit on any Continue → orange “joins a family pack” with no Family meta. Gate: Emit only when hasFamily() after execute.

Observe → confirm → emit (2026-07-16)

Shared pipeline: EventOutcome predicates + EventObservation.Confirm* before feeds. Relationship Beh hooks (find_lover, family group new/join/leave) migrated first. Rule: never treat BehResult.Continue as semantic success. Docs: docs/event-observation.md.