worldbox-observer-mod/IdleSpectator/Story/StoryReason.cs
DazedAnon c23b2b9c1e feat(spectator): add crisis chapters and harden combat theater truth
- Open war/disaster/outbreak crisis overlays with epilogue_crisis closers
- Keep Duel pairs hot only on owned cast; park sleep/freeze; drop ambient scrap pins
- Require a fallen theater partner for survivor aftermath; let king_killed cut mid-fight
- Gate crisis, combat cold, king cut-in, and living-partner aftermath in harness
2026-07-21 22:05:38 -05:00

90 lines
3.3 KiB
C#

namespace IdleSpectator;
/// <summary>Subject-led orange Labels for synthetic story aftermath / epilogue beats.</summary>
public static class StoryReason
{
public const string AftermathSurvivor = "aftermath_survivor";
public const string AftermathMourner = "aftermath_mourner";
public const string AftermathWarLinger = "aftermath_war_linger";
public const string AftermathPlotFallout = "aftermath_plot_fallout";
public const string AftermathLoveLinger = "aftermath_love_linger";
public const string EpilogueRelated = "epilogue_related";
public const string EpilogueCrisis = "epilogue_crisis";
public static bool IsStoryAsset(string assetId)
{
if (string.IsNullOrEmpty(assetId))
{
return false;
}
return assetId.StartsWith("aftermath_", System.StringComparison.OrdinalIgnoreCase)
|| assetId.StartsWith("epilogue_", System.StringComparison.OrdinalIgnoreCase);
}
public static bool IsCrisisEpilogue(string assetId)
{
return string.Equals(assetId, EpilogueCrisis, System.StringComparison.OrdinalIgnoreCase);
}
public static string AftermathLabel(string assetId, Actor follow, Actor related)
{
string name = EventFeedUtil.SafeName(follow);
if (string.IsNullOrEmpty(name))
{
name = "Someone";
}
string other = EventFeedUtil.SafeName(related);
string id = (assetId ?? "").Trim().ToLowerInvariant();
switch (id)
{
case AftermathMourner:
return string.IsNullOrEmpty(other)
? name + " mourns the fallen"
: name + " mourns " + other;
case AftermathWarLinger:
return name + " lingers on the war front";
case AftermathPlotFallout:
return name + " faces the plot's fallout";
case AftermathLoveLinger:
return string.IsNullOrEmpty(other)
? name + " stays with their love"
: name + " stays beside " + other;
case EpilogueRelated:
return string.IsNullOrEmpty(other)
? name + " carries on after the story"
: name + " seeks " + other + " after the story";
case EpilogueCrisis:
return name + " surveys the aftermath of the crisis";
case AftermathSurvivor:
default:
// Only name a dead theater partner. Never claim "the fallen" while the partner lives
// (soak: Norron vs Nerari attack gaps minted false survivor tips).
if (related != null)
{
bool dead = false;
try
{
dead = !related.isAlive();
}
catch
{
dead = true;
}
if (dead && !string.IsNullOrEmpty(other))
{
return name + " stands over " + other;
}
if (!dead)
{
return name + " catches their breath";
}
}
return name + " stands over the fallen";
}
}
}