using System; using System.Collections; using System.Collections.Generic; using System.Diagnostics; using System.Reflection; using System.Runtime.CompilerServices; using System.Runtime.InteropServices; using System.Runtime.Versioning; using BepInEx; using BepInEx.Configuration; using BepInEx.Logging; using HarmonyLib; using Landfall.TABS; using Landfall.TABS.AI.Components; using Landfall.TABS.GameState; using Microsoft.CodeAnalysis; using TFBGames; using UnityEngine; using UnityEngine.EventSystems; using UnityEngine.Events; using UnityEngine.UI; [assembly: CompilationRelaxations(8)] [assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)] [assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)] [assembly: AssemblyTitle("Stay & Combat Fixes")] [assembly: AssemblyDescription("Stay aura, lay-down combat, water physics, mirror shield, barrel death, gas grenade, and faction creator fixes for TABS")] [assembly: AssemblyConfiguration("")] [assembly: AssemblyCompany("Pretz")] [assembly: AssemblyProduct("StayCombatFix")] [assembly: AssemblyCopyright("Pretz")] [assembly: ComVisible(false)] [assembly: Guid("b2c3d4e5-f6a7-8901-bcde-f12345678901")] [assembly: AssemblyFileVersion("1.1.0.0")] [assembly: TargetFramework(".NETFramework,Version=v4.8", FrameworkDisplayName = ".NET Framework 4.8")] [assembly: AssemblyVersion("1.1.0.0")] [module: RefSafetyRules(11)] namespace Microsoft.CodeAnalysis { [CompilerGenerated] [Microsoft.CodeAnalysis.Embedded] internal sealed class EmbeddedAttribute : Attribute { } } namespace System.Runtime.CompilerServices { [CompilerGenerated] [Microsoft.CodeAnalysis.Embedded] [AttributeUsage(AttributeTargets.Module, AllowMultiple = false, Inherited = false)] internal sealed class RefSafetyRulesAttribute : Attribute { public readonly int Version; public RefSafetyRulesAttribute(int P_0) { Version = P_0; } } } namespace StayCombatFix { internal sealed class BarrelDeathPlan { internal Transform Root; internal float DelaySeconds; internal GameObject[] BarrelVisuals; internal Rigidbody[] BarrelRigidbodies; internal Transform[] BarrelAnchors; internal Vector3 SnapshotPosition; internal bool HasSnapshotPosition; internal Explosion CachedBarrelExplosion; internal GameObject CachedExplosionPrefab; internal Explosion FallbackExplosionTemplate; internal Unit OwnerUnit; } internal static class BarrelRollerDeathLogic { private struct PendingBarrelDeath { internal int RootId; internal BarrelDeathPlan Plan; internal float ExplodeAt; internal Vector3 ExplodePosition; internal bool HasExplodePosition; } [CompilerGenerated] private sealed class d__46 : IEnumerator, IDisposable, IEnumerator { private int <>1__state; private object <>2__current; object IEnumerator.Current { [DebuggerHidden] get { return <>2__current; } } object IEnumerator.Current { [DebuggerHidden] get { return <>2__current; } } [DebuggerHidden] public d__46(int <>1__state) { this.<>1__state = <>1__state; } [DebuggerHidden] void IDisposable.Dispose() { <>1__state = -2; } private bool MoveNext() { //IL_00b7: Unknown result type (might be due to invalid IL or missing references) switch (<>1__state) { default: return false; case 0: <>1__state = -1; break; case 1: <>1__state = -1; break; } if (PendingDeaths.Count > 0) { float time = Time.time; int num = 0; int num2 = PendingDeaths.Count - 1; while (num2 >= 0 && num < 8) { PendingBarrelDeath pendingBarrelDeath = PendingDeaths[num2]; if (!(time < pendingBarrelDeath.ExplodeAt)) { if ((Object)(object)pendingBarrelDeath.Plan?.Root == (Object)null) { PendingDeaths.RemoveAt(num2); PendingDeathRootIds.Remove(pendingBarrelDeath.RootId); } else { PendingDeaths.RemoveAt(num2); PendingDeathRootIds.Remove(pendingBarrelDeath.RootId); ExecuteDeathExplosion(pendingBarrelDeath.RootId, pendingBarrelDeath.Plan, pendingBarrelDeath.ExplodePosition, pendingBarrelDeath.HasExplodePosition); num++; } } num2--; } <>2__current = null; <>1__state = 1; return true; } _queueRunner = null; return false; } bool IEnumerator.MoveNext() { //ILSpy generated this explicit interface implementation from .override directive in MoveNext return this.MoveNext(); } [DebuggerHidden] void IEnumerator.Reset() { throw new NotSupportedException(); } } internal const int BarrelRollerUnitId = 846602731; private const float MinimumDelaySeconds = 0.45f; private const float MaxBarrelDistanceFromUnit = 80f; private static MonoBehaviour _runner; private static ManualLogSource _log; private static readonly Dictionary RecentBarrelExplosionTimeByRoot = new Dictionary(); private static readonly Dictionary AllowedBarrelExplosionTimeByRoot = new Dictionary(); private static readonly Dictionary ActiveBarrelRollerRoots = new Dictionary(); private static readonly HashSet KnownBarrelRollerRootIds = new HashSet(); private static readonly HashSet NotBarrelRollerRootIds = new HashSet(); private static readonly List PendingDeaths = new List(32); private static readonly HashSet PendingDeathRootIds = new HashSet(); private const float RecentBarrelExplosionWindowSeconds = 2.5f; private const float DuplicateAbilityExplosionWindowSeconds = 0.75f; private const float AbilityDeathSkipExplosionAgeSeconds = 0.5f; private const float AbilityExplosionOwnerSearchRadius = 20f; private const float DeathExplosionDamage = 15f; private const int MaxExplosionsPerFrame = 8; private static GameObject _sharedBarrelDeathExplosionPrefab; private static Explosion _sharedBarrelDeathExplosionTemplate; private static Coroutine _queueRunner; private static bool _executingDeathExplosion; internal static void Initialize(MonoBehaviour runner, ManualLogSource log) { _runner = runner; _log = log; } internal static void ResetBattleCaches() { RecentBarrelExplosionTimeByRoot.Clear(); AllowedBarrelExplosionTimeByRoot.Clear(); ActiveBarrelRollerRoots.Clear(); KnownBarrelRollerRootIds.Clear(); NotBarrelRollerRootIds.Clear(); PendingDeaths.Clear(); PendingDeathRootIds.Clear(); _executingDeathExplosion = false; _queueRunner = null; } private static void EvictRootCache(int rootId) { KnownBarrelRollerRootIds.Remove(rootId); NotBarrelRollerRootIds.Remove(rootId); ActiveBarrelRollerRoots.Remove(rootId); RecentBarrelExplosionTimeByRoot.Remove(rootId); AllowedBarrelExplosionTimeByRoot.Remove(rootId); PendingDeathRootIds.Remove(rootId); for (int num = PendingDeaths.Count - 1; num >= 0; num--) { if (PendingDeaths[num].RootId == rootId) { PendingDeaths.RemoveAt(num); } } } private static bool IsCachedBarrelRollerRoot(Transform root, int rootId) { if (!KnownBarrelRollerRootIds.Contains(rootId)) { return false; } if (!ActiveBarrelRollerRoots.TryGetValue(rootId, out var value) || (Object)(object)value == (Object)null) { EvictRootCache(rootId); return false; } if ((Object)(object)value != (Object)(object)root) { EvictRootCache(rootId); return false; } RememberBarrelRollerRoot(root); return true; } internal static void MarkRecentBarrelExplosion(Transform ownerRoot) { if (!((Object)(object)ownerRoot == (Object)null)) { RecentBarrelExplosionTimeByRoot[((Object)ownerRoot).GetInstanceID()] = Time.time; CancelPendingDeathExplosion(ownerRoot); } } internal static void PrepareBarrelOwnedExplosionForDetonation(Explosion explosion) { if (!((Object)(object)explosion == (Object)null) && MightBeBarrelRollerExplosion(explosion)) { Transform val = ResolveBarrelRollerOwnerRoot(((Component)explosion).transform); if (!((Object)(object)val == (Object)null) && IsBarrelRollerOwnedExplosion(explosion, val)) { StripDeathExplosionStatusEffects(((Component)((Component)explosion).transform.root).gameObject); } } } internal static bool TryBlockDuplicateBarrelExplosion(Explosion explosion) { if ((Object)(object)explosion == (Object)null || _executingDeathExplosion || !MightBeBarrelRollerExplosion(explosion)) { return false; } Transform val = ResolveBarrelRollerOwnerRoot(((Component)explosion).transform); if ((Object)(object)val == (Object)null || !IsBarrelRollerOwnedExplosion(explosion, val)) { return false; } int instanceID = ((Object)val).GetInstanceID(); float time = Time.time; if (AllowedBarrelExplosionTimeByRoot.TryGetValue(instanceID, out var value) && time - value <= 0.75f) { return true; } AllowedBarrelExplosionTimeByRoot[instanceID] = time; MarkRecentBarrelExplosion(val); return false; } private static bool MightBeBarrelRollerExplosion(Explosion explosion) { if ((Object)(object)explosion == (Object)null) { return false; } Transform transform = ((Component)explosion).transform; if ((Object)(object)transform == (Object)null) { return false; } if (IsRollingBarrelGearTransform(transform)) { return true; } if (ContainsBarrelExplosionName(((Object)((Component)transform).gameObject).name) || ContainsBarrelExplosionName(((Object)transform.root).name)) { return true; } int instanceID = ((Object)transform.root).GetInstanceID(); return KnownBarrelRollerRootIds.Contains(instanceID); } internal static void NotifyBarrelAbilityExplosionFromSpawn(Transform scope, GameObject prefab) { if (!((Object)(object)scope == (Object)null) && !((Object)(object)prefab == (Object)null) && !_executingDeathExplosion && ContainsBarrelExplosionName(((Object)prefab).name)) { Transform root = scope.root; if (IsBarrelRollerRoot(root)) { MarkRecentBarrelExplosion(root); } } } private static void CancelPendingDeathExplosion(Transform ownerRoot) { if ((Object)(object)ownerRoot == (Object)null) { return; } int instanceID = ((Object)ownerRoot).GetInstanceID(); PendingDeathRootIds.Remove(instanceID); for (int num = PendingDeaths.Count - 1; num >= 0; num--) { if (PendingDeaths[num].RootId == instanceID) { PendingDeaths.RemoveAt(num); } } } private static Transform ResolveBarrelRollerOwnerRoot(Transform explosionTransform) { //IL_0070: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)explosionTransform == (Object)null) { return null; } TeamHolder val = ((Component)explosionTransform).GetComponent() ?? ((Component)explosionTransform).GetComponentInParent(); if ((Object)(object)val?.spawner != (Object)null) { Transform root = val.spawner.transform.root; if (IsBarrelRollerRoot(root)) { return root; } } if (ContainsBarrelExplosionName(((Object)((Component)explosionTransform).gameObject).name) || ContainsBarrelExplosionName(((Object)explosionTransform.root).name)) { Transform val2 = FindBarrelRollerRootNear(explosionTransform.position); if ((Object)(object)val2 != (Object)null) { return val2; } } Transform root2 = explosionTransform.root; if (IsSpawnedBarrelExplosionPrefabRoot(root2)) { return null; } if (IsBarrelRollerRoot(root2)) { return root2; } return null; } private static bool IsSpawnedBarrelExplosionPrefabRoot(Transform root) { if ((Object)(object)root == (Object)null) { return false; } if ((Object)(object)((Component)root).GetComponentInChildren(true) != (Object)null) { return false; } return ContainsBarrelExplosionName(((Object)root).name); } private static Transform FindBarrelRollerRootNear(Vector3 position) { //IL_003b: 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) //IL_0041: Unknown result type (might be due to invalid IL or missing references) //IL_0046: Unknown result type (might be due to invalid IL or missing references) Transform result = null; float num = 400f; foreach (KeyValuePair activeBarrelRollerRoot in ActiveBarrelRollerRoots) { Transform value = activeBarrelRollerRoot.Value; if (!((Object)(object)value == (Object)null) && !IsSpawnedBarrelExplosionPrefabRoot(value)) { Vector3 val = value.position - position; float sqrMagnitude = ((Vector3)(ref val)).sqrMagnitude; if (!(sqrMagnitude > num)) { num = sqrMagnitude; result = value; } } } return result; } private static void RememberBarrelRollerRoot(Transform root) { if (!((Object)(object)root == (Object)null)) { ActiveBarrelRollerRoots[((Object)root).GetInstanceID()] = root; } } private static bool IsBarrelRollerOwnedExplosion(Explosion explosion, Transform ownerRoot) { if ((Object)(object)explosion == (Object)null || (Object)(object)ownerRoot == (Object)null) { return false; } if (ContainsBarrelExplosionName(((Object)((Component)explosion).gameObject).name) || ContainsBarrelExplosionName(((Object)((Component)explosion).transform.root).name)) { return true; } if (!BelongsToRoot(((Component)explosion).transform, ownerRoot)) { return false; } if (IsRollingBarrelGearTransform(((Component)explosion).transform)) { return true; } return IsUnderBarrelRollerAbilityMount(((Component)explosion).transform, ownerRoot); } private static bool ContainsBarrelExplosionName(string objectName) { if (string.IsNullOrEmpty(objectName)) { return false; } if (objectName.IndexOf("ExplosionBombBarrel", StringComparison.OrdinalIgnoreCase) >= 0) { return true; } if (objectName.IndexOf("BarrelE_Explosion", StringComparison.OrdinalIgnoreCase) >= 0) { return true; } if (objectName.IndexOf("Barrel", StringComparison.OrdinalIgnoreCase) >= 0) { return objectName.IndexOf("Explosion", StringComparison.OrdinalIgnoreCase) >= 0; } return false; } internal static bool IsBarrelRollerRoot(Transform root) { if ((Object)(object)root == (Object)null) { return false; } if (IsSpawnedBarrelExplosionPrefabRoot(root)) { return false; } int instanceID = ((Object)root).GetInstanceID(); if (IsCachedBarrelRollerRoot(root, instanceID)) { return true; } if (NotBarrelRollerRootIds.Contains(instanceID)) { return false; } Unit component = ((Component)root).GetComponent(); if (!IsBarrelAbilityUnit(root, component)) { NotBarrelRollerRootIds.Add(instanceID); return false; } KnownBarrelRollerRootIds.Add(instanceID); RememberBarrelRollerRoot(root); return true; } private static bool ShouldSkipDeathForAbilityKill(Transform root) { if ((Object)(object)root == (Object)null || !IsBarrelRollerRoot(root)) { return false; } if (TryGetRecentBarrelExplosionAge(root, out var ageSeconds)) { return ageSeconds <= 0.5f; } return false; } private static bool TryGetRecentBarrelExplosionAge(Transform root, out float ageSeconds) { ageSeconds = float.MaxValue; if ((Object)(object)root == (Object)null) { return false; } if (!RecentBarrelExplosionTimeByRoot.TryGetValue(((Object)root).GetInstanceID(), out var value)) { return false; } ageSeconds = Time.time - value; return ageSeconds <= 2.5f; } internal static bool ShouldSuppressDeathExplosion(Transform root) { if ((Object)(object)root == (Object)null || !IsBarrelRollerRoot(root)) { return false; } return HasRecentBarrelExplosion(root); } internal static void EnsureScheduledFromDead(DataHandler data) { if (!((Object)(object)data == (Object)null) && data.Dead) { TryScheduleFromScope(((Component)data).transform, "DataHandler.Dead"); } } private static void TryScheduleFromScope(Transform scope, string source) { if ((Object)(object)scope == (Object)null) { return; } Transform root = scope.root; if (!IsBarrelRollerRoot(root)) { return; } if (!TryBuildPlan(root, out var plan)) { ManualLogSource log = _log; if (log != null) { log.LogWarning((object)("Barrel death plan failed (" + source + ") on " + ((Object)root).name)); } } else { TrySchedule(plan, source); } } private static void TrySchedule(BarrelDeathPlan plan, string source) { //IL_00c5: Unknown result type (might be due to invalid IL or missing references) //IL_00c6: Unknown result type (might be due to invalid IL or missing references) //IL_007e: 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_0090: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)plan?.Root == (Object)null || (Object)(object)_runner == (Object)null) { ManualLogSource log = _log; if (log != null) { log.LogWarning((object)("Barrel death skip schedule (" + source + "): runner or root missing")); } return; } int instanceID = ((Object)plan.Root).GetInstanceID(); if (!ShouldSkipDeathForAbilityKill(plan.Root) && PendingDeathRootIds.Add(instanceID)) { Vector3 position; bool flag = TryResolveExplosionPosition(plan, out position); if (!flag && plan.HasSnapshotPosition && IsFinite(plan.SnapshotPosition)) { position = plan.SnapshotPosition; flag = true; } PendingDeaths.Add(new PendingBarrelDeath { RootId = instanceID, Plan = plan, ExplodeAt = Time.time + plan.DelaySeconds, ExplodePosition = position, HasExplodePosition = flag }); if (_queueRunner == null) { _queueRunner = _runner.StartCoroutine(ProcessDeathQueue()); } } } [IteratorStateMachine(typeof(d__46))] private static IEnumerator ProcessDeathQueue() { //yield-return decompiler failed: Unexpected instruction in Iterator.Dispose() return new d__46(0); } private static void ExecuteDeathExplosion(int rootId, BarrelDeathPlan plan, Vector3 scheduledPosition, bool hasScheduledPosition) { //IL_0026: 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) Transform val = plan?.Root; if ((Object)(object)val != (Object)null && ShouldSuppressDeathExplosion(val)) { CancelPendingDeathExplosion(val); return; } if (!TryResolveDeathExplosionPosition(plan, scheduledPosition, hasScheduledPosition, out var position)) { ManualLogSource log = _log; if (log != null) { log.LogWarning((object)$"Barrel death execute failed: no position (rootId={rootId})"); } return; } HideBarrelGear(plan); RefreshOwnerUnit(plan); _executingDeathExplosion = true; try { TriggerSingleBarrelExplosion(plan, position); } catch (Exception ex) { ManualLogSource log2 = _log; if (log2 != null) { log2.LogError((object)$"Barrel death execute failed (rootId={rootId}): {ex.Message}"); } } finally { _executingDeathExplosion = false; } } private static bool TryResolveDeathExplosionPosition(BarrelDeathPlan plan, Vector3 scheduledPosition, bool hasScheduledPosition, out Vector3 position) { //IL_0001: 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_0042: 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_0032: 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) position = default(Vector3); if (plan == null) { return false; } if ((Object)(object)plan.Root != (Object)null && TryResolveExplosionPosition(plan, out position)) { return true; } if (hasScheduledPosition && IsFinite(scheduledPosition)) { position = scheduledPosition; return true; } if (plan.HasSnapshotPosition && IsFinite(plan.SnapshotPosition)) { position = plan.SnapshotPosition; return true; } return false; } private static bool TryBuildPlan(Transform root, out BarrelDeathPlan plan) { //IL_00fb: Unknown result type (might be due to invalid IL or missing references) //IL_00fd: Unknown result type (might be due to invalid IL or missing references) plan = null; if ((Object)(object)root == (Object)null || !IsBarrelRollerRoot(root)) { return false; } float delayFromConditionalEvents = GetDelayFromConditionalEvents(((Component)root).GetComponentsInChildren(true)); Holdable[] componentsInChildren = ((Component)root).GetComponentsInChildren(true); CollectBarrelHoldableData(root, componentsInChildren, out var barrelRigidbodies, out var barrelAnchors, out var barrelVisuals); PickExplosionAssets(((Component)root).GetComponentsInChildren(true), out var cachedExplosion, out var fallbackTemplate); GameObject val = FindExplosionPrefab(root); if ((Object)(object)val == (Object)null && (Object)(object)cachedExplosion != (Object)null) { val = FindExplosionPrefabFromTemplate(cachedExplosion); } if ((Object)(object)val != (Object)null) { RememberSharedDeathExplosionAssets(val, cachedExplosion ?? fallbackTemplate); } else if ((Object)(object)_sharedBarrelDeathExplosionPrefab != (Object)null) { val = _sharedBarrelDeathExplosionPrefab; } if ((Object)(object)cachedExplosion == (Object)null && (Object)(object)fallbackTemplate == (Object)null && (Object)(object)_sharedBarrelDeathExplosionTemplate != (Object)null) { fallbackTemplate = _sharedBarrelDeathExplosionTemplate; } Vector3 position; bool hasSnapshotPosition = TryCaptureBarrelSnapshot(barrelRigidbodies, barrelAnchors, root, out position); plan = new BarrelDeathPlan { Root = root, DelaySeconds = delayFromConditionalEvents, BarrelVisuals = barrelVisuals, BarrelRigidbodies = barrelRigidbodies, BarrelAnchors = barrelAnchors, SnapshotPosition = position, HasSnapshotPosition = hasSnapshotPosition, CachedBarrelExplosion = cachedExplosion, CachedExplosionPrefab = val, FallbackExplosionTemplate = (cachedExplosion ?? fallbackTemplate), OwnerUnit = ((Component)root).GetComponent() }; return true; } private static float GetDelayFromConditionalEvents(ConditionalEvent[] conditionalEvents) { float num = 0.45f; if (conditionalEvents == null) { return num; } for (int i = 0; i < conditionalEvents.Length; i++) { ConditionalEventInstance[] array = conditionalEvents[i]?.events; if (array == null) { continue; } foreach (ConditionalEventInstance val in array) { if (HasUnitDeathCondition(val)) { float delay = val.delay; if (delay > num) { num = delay; } } } } return num; } private static void CollectBarrelHoldableData(Transform root, Holdable[] holdables, out Rigidbody[] barrelRigidbodies, out Transform[] barrelAnchors, out GameObject[] barrelVisuals) { List list = new List(); List list2 = new List(); List list3 = new List(); HashSet hashSet = new HashSet(); HashSet hashSet2 = new HashSet(); HashSet hashSet3 = new HashSet(); if (holdables != null) { foreach (Holdable holdable in holdables) { if (IsBarrelHoldable(holdable)) { AddBarrelHoldable(holdable, list, list2, list3, hashSet, hashSet2, hashSet3); } } } Transform[] componentsInChildren = ((Component)root).GetComponentsInChildren(true); foreach (Transform val in componentsInChildren) { if (((Object)val).name.IndexOf("BarrelArmor", StringComparison.OrdinalIgnoreCase) >= 0) { if (hashSet2.Add(((Object)val).GetInstanceID())) { list2.Add(val); } if (hashSet3.Add(((Object)((Component)val).gameObject).GetInstanceID())) { list3.Add(((Component)val).gameObject); } Rigidbody componentInChildren = ((Component)val).GetComponentInChildren(); if ((Object)(object)componentInChildren != (Object)null && hashSet.Add(((Object)componentInChildren).GetInstanceID())) { list.Add(componentInChildren); } } } barrelRigidbodies = list.ToArray(); barrelAnchors = list2.ToArray(); barrelVisuals = list3.ToArray(); } private static void AddBarrelHoldable(Holdable holdable, List rigidbodies, List anchors, List visuals, HashSet seenBodies, HashSet seenAnchors, HashSet seenVisuals) { Transform val = (((Object)(object)holdable.rig != (Object)null) ? ((Component)holdable.rig).transform : ((Component)holdable).transform); if ((Object)(object)val != (Object)null && seenAnchors.Add(((Object)val).GetInstanceID())) { anchors.Add(val); } Rigidbody val2 = holdable.rig ?? ((Component)holdable).GetComponentInChildren(); if ((Object)(object)val2 != (Object)null && seenBodies.Add(((Object)val2).GetInstanceID())) { rigidbodies.Add(val2); } if (seenVisuals.Add(((Object)((Component)holdable).gameObject).GetInstanceID())) { visuals.Add(((Component)holdable).gameObject); } } private static void PickExplosionAssets(Explosion[] explosions, out Explosion cachedExplosion, out Explosion fallbackTemplate) { cachedExplosion = null; fallbackTemplate = null; float num = float.MinValue; if (explosions == null) { return; } foreach (Explosion val in explosions) { if ((Object)(object)val == (Object)null) { continue; } if (fallbackTemplate == null) { fallbackTemplate = val; } if (IsBarrelDeathExplosionSource(((Component)val).transform, ((Component)val).transform.root)) { float num2 = ScoreBarrelExplosion(val); if (!(num2 <= num)) { num = num2; cachedExplosion = val; } } } } private static GameObject FindExplosionPrefab(Transform root) { GameObject preferred = null; GameObject val = null; GameObject any = null; RemoveAfterSeconds[] componentsInChildren = ((Component)root).GetComponentsInChildren(true); foreach (RemoveAfterSeconds val2 in componentsInChildren) { GameObject val3 = val2?.objectToSpawn; if ((Object)(object)val3 == (Object)null) { continue; } if (any == null) { any = val3; } if (val2.spawnObjectOnMainRig) { if (val == null) { val = val3; } } else { preferred = val3; } } if ((Object)(object)preferred != (Object)null) { return preferred; } KillAfterSeconds[] componentsInChildren2 = ((Component)root).GetComponentsInChildren(true); foreach (KillAfterSeconds val4 in componentsInChildren2) { GameObject val5 = val4?.objectToSpawn; if (!((Object)(object)val5 == (Object)null)) { if (any == null) { any = val5; } if (!val4.spawnObjectOnMainRig) { return val5; } if (val == null) { val = val5; } } } CollectSpawnPrefabs(root, ref preferred, ref any); return preferred ?? val ?? any; } private static void CollectSpawnPrefabs(Transform root, ref GameObject preferred, ref GameObject any) { SpawnObject[] componentsInChildren = ((Component)root).GetComponentsInChildren(true); foreach (SpawnObject val in componentsInChildren) { GameObject objectToSpawn = val.objectToSpawn; if (!((Object)(object)objectToSpawn == (Object)null)) { if (any == null) { any = objectToSpawn; } if (IsRollingBarrelGearTransform(((Component)val).transform)) { preferred = objectToSpawn; } } } CollisionEvent[] componentsInChildren2 = ((Component)root).GetComponentsInChildren(true); foreach (CollisionEvent val2 in componentsInChildren2) { GameObject objectToSpawn2 = val2.objectToSpawn; if (!((Object)(object)objectToSpawn2 == (Object)null)) { if (any == null) { any = objectToSpawn2; } if (IsRollingBarrelGearTransform(((Component)val2).transform)) { preferred = objectToSpawn2; } } } } internal static bool IsBarrelDeathDelayEvent(Component component) { if ((Object)(object)component == (Object)null) { return false; } ConditionalEvent componentInParent = component.GetComponentInParent(); if (componentInParent?.events == null) { return IsRollingBarrelGearTransform(component.transform); } for (int i = 0; i < componentInParent.events.Length; i++) { if (HasUnitDeathCondition(componentInParent.events[i])) { return true; } } return false; } private static GameObject FindExplosionPrefabFromTemplate(Explosion template) { if ((Object)(object)template == (Object)null) { return null; } Transform val = ((Component)template).transform; while ((Object)(object)val != (Object)null) { RemoveAfterSeconds component = ((Component)val).GetComponent(); if ((Object)(object)component?.objectToSpawn != (Object)null) { return component.objectToSpawn; } val = val.parent; } return null; } private static bool IsBarrelAbilityMountTransform(Transform transform) { if ((Object)(object)transform == (Object)null) { return false; } string name = ((Object)transform).name; if (name.IndexOf("Wings_Leg_Barrel", StringComparison.OrdinalIgnoreCase) >= 0) { return true; } if (name.IndexOf("Leg_Barrel", StringComparison.OrdinalIgnoreCase) >= 0) { return true; } return name.IndexOf("BarrelRoller", StringComparison.OrdinalIgnoreCase) >= 0; } private static bool IsBarrelRollerAbilityTransform(Transform transform) { return IsBarrelAbilityMountTransform(transform); } private static bool IsUnderBarrelAbilityMount(Transform transform, Transform ownerRoot) { Transform val = transform; while ((Object)(object)val != (Object)null && (!((Object)(object)ownerRoot != (Object)null) || !((Object)(object)val == (Object)(object)ownerRoot))) { if (IsBarrelAbilityMountTransform(val)) { return true; } val = val.parent; } return false; } private static bool IsUnderBarrelRollerAbilityMount(Transform transform, Transform ownerRoot) { return IsUnderBarrelAbilityMount(transform, ownerRoot); } private static bool IsBarrelAbilityUnit(Transform root, Unit unit) { if (MatchesBarrelRollerBlueprint(unit)) { return true; } return HasBarrelAbilityGear(root); } private static bool HasBarrelAbilityGear(Transform root) { if ((Object)(object)root == (Object)null) { return false; } Transform[] componentsInChildren = ((Component)root).GetComponentsInChildren(true); for (int i = 0; i < componentsInChildren.Length; i++) { if (IsBarrelAbilityMountTransform(componentsInChildren[i])) { return true; } } Holdable[] componentsInChildren2 = ((Component)root).GetComponentsInChildren(true); for (int i = 0; i < componentsInChildren2.Length; i++) { if (IsBarrelHoldable(componentsInChildren2[i])) { return true; } } Explosion[] componentsInChildren3 = ((Component)root).GetComponentsInChildren(true); for (int i = 0; i < componentsInChildren3.Length; i++) { if (IsBarrelDeathExplosionSource(((Component)componentsInChildren3[i]).transform, root)) { return true; } } DelayEvent[] componentsInChildren4 = ((Component)root).GetComponentsInChildren(true); for (int i = 0; i < componentsInChildren4.Length; i++) { if (IsBarrelDeathDelayEvent((Component)(object)componentsInChildren4[i])) { return true; } } return false; } private static bool IsBarrelDeathExplosionSource(Transform transform, Transform root) { if ((Object)(object)transform == (Object)null) { return false; } if (ContainsBarrelExplosionName(((Object)((Component)transform).gameObject).name)) { return true; } if (IsRollingBarrelGearTransform(transform)) { return true; } return IsUnderBarrelAbilityMount(transform, root); } private static bool MatchesBarrelRollerBlueprint(Unit unit) { //IL_0027: Unknown result type (might be due to invalid IL or missing references) object obj; if (unit == null) { obj = null; } else { UnitBlueprint unitBlueprint = unit.unitBlueprint; obj = ((unitBlueprint != null) ? unitBlueprint.Entity : null); } if (obj == null) { return false; } if (unit.unitBlueprint.Entity.GUID.m_ID == 846602731) { return true; } string name = unit.unitBlueprint.Entity.Name; if (string.IsNullOrEmpty(name)) { return false; } if (name.IndexOf("BOXER", StringComparison.OrdinalIgnoreCase) >= 0) { return false; } if (name.IndexOf("BARRELROLLER", StringComparison.OrdinalIgnoreCase) >= 0) { return true; } if (name.IndexOf("Barrel", StringComparison.OrdinalIgnoreCase) >= 0) { return name.IndexOf("Roller", StringComparison.OrdinalIgnoreCase) >= 0; } return false; } private static bool HasUnitDeathCondition(ConditionalEventInstance instance) { //IL_0020: Unknown result type (might be due to invalid IL or missing references) //IL_0026: Invalid comparison between Unknown and I4 EventCondition[] array = instance?.conditions; if (array == null) { return false; } foreach (EventCondition obj in array) { if (obj != null && (int)obj.conditionType == 5) { return true; } } return false; } private static bool TryResolveExplosionPosition(BarrelDeathPlan plan, out Vector3 position) { //IL_0001: Unknown result type (might be due to invalid IL or missing references) //IL_006e: Unknown result type (might be due to invalid IL or missing references) //IL_007c: Unknown result type (might be due to invalid IL or missing references) //IL_0081: Unknown result type (might be due to invalid IL or missing references) //IL_00df: Unknown result type (might be due to invalid IL or missing references) //IL_00b4: Unknown result type (might be due to invalid IL or missing references) //IL_00f2: Unknown result type (might be due to invalid IL or missing references) //IL_00f7: Unknown result type (might be due to invalid IL or missing references) //IL_00c7: Unknown result type (might be due to invalid IL or missing references) //IL_00cc: Unknown result type (might be due to invalid IL or missing references) position = default(Vector3); if ((Object)(object)plan?.Root == (Object)null) { return false; } if (TryGetTrackedRigidbodyPosition(plan.BarrelRigidbodies, plan.Root, out position)) { return true; } if (TryGetLiveScanPosition(plan.Root, plan.BarrelVisuals, out position)) { return true; } if (TryGetAnchorPosition(plan.BarrelAnchors, plan.Root, out position)) { return true; } if (plan.HasSnapshotPosition && IsUsableExplosionPosition(plan.Root, plan.SnapshotPosition)) { position = plan.SnapshotPosition; return true; } DataHandler componentInChildren = ((Component)plan.Root).GetComponentInChildren(); if ((Object)(object)componentInChildren?.mainRig != (Object)null && IsUsableExplosionPosition(plan.Root, componentInChildren.mainRig.position)) { position = componentInChildren.mainRig.position; return true; } if (IsUsableExplosionPosition(plan.Root, plan.Root.position)) { position = plan.Root.position; return true; } return false; } private static bool TryCaptureBarrelSnapshot(Rigidbody[] barrelRigidbodies, Transform[] barrelAnchors, Transform root, out Vector3 position) { if (TryGetTrackedRigidbodyPosition(barrelRigidbodies, root, out position)) { return true; } return TryGetAnchorPosition(barrelAnchors, root, out position); } private static bool TryGetAnchorPosition(Transform[] anchors, Transform root, out Vector3 position) { //IL_0001: 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_001f: Unknown result type (might be due to invalid IL or missing references) //IL_0024: 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) position = default(Vector3); if (anchors == null) { return false; } foreach (Transform val in anchors) { if (!((Object)(object)val == (Object)null)) { position = GetTransformCenter(val); if (IsUsableExplosionPosition(root, position)) { return true; } } } position = default(Vector3); return false; } private static bool TryGetTrackedRigidbodyPosition(Rigidbody[] trackedRigidbodies, Transform root, out Vector3 position) { //IL_0001: 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_0057: Unknown result type (might be due to invalid IL or missing references) position = default(Vector3); Rigidbody val = null; float num = float.MinValue; if (trackedRigidbodies != null) { foreach (Rigidbody val2 in trackedRigidbodies) { if (IsAliveRigidbody(val2)) { float num2 = ScoreBarrelRigidbody(val2); if (num2 > num) { num = num2; val = val2; } } } } if ((Object)(object)val == (Object)null) { return false; } position = val.worldCenterOfMass; return IsUsableExplosionPosition(root, position); } private static bool TryGetLiveScanPosition(Transform root, GameObject[] barrelVisuals, out Vector3 position) { //IL_0001: Unknown result type (might be due to invalid IL or missing references) //IL_001a: 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_0026: Unknown result type (might be due to invalid IL or missing references) //IL_00c8: Unknown result type (might be due to invalid IL or missing references) //IL_00cd: Unknown result type (might be due to invalid IL or missing references) //IL_00d4: Unknown result type (might be due to invalid IL or missing references) //IL_013e: 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) //IL_007e: Unknown result type (might be due to invalid IL or missing references) //IL_0085: Unknown result type (might be due to invalid IL or missing references) //IL_0116: Unknown result type (might be due to invalid IL or missing references) //IL_011b: Unknown result type (might be due to invalid IL or missing references) //IL_0122: Unknown result type (might be due to invalid IL or missing references) position = default(Vector3); Rigidbody val = FindBarrelRigidbody(root, null); if ((Object)(object)val != (Object)null) { position = val.worldCenterOfMass; return IsUsableExplosionPosition(root, position); } Holdable[] componentsInChildren = ((Component)root).GetComponentsInChildren(true); foreach (Holdable val2 in componentsInChildren) { if (!IsBarrelHoldable(val2)) { continue; } Transform val3 = (((Object)(object)val2.rig != (Object)null) ? ((Component)val2.rig).transform : ((Component)val2).transform); if (!((Object)(object)val3 == (Object)null)) { position = GetTransformCenter(val3); if (IsUsableExplosionPosition(root, position)) { return true; } } } Transform[] componentsInChildren2 = ((Component)root).GetComponentsInChildren(true); foreach (Transform val4 in componentsInChildren2) { if (((Object)val4).name.IndexOf("BarrelArmor", StringComparison.OrdinalIgnoreCase) >= 0) { position = GetTransformCenter(val4); if (IsUsableExplosionPosition(root, position)) { return true; } } } if (barrelVisuals != null) { foreach (GameObject val5 in barrelVisuals) { if (!((Object)(object)val5 == (Object)null) && val5.activeInHierarchy) { position = GetTransformCenter(val5.transform); if (IsUsableExplosionPosition(root, position)) { return true; } } } } position = default(Vector3); return false; } private static bool IsUsableExplosionPosition(Transform root, Vector3 position) { //IL_000b: Unknown result type (might be due to invalid IL or missing references) //IL_0018: Unknown result type (might be due to invalid IL or missing references) //IL_0025: Unknown result type (might be due to invalid IL or missing references) //IL_0045: Unknown result type (might be due to invalid IL or missing references) //IL_004a: 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_0073: Unknown result type (might be due to invalid IL or missing references) //IL_0074: 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) //IL_006c: Unknown result type (might be due to invalid IL or missing references) //IL_0071: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)root == (Object)null) { return false; } if (float.IsNaN(position.x) || float.IsNaN(position.y) || float.IsNaN(position.z)) { return false; } if (((Vector3)(ref position)).sqrMagnitude < 0.25f) { return false; } Vector3 position2 = root.position; DataHandler componentInChildren = ((Component)root).GetComponentInChildren(); if ((Object)(object)componentInChildren?.mainRig != (Object)null) { position2 = componentInChildren.mainRig.position; } Vector3 val = position - position2; return ((Vector3)(ref val)).sqrMagnitude <= 6400f; } private static bool IsAliveRigidbody(Rigidbody rigidbody) { return (Object)(object)rigidbody != (Object)null; } private static bool BelongsToRoot(Transform transform, Transform root) { if ((Object)(object)transform == (Object)null || (Object)(object)root == (Object)null) { return false; } return (Object)(object)transform.root == (Object)(object)root; } private static Rigidbody FindBarrelRigidbody(Transform root, Rigidbody[] trackedRigidbodies) { Rigidbody result = null; float num = float.MinValue; if (trackedRigidbodies != null) { foreach (Rigidbody val in trackedRigidbodies) { if (IsAliveRigidbody(val)) { float num2 = ScoreBarrelRigidbody(val); if (num2 > num) { num = num2; result = val; } } } } Holdable[] componentsInChildren = ((Component)root).GetComponentsInChildren(true); foreach (Holdable val2 in componentsInChildren) { if (!IsBarrelHoldable(val2)) { continue; } Rigidbody val3 = val2.rig ?? ((Component)val2).GetComponentInChildren(); if (!((Object)(object)val3 == (Object)null) && BelongsToRoot(((Component)val3).transform, root)) { float num3 = ScoreBarrelRigidbody(val3) + 50f; if (num3 > num) { num = num3; result = val3; } } } Rigidbody[] componentsInChildren2 = ((Component)root).GetComponentsInChildren(true); foreach (Rigidbody val4 in componentsInChildren2) { if (BelongsToRoot(((Component)val4).transform, root) && IsRollingBarrelGearTransform(((Component)val4).transform)) { float num4 = ScoreBarrelRigidbody(val4); if (num4 > num) { num = num4; result = val4; } } } return result; } private static bool IsBarrelHoldable(Holdable holdable) { if ((Object)(object)holdable == (Object)null) { return false; } if (IsAbilityMountName(((Object)holdable).name)) { return false; } if (IsBarrelName(((Object)holdable).name)) { return true; } return IsRollingBarrelGearTransform(((Component)holdable).transform); } private static bool IsAbilityMountName(string objectName) { if (string.IsNullOrEmpty(objectName)) { return false; } if (objectName.IndexOf("BarrelRoller", StringComparison.OrdinalIgnoreCase) < 0) { return objectName.IndexOf("Wings_Leg_Barrel", StringComparison.OrdinalIgnoreCase) >= 0; } return true; } internal static bool IsRollingBarrelGearTransform(Transform transform) { Transform val = transform; while ((Object)(object)val != (Object)null) { if (IsAbilityMountName(((Object)val).name)) { return false; } if (((Object)val).name.IndexOf("BarrelArmor", StringComparison.OrdinalIgnoreCase) >= 0) { return true; } if (IsBarrelName(((Object)val).name)) { return true; } if ((Object)(object)val.parent == (Object)null) { break; } val = val.parent; } return false; } private static float ScoreBarrelRigidbody(Rigidbody rigidbody) { float num = rigidbody.mass; string name = ((Object)((Component)rigidbody).transform).name; if (name.IndexOf("BarrelArmor", StringComparison.OrdinalIgnoreCase) >= 0) { num += 200f; } if (IsBarrelName(name)) { num += 100f; } return num; } private static Vector3 GetTransformCenter(Transform transform) { //IL_0009: Unknown result type (might be due to invalid IL or missing references) //IL_001e: Unknown result type (might be due to invalid IL or missing references) //IL_0023: Unknown result type (might be due to invalid IL or missing references) //IL_0061: Unknown result type (might be due to invalid IL or missing references) //IL_005a: 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) //IL_0043: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)transform == (Object)null) { return Vector3.zero; } Renderer[] componentsInChildren = ((Component)transform).GetComponentsInChildren(true); if (componentsInChildren.Length != 0) { Bounds bounds = componentsInChildren[0].bounds; for (int i = 1; i < componentsInChildren.Length; i++) { ((Bounds)(ref bounds)).Encapsulate(componentsInChildren[i].bounds); } return ((Bounds)(ref bounds)).center; } Rigidbody componentInChildren = ((Component)transform).GetComponentInChildren(); if ((Object)(object)componentInChildren != (Object)null) { return componentInChildren.worldCenterOfMass; } return transform.position; } private static bool IsBarrelName(string objectName) { if (string.IsNullOrEmpty(objectName)) { return false; } if (objectName.IndexOf("Barrel", StringComparison.OrdinalIgnoreCase) < 0) { return false; } if (objectName.IndexOf("DoubleBarrel", StringComparison.OrdinalIgnoreCase) >= 0) { return false; } if (objectName.IndexOf("GunBarrel", StringComparison.OrdinalIgnoreCase) >= 0) { return false; } return true; } private static Unit RefreshOwnerUnit(BarrelDeathPlan plan) { if (plan == null) { return null; } if ((Object)(object)plan.OwnerUnit != (Object)null) { return plan.OwnerUnit; } if ((Object)(object)plan.Root == (Object)null) { return null; } plan.OwnerUnit = ((Component)plan.Root).GetComponent(); return plan.OwnerUnit; } private static void RememberSharedDeathExplosionAssets(GameObject prefab, Explosion template) { if ((Object)(object)prefab != (Object)null && (Object)(object)_sharedBarrelDeathExplosionPrefab == (Object)null) { _sharedBarrelDeathExplosionPrefab = prefab; } if ((Object)(object)template != (Object)null && (Object)(object)_sharedBarrelDeathExplosionTemplate == (Object)null) { _sharedBarrelDeathExplosionTemplate = template; } } private static void TriggerSingleBarrelExplosion(BarrelDeathPlan plan, Vector3 position) { //IL_0000: 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_003f: 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_0078: Unknown result type (might be due to invalid IL or missing references) //IL_00f4: Unknown result type (might be due to invalid IL or missing references) //IL_00b7: 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) if (!IsFinite(position)) { return; } Unit ownerUnit = RefreshOwnerUnit(plan); Explosion template = plan.FallbackExplosionTemplate ?? plan.CachedBarrelExplosion ?? _sharedBarrelDeathExplosionTemplate; if ((Object)(object)plan.CachedExplosionPrefab != (Object)null) { GameObject obj = Object.Instantiate(plan.CachedExplosionPrefab, position, Quaternion.identity); PrepareDeathExplosionObject(obj, template); FinalizeDeathExplosionInstance(obj, ownerUnit); obj.SetActive(true); TriggerExplosionOnObject(obj, template); } else if ((Object)(object)_sharedBarrelDeathExplosionPrefab != (Object)null) { GameObject obj2 = Object.Instantiate(_sharedBarrelDeathExplosionPrefab, position, Quaternion.identity); PrepareDeathExplosionObject(obj2, template); FinalizeDeathExplosionInstance(obj2, ownerUnit); obj2.SetActive(true); TriggerExplosionOnObject(obj2, template); } else if ((Object)(object)plan.CachedBarrelExplosion != (Object)null) { GameObject obj3 = Object.Instantiate(((Component)plan.CachedBarrelExplosion).gameObject, position, ((Component)plan.CachedBarrelExplosion).transform.rotation); PrepareDeathExplosionObject(obj3, template); FinalizeDeathExplosionInstance(obj3, ownerUnit); obj3.SetActive(true); TriggerExplosionOnObject(obj3, template); Object.Destroy((Object)(object)obj3, 12f); } else if (!TryCreateFallbackExplosion(position, template, ownerUnit)) { ManualLogSource log = _log; if (log != null) { log.LogWarning((object)"Barrel death fallback explode failed: no viable explosion path"); } } } private static void AttachTeamHolder(GameObject instance, Unit ownerUnit) { if (!((Object)(object)instance == (Object)null) && !((Object)(object)ownerUnit == (Object)null)) { TeamHolder.AddTeamHolder(instance, ownerUnit, (TeamHolder)null); } } private static void FinalizeDeathExplosionInstance(GameObject instance, Unit ownerUnit) { if (!((Object)(object)instance == (Object)null) && !((Object)(object)ownerUnit == (Object)null)) { AttachTeamHolder(instance, ownerUnit); ApplyOwnerLevel(instance, ownerUnit); } } private static void StripDeathExplosionStatusEffects(GameObject instance) { if (!((Object)(object)instance == (Object)null)) { Explosion[] componentsInChildren = instance.GetComponentsInChildren(true); for (int i = 0; i < componentsInChildren.Length; i++) { componentsInChildren[i].addEffectFromParent = false; } ExplosionEffect[] componentsInChildren2 = instance.GetComponentsInChildren(true); for (int i = 0; i < componentsInChildren2.Length; i++) { Object.Destroy((Object)(object)componentsInChildren2[i]); } AddTargetableEffect[] componentsInChildren3 = instance.GetComponentsInChildren(true); for (int i = 0; i < componentsInChildren3.Length; i++) { Object.Destroy((Object)(object)componentsInChildren3[i]); } } } private static void ApplyOwnerLevel(GameObject instance, Unit ownerUnit) { Level val = FindOwnerLevel(ownerUnit); if (!((Object)(object)val == (Object)null)) { Level obj = instance.GetComponent() ?? instance.AddComponent(); obj.levelMultiplier = val.levelMultiplier; obj.level = val.level; obj.ignoreTeam = val.ignoreTeam; TargetableEffect[] componentsInChildren = instance.GetComponentsInChildren(true); for (int i = 0; i < componentsInChildren.Length; i++) { componentsInChildren[i].damageMultiplier = val.levelMultiplier; } } } private static Level FindOwnerLevel(Unit ownerUnit) { if ((Object)(object)ownerUnit == (Object)null) { return null; } Level component = ((Component)ownerUnit).GetComponent(); if ((Object)(object)component != (Object)null) { return component; } return ((Component)ownerUnit).GetComponentInChildren(true); } private static void HideBarrelGear(BarrelDeathPlan plan) { if (plan != null) { HideBarrelGearLive(plan.Root, plan.BarrelVisuals, plan.BarrelRigidbodies); } } private static void HideBarrelGearLive(Transform root, GameObject[] cachedVisuals, Rigidbody[] cachedRigidbodies) { if (cachedVisuals != null) { for (int i = 0; i < cachedVisuals.Length; i++) { HideGameObjectTree(cachedVisuals[i]); } } if (cachedRigidbodies != null) { for (int j = 0; j < cachedRigidbodies.Length; j++) { HideRigidbodyGear(cachedRigidbodies[j]); } } if ((Object)(object)root == (Object)null) { return; } Holdable[] componentsInChildren = ((Component)root).GetComponentsInChildren(true); foreach (Holdable val in componentsInChildren) { if (IsBarrelHoldable(val)) { HideGameObjectTree(((Component)val).gameObject); if ((Object)(object)val.rig != (Object)null) { HideRigidbodyGear(val.rig); } } } Transform[] componentsInChildren2 = ((Component)root).GetComponentsInChildren(true); foreach (Transform val2 in componentsInChildren2) { if (IsRollingBarrelGearTransform(val2) || ((Object)val2).name.IndexOf("BarrelArmor", StringComparison.OrdinalIgnoreCase) >= 0) { HideGameObjectTree(((Component)val2).gameObject); } } } private static void HideRigidbodyGear(Rigidbody rigidbody) { if (!((Object)(object)rigidbody == (Object)null)) { HideGameObjectTree(((Component)rigidbody).gameObject); } } private static void HideGameObjectTree(GameObject target) { if ((Object)(object)target == (Object)null) { return; } Renderer[] componentsInChildren = target.GetComponentsInChildren(true); foreach (Renderer val in componentsInChildren) { if ((Object)(object)val != (Object)null) { val.enabled = false; } } Collider[] componentsInChildren2 = target.GetComponentsInChildren(true); foreach (Collider val2 in componentsInChildren2) { if ((Object)(object)val2 != (Object)null) { val2.enabled = false; } } target.SetActive(false); } private static bool HasRecentBarrelExplosion(Transform root) { if ((Object)(object)root == (Object)null) { return false; } if (!RecentBarrelExplosionTimeByRoot.TryGetValue(((Object)root).GetInstanceID(), out var value)) { return false; } return Time.time - value <= 2.5f; } private static float ScoreBarrelExplosion(Explosion explosion) { float num = (((Object)(object)explosion != (Object)null) ? (explosion.radius + explosion.damage * 0.01f) : 0f); if ((((explosion != null) ? ((Object)((Component)explosion).transform).name : null) ?? string.Empty).IndexOf("BarrelArmor", StringComparison.OrdinalIgnoreCase) >= 0) { num += 100f; } return num; } private static void PrepareDeathExplosionObject(GameObject instance, Explosion template) { if ((Object)(object)instance == (Object)null) { return; } instance.SetActive(false); StripDeathExplosionStatusEffects(instance); Explosion[] componentsInChildren = instance.GetComponentsInChildren(true); foreach (Explosion val in componentsInChildren) { if (!((Object)(object)val == (Object)null)) { val.automatic = false; ApplyDeathExplosionStats(val, template); } } } private static bool TryCreateFallbackExplosion(Vector3 position, Explosion template, Unit ownerUnit) { //IL_0000: 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_0023: Expected O, but got Unknown //IL_0029: Unknown result type (might be due to invalid IL or missing references) if (!IsFinite(position) || ((Vector3)(ref position)).sqrMagnitude < 0.25f) { return false; } GameObject val = new GameObject("StayCombatFix_BarrelExplosion"); try { val.transform.position = position; FinalizeDeathExplosionInstance(val, ownerUnit); Explosion obj = val.AddComponent(); ApplyDeathExplosionStats(obj, template); obj.automatic = false; obj.Explode(); Object.Destroy((Object)(object)val, 10f); return true; } catch (Exception ex) { ManualLogSource log = _log; if (log != null) { log.LogError((object)("Barrel death fallback explode failed: " + ex.Message)); } Object.Destroy((Object)(object)val); return false; } } private static bool IsFinite(Vector3 value) { //IL_0000: 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_001a: Unknown result type (might be due to invalid IL or missing references) if (!float.IsNaN(value.x) && !float.IsNaN(value.y)) { return !float.IsNaN(value.z); } return false; } private static void TriggerExplosionOnObject(GameObject instance, Explosion template) { if ((Object)(object)instance == (Object)null) { return; } Explosion[] componentsInChildren = instance.GetComponentsInChildren(true); Explosion val = null; float num = float.MinValue; foreach (Explosion val2 in componentsInChildren) { if (!((Object)(object)val2 == (Object)null)) { float num2 = val2.radius + val2.damage * 0.01f; if (!(num2 <= num)) { num = num2; val = val2; } } } if (!((Object)(object)val == (Object)null)) { ApplyDeathExplosionStats(val, template); val.automatic = false; val.Explode(); } } private unsafe static void ApplyDeathExplosionStats(Explosion explosion, Explosion template) { //IL_007c: Unknown result type (might be due to invalid IL or missing references) //IL_0081: Unknown result type (might be due to invalid IL or missing references) //IL_0094: Unknown result type (might be due to invalid IL or missing references) //IL_0099: Unknown result type (might be due to invalid IL or missing references) //IL_0099->IL0099: Incompatible stack types: O vs I4 //IL_0093->IL0099: Incompatible stack types: I4 vs O //IL_0093->IL0099: Incompatible stack types: O vs I4 if (!((Object)(object)explosion == (Object)null)) { float radius = (((Object)(object)template != (Object)null) ? template.radius : 4f); float force = (((Object)(object)template != (Object)null) ? template.force : 350f); float minMassCap = (((Object)(object)template != (Object)null) ? template.minMassCap : 25f); explosion.damage = 15f; explosion.percentDamage = 0f; explosion.radius = radius; explosion.force = force; explosion.minMassCap = minMassCap; explosion.layerMask = LayerMask.op_Implicit(-1); object obj = explosion; int num; if ((Object)(object)template != (Object)null) { obj = template.forceDirection; num = (int)obj; } else { num = 0; obj = num; num = (int)obj; } System.Runtime.CompilerServices.Unsafe.Write(&((Explosion)num).forceDirection, (ForceDirection)obj); explosion.ignoreTeamMates = (Object)(object)template != (Object)null && template.ignoreTeamMates; explosion.ignoreRoot = true; } } } internal static class BarrelRollerDeathPatches { public static bool ConditionalEvent_OnUnitDead_Prefix(ConditionalEvent __instance) { Transform val = ((__instance != null) ? ((Component)__instance).transform.root : null); if ((Object)(object)val == (Object)null) { return true; } return !BarrelRollerDeathLogic.IsBarrelRollerRoot(val); } public static bool Explosion_Explode_Prefix(Explosion __instance) { BarrelRollerDeathLogic.PrepareBarrelOwnedExplosionForDetonation(__instance); return !BarrelRollerDeathLogic.TryBlockDuplicateBarrelExplosion(__instance); } public static void KillAfterSeconds_Spawn_Postfix(KillAfterSeconds __instance) { BarrelRollerDeathLogic.NotifyBarrelAbilityExplosionFromSpawn((__instance != null) ? ((Component)__instance).transform : null, __instance?.objectToSpawn); } public static void RemoveAfterSeconds_TriggerRemoval_Postfix(MonoBehaviour __instance) { if (!((Object)(object)__instance == (Object)null) && !(((object)__instance).GetType().Name != "RemoveAfterSeconds")) { GameObject value = Traverse.Create((object)__instance).Field("objectToSpawn").Value; BarrelRollerDeathLogic.NotifyBarrelAbilityExplosionFromSpawn(((Component)__instance).transform, value); } } public static bool DelayEvent_Go_Prefix(DelayEvent __instance) { Transform val = ((__instance != null) ? ((Component)__instance).transform.root : null); if ((Object)(object)val == (Object)null || !BarrelRollerDeathLogic.IsBarrelRollerRoot(val)) { return true; } if (!BarrelRollerDeathLogic.IsBarrelDeathDelayEvent((Component)(object)__instance)) { return true; } DataHandler componentInChildren = ((Component)val).GetComponentInChildren(); if ((Object)(object)componentInChildren == (Object)null || !componentInChildren.Dead) { return true; } return false; } public static void GameStateManager_EnterPlacementState_Postfix() { BarrelRollerDeathLogic.ResetBattleCaches(); } } internal sealed class FactionCreatorCostHoverState : MonoBehaviour { private bool _captured; private Transform _costParent; private int _costSiblingIndex; private Vector2 _anchorMin; private Vector2 _anchorMax; private Vector2 _pivot; private Vector2 _anchoredPosition; private Vector3 _localScale; internal void CaptureCostLayout(RectTransform costRect) { //IL_002c: 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_0038: 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_0044: 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_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) //IL_005c: Unknown result type (might be due to invalid IL or missing references) //IL_0061: Unknown result type (might be due to invalid IL or missing references) if (!_captured && !((Object)(object)costRect == (Object)null)) { _costParent = ((Transform)costRect).parent; _costSiblingIndex = ((Transform)costRect).GetSiblingIndex(); _anchorMin = costRect.anchorMin; _anchorMax = costRect.anchorMax; _pivot = costRect.pivot; _anchoredPosition = costRect.anchoredPosition; _localScale = ((Transform)costRect).localScale; _captured = true; } } internal void RestoreCostLayout(RectTransform costRect) { //IL_002d: 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_0045: Unknown result type (might be due to invalid IL or missing references) //IL_0051: Unknown result type (might be due to invalid IL or missing references) //IL_005d: Unknown result type (might be due to invalid IL or missing references) if (_captured && !((Object)(object)costRect == (Object)null)) { ((Transform)costRect).SetParent(_costParent, false); ((Transform)costRect).SetSiblingIndex(_costSiblingIndex); costRect.anchorMin = _anchorMin; costRect.anchorMax = _anchorMax; costRect.pivot = _pivot; costRect.anchoredPosition = _anchoredPosition; ((Transform)costRect).localScale = _localScale; } } internal static FactionCreatorCostHoverState GetOrCreate(UnitButtonBase button) { return ((Component)button).gameObject.GetComponent() ?? ((Component)button).gameObject.AddComponent(); } } internal sealed class FactionCreatorDragScrollSession : MonoBehaviour { private ScrollRect _scrollRect; private Camera _eventCamera; private FactionCreatorUnitDragReorder _drag; internal void Begin(ScrollRect scrollRect, Camera eventCamera, FactionCreatorUnitDragReorder drag) { _scrollRect = scrollRect; _eventCamera = eventCamera; _drag = drag; } private void Update() { //IL_0029: Unknown result type (might be due to invalid IL or missing references) if (!((Object)(object)_scrollRect == (Object)null) && !((Object)(object)_drag == (Object)null)) { FactionCreatorReorderLogic.UpdateDragScroll(_scrollRect, _drag.CurrentScreenPosition, _eventCamera); } } } internal static class FactionCreatorDropGap { private const string GapObjectName = "StayCombatFix_DropGap"; internal static RectTransform Create(RectTransform listParent, RectTransform unitButton, bool horizontal) { //IL_0018: 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_002d: 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_0058: Unknown result type (might be due to invalid IL or missing references) //IL_006a: Unknown result type (might be due to invalid IL or missing references) //IL_006f: Unknown result type (might be due to invalid IL or missing references) GameObject val = new GameObject("StayCombatFix_DropGap", new Type[1] { typeof(RectTransform) }); RectTransform component = val.GetComponent(); ((Transform)component).SetParent((Transform)(object)listParent, false); ((Transform)component).localScale = Vector3.one; LayoutElement obj = val.AddComponent(); float num = LayoutUtility.GetPreferredWidth(unitButton); float num2 = LayoutUtility.GetPreferredHeight(unitButton); Rect rect; if (num <= 1f) { rect = unitButton.rect; num = ((Rect)(ref rect)).width; } if (num2 <= 1f) { rect = unitButton.rect; num2 = ((Rect)(ref rect)).height; } obj.preferredWidth = num; obj.preferredHeight = num2; obj.minWidth = num; obj.minHeight = num2; obj.flexibleWidth = 0f; obj.flexibleHeight = 0f; CreateCircleHighlight(component, unitButton, num, num2); return component; } internal static void Destroy(RectTransform gap) { if ((Object)(object)gap != (Object)null) { Object.Destroy((Object)(object)((Component)gap).gameObject); } } private static void CreateCircleHighlight(RectTransform gapRect, RectTransform unitButton, float width, float height) { //IL_0034: 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_0052: Unknown result type (might be due to invalid IL or missing references) //IL_0067: Unknown result type (might be due to invalid IL or missing references) //IL_007c: 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_0093: Unknown result type (might be due to invalid IL or missing references) //IL_00c6: Unknown result type (might be due to invalid IL or missing references) //IL_00f5: Unknown result type (might be due to invalid IL or missing references) UnitButtonBase component = ((Component)unitButton).GetComponent(); Image val = component?.NameSelect; float num = Mathf.Min(width, height); GameObject val2 = new GameObject("Highlight", new Type[1] { typeof(RectTransform) }); RectTransform component2 = val2.GetComponent(); ((Transform)component2).SetParent((Transform)(object)gapRect, false); component2.anchorMin = new Vector2(0.5f, 0.5f); component2.anchorMax = new Vector2(0.5f, 0.5f); component2.pivot = new Vector2(0.5f, 0.5f); component2.sizeDelta = new Vector2(num, num); component2.anchoredPosition = Vector2.zero; Image val3 = val2.AddComponent(); ((Graphic)val3).raycastTarget = false; val3.preserveAspect = true; ((Graphic)val3).color = new Color(1f, 1f, 1f, 0.38f); if ((Object)(object)val != (Object)null && (Object)(object)val.sprite != (Object)null) { val3.sprite = val.sprite; val3.type = val.type; } else if ((Object)(object)component?.IconImage != (Object)null && (Object)(object)component.IconImage.sprite != (Object)null) { val3.sprite = component.IconImage.sprite; } } } internal static class FactionCreatorPatches { public static void AddNewUnit_Postfix(FactionCreatorManager __instance) { if (!((Object)(object)__instance?.FactionListParent == (Object)null) && __instance.FactionListParent.childCount != 0) { FactionCreatorReorderLogic.AttachDragHandle(((Component)__instance.FactionListParent.GetChild(__instance.FactionListParent.childCount - 1)).GetComponent(), __instance); } } public static void LoadFaction_Postfix(FactionCreatorManager __instance) { FactionCreatorReorderLogic.RefreshAllDragHandles(__instance); } public static void SaveNewFaction_Prefix(FactionCreatorManager __instance) { FactionCreatorReorderLogic.SyncAddedUnitsFromHierarchy(__instance); } public static void GetFactionUnits_Prefix(FactionCreatorManager __instance) { FactionCreatorReorderLogic.SyncAddedUnitsFromHierarchy(__instance); } public static bool UnitButtonFactionCreator_OnClick_Prefix(UnitButtonFactionCreator __instance) { FactionCreatorUnitDragReorder component = ((Component)__instance).GetComponent(); if (!((Object)(object)component == (Object)null)) { return !component.ConsumeClickSuppression(); } return true; } public static void UnitButtonBase_OnPointerEnter_Postfix(UnitButtonBase __instance) { FactionCreatorUnitCostHover.ShowOnHover(__instance); } public static void UnitButtonBase_OnPointerExit_Postfix(UnitButtonBase __instance) { FactionCreatorUnitCostHover.HideOnHover(__instance); } public static void UnitButtonBase_OnSelect_Postfix(UnitButtonBase __instance) { FactionCreatorUnitCostHover.ShowOnHover(__instance); } public static void UnitButtonBase_OnDeselect_Postfix(UnitButtonBase __instance) { FactionCreatorUnitCostHover.HideOnHover(__instance); } } internal static class FactionCreatorReorderLogic { private static readonly FieldInfo AddedUnitsField = AccessTools.Field(typeof(FactionCreatorManager), "addedUnits"); private static FieldInfo _spawnedButtonField; internal static void AttachDragHandle(UnitButtonBase button, FactionCreatorManager manager) { if (!((Object)(object)button == (Object)null) && !((Object)(object)manager == (Object)null) && !((Object)(object)((Component)button).GetComponent() != (Object)null)) { ((Component)button).gameObject.AddComponent().Initialize(manager, button); } } internal static void RefreshAllDragHandles(FactionCreatorManager manager) { if ((Object)(object)manager?.FactionListParent == (Object)null) { return; } for (int i = 0; i < manager.FactionListParent.childCount; i++) { UnitButtonBase component = ((Component)manager.FactionListParent.GetChild(i)).GetComponent(); if ((Object)(object)component != (Object)null) { AttachDragHandle(component, manager); } } } internal static int GetUnitIndex(FactionCreatorManager manager, UnitButtonBase button) { IList addedUnits = GetAddedUnits(manager); if (addedUnits == null || (Object)(object)button == (Object)null) { return -1; } for (int i = 0; i < addedUnits.Count; i++) { if ((Object)(object)GetSpawnedButton(addedUnits[i]) == (Object)(object)button) { return i; } } return -1; } internal static void SyncAddedUnitsFromHierarchy(FactionCreatorManager manager) { IList addedUnits = GetAddedUnits(manager); Transform val = manager?.FactionListParent; if (addedUnits == null || (Object)(object)val == (Object)null || addedUnits.Count == 0) { return; } Dictionary dictionary = new Dictionary(); for (int i = 0; i < addedUnits.Count; i++) { UnitButtonBase spawnedButton = GetSpawnedButton(addedUnits[i]); if ((Object)(object)spawnedButton != (Object)null && !dictionary.ContainsKey(spawnedButton)) { dictionary[spawnedButton] = addedUnits[i]; } } List list = new List(); for (int j = 0; j < val.childCount; j++) { UnitButtonBase component = ((Component)val.GetChild(j)).GetComponent(); if ((Object)(object)component != (Object)null && dictionary.TryGetValue(component, out var value)) { list.Add(value); } } if (list.Count == addedUnits.Count) { addedUnits.Clear(); for (int k = 0; k < list.Count; k++) { addedUnits.Add(list[k]); } } } internal static ScrollRect FindListScrollRect(FactionCreatorManager manager) { if (!((Object)(object)manager?.FactionListParent != (Object)null)) { return null; } return ((Component)manager.FactionListParent).GetComponentInParent(); } internal static bool IsHorizontalLayout(RectTransform listParent) { //IL_000a: Unknown result type (might be due to invalid IL or missing references) //IL_000f: Unknown result type (might be due to invalid IL or missing references) //IL_0018: 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) if ((Object)(object)listParent != (Object)null) { Rect rect = listParent.rect; float width = ((Rect)(ref rect)).width; rect = listParent.rect; return width >= ((Rect)(ref rect)).height; } return false; } internal static void UpdateDragScroll(ScrollRect scrollRect, Vector2 screenPosition, Camera eventCamera) { //IL_0037: 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_0049: 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) //IL_0072: Unknown result type (might be due to invalid IL or missing references) //IL_00fa: Unknown result type (might be due to invalid IL or missing references) //IL_0111: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)scrollRect == (Object)null) { return; } RectTransform val = (RectTransform)(((Object)(object)scrollRect.viewport != (Object)null) ? ((object)scrollRect.viewport) : ((object)/*isinst with value type is only supported in some contexts*/)); Vector2 val2 = default(Vector2); if ((Object)(object)val == (Object)null || !RectTransformUtility.ScreenPointToLocalPointInRectangle(val, screenPosition, eventCamera, ref val2)) { return; } Rect rect = val.rect; float unscaledDeltaTime = Time.unscaledDeltaTime; if (scrollRect.horizontal) { float num = val2.x - ((Rect)(ref rect)).xMin; float num2 = ((Rect)(ref rect)).xMax - val2.x; float num3 = 0f; if (num < 72f) { num3 = (0f - Mathf.InverseLerp(72f, 0f, num)) * 2.5f * unscaledDeltaTime; } else if (num2 < 72f) { num3 = Mathf.InverseLerp(72f, 0f, num2) * 2.5f * unscaledDeltaTime; } if (Mathf.Abs(num3) > 0.0001f) { scrollRect.horizontalNormalizedPosition = Mathf.Clamp01(scrollRect.horizontalNormalizedPosition + num3); } } if (scrollRect.vertical) { float num4 = val2.y - ((Rect)(ref rect)).yMin; float num5 = ((Rect)(ref rect)).yMax - val2.y; float num6 = 0f; if (num4 < 72f) { num6 = (0f - Mathf.InverseLerp(72f, 0f, num4)) * 2.5f * unscaledDeltaTime; } else if (num5 < 72f) { num6 = Mathf.InverseLerp(72f, 0f, num5) * 2.5f * unscaledDeltaTime; } if (Mathf.Abs(num6) > 0.0001f) { scrollRect.verticalNormalizedPosition = Mathf.Clamp01(scrollRect.verticalNormalizedPosition + num6); } } } internal static int GetInsertionIndex(FactionCreatorManager manager, Vector2 screenPosition, Camera camera, Transform ignore, int currentIndex = -1) { //IL_0026: Unknown result type (might be due to invalid IL or missing references) //IL_0052: Unknown result type (might be due to invalid IL or missing references) //IL_004a: 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_008e: Unknown result type (might be due to invalid IL or missing references) //IL_0092: Unknown result type (might be due to invalid IL or missing references) //IL_0097: Unknown result type (might be due to invalid IL or missing references) //IL_009c: Unknown result type (might be due to invalid IL or missing references) //IL_00a1: Unknown result type (might be due to invalid IL or missing references) //IL_00a6: Unknown result type (might be due to invalid IL or missing references) //IL_00b4: 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) Transform obj = manager?.FactionListParent; RectTransform val = (RectTransform)(object)((obj is RectTransform) ? obj : null); if ((Object)(object)val == (Object)null || ((Transform)val).childCount == 0) { return 0; } Vector2 val2 = default(Vector2); if (!RectTransformUtility.ScreenPointToLocalPointInRectangle(val, screenPosition, camera, ref val2)) { return Mathf.Clamp(currentIndex, 0, ((Transform)val).childCount); } bool flag = IsHorizontalLayout(val); float num = (flag ? val2.x : val2.y); int num2 = 0; for (int i = 0; i < ((Transform)val).childCount; i++) { Transform child = ((Transform)val).GetChild(i); RectTransform val3 = (RectTransform)(object)((child is RectTransform) ? child : null); if (!((Object)(object)val3 == (Object)null) && !((Object)(object)val3 == (Object)(object)ignore)) { Rect rect = val3.rect; Vector3 val4 = ((Transform)val).InverseTransformPoint(((Transform)val3).TransformPoint(Vector2.op_Implicit(((Rect)(ref rect)).center))); float num3 = (flag ? val4.x : val4.y); if (num > num3) { num2 = i + 1; } } } num2 = Mathf.Clamp(num2, 0, ((Transform)val).childCount); if (currentIndex < 0) { return num2; } if (num2 == currentIndex) { return currentIndex; } if (Mathf.Abs(num2 - currentIndex) > 1) { num2 = currentIndex + ((num2 > currentIndex) ? 1 : (-1)); } return num2; } private static IList GetAddedUnits(FactionCreatorManager manager) { return AddedUnitsField?.GetValue(manager) as IList; } private static UnitButtonBase GetSpawnedButton(object wrapper) { object? obj = (_spawnedButtonField ?? (_spawnedButtonField = AccessTools.Field(AccessTools.Inner(typeof(FactionCreatorManager), "SpawnedWrapper"), "spawnedButton")))?.GetValue(wrapper); return (UnitButtonBase)((obj is UnitButtonBase) ? obj : null); } } internal static class FactionCreatorUnitCostHover { private static readonly FieldInfo UnitCostField = AccessTools.Field(typeof(UnitButtonBase), "UnitCost"); private static readonly FieldInfo TargetIconColorField = AccessTools.Field(typeof(UnitButtonBase), "targetIconColor"); private static readonly MethodInfo GetUnitMethod = AccessTools.Method(typeof(UnitButtonBase), "GetUnit", (Type[])null, (Type[])null); private static readonly PropertyInfo IsCustomUnitProperty = AccessTools.Property(AccessTools.TypeByName("Landfall.TABS.UnitBlueprint"), "IsCustomUnit"); private static readonly MethodInfo GetUnitCostMethod = AccessTools.Method(AccessTools.TypeByName("Landfall.TABS.UnitBlueprint"), "GetUnitCost", new Type[1] { typeof(bool) }, (Type[])null); private static PropertyInfo _costTextProperty; private static readonly Color DimIconColor = new Color(0.32f, 0.32f, 0.32f, 1f); internal static bool IsFactionEditorUnitButton(UnitButtonBase button) { if ((Object)(object)button == (Object)null) { return false; } if (button is UnitButtonFactionCreator) { return true; } if (((object)button).GetType().Name == "FactionCreatorUnitBrowserUnitButton") { return true; } if (!((Object)(object)((Component)button).GetComponentInParent() != (Object)null)) { return (Object)(object)((Component)button).GetComponentInParent() != (Object)null; } return true; } internal static void ShowOnHover(UnitButtonBase button) { if (!IsFactionEditorUnitButton(button)) { return; } object obj = GetUnitMethod?.Invoke(button, null); if (obj != null && IsCustomUnit(obj)) { string unitCostText = GetUnitCostText(obj); if (unitCostText != null) { DimIcon(button); ShowCostOverlay(button, unitCostText); } } } internal static void HideOnHover(UnitButtonBase button) { if (IsFactionEditorUnitButton(button)) { object obj = GetUnitMethod?.Invoke(button, null); if (obj != null && IsCustomUnit(obj)) { RestoreIcon(button); HideCostOverlay(button); } } } private static bool IsCustomUnit(object unit) { if (IsCustomUnitProperty != null) { return (bool)IsCustomUnitProperty.GetValue(unit); } return false; } private static string GetUnitCostText(object unit) { if (GetUnitCostMethod == null) { return null; } return GetUnitCostMethod.Invoke(unit, new object[1] { true })?.ToString(); } private static void DimIcon(UnitButtonBase button) { //IL_002c: Unknown result type (might be due to invalid IL or missing references) TargetIconColorField?.SetValue(button, 1f); Image iconImage = button.IconImage; if ((Object)(object)iconImage != (Object)null) { ((Graphic)iconImage).color = DimIconColor; } } private static void RestoreIcon(UnitButtonBase button) { //IL_002c: Unknown result type (might be due to invalid IL or missing references) TargetIconColorField?.SetValue(button, 0f); Image iconImage = button.IconImage; if ((Object)(object)iconImage != (Object)null) { ((Graphic)iconImage).color = Color.white; } } private static void ShowCostOverlay(UnitButtonBase button, string costText) { //IL_00c9: Unknown result type (might be due to invalid IL or missing references) //IL_00de: Unknown result type (might be due to invalid IL or missing references) //IL_00f3: Unknown result type (might be due to invalid IL or missing references) //IL_00fe: 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) //IL_0085: 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) //IL_00a6: Unknown result type (might be due to invalid IL or missing references) //IL_00b2: 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_014f: Unknown result type (might be due to invalid IL or missing references) //IL_0151: Unknown result type (might be due to invalid IL or missing references) //IL_0156: Unknown result type (might be due to invalid IL or missing references) //IL_0166: Unknown result type (might be due to invalid IL or missing references) object? obj = UnitCostField?.GetValue(button); Behaviour val = (Behaviour)((obj is Behaviour) ? obj : null); if ((Object)(object)val == (Object)null) { return; } Transform transform = ((Component)val).transform; RectTransform val2 = (RectTransform)(object)((transform is RectTransform) ? transform : null); RectTransform val3 = (((Object)(object)button.IconImage != (Object)null) ? ((Graphic)button.IconImage).rectTransform : null); if (!((Object)(object)val2 == (Object)null)) { FactionCreatorCostHoverState.GetOrCreate(button).CaptureCostLayout(val2); if ((Object)(object)val3 != (Object)null) { ((Transform)val2).SetParent(((Transform)val3).parent, false); val2.anchorMin = val3.anchorMin; val2.anchorMax = val3.anchorMax; val2.pivot = new Vector2(0.5f, 0.5f); val2.anchoredPosition = val3.anchoredPosition; val2.sizeDelta = val3.sizeDelta; } else { val2.anchorMin = new Vector2(0.5f, 0.5f); val2.anchorMax = new Vector2(0.5f, 0.5f); val2.pivot = new Vector2(0.5f, 0.5f); val2.anchoredPosition = Vector2.zero; } ((Transform)val2).SetAsLastSibling(); SetText((Component)(object)val, costText); val.enabled = true; ((Component)val).gameObject.SetActive(true); PropertyInfo property = ((object)val).GetType().GetProperty("color"); if (property != null) { Color val4 = (Color)property.GetValue(val, null); val4 = Color.white; val4.a = 1f; property.SetValue(val, val4, null); } } } private static void HideCostOverlay(UnitButtonBase button) { object? obj = UnitCostField?.GetValue(button); Behaviour val = (Behaviour)((obj is Behaviour) ? obj : null); if (!((Object)(object)val == (Object)null)) { val.enabled = false; Transform transform = ((Component)val).transform; RectTransform costRect = (RectTransform)(object)((transform is RectTransform) ? transform : null); ((Component)button).GetComponent()?.RestoreCostLayout(costRect); } } private static void SetText(Component textComponent, string value) { if (!((Object)(object)textComponent == (Object)null)) { if ((object)_costTextProperty == null) { _costTextProperty = ((object)textComponent).GetType().GetProperty("text"); } _costTextProperty?.SetValue(textComponent, value, null); } } } internal sealed class FactionCreatorUnitDragReorder : MonoBehaviour, IBeginDragHandler, IEventSystemHandler, IDragHandler, IEndDragHandler { private static readonly Vector3[] WorldCorners = (Vector3[])(object)new Vector3[4]; private FactionCreatorManager _manager; private UnitButtonBase _button; private RectTransform _rectTransform; private RectTransform _canvasRect; private Canvas _canvas; private Camera _eventCamera; private Transform _listParent; private RectTransform _listParentRect; private RectTransform _dropGap; private ScrollRect _scrollRect; private FactionCreatorDragScrollSession _scrollSession; private bool _horizontalLayout; private int _targetIndex; private int _fromIndex; private bool _moved; private bool _suppressClick; private CanvasGroup _canvasGroup; private Vector2 _currentScreenPosition; internal Vector2 CurrentScreenPosition => _currentScreenPosition; internal void Initialize(FactionCreatorManager manager, UnitButtonBase button) { _manager = manager; _button = button; ref RectTransform rectTransform = ref _rectTransform; Transform transform = ((Component)this).transform; rectTransform = (RectTransform)(object)((transform is RectTransform) ? transform : null); _canvas = ((Component)this).GetComponentInParent(); _canvasRect = (RectTransform)(((Object)(object)_canvas != (Object)null) ? /*isinst with value type is only supported in some contexts*/: null); } internal bool ConsumeClickSuppression() { if (!_suppressClick) { return false; } _suppressClick = false; return true; } public void OnBeginDrag(PointerEventData eventData) { //IL_0039: Unknown result type (might be due to invalid IL or missing references) //IL_017e: Unknown result type (might be due to invalid IL or missing references) //IL_0183: Unknown result type (might be due to invalid IL or missing references) //IL_01c8: Unknown result type (might be due to invalid IL or missing references) if (!((Object)(object)_manager == (Object)null) && !((Object)(object)_button == (Object)null) && !((Object)(object)_rectTransform == (Object)null) && !((Object)(object)_canvasRect == (Object)null) && (int)eventData.button == 0 && FactionCreatorReorderLogic.GetUnitIndex(_manager, _button) >= 0) { _fromIndex = ((Component)_button).transform.GetSiblingIndex(); _targetIndex = _fromIndex; _moved = false; _listParent = _manager.FactionListParent; ref RectTransform listParentRect = ref _listParentRect; Transform listParent = _listParent; listParentRect = (RectTransform)(object)((listParent is RectTransform) ? listParent : null); _horizontalLayout = FactionCreatorReorderLogic.IsHorizontalLayout(_listParentRect); _scrollRect = FactionCreatorReorderLogic.FindListScrollRect(_manager); object obj = eventData.pressEventCamera; if (obj == null) { Canvas canvas = _canvas; obj = ((canvas != null) ? canvas.worldCamera : null); } _eventCamera = (Camera)obj; _canvasGroup = ((Component)this).gameObject.GetComponent(); if ((Object)(object)_canvasGroup == (Object)null) { _canvasGroup = ((Component)this).gameObject.AddComponent(); } _dropGap = FactionCreatorDropGap.Create(_listParentRect, _rectTransform, _horizontalLayout); ((Transform)_dropGap).SetSiblingIndex(_fromIndex); ((Component)this).transform.SetParent((Transform)(object)_canvasRect, true); _canvasGroup.blocksRaycasts = false; _canvasGroup.alpha = 0.85f; ((Component)this).transform.SetAsLastSibling(); _currentScreenPosition = eventData.position; if ((Object)(object)_scrollRect != (Object)null) { _scrollSession = ((Component)this).gameObject.AddComponent(); _scrollSession.Begin(_scrollRect, _eventCamera, this); } SnapCenterToCursor(eventData); UpdateDropTarget(_currentScreenPosition); } } public void OnDrag(PointerEventData eventData) { //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_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_0040: Unknown result type (might be due to invalid IL or missing references) if (!((Object)(object)_manager == (Object)null)) { Vector2 delta = eventData.delta; if (((Vector2)(ref delta)).sqrMagnitude > 0.01f) { _moved = true; } _currentScreenPosition = eventData.position; SnapCenterToCursor(eventData); UpdateDropTarget(_currentScreenPosition); } } public void OnEndDrag(PointerEventData eventData) { if (!((Object)(object)_manager == (Object)null) && !((Object)(object)_listParent == (Object)null)) { if ((Object)(object)_scrollSession != (Object)null) { Object.Destroy((Object)(object)_scrollSession); _scrollSession = null; } FactionCreatorDropGap.Destroy(_dropGap); _dropGap = null; ((Component)this).transform.SetParent(_listParent, false); ((Component)this).transform.SetSiblingIndex(_targetIndex); if (_moved) { FactionCreatorReorderLogic.SyncAddedUnitsFromHierarchy(_manager); _suppressClick = true; } if ((Object)(object)_canvasGroup != (Object)null) { _canvasGroup.blocksRaycasts = true; _canvasGroup.alpha = 1f; } if ((Object)(object)_listParentRect != (Object)null) { LayoutRebuilder.ForceRebuildLayoutImmediate(_listParentRect); } } } private void UpdateDropTarget(Vector2 screenPosition) { //IL_0006: Unknown result type (might be due to invalid IL or missing references) int insertionIndex = FactionCreatorReorderLogic.GetInsertionIndex(_manager, screenPosition, _eventCamera, (Transform)(object)_dropGap, _targetIndex); if (insertionIndex == _targetIndex) { return; } _targetIndex = insertionIndex; if ((Object)(object)_dropGap != (Object)null) { ((Transform)_dropGap).SetSiblingIndex(_targetIndex); if ((Object)(object)_listParentRect != (Object)null) { LayoutRebuilder.ForceRebuildLayoutImmediate(_listParentRect); } } } private void SnapCenterToCursor(PointerEventData eventData) { //IL_0016: 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_0026: 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_0035: 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_0056: 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_007c: Unknown result type (might be due to invalid IL or missing references) //IL_007d: Unknown result type (might be due to invalid IL or missing references) //IL_007e: Unknown result type (might be due to invalid IL or missing references) //IL_0083: Unknown result type (might be due to invalid IL or missing references) _rectTransform.GetWorldCorners(WorldCorners); Vector3 val = (WorldCorners[0] + WorldCorners[2]) * 0.5f; Vector3 val2 = default(Vector3); if (RectTransformUtility.ScreenPointToWorldPointInRectangle(_canvasRect, eventData.position, ((Object)(object)_canvas != (Object)null && (int)_canvas.renderMode == 0) ? null : _eventCamera, ref val2)) { RectTransform rectTransform = _rectTransform; ((Transform)rectTransform).position = ((Transform)rectTransform).position + (val2 - val); } } } internal static class GameStatePatches { public static void EnterBattleState_Postfix() { BarrelRollerDeathLogic.ResetBattleCaches(); WaterPatches.ResetRiverFlowDirections(); MirrorShieldLogic.ResetBattleState(); } } internal static class GasGrenadePatches { private const float FloorNormalMin = 0.45f; private const float DownwardProbeDistance = 0.75f; private static readonly int MapLayer = LayerMask.NameToLayer("Map"); [ThreadStatic] private static int _floorCatchFrame = -1; [ThreadStatic] private static int _floorCatchProjectileId; public static void ProjectileHit_DisableProjectile_Postfix(ProjectileHit __instance) { //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) if (IsGasGrenade((Component)(object)__instance)) { MoveTransform component = ((Component)__instance).GetComponent(); if (!((Object)(object)component == (Object)null)) { ((Behaviour)component).enabled = false; component.velocity = Vector3.zero; } } } public static void RaycastTrail_Check_Postfix(RaycastTrail __instance) { //IL_0041: 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_004d: Unknown result type (might be due to invalid IL or missing references) //IL_0090: Unknown result type (might be due to invalid IL or missing references) //IL_009b: Unknown result type (might be due to invalid IL or missing references) if (!IsGasGrenade((Component)(object)__instance)) { return; } ProjectileHit component = ((Component)__instance).GetComponent(); if ((Object)(object)component == (Object)null || component.done) { return; } MoveTransform component2 = ((Component)__instance).GetComponent(); if (!((Object)(object)component2 == (Object)null) && ((Behaviour)component2).enabled && TryFindFloorImpact(((Component)__instance).transform.position, component2.velocity, __instance.mask, out var hitInfo)) { int instanceID = ((Object)component).GetInstanceID(); if (_floorCatchFrame != Time.frameCount || _floorCatchProjectileId != instanceID) { _floorCatchFrame = Time.frameCount; _floorCatchProjectileId = instanceID; ((Component)__instance).transform.position = ((RaycastHit)(ref hitInfo)).point; component.Hit(hitInfo, 1f); } } } private static bool IsGasGrenade(Component component) { if ((Object)(object)component != (Object)null) { return ((Object)component.gameObject).name.IndexOf("Grenade_Gas", StringComparison.OrdinalIgnoreCase) >= 0; } return false; } private static bool TryFindFloorImpact(Vector3 position, Vector3 velocity, LayerMask mask, out RaycastHit hitInfo) { //IL_0001: Unknown result type (might be due to invalid IL or missing references) //IL_0007: Unknown result type (might be due to invalid IL or missing references) //IL_002a: Unknown result type (might be due to invalid IL or missing references) //IL_0014: 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_001f: 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_0053: Unknown result type (might be due to invalid IL or missing references) //IL_0059: 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_006f: Unknown result type (might be due to invalid IL or missing references) //IL_0070: Unknown result type (might be due to invalid IL or missing references) //IL_0071: Unknown result type (might be due to invalid IL or missing references) //IL_0078: Unknown result type (might be due to invalid IL or missing references) //IL_008a: Unknown result type (might be due to invalid IL or missing references) hitInfo = default(RaycastHit); if (velocity.y <= 0.25f && TryMapFloorHit(position, Vector3.down, 0.75f, mask, out hitInfo)) { return true; } if (velocity.y > -0.5f || Mathf.Abs(velocity.y) < ((Vector3)(ref velocity)).magnitude * 0.35f) { return false; } Vector3 val = velocity * Time.deltaTime; if (((Vector3)(ref val)).sqrMagnitude <= 1E-06f) { return false; } return TryMapFloorHit(position - val, ((Vector3)(ref val)).normalized, ((Vector3)(ref val)).magnitude + 0.2f, mask, out hitInfo); } private static bool TryMapFloorHit(Vector3 origin, Vector3 direction, float distance, LayerMask mask, out RaycastHit hitInfo) { //IL_0000: Unknown result type (might be due to invalid IL or missing references) //IL_0001: Unknown result type (might be due to invalid IL or missing references) //IL_0005: 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) if (!Physics.Raycast(origin, direction, ref hitInfo, distance, LayerMask.op_Implicit(mask), (QueryTriggerInteraction)1)) { return false; } Collider collider = ((RaycastHit)(ref hitInfo)).collider; if ((Object)(object)collider != (Object)null && ((Component)collider).gameObject.layer == MapLayer) { return ((RaycastHit)(ref hitInfo)).normal.y >= 0.45f; } return false; } } internal static class LayDownAbilityLogic { public const float LookAtEnemyMaxAngleDegrees = 10f; public static bool IsLookingAtEnemy(DataHandler data) { //IL_0071: Unknown result type (might be due to invalid IL or missing references) //IL_0076: Unknown result type (might be due to invalid IL or missing references) //IL_007d: Unknown result type (might be due to invalid IL or missing references) //IL_0082: Unknown result type (might be due to invalid IL or missing references) //IL_0083: 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_0064: Unknown result type (might be due to invalid IL or missing references) //IL_0057: Unknown result type (might be due to invalid IL or missing references) //IL_00a6: 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_00c8: Unknown result type (might be due to invalid IL or missing references) //IL_00c9: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)data?.targetMainRig == (Object)null) { return false; } DataHandler componentInParent = ((Component)data.targetMainRig).GetComponentInParent(); if ((Object)(object)componentInParent != (Object)null && componentInParent.Dead) { return false; } Vector3 val = (((Object)(object)data.torso != (Object)null) ? data.torso.position : (((Object)(object)data.mainRig != (Object)null) ? data.mainRig.position : ((Component)data).transform.position)); Vector3 val2 = data.targetMainRig.position - val; val2.y = 0f; if (((Vector3)(ref val2)).sqrMagnitude < 0.01f) { return true; } Vector3 lookForward = GetLookForward(data); lookForward.y = 0f; if (((Vector3)(ref lookForward)).sqrMagnitude < 0.0001f) { return false; } return Vector3.Angle(lookForward, val2) <= 10f; } private static Vector3 GetLookForward(DataHandler data) { //IL_006f: 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_0032: Unknown result type (might be due to invalid IL or missing references) //IL_00b4: Unknown result type (might be due to invalid IL or missing references) //IL_00a8: Unknown result type (might be due to invalid IL or missing references) //IL_0056: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)data.input != (Object)null && data.input.hasControl) { if ((Object)(object)MainCam.instance != (Object)null) { return ((Component)MainCam.instance).transform.forward; } if ((Object)(object)data.input.Direction != (Object)null) { return data.input.Direction.forward; } } if (((Vector3)(ref data.lookDirectionIntent)).sqrMagnitude > 0.01f) { return data.lookDirectionIntent; } if ((Object)(object)data.characterForwardObject != (Object)null) { return data.characterForwardObject.forward; } if ((Object)(object)data.mainRig != (Object)null) { return ((Component)data.mainRig).transform.forward; } return ((Component)data).transform.forward; } public static bool ShouldAutoTriggerLayDown(DataHandler data) { if ((Object)(object)data == (Object)null || data.Dead || (Object)(object)data.targetMainRig == (Object)null) { return false; } if (!IsLookingAtEnemy(data)) { return false; } return StayFixLogic.IsTargetWithinWeaponFireRange(data); } public static void ConfigureLayDownConditionalEvent(ConditionalEvent conditionalEvent) { if (!LayDownRangeLogic.IsLayDownConditionalEvent(conditionalEvent)) { return; } ConditionalEventInstance[] events = conditionalEvent.events; if (events == null) { return; } for (int i = 0; i < events.Length; i++) { if (events[i] != null) { events[i].checkAutomatically = true; } } } public static void TickLayDownWhilePossessed(ConditionalEvent conditionalEvent) { if (!LayDownRangeLogic.IsLayDownConditionalEvent(conditionalEvent)) { return; } DataHandler data = conditionalEvent.data; if ((Object)(object)data?.input == (Object)null || !data.input.hasControl || conditionalEvent.ignorePossession || !ShouldAutoTriggerLayDown(data)) { return; } ConditionalEventInstance[] events = conditionalEvent.events; if (events == null) { return; } foreach (ConditionalEventInstance val in events) { if (val != null) { val.checkAutomatically = true; conditionalEvent.CheckConditions(val, (ConditionType)8, false, false); } } } } internal static class LayDownAbilityPatches { public static void ConditionalEvent_Start_Postfix(ConditionalEvent __instance) { DataHandler val = __instance?.data; if ((Object)(object)val != (Object)null && LayDownWeaponExclusions.HasExcludedWeaponEquipped(val)) { LayDownWeaponExclusions.SuppressBundledLayDownForUnit(val); } LayDownAbilityLogic.ConfigureLayDownConditionalEvent(__instance); } public static void ConditionalEvent_Update_Postfix(ConditionalEvent __instance) { LayDownAbilityLogic.TickLayDownWhilePossessed(__instance); } public static bool CheckConditionsUpdate_Prefix(ConditionalEvent __instance, ref bool forceFail) { if (!LayDownRangeLogic.IsLayDownConditionalEvent(__instance)) { return true; } LayDownAbilityLogic.ConfigureLayDownConditionalEvent(__instance); if ((Object)(object)__instance.data == (Object)null || !LayDownAbilityLogic.ShouldAutoTriggerLayDown(__instance.data)) { return false; } if (forceFail) { forceFail = false; } return true; } public static bool CheckConditions_Prefix(ConditionalEvent __instance, ConditionalEventInstance eventToCheck, ref bool __result) { if (eventToCheck == null || (Object)(object)__instance?.data == (Object)null) { return true; } if (!LayDownWeaponExclusions.ShouldBlockLayDownInstance(__instance, eventToCheck, __instance.data)) { return true; } __result = false; return false; } public static void SetEnterUI_Postfix(object __instance, Unit unit) { if (!((Object)(object)unit == (Object)null) && LayDownRangeLogic.IsLayDownConditionalEvent(((Component)unit).GetComponentInChildren())) { CameraAbilityPossessUI value = Traverse.Create(__instance).Field("possessUI").Value; if ((Object)(object)value?.combatM != (Object)null) { value.combatM.SetActive(false); } } } } internal static class LayDownAttackLogic { public static void AfterSetAttackTarget(Rigidbody targetMainRig, DataHandler unitData, TargetData targetData, bool canSeeTarget, bool startAttack) { //IL_0030: Unknown result type (might be due to invalid IL or missing references) //IL_00a6: 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_00ad: 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) //IL_0099: 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) if ((Object)(object)targetMainRig == (Object)null || (Object)(object)unitData == (Object)null || !startAttack || !StayFixLogic.CanLayDownEngageTarget(unitData) || StayFixLogic.IsLayDownPlayerPossessed(unitData)) { return; } unitData.inRange = true; if (!(targetData.TargetInAttackRange == 1 && canSeeTarget) || !((Object)(object)unitData.unit != (Object)null) || !(unitData.unit.InRangeAttackCooldown <= 0f)) { WeaponHandler component = ((Component)unitData).GetComponent(); if (!((Object)(object)component == (Object)null)) { Vector3 position = (((Object)(object)unitData.torso != (Object)null) ? unitData.torso.position : (((Object)(object)unitData.mainRig != (Object)null) ? unitData.mainRig.position : targetMainRig.position)); LayDownWeaponLogic.TryLayDownAttack(component, position, targetMainRig, Vector3.zero, (ForceWeapon)0); } } } } internal static class LayDownAttackPatches { public static void SetAttackTarget_Prefix(DataHandler unitData, ref TargetData targetData) { if (StayFixLogic.ShouldLayDownAutoFire(unitData)) { unitData.inRange = true; targetData.TargetInAttackRange = 1; } } public static void SetAttackTarget_Postfix(Rigidbody mainRig, DataHandler unitData, TargetData targetData, bool canSeeTarget, bool startAttack) { //IL_0002: Unknown result type (might be due to invalid IL or missing references) LayDownAttackLogic.AfterSetAttackTarget(mainRig, unitData, targetData, canSeeTarget, startAttack); } } internal static class LayDownRangeLogic { private static readonly FieldInfo IsStunnedForField = AccessTools.Field(typeof(ConditionalEvent), "isStunnedFor"); private static readonly FieldInfo GameStateManagerField = AccessTools.Field(typeof(ConditionalEvent), "man"); public static bool IsLayDownConditionalEvent(ConditionalEvent conditionalEvent) { if ((Object)(object)conditionalEvent == (Object)null || !LayDownWeaponExclusions.ConditionalEventHasLayDown(conditionalEvent)) { return false; } return !LayDownWeaponExclusions.IsOnExcludedWeaponHierarchy(((Component)conditionalEvent).transform, conditionalEvent.data); } public static bool EvaluateLayDownDistanceCondition(ConditionalEvent conditionalEvent, EventCondition condition) { //IL_0019: Unknown result type (might be due to invalid IL or missing references) //IL_001f: Invalid comparison between Unknown and I4 //IL_0033: Unknown result type (might be due to invalid IL or missing references) DataHandler val = conditionalEvent?.data; if ((Object)(object)val == (Object)null) { return false; } if ((int)condition.valueType == 1) { if (StayFixLogic.IsTargetWithinWeaponFireRange(val)) { return LayDownAbilityLogic.IsLookingAtEnemy(val); } return false; } if ((int)condition.valueType == 0) { return val.distanceToTarget >= condition.value; } return true; } public static bool PassesConditionalPreamble(ConditionalEvent conditionalEvent, EventCondition condition, ConditionType conditionCall) { //IL_006c: Unknown result type (might be due to invalid IL or missing references) //IL_0072: Invalid comparison between Unknown and I4 DataHandler data = conditionalEvent.data; if ((Object)(object)data == (Object)null) { return false; } if (data.Dead && !conditionalEvent.ignoreDead) { return false; } if (IsStunnedForField?.GetValue(conditionalEvent) is float num && num > 0f) { return false; } object? obj = GameStateManagerField?.GetValue(conditionalEvent); GameStateManager val = (GameStateManager)((obj is GameStateManager) ? obj : null); if (val != null && (int)val.GameState != 1) { return false; } if (condition.ignoreInPossession && (Object)(object)data.input != (Object)null) { _ = data.input.hasControl; return true; } return true; } public static bool FailsTargetHpFailChance(ConditionalEvent conditionalEvent) { DataHandler data = conditionalEvent.data; if ((Object)(object)data == (Object)null || (Object)(object)data.targetData == (Object)null) { return false; } return data.targetData.maxHealth * conditionalEvent.failChancePer100Hp * Random.value * 0.01f > 1f; } public static void IncrementLayDownCooldownCounters(ConditionalEvent conditionalEvent) { //IL_0040: Unknown result type (might be due to invalid IL or missing references) DataHandler data = conditionalEvent.data; if ((Object)(object)data == (Object)null) { return; } ConditionalEventInstance[] events = conditionalEvent.events; if (events == null) { return; } for (int i = 0; i < events.Length; i++) { EventCondition[] array = events[i]?.conditions; if (array == null) { continue; } foreach (EventCondition val in array) { if ((int)val.conditionType == 0) { if (!val.onlyCountWhenUnitInRange) { val.counter += Time.deltaTime; } else if (StayFixLogic.IsTargetWithinWeaponFireRange(data)) { val.counter += Time.deltaTime; } } } } } } internal static class LayDownRangePatches { public static bool CheckCondition_Prefix(ConditionalEvent __instance, EventCondition condition, ConditionalEventInstance eventToCheck, ConditionType conditionCall, bool justCheck, ref bool __result) { //IL_0001: Unknown result type (might be due to invalid IL or missing references) //IL_0007: Invalid comparison between Unknown and I4 //IL_0017: Unknown result type (might be due to invalid IL or missing references) if ((int)condition.conditionType != 1) { return true; } if (!LayDownRangeLogic.IsLayDownConditionalEvent(__instance)) { return true; } if (!LayDownRangeLogic.PassesConditionalPreamble(__instance, condition, conditionCall)) { __result = false; return false; } __result = LayDownRangeLogic.EvaluateLayDownDistanceCondition(__instance, condition); if (__result && LayDownRangeLogic.FailsTargetHpFailChance(__instance)) { __result = false; } return false; } public static bool IncrementCounters_Prefix(ConditionalEvent __instance) { if (!LayDownRangeLogic.IsLayDownConditionalEvent(__instance)) { return true; } LayDownRangeLogic.IncrementLayDownCooldownCounters(__instance); return false; } } internal static class LayDownWeaponExclusions { internal const int Mg42EntityId = 1369807881; internal const int M2BrowningEntityId = 1606594406; private static readonly FieldInfo RightObjectField = AccessTools.Field(typeof(HoldingHandler), "rightObject"); private static readonly FieldInfo LeftObjectField = AccessTools.Field(typeof(HoldingHandler), "leftObject"); internal static bool HasExcludedWeaponEquipped(DataHandler data) { if ((Object)(object)data == (Object)null) { return false; } HoldingHandler component = ((Component)data).GetComponent(); if ((Object)(object)component == (Object)null) { return false; } if (!IsExcludedHoldable(GetHoldable(component, RightObjectField))) { return IsExcludedHoldable(GetHoldable(component, LeftObjectField)); } return true; } internal static bool HasUnitLayDownAbility(DataHandler data) { if ((Object)(object)data == (Object)null) { return false; } ConditionalEvent[] componentsInChildren = ((Component)data).GetComponentsInChildren(); foreach (ConditionalEvent val in componentsInChildren) { if (ConditionalEventHasLayDown(val) && !IsOnExcludedWeaponHierarchy(((Component)val).transform, data)) { return true; } } return false; } internal static bool ShouldBlockLayDownPose(DataHandler data) { if ((Object)(object)data != (Object)null && HasExcludedWeaponEquipped(data)) { return !HasUnitLayDownAbility(data); } return false; } internal static bool ShouldBlockLayDownInstance(ConditionalEvent conditionalEvent, ConditionalEventInstance instance, DataHandler data) { if (instance != null && InstanceHasLayDownMove(instance)) { return IsOnExcludedWeaponHierarchy((conditionalEvent != null) ? ((Component)conditionalEvent).transform : null, data); } return false; } internal static void SuppressBundledLayDownForUnit(DataHandler data) { if ((Object)(object)data == (Object)null) { return; } ConditionalEvent[] componentsInChildren = ((Component)data).GetComponentsInChildren(); foreach (ConditionalEvent val in componentsInChildren) { if (IsOnExcludedWeaponHierarchy(((Component)val).transform, data)) { DisableBuiltInLayDown(val); } } } internal static bool ConditionalEventHasLayDown(ConditionalEvent conditionalEvent) { if ((Object)(object)conditionalEvent == (Object)null) { return false; } if (StayFixLogic.HasLayDownMarkerInHierarchy(((Component)conditionalEvent).transform)) { return true; } ConditionalEventInstance[] events = conditionalEvent.events; if (events == null) { return false; } for (int i = 0; i < events.Length; i++) { if (InstanceHasLayDownMove(events[i])) { return true; } } return false; } internal static bool IsOnExcludedWeaponHierarchy(Transform transform, DataHandler data = null) { if ((Object)(object)transform == (Object)null) { return false; } if (IsExcludedWeaponTransform(transform)) { return true; } if (data == null) { data = ((Component)transform.root).GetComponentInChildren(); } if ((Object)(object)data == (Object)null) { return false; } HoldingHandler component = ((Component)data).GetComponent(); if ((Object)(object)component == (Object)null) { return false; } Holdable holdable = GetHoldable(component, RightObjectField); if (IsExcludedHoldable(holdable) && transform.IsChildOf(((Component)holdable).transform)) { return true; } Holdable holdable2 = GetHoldable(component, LeftObjectField); if (IsExcludedHoldable(holdable2)) { return transform.IsChildOf(((Component)holdable2).transform); } return false; } private static void DisableBuiltInLayDown(ConditionalEvent conditionalEvent) { if (conditionalEvent?.events == null) { return; } for (int i = 0; i < conditionalEvent.events.Length; i++) { ConditionalEventInstance val = conditionalEvent.events[i]; if (val == null || !InstanceHasLayDownMove(val)) { continue; } val.checkAutomatically = false; if (val.isOn) { val.isOn = false; UnityEvent turnOffEvent = val.turnOffEvent; if (turnOffEvent != null) { turnOffEvent.Invoke(); } } } } private static bool InstanceHasLayDownMove(ConditionalEventInstance instance) { Move[] array = instance?.moves; if (array == null) { return false; } for (int i = 0; i < array.Length; i++) { if ((Object)(object)array[i] != (Object)null && StayFixLogic.HasLayDownMarkerInHierarchy(((Component)array[i]).transform)) { return true; } } return false; } private static Holdable GetHoldable(HoldingHandler holding, FieldInfo field) { object? obj = field?.GetValue(holding); return (Holdable)((obj is Holdable) ? obj : null); } private static bool IsExcludedHoldable(Holdable holdable) { //IL_0035: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)holdable == (Object)null) { return false; } if (IsExcludedWeaponTransform(((Component)holdable).transform)) { return true; } WeaponItem component = ((Component)holdable).GetComponent(); if (((component != null) ? ((CharacterItem)component).Entity : null) != null && IsExcludedEntityId(((CharacterItem)component).Entity.GUID.m_ID)) { return true; } Weapon val = ((Component)holdable).GetComponent() ?? ((Component)holdable).GetComponentInChildren(); if ((Object)(object)val != (Object)null) { return IsExcludedWeaponTransform(((Component)val).transform); } return false; } private static bool IsExcludedWeaponTransform(Transform transform) { //IL_0035: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)transform == (Object)null) { return false; } if (IsExcludedWeaponName(((Object)transform).name)) { return true; } WeaponItem component = ((Component)transform).GetComponent(); if (((component != null) ? ((CharacterItem)component).Entity : null) != null) { return IsExcludedEntityId(((CharacterItem)component).Entity.GUID.m_ID); } return false; } private static bool IsExcludedEntityId(int entityId) { if (entityId != 1369807881) { return entityId == 1606594406; } return true; } private static bool IsExcludedWeaponName(string name) { string text = NormalizeWeaponName(name); if (!string.IsNullOrEmpty(text)) { if (!text.Contains("mg42")) { return text.Contains("m2browning"); } return true; } return false; } private static string NormalizeWeaponName(string name) { if (string.IsNullOrEmpty(name)) { return string.Empty; } string text = name; if (text.EndsWith("(Clone)", StringComparison.OrdinalIgnoreCase)) { text = text.Substring(0, text.Length - "(Clone)".Length); } return text.ToLowerInvariant().Replace(" ", string.Empty).Replace("_", string.Empty) .Replace("-", string.Empty); } } internal static class LayDownWeaponLogic { private static readonly FieldInfo WeaponHandlerDataField = AccessTools.Field(typeof(WeaponHandler), "data"); public static void TickLayDownVisibleCombat(DataHandler handler) { //IL_0040: 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) if (!StayFixLogic.CanLayDownEngageTarget(handler)) { return; } handler.inRange = true; if (StayFixLogic.ShouldLayDownAutoFire(handler)) { WeaponHandler component = ((Component)handler).GetComponent(); if (!((Object)(object)component == (Object)null) && !((Object)(object)handler.targetMainRig == (Object)null)) { TryLayDownAttack(component, GetAttackPosition(handler, handler.targetMainRig), handler.targetMainRig, Vector3.zero, (ForceWeapon)0); } } } public static bool TryLayDownAttack(WeaponHandler handler, Vector3 position, Rigidbody targetRig, Vector3 forceDirection, ForceWeapon forceWeapon) { //IL_004f: 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_0060: Unknown result type (might be due to invalid IL or missing references) object? obj = WeaponHandlerDataField?.GetValue(handler); DataHandler val = (DataHandler)((obj is DataHandler) ? obj : null); if ((Object)(object)val == (Object)null || (Object)(object)targetRig == (Object)null || !StayFixLogic.ShouldLayDownAutoFire(val)) { return false; } Unit unit = val.unit; if ((Object)(object)unit == (Object)null || !CanUnitAttackNow(unit)) { return false; } if (!TrySelectReadyWeapon(handler, forceWeapon, out var activeWeapon)) { return false; } ExecuteAttack(handler, activeWeapon, position, targetRig, forceDirection); ApplyUnitAttackCooldown(unit, handler); return true; } public static void TickLayDownWeaponCooldown(Weapon weapon, float attackSpeedMultiplier) { if ((Object)(object)weapon == (Object)null) { return; } float num = (weapon.isRange ? attackSpeedMultiplier : Mathf.Clamp((4f + attackSpeedMultiplier) * 0.2f, 1f, 2f)); if (weapon.countSelf) { for (int i = 0; i < weapon.weaponList.Length; i++) { Weapon obj = weapon.weaponList[i]; obj.internalCounter += Time.deltaTime * num; } } } internal static bool CanUnitAttackNow(Unit unit) { if ((Object)(object)unit == (Object)null || !Object.op_Implicit((Object)(object)unit.WeaponHandler)) { return false; } return unit.attackCounter * unit.WeaponHandler.attackSpeedMultiplier >= unit.lowestAttackTimeOfWeapons / 2f; } private static Vector3 GetAttackPosition(DataHandler data, Rigidbody targetRig) { //IL_0014: 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_002e: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)data.torso != (Object)null) { return data.torso.position; } if ((Object)(object)data.mainRig != (Object)null) { return data.mainRig.position; } return targetRig.position; } private static void ApplyUnitAttackCooldown(Unit unit, WeaponHandler handler) { if (!((Object)(object)unit == (Object)null) && !((Object)(object)handler == (Object)null)) { unit.attackCounter = unit.lowestAttackTimeOfWeapons * Random.Range(-0.2f, 0.2f); } } private static bool TrySelectReadyWeapon(WeaponHandler handler, ForceWeapon forceWeapon, out Weapon activeWeapon) { //IL_006d: Unknown result type (might be due to invalid IL or missing references) activeWeapon = null; if ((Object)(object)handler == (Object)null) { return false; } Weapon leftWeapon = handler.leftWeapon; Weapon rightWeapon = handler.rightWeapon; if (!Object.op_Implicit((Object)(object)leftWeapon) && !Object.op_Implicit((Object)(object)rightWeapon)) { return false; } object? obj = WeaponHandlerDataField?.GetValue(handler); DataHandler val = (DataHandler)((obj is DataHandler) ? obj : null); bool flag = (Object)(object)val?.input != (Object)null && val.input.IsRemotelyControlled; activeWeapon = SelectActiveWeapon(handler, leftWeapon, rightWeapon, forceWeapon, flag); if ((Object)(object)activeWeapon == (Object)null) { return false; } return !activeWeapon.IsOnCooldown() || flag; } private static void ExecuteAttack(WeaponHandler handler, Weapon activeWeapon, Vector3 position, Rigidbody targetRig, Vector3 forceDirection) { //IL_0048: Unknown result type (might be due to invalid IL or missing references) //IL_004a: Unknown result type (might be due to invalid IL or missing references) //IL_0090: Unknown result type (might be due to invalid IL or missing references) //IL_0092: Unknown result type (might be due to invalid IL or missing references) if (activeWeapon.randomCooldown) { activeWeapon.internalCounter = Mathf.Clamp(Random.Range(activeWeapon.internalCooldown * -0.8f, activeWeapon.internalCooldown * 0.2f), -1f, 1f); } else { activeWeapon.internalCounter = 0f; } activeWeapon.Attack(position, targetRig, forceDirection, false); AttackStartedDelegate value = Traverse.Create((object)handler).Field("AttackStarted").Value; if (value != null) { bool flag = (Object)(object)handler.leftWeapon != (Object)null && (Object)(object)activeWeapon == (Object)(object)handler.leftWeapon; value.Invoke(((Component)handler).GetComponentInParent(), position, targetRig, forceDirection, (ForceWeapon)(flag ? 1 : 2)); } } private static Weapon SelectActiveWeapon(WeaponHandler handler, Weapon leftWeapon, Weapon rightWeapon, ForceWeapon forceWeapon, bool isRemotelyControlled) { //IL_00b0: Unknown result type (might be due to invalid IL or missing references) //IL_00b2: Invalid comparison between Unknown and I4 //IL_00b6: Unknown result type (might be due to invalid IL or missing references) //IL_00b8: Invalid comparison between Unknown and I4 Weapon val = ((!Object.op_Implicit((Object)(object)leftWeapon)) ? rightWeapon : (Object.op_Implicit((Object)(object)rightWeapon) ? ((Object.op_Implicit((Object)(object)leftWeapon) && Random.value > 0.5f) ? leftWeapon : rightWeapon) : leftWeapon)); val = ((val != null) ? val.GetBestWeaponOnWeapon() : null); if (Object.op_Implicit((Object)(object)leftWeapon) && Object.op_Implicit((Object)(object)rightWeapon) && !isRemotelyControlled) { Weapon val2 = (((Object)(object)val == (Object)(object)rightWeapon) ? leftWeapon : rightWeapon); if (val.internalCounter < val.internalCooldown) { if (!Object.op_Implicit((Object)(object)val2) || val2.internalCounter <= val2.internalCooldown) { return val; } val = val2; } if (val2.maxRange > val.maxRange && !val2.IsOnCooldown()) { val = val2; } } if (Object.op_Implicit((Object)(object)leftWeapon) && Object.op_Implicit((Object)(object)rightWeapon)) { if ((int)forceWeapon == 1) { val = leftWeapon; } if ((int)forceWeapon == 2) { val = rightWeapon; } } return val; } } internal static class LayDownWeaponPatches { public static bool WeaponHandler_Attack_Prefix(WeaponHandler __instance, Vector3 position, Rigidbody targetRig, Vector3 forceDirection, ForceWeapon forceWeapon) { //IL_0001: 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) //IL_0004: Unknown result type (might be due to invalid IL or missing references) if (LayDownWeaponLogic.TryLayDownAttack(__instance, position, targetRig, forceDirection, forceWeapon)) { return false; } return true; } public static bool Weapon_UpdateCounters_Prefix(Weapon __instance, float attackSpeedMultiplier) { DataHandler connectedData = __instance.connectedData; if ((Object)(object)connectedData == (Object)null || !StayFixLogic.CanLayDownEngageTarget(connectedData)) { return true; } connectedData.inRange = true; if (!__instance.onlyCountInRange) { return true; } LayDownWeaponLogic.TickLayDownWeaponCooldown(__instance, attackSpeedMultiplier); return false; } } internal static class MirrorProjectileCosts { [CompilerGenerated] private sealed class d__10 : IEnumerable, IEnumerable, IEnumerator, IDisposable, IEnumerator { private int <>1__state; private Transform <>2__current; private int <>l__initialThreadId; private GameObject projectile; public GameObject <>3__projectile; private TeamHolder 5__2; private Transform 5__3; Transform IEnumerator.Current { [DebuggerHidden] get { return <>2__current; } } object IEnumerator.Current { [DebuggerHidden] get { return <>2__current; } } [DebuggerHidden] public d__10(int <>1__state) { this.<>1__state = <>1__state; <>l__initialThreadId = Environment.CurrentManagedThreadId; } [DebuggerHidden] void IDisposable.Dispose() { 5__2 = null; 5__3 = null; <>1__state = -2; } private bool MoveNext() { switch (<>1__state) { default: return false; case 0: <>1__state = -1; <>2__current = projectile.transform; <>1__state = 1; return true; case 1: <>1__state = -1; 5__2 = projectile.GetComponent(); if ((Object)(object)5__2?.spawnerWeapon != (Object)null) { <>2__current = 5__2.spawnerWeapon.transform; <>1__state = 2; return true; } goto IL_009c; case 2: <>1__state = -1; goto IL_009c; case 3: <>1__state = -1; goto IL_00dc; case 4: { <>1__state = -1; 5__3 = 5__3.parent; break; } IL_00dc: 5__3 = projectile.transform.parent; break; IL_009c: if ((Object)(object)5__2?.spawner != (Object)null) { <>2__current = 5__2.spawner.transform; <>1__state = 3; return true; } goto IL_00dc; } if ((Object)(object)5__3 != (Object)null) { <>2__current = 5__3; <>1__state = 4; return true; } 5__3 = null; return false; } bool IEnumerator.MoveNext() { //ILSpy generated this explicit interface implementation from .override directive in MoveNext return this.MoveNext(); } [DebuggerHidden] void IEnumerator.Reset() { throw new NotSupportedException(); } [DebuggerHidden] IEnumerator IEnumerable.GetEnumerator() { d__10 d__; if (<>1__state == -2 && <>l__initialThreadId == Environment.CurrentManagedThreadId) { <>1__state = 0; d__ = this; } else { d__ = new d__10(0); } d__.projectile = <>3__projectile; return d__; } [DebuggerHidden] IEnumerator IEnumerable.GetEnumerator() { return ((IEnumerable)this).GetEnumerator(); } } private static readonly int[] DeflectsAllowedByBlockPower = new int[4] { 12, 3, 2, 1 }; internal static int GetReflectCost(GameObject projectile) { int deflectsAllowed = GetDeflectsAllowed(GetBlockPowerTier(projectile)); return Mathf.Max(1, 12 / deflectsAllowed); } internal static int GetBlockPowerTier(GameObject projectile) { if (NameMatchesBallista(projectile)) { return 3; } if (NameMatchesZeus(projectile)) { return 2; } float rawBlockPoweredNeeded = GetRawBlockPoweredNeeded(projectile); if (rawBlockPoweredNeeded >= 2.5f) { return 3; } if (rawBlockPoweredNeeded >= 1.5f) { return 2; } if (rawBlockPoweredNeeded >= 0.5f) { return 1; } if (NameMatchesStandardArrow(projectile)) { return 1; } return 0; } private static float GetRawBlockPoweredNeeded(GameObject projectile) { if ((Object)(object)projectile == (Object)null) { return 1f; } ProjectileHit component = projectile.GetComponent(); if (!((Object)(object)component != (Object)null)) { return 1f; } return component.blockPoweredNeeded; } private static int GetDeflectsAllowed(int blockPower) { if (blockPower < DeflectsAllowedByBlockPower.Length) { return DeflectsAllowedByBlockPower[blockPower]; } return 1; } private static bool NameMatchesStandardArrow(GameObject projectile) { if (NameMatchesBlowdart(projectile)) { return false; } return NameMatchesAny(projectile, "P_Bow", "Crossbow", "Arrow"); } private static bool NameMatchesBlowdart(GameObject projectile) { return NameMatchesAny(projectile, "Blowdart", "BlowDart", "p_Blowdart"); } private static bool NameMatchesBallista(GameObject projectile) { foreach (Transform nameSource in GetNameSources(projectile)) { if (!((Object)(object)nameSource == (Object)null)) { string name = ((Object)nameSource).name; if (name.IndexOf("P_Ballista", StringComparison.OrdinalIgnoreCase) >= 0) { return true; } if (name.IndexOf("BallistaArrow", StringComparison.OrdinalIgnoreCase) >= 0) { return true; } if (name.IndexOf("Ballista", StringComparison.OrdinalIgnoreCase) >= 0 && name.IndexOf("Bolt", StringComparison.OrdinalIgnoreCase) >= 0) { return true; } } } return false; } private static bool NameMatchesZeus(GameObject projectile) { if ((Object)(object)projectile.GetComponent() != (Object)null) { return true; } foreach (Transform nameSource in GetNameSources(projectile)) { if ((Object)(object)nameSource == (Object)null) { continue; } string name = ((Object)nameSource).name; if (name.IndexOf("LightningBow", StringComparison.OrdinalIgnoreCase) < 0) { if (name.IndexOf("P_Zeus", StringComparison.OrdinalIgnoreCase) >= 0) { return true; } if (name.IndexOf("Zeus", StringComparison.OrdinalIgnoreCase) >= 0) { return true; } } } return false; } private static bool NameMatchesAny(GameObject projectile, params string[] needles) { foreach (Transform nameSource in GetNameSources(projectile)) { if ((Object)(object)nameSource == (Object)null) { continue; } string name = ((Object)nameSource).name; for (int i = 0; i < needles.Length; i++) { if (name.IndexOf(needles[i], StringComparison.OrdinalIgnoreCase) >= 0) { return true; } } } return false; } [IteratorStateMachine(typeof(d__10))] private static IEnumerable GetNameSources(GameObject projectile) { //yield-return decompiler failed: Unexpected instruction in Iterator.Dispose() return new d__10(-2) { <>3__projectile = projectile }; } } internal static class MirrorShieldAudio { [CompilerGenerated] private sealed class d__3 : IEnumerator, IDisposable, IEnumerator { private int <>1__state; private object <>2__current; public Transform weaponRoot; object IEnumerator.Current { [DebuggerHidden] get { return <>2__current; } } object IEnumerator.Current { [DebuggerHidden] get { return <>2__current; } } [DebuggerHidden] public d__3(int <>1__state) { this.<>1__state = <>1__state; } [DebuggerHidden] void IDisposable.Dispose() { <>1__state = -2; } private bool MoveNext() { switch (<>1__state) { default: return false; case 0: <>1__state = -1; <>2__current = null; <>1__state = 1; return true; case 1: <>1__state = -1; if ((Object)(object)weaponRoot != (Object)null) { PlayBreakImmediate(weaponRoot); } return false; } } bool IEnumerator.MoveNext() { //ILSpy generated this explicit interface implementation from .override directive in MoveNext return this.MoveNext(); } [DebuggerHidden] void IEnumerator.Reset() { throw new NotSupportedException(); } } private const string BreakSoundRef = "Effects/IceArrowEffect"; private const float BreakSoundVolume = 1.25f; internal static void PlayBreak(Transform weaponRoot) { if (MirrorShieldConfig.Improved && !((Object)(object)weaponRoot == (Object)null)) { if ((Object)(object)Plugin.Instance != (Object)null) { ((MonoBehaviour)Plugin.Instance).StartCoroutine(PlayBreakNextFrame(weaponRoot)); } else { PlayBreakImmediate(weaponRoot); } } } [IteratorStateMachine(typeof(d__3))] private static IEnumerator PlayBreakNextFrame(Transform weaponRoot) { //yield-return decompiler failed: Unexpected instruction in Iterator.Dispose() return new d__3(0) { weaponRoot = weaponRoot }; } private static void PlayBreakImmediate(Transform weaponRoot) { //IL_0011: 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_0051: 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) SoundPlayer service = ServiceLocator.GetService(); if (!((Object)(object)service == (Object)null)) { Vector3 val = ResolveSoundPosition(weaponRoot); AudioPathData val2 = null; if (AudioPathData.ValidateAndAssignPathData("Effects/IceArrowEffect", ref val2, (Object)(object)((Component)weaponRoot).gameObject) && val2 != null) { service.PlaySoundEffectNonAlloc(val2, 1.25f, val, (MaterialType)0, weaponRoot, 1f); } else { service.PlaySoundEffect("Effects/IceArrowEffect", 1.25f, val, (MaterialType)0, weaponRoot, 1f); } } } private static Vector3 ResolveSoundPosition(Transform weaponRoot) { //IL_0017: 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_002e: 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_0036: Unknown result type (might be due to invalid IL or missing references) SurfaceReflect componentInChildren = ((Component)weaponRoot).GetComponentInChildren(true); if ((Object)(object)componentInChildren != (Object)null) { return ((Component)componentInChildren).transform.position; } Renderer componentInChildren2 = ((Component)weaponRoot).GetComponentInChildren(); if ((Object)(object)componentInChildren2 != (Object)null) { Bounds bounds = componentInChildren2.bounds; return ((Bounds)(ref bounds)).center; } return weaponRoot.position; } } internal static class MirrorShieldConfig { internal static bool Improved = true; private static readonly ConfigDefinition[] OrphanedKeys = (ConfigDefinition[])(object)new ConfigDefinition[6] { new ConfigDefinition("Mirror.Shield", "Enabled"), new ConfigDefinition("Mirror.Shield", "BreakSoundEnabled"), new ConfigDefinition("Mirror.Shield", "BreakSoundMode"), new ConfigDefinition("Mirror.Shield", "VanillaBreakSoundRef"), new ConfigDefinition("Mirror.Shield", "CustomBreakSoundFile"), new ConfigDefinition("Mirror.Shield", "BreakSoundVolume") }; internal static void Bind(ConfigFile config) { ConfigDefinition[] orphanedKeys = OrphanedKeys; foreach (ConfigDefinition val in orphanedKeys) { config.Remove(val); } Improved = config.Bind("Mirror.Shield", "Improved", true, "Improved mirror shield (true) or vanilla mirror shield (false).").Value; } } internal static class MirrorShieldLogic { [CompilerGenerated] private sealed class d__26 : IEnumerator, IDisposable, IEnumerator { private int <>1__state; private object <>2__current; public GameObject projectile; public Vector3 velocity; private int 5__2; object IEnumerator.Current { [DebuggerHidden] get { return <>2__current; } } object IEnumerator.Current { [DebuggerHidden] get { return <>2__current; } } [DebuggerHidden] public d__26(int <>1__state) { this.<>1__state = <>1__state; } [DebuggerHidden] void IDisposable.Dispose() { <>1__state = -2; } private bool MoveNext() { //IL_0065: Unknown result type (might be due to invalid IL or missing references) //IL_006a: Unknown result type (might be due to invalid IL or missing references) switch (<>1__state) { default: return false; case 0: <>1__state = -1; 5__2 = 0; break; case 1: <>1__state = -1; 5__2++; break; } if (5__2 < 4) { if ((Object)(object)projectile == (Object)null) { return false; } MoveTransform component = projectile.GetComponent(); if ((Object)(object)component != (Object)null && ((Vector3)(ref component.velocity)).sqrMagnitude < ((Vector3)(ref velocity)).sqrMagnitude * 0.25f) { component.velocity = velocity; } <>2__current = null; <>1__state = 1; return true; } return false; } bool IEnumerator.MoveNext() { //ILSpy generated this explicit interface implementation from .override directive in MoveNext return this.MoveNext(); } [DebuggerHidden] void IEnumerator.Reset() { throw new NotSupportedException(); } } internal const int MaxReflects = 12; private static readonly Dictionary RemainingReflectsByWeaponKey = new Dictionary(); private static readonly HashSet HandledProjectileIdsThisFrame = new HashSet(); private static readonly FieldInfo CurrentProjectilesPerBlockField = typeof(BlockMove).GetField("currentProjectilesPerBlock", BindingFlags.Instance | BindingFlags.NonPublic); private static readonly FieldInfo BlockMoveDataField = typeof(BlockMove).GetField("data", BindingFlags.Instance | BindingFlags.NonPublic); private static readonly FieldInfo ProjectileHitCounterField = typeof(ProjectileHit).GetField("counter", BindingFlags.Instance | BindingFlags.NonPublic); private static int _handledProjectileFrame = -1; internal static void ResetBattleState() { RemainingReflectsByWeaponKey.Clear(); HandledProjectileIdsThisFrame.Clear(); MirrorShieldVfx.ResetBattleState(); _handledProjectileFrame = -1; } internal static bool IsMirrorWeapon(Transform transform) { if (!MirrorShieldConfig.Improved || (Object)(object)transform == (Object)null) { return false; } Holdable componentInParent = ((Component)transform).GetComponentInParent(); if ((Object)(object)componentInParent != (Object)null) { if ((Object)(object)((Component)componentInParent).GetComponentInChildren(true) != (Object)null) { return true; } Transform[] componentsInChildren = ((Component)componentInParent).GetComponentsInChildren(true); for (int i = 0; i < componentsInChildren.Length; i++) { if (((Object)componentsInChildren[i]).name.IndexOf("Mirror", StringComparison.OrdinalIgnoreCase) >= 0) { return true; } } } if ((Object)(object)((Component)transform).GetComponentInParent() != (Object)null) { return true; } Transform val = transform; while ((Object)(object)val != (Object)null) { if (((Object)val).name.IndexOf("Mirror", StringComparison.OrdinalIgnoreCase) >= 0) { return true; } val = val.parent; } return false; } internal static bool TryInterceptProjectileHit(Transform hitTransform, GameObject projectile, HitData hit) { if (!MirrorShieldConfig.Improved || (Object)(object)hitTransform == (Object)null || (Object)(object)projectile == (Object)null || !IsMirrorWeapon(hitTransform)) { return false; } Transform mirrorWeaponRoot = GetMirrorWeaponRoot(hitTransform); if (!HasReflectsRemaining(mirrorWeaponRoot)) { return false; } BlockMove block = ResolveBlockMoveFromHit(hitTransform); if (ShouldSkipMirrorReflect(projectile, hitTransform, block) || !CanAffordReflect(mirrorWeaponRoot, projectile)) { return false; } ProcessMirrorHit(mirrorWeaponRoot, block, projectile, hit); return true; } internal static void ApplyMirrorSurfaceResult(Transform owner, BlockMove block, GameObject projectile, HitData hit, out bool surfaceHandled) { surfaceHandled = false; if (MirrorShieldConfig.Improved) { Transform mirrorWeaponRoot = GetMirrorWeaponRoot(owner); if (HasReflectsRemaining(mirrorWeaponRoot) && !ShouldSkipMirrorReflect(projectile, owner, block) && CanAffordReflect(mirrorWeaponRoot, projectile)) { ProcessMirrorHit(mirrorWeaponRoot, block, projectile, hit); surfaceHandled = true; } } } internal static bool CanAffordReflect(Transform weaponRoot, GameObject projectile) { return GetRemainingReflects(weaponRoot) >= MirrorProjectileCosts.GetReflectCost(projectile); } internal static bool HasReflectsRemaining(Transform transform) { if (IsMirrorWeapon(transform)) { return GetRemainingReflects(transform) > 0; } return true; } internal static bool ShouldBlockDisable(BlockMove block) { if ((Object)(object)block != (Object)null && IsMirrorWeapon(((Component)block).transform)) { return HasReflectsRemaining(GetMirrorWeaponRoot(((Component)block).transform)); } return false; } internal static bool WasProjectileHandledThisFrame(GameObject projectile) { return WasAlreadyHandledThisFrame(projectile); } internal static BlockMove ResolveBlockMove(Component surfaceComponent) { if ((Object)(object)surfaceComponent == (Object)null) { return null; } SurfaceBlock val = (SurfaceBlock)(object)((surfaceComponent is SurfaceBlock) ? surfaceComponent : null); if (val != null && (Object)(object)val.blockMove != (Object)null) { return val.blockMove; } return surfaceComponent.GetComponentInParent() ?? surfaceComponent.GetComponentInChildren(); } private static void ProcessMirrorHit(Transform weaponRoot, BlockMove block, GameObject projectile, HitData hit) { TryInitialize(weaponRoot); if (WasAlreadyHandledThisFrame(projectile)) { return; } if ((Object)(object)block != (Object)null && !block.isActive) { block.SetEnabled(); } if (!ShouldSkipMirrorReflect(projectile, weaponRoot, block)) { int reflectCost = MirrorProjectileCosts.GetReflectCost(projectile); if (GetRemainingReflects(weaponRoot) >= reflectCost) { MarkHandledThisFrame(projectile); ReflectAndSpendCharge(weaponRoot, block, projectile, hit, reflectCost); } } } private static void TryInitialize(Transform weaponRoot) { int weaponKey = GetWeaponKey(weaponRoot); if (!RemainingReflectsByWeaponKey.ContainsKey(weaponKey)) { RemainingReflectsByWeaponKey[weaponKey] = 12; SyncVanillaBlockCounters(weaponRoot); MirrorShieldVfx.Bind(weaponRoot); } } private static void SyncVanillaBlockCounters(Transform weaponRoot) { SurfaceReflect[] componentsInParent = ((Component)weaponRoot).GetComponentsInParent(true); foreach (SurfaceReflect val in componentsInParent) { if (IsMirrorWeapon(((Component)val).transform)) { ((Behaviour)val).enabled = true; } } BlockMove[] componentsInParent2 = ((Component)weaponRoot).GetComponentsInParent(true); foreach (BlockMove val2 in componentsInParent2) { if (IsMirrorWeapon(((Component)val2).transform)) { val2.projectilesPerBlock = 12; val2.blockPower = 12f; CurrentProjectilesPerBlockField?.SetValue(val2, 12); if (!val2.isActive) { val2.SetEnabled(); } Counter component = ((Component)val2).GetComponent(); if ((Object)(object)component != (Object)null) { component.cooldown = 0f; } } } } private static void ReflectAndSpendCharge(Transform weaponRoot, BlockMove block, GameObject projectile, HitData hit, int cost) { ApplyReflect(weaponRoot, block, projectile, hit); PlayHitFeedback(weaponRoot, hit); SpendReflectCharge(weaponRoot, cost); } private static void PlayHitFeedback(Transform weaponRoot, HitData hit) { //IL_0012: Unknown result type (might be due to invalid IL or missing references) ShieldWobble componentInParent = ((Component)weaponRoot).GetComponentInParent(); if ((Object)(object)componentInParent != (Object)null) { componentInParent.OnHit(hit.point); } MirrorShieldVfx.PlayBlockHit(weaponRoot, hit); } private static void ApplyReflect(Transform weaponRoot, BlockMove block, GameObject projectile, HitData hit) { //IL_00b9: Unknown result type (might be due to invalid IL or missing references) //IL_0098: Unknown result type (might be due to invalid IL or missing references) //IL_009e: Unknown result type (might be due to invalid IL or missing references) //IL_00a8: Unknown result type (might be due to invalid IL or missing references) //IL_00ad: Unknown result type (might be due to invalid IL or missing references) MoveTransform component = projectile.GetComponent(); if (!((Object)(object)component == (Object)null)) { if ((Object)(object)((Component)weaponRoot).GetComponentInChildren(true) != (Object)null) { FlipVelocity(component); } else if ((Object)(object)block != (Object)null && block.reflect) { ReflectOffBlock(block, component, hit); } else { FlipVelocity(component); } ApplyTeamAfterReflect(block, projectile, weaponRoot); ProjectileHit component2 = projectile.GetComponent(); if ((Object)(object)component2 != (Object)null) { component2.canHitOrgUnit = true; } RaycastTrail component3 = projectile.GetComponent(); if ((Object)(object)component3 != (Object)null) { component3.ignoredFrames = 5; } if (((Vector3)(ref hit.normal)).sqrMagnitude > 0.0001f) { projectile.transform.position = hit.point + hit.normal * 0.15f; } EnforceReflectVelocity(projectile, component.velocity); } } private static void FlipVelocity(MoveTransform moveTransform) { //IL_0030: 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_003f: 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_0014: Unknown result type (might be due to invalid IL or missing references) //IL_001e: Unknown result type (might be due to invalid IL or missing references) //IL_0023: Unknown result type (might be due to invalid IL or missing references) if (((Vector3)(ref moveTransform.velocity)).sqrMagnitude > 0.0001f) { moveTransform.velocity *= -1f; } else { moveTransform.velocity = -((Component)moveTransform).transform.forward * 15f; } } private static void ReflectOffBlock(BlockMove block, MoveTransform moveTransform, HitData hit) { //IL_001a: Unknown result type (might be due to invalid IL or missing references) //IL_0012: 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_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_0034: 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_003a: 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_0072: 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_0077: Unknown result type (might be due to invalid IL or missing references) //IL_007b: Unknown result type (might be due to invalid IL or missing references) //IL_0080: Unknown result type (might be due to invalid IL or missing references) //IL_008a: Unknown result type (might be due to invalid IL or missing references) //IL_008f: Unknown result type (might be due to invalid IL or missing references) Vector3 val = ((((Vector3)(ref hit.normal)).sqrMagnitude > 0.0001f) ? hit.normal : Vector3.up); if (((Vector3)(ref moveTransform.velocity)).sqrMagnitude > 0.0001f) { moveTransform.velocity = Vector3.Reflect(moveTransform.velocity, val); return; } Vector3 forward = ((Component)moveTransform).transform.forward; Vector3 val2 = ((((Vector3)(ref forward)).sqrMagnitude > 0.0001f) ? ((Component)moveTransform).transform.forward : ((Component)block).transform.forward); moveTransform.velocity = -((Vector3)(ref val2)).normalized * 15f; } private static void ApplyTeamAfterReflect(BlockMove block, GameObject projectile, Transform weaponRoot) { //IL_004c: Unknown result type (might be due to invalid IL or missing references) //IL_0051: Unknown result type (might be due to invalid IL or missing references) TeamHolder component = projectile.GetComponent(); if ((Object)(object)component == (Object)null) { return; } if ((Object)(object)block != (Object)null && block.switchTeam) { DataHandler componentInChildren = ((Component)weaponRoot.root).GetComponentInChildren(); if ((Object)(object)componentInChildren != (Object)null && (Object)(object)componentInChildren.unit != (Object)null) { component.team = componentInChildren.unit.Team; } } else { component.SwitchTeam(); } } private static void EnforceReflectVelocity(GameObject projectile, Vector3 velocity) { //IL_0022: Unknown result type (might be due to invalid IL or missing references) if (!((Object)(object)Plugin.Instance == (Object)null) && !(((Vector3)(ref velocity)).sqrMagnitude < 0.01f)) { ((MonoBehaviour)Plugin.Instance).StartCoroutine(EnforceReflectVelocityRoutine(projectile, velocity)); } } [IteratorStateMachine(typeof(d__26))] private static IEnumerator EnforceReflectVelocityRoutine(GameObject projectile, Vector3 velocity) { //IL_000e: Unknown result type (might be due to invalid IL or missing references) //IL_000f: Unknown result type (might be due to invalid IL or missing references) //yield-return decompiler failed: Unexpected instruction in Iterator.Dispose() return new d__26(0) { projectile = projectile, velocity = velocity }; } private static void SpendReflectCharge(Transform weaponRoot, int cost) { int weaponKey = GetWeaponKey(weaponRoot); RemainingReflectsByWeaponKey[weaponKey] = Mathf.Max(0, GetRemainingReflects(weaponRoot) - Mathf.Max(1, cost)); if (GetRemainingReflects(weaponRoot) <= 0) { MirrorShieldAudio.PlayBreak(weaponRoot); } } internal static bool ShouldSkipMirrorReflect(GameObject projectile, Transform hitOnMirror, BlockMove block = null) { //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) if ((Object)(object)projectile == (Object)null || (Object)(object)hitOnMirror == (Object)null) { return false; } TeamHolder component = projectile.GetComponent(); if ((Object)(object)component == (Object)null) { return false; } GameObject gameObject = ((Component)hitOnMirror.root).gameObject; if ((Object)(object)component.spawner != (Object)null && (Object)(object)component.spawner == (Object)(object)gameObject) { return true; } Team? defenderTeam = GetDefenderTeam(hitOnMirror, block); if (!defenderTeam.HasValue) { return false; } return defenderTeam.Value == component.team; } internal static bool ProjectileHitWouldIgnoreTeamMate(ProjectileHit projectileHit, HitData hit) { //IL_00c6: Unknown result type (might be due to invalid IL or missing references) //IL_00cc: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)projectileHit == (Object)null || (Object)(object)hit.transform == (Object)null) { return false; } TeamHolder component = ((Component)projectileHit).GetComponent(); if ((Object)(object)component == (Object)null) { return false; } if ((Object)(object)component.spawner != (Object)null && (Object)(object)((Component)hit.transform.root).gameObject == (Object)(object)component.spawner && !projectileHit.canHitOrgUnit) { return true; } Unit component2 = ((Component)hit.transform.root).GetComponent(); MoveTransform component3 = ((Component)projectileHit).GetComponent(); if ((Object)(object)component2 == (Object)null || (Object)(object)component3 == (Object)null) { return false; } bool flag = false; if (ProjectileHitCounterField != null) { flag = (float)ProjectileHitCounterField.GetValue(projectileHit) * 0.01f * ((Vector3)(ref component3.velocity)).magnitude < 0.1f; } if (component.team == component2.Team && (flag || projectileHit.ignoreTeamMates)) { return !projectileHit.alwaysHitTeamMates; } return false; } private static Team? GetDefenderTeam(Transform hitOnMirror, BlockMove block) { //IL_0065: Unknown result type (might be due to invalid IL or missing references) //IL_0094: 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) if ((Object)(object)block != (Object)null && BlockMoveDataField != null) { object? value = BlockMoveDataField.GetValue(block); DataHandler val = (DataHandler)((value is DataHandler) ? value : null); if ((Object)(object)val != (Object)null && (Object)(object)val.unit != (Object)null) { return val.unit.Team; } } Unit component = ((Component)hitOnMirror.root).GetComponent(); if ((Object)(object)component != (Object)null) { return component.Team; } DataHandler componentInParent = ((Component)hitOnMirror).GetComponentInParent(); if ((Object)(object)componentInParent != (Object)null && (Object)(object)componentInParent.unit != (Object)null) { return componentInParent.unit.Team; } return null; } internal static BlockMove ResolveBlockMoveFromHit(Transform hitTransform) { return ((Component)hitTransform).GetComponentInParent(); } internal static Transform GetMirrorWeaponRoot(Transform hitTransform) { Holdable componentInParent = ((Component)hitTransform).GetComponentInParent(); if (!((Object)(object)componentInParent != (Object)null)) { return hitTransform.root; } return ((Component)componentInParent).transform; } private static bool WasAlreadyHandledThisFrame(GameObject projectile) { if (_handledProjectileFrame != Time.frameCount) { _handledProjectileFrame = Time.frameCount; HandledProjectileIdsThisFrame.Clear(); } return HandledProjectileIdsThisFrame.Contains(((Object)projectile).GetInstanceID()); } private static void MarkHandledThisFrame(GameObject projectile) { if (_handledProjectileFrame != Time.frameCount) { _handledProjectileFrame = Time.frameCount; HandledProjectileIdsThisFrame.Clear(); } HandledProjectileIdsThisFrame.Add(((Object)projectile).GetInstanceID()); } private static int GetRemainingReflects(Transform transform) { Transform mirrorWeaponRoot = GetMirrorWeaponRoot(transform); int weaponKey = GetWeaponKey(mirrorWeaponRoot); if (RemainingReflectsByWeaponKey.TryGetValue(weaponKey, out var value)) { return value; } TryInitialize(mirrorWeaponRoot); return 12; } private static int GetWeaponKey(Transform transform) { return ((Object)GetMirrorWeaponRoot(transform)).GetInstanceID(); } } internal static class MirrorShieldPatches { private static bool PassThrough => !MirrorShieldConfig.Improved; public static bool ProjectileHit_Hit_Prefix(ProjectileHit __instance, RaycastHit sentHit, float multiplier) { //IL_005c: 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_006f: Unknown result type (might be due to invalid IL or missing references) //IL_0075: Expected O, but got Unknown if (PassThrough || __instance.done) { return true; } Transform val = (((Object)(object)((RaycastHit)(ref sentHit)).rigidbody != (Object)null) ? ((Component)((RaycastHit)(ref sentHit)).rigidbody).transform : ((Component)((RaycastHit)(ref sentHit)).collider).transform); if (!MirrorShieldLogic.IsMirrorWeapon(val)) { return true; } HitData hit = new HitData(((RaycastHit)(ref sentHit)).transform, ((RaycastHit)(ref sentHit)).rigidbody, ((RaycastHit)(ref sentHit)).collider, ((RaycastHit)(ref sentHit)).normal, ((RaycastHit)(ref sentHit)).point, ((RaycastHit)(ref sentHit)).distance); BlockMove block = MirrorShieldLogic.ResolveBlockMoveFromHit(val); if (MirrorShieldLogic.ShouldSkipMirrorReflect(((Component)__instance).gameObject, val, block) || MirrorShieldLogic.ProjectileHitWouldIgnoreTeamMate(__instance, hit)) { return true; } return !MirrorShieldLogic.TryInterceptProjectileHit(val, ((Component)__instance).gameObject, hit); } public static bool SurfaceBlock_DoEffect_Prefix(SurfaceBlock __instance, HitData hit, GameObject projectile, ref bool __result) { if (PassThrough || !MirrorShieldLogic.IsMirrorWeapon(((Component)__instance).transform)) { return true; } BlockMove val = MirrorShieldLogic.ResolveBlockMove((Component)(object)__instance); if ((Object)(object)val == (Object)null) { return true; } if (MirrorShieldLogic.ShouldSkipMirrorReflect(projectile, ((Component)__instance).transform, val)) { __result = true; return false; } MirrorShieldLogic.ApplyMirrorSurfaceResult(((Component)__instance).transform, val, projectile, hit, out __result); return false; } public static bool SurfaceReflect_DoEffect_Prefix(SurfaceReflect __instance, HitData hit, GameObject projectile, ref bool __result) { if (PassThrough || !MirrorShieldLogic.IsMirrorWeapon(((Component)__instance).transform)) { return true; } BlockMove block = MirrorShieldLogic.ResolveBlockMove((Component)(object)__instance); if (MirrorShieldLogic.ShouldSkipMirrorReflect(projectile, ((Component)__instance).transform, block)) { __result = true; return false; } MirrorShieldLogic.ApplyMirrorSurfaceResult(((Component)__instance).transform, block, projectile, hit, out __result); return false; } public static bool BlockMove_ProjectileBlock_Prefix(BlockMove __instance, GameObject projectile, HitData hit, ref bool __result) { if (PassThrough || !MirrorShieldLogic.IsMirrorWeapon(((Component)__instance).transform)) { return true; } if (MirrorShieldLogic.ShouldSkipMirrorReflect(projectile, ((Component)__instance).transform, __instance)) { return true; } if (!MirrorShieldLogic.HasReflectsRemaining(((Component)__instance).transform)) { return true; } MirrorShieldLogic.ApplyMirrorSurfaceResult(((Component)__instance).transform, __instance, projectile, hit, out __result); return false; } public static bool BlockMove_SetDisabled_Prefix(BlockMove __instance) { if (PassThrough) { return true; } return !MirrorShieldLogic.ShouldBlockDisable(__instance); } public static bool BlockMoveHealth_DoBlock_Prefix(BlockMoveHealth __instance) { if (PassThrough) { return true; } return !MirrorShieldLogic.IsMirrorWeapon(((Component)__instance).transform); } public static bool Charges_UseCharge_Prefix(Charges __instance) { if (PassThrough) { return true; } return !MirrorShieldLogic.IsMirrorWeapon(((Component)__instance).transform); } public static void RaycastTrail_Check_Prefix(RaycastTrail __instance) { if (!PassThrough) { MirrorShieldSweep.TrySweepAhead(__instance); } } } internal static class MirrorShieldSweep { private const float MinCastRadius = 0.07f; private const float SpeedRadiusScale = 0.4f; private const float SpeedDistanceScale = 2f; private const float MinExtraCastDistance = 0.35f; private static readonly FieldInfo RaycastTrailLastPosField = typeof(RaycastTrail).GetField("lastPos", BindingFlags.Instance | BindingFlags.NonPublic); internal static void TrySweepAhead(RaycastTrail trail) { //IL_005b: 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_0067: Unknown result type (might be due to invalid IL or missing references) //IL_006c: Unknown result type (might be due to invalid IL or missing references) //IL_006d: 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_00ba: Unknown result type (might be due to invalid IL or missing references) //IL_00bd: 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_0125: Unknown result type (might be due to invalid IL or missing references) //IL_0128: Unknown result type (might be due to invalid IL or missing references) //IL_012d: Unknown result type (might be due to invalid IL or missing references) //IL_0168: Unknown result type (might be due to invalid IL or missing references) //IL_016d: Unknown result type (might be due to invalid IL or missing references) //IL_020c: Unknown result type (might be due to invalid IL or missing references) //IL_0211: Unknown result type (might be due to invalid IL or missing references) //IL_022a: Unknown result type (might be due to invalid IL or missing references) //IL_0231: Unknown result type (might be due to invalid IL or missing references) //IL_023d: Unknown result type (might be due to invalid IL or missing references) //IL_0244: Expected O, but got Unknown //IL_025d: Unknown result type (might be due to invalid IL or missing references) //IL_0264: Unknown result type (might be due to invalid IL or missing references) //IL_026e: Unknown result type (might be due to invalid IL or missing references) //IL_0273: Unknown result type (might be due to invalid IL or missing references) //IL_0278: Unknown result type (might be due to invalid IL or missing references) //IL_0280: Unknown result type (might be due to invalid IL or missing references) //IL_028d: Unknown result type (might be due to invalid IL or missing references) //IL_01e8: Unknown result type (might be due to invalid IL or missing references) if (!MirrorShieldConfig.Improved || (Object)(object)trail == (Object)null || trail.ignoredFrames > 0 || RaycastTrailLastPosField == null) { return; } ProjectileHit component = ((Component)trail).GetComponent(); if ((Object)(object)component == (Object)null || component.done) { return; } GameObject gameObject = ((Component)component).gameObject; if (MirrorShieldLogic.WasProjectileHandledThisFrame(gameObject)) { return; } Vector3 val = (Vector3)RaycastTrailLastPosField.GetValue(trail); Vector3 val2 = ((Component)trail).transform.position - val; float magnitude = ((Vector3)(ref val2)).magnitude; if (magnitude < 0.0001f) { return; } MoveTransform component2 = gameObject.GetComponent(); float num = (((Object)(object)component2 != (Object)null) ? ((Vector3)(ref component2.velocity)).magnitude : (magnitude / Mathf.Max(Time.deltaTime, 0.001f))); Vector3 val3 = val2 / magnitude; float num2 = (trail.useSphereCastOnUnits ? (Mathf.Max(trail.radius, 0.07f) + num * Time.deltaTime * 0.4f) : (0.07f + num * Time.deltaTime * 0.4f * 0.5f)); float num3 = magnitude + num * Time.deltaTime * 2f + num2 + 0.35f; RaycastHit[] array = Physics.SphereCastAll(val, num2, val3, num3, LayerMask.op_Implicit(trail.mask), (QueryTriggerInteraction)1); if (array == null || array.Length == 0) { return; } RaycastHit? val4 = null; float num4 = float.MaxValue; RaycastHit[] array2 = array; for (int i = 0; i < array2.Length; i++) { RaycastHit value = array2[i]; if (!((Object)(object)((RaycastHit)(ref value)).collider == (Object)null) && MirrorShieldLogic.IsMirrorWeapon(((Component)((RaycastHit)(ref value)).collider).transform)) { Transform mirrorWeaponRoot = MirrorShieldLogic.GetMirrorWeaponRoot(((Component)((RaycastHit)(ref value)).collider).transform); BlockMove block = MirrorShieldLogic.ResolveBlockMoveFromHit(((Component)((RaycastHit)(ref value)).collider).transform); if (MirrorShieldLogic.HasReflectsRemaining(mirrorWeaponRoot) && !MirrorShieldLogic.ShouldSkipMirrorReflect(gameObject, ((Component)((RaycastHit)(ref value)).collider).transform, block) && !(((RaycastHit)(ref value)).distance >= num4)) { num4 = ((RaycastHit)(ref value)).distance; val4 = value; } } } if (val4.HasValue) { RaycastHit value2 = val4.Value; HitData hit = new HitData(((RaycastHit)(ref value2)).transform, ((RaycastHit)(ref value2)).rigidbody, ((RaycastHit)(ref value2)).collider, ((RaycastHit)(ref value2)).normal, ((RaycastHit)(ref value2)).point, ((RaycastHit)(ref value2)).distance); if (MirrorShieldLogic.TryInterceptProjectileHit(((Component)((RaycastHit)(ref value2)).collider).transform, gameObject, hit)) { Vector3 val5 = ((RaycastHit)(ref value2)).point + ((RaycastHit)(ref value2)).normal * 0.15f; ((Component)trail).transform.position = val5; RaycastTrailLastPosField.SetValue(trail, val5); } } } } internal static class MirrorShieldVfx { private sealed class WeaponVfx { internal ParticleSystem[] HitParticles = Array.Empty(); internal SurfaceReflect SurfaceReflect; } private const int HitEmitCount = 10; private const float ReflectPartForwardOffset = 0.4f; private static readonly Dictionary CacheByWeaponKey = new Dictionary(); internal static void ResetBattleState() { CacheByWeaponKey.Clear(); } internal static void Bind(Transform weaponRoot) { //IL_0086: 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) if ((Object)(object)weaponRoot == (Object)null || !MirrorShieldLogic.IsMirrorWeapon(weaponRoot)) { return; } int instanceID = ((Object)weaponRoot).GetInstanceID(); if (CacheByWeaponKey.ContainsKey(instanceID)) { return; } SurfaceReflect componentInChildren = ((Component)weaponRoot).GetComponentInChildren(true); ParticleSystem val = (((Object)(object)componentInChildren != (Object)null) ? componentInChildren.part : null); List list = new List(); ParticleSystem[] componentsInChildren = ((Component)weaponRoot).GetComponentsInChildren(true); foreach (ParticleSystem val2 in componentsInChildren) { if ((Object)(object)val2 == (Object)null) { continue; } if ((Object)(object)val != (Object)null && (Object)(object)val2 == (Object)(object)val) { list.Add(val2); continue; } MainModule main = val2.main; if (!((MainModule)(ref main)).loop) { list.Add(val2); } } if ((Object)(object)val != (Object)null && !list.Contains(val)) { list.Add(val); } CacheByWeaponKey[instanceID] = new WeaponVfx { SurfaceReflect = componentInChildren, HitParticles = list.ToArray() }; } internal static void PlayBlockHit(Transform weaponRoot, HitData hit) { //IL_0037: Unknown result type (might be due to invalid IL or missing references) //IL_003c: 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_0047: 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) //IL_0057: Unknown result type (might be due to invalid IL or missing references) //IL_0078: Unknown result type (might be due to invalid IL or missing references) if (!MirrorShieldConfig.Improved || (Object)(object)weaponRoot == (Object)null) { return; } WeaponVfx orBind = GetOrBind(weaponRoot); Transform reflectTransform = (((Object)(object)orBind.SurfaceReflect != (Object)null) ? ((Component)orBind.SurfaceReflect).transform : null); Vector3 position = ResolveEmitPosition(hit, reflectTransform); EmitParams val = default(EmitParams); ((EmitParams)(ref val)).position = position; ((EmitParams)(ref val)).applyShapeToPosition = true; EmitParams val2 = val; ParticleSystem[] hitParticles = orBind.HitParticles; foreach (ParticleSystem val3 in hitParticles) { if (!((Object)(object)val3 == (Object)null)) { val3.Emit(val2, 10); } } } private static WeaponVfx GetOrBind(Transform weaponRoot) { int instanceID = ((Object)weaponRoot).GetInstanceID(); if (!CacheByWeaponKey.TryGetValue(instanceID, out var value)) { Bind(weaponRoot); CacheByWeaponKey.TryGetValue(instanceID, out value); } return value; } private static Vector3 ResolveEmitPosition(HitData hit, Transform reflectTransform) { //IL_000a: 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_001a: 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_0054: 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_003e: 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) if ((Object)(object)reflectTransform != (Object)null) { return hit.point + reflectTransform.forward * 0.4f; } if (((Vector3)(ref hit.normal)).sqrMagnitude > 0.0001f) { return hit.point + hit.normal * 0.15f; } return hit.point; } } internal static class ModInfo { public const string Author = "Pretz"; public const string PluginGuid = "pretz.staycombatfix"; public const string PluginName = "Stay & Combat Fixes"; public const string Version = "1.1.0"; public const int PatchCount = 49; } public static class ModMain { public static void Register() { } public static void load() { } public static void Load() { } public static void init() { } public static void Init() { } public static void Awake() { } public static void Start() { } } [BepInPlugin("pretz.staycombatfix", "Stay & Combat Fixes", "1.1.0")] public class Plugin : BaseUnityPlugin { internal static Plugin Instance { get; private set; } private void Awake() { //IL_0043: Unknown result type (might be due to invalid IL or missing references) //IL_0049: Expected O, but got Unknown Instance = this; ModMain.Register(); BarrelRollerDeathLogic.Initialize((MonoBehaviour)(object)this, ((BaseUnityPlugin)this).Logger); WaterConfig.Bind(((BaseUnityPlugin)this).Config); MirrorShieldConfig.Bind(((BaseUnityPlugin)this).Config); WaterPatches.LogInfo = delegate(string message) { ((BaseUnityPlugin)this).Logger.LogInfo((object)message); }; Harmony harmony = new Harmony("pretz.staycombatfix"); int num = 0; num += Patch(harmony, AccessTools.Method(typeof(UnitDontWalkFor), "Go", (Type[])null, (Type[])null), typeof(StayPatches), "UnitDontWalkFor_Go_Prefix", "UnitDontWalkFor_Go_Postfix"); num += Patch(harmony, AccessTools.Method(typeof(PoseHandler), "PlayAnimation", new Type[3] { typeof(StaticAnimation), typeof(Vector3), typeof(Quaternion) }, (Type[])null), typeof(StayPatches), "PoseHandler_PlayAnimation_Prefix"); num += Patch(harmony, AccessTools.Method(typeof(DataHandler), "DontWalkFor", (Type[])null, (Type[])null), typeof(StayPatches), "DataHandler_DontWalkFor_Prefix", "DataHandler_DontWalkFor_Postfix"); num += Patch(harmony, AccessTools.Method(typeof(DataHandler), "BatchedUpdate", (Type[])null, (Type[])null), typeof(StayPatches), "DataHandler_BatchedUpdate_Prefix", "DataHandler_BatchedUpdate_Postfix"); num += Patch(harmony, AccessTools.Method(typeof(DataHandler), "BatchedFixedUpdate", (Type[])null, (Type[])null), typeof(StayPatches), null, "DataHandler_BatchedFixedUpdate_Postfix"); num += Patch(harmony, AccessTools.PropertySetter(typeof(DataHandler), "Dead"), typeof(StayPatches), null, "DataHandler_Dead_Setter_Postfix"); num += Patch(harmony, AccessTools.Method(typeof(Rigidbody), "MovePosition", new Type[1] { typeof(Vector3) }, (Type[])null), typeof(StayPhysicsPatches), "Rigidbody_MovePosition_Prefix"); num += Patch(harmony, AccessTools.Method(typeof(HoldingHandler), "AddForce", (Type[])null, (Type[])null), typeof(WeaponStayPatches), "HoldingHandler_AddForce_Prefix"); num += Patch(harmony, AccessTools.DeclaredMethod(typeof(HoldingHandler), "DoPID", new Type[3] { typeof(PidDataInstance), typeof(HoldableDataInstance), typeof(float) }, (Type[])null), typeof(WeaponStayPatches), "HoldingHandler_DoPID_Prefix"); num += Patch(harmony, AccessTools.Method(typeof(HoldingHandler), "BatchedFixedUpdate", (Type[])null, (Type[])null), typeof(WeaponStayPatches), null, "HoldingHandler_BatchedFixedUpdate_Postfix"); num += Patch(harmony, AccessTools.Method(typeof(Holdable), "BatchedUpdate", (Type[])null, (Type[])null), typeof(WeaponStayPatches), "Holdable_BatchedUpdate_Prefix", "Holdable_BatchedUpdate_Postfix"); num += Patch(harmony, AccessTools.Method(typeof(Explosion), "Explode", (Type[])null, (Type[])null), typeof(BarrelRollerDeathPatches), "Explosion_Explode_Prefix"); num += Patch(harmony, AccessTools.Method(typeof(KillAfterSeconds), "Spawn", (Type[])null, (Type[])null), typeof(BarrelRollerDeathPatches), null, "KillAfterSeconds_Spawn_Postfix"); Type type = AccessTools.TypeByName("RemoveAfterSeconds"); if (type != null) { num += Patch(harmony, AccessTools.Method(type, "TriggerRemoval", (Type[])null, (Type[])null), typeof(BarrelRollerDeathPatches), null, "RemoveAfterSeconds_TriggerRemoval_Postfix"); } num += Patch(harmony, AccessTools.Method(typeof(DelayEvent), "Go", (Type[])null, (Type[])null), typeof(BarrelRollerDeathPatches), "DelayEvent_Go_Prefix"); num += Patch(harmony, AccessTools.Method(typeof(ConditionalEvent), "OnUnitDead", (Type[])null, (Type[])null), typeof(BarrelRollerDeathPatches), "ConditionalEvent_OnUnitDead_Prefix"); num += Patch(harmony, AccessTools.Method(typeof(GameStateManager), "EnterPlacementState", (Type[])null, (Type[])null), typeof(BarrelRollerDeathPatches), null, "GameStateManager_EnterPlacementState_Postfix"); num += Patch(harmony, AccessTools.Method(typeof(GameStateManager), "EnterBattleState", (Type[])null, (Type[])null), typeof(GameStatePatches), null, "EnterBattleState_Postfix"); num += Patch(harmony, AccessTools.Method(typeof(Water), "Start", (Type[])null, (Type[])null), typeof(WaterPatches), null, "Water_Start_Postfix"); num += Patch(harmony, AccessTools.Method(typeof(Water), "OnTriggerStay", (Type[])null, (Type[])null), typeof(WaterPatches), "Water_OnTriggerStay_Prefix", "Water_OnTriggerStay_Postfix"); num += Patch(harmony, AccessTools.Method(typeof(ProjectileHit), "Hit", new Type[2] { typeof(RaycastHit), typeof(float) }, (Type[])null), typeof(MirrorShieldPatches), "ProjectileHit_Hit_Prefix"); num += Patch(harmony, AccessTools.Method(typeof(ProjectileHit), "DisableProjectile", (Type[])null, (Type[])null), typeof(GasGrenadePatches), null, "ProjectileHit_DisableProjectile_Postfix"); num += Patch(harmony, AccessTools.Method(typeof(RaycastTrail), "Check", (Type[])null, (Type[])null), typeof(MirrorShieldPatches), "RaycastTrail_Check_Prefix"); num += Patch(harmony, AccessTools.Method(typeof(RaycastTrail), "Check", (Type[])null, (Type[])null), typeof(GasGrenadePatches), null, "RaycastTrail_Check_Postfix"); num += Patch(harmony, AccessTools.Method(typeof(SurfaceBlock), "DoEffect", (Type[])null, (Type[])null), typeof(MirrorShieldPatches), "SurfaceBlock_DoEffect_Prefix"); num += Patch(harmony, AccessTools.Method(typeof(SurfaceReflect), "DoEffect", (Type[])null, (Type[])null), typeof(MirrorShieldPatches), "SurfaceReflect_DoEffect_Prefix"); num += Patch(harmony, AccessTools.Method(typeof(BlockMove), "ProjectileBlock", (Type[])null, (Type[])null), typeof(MirrorShieldPatches), "BlockMove_ProjectileBlock_Prefix"); num += Patch(harmony, AccessTools.Method(typeof(BlockMove), "SetDisabled", (Type[])null, (Type[])null), typeof(MirrorShieldPatches), "BlockMove_SetDisabled_Prefix"); num += Patch(harmony, AccessTools.Method(typeof(BlockMoveHealth), "DoBlock", (Type[])null, (Type[])null), typeof(MirrorShieldPatches), "BlockMoveHealth_DoBlock_Prefix"); num += Patch(harmony, AccessTools.Method(typeof(Charges), "UseCharge", (Type[])null, (Type[])null), typeof(MirrorShieldPatches), "Charges_UseCharge_Prefix"); num += Patch(harmony, AccessTools.Method(typeof(ConditionalEvent), "CheckCondition", new Type[4] { typeof(EventCondition), typeof(ConditionalEventInstance), typeof(ConditionType), typeof(bool) }, (Type[])null), typeof(LayDownRangePatches), "CheckCondition_Prefix"); num += Patch(harmony, AccessTools.Method(typeof(ConditionalEvent), "IncrementCounters", (Type[])null, (Type[])null), typeof(LayDownRangePatches), "IncrementCounters_Prefix"); num += Patch(harmony, AccessTools.Method(typeof(WeaponHandler), "Attack", new Type[4] { typeof(Vector3), typeof(Rigidbody), typeof(Vector3), typeof(ForceWeapon) }, (Type[])null), typeof(LayDownWeaponPatches), "WeaponHandler_Attack_Prefix"); num += Patch(harmony, AccessTools.Method(typeof(Weapon), "UpdateCounters", new Type[1] { typeof(float) }, (Type[])null), typeof(LayDownWeaponPatches), "Weapon_UpdateCounters_Prefix"); Type type2 = AccessTools.TypeByName("Landfall.TABS.AI.UnitAPI, Assembly-CSharp"); Type type3 = AccessTools.TypeByName("Landfall.TABS.AI.Components.TargetData, Assembly-CSharp"); Type type4 = AccessTools.TypeByName("Unity.Mathematics.float3, Unity.Mathematics"); if (type2 != null && type3 != null && type4 != null) { MethodInfo methodInfo = AccessTools.Method(type2, "SetAttackTarget", new Type[6] { type4, typeof(Rigidbody), typeof(DataHandler), type3, typeof(bool), typeof(bool) }, (Type[])null); if (methodInfo != null) { num += Patch(harmony, methodInfo, typeof(LayDownAttackPatches), "SetAttackTarget_Prefix", "SetAttackTarget_Postfix"); } else { ((BaseUnityPlugin)this).Logger.LogWarning((object)"Lay-down attack patch skipped: SetAttackTarget method not found"); } } else { ((BaseUnityPlugin)this).Logger.LogWarning((object)"Lay-down attack patch skipped: UnitAPI / TargetData / float3 types not found"); } num += Patch(harmony, AccessTools.Method(typeof(ConditionalEvent), "CheckConditions", new Type[4] { typeof(ConditionalEventInstance), typeof(ConditionType), typeof(bool), typeof(bool) }, (Type[])null), typeof(LayDownAbilityPatches), "CheckConditions_Prefix"); num += Patch(harmony, AccessTools.Method(typeof(ConditionalEvent), "Start", (Type[])null, (Type[])null), typeof(LayDownAbilityPatches), null, "ConditionalEvent_Start_Postfix"); num += Patch(harmony, AccessTools.Method(typeof(ConditionalEvent), "Update", (Type[])null, (Type[])null), typeof(LayDownAbilityPatches), null, "ConditionalEvent_Update_Postfix"); num += Patch(harmony, AccessTools.Method(typeof(ConditionalEvent), "CheckConditionsUpdate", (Type[])null, (Type[])null), typeof(LayDownAbilityPatches), "CheckConditionsUpdate_Prefix"); num += Patch(harmony, AccessTools.Method(typeof(CameraAbilityPossess), "SetEnterUI", new Type[1] { typeof(Unit) }, (Type[])null), typeof(LayDownAbilityPatches), null, "SetEnterUI_Postfix"); MethodInfo methodInfo2 = AccessTools.Method(typeof(FactionCreatorManager), "AddNewUnit", new Type[1] { typeof(UnitBlueprint) }, (Type[])null); if (methodInfo2 != null) { num += Patch(harmony, methodInfo2, typeof(FactionCreatorPatches), null, "AddNewUnit_Postfix"); } else { ((BaseUnityPlugin)this).Logger.LogWarning((object)"Faction creator reorder: AddNewUnit patch skipped"); } MethodInfo methodInfo3 = AccessTools.Method(typeof(FactionCreatorManager), "LoadFaction", new Type[1] { typeof(Faction) }, (Type[])null); if (methodInfo3 != null) { num += Patch(harmony, methodInfo3, typeof(FactionCreatorPatches), null, "LoadFaction_Postfix"); } MethodInfo methodInfo4 = AccessTools.Method(typeof(FactionCreatorManager), "SaveNewFaction", (Type[])null, (Type[])null); if (methodInfo4 != null) { num += Patch(harmony, methodInfo4, typeof(FactionCreatorPatches), "SaveNewFaction_Prefix"); } MethodInfo methodInfo5 = AccessTools.Method(typeof(FactionCreatorManager), "GetFactionUnits", (Type[])null, (Type[])null); if (methodInfo5 != null) { num += Patch(harmony, methodInfo5, typeof(FactionCreatorPatches), "GetFactionUnits_Prefix"); } MethodInfo methodInfo6 = AccessTools.Method(typeof(UnitButtonFactionCreator), "OnClick", (Type[])null, (Type[])null); if (methodInfo6 != null) { num += Patch(harmony, methodInfo6, typeof(FactionCreatorPatches), "UnitButtonFactionCreator_OnClick_Prefix"); } MethodInfo methodInfo7 = AccessTools.Method(typeof(UnitButtonBase), "OnPointerEnter", (Type[])null, (Type[])null); if (methodInfo7 != null) { num += Patch(harmony, methodInfo7, typeof(FactionCreatorPatches), null, "UnitButtonBase_OnPointerEnter_Postfix"); } MethodInfo methodInfo8 = AccessTools.Method(typeof(UnitButtonBase), "OnPointerExit", (Type[])null, (Type[])null); if (methodInfo8 != null) { num += Patch(harmony, methodInfo8, typeof(FactionCreatorPatches), null, "UnitButtonBase_OnPointerExit_Postfix"); } MethodInfo methodInfo9 = AccessTools.Method(typeof(UnitButtonBase), "OnSelect", (Type[])null, (Type[])null); if (methodInfo9 != null) { num += Patch(harmony, methodInfo9, typeof(FactionCreatorPatches), null, "UnitButtonBase_OnSelect_Postfix"); } MethodInfo methodInfo10 = AccessTools.Method(typeof(UnitButtonBase), "OnDeselect", (Type[])null, (Type[])null); if (methodInfo10 != null) { num += Patch(harmony, methodInfo10, typeof(FactionCreatorPatches), null, "UnitButtonBase_OnDeselect_Postfix"); } string text = ((num == 49) ? $"{num}/{49}" : $"{num} ({49} core)"); ((BaseUnityPlugin)this).Logger.LogInfo((object)("Loaded v1.1.0 by Pretz — Harmony " + text)); ((BaseUnityPlugin)this).Logger.LogInfo((object)($"Water: still damp={WaterConfig.StillVelocityDamp}, river damp={WaterConfig.RiverVelocityDamp}, " + $"stream x={WaterConfig.StreamMultiplier}")); ((BaseUnityPlugin)this).Logger.LogInfo((object)("Mirror shield: " + (MirrorShieldConfig.Improved ? "improved" : "vanilla"))); } private int Patch(Harmony harmony, MethodBase original, Type patchClass, string prefix = null, string postfix = null, string transpiler = null) { //IL_0047: Unknown result type (might be due to invalid IL or missing references) //IL_0057: Unknown result type (might be due to invalid IL or missing references) //IL_0067: Unknown result type (might be due to invalid IL or missing references) if (original == null) { ((BaseUnityPlugin)this).Logger.LogError((object)("Patch target missing: " + patchClass.Name + "." + (prefix ?? postfix ?? transpiler))); return 0; } try { object obj = harmony; obj = original; obj = (object)((prefix == null) ? ((HarmonyMethod)null) : new HarmonyMethod(patchClass, prefix, (Type[])null)); obj = (object)((postfix == null) ? ((HarmonyMethod)null) : new HarmonyMethod(patchClass, postfix, (Type[])null)); obj = (object)((transpiler == null) ? ((HarmonyMethod)null) : new HarmonyMethod(patchClass, transpiler, (Type[])null)); ((Harmony)obj).Patch((MethodBase)obj, (HarmonyMethod)obj, (HarmonyMethod)obj, (HarmonyMethod)obj, (HarmonyMethod)null, (HarmonyMethod)null); return 1; } catch (Exception ex) { ((BaseUnityPlugin)this).Logger.LogError((object)("Failed to patch " + original.DeclaringType?.Name + "." + original.Name + ": " + ex.Message)); return 0; } } } public static class StayFixLogic { private static readonly Dictionary HorizontalAnchorByHandler = new Dictionary(); private static readonly Dictionary StayModeByHandler = new Dictionary(); private static readonly HashSet LayDownEligibleHandlers = new HashSet(); private static readonly Dictionary LayDownActiveUntilTime = new Dictionary(); private static readonly Dictionary LayDownWindUpEndsAt = new Dictionary(); private static readonly HashSet LayDownWasPlayingStaticAnim = new HashSet(); private static readonly HashSet AnchorReleased = new HashSet(); private const float AnchorReleaseSpeed = 2.5f; private const float AnchorReleaseDistance = 0.85f; private const float LayDownWindUpSeconds = 2f; private const float LayDownPulseGraceSeconds = 0.4f; private const float LayDownAnchorReleaseSpeed = 12f; private static readonly FieldInfo DontMoveForField = typeof(DataHandler).GetField("dontMoveFor", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic); private static readonly FieldInfo HipField = typeof(DataHandler).GetField("hip", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic); private const float LayDownWeaponAimPidMultiplier = 2.75f; private const float StayWeaponAimPidMultiplier = 1.85f; public static void Apply() { } public static void OnStayApplied(DataHandler handler, UnitDontWalkFor source) { if (!((Object)(object)handler == (Object)null)) { RegisterStayMode(handler, DetectStayModeFromSource(source, handler)); if (IsLayDownStay(handler)) { BeginLayDownStay(handler, ((Object)(object)source != (Object)null) ? source.time : 0f); } else if (ShouldApplyStayFix(handler)) { EnsureHorizontalAnchor(handler); ApplyStayFix(handler); } } } public static void OnStayApplied(DataHandler handler, float staySeconds) { if (!((Object)(object)handler == (Object)null)) { RegisterStayMode(handler, ResolveStayMode(handler, null)); if (IsLayDownStay(handler)) { BeginLayDownStay(handler, staySeconds); } else if (ShouldApplyStayFix(handler)) { EnsureHorizontalAnchor(handler); ApplyStayFix(handler); } } } public static void BeginLayDownStay(DataHandler handler, float staySeconds = 0f, float poseDurationSeconds = 0f) { if (!((Object)(object)handler == (Object)null)) { MarkLayDownEligible(handler); RegisterStayMode(handler, StayFixMode.LayDown); BeginLayDownWindUp(handler); RecordLayDownActivity(handler, staySeconds, poseDurationSeconds + 2f); AnchorReleased.Remove(handler); } } internal static void RegisterStayMode(DataHandler handler, StayFixMode mode) { if ((Object)(object)handler != (Object)null) { StayModeByHandler[handler] = mode; } } public static bool IsLayDownStay(DataHandler handler) { if ((Object)(object)handler != (Object)null && StayModeByHandler.TryGetValue(handler, out var value)) { return value == StayFixMode.LayDown; } return false; } internal static bool CanLayDownEngageTarget(DataHandler handler) { if ((Object)(object)handler == (Object)null || !IsLayDownAbilityActive(handler) || !IsLayDownStay(handler)) { return false; } if ((Object)(object)handler.targetMainRig == (Object)null) { return false; } DataHandler componentInParent = ((Component)handler.targetMainRig).GetComponentInParent(); if ((Object)(object)componentInParent != (Object)null && componentInParent.Dead) { return false; } if (!handler.CanSeeTarget) { return IsTargetWithinWeaponFireRange(handler); } return true; } internal static bool IsLayDownPlayerPossessed(DataHandler handler) { if ((Object)(object)handler?.input != (Object)null) { return handler.input.hasControl; } return false; } internal static bool ShouldLayDownAutoFire(DataHandler handler) { if (CanLayDownEngageTarget(handler)) { return !IsLayDownPlayerPossessed(handler); } return false; } internal static float GetWeaponTrackPidMultiplier(DataHandler handler) { if ((Object)(object)handler == (Object)null) { return 1f; } if (IsLayDownStay(handler) && (CanLayDownEngageTarget(handler) || IsLayDownAbilityActive(handler))) { return 2.75f; } if (IsStayLocked(handler)) { return 1.85f; } return 1f; } public static bool ShouldClampWeaponHoldPosition(DataHandler handler, Holdable holdable) { if (!IsStayLocked(handler) || ShouldSkipStayPhysicsLock(handler)) { return false; } if (!IsLayDownStay(handler)) { return true; } if (!IsHoldableInFireRange(handler, holdable)) { return ShouldTrackTargetWithWeapon(handler, holdable); } return true; } public static bool ShouldApplyStayFix(DataHandler handler) { if ((Object)(object)handler == (Object)null || handler.Dead || IsRiderRelatedUnit(handler)) { return false; } if (IsLayDownStay(handler) || IsLayDownEligible(handler)) { return ShouldApplyLayDownPhysics(handler); } if (!IsUnderStayEffect(handler)) { return false; } if (IsBearerOrPlayerControlled(handler)) { return false; } return true; } private static bool ShouldClearStayState(DataHandler handler) { if ((Object)(object)handler == (Object)null || handler.Dead || IsRiderRelatedUnit(handler)) { return true; } if (IsLayDownStay(handler) || IsLayDownEligible(handler)) { return !IsLayDownAbilityActive(handler); } if (IsBearerOrPlayerControlled(handler)) { return true; } return !IsUnderStayEffect(handler); } public static bool IsBearerOrPlayerControlled(DataHandler handler) { if ((Object)(object)handler == (Object)null) { return false; } if ((Object)(object)handler.unitToInheritDirectionFrom != (Object)null) { return true; } if ((Object)(object)handler.input == (Object)null) { return false; } if (handler.input.hasControl) { return true; } if (handler.input.IsRemotelyControlled) { return true; } if ((Object)(object)handler.unit != (Object)null) { return handler.unit.IsRemotelyControlled; } return false; } public static void PrepareStayFrame(DataHandler handler) { //IL_006b: Unknown result type (might be due to invalid IL or missing references) //IL_0070: Unknown result type (might be due to invalid IL or missing references) //IL_00aa: 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) //IL_00c4: Unknown result type (might be due to invalid IL or missing references) //IL_00c9: Unknown result type (might be due to invalid IL or missing references) //IL_00e4: Unknown result type (might be due to invalid IL or missing references) //IL_00e9: Unknown result type (might be due to invalid IL or missing references) //IL_00ec: Unknown result type (might be due to invalid IL or missing references) //IL_00f9: Unknown result type (might be due to invalid IL or missing references) //IL_0105: Unknown result type (might be due to invalid IL or missing references) //IL_0106: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)handler == (Object)null) { return; } if (LayDownWeaponExclusions.HasExcludedWeaponEquipped(handler)) { LayDownWeaponExclusions.SuppressBundledLayDownForUnit(handler); } UpdateLayDownAnchorPhase(handler); LayDownWeaponLogic.TickLayDownVisibleCombat(handler); if (ShouldClearStayState(handler)) { ClearStayState(handler); } else if (ShouldTrackLayDownPoseWithoutLock(handler)) { SyncLastPosToBody(handler); } else { if (!ShouldApplyStayFix(handler)) { return; } EnsureHorizontalAnchor(handler); TryReleaseAnchorIfPushed(handler); if ((Object)(object)handler.input != (Object)null) { handler.input.inputDirection = Vector3.zero; } if (!((Object)(object)handler.mainRig == (Object)null)) { Vector3 value; if (IsLayDownStay(handler) && ShouldLayDownHorizontalHold(handler)) { SyncLastPosHorizontalOnly(handler); } else if (!HasHorizontalAnchor(handler)) { handler.lastPos = handler.mainRig.position; } else if (ShouldSkipStayPhysicsLock(handler)) { handler.lastPos = handler.mainRig.position; } else if (HorizontalAnchorByHandler.TryGetValue(handler, out value)) { Vector3 position = handler.mainRig.position; position.x = value.x; position.z = value.z; handler.lastPos = position; } } } } public static void TickStayLight(DataHandler handler) { if ((Object)(object)handler == (Object)null) { return; } if (ShouldClearStayState(handler)) { ClearStayState(handler); } else if (ShouldApplyStayFix(handler)) { EnsureHorizontalAnchor(handler); TryReleaseAnchorIfPushed(handler); PreventStayMovementCreep(handler); if (HasHorizontalAnchor(handler) && !ShouldSkipStayPhysicsLock(handler)) { EnforcePlantPosition(handler); } } } public static void EnforcePlantPosition(DataHandler handler) { if ((Object)(object)handler == (Object)null || !ShouldApplyStayFix(handler)) { return; } EnsureHorizontalAnchor(handler); TryReleaseAnchorIfPushed(handler); PreventStayMovementCreep(handler); if (ShouldSkipStayPhysicsLock(handler)) { return; } if (IsLayDownStay(handler)) { if (ShouldLayDownHorizontalHold(handler)) { ApplyLayDownHorizontalHold(handler, fullStabilize: true); } } else { StabilizeMainBodyHorizontal(handler); ApplyHorizontalLock(handler); } } public static void TickStay(DataHandler handler) { if ((Object)(object)handler == (Object)null) { return; } if (ShouldClearStayState(handler)) { ClearStayState(handler); } else if (ShouldApplyStayFix(handler)) { EnsureHorizontalAnchor(handler); TryReleaseAnchorIfPushed(handler); if (HasHorizontalAnchor(handler) && !ShouldSkipStayPhysicsLock(handler)) { EnforcePlantPosition(handler); } } } public static void OnUnitDied(DataHandler handler) { ClearStayState(handler); } public static bool IsStayLocked(DataHandler handler) { return ShouldApplyStayFix(handler); } public static bool IsStayLocked(Component component) { if ((Object)(object)component == (Object)null) { return false; } return IsStayLocked(component.GetComponentInParent()); } public static bool HasHorizontalAnchorForStay(DataHandler handler) { return HasHorizontalAnchor(handler); } public static DataHandler ResolveHandler(UnitDontWalkFor source) { if ((Object)(object)source == (Object)null) { return null; } Unit componentInParent = ((Component)source).GetComponentInParent(); if ((Object)(object)componentInParent != (Object)null && (Object)(object)componentInParent.data != (Object)null) { return componentInParent.data; } return ((Component)source).GetComponentInParent(); } public static bool ShouldSkipStayPhysicsLock(DataHandler handler) { if (!((Object)(object)handler == (Object)null) && !handler.Dead) { return !HasHorizontalAnchor(handler); } return true; } public static bool TryClampBodyMovePosition(Rigidbody rb, ref Vector3 position) { //IL_0057: 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) DataHandler val = ((rb != null) ? ((Component)rb).GetComponentInParent() : null); if ((Object)(object)val == (Object)null || !HasHorizontalAnchor(val) || ShouldSkipStayPhysicsLock(val)) { return false; } if (IsLayDownStay(val) && !ShouldLayDownHorizontalHold(val)) { return false; } if (!IsUnitBodyRigidbody(val, rb)) { return false; } if (!HorizontalAnchorByHandler.TryGetValue(val, out var value)) { return false; } position.x = value.x; position.z = value.z; return true; } public static void ApplyStayFix(DataHandler handler) { EnforcePlantPosition(handler); } public static void StabilizeStayBody(DataHandler handler) { //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) if ((Object)(object)handler == (Object)null || handler.Dead) { if (handler != null && handler.Dead) { ClearStayState(handler); } } else if (ShouldApplyStayFix(handler) && !ShouldSkipStayPhysicsLock(handler)) { if ((Object)(object)handler.input != (Object)null) { handler.input.inputDirection = Vector3.zero; } PreventStayMovementCreep(handler); StabilizeMainBodyHorizontal(handler); } } public static void StabilizeBodyOnly(DataHandler handler) { EnforcePlantPosition(handler); } private static void StabilizeMainBodyHorizontal(DataHandler handler) { if ((Object)(object)handler == (Object)null) { return; } StabilizeRigidbodyHorizontal(handler.mainRig); if ((Object)(object)handler.torso != (Object)null) { StabilizeRigidbodyHorizontal(((Component)handler.torso).GetComponent()); } if (!handler.isGrounded) { object? obj = HipField?.GetValue(handler); Rigidbody val = (Rigidbody)((obj is Rigidbody) ? obj : null); if (val != null) { StabilizeRigidbodyHorizontal(val); } } } public static void StabilizeWeaponHold(DataHandler handler) { if (!((Object)(object)handler == (Object)null) && ShouldApplyStayFix(handler) && !ShouldSkipStayPhysicsLock(handler)) { HoldingHandler component = ((Component)handler).GetComponent(); if (!((Object)(object)component == (Object)null)) { StabilizeHoldableLinearOnly(handler, GetHoldable(component, "rightObject")); StabilizeHoldableLinearOnly(handler, GetHoldable(component, "leftObject")); } } } public static void ApplyExtendedLookAtAim(DataHandler handler, Holdable holdable) { //IL_0040: 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) //IL_0058: Unknown result type (might be due to invalid IL or missing references) //IL_005d: Unknown result type (might be due to invalid IL or missing references) //IL_007e: Unknown result type (might be due to invalid IL or missing references) //IL_007f: Unknown result type (might be due to invalid IL or missing references) //IL_0084: Unknown result type (might be due to invalid IL or missing references) if (!((Object)(object)handler?.mainRig == (Object)null) && holdable?.holdableData != null && !((Object)(object)handler.targetMainRig == (Object)null) && !UsesArcingHoldableAim(holdable)) { Vector3 val = handler.targetMainRig.position - ((Component)holdable).transform.position; Vector3 normalized = ((Vector3)(ref val)).normalized; if (!(((Vector3)(ref normalized)).sqrMagnitude < 0.0001f)) { holdable.holdableData.forwardRotation = ((Component)handler.mainRig).transform.InverseTransformDirection(normalized); } } } internal static bool UsesArcingHoldableAim(Holdable holdable) { if (holdable?.pidData != null) { return holdable.pidData.extraUpPerMeter != 0f; } return false; } public static bool ShouldTrackTargetWithWeapon(DataHandler handler, Holdable holdable = null) { if ((Object)(object)handler == (Object)null || (Object)(object)handler.targetMainRig == (Object)null) { return false; } DataHandler componentInParent = ((Component)handler.targetMainRig).GetComponentInParent(); if ((Object)(object)componentInParent != (Object)null && componentInParent.Dead) { return false; } if (CanLayDownEngageTarget(handler)) { return true; } if (handler.inRange) { return true; } if ((Object)(object)holdable != (Object)null && IsHoldableInFireRange(handler, holdable)) { return true; } if ((Object)(object)holdable == (Object)null) { HoldingHandler component = ((Component)handler).GetComponent(); if ((Object)(object)component != (Object)null) { if (IsHoldableInFireRange(handler, GetHoldable(component, "rightObject"))) { return true; } if (IsHoldableInFireRange(handler, GetHoldable(component, "leftObject"))) { return true; } } } if (holdable?.holdableData != null && holdable.holdableData.lookAtTargetWhenWithin > 0f && handler.distanceToTarget < holdable.holdableData.lookAtTargetWhenWithin) { return true; } return false; } internal static bool IsHoldableInFireRange(DataHandler handler, Holdable holdable) { if ((Object)(object)holdable == (Object)null) { return false; } float effectiveFireRange = GetEffectiveFireRange(holdable); if (effectiveFireRange <= 0f) { return false; } float num = 0f; if ((Object)(object)handler.targetData?.unit != (Object)null) { num = handler.targetData.unit.thickness; } return handler.distanceToTarget <= effectiveFireRange + num + 1f; } internal static bool IsTargetWithinWeaponFireRange(DataHandler handler) { if ((Object)(object)handler?.targetMainRig == (Object)null) { return false; } DataHandler componentInParent = ((Component)handler.targetMainRig).GetComponentInParent(); if ((Object)(object)componentInParent != (Object)null && componentInParent.Dead) { return false; } HoldingHandler component = ((Component)handler).GetComponent(); if ((Object)(object)component == (Object)null) { return false; } if (IsHoldableInFireRange(handler, GetHoldable(component, "rightObject"))) { return true; } return IsHoldableInFireRange(handler, GetHoldable(component, "leftObject")); } public static void StabilizeRigidbodyHorizontal(Rigidbody rb) { //IL_0013: Unknown result type (might be due to invalid IL or missing references) //IL_0018: Unknown result type (might be due to invalid IL or missing references) //IL_0019: Unknown result type (might be due to invalid IL or missing references) //IL_0057: 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) if (!((Object)(object)rb == (Object)null) && !rb.isKinematic) { Vector3 velocity = rb.velocity; if (!(Mathf.Abs(velocity.x) < 0.0001f) || !(Mathf.Abs(velocity.z) < 0.0001f)) { velocity.x = 0f; velocity.z = 0f; rb.velocity = velocity; } } } internal static bool IsUnitBodyRigidbody(DataHandler handler, Rigidbody rb) { if ((Object)(object)handler == (Object)null || (Object)(object)rb == (Object)null) { return false; } if ((Object)(object)rb == (Object)(object)handler.mainRig) { return true; } if ((Object)(object)handler.torso != (Object)null && (Object)(object)rb == (Object)(object)((Component)handler.torso).GetComponent()) { return true; } object? obj = HipField?.GetValue(handler); Rigidbody val = (Rigidbody)((obj is Rigidbody) ? obj : null); if (val != null && (Object)(object)rb == (Object)(object)val) { return true; } return false; } public static void ClearStayState(DataHandler handler) { if (!((Object)(object)handler == (Object)null)) { ClearHorizontalAnchor(handler); AnchorReleased.Remove(handler); StayModeByHandler.Remove(handler); LayDownEligibleHandlers.Remove(handler); LayDownActiveUntilTime.Remove(handler); LayDownWindUpEndsAt.Remove(handler); LayDownWasPlayingStaticAnim.Remove(handler); } } public static bool IsLayDownPoseAnimation(StaticAnimation animation) { if (animation == null || string.IsNullOrEmpty(animation.animationName)) { return false; } return HasLayDownMarkerInName(animation.animationName); } internal static StayFixMode DetectStayModeFromSource(UnitDontWalkFor source, DataHandler handler) { if (ShouldUseLayDownStayMode(handler)) { return StayFixMode.LayDown; } if ((Object)(object)source != (Object)null && HasLayDownMarkerInHierarchy(((Component)source).transform) && !LayDownWeaponExclusions.IsOnExcludedWeaponHierarchy(((Component)source).transform, handler)) { MarkLayDownEligible(handler); return StayFixMode.LayDown; } return StayFixMode.BannerAura; } private static bool ShouldUseLayDownStayMode(DataHandler handler) { if ((Object)(object)handler != (Object)null) { if (!IsLayDownEligible(handler)) { return handler.playingStaticAnim; } return true; } return false; } private static StayFixMode ResolveStayMode(DataHandler handler, UnitDontWalkFor source) { if ((Object)(object)source != (Object)null) { return DetectStayModeFromSource(source, handler); } if (ShouldUseLayDownStayMode(handler)) { return StayFixMode.LayDown; } return StayFixMode.BannerAura; } private static void MarkLayDownEligible(DataHandler handler) { if ((Object)(object)handler != (Object)null) { LayDownEligibleHandlers.Add(handler); } } private static bool IsLayDownEligible(DataHandler handler) { if ((Object)(object)handler != (Object)null) { return LayDownEligibleHandlers.Contains(handler); } return false; } private static void ForceRefreshHorizontalAnchor(DataHandler handler) { //IL_002d: Unknown result type (might be due to invalid IL or missing references) if (!((Object)(object)handler?.mainRig == (Object)null)) { AnchorReleased.Remove(handler); HorizontalAnchorByHandler[handler] = handler.mainRig.position; } } internal static bool HasLayDownMarkerInHierarchy(Transform transform) { Transform val = transform; while ((Object)(object)val != (Object)null) { if (HasLayDownMarkerInName(((Object)val).name)) { return true; } val = val.parent; } return false; } private static bool HasLayDownMarkerInName(string name) { if (string.IsNullOrEmpty(name)) { return false; } if (name.IndexOf("laydown", StringComparison.OrdinalIgnoreCase) >= 0 || name.IndexOf("lay down", StringComparison.OrdinalIgnoreCase) >= 0 || name.IndexOf("lay_down", StringComparison.OrdinalIgnoreCase) >= 0 || name.IndexOf("prone", StringComparison.OrdinalIgnoreCase) >= 0) { return true; } if (name.IndexOf("lay", StringComparison.OrdinalIgnoreCase) >= 0) { return name.IndexOf("down", StringComparison.OrdinalIgnoreCase) >= 0; } return false; } private static void RecordLayDownActivity(DataHandler handler, float staySeconds, float poseDurationSeconds = 0f) { if (!((Object)(object)handler == (Object)null)) { float num = Time.time + 0.4f; if (staySeconds > 0f) { num = Mathf.Max(num, Time.time + staySeconds); } if (poseDurationSeconds > 0f) { num = Mathf.Max(num, Time.time + poseDurationSeconds); } LayDownActiveUntilTime[handler] = num; } } internal static bool IsLayDownAbilityActive(DataHandler handler) { if ((Object)(object)handler == (Object)null || (!IsLayDownStay(handler) && !IsLayDownEligible(handler))) { return false; } if (handler.playingStaticAnim) { return true; } if (LayDownActiveUntilTime.TryGetValue(handler, out var value) && Time.time < value) { return true; } return IsUnderStayEffect(handler); } private static bool IsLayDownWindUpComplete(DataHandler handler) { if ((Object)(object)handler != (Object)null && LayDownWindUpEndsAt.TryGetValue(handler, out var value)) { return Time.time >= value; } return false; } private static bool ShouldTrackLayDownPoseWithoutLock(DataHandler handler) { if (IsLayDownAbilityActive(handler) && (IsLayDownStay(handler) || IsLayDownEligible(handler))) { return !ShouldApplyLayDownPhysics(handler); } return false; } private static void SyncLastPosToBody(DataHandler handler) { //IL_001b: Unknown result type (might be due to invalid IL or missing references) //IL_0020: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)handler?.mainRig != (Object)null) { handler.lastPos = handler.mainRig.position; } } internal static bool ShouldApplyLayDownPhysics(DataHandler handler) { if (!IsLayDownAbilityActive(handler)) { return false; } if (!IsLayDownStay(handler) && !IsLayDownEligible(handler)) { return false; } if (!IsLayDownWindUpComplete(handler)) { return false; } if (handler.playingStaticAnim) { return false; } return true; } private static bool ShouldLayDownHorizontalHold(DataHandler handler) { if (ShouldApplyLayDownPhysics(handler)) { return HasHorizontalAnchor(handler); } return false; } private static void BeginLayDownWindUp(DataHandler handler) { if (!((Object)(object)handler == (Object)null) && !LayDownWindUpEndsAt.ContainsKey(handler)) { LayDownWindUpEndsAt[handler] = Time.time + 2f; } } private static void UpdateLayDownAnchorPhase(DataHandler handler) { if ((Object)(object)handler == (Object)null || (!IsLayDownStay(handler) && !IsLayDownEligible(handler))) { return; } bool playingStaticAnim = handler.playingStaticAnim; bool flag = LayDownWasPlayingStaticAnim.Contains(handler); if (playingStaticAnim) { LayDownWasPlayingStaticAnim.Add(handler); } else { LayDownWasPlayingStaticAnim.Remove(handler); } if (!(!IsLayDownAbilityActive(handler) || !IsLayDownWindUpComplete(handler) || playingStaticAnim)) { if (flag && !playingStaticAnim) { FinalizeLayDownPlant(handler); } else if (!HasHorizontalAnchor(handler)) { FinalizeLayDownPlant(handler); } } } private static void FinalizeLayDownPlant(DataHandler handler) { if (!((Object)(object)handler?.mainRig == (Object)null) && ShouldApplyLayDownPhysics(handler)) { RefreshHorizontalAnchorXZ(handler); if (ShouldApplyLayDownPhysics(handler)) { ApplyLayDownHorizontalHold(handler, fullStabilize: true); } } } private static void RefreshHorizontalAnchorXZ(DataHandler handler) { //IL_0027: Unknown result type (might be due to invalid IL or missing references) //IL_002c: 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_0042: 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_004e: 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) if (!((Object)(object)handler?.mainRig == (Object)null)) { AnchorReleased.Remove(handler); Vector3 position = handler.mainRig.position; if (HorizontalAnchorByHandler.TryGetValue(handler, out var value)) { HorizontalAnchorByHandler[handler] = new Vector3(position.x, value.y, position.z); } else { HorizontalAnchorByHandler[handler] = position; } } } private static bool HasHorizontalAnchor(DataHandler handler) { if ((Object)(object)handler != (Object)null && HorizontalAnchorByHandler.ContainsKey(handler)) { return !AnchorReleased.Contains(handler); } return false; } private static void EnsureHorizontalAnchor(DataHandler handler) { //IL_003c: Unknown result type (might be due to invalid IL or missing references) if (!((Object)(object)handler?.mainRig == (Object)null) && !AnchorReleased.Contains(handler) && !HorizontalAnchorByHandler.ContainsKey(handler)) { HorizontalAnchorByHandler[handler] = handler.mainRig.position; } } private static void ClearHorizontalAnchor(DataHandler handler) { if ((Object)(object)handler != (Object)null) { HorizontalAnchorByHandler.Remove(handler); } } private static void ReleaseHorizontalAnchor(DataHandler handler) { if (!((Object)(object)handler == (Object)null)) { AnchorReleased.Add(handler); ClearHorizontalAnchor(handler); } } private static void TryReleaseAnchorIfPushed(DataHandler handler) { //IL_0071: Unknown result type (might be due to invalid IL or missing references) //IL_0076: 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_007c: 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_009f: Unknown result type (might be due to invalid IL or missing references) //IL_00a4: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)handler == (Object)null || AnchorReleased.Contains(handler) || !HasHorizontalAnchor(handler)) { return; } Rigidbody mainRig = handler.mainRig; if ((Object)(object)mainRig == (Object)null || !HorizontalAnchorByHandler.TryGetValue(handler, out var value)) { return; } if (IsLayDownStay(handler)) { Vector3 velocity = mainRig.velocity; velocity.y = 0f; if (((Vector3)(ref velocity)).sqrMagnitude >= 144f) { ReleaseHorizontalAnchor(handler); } return; } Vector3 val = mainRig.position - value; val.y = 0f; if (((Vector3)(ref val)).sqrMagnitude >= 0.7225f) { ReleaseHorizontalAnchor(handler); return; } Vector3 velocity2 = mainRig.velocity; velocity2.y = 0f; if (((Vector3)(ref velocity2)).sqrMagnitude >= 6.25f) { ReleaseHorizontalAnchor(handler); } } private static void ApplyLayDownHorizontalHold(DataHandler handler, bool fullStabilize) { //IL_0031: Unknown result type (might be due to invalid IL or missing references) //IL_0036: Unknown result type (might be due to invalid IL or missing references) if (!((Object)(object)handler?.mainRig == (Object)null) && HasHorizontalAnchor(handler)) { if ((Object)(object)handler.input != (Object)null) { handler.input.inputDirection = Vector3.zero; } PreventStayMovementCreep(handler); if (fullStabilize) { StabilizeLayDownRigs(handler); } else { StabilizeMainBodyHorizontal(handler); } ApplyHorizontalLock(handler); SyncLastPosHorizontalOnly(handler); } } private static void SyncLastPosHorizontalOnly(DataHandler handler) { //IL_002a: Unknown result type (might be due to invalid IL or missing references) //IL_002f: 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_003f: 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_004c: Unknown result type (might be due to invalid IL or missing references) if (!((Object)(object)handler?.mainRig == (Object)null) && HorizontalAnchorByHandler.TryGetValue(handler, out var value)) { Vector3 position = handler.mainRig.position; position.x = value.x; position.z = value.z; handler.lastPos = position; } } private static void StabilizeLayDownRigs(DataHandler handler) { StabilizeMainBodyHorizontal(handler); RigidbodyHolder allRigs = handler.allRigs; if (((allRigs != null) ? allRigs.AllRigs : null) == null) { return; } Rigidbody[] allRigs2 = handler.allRigs.AllRigs; foreach (Rigidbody val in allRigs2) { if (!((Object)(object)val == (Object)null) && !((Object)(object)val == (Object)(object)handler.mainRig)) { StabilizeRigidbodyHorizontal(val); } } } private static void PreventStayMovementCreep(DataHandler handler) { //IL_001a: 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_002f: Unknown result type (might be due to invalid IL or missing references) //IL_0034: 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) //IL_004f: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)handler?.input != (Object)null) { handler.input.inputDirection = Vector3.zero; } if (!((Object)(object)handler == (Object)null)) { Vector3 currentVelocity = handler.currentVelocity; currentVelocity.x = 0f; currentVelocity.z = 0f; handler.currentVelocity = currentVelocity; } } private static void ApplyHorizontalLock(DataHandler handler) { //IL_003b: 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) //IL_0043: 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_005c: 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_0064: Unknown result type (might be due to invalid IL or missing references) if (!((Object)(object)handler == (Object)null) && !handler.Dead && HasHorizontalAnchor(handler)) { Rigidbody mainRig = handler.mainRig; if (!((Object)(object)mainRig == (Object)null) && HorizontalAnchorByHandler.TryGetValue(handler, out var value)) { Vector3 position = mainRig.position; position.x = value.x; position.z = value.z; mainRig.MovePosition(position); handler.lastPos = position; } } } private static bool IsRiderRelatedUnit(DataHandler handler) { if ((Object)(object)handler == (Object)null) { return false; } Unit unit = handler.unit; if ((Object)(object)unit != (Object)null && (unit.IsRider || unit.IsRiderWithLinkedMount)) { return true; } GameObject val = (((Object)(object)unit != (Object)null) ? ((Component)unit).gameObject : ((Component)handler).gameObject); if ((Object)(object)val == (Object)null) { return false; } RiderHolder[] componentsInParent = ((Component)handler).GetComponentsInParent(true); foreach (RiderHolder val2 in componentsInParent) { if (!HasActiveRiders(val2)) { continue; } for (int j = 0; j < val2.riders.Count; j++) { GameObject val3 = val2.riders[j]; if (!((Object)(object)val3 == (Object)null) && val3.activeInHierarchy && ((Object)(object)val3 == (Object)(object)val || val3.transform.IsChildOf(val.transform) || val.transform.IsChildOf(val3.transform))) { return true; } } } RiderHolder componentInChildren = ((Component)((Component)handler).transform.root).GetComponentInChildren(); if ((Object)(object)componentInChildren != (Object)null && HasActiveRiders(componentInChildren)) { return true; } return false; } private static bool HasActiveRiders(RiderHolder holder) { if (holder?.riders == null) { return false; } for (int i = 0; i < holder.riders.Count; i++) { if ((Object)(object)holder.riders[i] != (Object)null && holder.riders[i].activeInHierarchy) { return true; } } return false; } private static Weapon GetWeaponFromHoldable(Holdable holdable) { if ((Object)(object)holdable == (Object)null) { return null; } return ((Component)holdable).GetComponent() ?? ((Component)holdable).GetComponentInChildren(); } private static float GetEffectiveFireRange(Holdable holdable) { Weapon weaponFromHoldable = GetWeaponFromHoldable(holdable); if ((Object)(object)weaponFromHoldable == (Object)null) { return 0f; } return weaponFromHoldable.maxRange; } private static void StabilizeHoldableLinearOnly(DataHandler handler, Holdable holdable) { if (!((Object)(object)holdable?.rig == (Object)null) && (!IsLayDownStay(handler) || IsHoldableInFireRange(handler, holdable) || ShouldTrackTargetWithWeapon(handler, holdable)) && !ShouldTrackTargetWithWeapon(handler, holdable)) { StabilizeRigidbodyHorizontal(holdable.rig); } } private static Holdable GetHoldable(HoldingHandler holding, string fieldName) { object? obj = typeof(HoldingHandler).GetField(fieldName, BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic)?.GetValue(holding); return (Holdable)((obj is Holdable) ? obj : null); } private static bool IsUnderStayEffect(DataHandler handler) { return GetDontMoveForRemaining(handler) > 0f; } private static float GetDontMoveForRemaining(DataHandler handler) { if ((Object)(object)handler == (Object)null || DontMoveForField == null) { return 0f; } object value = DontMoveForField.GetValue(handler); if (value is float) { return (float)value; } return 0f; } } internal enum StayFixMode { BannerAura, LayDown } internal static class StayPatches { public static void PoseHandler_PlayAnimation_Prefix(PoseHandler __instance, StaticAnimation animation, Vector3 pos, Quaternion rot) { if (StayFixLogic.IsLayDownPoseAnimation(animation)) { DataHandler poseHandlerData = GetPoseHandlerData(__instance); if (!((Object)(object)poseHandlerData == (Object)null) && !LayDownWeaponExclusions.ShouldBlockLayDownPose(poseHandlerData)) { float poseDurationSeconds = animation.startDelay + animation.time + 1f; StayFixLogic.BeginLayDownStay(poseHandlerData, 0f, poseDurationSeconds); } } } private static DataHandler GetPoseHandlerData(PoseHandler handler) { if (!((Object)(object)handler != (Object)null)) { return null; } return ((Component)((Component)handler).transform.root).GetComponentInChildren(); } public static void UnitDontWalkFor_Go_Prefix(UnitDontWalkFor __instance) { StayFixLogic.OnStayApplied(StayFixLogic.ResolveHandler(__instance), __instance); } public static void UnitDontWalkFor_Go_Postfix(UnitDontWalkFor __instance) { StayFixLogic.OnStayApplied(StayFixLogic.ResolveHandler(__instance), __instance); } public static void DataHandler_DontWalkFor_Prefix(DataHandler __instance, float time) { StayFixLogic.OnStayApplied(__instance, time); } public static void DataHandler_DontWalkFor_Postfix(DataHandler __instance, float time) { StayFixLogic.OnStayApplied(__instance, time); } public static void DataHandler_BatchedUpdate_Prefix(DataHandler __instance) { StayFixLogic.PrepareStayFrame(__instance); } public static void DataHandler_BatchedUpdate_Postfix(DataHandler __instance) { StayFixLogic.TickStayLight(__instance); } public static void DataHandler_BatchedFixedUpdate_Postfix(DataHandler __instance) { StayFixLogic.TickStay(__instance); } public static void DataHandler_Dead_Setter_Postfix(DataHandler __instance) { if (__instance.Dead) { StayFixLogic.OnUnitDied(__instance); BarrelRollerDeathLogic.EnsureScheduledFromDead(__instance); } } } internal static class StayPhysicsPatches { public static void Rigidbody_MovePosition_Prefix(Rigidbody __instance, ref Vector3 position) { StayFixLogic.TryClampBodyMovePosition(__instance, ref position); } } internal static class WaterConfig { internal static float StillVelocityDamp = 0.78f; internal static float StillMaxHorizontalSpeed = 1.25f; internal static float RiverVelocityDamp = 0.84f; internal static float StreamMultiplier = 2.2f; internal static float RiverMainRigPushScale = 1.05f; internal static float MinimumStreamForce = 500f; internal static float RiverEffectDepth = 3.5f; private static readonly string[] OrphanedCorpseKeys = new string[12] { "DeadBodyFloatForce", "DeadBodyFloatMultiplier", "DeadFloatMinDepth", "DeadVelocityDamp", "DeadFloatStrength", "DeadMinRiseSpeed", "DeadMaxRiseSpeed", "DeadRightingTorque", "DeadRightingDepth", "DeadLayFlatTorque", "DeadLayFlatDepth", "DeadLimbAngularDamp" }; internal static void Bind(ConfigFile config) { StillVelocityDamp = config.Bind("Water.Still", "VelocityDamp", 0.78f, "Lakes and ponds ONLY — replaces vanilla 0.15 mud damp (lower = slower, higher = faster). Default 0.78. Typical range 0.5–0.9.").Value; StillMaxHorizontalSpeed = config.Bind("Water.Still", "MaxHorizontalSpeed", 1.25f, "Lakes and ponds — max sideways speed in m/s. Stops still water from shoving units. 0 = off.").Value; RiverVelocityDamp = config.Bind("Water.River", "VelocityDamp", 0.84f, "Rivers ONLY — replaces vanilla 0.15 mud damp. Use 0.5–0.9. Do not set above 1.0.").Value; StreamMultiplier = config.Bind("Water.River", "StreamMultiplier", 2.2f, "Rivers ONLY — multiplies the map's streamForce at battle start.").Value; RiverMainRigPushScale = config.Bind("Water.River", "MainRigPushScale", 1.05f, "Rivers ONLY — extra current push at the hips, thighs, and feet each tick. Try 1.0 if too weak.").Value; MinimumStreamForce = config.Bind("Water.River", "MinimumStreamForce", 500f, "Rivers ONLY — fallback current when streamForce is 0 on the volume.").Value; RiverEffectDepth = config.Bind("Water.River", "RiverEffectDepth", 3.5f, "Rivers ONLY — push while swimming (not just feet on the river bed).").Value; RemoveOrphanedCorpseConfig(config); } private static void RemoveOrphanedCorpseConfig(ConfigFile config) { //IL_0015: Unknown result type (might be due to invalid IL or missing references) //IL_001f: Expected O, but got Unknown string[] orphanedCorpseKeys = OrphanedCorpseKeys; foreach (string text in orphanedCorpseKeys) { config.Remove(new ConfigDefinition("Water.Still", text)); } } } internal static class WaterPatches { private static readonly FieldInfo HipField = typeof(DataHandler).GetField("hip", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic); private const float VanillaVelocityRetention = 0.15f; private const float SurfaceSubmersionDepth = 1f; private const float MaxBobUpSpeed = 6f; private const float ForkBranchOffset = 20f; [ThreadStatic] private static bool _isStillWaterTick; [ThreadStatic] private static float _savedStreamForce; private static float _customPhysicsFixedTime = -1f; private static readonly HashSet _customPhysicsKeys = new HashSet(); private static readonly Dictionary CachedFlowDirectionByWaterId = new Dictionary(); private static bool _flowDirectionsCalibrated; private static bool _hasForkMap; internal static Action LogInfo; public static void Water_Start_Postfix(Water __instance) { if (IsStillWater(__instance)) { __instance.streamForce = 0f; } else if (Mathf.Abs(__instance.streamForce) > 1f) { __instance.streamForce *= WaterConfig.StreamMultiplier; } } public static void Water_OnTriggerStay_Prefix(Water __instance) { _isStillWaterTick = IsStillWater(__instance); if (_isStillWaterTick) { _savedStreamForce = 0f; __instance.streamForce = 0f; } else { EnsureRiverFlowDirectionsCalibrated(); _savedStreamForce = __instance.streamForce; __instance.streamForce = 0f; } } public static void Water_OnTriggerStay_Postfix(Water __instance, Collider other) { __instance.streamForce = _savedStreamForce; Rigidbody componentInParent = ((Component)other).GetComponentInParent(); if ((Object)(object)componentInParent == (Object)null) { return; } ApplyVelocityDamp(componentInParent); if (!_isStillWaterTick) { ApplyRiverStreamPush(__instance, componentInParent, other); } DataHandler componentInChildren = ((Component)((Component)other).transform.root).GetComponentInChildren(); if (!((Object)(object)componentInChildren?.mainRig == (Object)null) && !componentInChildren.Dead && ShouldApplyCustomPhysicsOnce(__instance, componentInChildren)) { if (_isStillWaterTick) { ClampStillHorizontal(componentInChildren.mainRig); ClampStillVertical(__instance, componentInChildren); } else { ApplyRiverLegBoost(__instance, componentInChildren); } } } internal static void ResetRiverFlowDirections() { CachedFlowDirectionByWaterId.Clear(); _flowDirectionsCalibrated = false; _hasForkMap = false; } private static void EnsureRiverFlowDirectionsCalibrated() { if (!_flowDirectionsCalibrated) { CalibrateRiverFlowDirections(); } } private static void CalibrateRiverFlowDirections() { //IL_0025: Unknown result type (might be due to invalid IL or missing references) //IL_002a: 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_003e: Unknown result type (might be due to invalid IL or missing references) //IL_0043: 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_0059: Unknown result type (might be due to invalid IL or missing references) //IL_0061: 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_0092: Unknown result type (might be due to invalid IL or missing references) //IL_0097: Unknown result type (might be due to invalid IL or missing references) //IL_0099: Unknown result type (might be due to invalid IL or missing references) //IL_00a0: Unknown result type (might be due to invalid IL or missing references) //IL_00b4: 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_00cd: Unknown result type (might be due to invalid IL or missing references) //IL_00d4: 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_00f1: Unknown result type (might be due to invalid IL or missing references) //IL_0171: Unknown result type (might be due to invalid IL or missing references) //IL_0176: Unknown result type (might be due to invalid IL or missing references) //IL_0168: Unknown result type (might be due to invalid IL or missing references) //IL_01cc: Unknown result type (might be due to invalid IL or missing references) CachedFlowDirectionByWaterId.Clear(); _hasForkMap = false; List list = CollectRiverWaters(); if (list.Count == 0) { _flowDirectionsCalibrated = true; return; } Vector3 val = Vector3.zero; for (int i = 0; i < list.Count; i++) { val += ((Component)list[i]).transform.position; } val /= (float)list.Count; val.y = 0f; int num = 0; int num2 = 0; int num3 = 0; int num4 = 0; for (int j = 0; j < list.Count; j++) { Vector3 position = ((Component)list[j]).transform.position; if (position.z - val.z > 20f) { num++; } else if (position.z - val.z < -20f) { num2++; } if (position.x - val.x > 20f) { num3++; } else if (position.x - val.x < -20f) { num4++; } } bool flag = num >= 2 && num2 >= 2; bool flag2 = num3 >= 2 && num4 >= 2; _hasForkMap = flag || flag2; for (int k = 0; k < list.Count; k++) { Water val2 = list[k]; CachedFlowDirectionByWaterId[((Object)val2).GetInstanceID()] = (_hasForkMap ? ResolveForkBranchFlowDirection(val2, val, flag, flag2) : ResolveDefaultFlowDirection(val2)); } _flowDirectionsCalibrated = true; LogInfo?.Invoke($"River flow calibrated: {list.Count} volumes, fork={_hasForkMap}, " + $"center={val}, posZ={num}, negZ={num2}, posX={num3}, negX={num4}"); } private static Vector3 ResolveForkBranchFlowDirection(Water water, Vector3 center, bool forkOnZ, bool forkOnX) { //IL_0006: Unknown result type (might be due to invalid IL or missing references) //IL_000b: 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_0038: 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_0025: 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_004a: Unknown result type (might be due to invalid IL or missing references) //IL_0056: Unknown result type (might be due to invalid IL or missing references) //IL_005c: Unknown result type (might be due to invalid IL or missing references) //IL_0085: 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_0075: Unknown result type (might be due to invalid IL or missing references) //IL_007b: Unknown result type (might be due to invalid IL or missing references) //IL_0097: Unknown result type (might be due to invalid IL or missing references) //IL_0098: 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) Vector3 val = FlattenHorizontal(((Component)water).transform.forward); if (((Vector3)(ref val)).sqrMagnitude < 0.0001f) { return ((Component)water).transform.forward; } ((Vector3)(ref val)).Normalize(); Vector3 position = ((Component)water).transform.position; if (!((forkOnZ && (!forkOnX || Mathf.Abs(position.z - center.z) >= Mathf.Abs(position.x - center.x))) ? (position.z > center.z) : (position.x > center.x))) { return val; } return -val; } private static List CollectRiverWaters() { List list = new List(); Water[] array = Object.FindObjectsOfType(); foreach (Water val in array) { if (!((Object)(object)val == (Object)null) && !IsStillWater(val)) { list.Add(val); } } return list; } private static Vector3 ResolveDefaultFlowDirection(Water water) { //IL_0015: Unknown result type (might be due to invalid IL or missing references) //IL_001a: 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_0009: Unknown result type (might be due to invalid IL or missing references) //IL_003c: Unknown result type (might be due to invalid IL or missing references) //IL_0034: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)water == (Object)null) { return Vector3.forward; } Vector3 val = FlattenHorizontal(((Component)water).transform.forward); if (!(((Vector3)(ref val)).sqrMagnitude > 0.0001f)) { return ((Component)water).transform.forward; } return ((Vector3)(ref val)).normalized; } private static Vector3 GetFlowDirection(Water water) { //IL_0025: Unknown result type (might be due to invalid IL or missing references) //IL_0022: Unknown result type (might be due to invalid IL or missing references) EnsureRiverFlowDirectionsCalibrated(); if ((Object)(object)water != (Object)null && CachedFlowDirectionByWaterId.TryGetValue(((Object)water).GetInstanceID(), out var value)) { return value; } return ResolveDefaultFlowDirection(water); } private static bool ShouldApplyCustomPhysicsOnce(Water water, DataHandler data) { if (Time.fixedTime != _customPhysicsFixedTime) { _customPhysicsFixedTime = Time.fixedTime; _customPhysicsKeys.Clear(); } long item = ((long)((Object)water).GetInstanceID() << 32) | (uint)((Object)data).GetInstanceID(); return _customPhysicsKeys.Add(item); } private static bool IsStillWater(Water water) { if (water.damageOverTime > 0f) { return Mathf.Abs(water.streamForce) < 1f; } return false; } private static void ApplyVelocityDamp(Rigidbody rb) { //IL_0016: Unknown result type (might be due to invalid IL or missing references) //IL_0020: Unknown result type (might be due to invalid IL or missing references) //IL_0026: 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_003c: 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) float num = (_isStillWaterTick ? WaterConfig.StillVelocityDamp : WaterConfig.RiverVelocityDamp); rb.velocity = rb.velocity / 0.15f * num; rb.angularVelocity = rb.angularVelocity / 0.15f * num; } private static Rigidbody GetHipBody(DataHandler data) { object? obj = HipField?.GetValue(data); Rigidbody val = (Rigidbody)((obj is Rigidbody) ? obj : null); if (val != null) { return val; } return null; } private static Rigidbody GetLegRigidbody(Transform leg) { if ((Object)(object)leg == (Object)null) { return null; } Rigidbody component = ((Component)leg).GetComponent(); if (!((Object)(object)component != (Object)null)) { return ((Component)leg).GetComponentInParent(); } return component; } private static Rigidbody GetFootRigidbody(Transform foot) { if ((Object)(object)foot == (Object)null) { return null; } Rigidbody component = ((Component)foot).GetComponent(); if (!((Object)(object)component != (Object)null)) { return ((Component)foot).GetComponentInParent(); } return component; } private static float CalcSubmersionFromCollider(Water water, Collider other) { //IL_0006: 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) return Mathf.Clamp((((Component)water).transform.position.y + water.waterSinkOffset - ((Component)other).transform.position.y) * 10f, 0f, 10f) * Time.deltaTime; } private static float CalcSubmersionFromSample(Water water, Vector3 samplePoint) { //IL_0006: 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) return Mathf.Clamp((((Component)water).transform.position.y + water.waterSinkOffset - samplePoint.y) * 10f, 0f, 10f) * Time.deltaTime; } private static Vector3 GetRiverSamplePoint(DataHandler data) { //IL_0002: Unknown result type (might be due to invalid IL or missing references) //IL_0007: Unknown result type (might be due to invalid IL or missing references) //IL_0018: Unknown result type (might be due to invalid IL or missing references) //IL_001a: 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_0024: 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_003e: Unknown result type (might be due to invalid IL or missing references) //IL_0043: 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_005b: Unknown result type (might be due to invalid IL or missing references) //IL_0062: Unknown result type (might be due to invalid IL or missing references) //IL_0067: Unknown result type (might be due to invalid IL or missing references) //IL_006c: Unknown result type (might be due to invalid IL or missing references) //IL_007f: Unknown result type (might be due to invalid IL or missing references) //IL_0086: 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_0090: Unknown result type (might be due to invalid IL or missing references) //IL_00a3: Unknown result type (might be due to invalid IL or missing references) //IL_00aa: 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) //IL_00b4: Unknown result type (might be due to invalid IL or missing references) //IL_00c9: Unknown result type (might be due to invalid IL or missing references) //IL_00cc: 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) int num = 0; Vector3 val = Vector3.zero; Rigidbody hipBody = GetHipBody(data); if ((Object)(object)hipBody != (Object)null) { val += hipBody.position; num++; } if ((Object)(object)data.legLeft != (Object)null) { val += data.legLeft.position; num++; } if ((Object)(object)data.legRight != (Object)null) { val += data.legRight.position; num++; } if ((Object)(object)data.footLeft != (Object)null) { val += data.footLeft.position; num++; } if ((Object)(object)data.footRight != (Object)null) { val += data.footRight.position; num++; } if (num <= 0) { return data.mainRig.position; } return val / (float)num; } private static void ApplyRiverLegForce(DataHandler data, Vector3 force) { //IL_008d: 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) //IL_009f: Unknown result type (might be due to invalid IL or missing references) //IL_0085: Unknown result type (might be due to invalid IL or missing references) //IL_00b5: Unknown result type (might be due to invalid IL or missing references) HashSet seen = new HashSet(); List targets = new List(); AddTarget(GetHipBody(data)); AddTarget(GetLegRigidbody(data.legLeft)); AddTarget(GetLegRigidbody(data.legRight)); AddTarget(GetFootRigidbody(data.footLeft)); AddTarget(GetFootRigidbody(data.footRight)); if (targets.Count == 0) { Rigidbody mainRig = data.mainRig; if (mainRig != null) { mainRig.AddForce(force, (ForceMode)5); } return; } Vector3 val = force / (float)targets.Count; foreach (Rigidbody item in targets) { item.AddForce(val, (ForceMode)5); } void AddTarget(Rigidbody target) { if (!((Object)(object)target == (Object)null) && seen.Add(target)) { targets.Add(target); } } } private static void ClampStillHorizontal(Rigidbody mainRig) { //IL_0019: Unknown result type (might be due to invalid IL or missing references) //IL_001e: 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_002c: Unknown result type (might be due to invalid IL or missing references) //IL_0046: Unknown result type (might be due to invalid IL or missing references) //IL_004c: Unknown result type (might be due to invalid IL or missing references) //IL_0051: 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_0059: Unknown result type (might be due to invalid IL or missing references) //IL_005f: 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) float stillMaxHorizontalSpeed = WaterConfig.StillMaxHorizontalSpeed; if (!(stillMaxHorizontalSpeed <= 0f) && !((Object)(object)mainRig == (Object)null)) { Vector3 velocity = mainRig.velocity; Vector3 val = default(Vector3); ((Vector3)(ref val))..ctor(velocity.x, 0f, velocity.z); if (!(((Vector3)(ref val)).sqrMagnitude <= stillMaxHorizontalSpeed * stillMaxHorizontalSpeed)) { val = ((Vector3)(ref val)).normalized * stillMaxHorizontalSpeed; mainRig.velocity = new Vector3(val.x, velocity.y, val.z); } } } private static void ClampStillVertical(Water water, DataHandler data) { if (!((Object)(object)data.mainRig == (Object)null) && !data.mainRig.isKinematic) { ClampBobSpeed(water, data.mainRig); } } private static void ClampBobSpeed(Water water, Rigidbody rb) { //IL_0006: Unknown result type (might be due to invalid IL or missing references) //IL_0018: Unknown result type (might be due to invalid IL or missing references) //IL_003c: Unknown result type (might be due to invalid IL or missing references) //IL_0041: 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_0051: Unknown result type (might be due to invalid IL or missing references) //IL_005c: Unknown result type (might be due to invalid IL or missing references) //IL_0062: Unknown result type (might be due to invalid IL or missing references) float num = (((Component)water).transform.position.y + water.waterSinkOffset - rb.position.y) * 10f; if (!(num <= 0f) && !(num > 1f)) { Vector3 velocity = rb.velocity; if (!(velocity.y <= 6f)) { rb.velocity = new Vector3(velocity.x, 6f, velocity.z); } } } private static void ApplyRiverStreamPush(Water water, Rigidbody rb, Collider other) { //IL_003b: 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) //IL_005b: Unknown result type (might be due to invalid IL or missing references) //IL_005c: 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_0051: Unknown result type (might be due to invalid IL or missing references) //IL_0056: Unknown result type (might be due to invalid IL or missing references) float num = CalcSubmersionFromCollider(water, other); float streamForce = water.streamForce; float num2; if (Mathf.Abs(streamForce) > 0f) { num2 = Mathf.Abs(streamForce); } else { if (!(WaterConfig.MinimumStreamForce > 0f)) { return; } num2 = WaterConfig.MinimumStreamForce; } Vector3 val = GetFlowDirection(water); if (!_hasForkMap && streamForce < 0f) { val = -val; } rb.AddForce(num2 * num * val, (ForceMode)5); } private static void ApplyRiverLegBoost(Water water, DataHandler data) { //IL_000f: Unknown result type (might be due to invalid IL or missing references) //IL_005d: Unknown result type (might be due to invalid IL or missing references) //IL_0062: Unknown result type (might be due to invalid IL or missing references) //IL_0083: Unknown result type (might be due to invalid IL or missing references) //IL_0084: 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_0073: Unknown result type (might be due to invalid IL or missing references) //IL_0078: Unknown result type (might be due to invalid IL or missing references) if (WaterConfig.RiverMainRigPushScale <= 0f) { return; } float num = Mathf.Max(CalcSubmersionFromSample(water, GetRiverSamplePoint(data)), WaterConfig.RiverEffectDepth * Time.deltaTime); float streamForce = water.streamForce; float num2; if (Mathf.Abs(streamForce) > 0f) { num2 = Mathf.Abs(streamForce); } else { if (!(WaterConfig.MinimumStreamForce > 0f)) { return; } num2 = WaterConfig.MinimumStreamForce; } Vector3 val = GetFlowDirection(water); if (!_hasForkMap && streamForce < 0f) { val = -val; } ApplyRiverLegForce(data, num2 * num * WaterConfig.RiverMainRigPushScale * val); } private static Vector3 FlattenHorizontal(Vector3 vector) { //IL_000c: Unknown result type (might be due to invalid IL or missing references) vector.y = 0f; return vector; } } internal static class WeaponStayPatches { private static readonly Dictionary SavedForwardRotation = new Dictionary(); private static readonly FieldInfo HoldingHandlerDataField = typeof(HoldingHandler).GetField("data", BindingFlags.Instance | BindingFlags.NonPublic); public static void HoldingHandler_AddForce_Prefix(HoldingHandler __instance, PidDataInstance pidData, ref Vector3 targetPosition, float multiplier) { //IL_0057: Unknown result type (might be due to invalid IL or missing references) //IL_005c: 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_006a: Unknown result type (might be due to invalid IL or missing references) //IL_0070: Unknown result type (might be due to invalid IL or missing references) //IL_0075: Unknown result type (might be due to invalid IL or missing references) DataHandler data = GetData(__instance); if (!((Object)(object)data == (Object)null) && StayFixLogic.IsStayLocked(data) && !StayFixLogic.ShouldSkipStayPhysicsLock(data) && !((Object)(object)pidData?.rig == (Object)null)) { Holdable holdable = FindHoldableByPid(__instance, pidData); if (StayFixLogic.ShouldClampWeaponHoldPosition(data, holdable) && !StayFixLogic.ShouldTrackTargetWithWeapon(data, holdable)) { Vector3 position = pidData.rig.position; targetPosition = new Vector3(position.x, targetPosition.y, position.z); } } } public static void HoldingHandler_DoPID_Prefix(HoldingHandler __instance, PidDataInstance pidData, HoldableDataInstance holdableData, ref float multiplier) { DataHandler data = GetData(__instance); if (!((Object)(object)data == (Object)null) && StayFixLogic.IsStayLocked(data) && pidData != null && holdableData != null) { Holdable val = FindHoldableByPid(__instance, pidData); if (!((Object)(object)val == (Object)null) && StayFixLogic.ShouldTrackTargetWithWeapon(data, val) && !StayFixLogic.UsesArcingHoldableAim(val)) { StayFixLogic.ApplyExtendedLookAtAim(data, val); multiplier *= StayFixLogic.GetWeaponTrackPidMultiplier(data); } } } public static void Holdable_BatchedUpdate_Prefix(Holdable __instance) { //IL_002e: Unknown result type (might be due to invalid IL or missing references) if (!((Object)(object)__instance?.holderData == (Object)null) && StayFixLogic.IsStayLocked(__instance.holderData)) { SavedForwardRotation[__instance] = __instance.holdableData.forwardRotation; } } public static void Holdable_BatchedUpdate_Postfix(Holdable __instance) { //IL_004d: 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) DataHandler val = __instance?.holderData; if ((Object)(object)val == (Object)null || !StayFixLogic.IsStayLocked(val)) { return; } Vector3 value; if (StayFixLogic.ShouldTrackTargetWithWeapon(val, __instance)) { if (!StayFixLogic.UsesArcingHoldableAim(__instance)) { StayFixLogic.ApplyExtendedLookAtAim(val, __instance); } } else if (SavedForwardRotation.TryGetValue(__instance, out value)) { __instance.holdableData.forwardRotation = value; } } public static void HoldingHandler_BatchedFixedUpdate_Postfix(HoldingHandler __instance) { DataHandler data = GetData(__instance); if (!((Object)(object)data == (Object)null) && StayFixLogic.IsStayLocked(data)) { StayFixLogic.EnforcePlantPosition(data); } } private static Holdable FindHoldableByPid(HoldingHandler holding, PidDataInstance pidData) { if ((Object)(object)holding == (Object)null || pidData == null) { return null; } string[] array = new string[2] { "rightObject", "leftObject" }; foreach (string name in array) { object? obj = typeof(HoldingHandler).GetField(name, BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic)?.GetValue(holding); Holdable val = (Holdable)((obj is Holdable) ? obj : null); if (val?.pidData == pidData) { return val; } } return null; } private static DataHandler GetData(HoldingHandler handler) { if ((Object)(object)handler == (Object)null || HoldingHandlerDataField == null) { return null; } object? value = HoldingHandlerDataField.GetValue(handler); return (DataHandler)((value is DataHandler) ? value : null); } } }