using System.Collections.Generic; using Twitch; namespace Harmony.EntityBuffsPatches { [HarmonyPatch(typeof(EntityBuffs))] [HarmonyPatch("OnDeath")] public class OnDeathPatch { public static bool Prefix(EntityBuffs __instance, global::EntityAlive _entityThatKilledMe, bool _blockKilledMe, FastTags _damageTypeTags, FastTags ___physicalDamageTypes ) { //Log.Out("EntityBuffsPatches-OnDeath START, parent: " + __instance.parent.EntityName); //Log.Out("EntityBuffsPatches-OnDeath __instance.ActiveBuffs.Count: " + __instance.ActiveBuffs.Count); if (_entityThatKilledMe != null) { //Log.Out("EntityBuffsPatches-OnDeath 1"); if (_entityThatKilledMe.entityId == __instance.parent.entityId) { //Log.Out("EntityBuffsPatches-OnDeath 2"); __instance.parent.FireEvent(MinEventTypes.onSelfKilledSelf, true); } else { //Log.Out("EntityBuffsPatches-OnDeath 3"); __instance.parent.MinEventContext.Other = _entityThatKilledMe; __instance.parent.FireEvent(MinEventTypes.onOtherKilledSelf, true); } } else if (_blockKilledMe) { //Log.Out("EntityBuffsPatches-OnDeath 4"); __instance.parent.FireEvent(MinEventTypes.onBlockKilledSelf, true); } __instance.parent.FireEvent(MinEventTypes.onSelfDied, true); List list = new List(); for (int i = 0; i < __instance.ActiveBuffs.Count; i++) { BuffValue buffValue = __instance.ActiveBuffs[i]; if (buffValue != null && buffValue.BuffClass != null) { //Log.Out("EntityBuffsPatches-OnDeath 5"); if (buffValue.BuffClass.RemoveOnDeath && !buffValue.Paused) { //Log.Out("EntityBuffsPatches-OnDeath 6"); buffValue.Remove = true; } //Log.Out("EntityBuffsPatches-OnDeath buffValue.InstigatorId: " + buffValue.InstigatorId); //Log.Out("EntityBuffsPatches-OnDeath buffValue.BuffName: " + buffValue.BuffName); if (buffValue.BuffClass.DamageType != EnumDamageTypes.None && !buffValue.Invalid && buffValue.Started && buffValue.InstigatorId != -1 && buffValue.InstigatorId != __instance.parent.entityId && (!(_entityThatKilledMe != null) || buffValue.InstigatorId != _entityThatKilledMe.entityId) && !list.Contains(buffValue.InstigatorId)) { //Log.Out("EntityBuffsPatches-OnDeath 7"); if (__instance.parent is EntityPlayer) { //Log.Out("EntityBuffsPatches-OnDeath 8"); global::EntityAlive killer; if (_entityThatKilledMe != null) { //Log.Out("EntityBuffsPatches-OnDeath 9"); killer = _entityThatKilledMe; } else { //Log.Out("EntityBuffsPatches-OnDeath 10"); killer = (GameManager.Instance.World.GetEntity(buffValue.InstigatorId) as global::EntityAlive); } if (buffValue.BuffClass.DamageType == EnumDamageTypes.BloodLoss || buffValue.BuffClass.DamageType == EnumDamageTypes.Electrical || buffValue.BuffClass.DamageType == EnumDamageTypes.Radiation || buffValue.BuffClass.DamageType == EnumDamageTypes.Heat || buffValue.BuffClass.DamageType == EnumDamageTypes.Cold) { //Log.Out("EntityBuffsPatches-OnDeath 11"); TwitchManager.Current.CheckKiller(__instance.parent as EntityPlayer, killer, __instance.parent.GetBlockPosition()); } } EntityPlayerLocal entityPlayerLocal = GameManager.Instance.World.GetEntity(buffValue.InstigatorId) as EntityPlayerLocal; if (!(entityPlayerLocal == null) && entityPlayerLocal.Spawned) { //Log.Out("EntityBuffsPatches-OnDeath 12"); if (!_damageTypeTags.Test_AnySet(___physicalDamageTypes)) { //Log.Out("EntityBuffsPatches-OnDeath 13"); if (__instance.parent.Buffs.GetCustomVar("ETrapHit", 0f) == 1f) { //Log.Out("EntityBuffsPatches-OnDeath 14"); float value = EffectManager.GetValue(PassiveEffects.ElectricalTrapXP, entityPlayerLocal.inventory.holdingItemItemValue, 0f, entityPlayerLocal, null, new FastTags(), true, true, true, true, true, 1, false); if (value > 0f) { //Log.Out("EntityBuffsPatches-OnDeath 15"); if (RebirthUtilities.IsHordeNight()) { RebirthVariables.localConstants["$varFuriousRamsayHNKills_Cst"]++; } // There should be no player experience gained from traps. Eventually, expertise for the Builder //entityPlayerLocal.AddKillXP(__instance.parent, value); __instance.parent.AwardKill(entityPlayerLocal); } } else { //Log.Out("EntityBuffsPatches-OnDeath 16"); //entityPlayerLocal.AddKillXP(__instance.parent, 1f); //__instance.parent.AwardKill(entityPlayerLocal); global::EntityAlive killer = (GameManager.Instance.World.GetEntity(buffValue.InstigatorId) as global::EntityAlive); if (killer is EntityPlayer) { //Log.Out("EntityBuffsPatches-OnDeath B killer: " + killer.EntityClass.entityClassName); //Log.Out("EntityBuffsPatches-OnDeath B killer: " + killer.EntityClass.entityClassName); //Log.Out("EntityBuffsPatches-OnDeath buffValue.BuffName: " + buffValue.BuffName); if (RebirthUtilities.IsHordeNight()) { RebirthVariables.localConstants["$varFuriousRamsayHNKills_Cst"]++; } string heldItem = ""; /*if (__instance.parent.MinEventContext.ItemValue != null) { //Log.Out("EntityBuffsPatches-OnDeath ItemValue: " + __instance.parent.MinEventContext.ItemValue); //Log.Out("EntityBuffsPatches-OnDeath ItemClass: " + __instance.parent.MinEventContext.ItemValue.ItemClass); //Log.Out("EntityBuffsPatches-OnDeath ItemClass Name: " + __instance.parent.MinEventContext.ItemValue.ItemClass.Name); heldItem = __instance.parent.MinEventContext.ItemValue.ItemClass.GetItemName(); //Log.Out("EntityBuffsPatches-OnDeath ItemClass __instance.parent.MinEventContext.ItemValue.ItemClass.GetItemName(): " + __instance.parent.MinEventContext.ItemValue.ItemClass.GetItemName()); }*/ try { if (buffValue.BuffName.ToLower().Contains("furiousramsaybleeddamagelevel")) { //Log.Out("EntityBuffsPatches-OnDeath BLED OUT BUTCHER DEBUFF"); RebirthUtilities.ProcessDamageXP(heldItem, __instance.parent.MinEventContext.Biome.m_Id, __instance.parent.MinEventContext.DamageResponse.HitBodyPart == EnumBodyPartHit.Head, killer.entityId, __instance.parent.entityId, 1, true, "meleeWpnBladeT3Machete"); if (!RebirthUtilities.IsHordeNight()) { RebirthUtilities.ProcessCheckAchievements(__instance.parent.MinEventContext.Biome.m_Id, killer, __instance.parent); } } else if (buffValue.BuffName.ToLower() == "buffinjurybleeding") { //Log.Out("EntityBuffsPatches-OnDeath BLED OUT buffInjuryBleeding"); RebirthUtilities.ProcessDamageXP(heldItem, __instance.parent.MinEventContext.Biome.m_Id, __instance.parent.MinEventContext.DamageResponse.HitBodyPart == EnumBodyPartHit.Head, killer.entityId, __instance.parent.entityId, 1, true); if (!RebirthUtilities.IsHordeNight()) { RebirthUtilities.ProcessCheckAchievements(__instance.parent.MinEventContext.Biome.m_Id, killer, __instance.parent); } } else if (buffValue.BuffName.ToLower() == "buffburningflamingarrow") { //Log.Out("EntityBuffsPatches-OnDeath buffburningflamingarrow"); RebirthUtilities.ProcessDamageXP(heldItem, __instance.parent.MinEventContext.Biome.m_Id, __instance.parent.MinEventContext.DamageResponse.HitBodyPart == EnumBodyPartHit.Head, killer.entityId, __instance.parent.entityId, 1, true); if (!RebirthUtilities.IsHordeNight()) { RebirthUtilities.ProcessCheckAchievements(__instance.parent.MinEventContext.Biome.m_Id, killer, __instance.parent); } } else if (buffValue.BuffName.ToLower().Contains("furiousramsayarrowrainparticle") || buffValue.BuffName.ToLower().Contains("furiousramsayknifeslashesparticle") || buffValue.BuffName.ToLower().Contains("furiousramsayaddshockauradamage") || buffValue.BuffName.ToLower().Contains("furiousramsayrangedbleeddamage") ) { //Log.Out("EntityBuffsPatches-OnDeath furiousramsayarrowrainparticle"); if (!RebirthUtilities.IsHordeNight()) { // possible bug here - NRE caught here // NullReferenceException: Object reference not set to an instance of an object // at Harmony.EntityBuffsPatches.OnDeathPatch.Prefix(EntityBuffs __instance, // EntityAlive _entityThatKilledMe, System.Boolean _blockKilledMe, FastTags`1[TTagGroup] _damageTypeTags, FastTags`1[TTagGroup] // ___physicalDamageTypes)[0x005f3] in < f0a14dac58264c04bd895edfddfc3b3a >:0 // The offset led to this statement being the source of this NRE, possibly the __instance variable == null here RebirthUtilities.ProcessCheckAchievements(__instance.parent.MinEventContext.Biome.m_Id, killer, __instance.parent); } } } catch (Exception ex) { Log.Out($"Caught exception: {ex.Message}"); Log.Out($"__instance: {__instance}, killer: {killer}"); } if (__instance.parent is EntityZombieSDX) { EntityZombieSDX zombie = (EntityZombieSDX)__instance.parent; zombie.entityThatKilledMeID = killer.entityId; entityPlayerLocal.AddKillXP(__instance.parent); //Log.Out("EntityBuffsPatches-OnDeath zombie.entityThatKilledMeID: " + zombie.entityThatKilledMeID); break; } } } } list.Add(entityPlayerLocal.entityId); } } } } __instance.Update(Time.deltaTime); //Log.Out("EntityBuffsPatches-OnDeath END"); return false; } } [HarmonyPatch(typeof(EntityBuffs))] [HarmonyPatch("Update")] public class UpdatePatch { public static bool Prefix(EntityBuffs __instance, float _deltaTime) { int num = __instance.ActiveBuffs.Count; for (int i = 0; i < num; i++) { BuffValue buffValue = new BuffValue(); try { buffValue = __instance.ActiveBuffs[i]; } catch { return false; } if (buffValue.Invalid) { __instance.ActiveBuffs.RemoveAt(i); i--; num--; } else { __instance.parent.MinEventContext.Buff = buffValue; if (__instance.parent.MinEventContext.Other == null) { __instance.parent.MinEventContext.Other = __instance.parent.GetAttackTarget(); } if (buffValue.Finished) { __instance.FireEvent(MinEventTypes.onSelfBuffFinish, buffValue.BuffClass, __instance.parent.MinEventContext); buffValue.Remove = true; } if (buffValue.Remove) { if (buffValue.BuffClass != null) { __instance.FireEvent(MinEventTypes.onSelfBuffRemove, buffValue.BuffClass, __instance.parent.MinEventContext); if (!buffValue.BuffClass.Hidden) { __instance.parent.Stats.EntityBuffRemoved(buffValue); } } try { __instance.ActiveBuffs.RemoveAt(i); } catch { //Log.Out("EntityBuffsPatches-Update CANNOT REMOVE BUFF entityClassName: " + __instance.parent.EntityClass.entityClassName); } i--; num--; } else if (!buffValue.Paused && !__instance.parent.bDead) { if (!buffValue.Started) { __instance.FireEvent(MinEventTypes.onSelfBuffStart, buffValue.BuffClass, __instance.parent.MinEventContext); buffValue.Started = true; if (!buffValue.BuffClass.Hidden) { __instance.parent.Stats.EntityBuffAdded(buffValue); } __instance.parent.BuffAdded(buffValue); } BuffManager.UpdateBuffTimers(buffValue, _deltaTime); if (buffValue.Update) { try { __instance.FireEvent(MinEventTypes.onSelfBuffUpdate, buffValue.BuffClass, __instance.parent.MinEventContext); buffValue.Update = false; } catch { } } } } } return false; } } }