using ai.behaviours; using HarmonyLib; namespace IdleSpectator; /// /// Feeds from task changes and curated behaviour beats. /// Only patch Beh types that declare execute - Harmony fails with "method null" /// when the method is inherited-only (e.g. BehSocializeTalk). /// [HarmonyPatch] public static class ActorActivityPatches { [HarmonyPatch(typeof(Actor), nameof(Actor.setTask))] [HarmonyPostfix] public static void PostfixSetTask(Actor __instance, string pTaskId) { if (__instance == null || string.IsNullOrEmpty(pTaskId)) { return; } ActivityLog.NoteTask(__instance, pTaskId); } [HarmonyPatch(typeof(BehPollinate), nameof(BehPollinate.execute))] [HarmonyPostfix] public static void PostfixPollinate(Actor pActor, BehResult __result) { if (pActor == null || __result == BehResult.Stop) { return; } string obj = ActivityInterestTable.PlaceOrObjectLabel(pActor); if (string.IsNullOrEmpty(obj)) { obj = "flower"; } ActivityLog.NoteActionBeat( pActor, "BehPollinate", "Pollinates " + obj, actorTarget: "", placeHint: obj); } [HarmonyPatch(typeof(BehUnloadResources), nameof(BehUnloadResources.execute))] [HarmonyPrefix] public static void PrefixUnload(Actor pActor, out bool __state) { __state = false; try { __state = pActor != null && pActor.isCarryingResources(); } catch { __state = false; } } [HarmonyPatch(typeof(BehUnloadResources), nameof(BehUnloadResources.execute))] [HarmonyPostfix] public static void PostfixUnload(Actor pActor, bool __state) { if (pActor == null || !__state) { return; } string carrying = ActivityInterestTable.TryGetCarryingLabel(pActor); string fact = string.IsNullOrEmpty(carrying) ? "Unloads resources" : "Unloads " + carrying; // Place comes from live context / city - never as a companion target. ActivityLog.NoteActionBeat(pActor, "BehUnloadResources", fact); } [HarmonyPatch(typeof(BehAttackActorHuntingTarget), nameof(BehAttackActorHuntingTarget.execute))] [HarmonyPostfix] public static void PostfixHuntAttack(Actor pActor, BehResult __result) { if (pActor == null) { return; } string actorTarget = ActivityInterestTable.ActorTargetName(pActor); ActivityLog.NoteActionBeat( pActor, "BehAttackActorHuntingTarget", string.IsNullOrEmpty(actorTarget) ? "Hunts prey" : "Hunts " + actorTarget, actorTarget: actorTarget); } [HarmonyPatch(typeof(BehCityActorRemoveFire), nameof(BehCityActorRemoveFire.execute))] [HarmonyPostfix] public static void PostfixRemoveFire(Actor pActor, BehResult __result) { if (pActor == null) { return; } ActivityLog.NoteActionBeat( pActor, "BehCityActorRemoveFire", "Fights fire", actorTarget: "", placeHint: "blaze"); } [HarmonyPatch(typeof(BehTryToSocialize), nameof(BehTryToSocialize.execute))] [HarmonyPostfix] public static void PostfixTrySocialize(Actor pActor, BehResult __result) { if (pActor == null || __result == BehResult.Stop) { return; } string actorTarget = ActivityInterestTable.ActorTargetName(pActor); ActivityLog.NoteActionBeat( pActor, "BehTryToSocialize", string.IsNullOrEmpty(actorTarget) ? "Tries to socialize" : "Tries to socialize with " + actorTarget, actorTarget: actorTarget); } [HarmonyPatch(typeof(BehPlantCrops), nameof(BehPlantCrops.execute))] [HarmonyPostfix] public static void PostfixPlantCrops(Actor pActor, BehResult __result) { if (pActor == null || __result == BehResult.Stop) { return; } ActivityLog.NoteActionBeat(pActor, "BehPlantCrops", "Plants crops"); } [HarmonyPatch(typeof(BehCityActorFertilizeCrop), nameof(BehCityActorFertilizeCrop.execute))] [HarmonyPostfix] public static void PostfixFertilize(Actor pActor, BehResult __result) { if (pActor == null || __result == BehResult.Stop) { return; } ActivityLog.NoteActionBeat(pActor, "BehCityActorFertilizeCrop", "Fertilizes crops"); } [HarmonyPatch(typeof(BehThrowResources), nameof(BehThrowResources.execute))] [HarmonyPrefix] public static void PrefixThrow(Actor pActor, out bool __state) { __state = false; try { __state = pActor != null && pActor.isCarryingResources(); } catch { __state = false; } } [HarmonyPatch(typeof(BehThrowResources), nameof(BehThrowResources.execute))] [HarmonyPostfix] public static void PostfixThrow(Actor pActor, bool __state) { if (pActor == null || !__state) { return; } string carrying = ActivityInterestTable.TryGetCarryingLabel(pActor); string fact = string.IsNullOrEmpty(carrying) ? "Throws resources" : "Throws " + carrying; ActivityLog.NoteActionBeat(pActor, "BehThrowResources", fact); } [HarmonyPatch(typeof(BehBuildTarget), nameof(BehBuildTarget.execute))] [HarmonyPostfix] public static void PostfixBuild(Actor pActor, BehResult __result) { if (pActor == null || __result == BehResult.Stop) { return; } string obj = ActivityInterestTable.PlaceOrObjectLabel(pActor); ActivityLog.NoteActionBeat( pActor, "BehBuildTarget", string.IsNullOrEmpty(obj) ? "Works a build" : "Builds " + obj, actorTarget: "", placeHint: obj); } [HarmonyPatch(typeof(BehPoopOutside), nameof(BehPoopOutside.execute))] [HarmonyPostfix] public static void PostfixPoopOutside(Actor pActor, BehResult __result) { if (pActor == null || __result == BehResult.Stop) { return; } ActivityLog.NoteActionBeat(pActor, "BehPoopOutside", "Private moment outdoors"); } [HarmonyPatch(typeof(BehPoopInside), nameof(BehPoopInside.execute))] [HarmonyPostfix] public static void PostfixPoopInside(Actor pActor, BehResult __result) { if (pActor == null || __result == BehResult.Stop) { return; } ActivityLog.NoteActionBeat(pActor, "BehPoopInside", "Private moment indoors"); } [HarmonyPatch(typeof(BehBoatFishing), nameof(BehBoatFishing.execute))] [HarmonyPostfix] public static void PostfixBoatFish(Actor pActor, BehResult __result) { if (pActor == null || __result == BehResult.Stop) { return; } ActivityLog.NoteActionBeat(pActor, "BehBoatFishing", "Fishes from the boat"); } [HarmonyPatch(typeof(BehBoatCollectFish), nameof(BehBoatCollectFish.execute))] [HarmonyPostfix] public static void PostfixBoatCollectFish(Actor pActor, BehResult __result) { if (pActor == null || __result == BehResult.Stop) { return; } ActivityLog.NoteActionBeat(pActor, "BehBoatCollectFish", "Collects the catch"); } [HarmonyPatch(typeof(BehClaimZoneForCityActorBorder), nameof(BehClaimZoneForCityActorBorder.execute))] [HarmonyPostfix] public static void PostfixClaimBorder(Actor pActor, BehResult __result) { if (pActor == null || __result == BehResult.Stop) { return; } string place = ""; try { if (pActor.city != null) { place = pActor.city.name ?? ""; } } catch { place = ""; } ActivityLog.NoteActionBeat( pActor, "BehClaimZoneForCityActorBorder", string.IsNullOrEmpty(place) ? "Claims border land" : "Claims border land for " + place, actorTarget: "", placeHint: place); } }