using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
using System.Runtime.Versioning;
using System.Security;
using System.Security.Permissions;
using AIGraph;
using AK;
using Agents;
using AmorLib.Networking.StateReplicators;
using BepInEx;
using BepInEx.Bootstrap;
using BepInEx.Configuration;
using BepInEx.Core.Logging.Interpolation;
using BepInEx.Logging;
using BepInEx.Unity.IL2CPP;
using EWC.CustomWeapon.Enums;
using EWC.CustomWeapon.Properties.Effects;
using EWC.CustomWeapon.Properties.Effects.Hit.Explosion;
using EWC.CustomWeapon.Properties.Shared.Triggers;
using EWC.CustomWeapon.WeaponContext.Contexts;
using EWC.CustomWeapon.WeaponContext.Contexts.Base;
using Enemies;
using FX_EffectSystem;
using GTFO.API;
using GTFO.API.Resources;
using GameData;
using HarmonyLib;
using Il2CppInterop.Runtime;
using Il2CppInterop.Runtime.InteropTypes;
using Il2CppInterop.Runtime.InteropTypes.Arrays;
using Il2CppInterop.Runtime.Runtime;
using Il2CppInterop.Runtime.Runtime.VersionSpecific.Class;
using Il2CppInterop.Runtime.Runtime.VersionSpecific.MethodInfo;
using Il2CppSystem.Collections.Generic;
using KillableSpitters.Events;
using KillableSpitters.Patches;
using KillableSpitters.Patches.Compat;
using KillableSpitters.Patches.Spitters;
using Microsoft.CodeAnalysis;
using Player;
using PlayerCoverage;
using SNetwork;
using SemanticVersioning;
using UnityEngine;
[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)]
[assembly: TargetFramework(".NETCoreApp,Version=v6.0", FrameworkDisplayName = ".NET 6.0")]
[assembly: AssemblyCompany("KillableSpitters")]
[assembly: AssemblyConfiguration("Release")]
[assembly: AssemblyFileVersion("1.0.0.0")]
[assembly: AssemblyInformationalVersion("1.0.0+eb84f64f9a4fc43941ac49a3e4a7530eeb0bb19d")]
[assembly: AssemblyProduct("KillableSpitters")]
[assembly: AssemblyTitle("KillableSpitters")]
[assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)]
[assembly: AssemblyVersion("1.0.0.0")]
[module: UnverifiableCode]
namespace Microsoft.CodeAnalysis
{
[CompilerGenerated]
[Embedded]
internal sealed class EmbeddedAttribute : Attribute
{
}
}
namespace System.Runtime.CompilerServices
{
[CompilerGenerated]
[Embedded]
[AttributeUsage(AttributeTargets.Class | AttributeTargets.Property | AttributeTargets.Field | AttributeTargets.Event | AttributeTargets.Parameter | AttributeTargets.ReturnValue | AttributeTargets.GenericParameter, AllowMultiple = false, Inherited = false)]
internal sealed class NullableAttribute : Attribute
{
public readonly byte[] NullableFlags;
public NullableAttribute(byte P_0)
{
NullableFlags = new byte[1] { P_0 };
}
public NullableAttribute(byte[] P_0)
{
NullableFlags = P_0;
}
}
[CompilerGenerated]
[Embedded]
[AttributeUsage(AttributeTargets.Class | AttributeTargets.Struct | AttributeTargets.Method | AttributeTargets.Interface | AttributeTargets.Delegate, AllowMultiple = false, Inherited = false)]
internal sealed class NullableContextAttribute : Attribute
{
public readonly byte Flag;
public NullableContextAttribute(byte P_0)
{
Flag = P_0;
}
}
}
namespace KillableSpitters
{
[BepInPlugin("the_tavern-KillableSpitters", "KillableSpitters", "1.1.0")]
[BepInProcess("GTFO.exe")]
[BepInDependency(/*Could not decode attribute arguments.*/)]
[BepInDependency(/*Could not decode attribute arguments.*/)]
[BepInDependency(/*Could not decode attribute arguments.*/)]
public class Plugin : BasePlugin
{
public const string Version = "1.1.0";
public const string Name = "the_tavern-KillableSpitters";
public static ManualLogSource Logger { get; private set; } = new ManualLogSource("KillableSpitters");
public static float Config_SpitterHealth { get; set; }
public static float Config_SpitterFreezeDuration { get; set; }
public static bool Config_CfoamKillsSpitters { get; set; }
public override void Load()
{
//IL_001b: Unknown result type (might be due to invalid IL or missing references)
//IL_0030: Unknown result type (might be due to invalid IL or missing references)
//IL_003a: Expected O, but got Unknown
//IL_003a: Expected O, but got Unknown
//IL_004b: Unknown result type (might be due to invalid IL or missing references)
//IL_0060: Unknown result type (might be due to invalid IL or missing references)
//IL_006a: Expected O, but got Unknown
//IL_006a: Expected O, but got Unknown
//IL_007b: Unknown result type (might be due to invalid IL or missing references)
//IL_008c: Unknown result type (might be due to invalid IL or missing references)
//IL_0096: Expected O, but got Unknown
//IL_0096: Expected O, but got Unknown
//IL_00e1: Unknown result type (might be due to invalid IL or missing references)
//IL_00e6: Unknown result type (might be due to invalid IL or missing references)
//IL_00f1: Expected O, but got Unknown
Logger = ((BasePlugin)this).Log;
ConfigEntry<float> val = ((BasePlugin)this).Config.Bind<float>(new ConfigDefinition("General", "SpitterHealth"), 30f, new ConfigDescription("Health pool for killable spitters. Only the lobby host's value applies.", (AcceptableValueBase)null, Array.Empty<object>()));
ConfigEntry<float> val2 = ((BasePlugin)this).Config.Bind<float>(new ConfigDefinition("C-Foam", "SpitterFreezeDuration"), 0.7f, new ConfigDescription("How many seconds a C-foamed spitter stays frozen before it dies if CfoamKillsSpitters is on, otherwise before it thaws back to normal. Only the lobby host's value applies to the kill timing.\nNote: Base GTFO freezes spitters for 240 seconds.", (AcceptableValueBase)null, Array.Empty<object>()));
ConfigEntry<bool> obj = ((BasePlugin)this).Config.Bind<bool>(new ConfigDefinition("C-Foam", "CfoamKillsSpitters"), true, new ConfigDescription("Whether C-foam kills spitters. Off keeps the vanilla freeze-only behavior. Only the lobby host's value applies.", (AcceptableValueBase)null, Array.Empty<object>()));
Config_SpitterHealth = val.Value;
Config_SpitterFreezeDuration = val2.Value;
Config_CfoamKillsSpitters = obj.Value;
((BasePlugin)this).Config.Save();
GameDataAPI.OnGameDataInitialized += SpitterKillManager.Setup;
Patch_SpitterDamage.LogDamageForwarderFoldState();
Fix_SpitterHealthRel.Install();
Harmony val3 = new Harmony("the_tavern-KillableSpitters");
val3.PatchAll();
EWCCompat.Init(val3);
}
}
}
namespace KillableSpitters.Patches
{
[HarmonyPatch]
internal static class Fix_SpitterBotAggro
{
private static bool _broken;
[HarmonyPatch(typeof(InfectionSpitter), "ManagerUpdate")]
[HarmonyPrefix]
public static bool Pre_ManagerUpdate(InfectionSpitter __instance, AIG_CourseNode courseNode, ref bool __result)
{
//IL_0035: Unknown result type (might be due to invalid IL or missing references)
//IL_003b: Expected O, but got Unknown
if (SpitterKillManager.ShouldBlockManagerUpdate(__instance))
{
__result = false;
return false;
}
if (_broken)
{
return true;
}
try
{
__result = ManagerUpdateNoBots(__instance, courseNode);
return false;
}
catch (Exception ex)
{
_broken = true;
ManualLogSource logger = Plugin.Logger;
bool flag = default(bool);
BepInExErrorLogInterpolatedStringHandler val = new BepInExErrorLogInterpolatedStringHandler(74, 1, ref flag);
if (flag)
{
((BepInExLogInterpolatedStringHandler)val).AppendLiteral("[SpitterBotAggro] Reimplementation failed, reverting to vanilla behavior: ");
((BepInExLogInterpolatedStringHandler)val).AppendFormatted<Exception>(ex);
}
logger.LogError(val);
return true;
}
}
private static bool ManagerUpdateNoBots(InfectionSpitter s, AIG_CourseNode courseNode)
{
//IL_002d: Unknown result type (might be due to invalid IL or missing references)
//IL_0033: Invalid comparison between Unknown and I4
//IL_0209: Unknown result type (might be due to invalid IL or missing references)
//IL_020f: Invalid comparison between Unknown and I4
//IL_01c3: Unknown result type (might be due to invalid IL or missing references)
//IL_01c9: Invalid comparison between Unknown and I4
//IL_035e: Unknown result type (might be due to invalid IL or missing references)
//IL_00da: Unknown result type (might be due to invalid IL or missing references)
//IL_00e0: Unknown result type (might be due to invalid IL or missing references)
//IL_00e5: Unknown result type (might be due to invalid IL or missing references)
//IL_00ea: Unknown result type (might be due to invalid IL or missing references)
//IL_0119: Unknown result type (might be due to invalid IL or missing references)
//IL_0145: Unknown result type (might be due to invalid IL or missing references)
//IL_014a: Unknown result type (might be due to invalid IL or missing references)
//IL_0159: Unknown result type (might be due to invalid IL or missing references)
//IL_0160: Unknown result type (might be due to invalid IL or missing references)
//IL_017c: Unknown result type (might be due to invalid IL or missing references)
//IL_0181: Unknown result type (might be due to invalid IL or missing references)
float num = Clock.Time - s.m_lastUpdate;
s.m_lastUpdate = Clock.Time;
s.m_freezeTime = s.m_lastUpdate + 30f;
bool result = false;
bool flag = (int)s.m_currentState == 2;
bool flag2 = false;
float num2 = 8.5f;
float num3 = 0f;
Il2CppReferenceArray<PlayerCoverageData> coverageDatas = courseNode.m_playerCoverage.m_coverageDatas;
Enumerator<PlayerAgent> enumerator = PlayerManager.PlayerAgentsInLevel.GetEnumerator();
float num5 = default(float);
while (enumerator.MoveNext())
{
PlayerAgent current = enumerator.Current;
if ((Object)(object)((current != null) ? current.Owner : null) == (Object)null || current.Owner.IsBot)
{
continue;
}
int playerSlotIndex = current.PlayerSlotIndex;
if (playerSlotIndex < 0 || playerSlotIndex >= ((Il2CppArrayBase<PlayerCoverageData>)(object)coverageDatas).Length || ((Il2CppArrayBase<PlayerCoverageData>)(object)coverageDatas)[playerSlotIndex].m_nodeDistanceUnblocked >= 2 || !((Agent)current).Alive)
{
continue;
}
result = true;
Vector3 val = ((Agent)current).EyePosition - s.m_position;
float magnitude = ((Vector3)(ref val)).magnitude;
((Vector3)(ref val)).Normalize();
float num4 = 0f;
bool flag3 = false;
if (((Agent)current).HasDetectionMod(ref num5) && magnitude < num5)
{
num4 = ((Agent)current).GetDetectionMod(val, magnitude);
flag3 = num4 > 0.001f;
}
bool flag4 = !flag && magnitude < num2;
if ((flag4 || flag3) && Vector3.Dot(s.m_fwd, val) >= -0.5f && !Physics.Linecast(s.m_position, ((Agent)current).EyePosition, LayerManager.MASK_WORLD))
{
if (flag4)
{
Vector3 horizontalVelocity = current.Locomotion.HorizontalVelocity;
num3 = ((Vector3)(ref horizontalVelocity)).magnitude;
num2 = magnitude;
flag2 = true;
}
s.m_lightMeasure += num4 * num * 5f;
}
}
if (s.m_lightMeasure > 0.5f)
{
if ((int)s.m_currentState != 2)
{
s.TryPlaySound(EVENTS.INFECTION_SPITTER_SCARED, false, 1f);
s.SetTimedRetract(30f, s.m_lightRetractSpeed);
}
else if (s.m_stayInTimer < 30f)
{
s.m_stayInTimer = 30f;
}
}
if ((int)s.m_currentState == 2)
{
s.m_timeToExplode = 3f;
s.StopPurring();
s.m_stayInTimer -= num;
if (s.m_stayInTimer < 0f)
{
s.m_stayInTimer = 0f;
s.m_currentState = (eSpitterState)1;
}
else if (s.m_stayInTimer < 1f)
{
s.TryPlaySound(EVENTS.INFECTION_SPITTER_PRIMED, true, 2f);
}
}
else if (flag2)
{
if (!s.m_isSoundOut)
{
s.TryPlaySound(EVENTS.INFECTION_SPITTER_OUT, true, 1f);
s.m_isSoundOut = true;
}
if (num2 < 6f)
{
float num6 = 1f - num2 / 6f;
float num7 = ((num3 > 5f) ? 3f : 1f);
s.m_timeToExplode -= num * (num6 * num6 * 6.5f) * num7;
s.UpdateTargetingRetraction();
if (!s.m_purrLoopPlaying)
{
s.TryPlaySound(EVENTS.INFECTION_SPITTER_PURR_LOOP, false, 1f);
s.m_purrLoopPlaying = true;
}
if (SNet.IsMaster && !s.m_isExploding && (num2 < 1f || s.m_timeToExplode <= 0f))
{
s.SendExplode();
}
}
else
{
s.RestoreTargetTimer(num);
}
s.m_currentState = (eSpitterState)1;
}
else
{
s.RestoreTargetTimer(num);
if ((int)s.m_currentState != 0)
{
if (s.m_hasReachedTarget && s.m_targetRetract > 0.99f)
{
((Behaviour)s).enabled = false;
s.m_currentState = (eSpitterState)0;
s.CleanupSound();
}
else
{
if (s.m_isSoundOut)
{
s.m_isSoundOut = false;
s.TryPlaySound(EVENTS.INFECTION_SPITTER_IN, true, 1f);
}
s.SetRetractTarget(0.5f, s.m_retractSpeed);
}
}
}
s.m_lightMeasure = Mathf.Clamp01(s.m_lightMeasure - num * 0.25f);
return result;
}
}
[HarmonyPatch]
internal static class Fix_SpitterExplosionDamage
{
private static bool _broken;
[HarmonyPatch(typeof(InfectionSpitter), "AssignCourseNode")]
[HarmonyPostfix]
public static void Post_AssignCourseNode(InfectionSpitter __instance)
{
//IL_003f: Unknown result type (might be due to invalid IL or missing references)
//IL_0045: Expected O, but got Unknown
//IL_0022: Unknown result type (might be due to invalid IL or missing references)
if (_broken)
{
return;
}
try
{
InfectionSpitterDamage damage = __instance.m_damage;
if (!((Object)(object)damage == (Object)null))
{
damage.DamageTargetPos = ((Component)damage).transform.position;
}
}
catch (Exception ex)
{
_broken = true;
ManualLogSource logger = Plugin.Logger;
bool flag = default(bool);
BepInExErrorLogInterpolatedStringHandler val = new BepInExErrorLogInterpolatedStringHandler(93, 1, ref flag);
if (flag)
{
((BepInExLogInterpolatedStringHandler)val).AppendLiteral("[SpitterExplosionDamage] Failed to set DamageTargetPos; explosions will not ");
((BepInExLogInterpolatedStringHandler)val).AppendLiteral("damage spitters: ");
((BepInExLogInterpolatedStringHandler)val).AppendFormatted<Exception>(ex);
}
logger.LogError(val);
}
}
}
[HarmonyPatch]
internal static class Fix_SpitterGlueCollisionCrash
{
private static bool _logged;
private static bool _loggedProbeFailure;
[HarmonyPatch(typeof(GlueGunProjectile), "CollisionCheck")]
[HarmonyFinalizer]
public static Exception? Finalize_CollisionCheck(GlueGunProjectile __instance, Exception? __exception)
{
if (!(__exception is NullReferenceException))
{
return __exception;
}
bool flag;
try
{
flag = SpitterColliders.IsSpitter(((StickingProjectileBase)__instance).m_projLastRayHitCollider);
}
catch (Exception ex)
{
flag = true;
if (!_loggedProbeFailure)
{
_loggedProbeFailure = true;
Plugin.Logger.LogWarning((object)("[SpitterGlueCollisionCrash] Could not identify the glue collision target, suppressing the NullReferenceException conservatively: " + ex.Message));
}
}
if (!flag)
{
return __exception;
}
if (!_logged)
{
_logged = true;
Plugin.Logger.LogWarning((object)"[SpitterGlueCollisionCrash] Suppressed a downstream NullReferenceException from a GlueGunProjectile.CollisionCheck postfix on a glue-vs-spitter collision (e.g. DoorEnemyFixUpdated <= 1.1.3). That is the other mod's bug; KillableSpitters is neutralizing it so C-Foam / glue-mines keep working.");
}
return null;
}
}
internal static class Fix_SpitterHealthRel
{
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
private delegate float HealthRelFn(IntPtr thisPtr, IntPtr methodInfoPtr);
private static HealthRelFn? _thunk;
private static bool _warnedThunkFailure;
internal static bool Installed { get; private set; }
internal unsafe static void Install()
{
//IL_029b: Unknown result type (might be due to invalid IL or missing references)
//IL_02a2: Expected O, but got Unknown
//IL_020e: Unknown result type (might be due to invalid IL or missing references)
//IL_0215: Expected O, but got Unknown
if (Installed)
{
return;
}
bool flag = default(bool);
try
{
IntPtr nativeClassPtr = Il2CppClassPointerStore<InfectionSpitterDamage>.NativeClassPtr;
if (nativeClassPtr == IntPtr.Zero)
{
WarnAborted("class pointer unavailable");
return;
}
IL2CPP.il2cpp_runtime_class_init(nativeClassPtr);
IntPtr intPtr = IL2CPP.il2cpp_class_get_method_from_name(nativeClassPtr, "GetHealthRel", 0);
if (intPtr == IntPtr.Zero)
{
WarnAborted("GetHealthRel not found on InfectionSpitterDamage");
return;
}
INativeMethodInfoStruct val = UnityVersionHandler.Wrap((Il2CppMethodInfo*)(void*)intPtr);
string text = Marshal.PtrToStringAnsi(val.Name);
if (text != "GetHealthRel")
{
WarnAborted("resolved method is named '" + text + "'");
return;
}
if (val.ParametersCount != 0)
{
WarnAborted($"unexpected parameter count {val.ParametersCount}");
return;
}
IntPtr intPtr2 = IL2CPP.il2cpp_method_get_return_type(intPtr);
string text2 = ((intPtr2 != IntPtr.Zero) ? Marshal.PtrToStringAnsi(IL2CPP.il2cpp_type_get_name(intPtr2)) : null);
if (text2 != "System.Single")
{
WarnAborted("unexpected return type '" + text2 + "'");
return;
}
INativeClassStruct obj = UnityVersionHandler.Wrap((Il2CppClass*)(void*)nativeClassPtr);
VirtualInvokeData* ptr = (VirtualInvokeData*)(void*)obj.VTable;
int vtableCount = obj.VtableCount;
List<int> list = new List<int>();
if (ptr != null)
{
for (int i = 0; i < vtableCount; i++)
{
if ((IntPtr)((VirtualInvokeData)((byte*)ptr + (nint)i * (nint)Unsafe.SizeOf<VirtualInvokeData>())).method == intPtr)
{
list.Add(i);
}
}
}
IntPtr methodPointer = val.MethodPointer;
_thunk = HealthRelThunk;
IntPtr functionPointerForDelegate = Marshal.GetFunctionPointerForDelegate(_thunk);
foreach (int item in list)
{
((VirtualInvokeData)((byte*)ptr + (nint)item * (nint)Unsafe.SizeOf<VirtualInvokeData>())).methodPtr = functionPointerForDelegate;
}
val.MethodPointer = functionPointerForDelegate;
Installed = true;
ManualLogSource logger = Plugin.Logger;
BepInExDebugLogInterpolatedStringHandler val2 = new BepInExDebugLogInterpolatedStringHandler(92, 3, ref flag);
if (flag)
{
((BepInExLogInterpolatedStringHandler)val2).AppendLiteral("[SpitterHealthRel] GetHealthRel redirected (original body 0x");
((BepInExLogInterpolatedStringHandler)val2).AppendFormatted(methodPointer, "X");
((BepInExLogInterpolatedStringHandler)val2).AppendLiteral(", ");
((BepInExLogInterpolatedStringHandler)val2).AppendFormatted<int>(list.Count);
((BepInExLogInterpolatedStringHandler)val2).AppendLiteral(" vtable slot(s) of ");
((BepInExLogInterpolatedStringHandler)val2).AppendFormatted<int>(vtableCount);
((BepInExLogInterpolatedStringHandler)val2).AppendLiteral(" rewritten)");
}
logger.LogDebug(val2);
if (list.Count == 0)
{
Plugin.Logger.LogWarning((object)"[SpitterHealthRel] No vtable slot referenced GetHealthRel's MethodInfo — native interface dispatch keeps the vanilla 0 (managed/interop callers are still redirected)");
}
}
catch (Exception ex)
{
ManualLogSource logger2 = Plugin.Logger;
BepInExWarningLogInterpolatedStringHandler val3 = new BepInExWarningLogInterpolatedStringHandler(125, 1, ref flag);
if (flag)
{
((BepInExLogInterpolatedStringHandler)val3).AppendLiteral("[SpitterHealthRel] Install failed, spitters keep the vanilla GetHealthRel() = 0 ");
((BepInExLogInterpolatedStringHandler)val3).AppendLiteral("(EWC projectiles/DoTs will ignore spitters): ");
((BepInExLogInterpolatedStringHandler)val3).AppendFormatted<Exception>(ex);
}
logger2.LogWarning(val3);
}
}
private static void WarnAborted(string reason)
{
Plugin.Logger.LogWarning((object)("[SpitterHealthRel] Install aborted (" + reason + "), spitters keep the vanilla GetHealthRel() = 0 (EWC projectiles/DoTs will ignore spitters)"));
}
private static float HealthRelThunk(IntPtr thisPtr, IntPtr methodInfoPtr)
{
try
{
return SpitterKillManager.GetHealthRelForDamagePtr(thisPtr);
}
catch (Exception ex)
{
WarnThunkOnce(ex);
return 0f;
}
}
private static void WarnThunkOnce(Exception ex)
{
//IL_0018: Unknown result type (might be due to invalid IL or missing references)
//IL_001e: Expected O, but got Unknown
if (_warnedThunkFailure)
{
return;
}
_warnedThunkFailure = true;
try
{
ManualLogSource logger = Plugin.Logger;
bool flag = default(bool);
BepInExWarningLogInterpolatedStringHandler val = new BepInExWarningLogInterpolatedStringHandler(62, 1, ref flag);
if (flag)
{
((BepInExLogInterpolatedStringHandler)val).AppendLiteral("[SpitterHealthRel] Health lookup failed, reporting vanilla 0: ");
((BepInExLogInterpolatedStringHandler)val).AppendFormatted<string>(ex.Message);
}
logger.LogWarning(val);
}
catch
{
}
}
internal static void LogSmokeCheck(InfectionSpitterDamage damage)
{
//IL_005f: Unknown result type (might be due to invalid IL or missing references)
//IL_0065: Expected O, but got Unknown
if (!Installed)
{
return;
}
try
{
Plugin.Logger.LogDebug((object)($"[SpitterHealthRel] Smoke check: GetHealthRel() = {damage.GetHealthRel()} " + "(expected > 0 for a live spitter)"));
}
catch (Exception ex)
{
ManualLogSource logger = Plugin.Logger;
bool flag = default(bool);
BepInExWarningLogInterpolatedStringHandler val = new BepInExWarningLogInterpolatedStringHandler(39, 1, ref flag);
if (flag)
{
((BepInExLogInterpolatedStringHandler)val).AppendLiteral("[SpitterHealthRel] Smoke check failed: ");
((BepInExLogInterpolatedStringHandler)val).AppendFormatted<string>(ex.Message);
}
logger.LogWarning(val);
}
}
}
[HarmonyPatch]
internal static class Fix_SpitterMineTrigger
{
private const float BeamRadius = 0.1f;
private const int MaxLookPastSteps = 8;
private static bool _broken;
[HarmonyPatch(typeof(MineDeployerInstance_Detect_Laser), "UpdateDetection")]
[HarmonyPrefix]
public static bool Pre_UpdateDetection(MineDeployerInstance_Detect_Laser __instance)
{
//IL_00f1: Unknown result type (might be due to invalid IL or missing references)
//IL_00f8: Expected O, but got Unknown
//IL_0010: Unknown result type (might be due to invalid IL or missing references)
//IL_0015: Unknown result type (might be due to invalid IL or missing references)
//IL_0016: Unknown result type (might be due to invalid IL or missing references)
//IL_0018: Invalid comparison between Unknown and I4
//IL_001a: Unknown result type (might be due to invalid IL or missing references)
//IL_001c: Invalid comparison between Unknown and I4
//IL_0042: Unknown result type (might be due to invalid IL or missing references)
//IL_0047: Unknown result type (might be due to invalid IL or missing references)
//IL_0048: Unknown result type (might be due to invalid IL or missing references)
//IL_004d: Unknown result type (might be due to invalid IL or missing references)
//IL_005e: Unknown result type (might be due to invalid IL or missing references)
//IL_0063: Unknown result type (might be due to invalid IL or missing references)
//IL_0065: Unknown result type (might be due to invalid IL or missing references)
//IL_006b: Unknown result type (might be due to invalid IL or missing references)
//IL_0087: Unknown result type (might be due to invalid IL or missing references)
//IL_00ab: Unknown result type (might be due to invalid IL or missing references)
//IL_00ac: Unknown result type (might be due to invalid IL or missing references)
//IL_00b0: Unknown result type (might be due to invalid IL or missing references)
if (_broken)
{
return true;
}
try
{
eStickyMineMode mode = __instance.m_core.Mode;
if ((int)mode != 2 && (int)mode != 1)
{
return true;
}
if (__instance.m_maxLineDistance <= 0f)
{
return true;
}
Transform lineRendererAlign = __instance.m_lineRendererAlign;
Vector3 position = lineRendererAlign.position;
Vector3 forward = lineRendererAlign.forward;
float maxLineDistance = __instance.m_maxLineDistance;
int scanMask = __instance.m_scanMask;
LayerMask enemyMask = __instance.m_enemyMask;
RaycastHit val = default(RaycastHit);
if (!Physics.SphereCast(position, 0.1f, forward, ref val, maxLineDistance, scanMask))
{
return true;
}
if (!IsOnMask(((RaycastHit)(ref val)).collider, enemyMask))
{
return true;
}
if (!SpitterColliders.IsSpitter(((RaycastHit)(ref val)).collider))
{
return true;
}
if (HasNonSpitterEnemy(position, forward, maxLineDistance, scanMask, enemyMask))
{
return true;
}
if (((RaycastHit)(ref val)).distance != __instance.DetectionRange)
{
__instance.UpdateDetectionRange(((RaycastHit)(ref val)).distance);
}
return false;
}
catch (Exception ex)
{
_broken = true;
ManualLogSource logger = Plugin.Logger;
bool flag = default(bool);
BepInExErrorLogInterpolatedStringHandler val2 = new BepInExErrorLogInterpolatedStringHandler(76, 1, ref flag);
if (flag)
{
((BepInExLogInterpolatedStringHandler)val2).AppendLiteral("[SpitterMineTrigger] Detection patch failed, reverting to vanilla behavior: ");
((BepInExLogInterpolatedStringHandler)val2).AppendFormatted<Exception>(ex);
}
logger.LogError(val2);
return true;
}
}
private static bool HasNonSpitterEnemy(Vector3 origin, Vector3 dir, float remaining, int scanMask, LayerMask enemyMask)
{
//IL_0004: Unknown result type (might be due to invalid IL or missing references)
//IL_000a: Unknown result type (might be due to invalid IL or missing references)
//IL_001f: Unknown result type (might be due to invalid IL or missing references)
//IL_0048: Unknown result type (might be due to invalid IL or missing references)
//IL_0049: Unknown result type (might be due to invalid IL or missing references)
//IL_004b: Unknown result type (might be due to invalid IL or missing references)
//IL_0050: Unknown result type (might be due to invalid IL or missing references)
//IL_0055: Unknown result type (might be due to invalid IL or missing references)
RaycastHit val = default(RaycastHit);
for (int i = 0; i < 8; i++)
{
if (!(remaining > 0.01f))
{
break;
}
if (!Physics.SphereCast(origin, 0.1f, dir, ref val, remaining, scanMask))
{
return false;
}
if (!IsOnMask(((RaycastHit)(ref val)).collider, enemyMask))
{
return false;
}
if (!SpitterColliders.IsSpitter(((RaycastHit)(ref val)).collider))
{
return true;
}
float num = ((RaycastHit)(ref val)).distance + 0.2f;
origin += dir * num;
remaining -= num;
}
return false;
}
private static bool IsOnMask(Collider collider, LayerMask mask)
{
if ((Object)(object)collider != (Object)null)
{
return (((LayerMask)(ref mask)).value & (1 << ((Component)collider).gameObject.layer)) != 0;
}
return false;
}
}
[HarmonyPatch]
internal static class Fix_SpitterSentryTarget
{
private const float LosProbeOffset = 0.4f;
private static bool _broken;
[HarmonyPatch(typeof(SentryGunInstance_Detection), "CheckForTargetLegacy")]
[HarmonyPrefix]
public static bool Pre_CheckForTargetLegacy(ArchetypeDataBlock archetypeData, Transform detectionSource, ref EnemyAgent? __result)
{
//IL_0028: Unknown result type (might be due to invalid IL or missing references)
//IL_002e: Expected O, but got Unknown
if (_broken)
{
return true;
}
try
{
__result = CheckForTargetSkippingSpitters(archetypeData, detectionSource);
return false;
}
catch (Exception ex)
{
_broken = true;
ManualLogSource logger = Plugin.Logger;
bool flag = default(bool);
BepInExErrorLogInterpolatedStringHandler val = new BepInExErrorLogInterpolatedStringHandler(84, 1, ref flag);
if (flag)
{
((BepInExLogInterpolatedStringHandler)val).AppendLiteral("[SpitterSentryTarget] Legacy detection patch failed, reverting to vanilla behavior: ");
((BepInExLogInterpolatedStringHandler)val).AppendFormatted<Exception>(ex);
}
logger.LogError(val);
return true;
}
}
private static EnemyAgent? CheckForTargetSkippingSpitters(ArchetypeDataBlock archetypeData, Transform detectionSource)
{
//IL_0001: Unknown result type (might be due to invalid IL or missing references)
//IL_0006: Unknown result type (might be due to invalid IL or missing references)
//IL_0008: Unknown result type (might be due to invalid IL or missing references)
//IL_000d: Unknown result type (might be due to invalid IL or missing references)
//IL_000e: Unknown result type (might be due to invalid IL or missing references)
//IL_0033: Unknown result type (might be due to invalid IL or missing references)
//IL_0038: Unknown result type (might be due to invalid IL or missing references)
//IL_003a: Unknown result type (might be due to invalid IL or missing references)
//IL_003b: Unknown result type (might be due to invalid IL or missing references)
//IL_003d: Unknown result type (might be due to invalid IL or missing references)
//IL_003e: Unknown result type (might be due to invalid IL or missing references)
//IL_0053: Unknown result type (might be due to invalid IL or missing references)
//IL_0054: Unknown result type (might be due to invalid IL or missing references)
//IL_0065: Unknown result type (might be due to invalid IL or missing references)
//IL_0066: Unknown result type (might be due to invalid IL or missing references)
//IL_0068: Unknown result type (might be due to invalid IL or missing references)
//IL_0072: Unknown result type (might be due to invalid IL or missing references)
//IL_0077: Unknown result type (might be due to invalid IL or missing references)
//IL_0088: Unknown result type (might be due to invalid IL or missing references)
//IL_0089: Unknown result type (might be due to invalid IL or missing references)
//IL_008b: Unknown result type (might be due to invalid IL or missing references)
//IL_0095: Unknown result type (might be due to invalid IL or missing references)
//IL_009a: Unknown result type (might be due to invalid IL or missing references)
Vector3 forward = detectionSource.forward;
Vector3 position = detectionSource.position;
Il2CppReferenceArray<Collider> val = Physics.OverlapSphere(position, archetypeData.Sentry_DetectionMaxRange, LayerManager.MASK_SENTRYGUN_DETECTION_TARGETS);
for (int i = 0; i < ((Il2CppArrayBase<Collider>)(object)val).Length; i++)
{
Vector3 position2 = ((Component)((Il2CppArrayBase<Collider>)(object)val)[i]).transform.position;
if (Vector3.Angle(forward, position2 - position) >= archetypeData.Sentry_DetectionMaxAngle || Physics.Linecast(position, position2, LayerManager.MASK_SENTRYGUN_DETECTION_BLOCKERS) || Physics.Linecast(position, position2 + Vector3.up * 0.4f, LayerManager.MASK_SENTRYGUN_DETECTION_BLOCKERS) || Physics.Linecast(position, position2 + Vector3.left * 0.4f, LayerManager.MASK_SENTRYGUN_DETECTION_BLOCKERS))
{
continue;
}
IDamageable component = ((Component)((Il2CppArrayBase<Collider>)(object)val)[i]).GetComponent<IDamageable>();
if (component != null && !(component.GetHealthRel() <= 0f))
{
Agent baseAgent = component.GetBaseAgent();
EnemyAgent val2 = ((baseAgent != null) ? ((Il2CppObjectBase)baseAgent).TryCast<EnemyAgent>() : null);
if (!((Object)(object)val2 == (Object)null) && ((!val2.RequireTagForDetection && !archetypeData.Sentry_FireTagOnly) || val2.IsTagged))
{
return val2;
}
}
}
return null;
}
}
internal static class SpitterColliders
{
internal static bool TryGetDamage(Collider collider, out InfectionSpitterDamage damage)
{
damage = null;
if ((Object)(object)collider == (Object)null)
{
return false;
}
damage = ((Component)collider).GetComponent<InfectionSpitterDamage>();
if ((Object)(object)damage != (Object)null)
{
return true;
}
ColliderMaterial component = ((Component)collider).GetComponent<ColliderMaterial>();
IDamageable val = ((component != null) ? component.Damageable : null);
if (val != null)
{
damage = ((Il2CppObjectBase)val).TryCast<InfectionSpitterDamage>();
}
return (Object)(object)damage != (Object)null;
}
internal static bool IsSpitter(Collider collider)
{
InfectionSpitterDamage damage;
return TryGetDamage(collider, out damage);
}
}
}
namespace KillableSpitters.Patches.Spitters
{
[HarmonyPatch]
internal static class Patch_SpitterDamage
{
[HarmonyPatch(typeof(InfectionSpitter), "OnIncomingDamage")]
[HarmonyPrefix]
public static bool Pre_OnIncomingDamage(InfectionSpitter __instance, float dam)
{
//IL_0025: Unknown result type (might be due to invalid IL or missing references)
//IL_002b: Invalid comparison between Unknown and I4
try
{
if (SpitterKillManager.IsDeadOrDying(__instance.m_spitterIndex))
{
return false;
}
if (__instance.m_isExploding)
{
SpitterKillManager.ReportDamage(__instance, dam);
return false;
}
if ((int)__instance.m_currentState == 2)
{
__instance.SendSlowExplode();
}
else
{
__instance.SendExplode();
}
SpitterKillManager.ReportDamage(__instance, dam);
return false;
}
catch (Exception ex)
{
SpitterKillManager.Break(ex);
return true;
}
}
[HarmonyPatch(typeof(InfectionSpitter), "DoGetGlued")]
[HarmonyPostfix]
public static void Post_DoGetGlued(InfectionSpitter __instance)
{
SpitterKillManager.OnSpitterGlued(__instance);
}
[HarmonyPatch(typeof(InfectionSpitter), "OnIncomingGlue")]
[HarmonyPrefix]
public static bool Pre_OnIncomingGlue(InfectionSpitter __instance)
{
try
{
return !SpitterKillManager.IsDeadOrDying(__instance.m_spitterIndex);
}
catch (Exception ex)
{
SpitterKillManager.Break(ex);
return true;
}
}
[HarmonyPatch(typeof(InfectionSpitter), "ReceiveDamage")]
[HarmonyPrefix]
public static bool Pre_ReceiveDamage(InfectionSpitterDamage data)
{
//IL_0000: Unknown result type (might be due to invalid IL or missing references)
try
{
return !SpitterKillManager.IsDeadOrDying(data.spitterIndex);
}
catch (Exception ex)
{
SpitterKillManager.Break(ex);
return true;
}
}
[HarmonyPatch(typeof(InfectionSpitter), "Update")]
[HarmonyPostfix]
public static void Post_Update(InfectionSpitter __instance)
{
SpitterKillManager.OnSpitterUpdatePostfix(__instance);
}
internal static void LogDamageForwarderFoldState()
{
//IL_01e9: Unknown result type (might be due to invalid IL or missing references)
//IL_01f0: Expected O, but got Unknown
//IL_00dd: Unknown result type (might be due to invalid IL or missing references)
//IL_00e4: Expected O, but got Unknown
bool flag = default(bool);
try
{
string[] array = new string[4] { "BulletDamage", "MeleeDamage", "FireDamage", "ExplosionDamage" };
Dictionary<string, IntPtr> dictionary = new Dictionary<string, IntPtr>();
FieldInfo[] fields = typeof(InfectionSpitterDamage).GetFields(BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic);
foreach (FieldInfo field in fields)
{
if (field.FieldType != typeof(IntPtr))
{
continue;
}
string text = Array.Find(array, (string f) => field.Name.StartsWith("NativeMethodInfoPtr_" + f + "_", StringComparison.Ordinal));
if (text != null)
{
IntPtr intPtr = (IntPtr)field.GetValue(null);
if (intPtr != IntPtr.Zero)
{
dictionary[text] = Marshal.ReadIntPtr(intPtr);
}
}
}
if (dictionary.Count < array.Length)
{
ManualLogSource logger = Plugin.Logger;
BepInExWarningLogInterpolatedStringHandler val = new BepInExWarningLogInterpolatedStringHandler(65, 2, ref flag);
if (flag)
{
((BepInExLogInterpolatedStringHandler)val).AppendLiteral("[SpitterKill] Damage-forwarder fold check incomplete (");
((BepInExLogInterpolatedStringHandler)val).AppendFormatted<int>(dictionary.Count);
((BepInExLogInterpolatedStringHandler)val).AppendLiteral("/");
((BepInExLogInterpolatedStringHandler)val).AppendFormatted<int>(array.Length);
((BepInExLogInterpolatedStringHandler)val).AppendLiteral(" resolved)");
}
logger.LogWarning(val);
}
else if (dictionary.Values.Distinct().Count() == 1)
{
Plugin.Logger.LogDebug((object)("[SpitterKill] InfectionSpitterDamage damage forwarders share one native body " + $"(ICF-folded at 0x{dictionary["BulletDamage"]:X}, expected — none of them is patched)"));
}
else
{
Plugin.Logger.LogWarning((object)("[SpitterKill] Damage forwarders are NOT folded on this build — the ICF assumption that keeps them unpatchable no longer holds (the tap is on OnIncomingDamage, but the house rule against patching a forwarder still stands): " + string.Join(", ", dictionary.Select((KeyValuePair<string, IntPtr> kv) => $"{kv.Key}=0x{kv.Value:X}"))));
}
}
catch (Exception ex)
{
ManualLogSource logger2 = Plugin.Logger;
BepInExWarningLogInterpolatedStringHandler val = new BepInExWarningLogInterpolatedStringHandler(68, 1, ref flag);
if (flag)
{
((BepInExLogInterpolatedStringHandler)val).AppendLiteral("[SpitterKill] Damage-forwarder fold check failed (diagnostic only): ");
((BepInExLogInterpolatedStringHandler)val).AppendFormatted<string>(ex.Message);
}
logger2.LogWarning(val);
}
}
}
public static class SpitterDeathFx
{
private const uint FlyerEnemyId = 42u;
private const string DeathFxPrefabName = "FXC_FlyerDeath";
private static bool _broken;
private static bool _warnedNoPool;
private static FX_Pool? _pool;
public static void PlayAt(Vector3 position)
{
//IL_0066: Unknown result type (might be due to invalid IL or missing references)
//IL_006c: Expected O, but got Unknown
//IL_000e: Unknown result type (might be due to invalid IL or missing references)
//IL_003f: Unknown result type (might be due to invalid IL or missing references)
//IL_0040: Unknown result type (might be due to invalid IL or missing references)
if (_broken)
{
return;
}
try
{
CellSound.Post(EVENTS.FLYER_DIE, position);
FX_Pool val = ResolvePool();
if ((Object)(object)val == (Object)null)
{
WarnNoPoolOnce();
return;
}
FX_EffectBase_Poolable val2 = val.AquireEffect();
if (!((Object)(object)val2 == (Object)null))
{
((FX_EffectBase)val2).Play((FX_Trigger)null, position, Quaternion.identity);
}
}
catch (ObjectCollectedException)
{
_pool = null;
}
catch (Exception ex2)
{
_broken = true;
ManualLogSource logger = Plugin.Logger;
bool flag = default(bool);
BepInExWarningLogInterpolatedStringHandler val3 = new BepInExWarningLogInterpolatedStringHandler(41, 1, ref flag);
if (flag)
{
((BepInExLogInterpolatedStringHandler)val3).AppendLiteral("[SpitterKill] Spitter death FX disabled: ");
((BepInExLogInterpolatedStringHandler)val3).AppendFormatted<Exception>(ex2);
}
logger.LogWarning(val3);
}
}
private static FX_Pool? ResolvePool()
{
if ((Object)(object)_pool != (Object)null)
{
return _pool;
}
_pool = FX_Manager.GetPreloadedEffectPool("FXC_FlyerDeath");
if ((Object)(object)_pool != (Object)null)
{
return _pool;
}
GameObject val = GetDeathFxPrefab();
if ((Object)(object)val == (Object)null)
{
val = Resources.Load<GameObject>("FXC_FlyerDeath");
}
if ((Object)(object)val != (Object)null)
{
_pool = FX_Manager.GetEffectPool(val);
}
return _pool;
}
private static GameObject? GetDeathFxPrefab()
{
GameObject enemyPrefab = EnemyPrefabManager.GetEnemyPrefab(42u);
if ((Object)(object)enemyPrefab == (Object)null)
{
return null;
}
FlyerAnimationController componentInChildren = enemyPrefab.GetComponentInChildren<FlyerAnimationController>(true);
if ((Object)(object)componentInChildren == (Object)null)
{
return null;
}
return componentInChildren.m_deathFX;
}
private static void WarnNoPoolOnce()
{
if (!_warnedNoPool)
{
_warnedNoPool = true;
Plugin.Logger.LogWarning((object)"[SpitterKill] Could not resolve the flyer death FX pool (FXC_FlyerDeath); spitter removals play sound only");
}
}
}
public struct SpitterDeathState
{
public const int MaskBytes = 240;
public const int SpittersPerShard = 1920;
public byte ShardIndex;
private unsafe fixed byte _deadBits[240];
public static (int shard, int local) MapIndex(ushort spitterIndex)
{
return (shard: spitterIndex / 1920, local: spitterIndex % 1920);
}
public unsafe bool IsDead(int localIndex)
{
if (localIndex < 0 || localIndex >= 1920)
{
return false;
}
fixed (byte* deadBits = _deadBits)
{
return (deadBits[localIndex >> 3] & (1 << (localIndex & 7))) != 0;
}
}
public unsafe void SetDead(int localIndex)
{
if (localIndex >= 0 && localIndex < 1920)
{
fixed (byte* deadBits = _deadBits)
{
byte* num = deadBits + (localIndex >> 3);
*num |= (byte)(1 << (localIndex & 7));
}
}
}
public unsafe void ClearDead(int localIndex)
{
if (localIndex >= 0 && localIndex < 1920)
{
fixed (byte* deadBits = _deadBits)
{
byte* num = deadBits + (localIndex >> 3);
*num &= (byte)(~(1 << (localIndex & 7)));
}
}
}
public unsafe byte GetMaskByte(int byteIndex)
{
if (byteIndex < 0 || byteIndex >= 240)
{
return 0;
}
fixed (byte* deadBits = _deadBits)
{
return deadBits[byteIndex];
}
}
}
public static class SpitterKillManager
{
private const string DamageEventName = "killable_spitters_damage";
private const string HealthEventName = "killable_spitters_health";
private const uint REPLICATOR_BASE_ID = 1263751252u;
private const int SHARD_COUNT = 4;
public const int SpitterCapacity = 7680;
private const float FinalizeGraceSeconds = 1.5f;
private const float FinalizeDeadlineSeconds = 5f;
private const float PopAdoptWindowSeconds = 1.5f;
private const float MaxReportedDamagePerHit = 100f;
private static bool _broken;
private static bool _setupDone;
private static bool _warnedCapacity;
private static readonly Dictionary<ushort, float> _healthByIndex = new Dictionary<ushort, float>();
private static readonly Dictionary<ushort, float> _healthRel = new Dictionary<ushort, float>();
private static readonly HashSet<ushort> _dead = new HashSet<ushort>();
private static readonly Dictionary<ushort, float> _dyingFinalizeAt = new Dictionary<ushort, float>();
private static readonly Dictionary<ushort, float> _dyingDeadline = new Dictionary<ushort, float>();
private static readonly HashSet<ushort> _finalized = new HashSet<ushort>();
private static readonly HashSet<ushort> _explodingNow = new HashSet<ushort>();
private static readonly Dictionary<ushort, float> _lastPopCompletedAt = new Dictionary<ushort, float>();
private static readonly HashSet<ushort> _pendingDeathFx = new HashSet<ushort>();
private static readonly HashSet<ushort> _modelHidden = new HashSet<ushort>();
private static readonly Dictionary<ushort, float> _gluedAt = new Dictionary<ushort, float>();
private static readonly Dictionary<IntPtr, ushort> _damagePtrToIndex = new Dictionary<IntPtr, ushort>();
private static readonly StateReplicator<SpitterDeathState>?[] _replicators = new StateReplicator<SpitterDeathState>[4];
private static readonly SpitterDeathState[] _currentStates = new SpitterDeathState[4];
private static readonly Action<SpitterDeathState, SpitterDeathState, bool>?[] _handlers = new Action<SpitterDeathState, SpitterDeathState, bool>[4];
public static void Setup()
{
if (!_setupDone)
{
_setupDone = true;
NetworkAPI.RegisterEvent<SpitterDamageEvent>("killable_spitters_damage", (Action<ulong, SpitterDamageEvent>)OnDamageEventReceived);
NetworkAPI.RegisterEvent<SpitterHealthEvent>("killable_spitters_health", (Action<ulong, SpitterHealthEvent>)OnHealthEventReceived);
LevelAPI.OnBuildDone += OnBuildDone;
LevelAPI.OnLevelCleanup += OnLevelCleanup;
LevelAPI.OnEnterLevel += ReconcileDeadSpitters;
}
}
public static bool IsDeadOrDying(ushort spitterIndex)
{
if (_dead.Count != 0)
{
return _dead.Contains(spitterIndex);
}
return false;
}
public static void ReportDamage(InfectionSpitter spitter, float dam)
{
if (_broken || (Object)(object)spitter == (Object)null || float.IsNaN(dam) || dam <= 0f)
{
return;
}
ushort spitterIndex = spitter.m_spitterIndex;
if (!IsDeadOrDying(spitterIndex))
{
if (spitterIndex >= 7680)
{
WarnCapacityOnce(spitterIndex);
}
else if (SNet.IsMaster)
{
AccumulateDamage(spitterIndex, Math.Min(dam, 100f));
}
else if (SNet.HasMaster)
{
NetworkAPI.InvokeEvent<SpitterDamageEvent>("killable_spitters_damage", new SpitterDamageEvent
{
SpitterIndex = spitterIndex,
Damage = dam
}, SNet.Master, (SNet_ChannelType)2);
}
}
}
internal static float GetHealthRelForDamagePtr(IntPtr damagePtr)
{
if (_broken || _damagePtrToIndex.Count == 0)
{
return 0f;
}
if (!_damagePtrToIndex.TryGetValue(damagePtr, out var value))
{
return 0f;
}
if (value >= 7680 || IsDeadOrDying(value))
{
return 0f;
}
if (_healthByIndex.TryGetValue(value, out var value2))
{
return Math.Clamp(value2 / Math.Max(1f, Plugin.Config_SpitterHealth), 0.01f, 1f);
}
if (_healthRel.TryGetValue(value, out var value3))
{
return Math.Clamp(value3, 0.01f, 1f);
}
return 1f;
}
public static bool ShouldBlockManagerUpdate(InfectionSpitter spitter)
{
if (_broken)
{
return false;
}
try
{
if ((Object)(object)spitter == (Object)null)
{
return false;
}
ushort spitterIndex = spitter.m_spitterIndex;
TickGlueKill(spitterIndex);
if (_dead.Count == 0 || !_dead.Contains(spitterIndex))
{
return false;
}
if (_dyingFinalizeAt.TryGetValue(spitterIndex, out var value))
{
float value2;
float num = (_dyingDeadline.TryGetValue(spitterIndex, out value2) ? value2 : float.MaxValue);
if (Clock.Time >= num || (value != float.MaxValue && Clock.Time >= value))
{
FinalizeSpitter(spitterIndex, spitter);
}
}
return true;
}
catch (Exception ex)
{
Break(ex);
return false;
}
}
public static void OnSpitterUpdatePostfix(InfectionSpitter spitter)
{
//IL_0095: Unknown result type (might be due to invalid IL or missing references)
//IL_00d5: Unknown result type (might be due to invalid IL or missing references)
//IL_00af: Unknown result type (might be due to invalid IL or missing references)
if (_broken || (Object)(object)spitter == (Object)null)
{
return;
}
try
{
ushort spitterIndex = spitter.m_spitterIndex;
SpitterVisuals.TickRestores();
if (spitter.m_isExploding)
{
_explodingNow.Add(spitterIndex);
float value;
if (_dyingFinalizeAt.ContainsKey(spitterIndex))
{
SpitterVisuals.ApplyDeathRamp(spitter);
}
else if (_healthRel.TryGetValue(spitterIndex, out value))
{
SpitterVisuals.ApplyDamageRamp(spitter, value);
}
}
else if (_explodingNow.Remove(spitterIndex))
{
_lastPopCompletedAt[spitterIndex] = Clock.Time;
float value2;
if (_dyingFinalizeAt.ContainsKey(spitterIndex))
{
SpitterVisuals.TintPop(spitterIndex, spitter, SpitterVisuals.DeathPopColor, recolorLiveParticles: false, untilFinalize: true);
if (_pendingDeathFx.Remove(spitterIndex))
{
SpitterDeathFx.PlayAt(spitter.m_position);
HideSpitterModel(spitterIndex, spitter);
}
}
else if (_healthRel.TryGetValue(spitterIndex, out value2))
{
SpitterVisuals.TintPop(spitterIndex, spitter, SpitterVisuals.GetPopColor(value2), recolorLiveParticles: false, untilFinalize: false);
SpitterVisuals.ApplyDamageTint(spitter, value2);
}
}
TickGlueKill(spitterIndex);
if (_dyingFinalizeAt.Count == 0 || !_dyingFinalizeAt.TryGetValue(spitterIndex, out var value3))
{
return;
}
float value4;
float num = (_dyingDeadline.TryGetValue(spitterIndex, out value4) ? value4 : float.MaxValue);
if (value3 == float.MaxValue)
{
if (!spitter.m_isExploding)
{
_dyingFinalizeAt[spitterIndex] = Clock.Time + 1.5f;
}
else if (Clock.Time >= num)
{
FinalizeSpitter(spitterIndex, spitter);
}
}
else if (Clock.Time >= value3 || Clock.Time >= num)
{
FinalizeSpitter(spitterIndex, spitter);
}
}
catch (Exception ex)
{
Break(ex);
}
}
public static void OnSpitterGlued(InfectionSpitter spitter)
{
if (_broken || (Object)(object)spitter == (Object)null)
{
return;
}
try
{
ushort spitterIndex = spitter.m_spitterIndex;
if (spitterIndex >= 7680)
{
WarnCapacityOnce(spitterIndex);
}
else
{
if (IsDeadOrDying(spitterIndex))
{
return;
}
if (Plugin.Config_CfoamKillsSpitters)
{
if (SNet.IsMaster)
{
_gluedAt.TryAdd(spitterIndex, Clock.Time);
}
}
else
{
spitter.m_stayInTimer = Math.Max(0f, Plugin.Config_SpitterFreezeDuration);
}
}
}
catch (Exception ex)
{
Break(ex);
}
}
private static void TickGlueKill(ushort index)
{
//IL_005e: Unknown result type (might be due to invalid IL or missing references)
//IL_0064: Expected O, but got Unknown
if (_gluedAt.Count == 0 || !SNet.IsMaster || !_gluedAt.TryGetValue(index, out var value))
{
return;
}
if (IsDeadOrDying(index))
{
_gluedAt.Remove(index);
}
else if (!(Clock.Time - value < Plugin.Config_SpitterFreezeDuration))
{
_gluedAt.Remove(index);
ManualLogSource logger = Plugin.Logger;
bool flag = default(bool);
BepInExDebugLogInterpolatedStringHandler val = new BepInExDebugLogInterpolatedStringHandler(46, 1, ref flag);
if (flag)
{
((BepInExLogInterpolatedStringHandler)val).AppendLiteral("[SpitterKill] Spitter ");
((BepInExLogInterpolatedStringHandler)val).AppendFormatted<ushort>(index);
((BepInExLogInterpolatedStringHandler)val).AppendLiteral(" killed by C-foam (host)");
}
logger.LogDebug(val);
HostMarkDead(index);
}
}
public static void Break(Exception ex)
{
//IL_004b: Unknown result type (might be due to invalid IL or missing references)
//IL_0051: Expected O, but got Unknown
//IL_00dd: Unknown result type (might be due to invalid IL or missing references)
//IL_00e3: Expected O, but got Unknown
//IL_0018: Unknown result type (might be due to invalid IL or missing references)
//IL_001e: Expected O, but got Unknown
if (_broken)
{
return;
}
_broken = true;
ManualLogSource logger = Plugin.Logger;
bool flag = default(bool);
BepInExErrorLogInterpolatedStringHandler val = new BepInExErrorLogInterpolatedStringHandler(69, 1, ref flag);
if (flag)
{
((BepInExLogInterpolatedStringHandler)val).AppendLiteral("[SpitterKill] Unexpected error, disabling killable spitters locally: ");
((BepInExLogInterpolatedStringHandler)val).AppendFormatted<Exception>(ex);
}
logger.LogError(val);
try
{
SpitterVisuals.RestoreAll();
}
catch (Exception ex2)
{
ManualLogSource logger2 = Plugin.Logger;
BepInExWarningLogInterpolatedStringHandler val2 = new BepInExWarningLogInterpolatedStringHandler(46, 1, ref flag);
if (flag)
{
((BepInExLogInterpolatedStringHandler)val2).AppendLiteral("[SpitterKill] FX restore during Break failed: ");
((BepInExLogInterpolatedStringHandler)val2).AppendFormatted<string>(ex2.Message);
}
logger2.LogWarning(val2);
}
try
{
foreach (ushort item in _modelHidden.ToList())
{
InfectionSpitter val3 = TryGetSpitter(item);
if ((Object)(object)val3 != (Object)null)
{
ShowSpitterModel(item, val3);
}
}
_modelHidden.Clear();
}
catch (Exception ex3)
{
ManualLogSource logger3 = Plugin.Logger;
BepInExWarningLogInterpolatedStringHandler val2 = new BepInExWarningLogInterpolatedStringHandler(49, 1, ref flag);
if (flag)
{
((BepInExLogInterpolatedStringHandler)val2).AppendLiteral("[SpitterKill] Model restore during Break failed: ");
((BepInExLogInterpolatedStringHandler)val2).AppendFormatted<string>(ex3.Message);
}
logger3.LogWarning(val2);
}
}
private static void OnDamageEventReceived(ulong senderPlayer, SpitterDamageEvent data)
{
if (_broken || !SNet.IsMaster)
{
return;
}
try
{
if (!float.IsNaN(data.Damage) && !(data.Damage <= 0f))
{
if (data.SpitterIndex >= 7680)
{
WarnCapacityOnce(data.SpitterIndex);
}
else
{
AccumulateDamage(data.SpitterIndex, Math.Min(data.Damage, 100f));
}
}
}
catch (Exception ex)
{
Break(ex);
}
}
private static void AccumulateDamage(ushort index, float dam)
{
if (!IsDeadOrDying(index))
{
if (!_healthByIndex.TryGetValue(index, out var value))
{
value = Math.Max(1f, Plugin.Config_SpitterHealth);
}
value -= dam;
if (value > 0f)
{
_healthByIndex[index] = value;
BroadcastHealth(index, value);
}
else
{
HostMarkDead(index);
}
}
}
private static void HostMarkDead(ushort index)
{
//IL_0078: Unknown result type (might be due to invalid IL or missing references)
//IL_007e: Expected O, but got Unknown
//IL_00c1: Unknown result type (might be due to invalid IL or missing references)
//IL_00c8: Expected O, but got Unknown
_healthByIndex.Remove(index);
_gluedAt.Remove(index);
_dead.Add(index);
var (num, dead) = SpitterDeathState.MapIndex(index);
_currentStates[num].SetDead(dead);
StateReplicator<SpitterDeathState> val = _replicators[num];
bool flag = default(bool);
if (val != null && val.IsValid)
{
val.SetState(_currentStates[num]);
}
else
{
ManualLogSource logger = Plugin.Logger;
BepInExWarningLogInterpolatedStringHandler val2 = new BepInExWarningLogInterpolatedStringHandler(73, 2, ref flag);
if (flag)
{
((BepInExLogInterpolatedStringHandler)val2).AppendLiteral("[SpitterKill] Replicator for shard ");
((BepInExLogInterpolatedStringHandler)val2).AppendFormatted<int>(num);
((BepInExLogInterpolatedStringHandler)val2).AppendLiteral(" missing, spitter ");
((BepInExLogInterpolatedStringHandler)val2).AppendFormatted<ushort>(index);
((BepInExLogInterpolatedStringHandler)val2).AppendLiteral(" death is local-only");
}
logger.LogWarning(val2);
}
ManualLogSource logger2 = Plugin.Logger;
BepInExDebugLogInterpolatedStringHandler val3 = new BepInExDebugLogInterpolatedStringHandler(36, 1, ref flag);
if (flag)
{
((BepInExLogInterpolatedStringHandler)val3).AppendLiteral("[SpitterKill] Spitter ");
((BepInExLogInterpolatedStringHandler)val3).AppendFormatted<ushort>(index);
((BepInExLogInterpolatedStringHandler)val3).AppendLiteral(" killed (host)");
}
logger2.LogDebug(val3);
KillSpitter(index, silent: false);
}
private static void BroadcastHealth(ushort index, float health)
{
SpitterHealthEvent spitterHealthEvent = new SpitterHealthEvent
{
SpitterIndex = index,
HealthRel = Math.Clamp(health / Math.Max(1f, Plugin.Config_SpitterHealth), 0f, 1f)
};
NetworkAPI.InvokeEvent<SpitterHealthEvent>("killable_spitters_health", spitterHealthEvent, (SNet_ChannelType)2);
OnHealthEventReceived(0uL, spitterHealthEvent);
}
private static void OnHealthEventReceived(ulong senderPlayer, SpitterHealthEvent data)
{
if (_broken)
{
return;
}
try
{
if (float.IsNaN(data.HealthRel))
{
return;
}
if (data.SpitterIndex >= 7680)
{
WarnCapacityOnce(data.SpitterIndex);
}
else if (!IsDeadOrDying(data.SpitterIndex))
{
float num = Math.Clamp(data.HealthRel, 0f, 1f);
_healthRel[data.SpitterIndex] = num;
InfectionSpitter val = TryGetSpitter(data.SpitterIndex);
if ((Object)(object)val != (Object)null)
{
SpitterVisuals.ApplyDamageTint(val, num);
}
}
}
catch (Exception ex)
{
Break(ex);
}
}
private static void OnDeathStateChanged(int shard, SpitterDeathState oldState, SpitterDeathState newState, bool isRecall)
{
if (_broken)
{
return;
}
try
{
_currentStates[shard] = newState;
for (int i = 0; i < 240; i++)
{
byte maskByte = oldState.GetMaskByte(i);
byte maskByte2 = newState.GetMaskByte(i);
if (maskByte == maskByte2)
{
continue;
}
byte b = (byte)(maskByte2 & ~maskByte);
byte b2 = (byte)(maskByte & ~maskByte2);
for (int j = 0; j < 8; j++)
{
ushort num = (ushort)(shard * 1920 + i * 8 + j);
int num2 = 1 << j;
if ((b & num2) != 0)
{
_dead.Add(num);
KillSpitter(num, isRecall);
}
else if ((b2 & num2) != 0)
{
ReviveSpitter(num);
}
}
}
}
catch (Exception ex)
{
Break(ex);
}
}
private static void KillSpitter(ushort index, bool silent)
{
//IL_0045: Unknown result type (might be due to invalid IL or missing references)
//IL_004b: Expected O, but got Unknown
//IL_012f: Unknown result type (might be due to invalid IL or missing references)
//IL_0135: Invalid comparison between Unknown and I4
//IL_0104: Unknown result type (might be due to invalid IL or missing references)
//IL_00db: Unknown result type (might be due to invalid IL or missing references)
//IL_00e8: Unknown result type (might be due to invalid IL or missing references)
if (_finalized.Contains(index) || (_dyingFinalizeAt.ContainsKey(index) && !silent))
{
return;
}
_dead.Add(index);
InfectionSpitter val = TryGetSpitter(index);
if ((Object)(object)val == (Object)null)
{
ManualLogSource logger = Plugin.Logger;
bool flag = default(bool);
BepInExDebugLogInterpolatedStringHandler val2 = new BepInExDebugLogInterpolatedStringHandler(60, 1, ref flag);
if (flag)
{
((BepInExLogInterpolatedStringHandler)val2).AppendLiteral("[SpitterKill] Spitter ");
((BepInExLogInterpolatedStringHandler)val2).AppendFormatted<ushort>(index);
((BepInExLogInterpolatedStringHandler)val2).AppendLiteral(" not resolvable yet, deferring removal");
}
logger.LogDebug(val2);
return;
}
if (silent)
{
FinalizeSpitter(index, val);
return;
}
float value;
if (val.m_isExploding)
{
_dyingFinalizeAt[index] = float.MaxValue;
_pendingDeathFx.Add(index);
}
else if (_lastPopCompletedAt.TryGetValue(index, out value) && Clock.Time - value <= 1.5f)
{
_dyingFinalizeAt[index] = Clock.Time + 1.5f;
SpitterVisuals.TintPop(index, val, SpitterVisuals.DeathPopColor, recolorLiveParticles: true, untilFinalize: true);
SpitterDeathFx.PlayAt(val.m_position);
HideSpitterModel(index, val);
}
else if (val.m_isGlued)
{
SpitterDeathFx.PlayAt(val.m_position);
HideSpitterModel(index, val);
_dyingFinalizeAt[index] = Clock.Time + 1.5f;
}
else
{
val.DoExplode(((int)val.m_currentState == 2) ? 0.5f : 1f);
_dyingFinalizeAt[index] = float.MaxValue;
_pendingDeathFx.Add(index);
}
_dyingDeadline[index] = Clock.Time + 5f;
}
private static void HideSpitterModel(ushort index, InfectionSpitter spitter)
{
_modelHidden.Add(index);
if ((Object)(object)spitter.m_renderer != (Object)null)
{
spitter.m_renderer.enabled = false;
}
if ((Object)(object)spitter.m_light != (Object)null)
{
((Behaviour)spitter.m_light).enabled = false;
}
if ((Object)(object)spitter.m_damage != (Object)null && (Object)(object)((Component)spitter.m_damage).gameObject != (Object)(object)((Component)spitter).gameObject)
{
((Component)spitter.m_damage).gameObject.SetActive(false);
}
}
private static void ShowSpitterModel(ushort index, InfectionSpitter spitter)
{
_modelHidden.Remove(index);
if ((Object)(object)spitter.m_renderer != (Object)null)
{
spitter.m_renderer.enabled = true;
}
if ((Object)(object)spitter.m_light != (Object)null)
{
((Behaviour)spitter.m_light).enabled = true;
}
if ((Object)(object)spitter.m_damage != (Object)null && (Object)(object)((Component)spitter.m_damage).gameObject != (Object)(object)((Component)spitter).gameObject)
{
((Component)spitter.m_damage).gameObject.SetActive(true);
}
}
private static void FinalizeSpitter(ushort index, InfectionSpitter spitter)
{
//IL_0070: Unknown result type (might be due to invalid IL or missing references)
//IL_00ce: Unknown result type (might be due to invalid IL or missing references)
//IL_00d4: Expected O, but got Unknown
if (_finalized.Add(index))
{
_dyingFinalizeAt.Remove(index);
_dyingDeadline.Remove(index);
_explodingNow.Remove(index);
_lastPopCompletedAt.Remove(index);
_modelHidden.Remove(index);
_healthRel.Remove(index);
SpitterVisuals.RestoreForSpitter(index);
spitter.CleanupSound();
if (_pendingDeathFx.Remove(index))
{
SpitterDeathFx.PlayAt(spitter.m_position);
}
((Behaviour)spitter).enabled = false;
((Component)spitter).gameObject.SetActive(false);
if ((Object)(object)spitter.m_damage != (Object)null && (Object)(object)((Component)spitter.m_damage).gameObject != (Object)(object)((Component)spitter).gameObject)
{
((Component)spitter.m_damage).gameObject.SetActive(false);
}
ManualLogSource logger = Plugin.Logger;
bool flag = default(bool);
BepInExDebugLogInterpolatedStringHandler val = new BepInExDebugLogInterpolatedStringHandler(30, 1, ref flag);
if (flag)
{
((BepInExLogInterpolatedStringHandler)val).AppendLiteral("[SpitterKill] Spitter ");
((BepInExLogInterpolatedStringHandler)val).AppendFormatted<ushort>(index);
((BepInExLogInterpolatedStringHandler)val).AppendLiteral(" removed");
}
logger.LogDebug(val);
}
}
private static void ReviveSpitter(ushort index)
{
//IL_00b2: Unknown result type (might be due to invalid IL or missing references)
//IL_00b8: Expected O, but got Unknown
_dead.Remove(index);
_finalized.Remove(index);
_dyingFinalizeAt.Remove(index);
_dyingDeadline.Remove(index);
_explodingNow.Remove(index);
_lastPopCompletedAt.Remove(index);
_pendingDeathFx.Remove(index);
_healthByIndex.Remove(index);
_healthRel.Remove(index);
_gluedAt.Remove(index);
SpitterVisuals.RestoreForSpitter(index);
InfectionSpitter val = TryGetSpitter(index);
if (!((Object)(object)val == (Object)null))
{
((Component)val).gameObject.SetActive(true);
ShowSpitterModel(index, val);
SpitterVisuals.ResetBodyGlow(val);
ManualLogSource logger = Plugin.Logger;
bool flag = default(bool);
BepInExDebugLogInterpolatedStringHandler val2 = new BepInExDebugLogInterpolatedStringHandler(50, 1, ref flag);
if (flag)
{
((BepInExLogInterpolatedStringHandler)val2).AppendLiteral("[SpitterKill] Spitter ");
((BepInExLogInterpolatedStringHandler)val2).AppendFormatted<ushort>(index);
((BepInExLogInterpolatedStringHandler)val2).AppendLiteral(" revived (checkpoint recall)");
}
logger.LogDebug(val2);
}
}
private static void ReconcileDeadSpitters()
{
if (_broken || _dead.Count == 0)
{
return;
}
try
{
foreach (ushort item in _dead.ToList())
{
if (!_finalized.Contains(item) && !_dyingFinalizeAt.ContainsKey(item))
{
InfectionSpitter val = TryGetSpitter(item);
if ((Object)(object)val != (Object)null)
{
FinalizeSpitter(item, val);
}
}
}
}
catch (Exception ex)
{
Break(ex);
}
}
private static InfectionSpitter? TryGetSpitter(ushort index)
{
List<InfectionSpitter> s_allSpitters = InfectionSpitter.s_allSpitters;
if (s_allSpitters == null || index >= s_allSpitters.Count)
{
return null;
}
return s_allSpitters[(int)index];
}
private static void OnBuildDone()
{
//IL_00ed: Unknown result type (might be due to invalid IL or missing references)
//IL_00f4: Expected O, but got Unknown
//IL_0071: Unknown result type (might be due to invalid IL or missing references)
//IL_0078: Expected O, but got Unknown
if (_broken)
{
return;
}
try
{
UnloadReplicators();
ClearRuntimeState();
if (!APIStatus.Network.Ready)
{
Plugin.Logger.LogError((object)"[SpitterKill] NetworkAPI not ready during OnBuildDone, spitters stay vanilla");
return;
}
bool flag = default(bool);
for (int i = 0; i < 4; i++)
{
SpitterDeathState spitterDeathState = new SpitterDeathState
{
ShardIndex = (byte)i
};
StateReplicator<SpitterDeathState> val = StateReplicator<SpitterDeathState>.Create((uint)(1263751252 + i), spitterDeathState, (LifeTimeType)1, (IStateReplicatorHolder<SpitterDeathState>)null);
if (val == null)
{
ManualLogSource logger = Plugin.Logger;
BepInExErrorLogInterpolatedStringHandler val2 = new BepInExErrorLogInterpolatedStringHandler(48, 1, ref flag);
if (flag)
{
((BepInExLogInterpolatedStringHandler)val2).AppendLiteral("[SpitterKill] Failed to create replicator shard ");
((BepInExLogInterpolatedStringHandler)val2).AppendFormatted<int>(i);
}
logger.LogError(val2);
}
else
{
_currentStates[i] = spitterDeathState;
int shard = i;
Action<SpitterDeathState, SpitterDeathState, bool> action = delegate(SpitterDeathState oldState, SpitterDeathState newState, bool isRecall)
{
OnDeathStateChanged(shard, oldState, newState, isRecall);
};
val.OnStateChanged += action;
_handlers[i] = action;
_replicators[i] = val;
}
}
RegisterDamagePointers();
ManualLogSource logger2 = Plugin.Logger;
BepInExDebugLogInterpolatedStringHandler val3 = new BepInExDebugLogInterpolatedStringHandler(49, 3, ref flag);
if (flag)
{
((BepInExLogInterpolatedStringHandler)val3).AppendLiteral("[SpitterKill] Ready (");
((BepInExLogInterpolatedStringHandler)val3).AppendFormatted<int>(4);
((BepInExLogInterpolatedStringHandler)val3).AppendLiteral(" shards, ");
((BepInExLogInterpolatedStringHandler)val3).AppendLiteral("health=");
((BepInExLogInterpolatedStringHandler)val3).AppendFormatted<float>(Plugin.Config_SpitterHealth);
((BepInExLogInterpolatedStringHandler)val3).AppendLiteral(", IsMaster=");
((BepInExLogInterpolatedStringHandler)val3).AppendFormatted<bool>(SNet.IsMaster);
((BepInExLogInterpolatedStringHandler)val3).AppendLiteral(")");
}
logger2.LogDebug(val3);
}
catch (Exception ex)
{
Break(ex);
}
}
private static void RegisterDamagePointers()
{
//IL_0067: Unknown result type (might be due to invalid IL or missing references)
//IL_006e: Expected O, but got Unknown
List<InfectionSpitter> s_allSpitters = InfectionSpitter.s_allSpitters;
if (s_allSpitters == null || s_allSpitters.Count == 0)
{
return;
}
for (int i = 0; i < s_allSpitters.Count; i++)
{
InfectionSpitter val = s_allSpitters[i];
if (!((Object)(object)val == (Object)null) && !((Object)(object)val.m_damage == (Object)null))
{
_damagePtrToIndex[((Il2CppObjectBase)val.m_damage).Pointer] = val.m_spitterIndex;
}
}
ManualLogSource logger = Plugin.Logger;
bool flag = default(bool);
BepInExDebugLogInterpolatedStringHandler val2 = new BepInExDebugLogInterpolatedStringHandler(51, 1, ref flag);
if (flag)
{
((BepInExLogInterpolatedStringHandler)val2).AppendLiteral("[SpitterKill] Registered ");
((BepInExLogInterpolatedStringHandler)val2).AppendFormatted<int>(_damagePtrToIndex.Count);
((BepInExLogInterpolatedStringHandler)val2).AppendLiteral(" spitter damage pointer(s)");
}
logger.LogDebug(val2);
InfectionSpitter val3 = s_allSpitters[0];
if ((Object)(object)val3 != (Object)null && (Object)(object)val3.m_damage != (Object)null)
{
Fix_SpitterHealthRel.LogSmokeCheck(val3.m_damage);
}
}
private static void OnLevelCleanup()
{
//IL_0017: Unknown result type (might be due to invalid IL or missing references)
//IL_001d: Expected O, but got Unknown
try
{
UnloadReplicators();
ClearRuntimeState();
}
catch (Exception ex)
{
ManualLogSource logger = Plugin.Logger;
bool flag = default(bool);
BepInExErrorLogInterpolatedStringHandler val = new BepInExErrorLogInterpolatedStringHandler(29, 1, ref flag);
if (flag)
{
((BepInExLogInterpolatedStringHandler)val).AppendLiteral("[SpitterKill] Cleanup error: ");
((BepInExLogInterpolatedStringHandler)val).AppendFormatted<Exception>(ex);
}
logger.LogError(val);
}
}
private static void UnloadReplicators()
{
for (int i = 0; i < 4; i++)
{
StateReplicator<SpitterDeathState> val = _replicators[i];
if (val != null)
{
if (_handlers[i] != null)
{
val.OnStateChanged -= _handlers[i];
}
val.Unload();
_replicators[i] = null;
_handlers[i] = null;
}
}
}
private static void ClearRuntimeState()
{
_healthByIndex.Clear();
_healthRel.Clear();
_dead.Clear();
_dyingFinalizeAt.Clear();
_dyingDeadline.Clear();
_finalized.Clear();
_explodingNow.Clear();
_lastPopCompletedAt.Clear();
_pendingDeathFx.Clear();
_modelHidden.Clear();
_gluedAt.Clear();
_damagePtrToIndex.Clear();
_warnedCapacity = false;
SpitterVisuals.RestoreAll();
for (int i = 0; i < 4; i++)
{
_currentStates[i] = new SpitterDeathState
{
ShardIndex = (byte)i
};
}
}
private static void WarnCapacityOnce(ushort index)
{
if (!_warnedCapacity)
{
_warnedCapacity = true;
Plugin.Logger.LogWarning((object)($"[SpitterKill] Spitter index {index} exceeds capacity {7680}; " + "spitters beyond capacity stay vanilla (unkillable)"));
}
}
}
public static class SpitterVisuals
{
private readonly struct OriginalStartColor
{
public readonly ParticleSystem Ps;
public readonly MainModule Main;
public readonly ParticleSystemGradientMode Mode;
public readonly Color ColorMin;
public readonly Color ColorMax;
public readonly Gradient? GradientMin;
public readonly Gradient? GradientMax;
public OriginalStartColor(ParticleSystem ps, MainModule main, MinMaxGradient captured)
{
//IL_0010: Unknown result type (might be due to invalid IL or missing references)
//IL_0015: Unknown result type (might be due to invalid IL or missing references)
//IL_001c: Unknown result type (might be due to invalid IL or missing references)
//IL_0021: Unknown result type (might be due to invalid IL or missing references)
//IL_0028: Unknown result type (might be due to invalid IL or missing references)
//IL_002d: Unknown result type (might be due to invalid IL or missing references)
Ps = ps;
Main = main;
Mode = captured.m_Mode;
ColorMin = captured.m_ColorMin;
ColorMax = captured.m_ColorMax;
GradientMin = captured.m_GradientMin;
GradientMax = captured.m_GradientMax;
}
}
private const float FxRestoreSeconds = 3f;
private const float SteadyGlowScale = 0.6f;
private static readonly Color OrangeGlowBase = new Color(1f, 0.45f, 0f) * 0.5f;
private static readonly Color RedGlowBase = new Color(1f, 0.06f, 0.04f) * 0.5f;
private static readonly Color32 GreenPopColor = new Color32((byte)60, byte.MaxValue, (byte)200, byte.MaxValue);
private static readonly Color32 OrangePopColor = new Color32(byte.MaxValue, (byte)150, (byte)30, byte.MaxValue);
private static readonly Color32 RedPopColor = new Color32(byte.MaxValue, (byte)24, (byte)16, byte.MaxValue);
private static bool _visualsBroken;
private const int GcRaceAttempts = 3;
private static MinMaxGradient? _sharedGradient;
private static readonly Dictionary<int, OriginalStartColor> _tintedSystems = new Dictionary<int, OriginalStartColor>();
private static readonly Dictionary<int, float> _pendingRestores = new Dictionary<int, float>();
private static readonly Dictionary<ushort, List<int>> _tintedBySpitter = new Dictionary<ushort, List<int>>();
public static Color32 DeathPopColor => RedPopColor;
public static Color DeathSteadyGlow => RedGlowBase * 0.6f;
private static Color GetBaseGlow(float healthRel)
{
//IL_002d: Unknown result type (might be due to invalid IL or missing references)
//IL_0032: Unknown result type (might be due to invalid IL or missing references)
//IL_0044: Unknown result type (might be due to invalid IL or missing references)
//IL_0010: Unknown result type (might be due to invalid IL or missing references)
//IL_0015: Unknown result type (might be due to invalid IL or missing references)
//IL_0027: Unknown result type (might be due to invalid IL or missing references)
healthRel = Mathf.Clamp01(healthRel);
if (!(healthRel >= 0.5f))
{
return Color.Lerp(OrangeGlowBase, RedGlowBase, (0.5f - healthRel) * 2f);
}
return Color.Lerp(InfectionSpitter.s_glowColor, OrangeGlowBase, (1f - healthRel) * 2f);
}
public static Color32 GetPopColor(float healthRel)
{
//IL_002d: Unknown result type (might be due to invalid IL or missing references)
//IL_0032: Unknown result type (might be due to invalid IL or missing references)
//IL_0044: Unknown result type (might be due to invalid IL or missing references)
//IL_0010: Unknown result type (might be due to invalid IL or missing references)
//IL_0015: Unknown result type (might be due to invalid IL or missing references)
//IL_0027: Unknown result type (might be due to invalid IL or missing references)
healthRel = Mathf.Clamp01(healthRel);
if (!(healthRel >= 0.5f))
{
return Color32.Lerp(OrangePopColor, RedPopColor, (0.5f - healthRel) * 2f);
}
return Color32.Lerp(GreenPopColor, OrangePopColor, (1f - healthRel) * 2f);
}
public static void ApplyBodyGlow(InfectionSpitter spitter, Color color)
{
//IL_0035: Unknown result type (might be due to invalid IL or missing references)
if (_visualsBroken)
{
return;
}
try
{
if (!((Object)(object)spitter == (Object)null) && spitter.m_propBlock != null && !((Object)(object)spitter.m_renderer == (Object)null))
{
spitter.m_propBlock.SetColor(InfectionSpitter.s_glowColorID, color);
spitter.m_renderer.SetPropertyBlock(spitter.m_propBlock, 0);
}
}
catch (ObjectCollectedException)
{
}
catch (Exception ex2)
{
BreakVisuals(ex2);
}
}
public static void ApplyDamageTint(InfectionSpitter spitter, float healthRel)
{
//IL_0002: Unknown result type (might be due to invalid IL or missing references)
//IL_000c: Unknown result type (might be due to invalid IL or missing references)
ApplyBodyGlow(spitter, GetBaseGlow(healthRel) * 0.6f);
}
public static void ApplyDamageRamp(InfectionSpitter spitter, float healthRel)
{
//IL_000c: Unknown result type (might be due to invalid IL or missing references)
//IL_0017: Unknown result type (might be due to invalid IL or missing references)
if (!((Object)(object)spitter == (Object)null))
{
ApplyBodyGlow(spitter, GetBaseGlow(healthRel) * spitter.m_explodeProgression);
}
}
public static void ApplyDeathRamp(InfectionSpitter spitter)
{
//IL_000b: Unknown result type (might be due to invalid IL or missing references)
//IL_0016: Unknown result type (might be due to invalid IL or missing references)
if (!((Object)(object)spitter == (Object)null))
{
ApplyBodyGlow(spitter, RedGlowBase * spitter.m_explodeProgression);
}
}
public static void ResetBodyGlow(InfectionSpitter spitter)
{
//IL_0001: Unknown result type (might be due to invalid IL or missing references)
ApplyBodyGlow(spitter, InfectionSpitter.s_startGlowColor);
}
public static void TintPop(ushort index, InfectionSpitter spitter, Color32 color, bool recolorLiveParticles, bool untilFinalize)
{
//IL_000f: Unknown result type (might be due to invalid IL or missing references)
if (_visualsBroken)
{
return;
}
for (int i = 1; i <= 3; i++)
{
try
{
TintPopCore(index, spitter, color, recolorLiveParticles, untilFinalize);
return;
}
catch (ObjectCollectedException)
{
}
catch (Exception ex2)
{
BreakVisuals(ex2);
return;
}
}
Plugin.Logger.LogDebug((object)"[SpitterKill] FX tint skipped (IL2CPP GC race persisted)");
}
private static void TintPopCore(ushort index, InfectionSpitter spitter, Color32 color, bool recolorLiveParticles, bool untilFinalize)
{
//IL_0090: Unknown result type (might be due to invalid IL or missing references)
//IL_0091: Unknown result type (might be due to invalid IL or missing references)
//IL_009f: Unknown result type (might be due to invalid IL or missing references)
FX_EffectBase_Poolable val = ((spitter != null) ? spitter.m_fx : null);
if ((Object)(object)val == (Object)null || val.m_inPool)
{
return;
}
Il2CppArrayBase<ParticleSystem> componentsInChildren = ((Component)val).GetComponentsInChildren<ParticleSystem>(true);
if (componentsInChildren == null)
{
return;
}
foreach (ParticleSystem item in componentsInChildren)
{
if ((Object)(object)item == (Object)null)
{
continue;
}
int instanceID = ((Object)item).GetInstanceID();
if (!_tintedSystems.TryGetValue(instanceID, out var value))
{
MainModule main = item.main;
value = new OriginalStartColor(item, main, main.startColor);
_tintedSystems[instanceID] = value;
}
WriteStartColor(value.Main, Color32.op_Implicit(color));
if (recolorLiveParticles)
{
RecolorLiveParticles(item, color);
}
if (untilFinalize)
{
_pendingRestores[instanceID] = float.MaxValue;
if (!_tintedBySpitter.TryGetValue(index, out List<int> value2))
{
value2 = (_tintedBySpitter[index] = new List<int>());
}
if (!value2.Contains(instanceID))
{
value2.Add(instanceID);
}
}
else
{
_pendingRestores[instanceID] = Clock.Time + 3f;
}
}
}
private static void WriteStartColor(MainModule main, Color color)
{
//IL_0002: Unknown result type (might be due to invalid IL or missing references)
//IL_0003: Unknown result type (might be due to invalid IL or missing references)
WriteStartColor(main, (ParticleSystemGradientMode)0, color, color, null, null);
}
private static void WriteStartColor(MainModule main, ParticleSystemGradientMode mode, Color colorMin, Color colorMax, Gradient? gradientMin, Gradient? gradientMax)
{
//IL_001b: Unknown result type (might be due to invalid IL or missing references)
//IL_0032: Unknown result type (might be due to invalid IL or missing references)
//IL_0039: Unknown result type (might be due to invalid IL or missing references)
//IL_0009: Unknown result type (might be due to invalid IL or missing references)
//IL_000e: Unknown result type (might be due to invalid IL or missing references)
//IL_0013: Unknown result type (might be due to invalid IL or missing references)
//IL_0019: Expected O, but got Unknown
object obj = _sharedGradient;
if (obj == null)
{
MinMaxGradient val = new MinMaxGradient(Color.white);
_sharedGradient = val;
obj = (object)val;
}
MinMaxGradient val2 = (MinMaxGradient)obj;
val2.m_Mode = mode;
val2.m_GradientMin = gradientMin;
val2.m_GradientMax = gradientMax;
val2.m_ColorMin = colorMin;
val2.m_ColorMax = colorMax;
main.startColor = val2;
}
private static void RecolorLiveParticles(ParticleSystem ps, Color32 color)
{
//IL_0022: Unknown result type (might be due to invalid IL or missing references)
//IL_0027: Unknown result type (might be due to invalid IL or missing references)
//IL_002b: Unknown result type (might be due to invalid IL or missing references)
//IL_0031: Unknown result type (might be due to invalid IL or missing references)
//IL_0037: Unknown result type (might be due to invalid IL or missing references)
//IL_0042: Unknown result type (might be due to invalid IL or missing references)
//IL_004e: Unknown result type (might be due to invalid IL or missing references)
int particleCount = ps.particleCount;
if (particleCount > 0)
{
Il2CppStructArray<Particle> val = new Il2CppStructArray<Particle>((long)particleCount);
int particles = ps.GetParticles(val);
for (int i = 0; i < particles; i++)
{
Particle val2 = ((Il2CppArrayBase<Particle>)(object)val)[i];
((Particle)(ref val2)).startColor = new Color32(color.r, color.g, color.b, byte.MaxValue);
((Il2CppArrayBase<Particle>)(object)val)[i] = val2;
}
ps.SetParticles(val, particles);
}
}
public static void TickRestores()
{
if (_pendingRestores.Count == 0)
{
return;
}
List<int> list = null;
foreach (var (item, num3) in _pendingRestores)
{
if (num3 != float.MaxValue && Clock.Time >= num3)
{
(list ?? (list = new List<int>())).Add(item);
}
}
if (list == null)
{
return;
}
foreach (int item2 in list)
{
RestoreSystem(item2);
}
}
public static void RestoreForSpitter(ushort index)
{
if (!_tintedBySpitter.TryGetValue(index, out List<int> value))
{
return;
}
foreach (int item in value)
{
RestoreSystem(item);
}
_tintedBySpitter.Remove(index);
}
public static void RestoreAll()
{
foreach (int item in _tintedSystems.Keys.ToList())
{
RestoreSystem(item);
}
_tintedSystems.Clear();
_pendingRestores.Clear();
_tintedBySpitter.Clear();
}
private static void RestoreSystem(int id)
{
//IL_0074: Unknown result type (might be due to invalid IL or missing references)
//IL_007a: Expected O, but got Unknown
//IL_002f: Unknown result type (might be due to invalid IL or missing references)
//IL_0035: Unknown result type (might be due to invalid IL or missing references)
//IL_003b: Unknown result type (might be due to invalid IL or missing references)
if (_tintedSystems.TryGetValue(id, out var value))
{
bool flag = default(bool);
for (int i = 1; i <= 3; i++)
{
try
{
if ((Object)(object)value.Ps != (Object)null)
{
WriteStartColor(value.Main, value.Mode, value.ColorMin, value.ColorMax, value.GradientMin, value.GradientMax);
}
}
catch (ObjectCollectedException)
{
if (i == 3)
{
Plugin.Logger.LogDebug((object)"[SpitterKill] FX tint restore skipped (IL2CPP GC race persisted)");
}
continue;
}
catch (Exception ex2)
{
ManualLogSource logger = Plugin.Logger;
BepInExWarningLogInterpolatedStringHandler val = new BepInExWarningLogInterpolatedStringHandler(41, 1, ref flag);
if (flag)
{
((BepInExLogInterpolatedStringHandler)val).AppendLiteral("[SpitterKill] Failed to restore FX tint: ");
((BepInExLogInterpolatedStringHandler)val).AppendFormatted<string>(ex2.Message);
}
logger.LogWarning(val);
}
break;
}
}
_tintedSystems.Remove(id);
_pendingRestores.Remove(id);
}
private static void BreakVisuals(Exception ex)
{
//IL_0018: Unknown result type (might be due to invalid IL or missing references)
//IL_001e: Expected O, but got Unknown
if (!_visualsBroken)
{
_visualsBroken = true;
ManualLogSource logger = Plugin.Logger;
bool flag = default(bool);
BepInExWarningLogInterpolatedStringHandler val = new BepInExWarningLogInterpolatedStringHandler(96, 1, ref flag);
if (flag)
{
((BepInExLogInterpolatedStringHandler)val).AppendLiteral("[SpitterKill] Damage-state visuals failed, disabling visuals locally (kill feature unaffected): ");
((BepInExLogInterpolatedStringHandler)val).AppendFormatted<Exception>(ex);
}
logger.LogWarning(val);
}
}
}
}
namespace KillableSpitters.Patches.Compat
{
internal static class EWCCompat
{
internal const string PluginGuid = "Dinorush.ExtraWeaponCustomization";
internal static void Init(Harmony harmony)
{
//IL_0032: Unknown result type (might be due to invalid IL or missing references)
//IL_0038: Expected O, but got Unknown
if (!((BaseChainloader<BasePlugin>)(object)IL2CPPChainloader.Instance).Plugins.TryGetValue("Dinorush.ExtraWeaponCustomization", out var value))
{
Plugin.Logger.LogDebug((object)"[EWCCompat] ExtraWeaponCustomization not present, compat patches skipped");
return;
}
ManualLogSource logger = Plugin.Logger;
bool flag = default(bool);
BepInExInfoLogInterpolatedStringHandler val = new BepInExInfoLogInterpolatedStringHandler(71, 1, ref flag);
if (flag)
{
((BepInExLogInterpolatedStringHandler)val).AppendLiteral("[EWCCompat] ExtraWeaponCustomization ");
((BepInExLogInterpolatedStringHandler)val).AppendFormatted<Version>(value.Metadata.Version);
((BepInExLogInterpolatedStringHandler)val).AppendLiteral(" detected, applying compat patches");
}
logger.LogInfo(val);
TryApply(harmony, "explosion", Fix_EWCExplosion.Apply);
TryApply(harmony, "foam", Fix_EWCFoam.Apply);
}
private static void TryApply(Harmony harmony, string name, Action<Harmony> apply)
{
//IL_0011: Unknown result type (might be due to invalid IL or missing references)
//IL_0017: Expected O, but got Unknown
//IL_004a: Unknown result type (might be due to invalid IL or missing references)
//IL_0050: Expected O, but got Unknown
bool flag = default(bool);
try
{
ApplyIsolated(harmony, apply);
ManualLogSource logger = Plugin.Logger;
BepInExDebugLogInterpolatedStringHandler val = new BepInExDebugLogInterpolatedStringHandler(33, 1, ref flag);
if (flag)
{
((BepInExLogInterpolatedStringHandler)val).AppendLiteral("[EWCCompat] ");
((BepInExLogInterpolatedStringHandler)val).AppendFormatted<string>(name);
((BepInExLogInterpolatedStringHandler)val).AppendLiteral(" compat patch applied");
}
logger.LogDebug(val);
}
catch (Exception ex)
{
ManualLogSource logger2 = Plugin.Logger;
BepInExWarningLogInterpolatedStringHandler val2 = new BepInExWarningLogInterpolatedStringHandler(103, 2, ref flag);
if (flag)
{
((BepInExLogInterpolatedStringHandler)val2).AppendLiteral("[EWCCompat] ");
((BepInExLogInterpolatedStringHandler)val2).AppendFormatted<string>(name);
((BepInExLogInterpolatedStringHandler)val2).AppendLiteral(" compat patch failed (EWC version mismatch?), that feature stays ");
((BepInExLogInterpolatedStringHandler)val2).AppendLiteral("EWC-default for spitters: ");
((BepInExLogInterpolatedStringHandler)val2).AppendFormatted<Exception>(ex);
}
logger2.LogWarning(val2);
}
}
[MethodImpl(MethodImplOptions.NoInlining)]
private static void ApplyIsolated(Harmony harmony, Action<Harmony> apply)
{
apply(harmony);
}
}
internal static class Fix_EWCExplosion
{
private static bool _broken;
private static bool _applied;
internal static void Apply(Harmony harmony)
{
//IL_0041: Unknown result type (might be due to invalid IL or missing references)
//IL_004e: Expected O, but got Unknown
if (!_applied)
{
MethodInfo methodInfo = AccessTools.Method(typeof(ExplosionManager), "DoExplosionDamage", (Type[])null, (Type[])null) ?? throw new MissingMethodException("EWC ExplosionManager.DoExplosionDamage not found");
harmony.Patch((MethodBase)methodInfo, (HarmonyMethod)null, new HarmonyMethod(typeof(Fix_EWCExplosion), "Post_DoExplosionDamage", (Type[])null), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null);
_applied = true;
}
}
public static void Post_DoExplosionDamage(Vector3 position, Explosive explosiveBase, float triggerAmt)
{
//IL_0135: Unknown result type (might be due to invalid IL or missing references)
//IL_013c: Expected O, but got Unknown
//IL_0040: Unknown result type (might be due to invalid IL or missing references)
//IL_00b1: Unknown result type (might be due to invalid IL or missing references)
//IL_00b6: Unknown result type (might be due to invalid IL or missing references)
//IL_00ba: Unknown result type (might be due to invalid IL or missing references)
//IL_00bb: Unknown result type (might be due to invalid IL or missing references)
//IL_00c0: Unknown result type (might be due to invalid IL or missing references)
//IL_00c2: Unknown result type (might be due to invalid IL or missing references)
//IL_00c3: Unknown result type (might be due to invalid IL or missing references)
//IL_00d1: Unknown result type (might be due to invalid IL or missing references)
//IL_00d2: Unknown result type (might be due to invalid IL or missing references)
//IL_0102: Unknown result type (might be due to invalid IL or missing references)
//IL_0103: Unknown result type (might be due to invalid IL or missing references)
if (_broken)
{
return;
}
try
{
float radius = explosiveBase.Radius;
if (radius <= 0f)
{
return;
}
float maxDamage = explosiveBase.MaxDamage;
float minDamage = explosiveBase.MinDamage;
if (maxDamage == 0f && minDamage == 0f)
{
return;
}
Il2CppReferenceArray<Collider> val = Physics.OverlapSphere(position, radius, LayerManager.MASK_EXPLOSION_TARGETS);
HashSet<IntPtr> hashSet = null;
for (int i = 0; i < ((Il2CppArrayBase<Collider>)(object)val).Length; i++)
{
Collider val2 = ((Il2CppArrayBase<Collider>)(object)val)[i];
if (!SpitterColliders.TryGetDamage(val2, out InfectionSpitterDamage damage))
{
continue;
}
if (hashSet == null)
{
hashSet = new HashSet<IntPtr>();
}
if (!hashSet.Add(((Il2CppObjectBase)damage).Pointer))
{
continue;
}
InfectionSpitter spitter = damage.m_spitter;
if ((Object)(object)spitter == (Object)null || SpitterKillManager.IsDeadOrDying(spitter.m_spitterIndex))
{
continue;
}
Bounds bounds = val2.bounds;
Vector3 val3 = ((Bounds)(ref bounds)).ClosestPoint(position);
if (!Physics.Linecast(position, val3, LayerManager.MASK_EXPLOSION_BLOCKERS))
{
float num = MapInverted(Vector3.Distance(position, val3), explosiveBase.InnerRadius, radius, maxDamage, minDamage, explosiveBase.Exponent);
num *= triggerAmt;
if (!(num <= 0f))
{
damage.ExplosionDamage(num, position, Vector3.zero, 0u);
}
}
}
}
catch (Exception ex)
{
_broken = true;
ManualLogSource logger = Plugin.Logger;
bool flag = default(bool);
BepInExErrorLogInterpolatedStringHandler val4 = new BepInExErrorLogInterpolatedStringHandler(81, 1, ref flag);
if (flag)
{
((BepInExLogInterpolatedStringHandler)val4).AppendLiteral("[EWCExplosion] Explosion sweep failed, EWC explosions no longer damage spitters: ");
((BepInExLogInterpolatedStringHandler)val4).AppendFormatted<Exception>(ex);
}
logger.LogError(val4);
}
}
private static float MapInverted(float distance, float innerRadius, float radius, float maxDamage, float minDamage, float exponent)
{
if (innerRadius == radius)
{
if (!(distance < innerRadius))
{
return minDamage;
}
return maxDamage;
}
float num = radius - innerRadius;
float num2 = Math.Clamp(distance - innerRadius, 0f, num);
if (exponent != 1f)
{
return (float)Math.Pow((num - num2) / num, exponent) * (maxDamage - minDamage) + minDamage;
}
return (num - num2) / num * (maxDamage - minDamage) + minDamage;
}
}
internal static class Fix_EWCFoam
{
private static class Cache
{
internal static readonly FieldRef<Effect, DamageType> BlacklistType = AccessTools.FieldRefAccess<Effect, DamageType>("_blacklistType");
}
private static bool _broken;
private static bool _applied;
internal static void Apply(Harmony harmony)
{
//IL_006b: Unknown result type (might be due to invalid IL or missing references)
//IL_0079: Expected O, but got Unknown
//IL_008d: Unknown result type (might be due to invalid IL or missing references)
//IL_009a: Expected O, but got Unknown
if (!_applied)
{
MethodInfo methodInfo = AccessTools.Method(typeof(Foam), "TriggerApply", (Type[])null, (Type[])null) ?? throw new MissingMethodException("EWC Foam.TriggerApply not found");
ConstructorInfo constructorInfo = AccessTools.Constructor(typeof(Foam), Type.EmptyTypes, false) ?? throw new MissingMethodException("EWC Foam constructor not found");
_ = Cache.BlacklistType;
harmony.Patch((MethodBase)methodInfo, new HarmonyMethod(typeof(Fix_EWCFoam), "Pre_TriggerApply", (Type[])null), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null);
harmony.Patch((MethodBase)constructorInfo, (HarmonyMethod)null, new HarmonyMethod(typeof(Fix_EWCFoam), "Post_FoamCtor", (Type[])null), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null);
_applied = true;
}
}
public static void Post_FoamCtor(Foam __instance)
{
//IL_008d: Unknown result type (might be due to invalid IL or missing references)
//IL_0094: Expected O, but got Unknown
//IL_0051: Unknown result type (might be due to invalid IL or missing references)
//IL_005b: Unknown result type (might be due to invalid IL or missing references)
if (_broken)
{
return;
}
try
{
ref DamageType reference = ref Cache.BlacklistType.Invoke((Effect)(object)__instance);
reference = (DamageType)((uint)reference & 0xFFFF7FFFu);
TriggerCoordinator trigger = ((Effect)__instance).Trigger;
if (trigger == null)
{
return;
}
foreach (ITrigger trigger2 in ((TriggerHolder)trigger.Activate).Triggers)
{
IDamageTypeTrigger val = (IDamageTypeTrigger)(object)((trigger2 is IDamageTypeTrigger) ? trigger2 : null);
if (val != null)
{
val.BlacklistType = (DamageType)(val.BlacklistType & -32769);
}
}
}
catch (Exception ex)
{
_broken = true;
ManualLogSource logger = Plugin.Logger;
bool flag = default(bool);
BepInExErrorLogInterpolatedStringHandler val2 = new BepInExErrorLogInterpolatedStringHandler(71, 1, ref flag);
if (flag)
{
((BepInExLogInterpolatedStringHandler)val2).AppendLiteral("[EWCFoam] Blacklist relax failed, EWC foam no longer affects spitters: ");
((BepInExLogInterpolatedStringHandler)val2).AppendFormatted<Exception>(ex);
}
logger.LogError(val2);
}
}
public static void Pre_TriggerApply(Foam __instance, List<TriggerContext> triggerList)
{
//IL_00e9: Unknown result type (might be due to invalid IL or missing references)
//IL_00f0: Expected O, but got Unknown
//IL_0017: Unknown result type (might be due to invalid IL or missing references)
//IL_001c: Unknown result type (might be due to invalid IL or missing references)
//IL_001d: Unknown result type (might be due to invalid IL or missing references)
//IL_0030: Unknown result type (might be due to invalid IL or missing references)
//IL_003a: Unknown result type (might be due to invalid IL or missing references)
//IL_0079: Unknown result type (might be due to invalid IL or missing references)
if (_broken)
{
return;
}
try
{
foreach (TriggerContext trigger in triggerList)
{
WeaponTriggerContext context = trigger.context;
WeaponHitDamageableContextBase val = (WeaponHitDamageableContextBase)(object)((context is WeaponHitDamageableContextBase) ? context : null);
if (val == null || (((WeaponDamageTypeContext)val).DamageType & 0x8000) == 0)
{
continue;
}
IDamageable damageable = val.Damageable;
InfectionSpitterDamage val2 = ((damageable != null) ? ((Il2CppObjectBase)damageable).TryCast<InfectionSpitterDamage>() : null);
if ((Object)(object)val2 == (Object)null)
{
continue;
}
InfectionSpitter spitter = val2.m_spitter;
if (!((Object)(object)spitter == (Object)null) && !SpitterKillManager.IsDeadOrDying(spitter.m_spitterIndex))
{
float num = trigger.triggerAmt * (__instance.IgnoreFalloff ? 1f : ((WeaponHitContextBase)val).Falloff);
if (!(Math.Max(__instance.Amount, __instance.BubbleAmount) * num <= 0f))
{
spitter.OnIncomingGlue();
}
}
}
}
catch (Exception ex)
{
_broken = true;
ManualLogSource logger = Plugin.Logger;
bool flag = default(bool);
BepInExErrorLogInterpolatedStringHandler val3 = new BepInExErrorLogInterpolatedStringHandler(74, 1, ref flag);
if (flag)
{
((BepInExLogInterpolatedStringHandler)val3).AppendLiteral("[EWCFoam] Spitter foam apply failed, EWC foam no longer affects spitters: ");
((BepInExLogInterpolatedStringHandler)val3).AppendFormatted<Exception>(ex);
}
logger.LogError(val3);
}
}
}
}
namespace KillableSpitters.Events
{
public struct SpitterDamageEvent
{
public ushort SpitterIndex { get; set; }
public float Damage { get; set; }
}
public struct SpitterHealthEvent
{
public ushort SpitterIndex { get; set; }
public float HealthRel { get; set; }
}
}