247 lines
7.9 KiB
C#
247 lines
7.9 KiB
C#
using ai.behaviours;
|
|
using HarmonyLib;
|
|
|
|
namespace IdleSpectator;
|
|
|
|
/// <summary>
|
|
/// Authoritative happiness hooks. Universal changeHappiness covers every effect id;
|
|
/// apply-site prefixes 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)
|
|
{
|
|
// Context for status fell_in_love → changeHappiness("fallen_in_love") during the body.
|
|
// Do not NoteCanonicalMilestone here - that would merge the ring before it writes.
|
|
HappinessContextBag.SetPair(__instance, pTarget, HappinessRelationRole.Lover, "fallen_in_love");
|
|
}
|
|
|
|
/// <summary>
|
|
/// Live path: status fell_in_love action_on_receive → changeHappiness("fallen_in_love").
|
|
/// Bridge still publishes for units that suppress changeHappiness (no emotions / egg),
|
|
/// and ensures related names when the status path is skipped. Self-merge within 0.35s
|
|
/// collapses the double for emotion units.
|
|
/// </summary>
|
|
[HarmonyPatch(typeof(Actor), nameof(Actor.becomeLoversWith))]
|
|
[HarmonyPostfix]
|
|
[HarmonyPriority(Priority.First)]
|
|
public static void PostfixLovers(Actor __instance, Actor pTarget)
|
|
{
|
|
try
|
|
{
|
|
BridgeFallenInLove(__instance, pTarget);
|
|
BridgeFallenInLove(pTarget, __instance);
|
|
}
|
|
finally
|
|
{
|
|
HappinessContextBag.ClearRelated();
|
|
}
|
|
}
|
|
|
|
private static void BridgeFallenInLove(Actor subject, Actor related)
|
|
{
|
|
if (subject == null || !subject.isAlive())
|
|
{
|
|
return;
|
|
}
|
|
|
|
Actor relatedAlive = related != null && related.isAlive() ? related : null;
|
|
int amount = HappinessGameApi.ResolveAmount("fallen_in_love", 0);
|
|
HappinessEventRouter.PublishApplied(
|
|
subject,
|
|
"fallen_in_love",
|
|
amount,
|
|
HappinessSourceHook.ChangeHappiness,
|
|
relatedAlive,
|
|
HappinessRelationRole.Lover);
|
|
}
|
|
|
|
[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();
|
|
}
|
|
|
|
[HarmonyPatch(typeof(Actor), nameof(Actor.newKillAction))]
|
|
[HarmonyPrefix]
|
|
public static void PrefixKillAction(Actor __instance, Actor pDeadUnit)
|
|
{
|
|
HappinessContextBag.SetRelated(pDeadUnit, HappinessRelationRole.Victim, "just_killed");
|
|
}
|
|
|
|
[HarmonyPatch(typeof(Actor), nameof(Actor.newKillAction))]
|
|
[HarmonyPostfix]
|
|
public static void PostfixKillAction()
|
|
{
|
|
HappinessContextBag.ClearRelated();
|
|
}
|
|
|
|
[HarmonyPatch(typeof(Actor), nameof(Actor.stealActionFrom))]
|
|
[HarmonyPrefix]
|
|
public static void PrefixSteal(Actor __instance, Actor pTarget)
|
|
{
|
|
// Victim gets got_robbed; related = thief.
|
|
HappinessContextBag.SetRelated(__instance, HappinessRelationRole.Robber, "got_robbed");
|
|
}
|
|
|
|
[HarmonyPatch(typeof(Actor), nameof(Actor.stealActionFrom))]
|
|
[HarmonyPostfix]
|
|
public static void PostfixSteal()
|
|
{
|
|
HappinessContextBag.ClearRelated();
|
|
}
|
|
|
|
[HarmonyPatch(typeof(BehCheckForBabiesFromSexualReproduction), nameof(BehCheckForBabiesFromSexualReproduction.execute))]
|
|
[HarmonyPrefix]
|
|
public static void PrefixKissed(Actor pActor)
|
|
{
|
|
Actor lover = null;
|
|
try
|
|
{
|
|
if (pActor != null && pActor.hasLover())
|
|
{
|
|
lover = pActor.lover;
|
|
}
|
|
}
|
|
catch
|
|
{
|
|
lover = null;
|
|
}
|
|
|
|
HappinessContextBag.SetPair(pActor, lover, HappinessRelationRole.Lover, "just_kissed");
|
|
}
|
|
|
|
[HarmonyPatch(typeof(BehCheckForBabiesFromSexualReproduction), nameof(BehCheckForBabiesFromSexualReproduction.execute))]
|
|
[HarmonyPostfix]
|
|
public static void PostfixKissed()
|
|
{
|
|
HappinessContextBag.ClearRelated();
|
|
}
|
|
|
|
[HarmonyPatch(typeof(BehFinishTalk), "finishTalk")]
|
|
[HarmonyPrefix]
|
|
public static void PrefixFinishTalk(Actor pActor, Actor pTarget)
|
|
{
|
|
HappinessContextBag.SetPair(pActor, pTarget, HappinessRelationRole.ConversationPartner, "just_talked");
|
|
}
|
|
|
|
[HarmonyPatch(typeof(BehFinishTalk), "finishTalk")]
|
|
[HarmonyPostfix]
|
|
public static void PostfixFinishTalk()
|
|
{
|
|
HappinessContextBag.ClearRelated();
|
|
}
|
|
|
|
[HarmonyPatch(typeof(BehFinishTalk), "makeGift")]
|
|
[HarmonyPrefix]
|
|
public static void PrefixMakeGift(Actor pActor, Actor pTarget)
|
|
{
|
|
HappinessContextBag.SetPair(pActor, pTarget, HappinessRelationRole.GiftPartner, "just_gave_gift");
|
|
}
|
|
|
|
[HarmonyPatch(typeof(BehFinishTalk), "makeGift")]
|
|
[HarmonyPostfix]
|
|
public static void PostfixMakeGift()
|
|
{
|
|
HappinessContextBag.ClearRelated();
|
|
}
|
|
}
|