event catalog

This commit is contained in:
DazedAnon 2026-07-16 00:40:53 -05:00
parent ff824c76a1
commit 63ba0ca3d1
51 changed files with 272 additions and 170 deletions

View file

@ -30,7 +30,7 @@ public static class ActivityHappinessHarness
{
List<string> liveIds = ActivityAssetCatalog.EnumerateLiveHappinessIds();
var authored = new HashSet<string>(StringComparer.OrdinalIgnoreCase);
foreach (string id in HappinessEventCatalog.AuthoredIds)
foreach (string id in EventCatalog.Happiness.AuthoredIds)
{
authored.Add(id);
}
@ -53,8 +53,8 @@ public static class ActivityHappinessHarness
string id = liveIds[i];
liveSet.Add(id);
HappinessAsset asset = ActivityAssetCatalog.TryGetHappinessAsset(id);
bool hasAuthored = HappinessEventCatalog.HasAuthored(id);
HappinessCatalogEntry entry = HappinessEventCatalog.GetOrFallback(id);
bool hasAuthored = EventCatalog.Happiness.HasAuthored(id);
HappinessCatalogEntry entry = EventCatalog.Happiness.GetOrFallback(id);
if (!hasAuthored || entry.IsFallback)
{
missingAuthored++;

View file

@ -36,7 +36,7 @@ public static class ActivityHappinessProse
out bool authored)
{
usedRelated = false;
authored = entry != null && !entry.IsFallback && HappinessEventCatalog.HasAuthored(entry.Id);
authored = entry != null && !entry.IsFallback && EventCatalog.Happiness.HasAuthored(entry.Id);
if (entry == null)
{
return "feels a change in happiness";

View file

@ -750,7 +750,7 @@ public static class ActivityLog
if (published != null && !string.IsNullOrEmpty(relatedName))
{
published.RelatedName = relatedName;
HappinessCatalogEntry entry = HappinessEventCatalog.GetOrFallback(effectId);
HappinessCatalogEntry entry = EventCatalog.Happiness.GetOrFallback(effectId);
string clause = ActivityHappinessProse.Clause(entry, relatedName, out bool usedRelated, out _);
published.PlainClause = clause;
published.RichClause = usedRelated
@ -770,7 +770,7 @@ public static class ActivityLog
return published != null;
}
HappinessCatalogEntry fallbackEntry = HappinessEventCatalog.GetOrFallback(effectId);
HappinessCatalogEntry fallbackEntry = EventCatalog.Happiness.GetOrFallback(effectId);
string fallbackClause = ActivityHappinessProse.Clause(
fallbackEntry, relatedName, out bool usedRel, out _);
string rich = usedRel && !string.IsNullOrEmpty(relatedName)

View file

@ -47,7 +47,7 @@ public static class ActivityStatusHarness
var liveSet = new HashSet<string>(StringComparer.OrdinalIgnoreCase);
var interestAuthored = new HashSet<string>(StringComparer.OrdinalIgnoreCase);
foreach (string id in StatusInterestCatalog.AuthoredIds)
foreach (string id in EventCatalog.Status.AuthoredIds)
{
interestAuthored.Add(id);
}
@ -65,8 +65,8 @@ public static class ActivityStatusHarness
missingAuthored++;
}
StatusInterestEntry interest = StatusInterestCatalog.GetOrFallback(id);
bool hasInterest = StatusInterestCatalog.HasAuthored(id) && !interest.IsFallback;
StatusInterestEntry interest = EventCatalog.Status.GetOrFallback(id);
bool hasInterest = EventCatalog.Status.HasAuthored(id) && !interest.IsFallback;
if (!hasInterest)
{
missingInterest++;

View file

@ -2486,14 +2486,14 @@ public static class AgentHarness
assetId = "disaster_tornado";
}
if (!WorldLogEventCatalog.HasAuthored(assetId))
if (!EventCatalog.WorldLog.HasAuthored(assetId))
{
_cmdFail++;
Emit(cmd, ok: false, detail: "not_authored:" + assetId);
return;
}
WorldLogEventEntry entry = WorldLogEventCatalog.GetOrFallback(assetId);
WorldLogEventEntry entry = EventCatalog.WorldLog.GetOrFallback(assetId);
Actor follow = ResolveUnit(null) ?? WorldActivityScanner.FindNearestAliveUnit(CameraPos(), 200f);
if (follow == null && entry.CreatesInterest)
{
@ -2581,7 +2581,7 @@ public static class AgentHarness
id = "set_lover";
}
entry = RelationshipEventCatalog.GetOrFallback(id);
entry = EventCatalog.Relationship.GetOrFallback(id);
Actor related = ActorRelation.ResolvePackRelated(unit)
?? WorldActivityScanner.FindNearestAliveUnit(unit.current_position, 40f);
if (related == unit)
@ -2623,7 +2623,7 @@ public static class AgentHarness
id = "new_war";
}
entry = PlotInterestCatalog.GetOrFallback(id);
entry = EventCatalog.Plot.GetOrFallback(id);
key = "plot:" + entry.Id + ":new:" + EventFeedUtil.SafeId(unit);
label = entry.MakeLabel(EventFeedUtil.SafeName(unit), "new");
strength = entry.EventStrength;
@ -2636,7 +2636,7 @@ public static class AgentHarness
id = "age_chaos";
}
entry = EraInterestCatalog.GetOrFallback(id);
entry = EventCatalog.Era.GetOrFallback(id);
key = "era:" + entry.Id;
label = entry.MakeLabel("", "");
strength = entry.EventStrength;
@ -2673,7 +2673,7 @@ public static class AgentHarness
id = "history_book";
}
entry = BookInterestCatalog.GetOrFallback(id);
entry = EventCatalog.Book.GetOrFallback(id);
key = "book:" + entry.Id + ":new:" + EventFeedUtil.SafeId(unit);
label = entry.MakeLabel(EventFeedUtil.SafeName(unit), "new");
strength = entry.EventStrength;
@ -2686,7 +2686,7 @@ public static class AgentHarness
id = "immortal";
}
entry = TraitInterestCatalog.GetOrFallback(id);
entry = EventCatalog.Trait.GetOrFallback(id);
key = "trait:" + entry.Id + ":gains:" + EventFeedUtil.SafeId(unit);
label = EventFeedUtil.SafeName(unit) + " gains " + entry.Id;
strength = entry.EventStrength;
@ -2728,7 +2728,7 @@ public static class AgentHarness
}
{
DiscreteEventEntry spellEntry = SpellInterestCatalog.GetOrFallback(id);
DiscreteEventEntry spellEntry = EventCatalog.Spell.GetOrFallback(id);
key = "spell:" + spellEntry.Id + ":" + EventFeedUtil.SafeId(unit);
label = spellEntry.MakeLabel(EventFeedUtil.SafeName(unit), "");
strength = spellEntry.EventStrength;
@ -2745,7 +2745,7 @@ public static class AgentHarness
}
{
DiscreteEventEntry itemEntry = ItemInterestCatalog.GetOrFallback(id);
DiscreteEventEntry itemEntry = EventCatalog.Item.GetOrFallback(id);
key = "item:" + itemEntry.Id + ":" + EventFeedUtil.SafeId(unit);
label = itemEntry.MakeLabel(EventFeedUtil.SafeName(unit), "");
strength = itemEntry.EventStrength;
@ -2762,7 +2762,7 @@ public static class AgentHarness
}
{
DiscreteEventEntry decEntry = DecisionInterestCatalog.GetOrFallback(id);
DiscreteEventEntry decEntry = EventCatalog.Decision.GetOrFallback(id);
key = "decision:" + decEntry.Id + ":" + EventFeedUtil.SafeId(unit);
label = decEntry.MakeLabel(EventFeedUtil.SafeName(unit), "");
strength = decEntry.EventStrength;
@ -2779,7 +2779,7 @@ public static class AgentHarness
}
{
DiscreteEventEntry powEntry = PowerInterestCatalog.GetOrFallback(id);
DiscreteEventEntry powEntry = EventCatalog.Power.GetOrFallback(id);
key = "power:" + powEntry.Id + ":" + EventFeedUtil.SafeId(unit);
label = powEntry.MakeLabel(EventFeedUtil.SafeName(unit), "");
strength = powEntry.EventStrength;
@ -2797,7 +2797,7 @@ public static class AgentHarness
}
{
DiscreteEventEntry stEntry = SubspeciesTraitInterestCatalog.GetOrFallback(id);
DiscreteEventEntry stEntry = EventCatalog.SubspeciesTrait.GetOrFallback(id);
key = "subspecies_trait:" + stEntry.Id + ":" + EventFeedUtil.SafeId(unit);
label = stEntry.MakeLabel(EventFeedUtil.SafeName(unit), "");
strength = stEntry.EventStrength;
@ -2814,7 +2814,7 @@ public static class AgentHarness
}
{
DiscreteEventEntry geneEntry = GeneInterestCatalog.GetOrFallback(id);
DiscreteEventEntry geneEntry = EventCatalog.Gene.GetOrFallback(id);
key = "gene:" + geneEntry.Id + ":" + EventFeedUtil.SafeId(unit);
label = geneEntry.MakeLabel(EventFeedUtil.SafeName(unit), "");
strength = geneEntry.EventStrength;

View file

@ -119,103 +119,103 @@ public static class DomainEventHarness
CatalogCoverageDiff plots = CatalogCoverageAudit.Diff(
"plots",
ActivityAssetCatalog.EnumerateLivePlotIds(),
PlotInterestCatalog.AuthoredIds);
AppendLibraryDomain(tsv, "plots", ActivityAssetCatalog.EnumerateLivePlotIds(), plots, PlotInterestCatalog.GetOrFallback);
EventCatalog.Plot.AuthoredIds);
AppendLibraryDomain(tsv, "plots", ActivityAssetCatalog.EnumerateLivePlotIds(), plots, EventCatalog.Plot.GetOrFallback);
CatalogCoverageDiff eras = CatalogCoverageAudit.Diff(
"eras",
ActivityAssetCatalog.EnumerateLiveEraIds(),
EraInterestCatalog.AuthoredIds);
AppendLibraryDomain(tsv, "eras", ActivityAssetCatalog.EnumerateLiveEraIds(), eras, EraInterestCatalog.GetOrFallback);
EventCatalog.Era.AuthoredIds);
AppendLibraryDomain(tsv, "eras", ActivityAssetCatalog.EnumerateLiveEraIds(), eras, EventCatalog.Era.GetOrFallback);
CatalogCoverageDiff books = CatalogCoverageAudit.Diff(
"books",
ActivityAssetCatalog.EnumerateLiveBookTypeIds(),
BookInterestCatalog.AuthoredIds);
AppendLibraryDomain(tsv, "books", ActivityAssetCatalog.EnumerateLiveBookTypeIds(), books, BookInterestCatalog.GetOrFallback);
EventCatalog.Book.AuthoredIds);
AppendLibraryDomain(tsv, "books", ActivityAssetCatalog.EnumerateLiveBookTypeIds(), books, EventCatalog.Book.GetOrFallback);
CatalogCoverageDiff traits = CatalogCoverageAudit.Diff(
"traits",
ActivityAssetCatalog.EnumerateLiveTraitIds(),
TraitInterestCatalog.AuthoredIds);
AppendLibraryDomain(tsv, "traits", ActivityAssetCatalog.EnumerateLiveTraitIds(), traits, TraitInterestCatalog.GetOrFallback);
EventCatalog.Trait.AuthoredIds);
AppendLibraryDomain(tsv, "traits", ActivityAssetCatalog.EnumerateLiveTraitIds(), traits, EventCatalog.Trait.GetOrFallback);
CatalogCoverageDiff spells = CatalogCoverageAudit.Diff(
"spells",
ActivityAssetCatalog.EnumerateLiveSpellIds(),
SpellInterestCatalog.AuthoredIds);
AppendLibraryDomain(tsv, "spells", ActivityAssetCatalog.EnumerateLiveSpellIds(), spells, SpellInterestCatalog.GetOrFallback);
EventCatalog.Spell.AuthoredIds);
AppendLibraryDomain(tsv, "spells", ActivityAssetCatalog.EnumerateLiveSpellIds(), spells, EventCatalog.Spell.GetOrFallback);
CatalogCoverageDiff powers = CatalogCoverageAudit.Diff(
"powers",
ActivityAssetCatalog.EnumerateLivePowerIds(),
PowerInterestCatalog.AuthoredIds);
AppendLibraryDomain(tsv, "powers", ActivityAssetCatalog.EnumerateLivePowerIds(), powers, PowerInterestCatalog.GetOrFallback);
EventCatalog.Power.AuthoredIds);
AppendLibraryDomain(tsv, "powers", ActivityAssetCatalog.EnumerateLivePowerIds(), powers, EventCatalog.Power.GetOrFallback);
CatalogCoverageDiff decisions = CatalogCoverageAudit.Diff(
"decisions",
ActivityAssetCatalog.EnumerateLiveDecisionIds(),
DecisionInterestCatalog.AuthoredIds);
AppendLibraryDomain(tsv, "decisions", ActivityAssetCatalog.EnumerateLiveDecisionIds(), decisions, DecisionInterestCatalog.GetOrFallback);
EventCatalog.Decision.AuthoredIds);
AppendLibraryDomain(tsv, "decisions", ActivityAssetCatalog.EnumerateLiveDecisionIds(), decisions, EventCatalog.Decision.GetOrFallback);
CatalogCoverageDiff items = CatalogCoverageAudit.Diff(
"items",
ActivityAssetCatalog.EnumerateLiveItemIds(),
ItemInterestCatalog.AuthoredIds);
AppendLibraryDomain(tsv, "items", ActivityAssetCatalog.EnumerateLiveItemIds(), items, ItemInterestCatalog.GetOrFallback);
EventCatalog.Item.AuthoredIds);
AppendLibraryDomain(tsv, "items", ActivityAssetCatalog.EnumerateLiveItemIds(), items, EventCatalog.Item.GetOrFallback);
CatalogCoverageDiff subspTraits = CatalogCoverageAudit.Diff(
"subspecies_traits",
ActivityAssetCatalog.EnumerateLiveSubspeciesTraitIds(),
SubspeciesTraitInterestCatalog.AuthoredIds);
EventCatalog.SubspeciesTrait.AuthoredIds);
AppendLibraryDomain(
tsv,
"subspecies_traits",
ActivityAssetCatalog.EnumerateLiveSubspeciesTraitIds(),
subspTraits,
SubspeciesTraitInterestCatalog.GetOrFallback);
EventCatalog.SubspeciesTrait.GetOrFallback);
CatalogCoverageDiff genes = CatalogCoverageAudit.Diff(
"genes",
ActivityAssetCatalog.EnumerateLiveGeneIds(),
GeneInterestCatalog.AuthoredIds);
AppendLibraryDomain(tsv, "genes", ActivityAssetCatalog.EnumerateLiveGeneIds(), genes, GeneInterestCatalog.GetOrFallback);
EventCatalog.Gene.AuthoredIds);
AppendLibraryDomain(tsv, "genes", ActivityAssetCatalog.EnumerateLiveGeneIds(), genes, EventCatalog.Gene.GetOrFallback);
CatalogCoverageDiff phenotypes = CatalogCoverageAudit.Diff(
"phenotypes",
ActivityAssetCatalog.EnumerateLivePhenotypeIds(),
PhenotypeInterestCatalog.AuthoredIds);
EventCatalog.Phenotype.AuthoredIds);
AppendLibraryDomain(
tsv,
"phenotypes",
ActivityAssetCatalog.EnumerateLivePhenotypeIds(),
phenotypes,
PhenotypeInterestCatalog.GetOrFallback);
EventCatalog.Phenotype.GetOrFallback);
CatalogCoverageDiff worldLaws = CatalogCoverageAudit.Diff(
"world_laws",
ActivityAssetCatalog.EnumerateLiveWorldLawIds(),
WorldLawInterestCatalog.AuthoredIds);
EventCatalog.WorldLaw.AuthoredIds);
AppendLibraryDomain(
tsv,
"world_laws",
ActivityAssetCatalog.EnumerateLiveWorldLawIds(),
worldLaws,
WorldLawInterestCatalog.GetOrFallback);
EventCatalog.WorldLaw.GetOrFallback);
CatalogCoverageDiff biomes = CatalogCoverageAudit.Diff(
"biomes",
ActivityAssetCatalog.EnumerateLiveBiomeIds(),
BiomeInterestCatalog.AuthoredIds);
AppendLibraryDomain(tsv, "biomes", ActivityAssetCatalog.EnumerateLiveBiomeIds(), biomes, BiomeInterestCatalog.GetOrFallback);
EventCatalog.Biome.AuthoredIds);
AppendLibraryDomain(tsv, "biomes", ActivityAssetCatalog.EnumerateLiveBiomeIds(), biomes, EventCatalog.Biome.GetOrFallback);
int relMissing = 0;
int relTotal = 0;
foreach (string id in RelationshipEventCatalog.AuthoredIds)
foreach (string id in EventCatalog.Relationship.AuthoredIds)
{
relTotal++;
DiscreteEventEntry entry = RelationshipEventCatalog.GetOrFallback(id);
bool ok = RelationshipEventCatalog.HasAuthored(id) && !entry.IsFallback;
DiscreteEventEntry entry = EventCatalog.Relationship.GetOrFallback(id);
bool ok = EventCatalog.Relationship.HasAuthored(id) && !entry.IsFallback;
if (!ok)
{
relMissing++;

View file

@ -26,13 +26,13 @@ public static class DisasterWarHarness
List<string> warTypes = ActivityAssetCatalog.EnumerateLiveWarTypeIds();
var authoredDisasters = new HashSet<string>(StringComparer.OrdinalIgnoreCase);
foreach (string id in DisasterInterestCatalog.AuthoredIds)
foreach (string id in EventCatalog.Disaster.AuthoredIds)
{
authoredDisasters.Add(id);
}
var authoredWars = new HashSet<string>(StringComparer.OrdinalIgnoreCase);
foreach (string id in WarTypeInterestCatalog.AuthoredIds)
foreach (string id in EventCatalog.WarType.AuthoredIds)
{
authoredWars.Add(id);
}
@ -49,8 +49,8 @@ public static class DisasterWarHarness
{
string id = disasters[i];
liveDisasters.Add(id);
DisasterInterestEntry entry = DisasterInterestCatalog.GetOrFallback(id);
bool has = DisasterInterestCatalog.HasAuthored(id) && !entry.IsFallback;
DisasterInterestEntry entry = EventCatalog.Disaster.GetOrFallback(id);
bool has = EventCatalog.Disaster.HasAuthored(id) && !entry.IsFallback;
if (!has)
{
missingDisaster++;
@ -77,8 +77,8 @@ public static class DisasterWarHarness
{
string id = warTypes[i];
liveWars.Add(id);
WarTypeInterestEntry entry = WarTypeInterestCatalog.GetOrFallback(id);
bool has = WarTypeInterestCatalog.HasAuthored(id) && !entry.IsFallback;
WarTypeInterestEntry entry = EventCatalog.WarType.GetOrFallback(id);
bool has = EventCatalog.WarType.HasAuthored(id) && !entry.IsFallback;
if (!has)
{
missingWarType++;

View file

@ -4,12 +4,14 @@ using System.Collections.Generic;
namespace IdleSpectator;
/// <summary>Authored interest overlay for every live book_types asset.</summary>
public static class BookInterestCatalog
public static partial class EventCatalog
{
public static class Book
{
private static readonly Dictionary<string, DiscreteEventEntry> Entries =
new Dictionary<string, DiscreteEventEntry>(StringComparer.OrdinalIgnoreCase);
static BookInterestCatalog()
static Book()
{
Add("family_story", 52f, "Culture", "{a} writes a family story");
Add("love_story", 58f, "Culture", "{a} writes a love story");
@ -64,3 +66,4 @@ public static class BookInterestCatalog
};
}
}
}

View file

@ -14,12 +14,14 @@ public sealed class DisasterInterestEntry
}
/// <summary>Authored interest overlay for every live disasters library asset.</summary>
public static class DisasterInterestCatalog
public static partial class EventCatalog
{
public static class Disaster
{
private static readonly Dictionary<string, DisasterInterestEntry> Entries =
new Dictionary<string, DisasterInterestEntry>(StringComparer.OrdinalIgnoreCase);
static DisasterInterestCatalog()
static Disaster()
{
Add("tornado", 95f, "disaster_tornado");
Add("heatwave", 88f, "disaster_heatwave");
@ -89,3 +91,4 @@ public static class DisasterInterestCatalog
};
}
}
}

View file

@ -4,12 +4,14 @@ using System.Collections.Generic;
namespace IdleSpectator;
/// <summary>Authored interest overlay for every live era_library asset.</summary>
public static class EraInterestCatalog
public static partial class EventCatalog
{
public static class Era
{
private static readonly Dictionary<string, DiscreteEventEntry> Entries =
new Dictionary<string, DiscreteEventEntry>(StringComparer.OrdinalIgnoreCase);
static EraInterestCatalog()
static Era()
{
Add("age_hope", 78f, "World", "Age of Hope");
Add("age_sun", 80f, "World", "Age of Sun");
@ -63,3 +65,4 @@ public static class EraInterestCatalog
};
}
}
}

View file

@ -4,7 +4,9 @@ using System.Collections.Generic;
namespace IdleSpectator;
/// <summary>Authored policy + prose for every live happiness effect.</summary>
public static class HappinessEventCatalog
public static partial class EventCatalog
{
public static class Happiness
{
private static readonly Dictionary<string, HappinessCatalogEntry> Entries =
new Dictionary<string, HappinessCatalogEntry>(StringComparer.OrdinalIgnoreCase)
@ -944,4 +946,4 @@ public static class HappinessEventCatalog
};
}
}
}

View file

@ -3,8 +3,10 @@ using System.Collections.Generic;
namespace IdleSpectator;
/// <summary>Live spells library interest overlay (Signal when cast resolves to a unit).</summary>
public static class SpellInterestCatalog
/// <summary>Live AssetManager library event dials (powers, genes, …).</summary>
public static partial class EventCatalog
{
public static class Spell
{
private static readonly Dictionary<string, DiscreteEventEntry> Entries =
new Dictionary<string, DiscreteEventEntry>(StringComparer.OrdinalIgnoreCase);
@ -43,7 +45,7 @@ public static class SpellInterestCatalog
}
/// <summary>God powers library - mostly Ambient; Signal for disaster/spectacle ids.</summary>
public static class PowerInterestCatalog
public static class Power
{
private static readonly Dictionary<string, DiscreteEventEntry> Entries =
new Dictionary<string, DiscreteEventEntry>(StringComparer.OrdinalIgnoreCase);
@ -100,7 +102,7 @@ public static class PowerInterestCatalog
}
/// <summary>AI decisions - Signal for war/rebellion/kingdom-affecting; Ambient otherwise.</summary>
public static class DecisionInterestCatalog
public static class Decision
{
private static readonly Dictionary<string, DiscreteEventEntry> Entries =
new Dictionary<string, DiscreteEventEntry>(StringComparer.OrdinalIgnoreCase);
@ -169,7 +171,7 @@ public static class DecisionInterestCatalog
}
/// <summary>Items library - Signal for legendary/wonder subset.</summary>
public static class ItemInterestCatalog
public static class Item
{
private static readonly Dictionary<string, DiscreteEventEntry> Entries =
new Dictionary<string, DiscreteEventEntry>(StringComparer.OrdinalIgnoreCase);
@ -223,7 +225,7 @@ public static class ItemInterestCatalog
}
/// <summary>Subspecies traits - Signal for dramatic; Ambient fill-capped.</summary>
public static class SubspeciesTraitInterestCatalog
public static class SubspeciesTrait
{
private static readonly Dictionary<string, DiscreteEventEntry> Entries =
new Dictionary<string, DiscreteEventEntry>(StringComparer.OrdinalIgnoreCase);
@ -280,7 +282,7 @@ public static class SubspeciesTraitInterestCatalog
}
/// <summary>Genes - Ambient default.</summary>
public static class GeneInterestCatalog
public static class Gene
{
private static readonly Dictionary<string, DiscreteEventEntry> Entries =
new Dictionary<string, DiscreteEventEntry>(StringComparer.OrdinalIgnoreCase);
@ -314,7 +316,7 @@ public static class GeneInterestCatalog
}
/// <summary>Phenotypes - Ambient default.</summary>
public static class PhenotypeInterestCatalog
public static class Phenotype
{
private static readonly Dictionary<string, DiscreteEventEntry> Entries =
new Dictionary<string, DiscreteEventEntry>(StringComparer.OrdinalIgnoreCase);
@ -347,7 +349,7 @@ public static class PhenotypeInterestCatalog
}
/// <summary>World laws - Ambient / location-only style.</summary>
public static class WorldLawInterestCatalog
public static class WorldLaw
{
private static readonly Dictionary<string, DiscreteEventEntry> Entries =
new Dictionary<string, DiscreteEventEntry>(StringComparer.OrdinalIgnoreCase);
@ -381,7 +383,7 @@ public static class WorldLawInterestCatalog
}
/// <summary>Biomes - Ambient.</summary>
public static class BiomeInterestCatalog
public static class Biome
{
private static readonly Dictionary<string, DiscreteEventEntry> Entries =
new Dictionary<string, DiscreteEventEntry>(StringComparer.OrdinalIgnoreCase);
@ -412,3 +414,5 @@ public static class BiomeInterestCatalog
return LiveLibraryInterest.Lookup(Entries, id, "Biome", "Biome shifts: {id}", 26f);
}
}
}

View file

@ -4,12 +4,14 @@ using System.Collections.Generic;
namespace IdleSpectator;
/// <summary>Authored interest overlay for every live plots_library asset.</summary>
public static class PlotInterestCatalog
public static partial class EventCatalog
{
public static class Plot
{
private static readonly Dictionary<string, DiscreteEventEntry> Entries =
new Dictionary<string, DiscreteEventEntry>(StringComparer.OrdinalIgnoreCase);
static PlotInterestCatalog()
static Plot()
{
Add("rebellion", 92f, "Politics", "{a} is plotting a rebellion");
Add("new_war", 94f, "Politics", "{a} is plotting a war");
@ -80,3 +82,4 @@ public static class PlotInterestCatalog
};
}
}
}

View file

@ -3,37 +3,15 @@ using System.Collections.Generic;
namespace IdleSpectator;
public sealed class DiscreteEventEntry
{
public string Id = "";
public float EventStrength = 50f;
public string Category = "Event";
public bool CreatesInterest = true;
public string LabelTemplate = "{a}";
public bool IsFallback;
public string MakeLabel(Actor a, Actor b = null)
{
return EventReason.Apply(LabelTemplate, a, b, Id);
}
public string MakeLabel(string a, string b)
{
string template = string.IsNullOrEmpty(LabelTemplate) ? "{id}" : LabelTemplate;
return template
.Replace("{id}", Id ?? "")
.Replace("{a}", a ?? "")
.Replace("{b}", b ?? "");
}
}
/// <summary>Authored discrete relationship lifecycle events (not a live asset library).</summary>
public static class RelationshipEventCatalog
public static partial class EventCatalog
{
public static class Relationship
{
private static readonly Dictionary<string, DiscreteEventEntry> Entries =
new Dictionary<string, DiscreteEventEntry>(StringComparer.OrdinalIgnoreCase);
static RelationshipEventCatalog()
static Relationship()
{
Add("set_lover", 72f, "Relationship", "{a} became lovers with {b}");
Add("clear_lover", 55f, "Relationship", "{a} parted from a lover");
@ -83,7 +61,9 @@ public static class RelationshipEventCatalog
EventStrength = 40f,
Category = "Relationship",
LabelTemplate = "{a} · {id}",
CreatesInterest = false,
IsFallback = true
};
}
}
}

View file

@ -16,12 +16,14 @@ public sealed class StatusInterestEntry
/// <summary>
/// Authored interest policy for every live status asset. Prose stays in ActivityStatusProse.
/// </summary>
public static class StatusInterestCatalog
public static partial class EventCatalog
{
public static class Status
{
private static readonly Dictionary<string, StatusInterestEntry> Entries =
new Dictionary<string, StatusInterestEntry>(StringComparer.OrdinalIgnoreCase);
static StatusInterestCatalog()
static Status()
{
// Spectacle / camera-worthy transformations
Add("burning", 70f, "StatusTransformation", true);
@ -146,3 +148,4 @@ public static class StatusInterestCatalog
};
}
}
}

View file

@ -4,12 +4,14 @@ using System.Collections.Generic;
namespace IdleSpectator;
/// <summary>Authored interest overlay for every live traits library asset.</summary>
public static class TraitInterestCatalog
public static partial class EventCatalog
{
public static class Trait
{
private static readonly Dictionary<string, DiscreteEventEntry> Entries =
new Dictionary<string, DiscreteEventEntry>(StringComparer.OrdinalIgnoreCase);
static TraitInterestCatalog()
static Trait()
{
Add("zombie", 82f);
Add("wise", 42f);
@ -164,3 +166,4 @@ public static class TraitInterestCatalog
};
}
}
}

View file

@ -14,12 +14,14 @@ public sealed class WarTypeInterestEntry
}
/// <summary>Authored interest overlay for every live war_types_library asset.</summary>
public static class WarTypeInterestCatalog
public static partial class EventCatalog
{
public static class WarType
{
private static readonly Dictionary<string, WarTypeInterestEntry> Entries =
new Dictionary<string, WarTypeInterestEntry>(StringComparer.OrdinalIgnoreCase);
static WarTypeInterestCatalog()
static WarType()
{
Add("normal", 90f, "War: {a}");
Add("spite", 88f, "Spite war: {a}");
@ -90,3 +92,4 @@ public static class WarTypeInterestCatalog
.Replace("{a}", special1 ?? "");
}
}
}

View file

@ -42,12 +42,14 @@ public sealed class WorldLogEventEntry
/// <summary>
/// Authored policy for every live WorldLog asset. Game library is inventory; this is presentation/scoring only.
/// </summary>
public static class WorldLogEventCatalog
public static partial class EventCatalog
{
public static class WorldLog
{
private static readonly Dictionary<string, WorldLogEventEntry> Entries =
new Dictionary<string, WorldLogEventEntry>(StringComparer.OrdinalIgnoreCase);
static WorldLogEventCatalog()
static WorldLog()
{
// Kings
Add("king_new", 78f, "Politics", true, "New king: {b} ({a})", 6f, 28f);
@ -188,3 +190,4 @@ public static class WorldLogEventCatalog
return GetOrFallback(message.asset_id).MakeLabel(message);
}
}
}

View file

@ -61,7 +61,8 @@ public static class LiveLibraryInterest
string id,
string category,
string labelTemplate,
float fallbackStrength = 40f)
float fallbackStrength = 40f,
bool fallbackCreatesInterest = false)
{
if (!string.IsNullOrEmpty(id) && entries != null && entries.TryGetValue(id.Trim(), out DiscreteEventEntry entry))
{
@ -75,6 +76,7 @@ public static class LiveLibraryInterest
EventStrength = fallbackStrength,
Category = category,
LabelTemplate = labelTemplate,
CreatesInterest = fallbackCreatesInterest,
IsFallback = true
};
}

View file

@ -0,0 +1,29 @@
namespace IdleSpectator;
/// <summary>
/// Shared catalog row for discrete / library-backed spectator events.
/// Lives in <c>Events/</c> with <see cref="EventReason"/> - catalogs own dials; director only ranks.
/// </summary>
public sealed class DiscreteEventEntry
{
public string Id = "";
public float EventStrength = 50f;
public string Category = "Event";
public bool CreatesInterest = true;
public string LabelTemplate = "{a}";
public bool IsFallback;
public string MakeLabel(Actor a, Actor b = null)
{
return EventReason.Apply(LabelTemplate, a, b, Id);
}
public string MakeLabel(string a, string b)
{
string template = string.IsNullOrEmpty(LabelTemplate) ? "{id}" : LabelTemplate;
return template
.Replace("{id}", Id ?? "")
.Replace("{a}", a ?? "")
.Replace("{b}", b ?? "");
}
}

View file

@ -0,0 +1,36 @@
namespace IdleSpectator;
/// <summary>
/// IdleSpectator event inventory (one type, split across partial files).
/// Call sites: EventCatalog.Status / .Happiness / .Combat / …
/// Director only ranks; feeds register from these dials.
///
/// Domain files under Events/Catalogs/:
/// EventCatalog.Status.cs
/// EventCatalog.Happiness.cs
/// EventCatalog.WorldLog.cs
/// EventCatalog.Trait.cs
/// EventCatalog.Book.cs
/// EventCatalog.Era.cs
/// EventCatalog.Plot.cs
/// EventCatalog.Relationship.cs
/// EventCatalog.Disaster.cs
/// EventCatalog.WarType.cs
/// EventCatalog.Libraries.cs (Spell, Power, Decision, Item, SubspeciesTrait, Gene, Phenotype, WorldLaw, Biome)
/// Combat policy lives in this file.
/// </summary>
public static partial class EventCatalog
{
/// <summary>Combat camera policy (activity + scanner share one key / dials).</summary>
public static class Combat
{
public const float ActivityStrength = 88f;
public const float ScannerStrengthFloor = 80f;
public const float MinWatch = 4f;
public const float MaxWatch = 60f;
public const float ActivityTtl = 20f;
public const float ScannerTtl = 18f;
public static string Key(long subjectId) => "combat:" + subjectId;
}
}

View file

@ -6,7 +6,8 @@ namespace IdleSpectator;
/// <summary>
/// Sole factory for interest Labels shown as the orange dossier reason.
/// Feeds must call these helpers (or Apply) instead of concatenating crumbs.
/// Part of the <c>Events/</c> module with catalogs - feeds call these helpers (or Apply)
/// instead of concatenating crumbs. Director never authors reasons.
/// </summary>
public static class EventReason
{

View file

@ -12,7 +12,7 @@ public static class BookInterestFeed
return;
}
DiscreteEventEntry entry = BookInterestCatalog.GetOrFallback(bookTypeId);
DiscreteEventEntry entry = EventCatalog.Book.GetOrFallback(bookTypeId);
if (!entry.CreatesInterest)
{
return;

View file

@ -11,7 +11,7 @@ public static class DeferredInterestFeed
"spell",
spellId,
caster,
SpellInterestCatalog.GetOrFallback,
EventCatalog.Spell.GetOrFallback,
related: null,
locationOnly: false);
}
@ -22,7 +22,7 @@ public static class DeferredInterestFeed
"item",
itemId,
craftsman,
ItemInterestCatalog.GetOrFallback,
EventCatalog.Item.GetOrFallback,
related: null,
locationOnly: false);
}
@ -33,14 +33,14 @@ public static class DeferredInterestFeed
"decision",
decisionId,
actor,
DecisionInterestCatalog.GetOrFallback,
EventCatalog.Decision.GetOrFallback,
related: null,
locationOnly: false);
}
public static void EmitPower(string powerId, Vector3 position, Actor nearUnit)
{
DiscreteEventEntry entry = PowerInterestCatalog.GetOrFallback(powerId);
DiscreteEventEntry entry = EventCatalog.Power.GetOrFallback(powerId);
if (!entry.CreatesInterest || AgentHarness.Busy)
{
return;
@ -48,7 +48,7 @@ public static class DeferredInterestFeed
if (nearUnit != null && nearUnit.isAlive())
{
EmitFromCatalog("power", powerId, nearUnit, PowerInterestCatalog.GetOrFallback, null, false);
EmitFromCatalog("power", powerId, nearUnit, EventCatalog.Power.GetOrFallback, null, false);
return;
}
@ -75,7 +75,7 @@ public static class DeferredInterestFeed
"subspecies_trait",
traitId,
anchor,
SubspeciesTraitInterestCatalog.GetOrFallback,
EventCatalog.SubspeciesTrait.GetOrFallback,
related: null,
locationOnly: false);
}
@ -86,7 +86,7 @@ public static class DeferredInterestFeed
"gene",
geneId,
actor,
GeneInterestCatalog.GetOrFallback,
EventCatalog.Gene.GetOrFallback,
related: null,
locationOnly: false);
}
@ -97,7 +97,7 @@ public static class DeferredInterestFeed
"phenotype",
phenotypeId,
actor,
PhenotypeInterestCatalog.GetOrFallback,
EventCatalog.Phenotype.GetOrFallback,
related: null,
locationOnly: false);
}
@ -109,7 +109,7 @@ public static class DeferredInterestFeed
return;
}
DiscreteEventEntry entry = WorldLawInterestCatalog.GetOrFallback(lawId);
DiscreteEventEntry entry = EventCatalog.WorldLaw.GetOrFallback(lawId);
if (!entry.CreatesInterest)
{
return;
@ -134,7 +134,7 @@ public static class DeferredInterestFeed
return;
}
DiscreteEventEntry entry = BiomeInterestCatalog.GetOrFallback(biomeId);
DiscreteEventEntry entry = EventCatalog.Biome.GetOrFallback(biomeId);
if (!entry.CreatesInterest)
{
return;

View file

@ -93,7 +93,7 @@ public static class InterestFeeds
return;
}
WorldLogEventEntry entry = WorldLogEventCatalog.GetOrFallback(message.asset_id);
WorldLogEventEntry entry = EventCatalog.WorldLog.GetOrFallback(message.asset_id);
if (!entry.CreatesInterest)
{
return;
@ -325,15 +325,14 @@ public static class InterestFeeds
}
string verb = taskOrBeat ?? "fighting";
// One combat key per fighter so activity + scanner merge instead of thrashing.
string key = "combat:" + id;
string key = EventCatalog.Combat.Key(id);
var candidate = new InterestCandidate
{
Key = key,
LeadKind = InterestLeadKind.EventLed,
Category = "Combat",
Source = "activity",
EventStrength = 88f,
EventStrength = EventCatalog.Combat.ActivityStrength,
VisualConfidence = 0.8f,
Position = actor.current_position,
FollowUnit = actor,
@ -348,9 +347,9 @@ public static class InterestFeeds
KingdomKey = actor.kingdom != null ? (actor.kingdom.name ?? "") : "",
CreatedAt = Time.unscaledTime,
LastSeenAt = Time.unscaledTime,
ExpiresAt = Time.unscaledTime + 20f,
MinWatch = 4f,
MaxWatch = 60f,
ExpiresAt = Time.unscaledTime + EventCatalog.Combat.ActivityTtl,
MinWatch = EventCatalog.Combat.MinWatch,
MaxWatch = EventCatalog.Combat.MaxWatch,
Completion = InterestCompletionKind.CombatActive
};
candidate.ParticipantIds.Add(id);
@ -370,7 +369,7 @@ public static class InterestFeeds
return;
}
StatusInterestEntry entry = StatusInterestCatalog.GetOrFallback(statusId);
StatusInterestEntry entry = EventCatalog.Status.GetOrFallback(statusId);
if (!entry.CreatesInterest)
{
return;

View file

@ -12,7 +12,7 @@ public static class MetaInterestFeed
return;
}
DiscreteEventEntry entry = EraInterestCatalog.GetOrFallback(eraId);
DiscreteEventEntry entry = EventCatalog.Era.GetOrFallback(eraId);
if (!entry.CreatesInterest)
{
return;

View file

@ -14,7 +14,7 @@ public static class PlotInterestFeed
return;
}
DiscreteEventEntry entry = PlotInterestCatalog.GetOrFallback(plotAssetId);
DiscreteEventEntry entry = EventCatalog.Plot.GetOrFallback(plotAssetId);
if (!entry.CreatesInterest)
{
return;

View file

@ -12,7 +12,7 @@ public static class RelationshipInterestFeed
return;
}
DiscreteEventEntry entry = RelationshipEventCatalog.GetOrFallback(eventId);
DiscreteEventEntry entry = EventCatalog.Relationship.GetOrFallback(eventId);
if (!entry.CreatesInterest)
{
return;
@ -69,7 +69,7 @@ public static class RelationshipInterestFeed
return;
}
DiscreteEventEntry entry = RelationshipEventCatalog.GetOrFallback(eventId);
DiscreteEventEntry entry = EventCatalog.Relationship.GetOrFallback(eventId);
Actor follow = anchor != null && anchor.isAlive() ? anchor : null;
if (follow == null)
{
@ -122,7 +122,7 @@ public static class RelationshipInterestFeed
return EventReason.FamilyPack(subject, related, "leave");
default:
return EventReason.Apply(
RelationshipEventCatalog.GetOrFallback(eventId).LabelTemplate,
EventCatalog.Relationship.GetOrFallback(eventId).LabelTemplate,
subject,
related,
eventId);

View file

@ -59,7 +59,7 @@ public static class WarInterestFeed
private static bool TryRegisterWar(object war, string phase)
{
string warTypeId = ReadWarTypeId(war);
WarTypeInterestEntry entry = WarTypeInterestCatalog.GetOrFallback(warTypeId);
WarTypeInterestEntry entry = EventCatalog.WarType.GetOrFallback(warTypeId);
if (!entry.CreatesInterest)
{
return false;
@ -86,7 +86,7 @@ public static class WarInterestFeed
string phaseKey = string.IsNullOrEmpty(phase) ? "active" : phase;
string key = "war:" + phaseKey + ":" + (ReadString(war, "id") ?? labelPair) + ":" + (warTypeId ?? "normal");
string label = WarTypeInterestCatalog.MakeLabel(entry, labelPair);
string label = EventCatalog.WarType.MakeLabel(entry, labelPair);
if (phaseKey == "new")
{
label = "War begins: " + labelPair;

View file

@ -287,7 +287,7 @@ public static class DeferredEventPatches
}
// High-frequency hook: only kingdom-affecting decisions, never idle AI ticks.
if (!DecisionInterestCatalog.IsCameraWorthy(id))
if (!EventCatalog.Decision.IsCameraWorthy(id))
{
return;
}
@ -304,7 +304,7 @@ public static class DeferredEventPatches
return;
}
string id = "phenotype";
string id = "";
try
{
object data = __instance.data;
@ -312,12 +312,19 @@ public static class DeferredEventPatches
?? data?.GetType().GetProperty("phenotype")?.GetValue(data, null);
if (ph != null)
{
id = ph.ToString();
id = ph.ToString() ?? "";
}
}
catch
{
// ignore
id = "";
}
// Placeholder / empty ids are not camera events (catalog ambient is CreatesInterest=false).
if (string.IsNullOrEmpty(id)
|| string.Equals(id, "phenotype", StringComparison.OrdinalIgnoreCase))
{
return;
}
DeferredInterestFeed.EmitPhenotype(id, __instance);

View file

@ -112,7 +112,7 @@ public static class TraitEventPatches
return;
}
DiscreteEventEntry entry = TraitInterestCatalog.GetOrFallback(traitId);
DiscreteEventEntry entry = EventCatalog.Trait.GetOrFallback(traitId);
if (!entry.CreatesInterest)
{
return;

View file

@ -14,7 +14,7 @@ public static class WorldLogMessageAddPatch
return;
}
WorldLogEventEntry entry = WorldLogEventCatalog.GetOrFallback(pMessage.asset_id);
WorldLogEventEntry entry = EventCatalog.WorldLog.GetOrFallback(pMessage.asset_id);
// Chronicle notable world events only (authored ChronicleEligible / story-strength+).
if (!entry.ChronicleEligible)
{

View file

@ -214,7 +214,7 @@ public static class HappinessEventRouter
FlushStaleAggregates();
HappinessCatalogEntry entry = HappinessEventCatalog.GetOrFallback(effectId);
HappinessCatalogEntry entry = EventCatalog.Happiness.GetOrFallback(effectId);
if (related == null
&& HappinessContextBag.TryGetRelated(subject, out Actor bagRelated, out HappinessRelationRole bagRole))
{
@ -407,7 +407,7 @@ public static class HappinessEventRouter
continue;
}
HappinessCatalogEntry entry = HappinessEventCatalog.GetOrFallback(bucket.EffectId);
HappinessCatalogEntry entry = EventCatalog.Happiness.GetOrFallback(bucket.EffectId);
HappinessOccurrence summary = BuildOccurrence(
subject,
bucket.EffectId,
@ -450,7 +450,7 @@ public static class HappinessEventRouter
bool applied,
bool suppressedByPsychopath)
{
HappinessCatalogEntry entry = HappinessEventCatalog.GetOrFallback(effectId);
HappinessCatalogEntry entry = EventCatalog.Happiness.GetOrFallback(effectId);
long subjectId = 0;
string subjectName = "Someone";
string species = "";

View file

@ -39,12 +39,12 @@ public static class InterestScoring
public static float EventStrengthForHappiness(string effectId)
{
return HappinessEventCatalog.GetOrFallback(effectId).EventStrength;
return EventCatalog.Happiness.GetOrFallback(effectId).EventStrength;
}
public static float EventStrengthForWorldLog(string assetId)
{
return WorldLogEventCatalog.GetOrFallback(assetId).EventStrength;
return EventCatalog.WorldLog.GetOrFallback(assetId).EventStrength;
}
public static bool IsFillScore(float totalScore)

View file

@ -126,11 +126,11 @@ public static class WorldActivityScanner
string label = EventReason.Fight(actor, foe);
var candidate = new InterestCandidate
{
Key = "combat:" + id,
Key = EventCatalog.Combat.Key(id),
LeadKind = InterestLeadKind.EventLed,
Category = "Combat",
Source = "scanner",
EventStrength = Mathf.Max(actionScore, 80f),
EventStrength = Mathf.Max(actionScore, EventCatalog.Combat.ScannerStrengthFloor),
CharacterSignificance = charScore,
VisualConfidence = 0.7f,
Position = actor.current_position,
@ -148,9 +148,9 @@ public static class WorldActivityScanner
NotableParticipantCount = notables,
CreatedAt = Time.unscaledTime,
LastSeenAt = Time.unscaledTime,
ExpiresAt = Time.unscaledTime + 18f,
MinWatch = 4f,
MaxWatch = 60f,
ExpiresAt = Time.unscaledTime + EventCatalog.Combat.ScannerTtl,
MinWatch = EventCatalog.Combat.MinWatch,
MaxWatch = EventCatalog.Combat.MaxWatch,
Completion = InterestCompletionKind.CombatActive
};
InterestScoring.ScoreCheap(candidate);

View file

@ -26,7 +26,7 @@ public static class WorldLogEventHarness
{
List<string> liveIds = ActivityAssetCatalog.EnumerateLiveWorldLogIds();
var authored = new HashSet<string>(StringComparer.OrdinalIgnoreCase);
foreach (string id in WorldLogEventCatalog.AuthoredIds)
foreach (string id in EventCatalog.WorldLog.AuthoredIds)
{
authored.Add(id);
}
@ -44,8 +44,8 @@ public static class WorldLogEventHarness
string id = liveIds[i];
liveSet.Add(id);
WorldLogAsset asset = ActivityAssetCatalog.TryGetWorldLogAsset(id);
bool hasAuthored = WorldLogEventCatalog.HasAuthored(id);
WorldLogEventEntry entry = WorldLogEventCatalog.GetOrFallback(id);
bool hasAuthored = EventCatalog.WorldLog.HasAuthored(id);
WorldLogEventEntry entry = EventCatalog.WorldLog.GetOrFallback(id);
if (!hasAuthored || entry.IsFallback)
{
missingAuthored++;

View file

@ -3,19 +3,19 @@ using System.Collections.Generic;
namespace IdleSpectator;
/// <summary>
/// Compatibility facade over <see cref="WorldLogEventCatalog"/>. Prefer the catalog directly.
/// Compatibility facade over <see cref="EventCatalog.WorldLog"/>. Prefer the catalog directly.
/// </summary>
public static class WorldLogInterestTable
{
public static bool TryGetEventStrength(string assetId, out float eventStrength)
{
return WorldLogEventCatalog.TryGetEventStrength(assetId, out eventStrength);
return EventCatalog.WorldLog.TryGetEventStrength(assetId, out eventStrength);
}
public static string MakeLabel(WorldLogMessage message)
{
return WorldLogEventCatalog.MakeLabel(message);
return EventCatalog.WorldLog.MakeLabel(message);
}
public static IEnumerable<string> AuthoredIds => WorldLogEventCatalog.AuthoredIds;
public static IEnumerable<string> AuthoredIds => EventCatalog.WorldLog.AuthoredIds;
}

View file

@ -1,7 +1,7 @@
{
"name": "IdleSpectator",
"author": "dazed",
"version": "0.20.12",
"version": "0.21.1",
"description": "AFK Idle Spectator (I) + Lore (L). Event-centered scene director + happiness Activity/Life logging.",
"GUID": "com.dazed.idlespectator"
}

View file

@ -95,7 +95,7 @@
"IdleSpectator/WorldActivityScanner.cs",
"IdleSpectator/InterestDirector.cs",
"IdleSpectator/InterestVariety.cs",
"IdleSpectator/InterestFeeds.cs"
"IdleSpectator/Events/Feeds/InterestFeeds.cs"
],
"designIntent": [
"Actions matter much more than characters.",

View file

@ -3,6 +3,10 @@
Inventory policy after the full gap expand.
Camera interrupt is score-margin only (`cutInMargin`); no Signal/Ambient ownership gate.
**Single inventory:** [`EventCatalog`](../IdleSpectator/Events/EventCatalog.cs) (partials under `Events/Catalogs/`).
Nested domains: `Status`, `Happiness`, `WorldLog`, `Trait`, `Combat`, `Spell`, …
Feeds/patches register from those dials; `InterestDirector` only ranks candidates.
## Dials
| Dial | Role |
@ -30,17 +34,17 @@ Ambient / Character fill is exempt - events may take the camera immediately.
| Source | Primary owner | Reason factory | Notes |
|--------|---------------|----------------|-------|
| WorldLog | `InterestFeeds.OnWorldLogMessage` | catalog / EventReason | Strength from WorldLogEventCatalog |
| Happiness | `IngestHappiness` | HappinessEventCatalog + EventReason | Birth/hatch freshness; grief sticky |
| WorldLog | `InterestFeeds.OnWorldLogMessage` | catalog / EventReason | Strength from `EventCatalog.WorldLog` |
| Happiness | `IngestHappiness` | `EventCatalog.Happiness` + EventReason | Birth/hatch freshness; grief sticky |
| Status | `OnStatusChange` | EventReason.Status | `drowning` CreatesInterest=true, strength ~50; notable via CharacterSignificance |
| Scanner combat | WorldActivityScanner | EventReason.Fight / Battle | Completion CombatActive |
| Scanner combat | WorldActivityScanner | EventReason.Fight / Battle | Completion CombatActive; dials `EventCatalog.Combat` |
| War | WarEventPatches + WarInterestFeed.Tick | war type labels | |
| Plot | PlotEventPatches + PlotInterestFeed.Tick | PlotInterestCatalog | |
| Plot | PlotEventPatches + PlotInterestFeed.Tick | `EventCatalog.Plot` | |
| Relationship | RelationshipEventPatches + happiness lovers | EventReason.* | |
| Trait | TraitEventPatches | EventReason.Trait | Spawn window filters routine traits |
| Building | BuildingEventPatches | EventReason.Building* | Eat/damage/falls |
| Boat | BoatEventPatches | EventReason.Boat | |
| Book | BookEventPatches | BookInterestCatalog sentences | |
| Book | BookEventPatches | `EventCatalog.Book` sentences | |
| Era / Meta | MetaEventPatches | EventReason.MetaNew / era labels | |
| Spell | CombatActionLibrary.tryToCastSpell | EventReason.Library | Ambient CreatesInterest=false except spectacle ids |
| Power | PlayerControl.clickedFinal | EventReason.HumanizeId | Spectacle ids create interest |

View file

@ -11,9 +11,23 @@ Quiet grace / inactive dwell clears the reason even if focus has not switched ye
## EventReason
[`IdleSpectator/EventReason.cs`](../IdleSpectator/EventReason.cs) is the sole Label factory for camera candidates.
[`IdleSpectator/Events/EventReason.cs`](../IdleSpectator/Events/EventReason.cs) is the sole Label factory for camera candidates.
It lives in the Events module with catalogs (not in the director).
Feeds call typed helpers (`Fight`, `BuildingEat`, `SeekingLover`, …) or `Apply(template, a, b, id)`.
## Events module layout
| Path | Role |
|------|------|
| `Events/EventCatalog.cs` (+ `Catalogs/EventCatalog.*.cs`) | **One inventory** - nested domains (`Status`, `Combat`, …) |
| `Events/Feeds/` | Build + register candidates from catalog dials |
| `Events/Patches/` | Harmony hooks → feeds |
| `Events/EventReason.cs` | Orange reason sentences |
| `Events/EventFeedUtil.cs` | Shared Register path |
| `Events/DiscreteEventEntry.cs` | Shared catalog row shape |
`InterestDirector` only ranks registered candidates for the camera - it does not author event inventory.
Rules:
- Sentence form with names: `{a} is fighting {b}`, `{a} is eating a beehive`, `{a} is seeking a lover`.