using System; using System.Collections; using System.Collections.Generic; using System.Diagnostics; using System.Reflection; using System.Reflection.Emit; using System.Runtime.CompilerServices; using System.Runtime.Versioning; using System.Security; using System.Security.Permissions; using BepInEx; using FishNet.Object; using FishNet.Object.Synchronizing; using HarmonyLib; using Microsoft.CodeAnalysis; using UnityEngine; using UnityEngine.InputSystem; using UnityEngine.InputSystem.Controls; [assembly: CompilationRelaxations(8)] [assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)] [assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)] [assembly: TargetFramework(".NETFramework,Version=v4.7.2", FrameworkDisplayName = ".NET Framework 4.7.2")] [assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)] [assembly: AssemblyVersion("0.0.0.0")] [module: UnverifiableCode] [module: RefSafetyRules(11)] namespace Microsoft.CodeAnalysis { [CompilerGenerated] [Embedded] internal sealed class EmbeddedAttribute : Attribute { } } namespace System.Runtime.CompilerServices { [CompilerGenerated] [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 MutatedWhalePhases { internal static class BallisticUtils { public static Vector3 SolveVelocityForFlightTime(Vector3 start, Vector3 end, float flightTime, float gravity) { //IL_000d: Unknown result type (might be due to invalid IL or missing references) //IL_000e: Unknown result type (might be due to invalid IL or missing references) //IL_000f: 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_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_002b: 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_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) flightTime = Mathf.Max(flightTime, 0.1f); Vector3 val = end - start; Vector3 val2 = new Vector3(val.x, 0f, val.z); float y = val.y; Vector3 val3 = val2 / flightTime; float num = y / flightTime + 0.5f * gravity * flightTime; return val3 + Vector3.up * num; } public static Vector3 PositionAtTime(Vector3 start, Vector3 initialVelocity, float gravity, float time) { //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_0003: Unknown result type (might be due to invalid IL or missing references) //IL_0008: Unknown result type (might be due to invalid IL or missing references) //IL_000d: Unknown result type (might be due to invalid IL or missing references) //IL_0024: Unknown result type (might be due to invalid IL or missing references) Vector3 result = start + initialVelocity * time; result.y -= 0.5f * gravity * time * time; return result; } } [HarmonyPatch(typeof(PlayerHands))] internal static class BoatHandVisualPatch { private static readonly FieldInfo PlayerField = AccessTools.Field(typeof(PlayerHands), "_player"); [HarmonyPatch(/*Could not decode attribute arguments.*/)] [HarmonyPrefix] private static bool BeforeDrivenBoatGetter(PlayerHands __instance, ref Boat __result) { if (!BowheadWhaleAccess.IsSecondPhaseActive()) { return true; } object? value = PlayerField.GetValue(__instance); Player val = (Player)((value is Player) ? value : null); if ((Object)(object)val == (Object)null || !Object.op_Implicit((Object)(object)val.Holding.HeldItem)) { return true; } __result = null; return false; } } [HarmonyPatch] internal static class BoatItemGatePatch { private static readonly MethodInfo IsDrivingLocallyGetter = AccessTools.PropertyGetter(typeof(Boat), "IsDrivingLocally"); private static readonly MethodInfo WantToDriveGetter = AccessTools.PropertyGetter(typeof(Boat), "WantToDrive"); private static readonly MethodInfo BypassIsDrivingLocallyMethod = AccessTools.Method(typeof(BoatItemGatePatch), "BypassIsDrivingLocally", (Type[])null, (Type[])null); private static readonly MethodInfo BypassWantToDriveMethod = AccessTools.Method(typeof(BoatItemGatePatch), "BypassWantToDrive", (Type[])null, (Type[])null); private static bool BypassIsDrivingLocally() { if (!BowheadWhaleAccess.IsSecondPhaseActive()) { return Boat.IsDrivingLocally; } return false; } private static bool BypassWantToDrive() { if (!BowheadWhaleAccess.IsSecondPhaseActive()) { return Boat.WantToDrive; } return false; } private static IEnumerable Transpile(IEnumerable instructions) { foreach (CodeInstruction instruction in instructions) { if (CodeInstructionExtensions.Calls(instruction, IsDrivingLocallyGetter)) { yield return new CodeInstruction(OpCodes.Call, (object)BypassIsDrivingLocallyMethod); } else if (CodeInstructionExtensions.Calls(instruction, WantToDriveGetter)) { yield return new CodeInstruction(OpCodes.Call, (object)BypassWantToDriveMethod); } else { yield return instruction; } } } [HarmonyPatch(typeof(PlayerInventory), "DeselectSlotInput")] [HarmonyTranspiler] private static IEnumerable TranspileDeselectSlotInput(IEnumerable instructions) { return Transpile(instructions); } [HarmonyPatch(typeof(PlayerInventory), "SelectSlotInput")] [HarmonyTranspiler] private static IEnumerable TranspileSelectSlotInput(IEnumerable instructions) { return Transpile(instructions); } [HarmonyPatch(typeof(PlayerInventory), "ScrollSlotInput")] [HarmonyTranspiler] private static IEnumerable TranspileScrollSlotInput(IEnumerable instructions) { return Transpile(instructions); } [HarmonyPatch(typeof(PlayerInventory), "ChangeBaitInput")] [HarmonyTranspiler] private static IEnumerable TranspileChangeBaitInput(IEnumerable instructions) { return Transpile(instructions); } [HarmonyPatch(typeof(PlayerHolding), "ScanForGrabbableItem")] [HarmonyTranspiler] private static IEnumerable TranspileScanForGrabbableItem(IEnumerable instructions) { return Transpile(instructions); } [HarmonyPatch(typeof(PlayerHolding), "ScanForInteractable")] [HarmonyTranspiler] private static IEnumerable TranspileScanForInteractable(IEnumerable instructions) { return Transpile(instructions); } [HarmonyPatch(typeof(PlayerPunching), "PunchInput")] [HarmonyTranspiler] private static IEnumerable TranspilePunchInput(IEnumerable instructions) { return Transpile(instructions); } } [HarmonyPatch] internal static class BoatPhaseTwoPatch { private static readonly FieldInfo DriverField = AccessTools.Field(typeof(Boat), "_driver"); [HarmonyPatch(typeof(Boat), "TrySetDriver")] [HarmonyPrefix] private static bool BeforeTrySetDriver(Boat __instance, Player newDriver) { if (!BowheadWhaleAccess.IsSecondPhaseActive()) { return true; } if (Object.op_Implicit((Object)(object)__instance.Driver) && Object.op_Implicit((Object)(object)newDriver)) { return false; } ((SyncVar)DriverField.GetValue(__instance)).Value = newDriver; return false; } } internal static class BowheadWhaleAccess { private static readonly FieldInfo ActiveWhaleField = typeof(BowheadWhale).GetField("_whale", BindingFlags.Static | BindingFlags.NonPublic); public static bool TryGetActiveBoss(out BowheadWhale whale) { //IL_001e: Unknown result type (might be due to invalid IL or missing references) //IL_0024: Invalid comparison between Unknown and I4 object? value = ActiveWhaleField.GetValue(null); whale = (BowheadWhale)((value is BowheadWhale) ? value : null); if ((Object)(object)whale != (Object)null && (int)((Creature)whale).BossType == 2) { return !((Creature)whale).IsDead; } return false; } public static bool IsSecondPhaseActive() { if (TryGetActiveBoss(out var whale)) { return whale._inSecondPhase.Value; } return false; } } internal static class DebugKeys { private static readonly MethodInfo SpawnMutatedWhaleMethod = AccessTools.Method(typeof(MainLava), "SpawnMutatedWhale", (Type[])null, (Type[])null); private static readonly FieldInfo IsSpawningWhaleField = AccessTools.Field(typeof(MainLava), "_isSpawningWhale"); public static void Update() { Keyboard current = Keyboard.current; if (current != null) { if (((ButtonControl)current.jKey).wasPressedThisFrame) { TrySpawnWhale(); } if (((ButtonControl)current.kKey).wasPressedThisFrame) { TrySetBossHpPercent(0.49f); } if (((ButtonControl)current.lKey).wasPressedThisFrame) { TrySetBossHpPercent(0.09f); } } } private static void TrySpawnWhale() { if (!((Object)(object)BossManager.Boss != (Object)null)) { MainLava val = Object.FindAnyObjectByType(); if (!((Object)(object)val == (Object)null) && !(bool)IsSpawningWhaleField.GetValue(val)) { ((MonoBehaviour)val).StartCoroutine((IEnumerator)SpawnMutatedWhaleMethod.Invoke(val, null)); } } } private static void TrySetBossHpPercent(float targetPercent) { Creature boss = BossManager.Boss; if (!((Object)(object)boss == (Object)null) && !boss.IsDead) { int num = Mathf.Max(1, Mathf.RoundToInt((float)BossManager.BossMaxHp * targetPercent)); int num2 = boss.Hp - num; if (num2 > 0) { boss.ServerChangeHp(num2); } } } } [BepInPlugin("community.howtofish.mutatedwhalephases", "Mutated Whale Phases", "1.0.0")] public class Plugin : BaseUnityPlugin { public const string PluginGuid = "community.howtofish.mutatedwhalephases"; public const string PluginName = "Mutated Whale Phases"; public const string PluginVersion = "1.0.0"; private Harmony _harmony; private void Awake() { //IL_0006: Unknown result type (might be due to invalid IL or missing references) //IL_0010: Expected O, but got Unknown _harmony = new Harmony("community.howtofish.mutatedwhalephases"); _harmony.PatchAll(); ((BaseUnityPlugin)this).Logger.LogInfo((object)"Mutated Whale Phases loaded: lava reflect + third phase patches applied."); } private void Update() { DebugKeys.Update(); } private void OnDestroy() { Harmony harmony = _harmony; if (harmony != null) { harmony.UnpatchSelf(); } } } [HarmonyPatch] internal static class SecondPhaseLaunchPatch { private const float MinFlightTime = 3.5f; private const float FlightSpeedCap = 40f; private const float LaunchHeightBonus = 25f; private const float LandingSnapDistance = 10f; private const float ScreenShakeDuration = 3f; private const float TargetDistanceMultiplier = 4f; private static readonly FieldInfo RigField = AccessTools.Field(typeof(PlayerMovement), "_rig"); private static readonly FieldInfo ExtraGravityForceField = AccessTools.Field(typeof(PlayerMovement), "_extraGravityForce"); private static readonly FieldInfo PlayerField = AccessTools.Field(typeof(PlayerMovement), "_player"); private static float GetGravity(PlayerMovement movement) { return (float)ExtraGravityForceField.GetValue(movement); } [HarmonyPatch(typeof(BowheadWhale), "OnHealthChange")] [HarmonyPostfix] private static void AfterOnHealthChange(BowheadWhale __instance, bool asServer) { //IL_0004: Unknown result type (might be due to invalid IL or missing references) //IL_000a: Invalid comparison between Unknown and I4 if (asServer && (int)((Creature)__instance).BossType == 2 && __instance._inSecondPhase.Value && !SecondPhaseSequenceState.SequenceTriggered) { SecondPhaseSequenceState.SequenceTriggered = true; ((MonoBehaviour)__instance).StartCoroutine(RunLaunchSequence(__instance)); } } private static IEnumerator RunLaunchSequence(BowheadWhale whale) { Vector3 position = ((Component)whale).transform.position; Vector3 targetPos = (SecondPhaseSequenceState.TargetPosition = ComputeOpenWaterTarget(position)); foreach (Player alivePlayer in PlayerManager.AlivePlayers) { alivePlayer.ScreenShake.ConstantShake(true); } yield return null; LaunchAllPlayers(targetPos); LaunchBoatToFollow(targetPos); while (SecondPhaseSequenceState.FlyingPlayers.Count > 0) { yield return null; } SnapBoatAndPlayersToLanding(targetPos); foreach (Player alivePlayer2 in PlayerManager.AlivePlayers) { alivePlayer2.ScreenShake.ConstantShake(false); } SecondPhaseWhaleFollowPatch.BeginFollow(whale, BoatManager.Boat); } private static Vector3 ComputeOpenWaterTarget(Vector3 whalePos) { //IL_006f: 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_000a: 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_0015: 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_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_0037: Unknown result type (might be due to invalid IL or missing references) //IL_003b: Unknown result type (might be due to invalid IL or missing references) //IL_0025: 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_0042: Unknown result type (might be due to invalid IL or missing references) //IL_0047: Unknown result type (might be due to invalid IL or missing references) //IL_0054: 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_006c: 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_00ba: Unknown result type (might be due to invalid IL or missing references) //IL_00b0: Unknown result type (might be due to invalid IL or missing references) //IL_00bf: 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_008f: 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) int totalIslands = IslandManager.TotalIslands; if (totalIslands <= 0) { Vector3 val = whalePos - Island.IslandPos; Vector3 val2; if (!(((Vector3)(ref val)).sqrMagnitude > 1f)) { val2 = Vector3.forward; } else { val = whalePos - Island.IslandPos; val2 = ((Vector3)(ref val)).normalized; } Vector3 val3 = val2; Vector3 result = Island.IslandPos + val3 * (Island.IslandSize * 4f); result.y = WaterManager.WaterHeight; return result; } Vector3 val4 = Vector3.zero; int num = 0; for (int i = 0; i < totalIslands; i++) { IslandInfo islandInfo; try { islandInfo = IslandManager.GetIslandInfo(i); } catch { continue; } if (islandInfo != null) { val4 += islandInfo.IslandPosition; num++; } } Vector3 result2 = ((num > 0) ? (val4 / (float)num) : Island.IslandPos); result2.y = WaterManager.WaterHeight; return result2; } private static void LaunchAllPlayers(Vector3 targetPos) { //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_0024: 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_0038: 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_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_006b: 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) foreach (Player alivePlayer in PlayerManager.AlivePlayers) { Vector3 position = alivePlayer.Transform.position; Vector3 val = targetPos + Vector3.up * 25f; float num = Vector3.Distance(position, val); float num2 = Mathf.Max(3.5f, num / 40f); float gravity = GetGravity(alivePlayer.Movement); Vector3 linearVelocity = BallisticUtils.SolveVelocityForFlightTime(position, val, num2, gravity); Rigidbody rigidbody = alivePlayer.Rigidbody; if ((Object)(object)rigidbody != (Object)null) { rigidbody.linearVelocity = linearVelocity; } SecondPhaseSequenceState.FlyingPlayers.Add(alivePlayer); SecondPhaseSequenceState.LaunchTime[alivePlayer] = Time.time; SecondPhaseSequenceState.FlightDuration[alivePlayer] = num2; } SecondPhaseSequenceState.PlayersAirborne = true; } private static void LaunchBoatToFollow(Vector3 targetPos) { Boat boat = BoatManager.Boat; if (!((Object)(object)boat == (Object)null)) { boat.HiddenPhysicsRig.isKinematic = true; } } [HarmonyPatch(typeof(PlayerMovement), "Move")] [HarmonyPrefix] private static bool BeforeMove(PlayerMovement __instance) { //IL_0047: 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_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) object? value = PlayerField.GetValue(__instance); Player val = (Player)((value is Player) ? value : null); if ((Object)(object)val == (Object)null || !SecondPhaseSequenceState.FlyingPlayers.Contains(val)) { return true; } object? value2 = RigField.GetValue(__instance); Rigidbody val2 = (Rigidbody)((value2 is Rigidbody) ? value2 : null); if ((Object)(object)val2 == (Object)null) { return true; } val2.linearVelocity += Vector3.down * (GetGravity(__instance) * Time.fixedDeltaTime); TryLandPlayer(val, val2); return false; } private static void TryLandPlayer(Player player, Rigidbody rig) { //IL_005b: 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_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_0081: Unknown result type (might be due to invalid IL or missing references) //IL_0091: Unknown result type (might be due to invalid IL or missing references) //IL_00bd: Unknown result type (might be due to invalid IL or missing references) Boat boat = BoatManager.Boat; if (!((Object)(object)boat == (Object)null)) { FollowPlayersWithBoat(boat); float value; float num = (SecondPhaseSequenceState.LaunchTime.TryGetValue(player, out value) ? value : Time.time); float value2; float num2 = (SecondPhaseSequenceState.FlightDuration.TryGetValue(player, out value2) ? value2 : 3.5f); bool num3 = Time.time - num >= num2 + 1.5f; Vector3 val = rig.position - boat.HiddenPhysicsRig.position; bool flag = ((Vector3)(ref val)).sqrMagnitude <= 100f && rig.position.y <= boat.HiddenPhysicsRig.position.y + 3f; if (num3 || flag) { SecondPhaseSequenceState.FlyingPlayers.Remove(player); rig.linearVelocity = Vector3.zero; } } } private static void FollowPlayersWithBoat(Boat boat) { //IL_0000: 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_001f: Unknown result type (might be due to invalid IL or missing references) //IL_0027: Unknown result type (might be due to invalid IL or missing references) //IL_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_0053: 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_005b: 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_0069: Unknown result type (might be due to invalid IL or missing references) //IL_007a: Unknown result type (might be due to invalid IL or missing references) Vector3 val = Vector3.zero; int num = 0; foreach (Player flyingPlayer in SecondPhaseSequenceState.FlyingPlayers) { val += flyingPlayer.Transform.position; num++; } if (num != 0) { Vector3 val2 = val / (float)num; Vector3 val3 = default(Vector3); ((Vector3)(ref val3))..ctor(val2.x, WaterManager.WaterHeight, val2.z); boat.HiddenPhysicsRig.MovePosition(val3); } } private static void SnapBoatAndPlayersToLanding(Vector3 targetPos) { //IL_0011: Unknown result type (might be due to invalid IL or missing references) //IL_001c: Unknown result type (might be due to invalid IL or missing references) //IL_002d: Unknown result type (might be due to invalid IL or missing references) Boat boat = BoatManager.Boat; if ((Object)(object)boat != (Object)null) { Vector3 val = default(Vector3); ((Vector3)(ref val))..ctor(targetPos.x, WaterManager.WaterHeight, targetPos.z); boat.HiddenPhysicsRig.MovePosition(val); boat.HiddenPhysicsRig.isKinematic = false; } SecondPhaseSequenceState.PlayersAirborne = false; } } internal static class SecondPhaseSequenceState { public static bool SequenceTriggered; public static bool PlayersAirborne; public static Vector3 TargetPosition; public static readonly HashSet FlyingPlayers = new HashSet(); public static readonly Dictionary LaunchTime = new Dictionary(); public static readonly Dictionary FlightDuration = new Dictionary(); public static void Reset() { //IL_000c: Unknown result type (might be due to invalid IL or missing references) //IL_0011: Unknown result type (might be due to invalid IL or missing references) SequenceTriggered = false; PlayersAirborne = false; TargetPosition = Vector3.zero; FlyingPlayers.Clear(); LaunchTime.Clear(); FlightDuration.Clear(); } } [HarmonyPatch(typeof(BowheadWhale))] internal static class SecondPhaseTargetPriorityPatch { private const int LethalDamage = 99999; private static readonly FieldInfo TargetField = AccessTools.Field(typeof(AttackingFish), "_target"); private static Player _priorityTarget; [HarmonyPatch("UpdateMovement")] [HarmonyPostfix] private static void AfterUpdateMovement(BowheadWhale __instance) { if (!BowheadWhaleAccess.IsSecondPhaseActive() || !((NetworkBehaviour)__instance).IsServerInitialized) { _priorityTarget = null; return; } Player val = (_priorityTarget = FindPlayerInWater()); if ((Object)(object)val != (Object)null) { TargetField.SetValue(__instance, val); } } private static Player FindPlayerInWater() { //IL_0037: Unknown result type (might be due to invalid IL or missing references) foreach (Player alivePlayer in PlayerManager.AlivePlayers) { bool num = (Object)(object)alivePlayer.Movement != (Object)null && alivePlayer.Movement.OnBoat; bool flag = alivePlayer.Transform.position.y <= WaterManager.WaterHeight; if (!num && flag) { return alivePlayer; } } return null; } [HarmonyPatch("DamageOnCollision")] [HarmonyPrefix] private static bool BeforeDamageOnCollision(BowheadWhale __instance, Player player, Vector3 pos) { //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) if (!BowheadWhaleAccess.IsSecondPhaseActive() || (Object)(object)_priorityTarget == (Object)null || (Object)(object)player != (Object)(object)_priorityTarget) { return true; } Server.Instance.HitPlayer(player, 99999, Vector3.zero, pos, (byte)2, (Player)null); return false; } } [HarmonyPatch(typeof(BowheadWhale))] internal static class SecondPhaseWhaleFollowPatch { private const float RoarShakeDuration = 3f; private const float BowOffsetDistance = 20f; private const float MinFlightTime = 2.5f; private const float SpeedCap = 60f; private static readonly FieldInfo RigField = AccessTools.Field(typeof(Item), "_rig"); private static readonly FieldInfo JumpsLeftField = AccessTools.Field(typeof(BowheadWhale), "_jumpsLeft"); private static readonly FieldInfo AddedFlyingGravity2Field = AccessTools.Field(typeof(BowheadWhale), "_addedFlyingGravity2"); private static readonly MethodInfo FlyMethod = AccessTools.Method(typeof(BowheadWhale), "Fly", (Type[])null, (Type[])null); private static readonly MethodInfo MakeNoiseSoundMethod = AccessTools.Method(typeof(BowheadWhale), "MakeNoiseSound", (Type[])null, (Type[])null); private static float GetGravity(BowheadWhale whale) { return (float)AddedFlyingGravity2Field.GetValue(whale); } public static void BeginFollow(BowheadWhale whale, Boat boat) { //IL_0008: Unknown result type (might be due to invalid IL or missing references) //IL_000d: Unknown result type (might be due to invalid IL or missing references) //IL_001d: 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_0051: 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_0056: 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_0070: 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_007d: Unknown result type (might be due to invalid IL or missing references) //IL_00a7: Unknown result type (might be due to invalid IL or missing references) SecondPhaseWhaleFollowState secondPhaseWhaleFollowState = SecondPhaseWhaleFollowState.Get(whale); Vector3 val = ComputeBowTarget(whale, boat); secondPhaseWhaleFollowState.Active = true; secondPhaseWhaleFollowState.HasSurfaced = false; secondPhaseWhaleFollowState.TargetPosition = val; secondPhaseWhaleFollowState.IsDescending = false; object? value = RigField.GetValue(whale); Rigidbody val2 = (Rigidbody)((value is Rigidbody) ? value : null); Vector3 val3 = (((Object)(object)val2 != (Object)null) ? val2.worldCenterOfMass : ((Component)whale).transform.position); float num = Vector3.Distance(val3, val); float flightTime = Mathf.Max(2.5f, num / 60f); Vector3 linearVelocity = BallisticUtils.SolveVelocityForFlightTime(val3, val, flightTime, GetGravity(whale)); JumpsLeftField.SetValue(whale, 1); FlyMethod.Invoke(whale, null); if ((Object)(object)val2 != (Object)null) { val2.linearVelocity = linearVelocity; } } private static Vector3 ComputeBowTarget(BowheadWhale whale, Boat boat) { //IL_0017: Unknown result type (might be due to invalid IL or missing references) //IL_0029: 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_0047: 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_0064: Unknown result type (might be due to invalid IL or missing references) //IL_0069: 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_0054: Unknown result type (might be due to invalid IL or missing references) Vector3 val = (((Object)(object)boat != (Object)null && (Object)(object)boat.VisualBoat != (Object)null) ? boat.VisualBoat.forward : Vector3.forward); Vector3 result = (((Object)(object)boat != (Object)null && (Object)(object)boat.VisualBoat != (Object)null) ? boat.VisualBoat.position : ((Component)whale).transform.position) + val * 20f; result.y = WaterManager.WaterHeight; return result; } [HarmonyPatch("InitializeMovement")] [HarmonyPrefix] private static bool BeforeInitializeMovement(BowheadWhale __instance) { return !SecondPhaseWhaleFollowState.Get(__instance).Active; } [HarmonyPatch("SetFlying")] [HarmonyPrefix] private static bool BeforeSetFlying(BowheadWhale __instance) { //IL_0036: Unknown result type (might be due to invalid IL or missing references) //IL_003b: Unknown result type (might be due to invalid IL or missing references) //IL_0054: 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_006c: Unknown result type (might be due to invalid IL or missing references) //IL_00be: Unknown result type (might be due to invalid IL or missing references) SecondPhaseWhaleFollowState secondPhaseWhaleFollowState = SecondPhaseWhaleFollowState.Get(__instance); if (!secondPhaseWhaleFollowState.Active || secondPhaseWhaleFollowState.HasSurfaced) { return true; } object? value = RigField.GetValue(__instance); Rigidbody val = (Rigidbody)((value is Rigidbody) ? value : null); if ((Object)(object)val == (Object)null) { return true; } Vector3 linearVelocity = val.linearVelocity; linearVelocity.y -= GetGravity(__instance) * Time.fixedDeltaTime; val.linearVelocity = linearVelocity; if (!(val.worldCenterOfMass.y <= WaterManager.WaterHeight) || !(linearVelocity.y < -1f)) { secondPhaseWhaleFollowState.IsDescending = false; return false; } if (!secondPhaseWhaleFollowState.IsDescending) { secondPhaseWhaleFollowState.IsDescending = true; secondPhaseWhaleFollowState.DescendStartTime = Time.time; return false; } if (Time.time - secondPhaseWhaleFollowState.DescendStartTime >= 0.6f) { secondPhaseWhaleFollowState.HasSurfaced = true; PlaySplashBurst(val.position, 6, 5f); JumpsLeftField.SetValue(__instance, 1); FlyMethod.Invoke(__instance, null); ((MonoBehaviour)__instance).StartCoroutine(RoarAfterSurfacing(__instance, val)); } return false; } private static IEnumerator RoarAfterSurfacing(BowheadWhale whale, Rigidbody rig) { foreach (Player alivePlayer in PlayerManager.AlivePlayers) { alivePlayer.ScreenShake.ConstantShake(true); } MakeNoiseSoundMethod.Invoke(whale, new object[1] { true }); PlaySplashBurst(new Vector3(rig.position.x, WaterManager.WaterHeight, rig.position.z), 14, 9f); yield return (object)new WaitForSeconds(3f); foreach (Player alivePlayer2 in PlayerManager.AlivePlayers) { alivePlayer2.ScreenShake.ConstantShake(false); } SecondPhaseWhaleFollowState.Get(whale).Active = false; } private static void PlaySplashBurst(Vector3 center, int count, float radius) { //IL_0004: Unknown result type (might be due to invalid IL or missing references) //IL_000a: Unknown result type (might be due to invalid IL or missing references) //IL_000f: Unknown result type (might be due to invalid IL or missing references) //IL_001c: Unknown result type (might be due to invalid IL or missing references) //IL_001d: Unknown result type (might be due to invalid IL or missing references) //IL_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_0035: 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) for (int i = 0; i < count; i++) { Vector3 val = Random.insideUnitSphere * radius; val.y = 0f; Vector3 val2 = center + val; val2.y = WaterManager.WaterHeight; VFXManager.Play("WaterSplash", val2, Vector3.zero); } } } internal sealed class SecondPhaseWhaleFollowState { public bool Active; public bool HasSurfaced; public Vector3 TargetPosition; public bool IsDescending; public float DescendStartTime = -1f; private static readonly ConditionalWeakTable States = new ConditionalWeakTable(); public static SecondPhaseWhaleFollowState Get(BowheadWhale whale) { return States.GetOrCreateValue(whale); } } [HarmonyPatch(typeof(BowheadWhale))] internal static class ThirdPhasePatch { private const float ThirdPhaseHpThreshold = 0.1f; private const float FleeArrivalDistance = 4f; private static readonly FieldInfo RigField = AccessTools.Field(typeof(Item), "_rig"); private static readonly FieldInfo IsFlyingField = AccessTools.Field(typeof(BowheadWhale), "_isFlying"); private static readonly FieldInfo IsShootingLavaField = AccessTools.Field(typeof(BowheadWhale), "_isShootingLava"); private static readonly FieldInfo ShootLavaChanceField = AccessTools.Field(typeof(BowheadWhale), "_shootLavaChance"); private static readonly FieldInfo LavaCountField = AccessTools.Field(typeof(BowheadWhale), "_lavaCount"); private static readonly FieldInfo JumpsLeftField = AccessTools.Field(typeof(BowheadWhale), "_jumpsLeft"); private static readonly FieldInfo FlyForceTowardsPlayerField = AccessTools.Field(typeof(BowheadWhale), "_flyForceTowardsPlayer"); private static readonly MethodInfo ShootLavaMethod = AccessTools.Method(typeof(BowheadWhale), "ShootLava", (Type[])null, (Type[])null); private static readonly MethodInfo FlyMethod = AccessTools.Method(typeof(BowheadWhale), "Fly", (Type[])null, (Type[])null); private static readonly MethodInfo OnLandedMethod = AccessTools.Method(typeof(BowheadWhale), "OnLanded", (Type[])null, (Type[])null); private const float MaxFallSeconds = 4f; [HarmonyPatch("Awake")] [HarmonyPostfix] private static void AfterAwake(BowheadWhale __instance) { //IL_0016: Unknown result type (might be due to invalid IL or missing references) //IL_001b: Unknown result type (might be due to invalid IL or missing references) ThirdPhaseState thirdPhaseState = ThirdPhaseState.Get(__instance); if (!thirdPhaseState.SpawnPositionCaptured) { thirdPhaseState.SpawnPosition = ((Component)__instance).transform.position; thirdPhaseState.SpawnPositionCaptured = true; } } [HarmonyPatch("OnHealthChange")] [HarmonyPostfix] private static void AfterHealthChange(BowheadWhale __instance, int next, bool asServer) { //IL_0004: Unknown result type (might be due to invalid IL or missing references) //IL_000a: Invalid comparison between Unknown and I4 if (!asServer || (int)((Creature)__instance).BossType != 2) { return; } ThirdPhaseState thirdPhaseState = ThirdPhaseState.Get(__instance); if (!thirdPhaseState.PhaseActive && !thirdPhaseState.Resolved) { float num = (float)next / (float)BossManager.BossMaxHp; if (num > 0f && num <= 0.1f) { thirdPhaseState.PhaseActive = true; JumpsLeftField.SetValue(__instance, 1); } } } [HarmonyPatch("InitializeMovement")] [HarmonyPrefix] private static bool BeforeInitializeMovement(BowheadWhale __instance) { ThirdPhaseState thirdPhaseState = ThirdPhaseState.Get(__instance); if (!thirdPhaseState.PhaseActive || thirdPhaseState.Resolved) { return true; } if (!(bool)IsFlyingField.GetValue(__instance)) { JumpsLeftField.SetValue(__instance, 1); FlyMethod.Invoke(__instance, null); } if (!(bool)IsShootingLavaField.GetValue(__instance)) { float num = (float)ShootLavaChanceField.GetValue(__instance); if (Random.Range(0f, 1f) <= num) { int num2 = (int)LavaCountField.GetValue(__instance); ((MonoBehaviour)__instance).StartCoroutine((IEnumerator)ShootLavaMethod.Invoke(__instance, new object[1] { num2 })); } } return false; } [HarmonyPatch("UpdateMovement")] [HarmonyPostfix] private static void AfterUpdateMovement(BowheadWhale __instance) { //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_004f: 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_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) //IL_007a: Unknown result type (might be due to invalid IL or missing references) //IL_00c3: Unknown result type (might be due to invalid IL or missing references) //IL_00c5: Unknown result type (might be due to invalid IL or missing references) //IL_00cb: Unknown result type (might be due to invalid IL or missing references) //IL_00d0: Unknown result type (might be due to invalid IL or missing references) //IL_00d2: Unknown result type (might be due to invalid IL or missing references) //IL_00d9: Unknown result type (might be due to invalid IL or missing references) //IL_00e0: Unknown result type (might be due to invalid IL or missing references) //IL_00e5: Unknown result type (might be due to invalid IL or missing references) //IL_0114: Unknown result type (might be due to invalid IL or missing references) //IL_0119: Unknown result type (might be due to invalid IL or missing references) //IL_011c: Unknown result type (might be due to invalid IL or missing references) //IL_0123: Unknown result type (might be due to invalid IL or missing references) //IL_012a: Unknown result type (might be due to invalid IL or missing references) //IL_0131: Unknown result type (might be due to invalid IL or missing references) ThirdPhaseState thirdPhaseState = ThirdPhaseState.Get(__instance); if (!thirdPhaseState.PhaseActive || thirdPhaseState.Resolved || !thirdPhaseState.SpawnPositionCaptured || !((NetworkBehaviour)__instance).IsServerInitialized) { return; } object? value = RigField.GetValue(__instance); Rigidbody val = (Rigidbody)((value is Rigidbody) ? value : null); if ((Object)(object)val == (Object)null) { return; } Vector3 val2 = thirdPhaseState.SpawnPosition - val.worldCenterOfMass; val2.y = 0f; float magnitude = ((Vector3)(ref val2)).magnitude; Vector3 val3 = thirdPhaseState.SpawnPosition - val.worldCenterOfMass; if (((Vector3)(ref val3)).magnitude <= 4f) { thirdPhaseState.Resolved = true; ((NetworkBehaviour)__instance).Despawn(((Component)__instance).gameObject, (DespawnType?)null); } else if ((bool)IsFlyingField.GetValue(__instance) && !(magnitude < 0.01f)) { Vector3 val4 = val2 / magnitude; Vector3 linearVelocity = val.linearVelocity; Vector2 val5 = new Vector2(linearVelocity.x, linearVelocity.z); float num = ((Vector2)(ref val5)).magnitude; float num2 = (float)FlyForceTowardsPlayerField.GetValue(__instance) * 0.5f; if (num < num2) { num = num2; } Vector3 val6 = val4 * num; val.linearVelocity = new Vector3(val6.x, linearVelocity.y, val6.z); } } [HarmonyPatch("SetFlying")] [HarmonyPostfix] private static void AfterSetFlying(BowheadWhale __instance) { //IL_004e: Unknown result type (might be due to invalid IL or missing references) ThirdPhaseState thirdPhaseState = ThirdPhaseState.Get(__instance); if (!thirdPhaseState.PhaseActive || thirdPhaseState.Resolved) { return; } if (!(bool)IsFlyingField.GetValue(__instance)) { thirdPhaseState.IsDescending = false; return; } object? value = RigField.GetValue(__instance); Rigidbody val = (Rigidbody)((value is Rigidbody) ? value : null); if (!((Object)(object)val == (Object)null)) { if (!(val.linearVelocity.y < -1f)) { thirdPhaseState.IsDescending = false; } else if (!thirdPhaseState.IsDescending) { thirdPhaseState.IsDescending = true; thirdPhaseState.DescendStartTime = Time.time; } else if (Time.time - thirdPhaseState.DescendStartTime >= 4f) { thirdPhaseState.IsDescending = false; OnLandedMethod.Invoke(__instance, null); } } } [HarmonyPatch("OnLanded")] [HarmonyPostfix] private static void AfterOnLanded(BowheadWhale __instance) { //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_0024: 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_0046: 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_0058: 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_005a: 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_0072: 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) ThirdPhaseState thirdPhaseState = ThirdPhaseState.Get(__instance); if (!thirdPhaseState.PhaseActive || thirdPhaseState.Resolved) { return; } Vector3 position = ((Component)__instance).transform.position; if (!(position.y > WaterManager.WaterHeight + 1f)) { for (int i = 0; i < 6; i++) { Vector3 val = Random.insideUnitSphere * 4f; val.y = 0f; Vector3 val2 = position + val; val2.y = WaterManager.WaterHeight; VFXManager.Play("WaterSplash", val2, Vector3.zero); } } } } internal sealed class ThirdPhaseState { public Vector3 SpawnPosition; public bool SpawnPositionCaptured; public bool PhaseActive; public bool Resolved; public bool IsDescending; public float DescendStartTime = -1f; private static readonly ConditionalWeakTable States = new ConditionalWeakTable(); public static ThirdPhaseState Get(BowheadWhale whale) { return States.GetOrCreateValue(whale); } } }