using System; using HarmonyLib; namespace IdleSpectator; /// /// Feeds Activity status gain/loss lines from authoritative WorldBox status transitions. /// Gain = new dict entry (). /// Loss = (remove, expire, clear) while the actor is still alive. /// [HarmonyPatch] public static class ActorStatusPatches { [HarmonyPatch(typeof(BaseSimObject), "addNewStatusEffect")] [HarmonyPostfix] public static void PostfixAddNewStatusEffect( BaseSimObject __instance, StatusAsset pStatusAsset, float pOverrideTimer, bool pColorEffect, bool pIsActor, bool pHasAnyStatus) { _ = pOverrideTimer; _ = pColorEffect; _ = pHasAnyStatus; if (__instance == null || pStatusAsset == null) { return; } Actor actor = ResolveLivingActor(__instance, pIsActor); if (actor == null) { return; } ActivityLog.NoteStatusChange(actor, pStatusAsset.id, gained: true); } /// /// Count timer-refresh reapplications for harness asserts (no Activity line). /// [HarmonyPatch( typeof(BaseSimObject), "addStatusEffect", new Type[] { typeof(StatusAsset), typeof(float), typeof(bool) })] [HarmonyPrefix] public static void PrefixAddStatusEffect( BaseSimObject __instance, StatusAsset pStatusAsset, out bool __state) { __state = false; if (__instance == null || pStatusAsset == null || string.IsNullOrEmpty(pStatusAsset.id)) { return; } try { if (!__instance.isActor()) { return; } __state = ActorAlreadyHasStatus(__instance, pStatusAsset.id); } catch { __state = false; } } [HarmonyPatch( typeof(BaseSimObject), "addStatusEffect", new Type[] { typeof(StatusAsset), typeof(float), typeof(bool) })] [HarmonyPostfix] public static void PostfixAddStatusEffect( BaseSimObject __instance, StatusAsset pStatusAsset, bool __result, bool __state) { if (!__state || !__result || __instance == null || pStatusAsset == null) { return; } try { if (!__instance.isActor()) { return; } Actor actor = __instance.a; long actorId = 0; try { if (actor != null) { actorId = actor.getID(); } } catch { actorId = 0; } ActivityLog.NoteStatusRefresh(pStatusAsset.id, actorId); } catch { // ignore } } [HarmonyPatch(typeof(Status), nameof(Status.finish))] [HarmonyPrefix] public static void PrefixFinish(Status __instance, out bool __state) { __state = false; try { __state = __instance != null && !__instance.is_finished; } catch { __state = false; } } [HarmonyPatch(typeof(Status), nameof(Status.finish))] [HarmonyPostfix] public static void PostfixFinish(Status __instance, bool __state) { if (!__state || __instance == null) { return; } BaseSimObject sim; StatusAsset asset; try { sim = __instance.sim_object; asset = __instance.asset; } catch { return; } if (sim == null || asset == null || string.IsNullOrEmpty(asset.id)) { return; } Actor actor; try { if (!sim.isActor()) { return; } actor = sim.a; } catch { return; } if (actor == null) { return; } // Skip death/dispose cleanup bursts - death milestone covers that moment. try { if (!actor.isAlive()) { return; } } catch { return; } ActivityLog.NoteStatusChange(actor, asset.id, gained: false); } private static Actor ResolveLivingActor(BaseSimObject sim, bool hintedActor) { if (sim == null) { return null; } try { if (!hintedActor && !sim.isActor()) { return null; } Actor actor = sim.a; if (actor == null || !actor.isAlive()) { return null; } return actor; } catch { return null; } } private static bool ActorAlreadyHasStatus(BaseSimObject sim, string statusId) { try { var ids = sim.getStatusesIds(); if (ids == null) { return false; } foreach (string id in ids) { if (!string.IsNullOrEmpty(id) && id.Equals(statusId, StringComparison.OrdinalIgnoreCase)) { return true; } } } catch { // fall through } return false; } }