worldbox-observer-mod/IdleSpectator/ActorHappinessPatches.cs

143 lines
4.4 KiB
C#

using HarmonyLib;
namespace IdleSpectator;
/// <summary>
/// Authoritative happiness hooks. Universal changeHappiness covers every effect id;
/// death/birth patches supply related-unit context the history struct lacks.
/// </summary>
[HarmonyPatch]
internal static class ActorHappinessPatches
{
[HarmonyPatch(typeof(Actor), nameof(Actor.changeHappiness))]
[HarmonyPostfix]
public static void PostfixChangeHappiness(Actor __instance, string pID, int pValue, bool __result)
{
if (__instance == null || string.IsNullOrEmpty(pID))
{
return;
}
if (!__result)
{
HappinessEventRouter.PublishSuppressed(
__instance, pID, HappinessSourceHook.ChangeHappiness);
return;
}
Actor related = null;
HappinessRelationRole role = HappinessRelationRole.None;
HappinessSourceHook hook = HappinessSourceHook.ChangeHappiness;
if (HappinessContextBag.TryGetRelated(__instance, out Actor bagRelated, out HappinessRelationRole bagRole))
{
related = bagRelated;
role = bagRole != HappinessRelationRole.None
? bagRole
: HappinessContextBag.RoleForDeathEffect(pID);
if (pID != null && pID.StartsWith("death_"))
{
hook = HappinessSourceHook.DeathEvent;
}
}
else if (pID != null && pID.StartsWith("death_"))
{
// Death event without bag - still log survivor-centered subject-only if required fails.
role = HappinessContextBag.RoleForDeathEffect(pID);
hook = HappinessSourceHook.DeathEvent;
}
int amount = HappinessGameApi.ResolveAmount(pID, pValue);
HappinessEventRouter.PublishApplied(__instance, pID, amount, hook, related, role);
}
[HarmonyPatch(typeof(Actor), "checkHappinessChangeFromDeathEvent")]
[HarmonyPrefix]
public static void PrefixDeathHappiness(Actor __instance)
{
HappinessContextBag.BeginDeathEvent(__instance);
}
[HarmonyPatch(typeof(Actor), "checkHappinessChangeFromDeathEvent")]
[HarmonyPostfix]
public static void PostfixDeathHappiness()
{
HappinessContextBag.EndDeathEvent();
}
[HarmonyPatch(typeof(Actor), nameof(Actor.birthEvent))]
[HarmonyPrefix]
public static void PrefixBirthEvent(Actor __instance)
{
// birthEvent runs on the parent; related newborn is not passed.
// Mark role so prose can stay subject-aware even without a name.
HappinessContextBag.SetRelated(null, HappinessRelationRole.Newborn, "just_had_child");
}
[HarmonyPatch(typeof(Actor), nameof(Actor.birthEvent))]
[HarmonyPostfix]
public static void PostfixBirthEvent()
{
HappinessContextBag.ClearRelated();
}
[HarmonyPatch(typeof(Actor), nameof(Actor.becomeLoversWith))]
[HarmonyPrefix]
public static void PrefixLovers(Actor __instance, Actor pTarget)
{
HappinessContextBag.SetPair(__instance, pTarget, HappinessRelationRole.Lover, "fallen_in_love");
try
{
if (__instance != null)
{
HappinessEventRouter.NoteCanonicalMilestone(__instance.getID(), "milestone_lover");
}
if (pTarget != null)
{
HappinessEventRouter.NoteCanonicalMilestone(pTarget.getID(), "milestone_lover");
}
}
catch
{
// ignore
}
}
[HarmonyPatch(typeof(Actor), nameof(Actor.becomeLoversWith))]
[HarmonyPostfix]
public static void PostfixLovers()
{
HappinessContextBag.ClearRelated();
}
[HarmonyPatch(typeof(Actor), nameof(Actor.setBestFriend))]
[HarmonyPrefix]
public static void PrefixBestFriend(Actor __instance, Actor pActor, bool pNew)
{
if (!pNew)
{
return;
}
HappinessContextBag.SetRelated(pActor, HappinessRelationRole.BestFriend, "just_made_friend");
try
{
if (__instance != null)
{
HappinessEventRouter.NoteCanonicalMilestone(__instance.getID(), "milestone_friend");
}
}
catch
{
// ignore
}
}
[HarmonyPatch(typeof(Actor), nameof(Actor.setBestFriend))]
[HarmonyPostfix]
public static void PostfixBestFriend()
{
HappinessContextBag.ClearRelated();
}
}