7.6 KiB
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 tojust_got_out_of_egg/just_hatched, notjust_born. - True hatch prose (
just_got_out_of_egg→ "hatches from an egg") matchesActor.eventHatchFromEgg. - Live parent beat is
just_had_child, notjust_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
egghasCreatesInterest=false(becoming an egg is not a camera beat). OnStatusChangepreviously ignored losses, so "Hatches from an egg" never became interest.- Happiness
just_got_out_of_eggis often suppressed (!hasEmotions()). - Even when a hatch Label existed, dossier identity filter dropped verbs without
is(e.g. "Name hatches …").
Fix:
- Egg status loss →
InterestFeeds.EmitHatch+EventReason.Hatch, keyhatch:{id}shared with happiness. - Keep
Name verb …EventReason sentences inUnitDossier.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:
ActorStatusPatches → addNewStatusEffect / 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 4–7 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.