- Add related unit tracking for activity logs and dossiers - Implement colorized names for related units in reason lines - Update harness scenarios to validate new interactions - Increment version to 0.26.1 in mod.json
284 lines
8.4 KiB
C#
284 lines
8.4 KiB
C#
using ai.behaviours;
|
|
using HarmonyLib;
|
|
|
|
namespace IdleSpectator;
|
|
|
|
/// <summary>
|
|
/// Feeds <see cref="ActivityLog"/> from task changes and curated behaviour beats.
|
|
/// Only patch Beh types that declare <c>execute</c> - Harmony fails with "method null"
|
|
/// when the method is inherited-only (e.g. BehSocializeTalk).
|
|
/// </summary>
|
|
[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,
|
|
relatedId: ActivityInterestTable.ActorTargetId(pActor));
|
|
}
|
|
|
|
[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,
|
|
relatedId: ActivityInterestTable.ActorTargetId(pActor));
|
|
}
|
|
|
|
[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);
|
|
}
|
|
}
|