- Introduce new narrative probes for episode grammar, ensemble balance, and prose redundancy - Implement narrative presentation coverage tracking for better event visibility - Update harness scenarios to include new narrative ingestion and persistence tests - Refactor event emission to include narrative development IDs and presentations - Expand InterestCandidate to support narrative presentation models and roles
290 lines
7 KiB
C#
290 lines
7 KiB
C#
using System.Collections.Generic;
|
|
|
|
namespace IdleSpectator;
|
|
|
|
public enum NarrativeDevelopmentKind
|
|
{
|
|
Unknown,
|
|
BondFormed,
|
|
BondBroken,
|
|
ChildBorn,
|
|
FriendFormed,
|
|
Death,
|
|
Kill,
|
|
RoleGained,
|
|
RoleLost,
|
|
HomeFounded,
|
|
HomeGained,
|
|
HomeLost,
|
|
WarJoined,
|
|
WarEnded,
|
|
PlotJoined,
|
|
PlotEnded,
|
|
RivalEncounter,
|
|
Transformation,
|
|
Recovery
|
|
}
|
|
|
|
public enum NarrativeFunction
|
|
{
|
|
Noise,
|
|
CharacterTexture,
|
|
WorldContext,
|
|
ThreadOpener,
|
|
Development,
|
|
Escalation,
|
|
TurningPoint,
|
|
Resolution,
|
|
Consequence
|
|
}
|
|
|
|
public enum NarrativeThreadKind
|
|
{
|
|
Unknown,
|
|
Courtship,
|
|
Partnership,
|
|
Lineage,
|
|
SeparationGrief,
|
|
RiseToRule,
|
|
Reign,
|
|
Succession,
|
|
Founding,
|
|
HomeLoss,
|
|
Rivalry,
|
|
PersonalCombat,
|
|
WarInvolvement,
|
|
PlotBetrayal,
|
|
Transformation,
|
|
Recovery
|
|
}
|
|
|
|
public enum NarrativePhase
|
|
{
|
|
Setup,
|
|
Pressure,
|
|
Escalation,
|
|
TurningPoint,
|
|
Outcome,
|
|
Consequence
|
|
}
|
|
|
|
public enum NarrativeThreadStatus
|
|
{
|
|
Emerging,
|
|
Active,
|
|
Dormant,
|
|
Resolved,
|
|
Abandoned
|
|
}
|
|
|
|
public enum CharacterConsequenceKind
|
|
{
|
|
Unknown,
|
|
FoundLove,
|
|
LostPartner,
|
|
BecameParent,
|
|
WasBorn,
|
|
LostFamily,
|
|
LostLife,
|
|
TookLife,
|
|
RoseToRole,
|
|
LostRole,
|
|
FoundedHome,
|
|
LostHome,
|
|
EnteredWar,
|
|
SurvivedWar,
|
|
JoinedPlot,
|
|
PlotResolved,
|
|
Transformed,
|
|
Recovered
|
|
}
|
|
|
|
/// <summary>Evidence-backed semantic state transition. Contains no final player-facing prose.</summary>
|
|
public sealed class NarrativeDevelopment
|
|
{
|
|
public string Id = "";
|
|
public NarrativeDevelopmentKind Kind;
|
|
public NarrativeFunction Function;
|
|
public long SubjectId;
|
|
public LifeSagaIdentity Subject;
|
|
public long OtherId;
|
|
public LifeSagaIdentity Other;
|
|
public readonly List<long> OtherIds = new List<long>(4);
|
|
public string CorrelationKey = "";
|
|
public string FamilyKey = "";
|
|
public string CityKey = "";
|
|
public string KingdomKey = "";
|
|
public string WarKey = "";
|
|
public string PlotKey = "";
|
|
public string PreviousState = "";
|
|
public string NewState = "";
|
|
public string Outcome = "";
|
|
public string EvidenceSource = "";
|
|
public string DateLabel = "";
|
|
public float OccurredAt;
|
|
public float Magnitude;
|
|
public float Confidence = 1f;
|
|
public bool Presentable = true;
|
|
public bool IsNewStateChange = true;
|
|
}
|
|
|
|
public sealed class NarrativeCastRole
|
|
{
|
|
public long CharacterId;
|
|
public string Role = "";
|
|
}
|
|
|
|
/// <summary>Durable unresolved question centered on one life.</summary>
|
|
public sealed class NarrativeThread
|
|
{
|
|
public string Id = "";
|
|
public NarrativeThreadKind Kind;
|
|
public long ProtagonistId;
|
|
public readonly List<NarrativeCastRole> Cast = new List<NarrativeCastRole>(6);
|
|
public readonly List<string> DevelopmentIds = new List<string>(12);
|
|
public string AnchorKey = "";
|
|
public string OpenedByDevelopmentId = "";
|
|
public string LatestMeaningfulChangeId = "";
|
|
public string CentralQuestion = "";
|
|
public string PressureEvidence = "";
|
|
public string Resolution = "";
|
|
public NarrativePhase Phase;
|
|
public NarrativeThreadStatus Status;
|
|
public float OpenedAt;
|
|
public float UpdatedAt;
|
|
public float Momentum;
|
|
public float Urgency;
|
|
public float Coherence;
|
|
public float Novelty;
|
|
public float CoverageDebt;
|
|
|
|
public bool IsOpen => Status == NarrativeThreadStatus.Emerging
|
|
|| Status == NarrativeThreadStatus.Active
|
|
|| Status == NarrativeThreadStatus.Dormant;
|
|
|
|
public bool HasCast(long id)
|
|
{
|
|
if (id == 0) return false;
|
|
for (int i = 0; i < Cast.Count; i++)
|
|
{
|
|
if (Cast[i] != null && Cast[i].CharacterId == id) return true;
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
public void AddCast(long id, string role)
|
|
{
|
|
if (id == 0 || HasCast(id)) return;
|
|
Cast.Add(new NarrativeCastRole { CharacterId = id, Role = role ?? "" });
|
|
}
|
|
}
|
|
|
|
public sealed class CharacterConsequence
|
|
{
|
|
public string Id = "";
|
|
public long CharacterId;
|
|
public string ThreadId = "";
|
|
public string DevelopmentId = "";
|
|
public CharacterConsequenceKind Kind;
|
|
public string Role = "";
|
|
public long OtherId;
|
|
public LifeSagaIdentity Other;
|
|
public string Context = "";
|
|
public string Outcome = "";
|
|
public string DateLabel = "";
|
|
public float OccurredAt;
|
|
public float Importance;
|
|
public float Confidence = 1f;
|
|
}
|
|
|
|
public sealed class CharacterStoryState
|
|
{
|
|
public long CharacterId;
|
|
public LifeSagaIdentity Identity;
|
|
public readonly List<string> OpenThreadIds = new List<string>(6);
|
|
public readonly List<string> ResolvedThreadIds = new List<string>(8);
|
|
public readonly List<string> RecentDevelopmentIds = new List<string>(16);
|
|
public readonly List<string> ConsequenceIds = new List<string>(16);
|
|
public float StoryMomentum;
|
|
public float StoryPotential;
|
|
public float LastMeaningfulChangeAt;
|
|
}
|
|
|
|
public sealed class NarrativeChapter
|
|
{
|
|
public string Id = "";
|
|
public string ThreadId = "";
|
|
public string Line = "";
|
|
public string DateLabel = "";
|
|
public float At;
|
|
public float Importance;
|
|
}
|
|
|
|
public enum EpisodePurpose
|
|
{
|
|
Establish,
|
|
Develop,
|
|
Payoff,
|
|
Consequence,
|
|
Reintroduce
|
|
}
|
|
|
|
public enum EpisodeShotRole
|
|
{
|
|
Unknown,
|
|
Establish,
|
|
Development,
|
|
Pressure,
|
|
TurningPoint,
|
|
Payoff,
|
|
Consequence,
|
|
Reintroduction,
|
|
WorldContext
|
|
}
|
|
|
|
public sealed class EpisodePlan
|
|
{
|
|
public string ThreadId = "";
|
|
public long ProtagonistId;
|
|
public readonly List<long> EligibleCastIds = new List<long>(6);
|
|
public string EntryDevelopmentId = "";
|
|
public EpisodePurpose Purpose;
|
|
public string InformationGoal = "";
|
|
public float StartedAt;
|
|
public float LastProgressAt;
|
|
public float InterruptedAt = -1f;
|
|
public string LastShotKey = "";
|
|
public long LastSubjectId;
|
|
public int RepeatedSubjectCount;
|
|
public int CombatShotCount;
|
|
public bool GoalMet;
|
|
public string CompletionReason = "";
|
|
public readonly List<EpisodeShotRole> CoveredRoles = new List<EpisodeShotRole>(8);
|
|
public readonly List<EpisodeShotRole> PendingRoles = new List<EpisodeShotRole>(8);
|
|
public readonly List<string> RecentSemanticKeys = new List<string>(10);
|
|
|
|
public bool HasCovered(EpisodeShotRole role) => CoveredRoles.Contains(role);
|
|
|
|
public void Cover(EpisodeShotRole role)
|
|
{
|
|
if (role == EpisodeShotRole.Unknown || role == EpisodeShotRole.WorldContext) return;
|
|
if (!CoveredRoles.Contains(role)) CoveredRoles.Add(role);
|
|
PendingRoles.Remove(role);
|
|
}
|
|
}
|
|
|
|
public sealed class NarrativeBeatModel
|
|
{
|
|
public long PerspectiveCharacterId;
|
|
public string DevelopmentId = "";
|
|
public string ThreadId = "";
|
|
public NarrativeDevelopmentKind ActionKind;
|
|
public long OtherId;
|
|
public LifeSagaIdentity Other;
|
|
public string Change = "";
|
|
public string Outcome = "";
|
|
public NarrativePhase ThreadPhase;
|
|
public string ContextEvidence = "";
|
|
public float Confidence = 1f;
|
|
}
|