using System.Collections.Generic; using UnityEngine; namespace IdleSpectator; public enum InterestLeadKind { EventLed = 0, CharacterLed = 1 } public enum InterestCompletionKind { /// One-shot narrative dwell (WorldLog, harness tips). FixedDwell = 0, /// Combat / hunt / fire while participants stay live. CombatActive = 1, /// Owning AI task / beat still live. ActivityActive = 2, /// Grief / family emotion with survivor + optional crying. HappinessGrief = 3, /// Status phase still present on subject. StatusPhase = 4, /// Character vignette until max watch or cold activity. CharacterVignette = 5, /// Harness-forced session; active until released or max cap. Manual = 6 } /// /// Durable interest scene candidate. is the sole ranking signal; /// typed fields (lead, completion, combat) gate interrupt policy. /// public sealed class InterestCandidate { public string Key = ""; public InterestLeadKind LeadKind = InterestLeadKind.EventLed; public string Category = ""; public string Source = ""; public float EventStrength; public float CharacterSignificance; public float Novelty = 1f; public float VisualConfidence = 0.5f; public float TotalScore; /// Live fighters / participants in a cluster (battles, multi-unit events). public int ParticipantCount; /// Peak fighters seen this combat scene (scale demotion hysteresis). public int CombatPeakParticipants; /// Sticky opposing camps for the orange tip (species/kingdom keys). public EnsembleFrame CombatSideFrame = EnsembleFrame.CountOnly; public string CombatSideAKey = ""; public string CombatSideADisplay = ""; public string CombatSideAKingdom = ""; public int CombatSideACount; public string CombatSideBKey = ""; public string CombatSideBDisplay = ""; public string CombatSideBKingdom = ""; public int CombatSideBCount; /// Tracked camp members for sticky scoreboard (kept until combat grace ends). public readonly List CombatSideAIds = new List(8); public readonly List CombatSideBIds = new List(8); /// Notable (king/favorite/leader/high renown) participants in the cluster. public int NotableParticipantCount; public Vector3 Position; public Actor FollowUnit; public Actor RelatedUnit; public long SubjectId; public long RelatedId; public string Label = ""; public string AssetId = ""; public string SpeciesId = ""; public string Verb = ""; public string CityKey = ""; public string KingdomKey = ""; public string RegionKey = ""; public string HappinessEffectId = ""; public string StatusId = ""; public string CorrelationKey = ""; public float CreatedAt; public float LastSeenAt; public float ExpiresAt; public float MinWatch = 1.5f; public float MaxWatch = 45f; public InterestCompletionKind Completion = InterestCompletionKind.FixedDwell; public bool Resumable = true; public bool ForceActive; public bool Selected; public string ScoreDetail = ""; public readonly List ParticipantIds = new List(4); public bool HasFollowUnit => FollowUnit != null && FollowUnit.isAlive(); public bool HasValidPosition => HasFollowUnit || (Position != Vector3.zero && !float.IsNaN(Position.x)); public bool HasStickyCombatSides => !string.IsNullOrEmpty(CombatSideAKey) && !string.IsNullOrEmpty(CombatSideBKey) && (CombatSideFrame == EnsembleFrame.SpeciesVsSpecies || CombatSideFrame == EnsembleFrame.KingdomVsKingdom); public void ClearCombatSticky() { CombatPeakParticipants = 0; CombatSideFrame = EnsembleFrame.CountOnly; CombatSideAKey = ""; CombatSideADisplay = ""; CombatSideAKingdom = ""; CombatSideACount = 0; CombatSideBKey = ""; CombatSideBDisplay = ""; CombatSideBKingdom = ""; CombatSideBCount = 0; CombatSideAIds.Clear(); CombatSideBIds.Clear(); } public InterestEvent ToInterestEvent() { return new InterestEvent { Score = TotalScore, Position = Position, FollowUnit = FollowUnit, RelatedUnit = RelatedUnit, Label = Label, CreatedAt = CreatedAt, AssetId = AssetId, ParticipantCount = ParticipantCount, NotableParticipantCount = NotableParticipantCount, CharacterSignificance = CharacterSignificance }; } public InterestCandidate CloneShallow() { var copy = new InterestCandidate { Key = Key, LeadKind = LeadKind, Category = Category, Source = Source, EventStrength = EventStrength, CharacterSignificance = CharacterSignificance, Novelty = Novelty, VisualConfidence = VisualConfidence, TotalScore = TotalScore, ParticipantCount = ParticipantCount, CombatPeakParticipants = CombatPeakParticipants, CombatSideFrame = CombatSideFrame, CombatSideAKey = CombatSideAKey, CombatSideADisplay = CombatSideADisplay, CombatSideAKingdom = CombatSideAKingdom, CombatSideACount = CombatSideACount, CombatSideBKey = CombatSideBKey, CombatSideBDisplay = CombatSideBDisplay, CombatSideBKingdom = CombatSideBKingdom, CombatSideBCount = CombatSideBCount, NotableParticipantCount = NotableParticipantCount, Position = Position, FollowUnit = FollowUnit, RelatedUnit = RelatedUnit, SubjectId = SubjectId, RelatedId = RelatedId, Label = Label, AssetId = AssetId, SpeciesId = SpeciesId, Verb = Verb, CityKey = CityKey, KingdomKey = KingdomKey, RegionKey = RegionKey, HappinessEffectId = HappinessEffectId, StatusId = StatusId, CorrelationKey = CorrelationKey, CreatedAt = CreatedAt, LastSeenAt = LastSeenAt, ExpiresAt = ExpiresAt, MinWatch = MinWatch, MaxWatch = MaxWatch, Completion = Completion, Resumable = Resumable, ForceActive = ForceActive, Selected = Selected, ScoreDetail = ScoreDetail }; for (int i = 0; i < ParticipantIds.Count; i++) { copy.ParticipantIds.Add(ParticipantIds[i]); } for (int i = 0; i < CombatSideAIds.Count; i++) { copy.CombatSideAIds.Add(CombatSideAIds[i]); } for (int i = 0; i < CombatSideBIds.Count; i++) { copy.CombatSideBIds.Add(CombatSideBIds[i]); } return copy; } }