using System.Collections.Generic; using HarmonyLib; namespace NecromancerTome { /// /// Lets a charmed ("DeviĀ­ator"-hit) zombie actually hurt other zombies. /// /// EntityAlive.DamageEntity has a hardcoded block, independent of anything AI/targeting /// related: `if (!isHeatDamage && (entityFlags & attacker.entityFlags & EntityFlags.Zombie) != None) /// return -1;` - i.e. any two entities that are BOTH flagged EntityFlags.Zombie (which is /// every zombie, always) simply cannot damage each other, full stop, no matter what /// CharmPatch.cs did to the attacker's AI targeting. Without this, a charmed zombie would /// walk up to another zombie and "attack" it forever with every hit landing as a no-op. /// /// Fix: for the duration of a single DamageEntity call where the attacker currently has /// buffNecroDeviatorCharm and the target is also a zombie, temporarily clear /// EntityFlags.Zombie on the ATTACKER only (never the target, never persisted) so the AND /// check in the original method comes up empty and damage proceeds normally. Restored /// immediately afterward, so nothing else about that zombie (kill-counting via its Tags /// property, quest tracking, anything else keyed off EntityFlags) is ever affected outside /// this one call. A Stack (not a single field) survives re-entrant DamageEntity calls /// correctly (e.g. explosions/knockback triggering further damage inside the same callstack). /// [HarmonyPatch(typeof(EntityAlive), "DamageEntity")] public static class Patch_EntityAlive_DamageEntity_CharmedZombieVsZombie { public static readonly Stack ToggledAttackers = new Stack(); public static void Prefix(EntityAlive __instance, DamageSource _damageSource) { EntityZombie toggled = null; if (__instance is EntityZombie && __instance.world != null) { EntityAlive attacker = __instance.world.GetEntity(_damageSource.getEntityId()) as EntityAlive; if (attacker is EntityZombie attackerZombie && attackerZombie.Buffs != null && attackerZombie.Buffs.HasBuff(Patch_EntityBuffs_AddBuff_DeviatorCharm.CharmBuffName) && (attackerZombie.entityFlags & EntityFlags.Zombie) != EntityFlags.None) { attackerZombie.entityFlags &= ~EntityFlags.Zombie; toggled = attackerZombie; } } ToggledAttackers.Push(toggled); } public static void Postfix() { EntityZombie toggled = ToggledAttackers.Pop(); if (toggled != null) { toggled.entityFlags |= EntityFlags.Zombie; } } } }