worldbox-observer-mod/IdleSpectator/Events/EventReason.cs

371 lines
9.8 KiB
C#

using System;
using System.Globalization;
using System.Text;
namespace IdleSpectator;
/// <summary>
/// Sole factory for interest Labels shown as the orange dossier reason.
/// Part of the <c>Events/</c> module with catalogs - feeds call these helpers (or Apply)
/// instead of concatenating crumbs. Director never authors reasons.
/// </summary>
public static class EventReason
{
public static string Fight(Actor a, Actor b)
{
string name = Name(a);
if (string.IsNullOrEmpty(name))
{
name = "Someone";
}
string foe = Name(b);
if (string.IsNullOrEmpty(foe))
{
return name + " is fighting";
}
return name + " is fighting " + foe;
}
public static string Battle(Actor focus, int fighters)
{
string name = Name(focus);
if (string.IsNullOrEmpty(name))
{
name = "Someone";
}
int n = Math.Max(1, fighters);
if (n <= 2)
{
return name + " is in a duel";
}
return name + " is in a fight of " + n.ToString(CultureInfo.InvariantCulture);
}
public static string SeekingLover(Actor a)
{
return NameOrSomeone(a) + " is seeking a lover";
}
public static string Hatch(Actor a)
{
return NameOrSomeone(a) + " hatches from an egg";
}
public static string Lovers(Actor a, Actor b)
{
string an = NameOrSomeone(a);
string bn = Name(b);
if (string.IsNullOrEmpty(bn))
{
return an + " found a lover";
}
return an + " became lovers with " + bn;
}
public static string LoverParted(Actor a)
{
return NameOrSomeone(a) + " parted from a lover";
}
public static string FamilyPack(Actor a, Actor peer, string phase)
{
string an = NameOrSomeone(a);
string bn = Name(peer);
string p = (phase ?? "").Trim().ToLowerInvariant();
switch (p)
{
case "join":
case "family_group_join":
return string.IsNullOrEmpty(bn)
? an + " joins a family pack"
: an + " joins a family pack with " + bn;
case "leave":
case "family_group_leave":
return string.IsNullOrEmpty(bn)
? an + " leaves a family pack"
: an + " leaves a family pack with " + bn;
case "form":
case "new":
case "family_group_new":
return string.IsNullOrEmpty(bn)
? an + " forms a family pack"
: an + " forms a family pack with " + bn;
default:
return an + " gathers with kin";
}
}
public static string NewChild(Actor a, Actor b)
{
string an = NameOrSomeone(a);
string bn = Name(b);
if (string.IsNullOrEmpty(bn))
{
return an + " has a new child";
}
// related is the child (Actor.addChild), not a co-parent.
return an + " gains a child, " + bn;
}
public static string BabyBorn(Actor a)
{
// Subject is the baby from createBabyActorFromData.
return NameOrSomeone(a) + " is created as a baby";
}
public static string NewFamily(Actor a)
{
return NameOrSomeone(a) + " starts a new family";
}
public static string FamilyEnded(Actor a)
{
return NameOrSomeone(a) + "'s family ends";
}
public static string BuildingEat(Actor a, Building food)
{
string an = NameOrSomeone(a);
string buildingId = BuildingId(food);
string buildingType = BuildingType(food);
if (string.Equals(buildingType, "type_fruits", StringComparison.OrdinalIgnoreCase))
{
return string.IsNullOrEmpty(buildingId)
? an + " is foraging fruit"
: an + " is foraging " + HumanizeId(buildingId);
}
if (!string.IsNullOrEmpty(buildingId))
{
return an + " is eating a " + HumanizeId(buildingId);
}
return an + " is eating";
}
public static string BuildingDamage(Actor a, Building building)
{
string an = NameOrSomeone(a);
string buildingId = BuildingId(building);
if (!string.IsNullOrEmpty(buildingId))
{
return an + " is damaging a " + HumanizeId(buildingId);
}
return an + " is damaging a building";
}
public static string BuildingFalls(string buildingId, Actor near)
{
string id = HumanizeId(buildingId);
if (near != null && near.isAlive())
{
string n = Name(near);
if (!string.IsNullOrEmpty(n))
{
return string.IsNullOrEmpty(id)
? "A building falls near " + n
: "A " + id + " falls near " + n;
}
}
return string.IsNullOrEmpty(id) ? "A building falls" : "A " + id + " falls";
}
public static string Status(Actor a, string phrase)
{
string an = NameOrSomeone(a);
string p = (phrase ?? "").Trim();
if (string.IsNullOrEmpty(p))
{
return an + " changes status";
}
// Prose often already includes a verb phrase ("is burning").
if (p.StartsWith("is ", StringComparison.OrdinalIgnoreCase)
|| p.StartsWith("are ", StringComparison.OrdinalIgnoreCase))
{
return an + " " + p;
}
return an + " · " + p;
}
public static string Trait(Actor a, string traitId, bool gained)
{
string an = NameOrSomeone(a);
string id = HumanizeId(traitId);
if (string.IsNullOrEmpty(id))
{
id = "a trait";
}
return gained ? an + " gains " + id : an + " loses " + id;
}
public static string Boat(Actor a, string phase)
{
string an = NameOrSomeone(a);
switch ((phase ?? "").Trim().ToLowerInvariant())
{
case "unload":
case "boat_unload":
return an + " is unloading passengers";
case "load":
case "boat_load":
return an + " is loading passengers";
case "trade":
case "boat_trade":
return an + " is trading by boat";
default:
return an + " is on a boat";
}
}
public static string MetaNew(Actor a, string kind)
{
string an = NameOrSomeone(a);
string k = HumanizeId(kind);
if (string.IsNullOrEmpty(k))
{
k = "something new";
}
return an + " founds a " + k;
}
public static string Library(Actor a, string kind, string assetId)
{
string an = NameOrSomeone(a);
string id = HumanizeId(assetId);
string k = HumanizeId(kind);
if (string.IsNullOrEmpty(id))
{
return an + " triggers " + (string.IsNullOrEmpty(k) ? "an event" : k);
}
switch ((kind ?? "").Trim().ToLowerInvariant())
{
case "spell":
return an + " casts " + id;
case "item":
return an + " forges " + id;
case "decision":
return an + " decides " + id;
case "gene":
return an + " gains gene " + id;
case "phenotype":
return an + " shows phenotype " + id;
case "power":
return an + " channels " + id;
case "subspecies_trait":
return an + " gains " + id;
default:
return an + " · " + id;
}
}
/// <summary>
/// Apply a sentence template with {a}/{b}/{id}. Prefer typed helpers for new copy.
/// </summary>
public static string Apply(string template, Actor a, Actor b = null, string id = "")
{
string t = string.IsNullOrEmpty(template) ? "{a}" : template;
return t
.Replace("{id}", id ?? "")
.Replace("{a}", Name(a) ?? "")
.Replace("{b}", Name(b) ?? "");
}
public static string HumanizeId(string id)
{
if (string.IsNullOrEmpty(id))
{
return "";
}
string raw = id.Trim().Replace('-', '_');
if (raw.StartsWith("type_", StringComparison.OrdinalIgnoreCase))
{
raw = raw.Substring(5);
}
string[] parts = raw.Split(new[] { '_' }, StringSplitOptions.RemoveEmptyEntries);
if (parts.Length == 0)
{
return raw;
}
var sb = new StringBuilder(raw.Length + 4);
for (int i = 0; i < parts.Length; i++)
{
if (i > 0)
{
sb.Append(' ');
}
string p = parts[i];
if (p.Length == 0)
{
continue;
}
sb.Append(char.ToUpperInvariant(p[0]));
if (p.Length > 1)
{
sb.Append(p.Substring(1).ToLowerInvariant());
}
}
return sb.ToString();
}
private static string NameOrSomeone(Actor a)
{
string n = Name(a);
return string.IsNullOrEmpty(n) ? "Someone" : n;
}
private static string Name(Actor a) => EventFeedUtil.SafeName(a);
private static string BuildingId(Building building)
{
if (building?.asset == null)
{
return "";
}
try
{
return building.asset.id ?? "";
}
catch
{
return "";
}
}
private static string BuildingType(Building building)
{
if (building?.asset == null)
{
return "";
}
try
{
return building.asset.type ?? "";
}
catch
{
return "";
}
}
}