using UnityEngine; namespace IdleSpectator; /// Thin adapters from confirmed game observations to semantic narrative developments. public static class NarrativeDevelopmentRouter { public static bool BondFormed(Actor subject, Actor partner, string source) { return BondFormed(subject, partner, source, out _); } public static bool BondFormed(Actor subject, Actor partner, string source, out string developmentId) { developmentId = BondFormedId(subject, partner); return Record(NarrativeDevelopmentKind.BondFormed, NarrativeFunction.ThreadOpener, subject, partner, developmentId, source, magnitude: 72f); } public static bool BondBroken(Actor subject, Actor former, string source) { return BondBroken(subject, former, source, out _); } public static bool BondBroken(Actor subject, Actor former, string source, out string developmentId) { developmentId = BondBrokenId(subject, former); return Record(NarrativeDevelopmentKind.BondBroken, NarrativeFunction.TurningPoint, subject, former, developmentId, source, magnitude: 88f, outcome: "partnership ended"); } public static bool ChildBorn(Actor parent, Actor child, string source) { return ChildBorn(parent, child, source, out _); } public static bool ChildBorn(Actor parent, Actor child, string source, out string developmentId) { string family = FamilyKey(parent); developmentId = ChildBornId(parent, child); return Record(NarrativeDevelopmentKind.ChildBorn, NarrativeFunction.Consequence, parent, child, developmentId, source, familyKey: family, magnitude: 76f, outcome: "child born"); } public static bool FriendFormed(Actor subject, Actor friend, string source) { return FriendFormed(subject, friend, source, out _); } public static bool FriendFormed(Actor subject, Actor friend, string source, out string developmentId) { developmentId = FriendFormedId(subject, friend); return Record(NarrativeDevelopmentKind.FriendFormed, NarrativeFunction.ThreadOpener, subject, friend, developmentId, source, magnitude: 55f); } public static string BondFormedId(Actor subject, Actor partner) => "bond:" + Pair(subject, partner) + ":formed:" + TimeBucket(); public static string BondBrokenId(Actor subject, Actor former) => "bond:" + Pair(subject, former) + ":broken:" + TimeBucket(); public static string ChildBornId(Actor parent, Actor child) => "child:" + EventFeedUtil.SafeId(parent) + ":" + EventFeedUtil.SafeId(child); public static string FriendFormedId(Actor subject, Actor friend) => "friend:" + Pair(subject, friend); internal static bool BondFormedExact( Actor subject, Actor partner, string source, string developmentId) => Record(NarrativeDevelopmentKind.BondFormed, NarrativeFunction.ThreadOpener, subject, partner, developmentId, source, magnitude: 72f); internal static bool BondBrokenExact( Actor subject, Actor former, string source, string developmentId) => Record(NarrativeDevelopmentKind.BondBroken, NarrativeFunction.TurningPoint, subject, former, developmentId, source, magnitude: 88f, outcome: "partnership ended"); internal static bool ChildBornExact( Actor parent, Actor child, string source, string developmentId) => Record(NarrativeDevelopmentKind.ChildBorn, NarrativeFunction.Consequence, parent, child, developmentId, source, familyKey: FamilyKey(parent), magnitude: 76f, outcome: "child born"); internal static bool FriendFormedExact( Actor subject, Actor friend, string source, string developmentId) => Record(NarrativeDevelopmentKind.FriendFormed, NarrativeFunction.ThreadOpener, subject, friend, developmentId, source, magnitude: 55f); public static bool Death(Actor victim, Actor killer, string attackType, string source) { return DeathExact(victim, killer, attackType, source, DeathId(victim)); } public static string DeathId(Actor victim) => "death:" + EventFeedUtil.SafeId(victim); internal static bool DeathExact( Actor victim, Actor killer, string attackType, string source, string developmentId) { return Record(NarrativeDevelopmentKind.Death, NarrativeFunction.Resolution, victim, killer, developmentId, source, newState: "dead", outcome: attackType ?? "", magnitude: 100f); } public static bool Kill(Actor killer, Actor victim, string source) { return KillExact(killer, victim, source, KillId(killer, victim)); } public static string KillId(Actor killer, Actor victim) => "kill:" + EventFeedUtil.SafeId(killer) + ":" + EventFeedUtil.SafeId(victim); internal static bool KillExact( Actor killer, Actor victim, string source, string developmentId) { return Record(NarrativeDevelopmentKind.Kill, NarrativeFunction.TurningPoint, killer, victim, developmentId, source, outcome: "victim died", magnitude: 82f); } public static bool Role(Actor subject, string role, bool gained, string source) { return RoleExact(subject, role, gained, source, RoleId(subject, role, gained)); } public static string RoleId(Actor subject, string role, bool gained) => "role:" + EventFeedUtil.SafeId(subject) + ":" + (role ?? "") + ":" + gained; internal static bool RoleExact( Actor subject, string role, bool gained, string source, string developmentId) { return Record(gained ? NarrativeDevelopmentKind.RoleGained : NarrativeDevelopmentKind.RoleLost, gained ? NarrativeFunction.TurningPoint : NarrativeFunction.Consequence, subject, null, developmentId, source, newState: role, magnitude: 78f); } public static bool Home(Actor subject, bool gained, string source) { return HomeExact(subject, gained, source, HomeId(subject, gained)); } public static string HomeId(Actor subject, bool gained) => "home:" + EventFeedUtil.SafeId(subject) + ":" + gained; internal static bool HomeExact( Actor subject, bool gained, string source, string developmentId) { return Record( gained ? NarrativeDevelopmentKind.HomeGained : NarrativeDevelopmentKind.HomeLost, gained ? NarrativeFunction.Development : NarrativeFunction.Consequence, subject, null, developmentId, source, newState: gained ? "home" : "", outcome: gained ? "" : "home lost", magnitude: gained ? 64f : 72f); } public static bool Founding(Actor subject, string kind, string key, string source) { return FoundingExact(subject, kind, key, source, FoundingId(subject, kind, key)); } public static string FoundingId(Actor subject, string kind, string key) => "founding:" + (kind ?? "") + ":" + (key ?? "") + ":" + EventFeedUtil.SafeId(subject); internal static bool FoundingExact( Actor subject, string kind, string key, string source, string developmentId) { return Record(NarrativeDevelopmentKind.HomeFounded, NarrativeFunction.TurningPoint, subject, null, developmentId, source, cityKey: kind == "city" ? key : "", kingdomKey: kind == "kingdom" ? key : "", newState: kind, magnitude: 82f); } public static bool War(Actor subject, Actor other, string warKey, bool ended, string source) { return WarExact(subject, other, warKey, ended, source, WarId(subject, warKey, ended)); } public static string WarId(Actor subject, string warKey, bool ended) => "war:" + (warKey ?? "") + ":" + EventFeedUtil.SafeId(subject) + ":" + ended; internal static bool WarExact( Actor subject, Actor other, string warKey, bool ended, string source, string developmentId) { return Record(ended ? NarrativeDevelopmentKind.WarEnded : NarrativeDevelopmentKind.WarJoined, ended ? NarrativeFunction.Resolution : NarrativeFunction.Escalation, subject, other, developmentId, source, warKey: warKey, magnitude: ended ? 86f : 68f, outcome: ended ? "war ended" : ""); } public static bool Plot(Actor subject, Actor other, string plotKey, bool ended, string source) { return PlotExact(subject, other, plotKey, ended, source, PlotId(subject, plotKey, ended)); } public static string PlotId(Actor subject, string plotKey, bool ended) => "plot:" + (plotKey ?? "") + ":" + EventFeedUtil.SafeId(subject) + ":" + ended; internal static bool PlotExact( Actor subject, Actor other, string plotKey, bool ended, string source, string developmentId) { return Record(ended ? NarrativeDevelopmentKind.PlotEnded : NarrativeDevelopmentKind.PlotJoined, ended ? NarrativeFunction.Resolution : NarrativeFunction.Escalation, subject, other, developmentId, source, plotKey: plotKey, magnitude: ended ? 78f : 64f, outcome: ended ? "plot ended" : ""); } private static bool Record( NarrativeDevelopmentKind kind, NarrativeFunction function, Actor subject, Actor other, string id, string source, string familyKey = "", string cityKey = "", string kingdomKey = "", string warKey = "", string plotKey = "", string newState = "", string outcome = "", float magnitude = 50f) { long subjectId = EventFeedUtil.SafeId(subject); if (subjectId == 0) return false; long otherId = EventFeedUtil.SafeId(other); return NarrativeStoryStore.Record(new NarrativeDevelopment { Id = id ?? "", Kind = kind, Function = function, SubjectId = subjectId, Subject = LifeSagaMemory.Snapshot(subject), OtherId = otherId, Other = LifeSagaMemory.Snapshot(other), CorrelationKey = id ?? "", FamilyKey = familyKey ?? "", CityKey = cityKey ?? "", KingdomKey = kingdomKey ?? "", WarKey = warKey ?? "", PlotKey = plotKey ?? "", NewState = newState ?? "", Outcome = outcome ?? "", EvidenceSource = source ?? "", DateLabel = LatestDate(subjectId), OccurredAt = Time.unscaledTime, Magnitude = magnitude, Confidence = 1f, Presentable = true, IsNewStateChange = true }); } private static string LatestDate(long subjectId) { var facts = LifeSagaMemory.FactsFor(subjectId); if (facts != null && facts.Count > 0 && facts[0] != null) return facts[0].DateLabel ?? ""; return ""; } private static string Pair(Actor a, Actor b) { long ai = EventFeedUtil.SafeId(a); long bi = EventFeedUtil.SafeId(b); if (bi == 0) return ai.ToString(); return ai <= bi ? ai + ":" + bi : bi + ":" + ai; } private static string FamilyKey(Actor actor) { try { if (actor != null && actor.hasFamily() && actor.family != null) { return actor.family.getID().ToString(); } } catch { // Subject id remains a stable lineage fallback. } return EventFeedUtil.SafeId(actor).ToString(); } private static int TimeBucket() => Mathf.FloorToInt(Time.unscaledTime * 10f); }