worldbox-observer-mod/IdleSpectator/Story/LifeSagaOverview.cs
DazedAnon 4b6c829bd0 feat(saga): ship adaptive dossier tabs with durable memory
- Add Dossier/Saga tabs, Design A panel, and hover preview with read-pause
- Persist observed saga facts across roster churn; pin subject without stale fallback
- Restore Saga after Open Lore; hide redundant Kind · Climax spine under matching tips
- Densify dossier header/chips and keep the cast rail as stable top chrome
- Extend harness coverage for hover restore, empty pick, Evidence, and Lore return
2026-07-22 03:27:46 -05:00

135 lines
3.9 KiB
C#

using System.Collections.Generic;
namespace IdleSpectator;
/// <summary>
/// Compatibility façade over <see cref="LifeSagaPresentation"/>.
/// Prefer <see cref="LifeSagaPresentation.Build"/> for new UI.
/// </summary>
public static class LifeSagaOverview
{
public static LifeSagaSnapshot BuildSnapshot(LifeSagaSlot slot)
{
var snapshot = new LifeSagaSnapshot();
if (slot == null || slot.UnitId == 0)
{
return snapshot;
}
LifeSagaViewModel model = LifeSagaPresentation.Build(slot.UnitId);
snapshot.UnitId = model.UnitId;
snapshot.Header = model.Name;
snapshot.Subtitle = model.Title;
if (!string.IsNullOrEmpty(model.StakeLine))
{
snapshot.Rows.Add(new LifeSagaSnapshotRow
{
Kind = LifeSagaSnapshotRowKind.Headline,
Text = model.StakeLine
});
}
if (model.Cast.Count > 0)
{
var parts = new List<string>(model.Cast.Count);
for (int i = 0; i < model.Cast.Count; i++)
{
parts.Add(model.Cast[i].Relation + " " + model.Cast[i].Name);
}
snapshot.Rows.Add(new LifeSagaSnapshotRow
{
Kind = LifeSagaSnapshotRowKind.Circle,
Text = string.Join(" · ", parts)
});
}
if (!string.IsNullOrEmpty(model.EvidenceLine))
{
snapshot.Rows.Add(new LifeSagaSnapshotRow
{
Kind = LifeSagaSnapshotRowKind.Current,
Text = model.EvidenceTitle + ": " + model.EvidenceLine
});
}
for (int i = 0; i < model.Legacy.Count; i++)
{
snapshot.Rows.Add(new LifeSagaSnapshotRow
{
Kind = LifeSagaSnapshotRowKind.Chapter,
ChapterKind = ToChapterKind(model.Legacy[i].Kind),
Text = model.Legacy[i].Line
});
}
return snapshot;
}
public static string Build(LifeSagaSlot slot)
{
return LifeSagaPresentation.BuildPlainText(slot);
}
public static float StandoutTraitScore(Actor actor)
{
return UnitDossier.ReadStandoutTraitNames(actor, 1).Count > 0 ? 100f : 0f;
}
private static LifeSagaChapterKind ToChapterKind(LifeSagaFactKind kind)
{
switch (kind)
{
case LifeSagaFactKind.Kill:
case LifeSagaFactKind.RivalEarned:
case LifeSagaFactKind.HardArcCombat:
return LifeSagaChapterKind.Combat;
case LifeSagaFactKind.WarJoin:
case LifeSagaFactKind.WarEnd:
case LifeSagaFactKind.HardArcWar:
return LifeSagaChapterKind.War;
case LifeSagaFactKind.PlotJoin:
case LifeSagaFactKind.PlotEnd:
case LifeSagaFactKind.HardArcPlot:
return LifeSagaChapterKind.Plot;
case LifeSagaFactKind.BondFormed:
case LifeSagaFactKind.HardArcLove:
return LifeSagaChapterKind.Love;
case LifeSagaFactKind.BondBroken:
case LifeSagaFactKind.Death:
case LifeSagaFactKind.HardArcGrief:
return LifeSagaChapterKind.Grief;
default:
return LifeSagaChapterKind.Unknown;
}
}
}
public enum LifeSagaSnapshotRowKind
{
Headline,
Current,
Circle,
Qualities,
Chapter
}
public sealed class LifeSagaSnapshotRow
{
public LifeSagaSnapshotRowKind Kind;
public LifeSagaChapterKind ChapterKind;
public string Text = "";
}
public sealed class LifeSagaSnapshot
{
public long UnitId;
public string Header = "";
public string Subtitle = "";
public readonly List<LifeSagaSnapshotRow> Rows = new List<LifeSagaSnapshotRow>();
public string ToPlainText()
{
return LifeSagaPresentation.BuildPlainText(UnitId);
}
}