using System; using System.Collections; using System.Collections.Generic; using System.Diagnostics; using System.IO; using System.Linq; using System.Reflection; using System.Reflection.Emit; using System.Runtime.CompilerServices; using System.Runtime.Versioning; using System.Text; using BepInEx; using BepInEx.Configuration; using BepInEx.Logging; using HarmonyLib; using Microsoft.CodeAnalysis; using PluginConfig.API; using PluginConfig.API.Decorators; using PluginConfig.API.Fields; using Sandbox.Arm; using ULTRAKILL.Cheats; using ULTRAKILL.Enemy; using UnityEngine; using UnityEngine.AddressableAssets; using UnityEngine.Events; using UnityEngine.SceneManagement; using UnityEngine.UI; [assembly: CompilationRelaxations(8)] [assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)] [assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)] [assembly: TargetFramework(".NETStandard,Version=v2.1", FrameworkDisplayName = ".NET Standard 2.1")] [assembly: AssemblyCompany("GrenadeLauncher")] [assembly: AssemblyConfiguration("Release")] [assembly: AssemblyFileVersion("1.0.2.0")] [assembly: AssemblyInformationalVersion("1.0.2+4cb420845310a5af127943c5c300f3a8f26a3252")] [assembly: AssemblyProduct("GrenadeLauncher")] [assembly: AssemblyTitle("GrenadeLauncher")] [assembly: AssemblyVersion("1.0.2.0")] [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 GrenadeLauncherMod { [BepInPlugin("docvalentyne.ultrakill.grenadelauncher", "Grenade Launcher", "1.0.2")] [BepInDependency(/*Could not decode attribute arguments.*/)] public sealed class Plugin : BaseUnityPlugin { public const string Guid = "docvalentyne.ultrakill.grenadelauncher"; public const string Name = "Grenade Launcher"; public const string Version = "1.0.2"; private readonly Dictionary> slotLoadouts = new Dictionary>(); private readonly Dictionary> variantLoadouts = new Dictionary>(); private readonly Dictionary> variantMigrations = new Dictionary>(); private Harmony harmony; private GameObject runtimeHost; internal static Plugin Instance { get; private set; } internal static ManualLogSource LogSource { get; private set; } internal bool GrenadeModeEnabled { get { return GetSlotEntry(GameProgressSaver.currentSlot).Value; } set { GetSlotEntry(GameProgressSaver.currentSlot).Value = value; ((BaseUnityPlugin)this).Config.Save(); TerminalIntegration.RefreshAll(); } } internal bool AnyGrenadeModeEnabled { get { int slot = Math.Max(0, GameProgressSaver.currentSlot); if (!GetVariantMigrationEntry(slot).Value) { return GetSlotEntry(slot).Value; } if (!GetVariantEntry(slot, 0).Value && !GetVariantEntry(slot, 1).Value) { return GetVariantEntry(slot, 2).Value; } return true; } } internal bool IsGrenadeModeEnabled(int variation) { if (variation < 0 || variation > 2) { return false; } int slot = Math.Max(0, GameProgressSaver.currentSlot); if (!GetVariantMigrationEntry(slot).Value) { return GetSlotEntry(slot).Value; } return GetVariantEntry(slot, variation).Value; } internal bool IsGrenadeModeEnabled(RocketLauncher launcher) { if ((Object)(object)launcher != (Object)null) { return IsGrenadeModeEnabled(launcher.variation); } return false; } internal void SetGrenadeModeEnabled(int variation, bool enabled) { if (variation >= 0 && variation <= 2) { int slot = Math.Max(0, GameProgressSaver.currentSlot); EnsureVariantMigration(); GetVariantEntry(slot, variation).Value = enabled; ((BaseUnityPlugin)this).Config.Save(); } } internal void EnsureVariantMigration() { int slot = Math.Max(0, GameProgressSaver.currentSlot); ConfigEntry variantMigrationEntry = GetVariantMigrationEntry(slot); if (!variantMigrationEntry.Value) { bool value = GetSlotEntry(slot).Value; for (int i = 0; i < 3; i++) { GetVariantEntry(slot, i).Value = value; } variantMigrationEntry.Value = true; ((BaseUnityPlugin)this).Config.Save(); ((BaseUnityPlugin)this).Logger.LogInfo((object)("Migrated the old all-rocket loadout to per-variant Grenade Launcher choices for save slot " + slot + ".")); } } private void Awake() { //IL_001c: Unknown result type (might be due to invalid IL or missing references) //IL_0026: Expected O, but got Unknown //IL_0046: Unknown result type (might be due to invalid IL or missing references) //IL_0050: Expected O, but got Unknown Instance = this; LogSource = ((BaseUnityPlugin)this).Logger; PluginSettings.Initialize(); harmony = new Harmony("docvalentyne.ultrakill.grenadelauncher"); harmony.PatchAll(typeof(Plugin).Assembly); runtimeHost = new GameObject("Grenade Launcher Runtime"); Object.DontDestroyOnLoad((Object)(object)runtimeHost); ((Object)runtimeHost).hideFlags = (HideFlags)61; runtimeHost.AddComponent(); runtimeHost.AddComponent(); ((BaseUnityPlugin)this).Logger.LogInfo((object)"Grenade Launcher v1.0.2 loaded."); } private void OnDestroy() { Harmony obj = harmony; if (obj != null) { obj.UnpatchSelf(); } GrenadeSpawnContext.Reset(); GrenadeLauncherHookContext.Reset(); AlternateFireRuntime.CleanupAll(); TerminalIntegration.Cleanup(); if ((Object)(object)runtimeHost != (Object)null) { Object.Destroy((Object)(object)runtimeHost); } if ((Object)(object)Instance == (Object)(object)this) { Instance = null; } if (LogSource == ((BaseUnityPlugin)this).Logger) { LogSource = null; } } private ConfigEntry GetSlotEntry(int slot) { if (slot < 0) { slot = 0; } if (!slotLoadouts.TryGetValue(slot, out var value)) { value = ((BaseUnityPlugin)this).Config.Bind("Loadout", "SaveSlot" + slot + "UsesGrenadeLauncher", false, "Equip Grenade Launcher primary fire for all three Rocket Launcher variants in this save slot."); slotLoadouts.Add(slot, value); } return value; } private ConfigEntry GetVariantEntry(int slot, int variation) { string key = slot + ":" + variation; if (!variantLoadouts.TryGetValue(key, out var value)) { value = ((BaseUnityPlugin)this).Config.Bind("Loadout", "SaveSlot" + slot + "RocketVariant" + variation + "UsesGrenadeLauncher", false, "Use the alternate Grenade Launcher form for this Rocket Launcher variant."); variantLoadouts.Add(key, value); } return value; } private ConfigEntry GetVariantMigrationEntry(int slot) { if (!variantMigrations.TryGetValue(slot, out var value)) { value = ((BaseUnityPlugin)this).Config.Bind("Loadout", "SaveSlot" + slot + "PerVariantLoadoutMigrated", false, "Whether the old all-rocket setting has been copied to the native per-variant terminal controls."); variantMigrations.Add(slot, value); } return value; } } [HarmonyPatch(typeof(LeaderboardController), "SubmitCyberGrindScore")] internal static class CyberGrindLeaderboardPatch { private static bool Prefix() { ManualLogSource logSource = Plugin.LogSource; if (logSource != null) { logSource.LogInfo((object)"Blocked Cyber Grind leaderboard submission while Grenade Launcher is loaded; local high score remains enabled."); } return false; } } internal enum GrenadeProjectileProfile { Primary, GreenContact, BlueDelivery } internal static class GrenadeSpawnContext { private static int depth; internal static bool Active => depth > 0; internal static GrenadeProjectileProfile Profile { get; private set; } internal static void Enter(GrenadeProjectileProfile profile = GrenadeProjectileProfile.Primary) { if (depth == 0) { Profile = profile; } depth++; } internal static void Exit() { depth = Math.Max(0, depth - 1); } internal static void Reset() { depth = 0; Profile = GrenadeProjectileProfile.Primary; } } internal static class SharedRocketFireCooldown { private static float readyAt; internal static bool Ready { get { if (!CooldownRules.NoWeaponCooldown) { return Time.time >= readyAt; } return true; } } internal static void Mark(float duration) { if (!CooldownRules.NoWeaponCooldown) { readyAt = Mathf.Max(readyAt, Time.time + Mathf.Max(0.05f, duration)); } } internal static void Reset() { readyAt = 0f; } } internal static class CooldownRules { internal static bool NoWeaponCooldown => NoWeaponCooldown.NoCooldown; } [HarmonyPatch(typeof(RocketLauncher), "Shoot")] internal static class RocketLauncherShootPatch { private struct State { internal bool Active; internal bool EnteredContext; internal bool Executed; internal bool SharedEnforced; internal bool NotifyGreenPrimary; internal bool NotifyBluePrimary; internal float RateOfFire; internal float SharedInterval; } private static readonly FieldRef WeaponId = AccessTools.FieldRefAccess("wid"); private static bool Prefix(RocketLauncher __instance, out State __state) { bool flag = (Object)(object)Plugin.Instance != (Object)null && Plugin.Instance.IsGrenadeModeEnabled(__instance); bool flag2 = (Object)(object)Plugin.Instance != (Object)null && Plugin.Instance.AnyGrenadeModeEnabled; WeaponIdentifier val = WeaponId.Invoke(__instance); bool flag3 = (Object)(object)val != (Object)null && val.duplicate; __state = new State { Active = flag, SharedEnforced = (flag2 && !flag3), RateOfFire = __instance.rateOfFire, SharedInterval = (flag ? PluginSettings.FireInterval : __instance.rateOfFire) }; if (__state.SharedEnforced && !SharedRocketFireCooldown.Ready) { return false; } __state.Executed = true; if (!__state.Active) { return true; } __instance.rateOfFire = PluginSettings.FireInterval; if (!GrenadeSpawnContext.Active) { __state.NotifyGreenPrimary = __instance.variation == 1; __state.NotifyBluePrimary = __instance.variation == 0; GrenadeSpawnContext.Enter(); __state.EnteredContext = true; } return true; } private static Exception Finalizer(RocketLauncher __instance, State __state, Exception __exception) { Restore(__instance, __state); if (__exception == null && __state.Executed && __state.SharedEnforced) { SharedRocketFireCooldown.Mark(__state.SharedInterval); } if (__exception == null && __state.NotifyGreenPrimary) { AlternateFireController.OnGreenPrimaryFired(); } if (__exception == null && __state.NotifyBluePrimary) { AlternateFireController.OnBluePrimaryFired(); } return __exception; } private static void Restore(RocketLauncher launcher, State state) { if (state.Active) { launcher.rateOfFire = state.RateOfFire; if (state.EnteredContext) { GrenadeSpawnContext.Exit(); } } } } [HarmonyPatch(typeof(CameraController), "CameraShake", new Type[] { typeof(float) })] internal static class GrenadeLauncherCameraShakePatch { private static bool Prefix() { return !GrenadeSpawnContext.Active; } } [HarmonyPatch(typeof(ObjectTracker), "GetGrenade")] internal static class GrenadeLauncherWhiplashPatch { private static void Postfix(ref Grenade __result) { if (!((Object)(object)__result == (Object)null)) { GrenadeLauncherProjectile component = ((Component)__result).GetComponent(); if ((Object)(object)component != (Object)null && !component.CanBeWhiplashed) { __result = null; } if ((Object)(object)__result != (Object)null && (Object)(object)((Component)__result).GetComponent() != (Object)null) { __result = null; } } } } internal static class GrenadeLauncherHookContext { private static int depth; internal static bool Active => depth > 0; internal static void Enter() { depth++; } internal static void Exit() { depth = Math.Max(0, depth - 1); } internal static void Reset() { depth = 0; } } [HarmonyPatch(typeof(HookArm), "FixedUpdate")] internal static class GrenadeLauncherHookArmPatch { private static void Prefix() { GrenadeLauncherHookContext.Enter(); } private static Exception Finalizer(Exception __exception) { GrenadeLauncherHookContext.Exit(); return __exception; } } [HarmonyPatch(typeof(Grenade), "Explode", new Type[] { typeof(bool), typeof(bool), typeof(bool), typeof(float), typeof(bool), typeof(GameObject), typeof(bool) })] internal static class GrenadeLauncherHookExplosionPatch { private static bool Prefix(Grenade __instance) { if ((Object)(object)((Component)__instance).GetComponent() != (Object)null) { return false; } GrenadeLauncherProjectile component = ((Component)__instance).GetComponent(); if ((Object)(object)component == (Object)null) { return true; } if (component.IsStuck) { if (StuckDetonationContext.CanCurrentBeamDetonate) { component.DetonateStuck(); } return false; } return !GrenadeLauncherHookContext.Active; } } internal static class PluginSettings { internal const string ArcOriginal = "Original TF2-scaled arc"; internal const string ArcCurrent = "Current snappier arc"; internal const string ArcCustom = "Custom gravity"; private static StringListField arcPreset; private static FloatSliderField damage; private static FloatSliderField speed; private static FloatSliderField upwardVelocity; private static FloatSliderField customGravity; private static FloatSliderField fireInterval; private static FloatSliderField explosionSize; private static FloatSliderField knockback; private static FloatSliderField lifetime; private static FloatSliderField surfaceFuse; private static FloatSliderField hookFuseGrace; private static FloatSliderField surfaceDamage; private static FloatSliderField bounceRetention; private static FloatSliderField parryDamage; private static FloatSliderField parryExplosionSize; private static FloatSliderField parrySpeed; private static FloatSliderField directSelfDamage; private static FloatSliderField surfaceSelfDamage; private static FloatSliderField parrySelfDamage; private static BoolField eyeHeightScaling; private static FloatSliderField fallbackEyeHeight; private static Texture2D configuratorIconTexture; private static Sprite configuratorIconSprite; private static readonly Dictionary enemyDamageMultipliers = new Dictionary(); private static readonly Dictionary releaseEnemyDamageDefaults = new Dictionary { { (EnemyType)0, 120f }, { (EnemyType)33, 110f }, { (EnemyType)2, 85f }, { (EnemyType)4, 100f }, { (EnemyType)31, 200f }, { (EnemyType)38, 175f }, { (EnemyType)14, 125f } }; private static FloatSliderField greenCooldown; private static FloatSliderField greenSpeed; private static FloatSliderField greenUpwardVelocity; private static FloatSliderField greenGravity; private static FloatSliderField greenDirectDamage; private static FloatSliderField greenSurfaceDamage; private static FloatSliderField greenDirectExplosionSize; private static FloatSliderField greenSurfaceExplosionSize; private static FloatSliderField greenDirectSelfDamage; private static FloatSliderField greenSurfaceSelfDamage; private static FloatSliderField greenKnockback; private static FloatSliderField greenLifetime; private static FloatSliderField gelProjectileSpeed; private static FloatSliderField gelCoveragePerDroplet; private static FloatSliderField gelCoverageRequired; private static FloatSliderField gelSpotSize; private static FloatSliderField stuckDamage; private static FloatSliderField greenStuckDamage; private static FloatSliderField stuckExplosionSize; private static FloatSliderField stuckSelfDamage; private static FloatSliderField stuckKnockback; private static FloatSliderField stuckChainRadius; private static FloatSliderField stuckChainPropagationSpeed; private static BoolField enemyCarrierDirectDamage; private static BoolField timedFuseDetonatesStuck; private static FloatSliderField blueDistance; private static FloatSliderField blueCooldown; private static FloatSliderField blueSlingshotForce; private static FloatSliderField bluePointSize; private static FloatSliderField pipeDreamDistance; private static FloatSliderField moonShotDistance; private static FloatSliderField pipeDreamStylePoints; private static FloatSliderField moonShotStylePoints; private static FloatSliderField outSnipedStylePoints; private static FloatSliderField walkingBombStylePoints; private static FloatSliderField pipeDreamDamageMultiplier; private static FloatSliderField pipeDreamExplosionSizeMultiplier; private static FloatSliderField moonShotDamageMultiplier; private static FloatSliderField moonShotExplosionSizeMultiplier; private static BoolField rangeTelemetry; internal static float Damage { get { FloatSliderField obj = damage; if (obj == null) { return 4f; } return obj.value; } } internal static float SpeedMultiplier { get { FloatSliderField obj = speed; if (obj == null) { return 1f; } return obj.value; } } internal static float UpwardVelocityMultiplier { get { FloatSliderField obj = upwardVelocity; if (obj == null) { return 1f; } return obj.value; } } internal static float FireInterval { get { FloatSliderField obj = fireInterval; if (obj == null) { return 0.6f; } return obj.value; } } internal static float ExplosionSizeMultiplier { get { FloatSliderField obj = explosionSize; if (obj == null) { return 0.9f; } return obj.value; } } internal static float KnockbackMultiplier { get { FloatSliderField obj = knockback; if (obj == null) { return 1f; } return obj.value; } } internal static float Lifetime { get { FloatSliderField obj = lifetime; if (obj == null) { return 15f; } return obj.value; } } internal static float SurfaceFuse { get { FloatSliderField obj = surfaceFuse; if (obj == null) { return 1f; } return obj.value; } } internal static float HookFuseGrace { get { FloatSliderField obj = hookFuseGrace; if (obj == null) { return 0.1f; } return obj.value; } } internal static float SurfaceDamage { get { FloatSliderField obj = surfaceDamage; if (obj == null) { return 2.5f; } return obj.value; } } internal static float BounceRetention { get { FloatSliderField obj = bounceRetention; if (obj == null) { return 0.1f; } return obj.value; } } internal static float ParryDamage { get { FloatSliderField obj = parryDamage; if (obj == null) { return 4.5f; } return obj.value; } } internal static float ParryExplosionSize { get { FloatSliderField obj = parryExplosionSize; if (obj == null) { return 1f; } return obj.value; } } internal static float ParrySpeedMultiplier { get { FloatSliderField obj = parrySpeed; if (obj == null) { return 3f; } return obj.value; } } internal static float DirectSelfDamage { get { FloatSliderField obj = directSelfDamage; if (obj == null) { return 35f; } return obj.value; } } internal static float SurfaceSelfDamage { get { FloatSliderField obj = surfaceSelfDamage; if (obj == null) { return 25f; } return obj.value; } } internal static float ParrySelfDamage { get { FloatSliderField obj = parrySelfDamage; if (obj == null) { return 30f; } return obj.value; } } internal static bool EyeHeightScaling { get { BoolField obj = eyeHeightScaling; if (obj == null) { return true; } return obj.value; } } internal static float FallbackEyeHeight { get { FloatSliderField obj = fallbackEyeHeight; if (obj == null) { return 2.9f; } return obj.value; } } internal static float GravityMultiplier { get { StringListField obj = arcPreset; string text = ((obj != null) ? obj.value : null) ?? "Original TF2-scaled arc"; if (text == "Original TF2-scaled arc") { return 1f; } if (text == "Current snappier arc") { return 2f; } FloatSliderField obj2 = customGravity; if (obj2 == null) { return 1f; } return obj2.value; } } internal static float GreenCooldown { get { FloatSliderField obj = greenCooldown; if (obj == null) { return 6f; } return obj.value; } } internal static float GreenSpeedMultiplier { get { FloatSliderField obj = greenSpeed; if (obj == null) { return 1.5f; } return obj.value; } } internal static float GreenUpwardVelocityMultiplier { get { FloatSliderField obj = greenUpwardVelocity; if (obj == null) { return 1f; } return obj.value; } } internal static float GreenGravityMultiplier { get { FloatSliderField obj = greenGravity; if (obj == null) { return 1f; } return obj.value; } } internal static float GreenDirectDamage { get { FloatSliderField obj = greenDirectDamage; if (obj == null) { return 6f; } return obj.value; } } internal static float GreenSurfaceDamage { get { FloatSliderField obj = greenSurfaceDamage; if (obj == null) { return 4f; } return obj.value; } } internal static float GreenDirectExplosionSize { get { FloatSliderField obj = greenDirectExplosionSize; if (obj == null) { return 1.4f; } return obj.value; } } internal static float GreenSurfaceExplosionSize { get { FloatSliderField obj = greenSurfaceExplosionSize; if (obj == null) { return 1f; } return obj.value; } } internal static float GreenDirectSelfDamage { get { FloatSliderField obj = greenDirectSelfDamage; if (obj == null) { return 35f; } return obj.value; } } internal static float GreenSurfaceSelfDamage { get { FloatSliderField obj = greenSurfaceSelfDamage; if (obj == null) { return 35f; } return obj.value; } } internal static float GreenKnockbackMultiplier { get { FloatSliderField obj = greenKnockback; if (obj == null) { return 1f; } return obj.value; } } internal static float GreenLifetime { get { FloatSliderField obj = greenLifetime; if (obj == null) { return 15f; } return obj.value; } } internal static float GelProjectileSpeedMultiplier { get { FloatSliderField obj = gelProjectileSpeed; if (obj == null) { return 1f; } return obj.value; } } internal static float GelCoveragePerDroplet { get { FloatSliderField obj = gelCoveragePerDroplet; return ((obj != null) ? obj.value : 4f) / 100f; } } internal static float GelCoverageRequired { get { FloatSliderField obj = gelCoverageRequired; return ((obj != null) ? obj.value : 75f) / 100f; } } internal static float GelSpotSize { get { FloatSliderField obj = gelSpotSize; if (obj == null) { return 1.25f; } return obj.value; } } internal static float StuckDamage { get { FloatSliderField obj = stuckDamage; if (obj == null) { return 4f; } return obj.value; } } internal static float GreenStuckDamage { get { FloatSliderField obj = greenStuckDamage; if (obj == null) { return 6f; } return obj.value; } } internal static float StuckExplosionSize { get { FloatSliderField obj = stuckExplosionSize; if (obj == null) { return 1.3f; } return obj.value; } } internal static float StuckSelfDamage { get { FloatSliderField obj = stuckSelfDamage; if (obj == null) { return 45f; } return obj.value; } } internal static float StuckKnockbackMultiplier { get { FloatSliderField obj = stuckKnockback; if (obj == null) { return 1f; } return obj.value; } } internal static float StuckChainRadiusMultiplier { get { FloatSliderField obj = stuckChainRadius; if (obj == null) { return 2f; } return obj.value; } } internal static float StuckChainPropagationSpeed { get { FloatSliderField obj = stuckChainPropagationSpeed; if (obj == null) { return 50f; } return obj.value; } } internal static bool EnemyCarrierTakesDirectDamage { get { BoolField obj = enemyCarrierDirectDamage; if (obj == null) { return true; } return obj.value; } } internal static bool TimedFuseDetonatesStuck { get { BoolField obj = timedFuseDetonatesStuck; if (obj == null) { return false; } return obj.value; } } internal static float BlueDistance { get { FloatSliderField obj = blueDistance; if (obj == null) { return 27f; } return obj.value; } } internal static float BlueCooldown { get { FloatSliderField obj = blueCooldown; if (obj == null) { return 7f; } return obj.value; } } internal static float BlueSlingshotForce { get { FloatSliderField obj = blueSlingshotForce; if (obj == null) { return 0f; } return obj.value; } } internal static float BluePointSize { get { FloatSliderField obj = bluePointSize; if (obj == null) { return 1f; } return obj.value; } } internal static float PipeDreamMinimumDistance { get { FloatSliderField obj = pipeDreamDistance; if (obj == null) { return 56f; } return obj.value; } } internal static float MoonShotMinimumDistance { get { FloatSliderField obj = moonShotDistance; if (obj == null) { return 125f; } return obj.value; } } internal static int PipeDreamStylePoints { get { FloatSliderField obj = pipeDreamStylePoints; return Mathf.RoundToInt((obj != null) ? obj.value : 100f); } } internal static int MoonShotStylePoints { get { FloatSliderField obj = moonShotStylePoints; return Mathf.RoundToInt((obj != null) ? obj.value : 500f); } } internal static int OutSnipedStylePoints { get { FloatSliderField obj = outSnipedStylePoints; return Mathf.RoundToInt((obj != null) ? obj.value : 500f); } } internal static int WalkingBombStylePoints { get { FloatSliderField obj = walkingBombStylePoints; return Mathf.RoundToInt((obj != null) ? obj.value : 90f); } } internal static float PipeDreamDamageMultiplier { get { FloatSliderField obj = pipeDreamDamageMultiplier; if (obj == null) { return 1f; } return obj.value; } } internal static float PipeDreamExplosionSizeMultiplier { get { FloatSliderField obj = pipeDreamExplosionSizeMultiplier; if (obj == null) { return 1f; } return obj.value; } } internal static float MoonShotDamageMultiplier { get { FloatSliderField obj = moonShotDamageMultiplier; if (obj == null) { return 1.15f; } return obj.value; } } internal static float MoonShotExplosionSizeMultiplier { get { FloatSliderField obj = moonShotExplosionSizeMultiplier; if (obj == null) { return 1.15f; } return obj.value; } } internal static bool RangeTelemetryEnabled { get { BoolField obj = rangeTelemetry; if (obj == null) { return false; } return obj.value; } } internal static float GetEnemyDamageMultiplier(EnemyType enemyType) { //IL_0005: Unknown result type (might be due to invalid IL or missing references) if (!enemyDamageMultipliers.TryGetValue(enemyType, out var value)) { return 1f; } return Mathf.Max(0f, value.value) / 100f; } internal unsafe static void Initialize() { //IL_0023: 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_0066: Expected O, but got Unknown //IL_0315: Unknown result type (might be due to invalid IL or missing references) //IL_031a: Unknown result type (might be due to invalid IL or missing references) //IL_0325: Unknown result type (might be due to invalid IL or missing references) //IL_0336: Expected O, but got Unknown //IL_0331: Unknown result type (might be due to invalid IL or missing references) //IL_033b: Expected O, but got Unknown //IL_035a: Expected O, but got Unknown //IL_0375: Unknown result type (might be due to invalid IL or missing references) //IL_037b: Expected O, but got Unknown //IL_03d1: Unknown result type (might be due to invalid IL or missing references) //IL_03d6: Unknown result type (might be due to invalid IL or missing references) //IL_03dc: Unknown result type (might be due to invalid IL or missing references) //IL_03de: Unknown result type (might be due to invalid IL or missing references) //IL_0414: Unknown result type (might be due to invalid IL or missing references) PluginConfigurator val = PluginConfigurator.Create("Grenade Launcher", "docvalentyne.ultrakill.grenadelauncher"); ApplyConfiguratorIcon(val); new ConfigHeader(val.rootPanel, "Get comfortable with the weapon before changing its settings.", 24); arcPreset = new StringListField(val.rootPanel, "Arc preset", "arcPreset", new string[3] { "Current snappier arc", "Original TF2-scaled arc", "Custom gravity" }, "Original TF2-scaled arc"); damage = Slider(val, "Damage", "damage", 0f, 10f, 4f, 2); MigrateDamageDefault(); speed = Slider(val, "Projectile speed multiplier", "speedMultiplier", 0.1f, 3f, 1f, 2); upwardVelocity = Slider(val, "Upward velocity multiplier", "upwardVelocityMultiplier", 0f, 3f, 1f, 2); customGravity = Slider(val, "Custom gravity multiplier", "customGravityMultiplier", 0.1f, 5f, 1f, 2); fireInterval = Slider(val, "Fire interval (seconds)", "fireInterval", 0.1f, 2f, 0.6f, 2); explosionSize = Slider(val, "Explosion size (rocket = 1)", "explosionSizeMultiplier", 0.25f, 3f, 0.9f, 2); knockback = Slider(val, "Explosion knockback (rocket = 1)", "knockbackMultiplier", 0f, 3f, 1f, 2); lifetime = Slider(val, "Silent projectile lifetime", "projectileLifetime", 1f, 60f, 15f, 1); surfaceFuse = Slider(val, "Surface fuse (seconds)", "surfaceFuse", 0.1f, 10f, 1f, 2); hookFuseGrace = Slider(val, "Fuse time added per Whiplash hook (seconds)", "hookFuseGrace", 0f, 2f, 0.1f, 2); surfaceDamage = Slider(val, "Surface detonation damage", "surfaceDamage", 0f, 10f, 2.5f, 2); bounceRetention = Slider(val, "Surface bounce speed retention", "bounceRetention", 0f, 1f, 0.1f, 2); parryDamage = Slider(val, "Parried grenade damage", "parryDamage", 0f, 20f, 4.5f, 2); parryExplosionSize = Slider(val, "Parried explosion size (rocket = 1)", "parryExplosionSize", 0.25f, 5f, 1f, 2); parrySpeed = Slider(val, "Parried projectile speed multiplier", "parrySpeedMultiplier", 0.1f, 5f, 3f, 2); directSelfDamage = Slider(val, "Direct explosion self damage (HP)", "directSelfDamage", 0f, 100f, 35f, 0); surfaceSelfDamage = Slider(val, "Timed explosion self damage (HP)", "surfaceSelfDamage", 0f, 100f, 25f, 0); parrySelfDamage = Slider(val, "Parried explosion self damage (HP)", "parrySelfDamage", 0f, 100f, 30f, 0); ConfigPanel val2 = new ConfigPanel(val.rootPanel, "Debug / trajectory calibration", "debugTrajectoryCalibration") { headerText = "Only change these when diagnosing trajectory calibration." }; eyeHeightScaling = new BoolField(val2, "Use eye-height calibration", "eyeHeightScaling", true); fallbackEyeHeight = Slider(val2, "Fallback V1 eye height", "fallbackEyeHeight", 0.5f, 10f, 2.9f, 2); InitializeAlternateSettings(val); ConfigPanel val3 = new ConfigPanel(val.rootPanel, "Enemy grenade damage", "enemyDamageMultipliers"); val3.headerText = "Damage percentage is applied after ULTRAKILL's normal explosive weakness or resistance."; enemyDamageMultipliers.Clear(); foreach (EnemyType item in from EnemyType val4 in Enum.GetValues(typeof(EnemyType)) orderby ((object)(*(EnemyType*)(&val4))/*cast due to .constrained prefix*/).ToString() select val4) { enemyDamageMultipliers[item] = Slider(val3, FriendlyEnemyName(item) + " damage (%)", "enemyDamage_" + ((object)(*(EnemyType*)(&item))/*cast due to .constrained prefix*/).ToString(), 0f, 500f, releaseEnemyDamageDefaults.TryGetValue(item, out var value) ? value : 100f, 0); } } private static void ApplyConfiguratorIcon(PluginConfigurator configurator) { //IL_008e: Unknown result type (might be due to invalid IL or missing references) //IL_0098: Expected O, but got Unknown //IL_0101: Unknown result type (might be due to invalid IL or missing references) //IL_0110: Unknown result type (might be due to invalid IL or missing references) using Stream stream = typeof(Plugin).Assembly.GetManifestResourceStream("GrenadeLauncherMod.icon.png"); if (stream == null) { ManualLogSource logSource = Plugin.LogSource; if (logSource != null) { logSource.LogWarning((object)"Embedded Plugin Configurator icon was not found."); } return; } byte[] array = new byte[stream.Length]; int i; int num; for (i = 0; i < array.Length; i += num) { num = stream.Read(array, i, array.Length - i); if (num <= 0) { break; } } if (i != array.Length) { ManualLogSource logSource2 = Plugin.LogSource; if (logSource2 != null) { logSource2.LogWarning((object)"Embedded Plugin Configurator icon could not be read completely."); } return; } configuratorIconTexture = new Texture2D(2, 2, (TextureFormat)4, false); ((Object)configuratorIconTexture).name = "Grenade Launcher Icon"; if (!ImageConversion.LoadImage(configuratorIconTexture, array, false)) { Object.Destroy((Object)(object)configuratorIconTexture); configuratorIconTexture = null; ManualLogSource logSource3 = Plugin.LogSource; if (logSource3 != null) { logSource3.LogWarning((object)"Embedded Plugin Configurator icon was not a valid image."); } } else { configuratorIconSprite = Sprite.Create(configuratorIconTexture, new Rect(0f, 0f, (float)((Texture)configuratorIconTexture).width, (float)((Texture)configuratorIconTexture).height), new Vector2(0.5f, 0.5f)); ((Object)configuratorIconSprite).name = "Grenade Launcher Icon"; configurator.icon = configuratorIconSprite; } } private static FloatSliderField Slider(PluginConfigurator configurator, string displayName, string guid, float minimum, float maximum, float defaultValue, int decimals) { //IL_0014: Unknown result type (might be due to invalid IL or missing references) //IL_001a: Expected O, but got Unknown return new FloatSliderField(configurator.rootPanel, displayName, guid, new Tuple(minimum, maximum), defaultValue, decimals); } private static FloatSliderField Slider(ConfigPanel panel, string displayName, string guid, float minimum, float maximum, float defaultValue, int decimals) { //IL_000f: Unknown result type (might be due to invalid IL or missing references) //IL_0015: Expected O, but got Unknown return new FloatSliderField(panel, displayName, guid, new Tuple(minimum, maximum), defaultValue, decimals); } private unsafe static string FriendlyEnemyName(EnemyType enemyType) { string text = ((object)(*(EnemyType*)(&enemyType))/*cast due to .constrained prefix*/).ToString(); StringBuilder stringBuilder = new StringBuilder(text.Length + 8); for (int i = 0; i < text.Length; i++) { char c = text[i]; if (i > 0 && char.IsUpper(c) && !char.IsUpper(text[i - 1])) { stringBuilder.Append(' '); } stringBuilder.Append(c); } return stringBuilder.ToString(); } private static void MigrateDamageDefault() { ConfigEntry val = ((BaseUnityPlugin)Plugin.Instance).Config.Bind("Migration", "DefaultsVersion", 0, "Internal version used to apply changed defaults once without overwriting later customization."); if (val.Value < 1) { if (Mathf.Approximately(damage.value, 3f)) { damage.value = 4f; } val.Value = 1; ((BaseUnityPlugin)Plugin.Instance).Config.Save(); } } private static void InitializeAlternateSettings(PluginConfigurator configurator) { //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_0035: Expected O, but got Unknown //IL_003a: Unknown result type (might be due to invalid IL or missing references) //IL_005a: Expected O, but got Unknown //IL_005f: Unknown result type (might be due to invalid IL or missing references) //IL_007f: Expected O, but got Unknown //IL_0084: Unknown result type (might be due to invalid IL or missing references) //IL_00a4: Expected O, but got Unknown //IL_00a9: Unknown result type (might be due to invalid IL or missing references) //IL_00c9: Expected O, but got Unknown //IL_00ce: Unknown result type (might be due to invalid IL or missing references) //IL_00ee: Expected O, but got Unknown //IL_00f3: Unknown result type (might be due to invalid IL or missing references) //IL_0113: Expected O, but got Unknown //IL_0118: Unknown result type (might be due to invalid IL or missing references) //IL_0138: Expected O, but got Unknown //IL_013d: Unknown result type (might be due to invalid IL or missing references) //IL_015d: Expected O, but got Unknown //IL_0162: Unknown result type (might be due to invalid IL or missing references) //IL_0182: Expected O, but got Unknown //IL_0187: Unknown result type (might be due to invalid IL or missing references) //IL_01a7: Expected O, but got Unknown //IL_01cb: Expected O, but got Unknown //IL_01e0: Unknown result type (might be due to invalid IL or missing references) //IL_01e5: Unknown result type (might be due to invalid IL or missing references) //IL_0205: Expected O, but got Unknown //IL_020a: Unknown result type (might be due to invalid IL or missing references) //IL_022a: Expected O, but got Unknown //IL_022f: Unknown result type (might be due to invalid IL or missing references) //IL_024f: Expected O, but got Unknown //IL_0254: Unknown result type (might be due to invalid IL or missing references) //IL_0274: Expected O, but got Unknown //IL_0279: Unknown result type (might be due to invalid IL or missing references) //IL_0299: Expected O, but got Unknown //IL_029e: Unknown result type (might be due to invalid IL or missing references) //IL_02be: Expected O, but got Unknown //IL_02c3: Unknown result type (might be due to invalid IL or missing references) //IL_02e3: Expected O, but got Unknown //IL_02e8: Unknown result type (might be due to invalid IL or missing references) //IL_0308: Expected O, but got Unknown //IL_030d: Unknown result type (might be due to invalid IL or missing references) //IL_032d: Expected O, but got Unknown //IL_0332: Unknown result type (might be due to invalid IL or missing references) //IL_0352: Expected O, but got Unknown //IL_0357: Unknown result type (might be due to invalid IL or missing references) //IL_0377: Expected O, but got Unknown //IL_037c: Unknown result type (might be due to invalid IL or missing references) //IL_038d: Expected O, but got Unknown //IL_0388: Unknown result type (might be due to invalid IL or missing references) //IL_0392: Expected O, but got Unknown //IL_03a2: Expected O, but got Unknown //IL_039d: Unknown result type (might be due to invalid IL or missing references) //IL_03a7: Expected O, but got Unknown //IL_03b7: Unknown result type (might be due to invalid IL or missing references) //IL_03bc: Unknown result type (might be due to invalid IL or missing references) //IL_03dc: Expected O, but got Unknown //IL_03e1: Unknown result type (might be due to invalid IL or missing references) //IL_0401: Expected O, but got Unknown //IL_0406: Unknown result type (might be due to invalid IL or missing references) //IL_0426: Expected O, but got Unknown //IL_044a: Expected O, but got Unknown //IL_045f: Unknown result type (might be due to invalid IL or missing references) //IL_0464: Unknown result type (might be due to invalid IL or missing references) //IL_0484: Expected O, but got Unknown //IL_0489: Unknown result type (might be due to invalid IL or missing references) //IL_04a9: Expected O, but got Unknown //IL_04ae: Unknown result type (might be due to invalid IL or missing references) //IL_04ce: Expected O, but got Unknown //IL_04d3: Unknown result type (might be due to invalid IL or missing references) //IL_04f3: Expected O, but got Unknown //IL_04f8: Unknown result type (might be due to invalid IL or missing references) //IL_0518: Expected O, but got Unknown //IL_051d: Unknown result type (might be due to invalid IL or missing references) //IL_053d: Expected O, but got Unknown //IL_0542: Unknown result type (might be due to invalid IL or missing references) //IL_0562: Expected O, but got Unknown //IL_0567: Unknown result type (might be due to invalid IL or missing references) //IL_0587: Expected O, but got Unknown //IL_058c: Unknown result type (might be due to invalid IL or missing references) //IL_05ac: Expected O, but got Unknown //IL_05d0: Expected O, but got Unknown //IL_05e5: Unknown result type (might be due to invalid IL or missing references) //IL_05ea: Unknown result type (might be due to invalid IL or missing references) //IL_0605: Expected O, but got Unknown //IL_0600: Unknown result type (might be due to invalid IL or missing references) //IL_060a: Expected O, but got Unknown ConfigPanel val = new ConfigPanel(configurator.rootPanel, "Green contact grenade", "greenContactGrenade"); greenCooldown = Slider(val, "Cooldown (seconds)", "greenCooldown", 0.05f, 10f, 6f, 2); greenSpeed = Slider(val, "Projectile speed multiplier", "greenSpeedMultiplier", 0.1f, 5f, 1.5f, 2); greenUpwardVelocity = Slider(val, "Upward velocity multiplier", "greenUpwardVelocityMultiplier", 0f, 5f, 1f, 2); greenGravity = Slider(val, "Gravity multiplier", "greenGravityMultiplier", 0.1f, 5f, 1f, 2); greenDirectDamage = Slider(val, "Direct hit damage", "greenDirectDamage", 0f, 20f, 6f, 2); greenSurfaceDamage = Slider(val, "Surface contact damage", "greenSurfaceDamage", 0f, 20f, 4f, 2); greenDirectExplosionSize = Slider(val, "Direct explosion size (rocket = 1)", "greenDirectExplosionSize", 0.1f, 5f, 1.4f, 2); greenSurfaceExplosionSize = Slider(val, "Surface explosion size (rocket = 1)", "greenSurfaceExplosionSize", 0.1f, 5f, 1f, 2); greenDirectSelfDamage = Slider(val, "Direct self damage (HP)", "greenDirectSelfDamage", 0f, 100f, 35f, 0); greenSurfaceSelfDamage = Slider(val, "Surface self damage (HP)", "greenSurfaceSelfDamage", 0f, 100f, 35f, 0); greenKnockback = Slider(val, "Explosion knockback (rocket = 1)", "greenKnockbackMultiplier", 0f, 5f, 1f, 2); greenLifetime = Slider(val, "Silent projectile lifetime", "greenLifetime", 1f, 60f, 15f, 1); ConfigPanel val2 = new ConfigPanel(configurator.rootPanel, "Red blue-gel system", "redGelSystem"); gelProjectileSpeed = Slider(val2, "Gel projectile speed multiplier", "gelProjectileSpeedMultiplier", 0.1f, 5f, 1f, 2); gelCoveragePerDroplet = Slider(val2, "Enemy coverage per droplet (%)", "gelCoveragePerDroplet", 0.1f, 100f, 4f, 1); gelCoverageRequired = Slider(val2, "Enemy coverage required (%)", "gelCoverageRequired", 0f, 100f, 75f, 1); gelSpotSize = Slider(val2, "Terrain gel size (normal = 1)", "gelSpotSize", 0.1f, 5f, 1.25f, 2); stuckDamage = Slider(val2, "Primary stuck grenade damage", "stuckDamage", 0f, 20f, 4f, 2); greenStuckDamage = Slider(val2, "Green stuck grenade damage", "greenStuckDamage", 0f, 20f, 6f, 2); stuckExplosionSize = Slider(val2, "Stuck explosion size (rocket = 1)", "stuckExplosionSize", 0.1f, 5f, 1.3f, 2); stuckSelfDamage = Slider(val2, "Stuck explosion self damage (HP)", "stuckSelfDamage", 0f, 100f, 45f, 0); stuckKnockback = Slider(val2, "Stuck explosion knockback (rocket = 1)", "stuckKnockbackMultiplier", 0f, 5f, 1f, 2); stuckChainRadius = Slider(val2, "Stuck grenade chain radius multiplier", "stuckChainRadiusMultiplier", 0f, 10f, 2f, 2); stuckChainPropagationSpeed = Slider(val2, "Chain propagation speed (units/second)", "stuckChainPropagationSpeed", 1f, 200f, 50f, 1); enemyCarrierDirectDamage = new BoolField(val2, "Enemy carrier takes direct-hit damage", "enemyCarrierDirectDamage", true); timedFuseDetonatesStuck = new BoolField(val2, "Timed-fuse explosions detonate stuck grenades", "timedFuseDetonatesStuck", false); ConfigPanel val3 = new ConfigPanel(configurator.rootPanel, "Blue slingshot point", "blueSlingshotPoint"); blueDistance = Slider(val3, "Placement distance", "bluePlacementDistance", 5.5f, 200f, 27f, 1); blueCooldown = Slider(val3, "Cooldown (seconds)", "blueCooldown", 0.05f, 10f, 7f, 2); blueSlingshotForce = Slider(val3, "Extra slingshot force", "blueSlingshotForce", -50f, 200f, 0f, 1); bluePointSize = Slider(val3, "Hook point size multiplier", "bluePointSize", 0.25f, 4f, 1f, 2); ConfigPanel val4 = new ConfigPanel(configurator.rootPanel, "Style bonuses", "styleBonuses"); pipeDreamDistance = Slider(val4, "PIPE DREAM minimum distance", "pipeDreamMinimumDistance", 1f, 250f, 56f, 1); moonShotDistance = Slider(val4, "MOON SHOT / OUT-SNIPED minimum distance", "moonShotMinimumDistance", 1f, 400f, 125f, 1); pipeDreamStylePoints = Slider(val4, "PIPE DREAM style points", "pipeDreamStylePoints", 0f, 5000f, 100f, 0); moonShotStylePoints = Slider(val4, "MOON SHOT style points", "moonShotStylePoints", 0f, 5000f, 500f, 0); outSnipedStylePoints = Slider(val4, "OUT-SNIPED style points", "outSnipedStylePoints", 0f, 5000f, 500f, 0); walkingBombStylePoints = Slider(val4, "WALKING BOMB style points", "walkingBombStylePoints", 0f, 5000f, 90f, 0); pipeDreamDamageMultiplier = Slider(val4, "PIPE DREAM damage multiplier", "pipeDreamDamageMultiplier", 0f, 10f, 1f, 2); pipeDreamExplosionSizeMultiplier = Slider(val4, "PIPE DREAM explosion size multiplier", "pipeDreamExplosionSizeMultiplier", 0.1f, 10f, 1f, 2); moonShotDamageMultiplier = Slider(val4, "MOON SHOT damage multiplier", "moonShotDamageMultiplier", 0f, 10f, 1.15f, 2); moonShotExplosionSizeMultiplier = Slider(val4, "MOON SHOT explosion size multiplier", "moonShotExplosionSizeMultiplier", 0.1f, 10f, 1.15f, 2); rangeTelemetry = new BoolField(new ConfigPanel(configurator.rootPanel, "Debug logging", "debugLogging") { headerText = "These settings only write diagnostic information to the BepInEx log." }, "Log direct-hit ranges", "rangeTelemetry", false); } } [HarmonyPatch(typeof(Grenade), "Awake")] internal static class GrenadeAwakePatch { private static void Postfix(Grenade __instance) { //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) if (!GrenadeSpawnContext.Active) { return; } if (GrenadeSpawnContext.Profile == GrenadeProjectileProfile.BlueDelivery) { if ((Object)(object)((Component)__instance).GetComponent() == (Object)null) { BlueHookDeliveryProjectile blueHookDeliveryProjectile = ((Component)__instance).gameObject.AddComponent(); blueHookDeliveryProjectile.Grenade = __instance; blueHookDeliveryProjectile.Target = BlueHookDeliveryContext.Target; } } else if ((Object)(object)((Component)__instance).GetComponent() == (Object)null) { GrenadeLauncherProjectile grenadeLauncherProjectile = ((Component)__instance).gameObject.AddComponent(); grenadeLauncherProjectile.Grenade = __instance; grenadeLauncherProjectile.Profile = GrenadeSpawnContext.Profile; } } } [HarmonyPatch(typeof(Grenade), "FixedUpdate")] internal static class GrenadeFixedUpdatePatch { private static bool Prefix(Grenade __instance) { if ((Object)(object)((Component)__instance).GetComponent() == (Object)null) { return (Object)(object)((Component)__instance).GetComponent() == (Object)null; } return false; } } [HarmonyPatch(typeof(CustomGravity), "FixedUpdate")] internal static class GrenadeCustomGravityPatch { private static bool Prefix(CustomGravity __instance) { if ((Object)(object)((Component)__instance).GetComponent() == (Object)null) { return (Object)(object)((Component)__instance).GetComponent() == (Object)null; } return false; } } [HarmonyPatch(typeof(Grenade), "Start")] internal static class GrenadeStartPatch { private static void Postfix(Grenade __instance) { ((Component)__instance).GetComponent()?.Launch(); ((Component)__instance).GetComponent()?.Launch(); } } [HarmonyPatch(typeof(Grenade), "OnCollisionEnter")] internal static class GrenadeOnCollisionEnterPatch { private static bool Prefix(Grenade __instance, Collision collision) { //IL_0039: 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_0033: 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_0051: 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_0056: 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_0066: 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_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_0087: 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) if ((Object)(object)((Component)__instance).GetComponent() != (Object)null) { return false; } GrenadeLauncherProjectile component = ((Component)__instance).GetComponent(); if ((Object)(object)component == (Object)null) { return true; } ContactPoint val = (ContactPoint)((collision.contactCount > 0) ? collision.GetContact(0) : default(ContactPoint)); Vector3 collisionNormal = ((collision.contactCount > 0) ? ((ContactPoint)(ref val)).normal : Vector3.zero); Vector3 collisionPoint = ((collision.contactCount > 0) ? ((ContactPoint)(ref val)).point : ((Component)__instance).transform.position); component.HandleCollision(collision.collider, -collision.relativeVelocity, collisionNormal, collisionPoint); return false; } } [HarmonyPatch(typeof(Grenade), "Collision", new Type[] { typeof(Collider), typeof(Vector3) })] internal static class GrenadeCollisionPatch { private static bool Prefix(Grenade __instance, Collider other, Vector3 velocity) { //IL_0024: 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_0030: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)((Component)__instance).GetComponent() != (Object)null) { return false; } GrenadeLauncherProjectile component = ((Component)__instance).GetComponent(); if ((Object)(object)component == (Object)null) { return true; } component.HandleCollision(other, velocity, Vector3.zero, ((Component)__instance).transform.position); return false; } } [HarmonyPatch(typeof(Explosion), "Collide")] internal static class GrenadeLauncherExplosionPatch { private struct State { internal bool ChangedMultiplier; internal float EnemyDamageMultiplier; internal bool ChangedDamage; internal int Damage; internal GrenadeLauncherExplosionMarker Marker; internal EnemyIdentifier Enemy; } private static bool Prefix(Explosion __instance, Collider other, out State __state) { //IL_011d: Unknown result type (might be due to invalid IL or missing references) //IL_00f0: Unknown result type (might be due to invalid IL or missing references) //IL_00f6: Invalid comparison between Unknown and I4 __state = default(State); GrenadeLauncherExplosionMarker componentInParent = ((Component)__instance).GetComponentInParent(); GrenadeLauncherProjectile grenadeLauncherProjectile = (((Object)(object)other != (Object)null) ? ((Component)other).GetComponentInParent() : null); if ((Object)(object)grenadeLauncherProjectile != (Object)null && grenadeLauncherProjectile.IsStuck) { if ((Object)(object)componentInParent != (Object)null && componentInParent.Mode == GrenadeExplosionMode.Surface && !PluginSettings.TimedFuseDetonatesStuck) { return false; } if (!__instance.enemy && (Object)(object)__instance.sourceWeapon != (Object)null) { grenadeLauncherProjectile.DetonateStuck(); } return false; } if ((Object)(object)componentInParent == (Object)null) { return true; } EnemyIdentifier val = GrenadeLauncherProjectile.TryGetLivingEnemy(other); if ((Object)(object)val == (Object)null) { return true; } __state.Marker = componentInParent; __state.Enemy = val; if (PluginSettings.EnemyCarrierTakesDirectDamage && componentInParent.StuckHostEnemyId != 0 && ((Object)val).GetInstanceID() == componentInParent.StuckHostEnemyId) { __state.ChangedDamage = true; __state.Damage = __instance.damage; __instance.damage = Mathf.RoundToInt(Mathf.Max(0f, componentInParent.StuckCarrierDamage) * 10f); } if (componentInParent.Parried && (int)val.enemyType == 4) { componentInParent.DamageBlockedEnemy(val, other); return false; } __state.ChangedMultiplier = true; __state.EnemyDamageMultiplier = __instance.enemyDamageMultiplier; __instance.enemyDamageMultiplier *= PluginSettings.GetEnemyDamageMultiplier(val.enemyType); return true; } private static Exception Finalizer(Explosion __instance, State __state, Exception __exception) { if (__state.ChangedMultiplier) { __instance.enemyDamageMultiplier = __state.EnemyDamageMultiplier; } if (__state.ChangedDamage) { __instance.damage = __state.Damage; } if (__exception == null && (Object)(object)__state.Marker != (Object)null && (Object)(object)__state.Enemy != (Object)null) { __state.Marker.TryAwardLongRangeStyle(__state.Enemy); __state.Marker.TryAwardWalkingBomb(__state.Enemy); __state.Marker.QueueDirectHitTelemetry(__state.Enemy); } return __exception; } } internal enum GrenadeExplosionMode { Direct, Surface, Parried, GreenDirect, GreenSurface, Stuck } internal enum GrenadeLongRangeStyle { None, PipeDream, MoonShot } internal static class GrenadeStyleAwards { private const string PipeDreamId = "grenadelauncher.pipe_dream"; private const string MoonShotId = "grenadelauncher.moon_shot"; private const string OutSnipedId = "grenadelauncher.out_sniped"; private const string WalkingBombId = "grenadelauncher.walking_bomb"; private static StyleHUD registeredHud; private static readonly HashSet walkingBombAwardedChains = new HashSet(); internal static void Award(GrenadeLongRangeStyle style, EnemyIdentifier enemy, GameObject sourceWeapon) { //IL_0016: Unknown result type (might be due to invalid IL or missing references) //IL_001d: Invalid comparison between Unknown and I4 StyleHUD val = EnsureRegistered(enemy); if ((Object)(object)val == (Object)null) { return; } int num; object obj; if (style == GrenadeLongRangeStyle.MoonShot && (int)enemy.enemyType == 20) { num = (enemy.dead ? 1 : 0); if (num != 0) { obj = "grenadelauncher.out_sniped"; goto IL_0042; } } else { num = 0; } obj = ((style == GrenadeLongRangeStyle.MoonShot) ? "grenadelauncher.moon_shot" : "grenadelauncher.pipe_dream"); goto IL_0042; IL_0042: string text = (string)obj; int num2 = ((num != 0) ? PluginSettings.OutSnipedStylePoints : ((style == GrenadeLongRangeStyle.MoonShot) ? PluginSettings.MoonShotStylePoints : PluginSettings.PipeDreamStylePoints)); val.AddPoints(num2, text, sourceWeapon, enemy, -1, "", ""); } internal static void AwardWalkingBomb(int chainId, EnemyIdentifier enemy, GameObject sourceWeapon) { if (chainId > 0 && walkingBombAwardedChains.Add(chainId)) { StyleHUD val = EnsureRegistered(enemy); if ((Object)(object)val != (Object)null) { val.AddPoints(PluginSettings.WalkingBombStylePoints, "grenadelauncher.walking_bomb", sourceWeapon, enemy, -1, "", ""); } } } internal static void ResetWalkingBombChains() { walkingBombAwardedChains.Clear(); } private static StyleHUD EnsureRegistered(EnemyIdentifier enemy) { StyleHUD instance = MonoSingleton.Instance; if ((Object)(object)instance == (Object)null || (Object)(object)enemy == (Object)null) { return null; } if ((Object)(object)registeredHud != (Object)(object)instance) { instance.RegisterStyleItem("grenadelauncher.pipe_dream", "PIPE DREAM"); instance.RegisterStyleItem("grenadelauncher.moon_shot", "MOON SHOT"); instance.RegisterStyleItem("grenadelauncher.out_sniped", "OUT-SNIPED"); instance.RegisterStyleItem("grenadelauncher.walking_bomb", "WALKING BOMB"); registeredHud = instance; } return instance; } } internal sealed class GrenadeLauncherExplosionMarker : MonoBehaviour { private readonly HashSet manuallyDamagedEnemies = new HashSet(); private readonly HashSet styleAwardedEnemies = new HashSet(); private bool walkingBombAwarded; private bool telemetryQueued; private EnemyIdentifier telemetryEnemy; internal bool Parried; internal GrenadeExplosionMode Mode; internal float Damage; internal GameObject SourceWeapon; internal int DirectEnemyId; internal GrenadeLongRangeStyle LongRangeStyle; internal int StuckHostEnemyId; internal float StuckCarrierDamage; internal int StuckChainGroupId; internal GrenadeProjectileProfile DirectProfile; internal float DirectPlanarDistance; internal float DirectStraightDistance; internal float TheoreticalSameHeightRange; internal float LaunchElevationDegrees; internal float ConfiguredStyleThreshold; internal void TryAwardLongRangeStyle(EnemyIdentifier enemy) { if (!((Object)(object)enemy == (Object)null) && LongRangeStyle != GrenadeLongRangeStyle.None && ((Object)enemy).GetInstanceID() == DirectEnemyId && styleAwardedEnemies.Add(DirectEnemyId)) { GrenadeStyleAwards.Award(LongRangeStyle, enemy, SourceWeapon); } } internal void TryAwardWalkingBomb(EnemyIdentifier enemy) { if (!walkingBombAwarded && !((Object)(object)enemy == (Object)null) && enemy.dead && StuckHostEnemyId != 0 && ((Object)enemy).GetInstanceID() != StuckHostEnemyId) { walkingBombAwarded = true; GrenadeStyleAwards.AwardWalkingBomb(StuckChainGroupId, enemy, SourceWeapon); } } internal void QueueDirectHitTelemetry(EnemyIdentifier enemy) { if (PluginSettings.RangeTelemetryEnabled && !telemetryQueued && !((Object)(object)enemy == (Object)null) && DirectEnemyId != 0 && ((Object)enemy).GetInstanceID() == DirectEnemyId) { telemetryQueued = true; telemetryEnemy = enemy; ((MonoBehaviour)this).StartCoroutine(LogDirectHitTelemetryAtEndOfFrame()); } } private IEnumerator LogDirectHitTelemetryAtEndOfFrame() { yield return (object)new WaitForEndOfFrame(); string arg = (((Object)(object)telemetryEnemy != (Object)null) ? ((object)Unsafe.As(ref telemetryEnemy.enemyType)/*cast due to .constrained prefix*/).ToString() : "Destroyed"); bool flag = (Object)(object)telemetryEnemy == (Object)null || telemetryEnemy.dead; float num = ((TheoreticalSameHeightRange > 0.001f) ? (DirectPlanarDistance / TheoreticalSameHeightRange) : 0f); string text = ((DirectProfile == GrenadeProjectileProfile.GreenContact) ? "GREEN" : "PRIMARY"); ManualLogSource logSource = Plugin.LogSource; if (logSource != null) { logSource.LogInfo((object)("[RangeTelemetry] " + text + " direct hit | " + $"planar={DirectPlanarDistance:0.###}u | straight={DirectStraightDistance:0.###}u | " + $"launchElevation={LaunchElevationDegrees:0.###}deg | " + $"calculatedSameHeightMax={TheoreticalSameHeightRange:0.###}u | ratio={num:0.###} | " + $"styleThreshold={ConfiguredStyleThreshold:0.###}u | " + $"enemy={arg} | killed={flag}")); } } internal void DamageBlockedEnemy(EnemyIdentifier enemy, Collider hitCollider) { //IL_0037: 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_0068: 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_0052: 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_008d: 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 (!((Object)(object)enemy == (Object)null) && !enemy.dead && manuallyDamagedEnemies.Add(((Object)enemy).GetInstanceID())) { enemy.hitter = "grenadelauncherparry"; float num = Damage * PluginSettings.GetEnemyDamageMultiplier(enemy.enemyType); Vector3 val; if (!((Object)(object)hitCollider != (Object)null)) { val = ((Component)this).transform.position; } else { Bounds bounds = hitCollider.bounds; val = ((Bounds)(ref bounds)).ClosestPoint(((Component)this).transform.position); } Vector3 val2 = val; GameObject val3 = (((Object)(object)hitCollider != (Object)null) ? ((Component)hitCollider).gameObject : ((Component)enemy).gameObject); enemy.DeliverDamage(val3, Vector3.zero, val2, num, false, 0f, SourceWeapon, false, true); } } } [DefaultExecutionOrder(10000)] internal sealed class GrenadeLauncherProjectile : MonoBehaviour { private const float Tf2DemomanEyeHeightHu = 68f; private const float Tf2ForwardSpeedHu = 1200f; private const float Tf2UpwardSpeedHu = 200f; private const float Tf2GravityHu = 800f; private static int nextChainGroupId; internal Grenade Grenade; internal GrenadeProjectileProfile Profile; private Rigidbody body; private readonly List customGravityComponents = new List(1); private Collider[] ownColliders = Array.Empty(); private ParryReceiver parryReceiver; private bool launched; private bool finished; private bool bounced; private bool parried; private bool stuck; private int stuckHostEnemyId; private int chainGroupId; private bool wasHooked; private GelStainMarker stuckGelStain; private GelCoverage stuckGelCoverage; private float launchForwardSpeed; private float launchElevationDegrees; private float sameHeightMaximumRange; private Vector3 launchPosition; private Vector3 capturedGravity; private Collider lastBounceSurface; private Vector3 lastBounceNormal; private Vector3 lastBouncePoint; private bool hasLastBouncePoint; private float bornAt; private float fuseRemaining = -1f; private float chainDetonationAt = -1f; private Vector3 simulatedVelocity; private Vector3 lastVelocity; private Quaternion lastFixedRotation; private static bool loggedTrajectory; private static bool loggedExplosion; private static bool loggedPortalRotation; private static bool loggedRejectedExternalChange; internal bool CanBeWhiplashed { get { if (Profile == GrenadeProjectileProfile.Primary && bounced && !stuck) { return !finished; } return false; } } internal bool IsStuck { get { if (stuck) { return !finished; } return false; } } internal int ChainGroupId => chainGroupId; internal void Launch() { //IL_0139: 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_0143: Unknown result type (might be due to invalid IL or missing references) //IL_0148: Unknown result type (might be due to invalid IL or missing references) //IL_017d: Unknown result type (might be due to invalid IL or missing references) //IL_0182: Unknown result type (might be due to invalid IL or missing references) //IL_01b5: Unknown result type (might be due to invalid IL or missing references) //IL_01ac: 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_01ba: Unknown result type (might be due to invalid IL or missing references) //IL_01bd: Unknown result type (might be due to invalid IL or missing references) //IL_01c1: 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) //IL_01cd: Unknown result type (might be due to invalid IL or missing references) //IL_01e4: Unknown result type (might be due to invalid IL or missing references) //IL_01ef: Unknown result type (might be due to invalid IL or missing references) //IL_01fa: Unknown result type (might be due to invalid IL or missing references) //IL_0201: Unknown result type (might be due to invalid IL or missing references) //IL_0206: Unknown result type (might be due to invalid IL or missing references) //IL_0223: Unknown result type (might be due to invalid IL or missing references) //IL_0228: 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_023c: Unknown result type (might be due to invalid IL or missing references) //IL_0241: Unknown result type (might be due to invalid IL or missing references) //IL_0243: Unknown result type (might be due to invalid IL or missing references) //IL_0248: Unknown result type (might be due to invalid IL or missing references) //IL_02a6: Unknown result type (might be due to invalid IL or missing references) //IL_02ab: Unknown result type (might be due to invalid IL or missing references) //IL_02b2: Unknown result type (might be due to invalid IL or missing references) //IL_02b7: Unknown result type (might be due to invalid IL or missing references) //IL_02c3: Unknown result type (might be due to invalid IL or missing references) //IL_02c8: Unknown result type (might be due to invalid IL or missing references) //IL_03cc: Unknown result type (might be due to invalid IL or missing references) //IL_034a: Unknown result type (might be due to invalid IL or missing references) //IL_0354: Expected O, but got Unknown //IL_0316: Unknown result type (might be due to invalid IL or missing references) //IL_0320: Expected O, but got Unknown if (launched || (Object)(object)Grenade == (Object)null) { return; } launched = true; bornAt = Time.time; body = (((Object)(object)Grenade.rb != (Object)null) ? Grenade.rb : ((Component)this).GetComponent()); if ((Object)(object)body == (Object)null) { Plugin.LogSource.LogWarning((object)"Grenade projectile had no Rigidbody; removing it."); Object.Destroy((Object)(object)((Component)this).gameObject); return; } ownColliders = ((Component)this).GetComponentsInChildren(true); float eyeHeight = TrajectoryCalibration.GetEyeHeight(); float num = eyeHeight / 68f; float num2 = ((Profile == GrenadeProjectileProfile.GreenContact) ? (PluginSettings.SpeedMultiplier * PluginSettings.GreenSpeedMultiplier) : PluginSettings.SpeedMultiplier); float num3 = ((Profile == GrenadeProjectileProfile.GreenContact) ? (PluginSettings.UpwardVelocityMultiplier * PluginSettings.GreenUpwardVelocityMultiplier) : PluginSettings.UpwardVelocityMultiplier); float num4 = ((Profile == GrenadeProjectileProfile.GreenContact) ? (PluginSettings.GreenGravityMultiplier * PluginSettings.GravityMultiplier) : PluginSettings.GravityMultiplier); launchForwardSpeed = 1200f * num * Mathf.Max(0.05f, num2); float num5 = 200f * num * Mathf.Max(0f, num3); float num6 = 800f * num * Mathf.Max(0.05f, num4); launchPosition = ((Component)this).transform.position; Vector3 val = Physics.gravity; NewMovement instance = MonoSingleton.Instance; if ((Object)(object)instance != (Object)null && (Object)(object)instance.rb != (Object)null) { val = PhysicsExtensions.GetGravityVector(instance.rb); } Vector3 val2 = Physics.gravity; float num7 = Mathf.Max(0.01f, ((Vector3)(ref val2)).magnitude); float num8 = ((Vector3)(ref val)).magnitude / num7; Vector3 val3 = ((((Vector3)(ref val)).sqrMagnitude > 0.0001f) ? ((Vector3)(ref val)).normalized : Vector3.down); capturedGravity = val3 * num6 * num8; LockNativeGravity(); body.velocity = ((Component)this).transform.forward * launchForwardSpeed + ((Component)this).transform.up * num5; float magnitude = ((Vector3)(ref capturedGravity)).magnitude; float num9 = Vector3.Dot(body.velocity, -val3); val2 = Vector3.ProjectOnPlane(body.velocity, val3); float magnitude2 = ((Vector3)(ref val2)).magnitude; launchElevationDegrees = Mathf.Atan2(num9, Mathf.Max(0.0001f, magnitude2)) * 57.29578f; sameHeightMaximumRange = ((magnitude > 0.001f && num9 > 0f) ? (magnitude2 * (2f * num9 / magnitude)) : 0f); simulatedVelocity = body.velocity; lastVelocity = simulatedVelocity; lastFixedRotation = ((Component)this).transform.rotation; if (Profile == GrenadeProjectileProfile.Primary) { parryReceiver = ((Component)this).GetComponent(); if ((Object)(object)parryReceiver == (Object)null) { parryReceiver = ((Component)this).gameObject.AddComponent(); } if (parryReceiver.onParry == null) { parryReceiver.onParry = new UnityEvent(); } parryReceiver.parryHeal = false; parryReceiver.disappearOnParry = false; parryReceiver.onParry.AddListener(new UnityAction(Parry)); ((Behaviour)parryReceiver).enabled = false; } else { parryReceiver = ((Component)this).GetComponent(); if ((Object)(object)parryReceiver != (Object)null) { ((Behaviour)parryReceiver).enabled = false; } } if (!loggedTrajectory) { loggedTrajectory = true; Plugin.LogSource.LogInfo((object)($"TF2 trajectory converted from V1 eye height {eyeHeight:0.###}: " + $"forward {launchForwardSpeed:0.###} u/s, up {num5:0.###} u/s, " + $"captured gravity {capturedGravity} u/s².")); } } private void OnDestroy() { //IL_002d: Unknown result type (might be due to invalid IL or missing references) //IL_0037: Expected O, but got Unknown if ((Object)(object)parryReceiver != (Object)null && parryReceiver.onParry != null) { parryReceiver.onParry.RemoveListener(new UnityAction(Parry)); } GelSystem.UnregisterStuck(this); } private void FixedUpdate() { //IL_0122: Unknown result type (might be due to invalid IL or missing references) //IL_0127: Unknown result type (might be due to invalid IL or missing references) //IL_012e: Unknown result type (might be due to invalid IL or missing references) //IL_0133: 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_00f9: Unknown result type (might be due to invalid IL or missing references) //IL_01be: Unknown result type (might be due to invalid IL or missing references) //IL_01c3: Unknown result type (might be due to invalid IL or missing references) //IL_01c5: Unknown result type (might be due to invalid IL or missing references) //IL_01ca: Unknown result type (might be due to invalid IL or missing references) //IL_01cb: 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) //IL_01cd: Unknown result type (might be due to invalid IL or missing references) //IL_01d2: Unknown result type (might be due to invalid IL or missing references) //IL_01ad: Unknown result type (might be due to invalid IL or missing references) //IL_01b2: Unknown result type (might be due to invalid IL or missing references) //IL_0202: Unknown result type (might be due to invalid IL or missing references) //IL_0203: Unknown result type (might be due to invalid IL or missing references) //IL_0218: Unknown result type (might be due to invalid IL or missing references) //IL_021e: Unknown result type (might be due to invalid IL or missing references) //IL_0223: Unknown result type (might be due to invalid IL or missing references) //IL_0228: Unknown result type (might be due to invalid IL or missing references) //IL_022d: Unknown result type (might be due to invalid IL or missing references) //IL_0230: 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_0237: Unknown result type (might be due to invalid IL or missing references) //IL_0238: Unknown result type (might be due to invalid IL or missing references) //IL_023e: Unknown result type (might be due to invalid IL or missing references) //IL_0241: Unknown result type (might be due to invalid IL or missing references) //IL_0246: Unknown result type (might be due to invalid IL or missing references) //IL_024b: Unknown result type (might be due to invalid IL or missing references) //IL_0270: Unknown result type (might be due to invalid IL or missing references) //IL_0276: Unknown result type (might be due to invalid IL or missing references) //IL_0296: Unknown result type (might be due to invalid IL or missing references) //IL_0349: Unknown result type (might be due to invalid IL or missing references) //IL_0355: Unknown result type (might be due to invalid IL or missing references) //IL_035a: Unknown result type (might be due to invalid IL or missing references) //IL_0323: Unknown result type (might be due to invalid IL or missing references) //IL_0329: Unknown result type (might be due to invalid IL or missing references) //IL_0333: Unknown result type (might be due to invalid IL or missing references) //IL_0338: Unknown result type (might be due to invalid IL or missing references) //IL_033d: Unknown result type (might be due to invalid IL or missing references) //IL_03c0: Unknown result type (might be due to invalid IL or missing references) //IL_03c5: Unknown result type (might be due to invalid IL or missing references) //IL_02d4: Unknown result type (might be due to invalid IL or missing references) //IL_02da: Unknown result type (might be due to invalid IL or missing references) //IL_02fa: Unknown result type (might be due to invalid IL or missing references) //IL_0390: Unknown result type (might be due to invalid IL or missing references) //IL_0395: Unknown result type (might be due to invalid IL or missing references) //IL_0383: Unknown result type (might be due to invalid IL or missing references) //IL_039a: Unknown result type (might be due to invalid IL or missing references) //IL_03a8: Unknown result type (might be due to invalid IL or missing references) //IL_03ad: Unknown result type (might be due to invalid IL or missing references) //IL_03af: Unknown result type (might be due to invalid IL or missing references) if (!launched || finished || (Object)(object)body == (Object)null) { return; } if (stuck) { if (chainDetonationAt >= 0f && Time.time >= chainDetonationAt) { DetonateStuck(); } return; } float num = ((Profile == GrenadeProjectileProfile.GreenContact) ? PluginSettings.GreenLifetime : PluginSettings.Lifetime); if (Time.time - bornAt >= Mathf.Max(1f, num)) { FinishSilently(); return; } if ((Object)(object)Grenade != (Object)null && Grenade.hooked) { Grenade.CanCollideWithPlayer(false); if (!wasHooked && bounced && !parried && fuseRemaining >= 0f) { fuseRemaining += Mathf.Max(0f, PluginSettings.HookFuseGrace); } wasHooked = true; lastFixedRotation = ((Component)this).transform.rotation; return; } if (wasHooked) { wasHooked = false; if (!body.isKinematic) { simulatedVelocity = body.velocity; lastVelocity = simulatedVelocity; } } if ((Object)(object)Grenade != (Object)null && Grenade.frozen) { return; } if (bounced && !parried && fuseRemaining >= 0f) { fuseRemaining -= Time.fixedDeltaTime; if (fuseRemaining <= 0f) { Explode(GrenadeExplosionMode.Surface); return; } } if (body.isKinematic) { lastFixedRotation = ((Component)this).transform.rotation; return; } Vector3 velocity = body.velocity; Vector3 val = lastVelocity; Vector3 val2 = velocity - val; bool flag = ((Vector3)(ref val2)).sqrMagnitude > 4f && Time.time - bornAt > Time.fixedDeltaTime * 2f; bool flag2 = flag && IsMagnitudePreservingRotation(val, velocity); if (flag2) { Quaternion val3 = ((Component)this).transform.rotation * Quaternion.Inverse(lastFixedRotation); simulatedVelocity = velocity; lastVelocity = velocity; capturedGravity = val3 * capturedGravity; } if (flag2 && !loggedPortalRotation) { loggedPortalRotation = true; Plugin.LogSource.LogInfo((object)("Detected a seamless portal transform; rotating the captured launch trajectory and gravity. " + $"expected {val}, actual {velocity}, " + $"rigidbody gravity={body.useGravity}, world gravity={Physics.gravity}.")); } else if (flag && !flag2 && !loggedRejectedExternalChange) { loggedRejectedExternalChange = true; Plugin.LogSource.LogWarning((object)("Rejected an external grenade velocity change to preserve the custom trajectory: " + $"expected {val}, actual {velocity}, " + $"rigidbody gravity={body.useGravity}, world gravity={Physics.gravity}.")); } LockNativeGravity(); if (!parried) { simulatedVelocity += capturedGravity * Time.fixedDeltaTime; } body.velocity = simulatedVelocity; lastVelocity = simulatedVelocity; if (((Vector3)(ref simulatedVelocity)).sqrMagnitude > 0.01f) { Vector3 val4 = ((((Vector3)(ref capturedGravity)).sqrMagnitude > 0.001f) ? (-((Vector3)(ref capturedGravity)).normalized) : Vector3.up); ((Component)this).transform.rotation = Quaternion.LookRotation(((Vector3)(ref simulatedVelocity)).normalized, val4); } lastFixedRotation = ((Component)this).transform.rotation; } private static bool IsMagnitudePreservingRotation(Vector3 before, Vector3 after) { //IL_003f: Unknown result type (might be due to invalid IL or missing references) //IL_0040: Unknown result type (might be due to invalid IL or missing references) float magnitude = ((Vector3)(ref before)).magnitude; float magnitude2 = ((Vector3)(ref after)).magnitude; if (magnitude < 0.5f || magnitude2 < 0.5f) { return false; } float num = Mathf.Max(0.35f, magnitude * 0.015f); if (Mathf.Abs(magnitude - magnitude2) <= num) { return Vector3.Angle(before, after) >= 2f; } return false; } private void LockNativeGravity() { if ((Object)(object)body == (Object)null) { return; } body.useGravity = false; PhysicsExtensions.SetGravityMode(body, false); ((Component)body).GetComponents(customGravityComponents); foreach (CustomGravity customGravityComponent in customGravityComponents) { if ((Object)(object)customGravityComponent != (Object)null) { customGravityComponent.useGravity = false; } } } internal void HandleCollision(Collider other, Vector3 incomingVelocity, Vector3 collisionNormal, Vector3 collisionPoint) { //IL_0166: Unknown result type (might be due to invalid IL or missing references) //IL_0175: 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_00b3: Unknown result type (might be due to invalid IL or missing references) //IL_01d5: Unknown result type (might be due to invalid IL or missing references) //IL_01d6: Unknown result type (might be due to invalid IL or missing references) //IL_01d7: Unknown result type (might be due to invalid IL or missing references) //IL_0140: Unknown result type (might be due to invalid IL or missing references) //IL_01c2: Unknown result type (might be due to invalid IL or missing references) //IL_01c8: Invalid comparison between Unknown and I4 if (finished || (Object)(object)other == (Object)null || stuck || ((Component)other).CompareTag("Player") || ((Component)other).gameObject.layer == 14 || ((Component)other).gameObject.layer == 20) { return; } if ((Object)(object)((Component)other).GetComponentInParent() != (Object)null) { Collider[] array = ownColliders; foreach (Collider val in array) { if ((Object)(object)val != (Object)null && (Object)(object)val != (Object)(object)other) { Physics.IgnoreCollision(val, other, true); } } if ((Object)(object)body != (Object)null && !body.isKinematic) { body.velocity = simulatedVelocity; } return; } if (Profile == GrenadeProjectileProfile.Primary) { Glass componentInParent = ((Component)other).GetComponentInParent(); if ((Object)(object)componentInParent != (Object)null) { componentInParent.Shatter(); Collider[] array = ownColliders; foreach (Collider val2 in array) { if ((Object)(object)val2 != (Object)null && (Object)(object)val2 != (Object)(object)other) { Physics.IgnoreCollision(val2, other, true); } } if ((Object)(object)body != (Object)null && !body.isKinematic) { body.velocity = simulatedVelocity; } return; } } EnemyIdentifier val3 = TryGetLivingEnemy(other); if (!other.isTrigger || !((Object)(object)val3 == (Object)null)) { if (GelSystem.TryGetStickTarget(other, val3, collisionPoint, out var stain, out var coverage)) { StickToGel(other, collisionNormal, collisionPoint, val3, stain, coverage); } else if (Profile == GrenadeProjectileProfile.GreenContact) { Explode(((Object)(object)val3 != (Object)null) ? GrenadeExplosionMode.GreenDirect : GrenadeExplosionMode.GreenSurface, val3); } else if (parried) { Explode(GrenadeExplosionMode.Parried); } else if (!bounced && (Object)(object)val3 != (Object)null && (int)val3.enemyType != 4) { Explode(GrenadeExplosionMode.Direct, val3); } else { Bounce(other, incomingVelocity, collisionNormal, collisionPoint); } } } internal static EnemyIdentifier TryGetLivingEnemy(Collider other) { if ((Object)(object)other == (Object)null) { return null; } EnemyIdentifierIdentifier val = null; if ((Object)(object)other.attachedRigidbody != (Object)null) { val = ((Component)other.attachedRigidbody).GetComponent(); } if ((Object)(object)val == (Object)null) { val = ((Component)other).GetComponentInParent(); } if ((Object)(object)val != (Object)null && (Object)(object)val.eid != (Object)null && !val.eid.dead) { return val.eid; } EnemyIdentifier componentInParent = ((Component)other).GetComponentInParent(); if (!((Object)(object)componentInParent != (Object)null) || componentInParent.dead) { return null; } return componentInParent; } private void Bounce(Collider surface, Vector3 incomingVelocity, Vector3 collisionNormal, Vector3 collisionPoint) { //IL_0063: 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_0068: 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_006a: 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_007f: 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_0093: 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_00a0: Unknown result type (might be due to invalid IL or missing references) //IL_00a5: Unknown result type (might be due to invalid IL or missing references) //IL_0113: 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_011a: 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_0140: Unknown result type (might be due to invalid IL or missing references) //IL_0141: Unknown result type (might be due to invalid IL or missing references) //IL_0142: Unknown result type (might be due to invalid IL or missing references) //IL_0148: Unknown result type (might be due to invalid IL or missing references) //IL_014d: Unknown result type (might be due to invalid IL or missing references) //IL_00f6: 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_00d6: Unknown result type (might be due to invalid IL or missing references) //IL_00db: Unknown result type (might be due to invalid IL or missing references) //IL_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_0189: Unknown result type (might be due to invalid IL or missing references) //IL_018e: 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) //IL_0177: Unknown result type (might be due to invalid IL or missing references) //IL_017d: Unknown result type (might be due to invalid IL or missing references) //IL_0104: 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_010a: 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) if ((Object)(object)body == (Object)null) { return; } if (!bounced) { bounced = true; fuseRemaining = Mathf.Max(0.1f, PluginSettings.SurfaceFuse); if ((Object)(object)parryReceiver != (Object)null) { ((Behaviour)parryReceiver).enabled = true; } } Vector3 val = ((((Vector3)(ref lastVelocity)).sqrMagnitude > 0.01f) ? lastVelocity : incomingVelocity); Vector3 val2 = collisionNormal; if (((Vector3)(ref val2)).sqrMagnitude < 0.01f) { Bounds bounds = surface.bounds; Vector3 val3 = ((Bounds)(ref bounds)).ClosestPoint(((Component)this).transform.position); val2 = ((Component)this).transform.position - val3; } if (((Vector3)(ref val2)).sqrMagnitude < 0.01f) { val2 = ((((Vector3)(ref val)).sqrMagnitude > 0.01f) ? (-((Vector3)(ref val)).normalized) : (-((Vector3)(ref capturedGravity)).normalized)); } ((Vector3)(ref val2)).Normalize(); if (((Vector3)(ref val)).sqrMagnitude > 0.01f && Vector3.Dot(val2, val) > 0f) { val2 = -val2; } lastBounceSurface = surface; lastBounceNormal = val2; lastBouncePoint = collisionPoint; hasLastBouncePoint = true; float num = Mathf.Clamp01(PluginSettings.BounceRetention); body.constraints = (RigidbodyConstraints)0; simulatedVelocity = Vector3.Reflect(val, val2) * num; if (!body.isKinematic) { body.velocity = simulatedVelocity; Rigidbody obj = body; obj.angularVelocity *= num; } lastVelocity = simulatedVelocity; } private void Parry() { //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_007e: 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_0099: 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_00b2: Unknown result type (might be due to invalid IL or missing references) //IL_00d7: Unknown result type (might be due to invalid IL or missing references) //IL_00e7: 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_00f8: 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_0110: Unknown result type (might be due to invalid IL or missing references) //IL_0115: 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) if (!finished && bounced && !((Object)(object)body == (Object)null)) { parried = true; fuseRemaining = -1f; if ((Object)(object)parryReceiver != (Object)null) { ((Behaviour)parryReceiver).enabled = false; } Grenade.CanCollideWithPlayer(false); CameraController instance = MonoSingleton.Instance; Vector3 val = (((Object)(object)instance != (Object)null) ? ((Component)instance).transform.forward : ((Component)this).transform.forward); body.constraints = (RigidbodyConstraints)0; simulatedVelocity = ((Vector3)(ref val)).normalized * launchForwardSpeed * Mathf.Max(0.1f, PluginSettings.ParrySpeedMultiplier); if (body.isKinematic) { body.isKinematic = false; } body.velocity = simulatedVelocity; body.angularVelocity = Vector3.zero; lastVelocity = simulatedVelocity; ((Component)this).transform.rotation = Quaternion.LookRotation(((Vector3)(ref val)).normalized, ((Component)this).transform.up); if (IsParriedIntoLastSurface(((Vector3)(ref val)).normalized)) { Explode(GrenadeExplosionMode.Parried); } } } private bool IsParriedIntoLastSurface(Vector3 direction) { //IL_0023: 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_0029: 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_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_004d: 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_0055: 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_0075: 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_0085: 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_00a9: Unknown result type (might be due to invalid IL or missing references) //IL_00ae: Unknown result type (might be due to invalid IL or missing references) //IL_0102: Unknown result type (might be due to invalid IL or missing references) //IL_0107: 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) //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_0123: 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_0146: Unknown result type (might be due to invalid IL or missing references) //IL_014c: 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_0173: Unknown result type (might be due to invalid IL or missing references) //IL_01ad: Unknown result type (might be due to invalid IL or missing references) //IL_01b8: Unknown result type (might be due to invalid IL or missing references) //IL_01bd: Unknown result type (might be due to invalid IL or missing references) //IL_01a5: Unknown result type (might be due to invalid IL or missing references) //IL_01c2: Unknown result type (might be due to invalid IL or missing references) //IL_01d3: Unknown result type (might be due to invalid IL or missing references) //IL_01d6: Unknown result type (might be due to invalid IL or missing references) //IL_01f6: Unknown result type (might be due to invalid IL or missing references) //IL_01f9: Unknown result type (might be due to invalid IL or missing references) //IL_01fe: Unknown result type (might be due to invalid IL or missing references) //IL_0203: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)lastBounceSurface == (Object)null) { return false; } float fullProjectileClearance = GetFullProjectileClearance(); RaycastHit val = default(RaycastHit); bool num = lastBounceSurface.Raycast(new Ray(((Component)this).transform.position, direction), ref val, fullProjectileClearance); Vector3 val2 = ((Component)this).transform.position - direction * fullProjectileClearance; RaycastHit val3 = default(RaycastHit); bool num2 = lastBounceSurface.Raycast(new Ray(val2, direction), ref val3, fullProjectileClearance * 2f); float num3 = (num2 ? Vector3.Dot(((RaycastHit)(ref val3)).point - ((Component)this).transform.position, direction) : float.PositiveInfinity); bool flag = num2 && num3 >= -0.05f; RaycastHit val4 = default(RaycastHit); bool flag2 = Physics.Raycast(((Component)this).transform.position, direction, ref val4, fullProjectileClearance, -1, (QueryTriggerInteraction)1) && (Object)(object)((RaycastHit)(ref val4)).collider != (Object)null && !((Component)((RaycastHit)(ref val4)).collider).transform.IsChildOf(((Component)this).transform) && !((Component)((RaycastHit)(ref val4)).collider).CompareTag("Player"); Bounds bounds = lastBounceSurface.bounds; Vector3 val5 = ((Bounds)(ref bounds)).ClosestPoint(((Component)this).transform.position); float num4 = Vector3.Distance(((Component)this).transform.position, val5); float num5 = (hasLastBouncePoint ? Vector3.Distance(((Component)this).transform.position, lastBouncePoint) : float.PositiveInfinity); float num6 = ((((Vector3)(ref lastBounceNormal)).sqrMagnitude >= 0.01f) ? Vector3.Dot(direction, lastBounceNormal) : float.NaN); bool num7 = ((Vector3)(ref lastBounceNormal)).sqrMagnitude >= 0.01f && num6 < -0.05f; Vector3 val6 = (hasLastBouncePoint ? (lastBouncePoint - ((Component)this).transform.position) : Vector3.zero); float num8 = (hasLastBouncePoint ? Mathf.Abs(Vector3.Dot(val6, lastBounceNormal)) : float.PositiveInfinity); float num9; if (!hasLastBouncePoint) { num9 = float.PositiveInfinity; } else { Vector3 val7 = Vector3.ProjectOnPlane(val6, lastBounceNormal); num9 = ((Vector3)(ref val7)).magnitude; } float num10 = num9; bool flag3 = hasLastBouncePoint && num8 <= fullProjectileClearance + 0.25f && num10 <= fullProjectileClearance; bool flag4 = num7 && (num4 <= fullProjectileClearance || num5 <= fullProjectileClearance || flag3); return num || flag || flag2 || flag4; } private float GetFullProjectileClearance() { //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_003c: 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_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) float num = 0.75f; Collider[] array = ownColliders; foreach (Collider val in array) { if (!((Object)(object)val == (Object)null) && val.enabled && !val.isTrigger) { Bounds bounds = val.bounds; float num2 = Vector3.Distance(((Component)this).transform.position, ((Bounds)(ref bounds)).center); Vector3 extents = ((Bounds)(ref bounds)).extents; float num3 = num2 + ((Vector3)(ref extents)).magnitude; num = Mathf.Max(num, num3 + 0.2f); } } return num; } private void StickToGel(Collider surface, Vector3 collisionNormal, Vector3 collisionPoint, EnemyIdentifier hostEnemy, GelStainMarker gelStain, GelCoverage gelCoverage) { //IL_00d7: 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_00ce: Unknown result type (might be due to invalid IL or missing references) //IL_00dc: Unknown result type (might be due to invalid IL or missing references) //IL_00dd: 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_00df: 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_0115: 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_011c: Unknown result type (might be due to invalid IL or missing references) //IL_0121: Unknown result type (might be due to invalid IL or missing references) //IL_00f6: Unknown result type (might be due to invalid IL or missing references) //IL_00fb: Unknown result type (might be due to invalid IL or missing references) //IL_0104: Unknown result type (might be due to invalid IL or missing references) //IL_0109: Unknown result type (might be due to invalid IL or missing references) //IL_010e: Unknown result type (might be due to invalid IL or missing references) //IL_018b: Unknown result type (might be due to invalid IL or missing references) //IL_019b: Unknown result type (might be due to invalid IL or missing references) if (!finished && !stuck && !((Object)(object)body == (Object)null)) { stuck = true; stuckHostEnemyId = (((Object)(object)hostEnemy != (Object)null) ? ((Object)hostEnemy).GetInstanceID() : 0); stuckGelStain = gelStain; stuckGelCoverage = gelCoverage; bounced = false; parried = false; fuseRemaining = -1f; if ((Object)(object)parryReceiver != (Object)null) { ((Behaviour)parryReceiver).enabled = false; } if ((Object)(object)Grenade != (Object)null) { Grenade.hooked = false; Grenade.ignoreExplosions = true; Grenade.CanCollideWithPlayer(false); } Vector3 val = ((((Vector3)(ref collisionNormal)).sqrMagnitude > 0.01f) ? ((Vector3)(ref collisionNormal)).normalized : (-((Vector3)(ref simulatedVelocity)).normalized)); Vector3 val2 = collisionPoint; if (val2 == Vector3.zero && (Object)(object)surface != (Object)null) { Bounds bounds = surface.bounds; val2 = ((Bounds)(ref bounds)).ClosestPoint(((Component)this).transform.position); } ((Component)this).transform.position = val2 + val * 0.05f; Transform val3 = (((Object)(object)surface != (Object)null && (Object)(object)surface.attachedRigidbody != (Object)null) ? ((Component)surface.attachedRigidbody).transform : (((Object)(object)surface != (Object)null) ? ((Component)surface).transform : null)); if ((Object)(object)val3 != (Object)null) { ((Component)this).transform.SetParent(val3, true); } if (!body.isKinematic) { body.velocity = Vector3.zero; body.angularVelocity = Vector3.zero; } body.useGravity = false; body.constraints = (RigidbodyConstraints)126; body.isKinematic = true; GelSystem.RegisterStuck(this); } } internal void DetonateStuck() { if (!IsStuck) { return; } if (chainGroupId <= 0) { nextChainGroupId++; if (nextChainGroupId <= 0) { nextChainGroupId = 1; } chainGroupId = nextChainGroupId; } Explode(GrenadeExplosionMode.Stuck); } internal void ScheduleChainDetonation(float delay, int incomingChainGroupId) { if (!IsStuck) { return; } float num = Time.time + Mathf.Max(0f, delay); if (chainDetonationAt < 0f || num < chainDetonationAt) { chainDetonationAt = num; if (incomingChainGroupId > 0) { chainGroupId = incomingChainGroupId; } } } private void Explode(GrenadeExplosionMode mode, EnemyIdentifier directEnemy = null) { //IL_0153: Unknown result type (might be due to invalid IL or missing references) //IL_0158: Unknown result type (might be due to invalid IL or missing references) //IL_0426: Unknown result type (might be due to invalid IL or missing references) //IL_0438: Unknown result type (might be due to invalid IL or missing references) //IL_021c: Unknown result type (might be due to invalid IL or missing references) //IL_0222: Unknown result type (might be due to invalid IL or missing references) //IL_0227: Unknown result type (might be due to invalid IL or missing references) //IL_022c: 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: Unknown result type (might be due to invalid IL or missing references) //IL_024b: Unknown result type (might be due to invalid IL or missing references) //IL_0250: Unknown result type (might be due to invalid IL or missing references) //IL_03ef: Unknown result type (might be due to invalid IL or missing references) //IL_03f5: Unknown result type (might be due to invalid IL or missing references) if (finished) { return; } finished = true; GrenadeLongRangeStyle longRangeStyle = GetLongRangeStyle(mode, directEnemy); float num; float num2; float num3; float num4; switch (mode) { case GrenadeExplosionMode.Direct: num = PluginSettings.Damage; num2 = PluginSettings.ExplosionSizeMultiplier; num3 = PluginSettings.DirectSelfDamage; num4 = PluginSettings.KnockbackMultiplier; break; case GrenadeExplosionMode.Surface: num = PluginSettings.SurfaceDamage; num2 = PluginSettings.ExplosionSizeMultiplier; num3 = PluginSettings.SurfaceSelfDamage; num4 = PluginSettings.KnockbackMultiplier; break; case GrenadeExplosionMode.Parried: num = PluginSettings.ParryDamage; num2 = PluginSettings.ParryExplosionSize; num3 = PluginSettings.ParrySelfDamage; num4 = PluginSettings.KnockbackMultiplier; break; case GrenadeExplosionMode.GreenDirect: num = PluginSettings.GreenDirectDamage; num2 = PluginSettings.GreenDirectExplosionSize; num3 = PluginSettings.GreenDirectSelfDamage; num4 = PluginSettings.GreenKnockbackMultiplier; break; case GrenadeExplosionMode.GreenSurface: num = PluginSettings.GreenSurfaceDamage; num2 = PluginSettings.GreenSurfaceExplosionSize; num3 = PluginSettings.GreenSurfaceSelfDamage; num4 = PluginSettings.GreenKnockbackMultiplier; break; default: num = ((Profile == GrenadeProjectileProfile.GreenContact) ? PluginSettings.GreenStuckDamage : PluginSettings.StuckDamage); num2 = PluginSettings.StuckExplosionSize; num3 = PluginSettings.StuckSelfDamage; num4 = PluginSettings.StuckKnockbackMultiplier; break; } switch (longRangeStyle) { case GrenadeLongRangeStyle.PipeDream: num *= PluginSettings.PipeDreamDamageMultiplier; num2 *= PluginSettings.PipeDreamExplosionSizeMultiplier; break; case GrenadeLongRangeStyle.MoonShot: num *= PluginSettings.MoonShotDamageMultiplier; num2 *= PluginSettings.MoonShotExplosionSizeMultiplier; break; } float num5 = 5f * num2; if ((Object)(object)Grenade != (Object)null && (Object)(object)Grenade.explosion != (Object)null) { GameObject val = Object.Instantiate(Grenade.explosion, ((Component)this).transform.position, Quaternion.identity); GrenadeLauncherExplosionMarker grenadeLauncherExplosionMarker = val.AddComponent(); grenadeLauncherExplosionMarker.Parried = mode == GrenadeExplosionMode.Parried; grenadeLauncherExplosionMarker.Mode = mode; grenadeLauncherExplosionMarker.Damage = Mathf.Max(0f, num); grenadeLauncherExplosionMarker.SourceWeapon = Grenade.sourceWeapon; grenadeLauncherExplosionMarker.DirectEnemyId = (((Object)(object)directEnemy != (Object)null) ? ((Object)directEnemy).GetInstanceID() : 0); grenadeLauncherExplosionMarker.LongRangeStyle = longRangeStyle; grenadeLauncherExplosionMarker.StuckHostEnemyId = ((mode == GrenadeExplosionMode.Stuck) ? stuckHostEnemyId : 0); grenadeLauncherExplosionMarker.StuckCarrierDamage = ((Profile == GrenadeProjectileProfile.GreenContact) ? PluginSettings.GreenDirectDamage : PluginSettings.Damage); grenadeLauncherExplosionMarker.StuckChainGroupId = ((mode == GrenadeExplosionMode.Stuck) ? chainGroupId : 0); if ((Object)(object)directEnemy != (Object)null) { Vector3 val2 = ((Component)this).transform.position - launchPosition; grenadeLauncherExplosionMarker.DirectProfile = Profile; Vector2 val3 = new Vector2(val2.x, val2.z); grenadeLauncherExplosionMarker.DirectPlanarDistance = ((Vector2)(ref val3)).magnitude; grenadeLauncherExplosionMarker.DirectStraightDistance = ((Vector3)(ref val2)).magnitude; grenadeLauncherExplosionMarker.TheoreticalSameHeightRange = sameHeightMaximumRange; grenadeLauncherExplosionMarker.LaunchElevationDegrees = launchElevationDegrees; grenadeLauncherExplosionMarker.ConfiguredStyleThreshold = ((grenadeLauncherExplosionMarker.LongRangeStyle == GrenadeLongRangeStyle.MoonShot) ? PluginSettings.MoonShotMinimumDistance : PluginSettings.PipeDreamMinimumDistance); } Explosion[] componentsInChildren = val.GetComponentsInChildren(true); foreach (Explosion val4 in componentsInChildren) { if (!loggedExplosion) { loggedExplosion = true; Plugin.LogSource.LogInfo((object)($"Vanilla rocket explosion baseline: damage {val4.damage}, " + $"enemy multiplier {val4.enemyDamageMultiplier:0.###}, " + $"push {val4.pushForceMultiplier:0.###}, radius {val4.maxSize:0.###}.")); } val4.sourceWeapon = Grenade.sourceWeapon; if (val4.damage > 0) { val4.damage = Mathf.RoundToInt(Mathf.Max(0f, num) * 10f); } val4.playerDamageOverride = Mathf.RoundToInt(Mathf.Max(0f, num3)); val4.maxSize *= num2; num5 = Mathf.Max(num5, val4.maxSize); val4.speed *= num2; val4.pushForceMultiplier *= num4; val4.rocketExplosion = false; val4.isFup = false; val4.boosted = false; val4.unblockable = mode == GrenadeExplosionMode.Parried; } Transform transform = val.transform; transform.localScale *= num2; } else { Plugin.LogSource.LogWarning((object)"Grenade explosion prefab missing; projectile removed without a blast."); } if (mode == GrenadeExplosionMode.Stuck) { GelSystem.Consume(stuckGelStain, stuckGelCoverage, ((Component)this).transform.position, num5); GelSystem.TriggerChain(((Component)this).transform.position, this, num5); } GelSystem.UnregisterStuck(this); Object.Destroy((Object)(object)((Component)this).gameObject); } private GrenadeLongRangeStyle GetLongRangeStyle(GrenadeExplosionMode mode, EnemyIdentifier directEnemy) { //IL_0018: 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_0028: 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_002f: Unknown result type (might be due to invalid IL or missing references) //IL_0035: Unknown result type (might be due to invalid IL or missing references) //IL_003a: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)directEnemy == (Object)null || (mode != GrenadeExplosionMode.Direct && mode != GrenadeExplosionMode.GreenDirect)) { return GrenadeLongRangeStyle.None; } Vector3 val = ((Component)this).transform.position - launchPosition; Vector2 val2 = new Vector2(val.x, val.z); float magnitude = ((Vector2)(ref val2)).magnitude; if (magnitude >= Mathf.Max(0f, PluginSettings.MoonShotMinimumDistance)) { return GrenadeLongRangeStyle.MoonShot; } if (magnitude >= Mathf.Max(0f, PluginSettings.PipeDreamMinimumDistance)) { return GrenadeLongRangeStyle.PipeDream; } return GrenadeLongRangeStyle.None; } private void FinishSilently() { if (!finished) { finished = true; GelSystem.UnregisterStuck(this); Object.Destroy((Object)(object)((Component)this).gameObject); } } } internal static class TrajectoryCalibration { private static float cachedEyeHeight = -1f; internal static void CaptureStandingEyeHeight() { if (!(cachedEyeHeight > 0f) && !((Object)(object)Plugin.Instance == (Object)null) && PluginSettings.EyeHeightScaling) { float num = TryMeasure(); if (num > 0f) { cachedEyeHeight = num; Plugin.LogSource.LogInfo((object)$"Calibrated standing V1 eye height once: {cachedEyeHeight:0.###} Unity units."); } } } internal static float GetEyeHeight() { float result = Mathf.Clamp(PluginSettings.FallbackEyeHeight, 0.5f, 10f); if (!PluginSettings.EyeHeightScaling) { return result; } if (cachedEyeHeight > 0f) { return cachedEyeHeight; } float num = TryMeasure(); if (num > 0f) { cachedEyeHeight = num; return cachedEyeHeight; } return result; } private static float TryMeasure() { //IL_0060: 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_0079: Unknown result type (might be due to invalid IL or missing references) try { NewMovement instance = MonoSingleton.Instance; CameraController instance2 = MonoSingleton.Instance; if ((Object)(object)instance == (Object)null || (Object)(object)instance.playerCollider == (Object)null || (Object)(object)instance2 == (Object)null) { return -1f; } if ((Object)(object)instance.gc != (Object)null && !instance.gc.onGround) { return -1f; } float y = ((Component)instance2).transform.position.y; Bounds bounds = ((Collider)instance.playerCollider).bounds; float num = y - ((Bounds)(ref bounds)).min.y; return (num >= 0.5f && num <= 10f) ? num : (-1f); } catch (Exception ex) { Plugin.LogSource.LogDebug((object)("Could not measure V1 eye height: " + ex.Message)); return -1f; } } } internal sealed class TerminalIntegration : MonoBehaviour { private const string PanelName = "Grenade Launcher Mod Equipment"; private static readonly List Controllers = new List(); private float nextScan; private void Update() { //IL_005e: Unknown result type (might be due to invalid IL or missing references) //IL_0063: Unknown result type (might be due to invalid IL or missing references) if (Time.unscaledTime < nextScan) { return; } nextScan = Time.unscaledTime + 1f; Controllers.RemoveAll((RocketVariantTerminalController controller) => (Object)(object)controller == (Object)null); GameObject val = GameObject.Find("Rocket Launcher Window"); if ((Object)(object)val == (Object)null) { return; } Scene scene = val.scene; if (!((Scene)(ref scene)).IsValid()) { return; } Transform transform = val.transform; TrajectoryCalibration.CaptureStandingEyeHeight(); Transform val2 = transform.Find("Grenade Launcher Mod Equipment"); if ((Object)(object)val2 != (Object)null) { Object.Destroy((Object)(object)((Component)val2).gameObject); } Plugin.Instance?.EnsureVariantMigration(); VariationInfo[] componentsInChildren = ((Component)transform).GetComponentsInChildren(true); foreach (VariationInfo val3 in componentsInChildren) { if (val3.weaponName != null && val3.weaponName.StartsWith("rock", StringComparison.Ordinal) && val3.weaponName.Length == 5 && !((Object)(object)((Component)val3).GetComponent() != (Object)null)) { RocketVariantTerminalController rocketVariantTerminalController = ((Component)val3).gameObject.AddComponent(); rocketVariantTerminalController.Initialize(val3, val3.weaponName[4] - 48); Controllers.Add(rocketVariantTerminalController); } } } internal static void RefreshAll() { Controllers.RemoveAll((RocketVariantTerminalController controller) => (Object)(object)controller == (Object)null); foreach (RocketVariantTerminalController controller in Controllers) { controller.RefreshDisplay(); } } internal static void Cleanup() { foreach (RocketVariantTerminalController controller in Controllers) { if ((Object)(object)controller != (Object)null) { Object.Destroy((Object)(object)controller); } } Controllers.Clear(); } } internal sealed class RocketVariantTerminalController : MonoBehaviour { private static readonly FieldInfo EquipStatusField = AccessTools.Field(typeof(VariationInfo), "equipStatus"); private static readonly FieldInfo GunSetterField = AccessTools.Field(typeof(VariationInfo), "gs"); private static readonly MethodInfo SetEquipStatusTextMethod = AccessTools.Method(typeof(VariationInfo), "SetEquipStatusText", (Type[])null, (Type[])null); private readonly List> listeners = new List>(); private VariationInfo variationInfo; private int variation; private int displayedStatus; internal void Initialize(VariationInfo info, int variant) { variationInfo = info; variation = variant; AddPointerListener(((Component)info).transform.Find("Equipment/Equipment Status"), 1); AddPointerListener(((Component)info).transform.Find("Equipment/Buttons/Previous Button"), -1); AddPointerListener(((Component)info).transform.Find("Equipment/Buttons/Next Button"), 1); RefreshDisplay(); } private void AddPointerListener(Transform button, int direction) { //IL_0069: Unknown result type (might be due to invalid IL or missing references) //IL_006f: Expected O, but got Unknown //IL_0076: Unknown result type (might be due to invalid IL or missing references) //IL_007c: Expected O, but got Unknown if ((Object)(object)button == (Object)null) { return; } Component val = ((IEnumerable)((Component)button).GetComponents()).FirstOrDefault((Func)((Component component) => (Object)(object)component != (Object)null && ((object)component).GetType().Name == "ControllerPointer")); if (!((Object)(object)val == (Object)null)) { UnityEvent val2 = (UnityEvent)AccessTools.Property(((object)val).GetType(), "OnPressed").GetValue(val); UnityAction val3 = (UnityAction)delegate { AfterNativeChange(direction); }; val2.AddListener(val3); listeners.Add(Tuple.Create(val2, val3)); } } private void AfterNativeChange(int direction) { //IL_009a: Unknown result type (might be due to invalid IL or missing references) //IL_00a0: Expected O, but got Unknown if (!((Object)(object)Plugin.Instance == (Object)null) && !((Object)(object)variationInfo == (Object)null)) { int num = ((direction > 0) ? (displayedStatus + 1) : (displayedStatus - 1)); if (num > 2) { num = 0; } else if (num < 0) { num = 2; } displayedStatus = num; PrefsManager instance = MonoSingleton.Instance; if ((Object)(object)instance != (Object)null) { instance.SetInt("weapon.rock" + variation, (num != 0) ? 1 : 0); } Plugin.Instance.SetGrenadeModeEnabled(variation, num == 2); GunSetter val = (GunSetter)GunSetterField.GetValue(variationInfo); if ((Object)(object)val != (Object)null) { val.ResetWeapons(false); } ApplyDisplay(num); } } private void LateUpdate() { if ((Object)(object)variationInfo != (Object)null && ((Component)this).gameObject.activeInHierarchy) { RefreshDisplay(); } } internal void RefreshDisplay() { if (!((Object)(object)Plugin.Instance == (Object)null) && !((Object)(object)variationInfo == (Object)null)) { PrefsManager instance = MonoSingleton.Instance; int num = ((!((Object)(object)instance != (Object)null)) ? 1 : instance.GetInt("weapon.rock" + variation, 1)); displayedStatus = ((num > 0) ? ((!Plugin.Instance.IsGrenadeModeEnabled(variation)) ? 1 : 2) : 0); ApplyDisplay(displayedStatus); } } private void ApplyDisplay(int status) { //IL_0096: 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_00ce: 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) EquipStatusField.SetValue(variationInfo, status); SetEquipStatusTextMethod.Invoke(variationInfo, new object[1] { status }); bool flag = status != 0; if ((Object)(object)variationInfo.orderButtons != (Object)null) { variationInfo.orderButtons.SetActive(flag); } if ((Object)(object)variationInfo.icon != (Object)null) { ((Graphic)variationInfo.icon).rectTransform.anchoredPosition = (Vector2)(flag ? new Vector2(25f, 0f) : Vector2.zero); ((Graphic)variationInfo.icon).rectTransform.sizeDelta = (flag ? new Vector2(75f, 75f) : new Vector2(100f, 100f)); } } private void OnDestroy() { foreach (Tuple listener in listeners) { listener.Item1.RemoveListener(listener.Item2); } listeners.Clear(); } } internal static class AlternateFireInputContext { internal static InputActionState SuppressedAction; internal static int Depth; internal static bool Active { get { if (Depth > 0) { return SuppressedAction != null; } return false; } } internal static void Enter(InputActionState action) { SuppressedAction = action; Depth++; } internal static void Exit() { Depth = Math.Max(0, Depth - 1); if (Depth == 0) { SuppressedAction = null; } } } [HarmonyPatch(typeof(InputActionState), "get_IsPressed")] internal static class AlternateFirePressedPatch { private static void Postfix(InputActionState __instance, ref bool __result) { if (AlternateFireInputContext.Active && __instance == AlternateFireInputContext.SuppressedAction) { __result = false; } } } [HarmonyPatch(typeof(InputActionState), "get_WasPerformedThisFrame")] internal static class AlternateFirePerformedPatch { private static void Postfix(InputActionState __instance, ref bool __result) { if (AlternateFireInputContext.Active && __instance == AlternateFireInputContext.SuppressedAction) { __result = false; } } } [HarmonyPatch(typeof(RocketLauncher), "Update")] internal static class GrenadeAlternateUpdatePatch { private struct State { internal bool Active; internal bool AltHeld; } private static readonly FieldRef TimerMeter = AccessTools.FieldRefAccess("timerMeter"); private static readonly FieldRef TimerArm = AccessTools.FieldRefAccess("timerArm"); private static readonly FieldRef TimerWindupSound = AccessTools.FieldRefAccess("timerWindupSound"); private static readonly Dictionary blueLastProgress = new Dictionary(); private static void Prefix(RocketLauncher __instance, out State __state) { __state = default(State); if ((Object)(object)Plugin.Instance == (Object)null || !Plugin.Instance.IsGrenadeModeEnabled(__instance) || (__instance.variation != 0 && __instance.variation != 1)) { return; } InputManager instance = MonoSingleton.Instance; PlayerInput val = ((instance != null) ? instance.InputSource : null); if (val == null || val.Fire2 == null) { return; } __state.Active = true; __state.AltHeld = val.Fire2.IsPressed; WeaponCharges instance2 = MonoSingleton.Instance; if ((Object)(object)instance2 != (Object)null) { if (__instance.variation == 1) { instance2.rocketCannonballCharge = AlternateFireController.GreenCooldownProgress; } else if (__instance.variation == 0) { instance2.rocketFrozen = false; instance2.rocketFreezeTime = 0f; } } AlternateFireInputContext.Enter(val.Fire2); } private static void Postfix(RocketLauncher __instance, State __state) { //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_005b: Unknown result type (might be due to invalid IL or missing references) if (__state.Active) { Image val = TimerMeter.Invoke(__instance); if ((Object)(object)val != (Object)null) { if (__instance.variation == 0) { float num = (val.fillAmount = AlternateFireController.BlueCooldownProgress); RectTransform val2 = TimerArm.Invoke(__instance); if ((Object)(object)val2 != (Object)null) { ((Transform)val2).localRotation = Quaternion.Euler(Vector3.forward * (-360f * num)); } PlayBlueMilestoneSounds(__instance, num); } else if (__instance.variation == 1) { val.fillAmount = AlternateFireController.GreenCooldownProgress; } } } if (__state.Active && __state.AltHeld) { AlternateFireController.TryFire(__instance); } } private static Exception Finalizer(State __state, Exception __exception) { if (__state.Active) { AlternateFireInputContext.Exit(); } return __exception; } private static void PlayBlueMilestoneSounds(RocketLauncher launcher, float progress) { int instanceID = ((Object)launcher).GetInstanceID(); if (!blueLastProgress.TryGetValue(instanceID, out var value)) { value = progress; } if (progress + 0.001f < value) { value = progress; } int num = Mathf.Clamp(Mathf.FloorToInt(value * 4f + 0.001f), 0, 4); int num2 = Mathf.Clamp(Mathf.FloorToInt(progress * 4f + 0.001f), 0, 4); if (num2 > num) { AudioSource val = TimerWindupSound.Invoke(launcher); for (int i = num + 1; i <= num2; i++) { if ((Object)(object)val == (Object)null) { break; } Object.Instantiate(val).pitch = 0.6f + (float)i * 0.1f; } } blueLastProgress[instanceID] = progress; } internal static void ResetAudioTracking() { blueLastProgress.Clear(); } } internal static class AlternateFireController { private static readonly FieldRef WeaponId = AccessTools.FieldRefAccess("wid"); private static float greenReadyAt; private static float greenDisplayReadyAt; private static float greenDisplayStartedAt; private static float greenDisplayDuration; private static float blueReadyAt; private static float blueDisplayReadyAt; private static float blueDisplayStartedAt; private static float blueDisplayDuration; private static int greenVolleyFrame = -1; internal static float GreenCooldownProgress { get { if (CooldownRules.NoWeaponCooldown) { return 1f; } if (Time.time >= greenDisplayReadyAt || greenDisplayDuration <= 0f) { return 1f; } return Mathf.Clamp01((Time.time - greenDisplayStartedAt) / greenDisplayDuration); } } internal static float BlueCooldownProgress { get { if (CooldownRules.NoWeaponCooldown) { return 1f; } if (Time.time >= blueDisplayReadyAt || blueDisplayDuration <= 0f) { return 1f; } return Mathf.Clamp01((Time.time - blueDisplayStartedAt) / blueDisplayDuration); } } internal static void OnGreenPrimaryFired() { if (CooldownRules.NoWeaponCooldown) { greenReadyAt = 0f; return; } float num = Mathf.Max(0.05f, PluginSettings.FireInterval); float num2 = Time.time + num; if (!(greenReadyAt >= num2)) { greenReadyAt = num2; } } internal static void OnBluePrimaryFired() { if (CooldownRules.NoWeaponCooldown) { blueReadyAt = 0f; return; } float num = Mathf.Max(0.05f, PluginSettings.FireInterval); float num2 = Time.time + num; if (blueReadyAt < num2) { blueReadyAt = num2; } } internal static void TryFire(RocketLauncher launcher) { //IL_018c: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)launcher == (Object)null || ((Object)(object)GameStateManager.Instance != (Object)null && GameStateManager.Instance.PlayerInputLocked)) { return; } WeaponIdentifier val = WeaponId.Invoke(launcher); bool flag = (Object)(object)val != (Object)null && val.duplicate; if (launcher.variation == 0 && flag) { return; } bool flag2 = launcher.variation == 1 && Time.frameCount == greenVolleyFrame; bool flag3 = flag2 && flag; if (!SharedRocketFireCooldown.Ready && !flag3) { return; } if (launcher.variation == 1 && (CooldownRules.NoWeaponCooldown || Time.time >= greenReadyAt || flag2)) { greenVolleyFrame = Time.frameCount; if (!flag) { GrenadeSpawnContext.Enter(GrenadeProjectileProfile.GreenContact); try { launcher.Shoot(); if (CooldownRules.NoWeaponCooldown) { greenDisplayDuration = 0f; greenDisplayReadyAt = 0f; greenReadyAt = 0f; } else { greenDisplayStartedAt = Time.time; greenDisplayDuration = Mathf.Max(0.05f, PluginSettings.GreenCooldown); greenDisplayReadyAt = Time.time + greenDisplayDuration; greenReadyAt = greenDisplayReadyAt; } WeaponCharges instance = MonoSingleton.Instance; if ((Object)(object)instance != (Object)null) { instance.rocketCannonballCharge = 0f; } return; } finally { GrenadeSpawnContext.Exit(); } } DelayedGreenShot.Schedule(launcher, ((Object)(object)val != (Object)null) ? val.delay : 0f); } else { if (launcher.variation != 0 || (!CooldownRules.NoWeaponCooldown && !(Time.time >= blueReadyAt)) || !HookPointManager.TryGetDeliveryTarget(out var point)) { return; } BlueHookDeliveryContext.Enter(point); GrenadeSpawnContext.Enter(GrenadeProjectileProfile.BlueDelivery); try { launcher.Shoot(); if (CooldownRules.NoWeaponCooldown) { blueDisplayDuration = 0f; blueDisplayReadyAt = 0f; blueReadyAt = 0f; } else { blueDisplayStartedAt = Time.time; blueDisplayDuration = Mathf.Max(0.05f, PluginSettings.BlueCooldown); blueDisplayReadyAt = Time.time + blueDisplayDuration; blueReadyAt = blueDisplayReadyAt; } } finally { GrenadeSpawnContext.Exit(); BlueHookDeliveryContext.Exit(); } } } internal static void Reset() { greenReadyAt = 0f; greenDisplayReadyAt = 0f; greenDisplayStartedAt = 0f; greenDisplayDuration = 0f; blueReadyAt = 0f; blueDisplayReadyAt = 0f; blueDisplayStartedAt = 0f; blueDisplayDuration = 0f; greenVolleyFrame = -1; DelayedGreenShot.CancelAll(); GrenadeAlternateUpdatePatch.ResetAudioTracking(); SharedRocketFireCooldown.Reset(); } internal static void FireDelayedGreen(RocketLauncher launcher) { if ((Object)(object)launcher == (Object)null || !((Component)launcher).gameObject.activeInHierarchy || (Object)(object)Plugin.Instance == (Object)null || !Plugin.Instance.IsGrenadeModeEnabled(launcher) || launcher.variation != 1) { return; } GrenadeSpawnContext.Enter(GrenadeProjectileProfile.GreenContact); try { launcher.Shoot(); } finally { GrenadeSpawnContext.Exit(); } } } internal sealed class DelayedGreenShot : MonoBehaviour { private static readonly HashSet instances = new HashSet(); private RocketLauncher launcher; private float fireAt = -1f; private void Awake() { instances.Add(this); } private void OnDestroy() { instances.Remove(this); } internal static void Schedule(RocketLauncher launcher, float delay) { if (!((Object)(object)launcher == (Object)null)) { DelayedGreenShot delayedGreenShot = ((Component)launcher).GetComponent(); if ((Object)(object)delayedGreenShot == (Object)null) { delayedGreenShot = ((Component)launcher).gameObject.AddComponent(); } if (!(delayedGreenShot.fireAt >= 0f)) { delayedGreenShot.launcher = launcher; delayedGreenShot.fireAt = Time.time + Mathf.Max(0f, delay); } } } internal static void CancelAll() { instances.RemoveWhere((DelayedGreenShot shot) => (Object)(object)shot == (Object)null); DelayedGreenShot[] array = instances.ToArray(); foreach (DelayedGreenShot delayedGreenShot in array) { if ((Object)(object)delayedGreenShot != (Object)null) { delayedGreenShot.fireAt = -1f; } } } private void Update() { if (!(fireAt < 0f) && !(Time.time < fireAt)) { fireAt = -1f; AlternateFireController.FireDelayedGreen(launcher); } } } internal static class BlueHookDeliveryContext { private static int depth; internal static Vector3 Target { get; private set; } internal static void Enter(Vector3 target) { //IL_0007: Unknown result type (might be due to invalid IL or missing references) if (depth == 0) { Target = target; } depth++; } internal static void Exit() { //IL_0019: Unknown result type (might be due to invalid IL or missing references) depth = Math.Max(0, depth - 1); if (depth == 0) { Target = Vector3.zero; } } internal static void Reset() { //IL_0006: Unknown result type (might be due to invalid IL or missing references) depth = 0; Target = Vector3.zero; } } internal static class GelSpawnContext { internal static int Depth; internal static bool Active => Depth > 0; } [HarmonyPatch(typeof(RocketLauncher), "ShootNapalm")] internal static class GelNapalmPatch { private static void Prefix(RocketLauncher __instance, out bool __state) { __state = (Object)(object)Plugin.Instance != (Object)null && Plugin.Instance.IsGrenadeModeEnabled(__instance) && __instance.variation == 2; if (__state) { GelSpawnContext.Depth++; } } private static Exception Finalizer(bool __state, Exception __exception) { if (__state) { GelSpawnContext.Depth = Math.Max(0, GelSpawnContext.Depth - 1); } return __exception; } private static IEnumerable Transpiler(IEnumerable instructions) { MethodInfo replacement = AccessTools.Method(typeof(GelNapalmPatch), "InstantiateProjectile", (Type[])null, (Type[])null); bool replaced = false; foreach (CodeInstruction instruction in instructions) { if (!replaced && instruction.opcode == OpCodes.Call && instruction.operand is MethodInfo { Name: "Instantiate", IsGenericMethod: not false } methodInfo && methodInfo.GetGenericArguments()[0] == typeof(Rigidbody)) { instruction.operand = replacement; replaced = true; } yield return instruction; } if (!replaced) { Plugin.LogSource.LogError((object)"Could not install the red gel projectile factory; ShootNapalm changed."); } } private static Rigidbody InstantiateProjectile(Rigidbody original, Vector3 position, Quaternion rotation) { //IL_0001: Unknown result type (might be due to invalid IL or missing references) //IL_0002: Unknown result type (might be due to invalid IL or missing references) Rigidbody val = Object.Instantiate(original, position, rotation); if (GelSpawnContext.Active && (Object)(object)val != (Object)null && (Object)(object)((Component)val).GetComponent() == (Object)null) { ((Component)val).gameObject.AddComponent(); } return val; } } [HarmonyPatch(typeof(GasolineProjectile), "OnTriggerEnter")] internal static class GelProjectileCollisionPatch { private static bool Prefix(GasolineProjectile __instance, Collider other, out bool __state) { __state = false; GelProjectileMarker componentInParent = ((Component)__instance).GetComponentInParent(); if ((Object)(object)componentInParent == (Object)null) { return true; } EnemyIdentifier val = GrenadeLauncherProjectile.TryGetLivingEnemy(other); if ((Object)(object)val != (Object)null) { componentInParent.HitEnemy(__instance, other, val); return false; } if ((Object)(object)other == (Object)null || ((Component)other).CompareTag("Player") || ((Component)other).gameObject.layer == 14 || !LayerMaskDefaults.IsMatchingLayer(((Component)other).gameObject.layer, (LMD)1)) { return false; } __state = true; GelStainSpawnContext.Enter(); return true; } private static Exception Finalizer(bool __state, Exception __exception) { if (__state) { GelStainSpawnContext.Exit(); } return __exception; } } internal static class GelStainSpawnContext { private static int depth; internal static bool Active => depth > 0; internal static void Enter() { depth++; } internal static void Exit() { depth = Math.Max(0, depth - 1); } internal static void Reset() { depth = 0; } } [HarmonyPatch(typeof(GasolineStain), "Awake")] internal static class GelStainAwakePatch { private static void Postfix(GasolineStain __instance) { if (GelStainSpawnContext.Active && (Object)(object)((Component)__instance).GetComponent() == (Object)null) { ((Component)__instance).gameObject.AddComponent(); } } } [HarmonyPatch(typeof(GasolineStain), "AttachTo")] internal static class GelStainAttachPatch { private static bool Prefix(GasolineStain __instance, Collider other) { //IL_0019: 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) GelStainMarker component = ((Component)__instance).GetComponent(); if ((Object)(object)component == (Object)null) { return true; } Transform transform = ((Component)__instance).transform; transform.position -= ((Component)__instance).transform.forward * 0.02f; ((Component)__instance).transform.SetParent(((Component)other).transform, true); __instance.SetSize(Mathf.Max(0.1f, PluginSettings.GelSpotSize)); component.Surface = other; component.EnemyVisual = (Object)(object)GrenadeLauncherProjectile.TryGetLivingEnemy(other) != (Object)null; component.Radius = 0.75f * Mathf.Max(0.1f, PluginSettings.GelSpotSize); GelSystem.PrepareAndRegisterStain(component); return false; } } internal sealed class GelProjectileMarker : MonoBehaviour { private bool hit; private void Start() { //IL_0012: 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_0049: Unknown result type (might be due to invalid IL or missing references) //IL_0050: Expected O, but got Unknown //IL_007a: 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_0096: Unknown result type (might be due to invalid IL or missing references) //IL_009d: Unknown result type (might be due to invalid IL or missing references) Rigidbody component = ((Component)this).GetComponent(); if ((Object)(object)component != (Object)null) { component.velocity *= Mathf.Max(0.1f, PluginSettings.GelProjectileSpeedMultiplier); } Renderer[] componentsInChildren = ((Component)this).GetComponentsInChildren(true); Color val3 = default(Color); foreach (Renderer val in componentsInChildren) { if (!((Object)(object)val == (Object)null)) { MaterialPropertyBlock val2 = new MaterialPropertyBlock(); val.GetPropertyBlock(val2); ((Color)(ref val3))..ctor(0.05f, 0.4f, 1f, 1f); val2.SetColor("_Color", val3); val2.SetColor("_BaseColor", val3); val2.SetColor("_EmissionColor", val3 * 2f); val.SetPropertyBlock(val2); } } } internal void HitEnemy(GasolineProjectile projectile, Collider other, EnemyIdentifier enemy) { if (!hit && !((Object)(object)projectile == (Object)null) && !((Object)(object)other == (Object)null) && !((Object)(object)enemy == (Object)null)) { hit = true; GelSystem.AddCoverage(enemy); Object.Destroy((Object)(object)((Component)this).gameObject); } } } internal sealed class GelCoverage : MonoBehaviour { internal float Amount; internal void ApplyVisual() { SetOiledAmount(Amount); } private void OnDestroy() { SetOiledAmount(0f); } private void SetOiledAmount(float amount) { //IL_0047: Unknown result type (might be due to invalid IL or missing references) //IL_004e: Expected O, but got Unknown EnemyIdentifier component = ((Component)this).GetComponent(); Renderer[] componentsInChildren = ((Component)this).GetComponentsInChildren(true); foreach (Renderer val in componentsInChildren) { if (!((Object)(object)val == (Object)null) && !(val is ParticleSystemRenderer) && (!((Object)(object)component != (Object)null) || component.buffUnaffectedRenderers == null || !component.buffUnaffectedRenderers.Contains(val))) { MaterialPropertyBlock val2 = new MaterialPropertyBlock(); val.GetPropertyBlock(val2); val2.SetFloat("_OiledAmount", Mathf.Clamp01(amount)); val.SetPropertyBlock(val2); } } } } internal sealed class GelStainMarker : MonoBehaviour { internal Collider Surface; internal float Radius; internal bool EnemyVisual; } internal static class GelSystem { private static readonly List stains = new List(); private static readonly HashSet stuckGrenades = new HashSet(); internal static void AddCoverage(EnemyIdentifier enemy) { if (!((Object)(object)enemy == (Object)null)) { GelCoverage gelCoverage = ((Component)enemy).GetComponent(); if ((Object)(object)gelCoverage == (Object)null) { gelCoverage = ((Component)enemy).gameObject.AddComponent(); } gelCoverage.Amount = Mathf.Clamp01(gelCoverage.Amount + PluginSettings.GelCoveragePerDroplet); gelCoverage.ApplyVisual(); } } internal static void PrepareAndRegisterStain(GelStainMarker marker) { //IL_00d3: Unknown result type (might be due to invalid IL or missing references) //IL_00da: Expected O, but got Unknown //IL_00e9: Unknown result type (might be due to invalid IL or missing references) //IL_00f6: Unknown result type (might be due to invalid IL or missing references) //IL_0103: Unknown result type (might be due to invalid IL or missing references) //IL_0110: 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_0072: Unknown result type (might be due to invalid IL or missing references) //IL_008d: 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_00c3: 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)marker == (Object)null) { return; } Color val = default(Color); ((Color)(ref val))..ctor(0.05f, 0.4f, 1f, 1f); Renderer[] componentsInChildren = ((Component)marker).GetComponentsInChildren(true); foreach (Renderer val2 in componentsInChildren) { if ((Object)(object)val2 == (Object)null) { continue; } val2.enabled = true; Material material = val2.material; if ((Object)(object)material != (Object)null) { if (material.HasProperty("_Color")) { material.SetColor("_Color", val); } if (material.HasProperty("_BaseColor")) { material.SetColor("_BaseColor", val); } if (material.HasProperty("_TintColor")) { material.SetColor("_TintColor", val); } if (material.HasProperty("_EmissionColor")) { material.SetColor("_EmissionColor", val * 1.25f); } } MaterialPropertyBlock val3 = new MaterialPropertyBlock(); val2.GetPropertyBlock(val3); val3.SetColor("_Color", val); val3.SetColor("_BaseColor", val); val3.SetColor("_TintColor", val); val3.SetColor("_EmissionColor", val * 1.25f); val2.SetPropertyBlock(val3); } stains.Add(marker); } internal static bool TryGetStickTarget(Collider surface, EnemyIdentifier enemy, Vector3 point, out GelStainMarker stain, out GelCoverage coverage) { //IL_003b: Unknown result type (might be due to invalid IL or missing references) stain = null; coverage = null; if ((Object)(object)enemy != (Object)null) { coverage = ((Component)enemy).GetComponent(); if ((Object)(object)coverage != (Object)null) { return coverage.Amount >= PluginSettings.GelCoverageRequired; } return false; } stain = FindStain(surface, point); return (Object)(object)stain != (Object)null; } internal static GelStainMarker FindStain(Collider surface, Vector3 point) { //IL_00ad: 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) stains.RemoveAll((GelStainMarker stain) => (Object)(object)stain == (Object)null); foreach (GelStainMarker stain in stains) { if (!stain.EnemyVisual && !((Object)(object)stain.Surface == (Object)null) && ((Object)(object)surface == (Object)(object)stain.Surface || (Object)(object)((Component)surface).transform == (Object)(object)((Component)stain.Surface).transform || ((Object)(object)surface.attachedRigidbody != (Object)null && (Object)(object)stain.Surface.attachedRigidbody == (Object)(object)surface.attachedRigidbody)) && Vector3.Distance(point, ((Component)stain).transform.position) <= stain.Radius + 0.3f) { return stain; } } return null; } internal static void Consume(GelStainMarker stain, GelCoverage coverage, Vector3 origin, float visibleRadius) { //IL_0080: Unknown result type (might be due to invalid IL or missing references) //IL_0087: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)stain != (Object)null) { stains.RemoveAll((GelStainMarker candidate) => (Object)(object)candidate == (Object)null); float num = Mathf.Max(stain.Radius + 0.3f, visibleRadius); GelStainMarker[] array = stains.ToArray(); foreach (GelStainMarker gelStainMarker in array) { if (!((Object)(object)gelStainMarker == (Object)null) && !gelStainMarker.EnemyVisual && SameSurface(gelStainMarker.Surface, stain.Surface) && !(Vector3.Distance(origin, ((Component)gelStainMarker).transform.position) > num + gelStainMarker.Radius)) { stains.Remove(gelStainMarker); Object.Destroy((Object)(object)((Component)gelStainMarker).gameObject); } } } if ((Object)(object)coverage != (Object)null) { Object.Destroy((Object)(object)coverage); } } private static bool SameSurface(Collider first, Collider second) { if ((Object)(object)first == (Object)null || (Object)(object)second == (Object)null) { return false; } if (!((Object)(object)first == (Object)(object)second) && !((Object)(object)((Component)first).transform == (Object)(object)((Component)second).transform)) { if ((Object)(object)first.attachedRigidbody != (Object)null) { return (Object)(object)first.attachedRigidbody == (Object)(object)second.attachedRigidbody; } return false; } return true; } internal static void RegisterStuck(GrenadeLauncherProjectile projectile) { if ((Object)(object)projectile != (Object)null) { stuckGrenades.Add(projectile); } } internal static void UnregisterStuck(GrenadeLauncherProjectile projectile) { if ((Object)(object)projectile != (Object)null) { stuckGrenades.Remove(projectile); } } internal static void TriggerChain(Vector3 origin, GrenadeLauncherProjectile source, float visibleRadius) { //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) float num = Mathf.Max(0f, visibleRadius * PluginSettings.StuckChainRadiusMultiplier); if (num <= 0f) { return; } float num2 = Mathf.Max(1f, PluginSettings.StuckChainPropagationSpeed); GrenadeLauncherProjectile[] array = new GrenadeLauncherProjectile[stuckGrenades.Count]; stuckGrenades.CopyTo(array); GrenadeLauncherProjectile[] array2 = array; foreach (GrenadeLauncherProjectile grenadeLauncherProjectile in array2) { if (!((Object)(object)grenadeLauncherProjectile == (Object)null) && !((Object)(object)grenadeLauncherProjectile == (Object)(object)source) && grenadeLauncherProjectile.IsStuck) { float num3 = Vector3.Distance(origin, ((Component)grenadeLauncherProjectile).transform.position); if (num3 <= num) { grenadeLauncherProjectile.ScheduleChainDetonation(num3 / num2, source.ChainGroupId); } } } } internal static void Cleanup() { GrenadeLauncherProjectile[] array = new GrenadeLauncherProjectile[stuckGrenades.Count]; stuckGrenades.CopyTo(array); GrenadeLauncherProjectile[] array2 = array; foreach (GrenadeLauncherProjectile grenadeLauncherProjectile in array2) { if ((Object)(object)grenadeLauncherProjectile != (Object)null) { Object.Destroy((Object)(object)((Component)grenadeLauncherProjectile).gameObject); } } foreach (GelStainMarker stain in stains) { if ((Object)(object)stain != (Object)null) { Object.Destroy((Object)(object)((Component)stain).gameObject); } } GelCoverage[] array3 = Object.FindObjectsOfType(); foreach (GelCoverage gelCoverage in array3) { if ((Object)(object)gelCoverage != (Object)null) { Object.Destroy((Object)(object)gelCoverage); } } stains.Clear(); stuckGrenades.Clear(); } } internal static class StuckDetonationContext { private static readonly Stack beams = new Stack(); internal static RevolverBeam Current { get { if (beams.Count <= 0) { return null; } return beams.Peek(); } } internal static bool CanCurrentBeamDetonate { get { //IL_0012: 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_0022: Invalid comparison between Unknown and I4 RevolverBeam current = Current; if ((Object)(object)current == (Object)null) { return false; } if ((int)current.beamType == 0) { return true; } if ((int)current.beamType != 1) { return false; } Railcannon val = (((Object)(object)current.sourceWeapon != (Object)null) ? current.sourceWeapon.GetComponentInParent() : null); if ((Object)(object)val != (Object)null) { return val.variation != 1; } return false; } } internal static void Enter(RevolverBeam beam) { beams.Push(beam); } internal static void Exit() { if (beams.Count > 0) { beams.Pop(); } } } [HarmonyPatch(typeof(RevolverBeam), "ExecuteHits")] internal static class StuckBeamContextPatch { private static void Prefix(RevolverBeam __instance) { StuckDetonationContext.Enter(__instance); } private static Exception Finalizer(Exception __exception) { StuckDetonationContext.Exit(); return __exception; } } [HarmonyPatch(typeof(Coin), "ExplosiveReflectCheck")] internal static class StuckGrenadeCoinTargetPatch { private static bool Prefix(TargetDataRef data, ref bool __result) { //IL_0000: 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) GameObject val = ((data.target != null) ? data.target.GameObject : null); GrenadeLauncherProjectile grenadeLauncherProjectile = (((Object)(object)val != (Object)null) ? val.GetComponentInParent() : null); if ((Object)(object)grenadeLauncherProjectile == (Object)null || !grenadeLauncherProjectile.IsStuck) { return true; } __result = false; return false; } } internal static class BlueSphereVisualFactory { internal static GameObject Create(Vector3 position, float size) { //IL_0017: 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_0033: Unknown result type (might be due to invalid IL or missing references) //IL_010b: 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_0081: Expected O, but got Unknown //IL_009b: Unknown result type (might be due to invalid IL or missing references) //IL_00e1: Unknown result type (might be due to invalid IL or missing references) //IL_00eb: Unknown result type (might be due to invalid IL or missing references) GameObject obj = GameObject.CreatePrimitive((PrimitiveType)0); ((Object)obj).name = "Grenade Launcher Generated Blue Sphere"; obj.transform.position = position; obj.transform.localScale = Vector3.one * Mathf.Max(0.25f, size); Renderer component = obj.GetComponent(); Shader val = Shader.Find("Standard") ?? Shader.Find("Unlit/Color"); if ((Object)(object)component != (Object)null && (Object)(object)val != (Object)null) { component.material = new Material(val); component.material.color = new Color(0.05f, 0.45f, 1f, 1f); if (component.material.HasProperty("_EmissionColor")) { component.material.EnableKeyword("_EMISSION"); component.material.SetColor("_EmissionColor", new Color(0f, 0.2f, 1f) * 2f); } } Light obj2 = obj.AddComponent(); obj2.color = new Color(0.05f, 0.4f, 1f); obj2.range = 10f; obj2.intensity = 2.5f; return obj; } } internal sealed class BlueHookDeliveryProjectile : MonoBehaviour { private const float TravelDuration = 0.25f; internal Grenade Grenade; internal Vector3 Target; private Vector3 start; private float startedAt; private bool launched; private bool completed; internal void Launch() { //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_006b: 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_01b3: Unknown result type (might be due to invalid IL or missing references) if (launched || (Object)(object)Grenade == (Object)null) { return; } launched = true; start = ((Component)this).transform.position; startedAt = Time.time; Rigidbody val = (((Object)(object)Grenade.rb != (Object)null) ? Grenade.rb : ((Component)this).GetComponent()); if ((Object)(object)val != (Object)null) { val.velocity = Vector3.zero; val.angularVelocity = Vector3.zero; val.useGravity = false; PhysicsExtensions.SetGravityMode(val, false); val.isKinematic = true; } CustomGravity[] components = ((Component)this).GetComponents(); foreach (CustomGravity val2 in components) { if ((Object)(object)val2 != (Object)null) { val2.useGravity = false; } } Collider[] componentsInChildren = ((Component)this).GetComponentsInChildren(true); foreach (Collider val3 in componentsInChildren) { if ((Object)(object)val3 != (Object)null) { val3.enabled = false; } } Renderer[] componentsInChildren2 = ((Component)this).GetComponentsInChildren(true); foreach (Renderer val4 in componentsInChildren2) { if ((Object)(object)val4 != (Object)null) { val4.enabled = false; } } TrailRenderer[] componentsInChildren3 = ((Component)this).GetComponentsInChildren(true); foreach (TrailRenderer val5 in componentsInChildren3) { if ((Object)(object)val5 != (Object)null) { ((Renderer)val5).enabled = false; } } ParticleSystem[] componentsInChildren4 = ((Component)this).GetComponentsInChildren(true); foreach (ParticleSystem val6 in componentsInChildren4) { if ((Object)(object)val6 != (Object)null) { val6.Stop(true, (ParticleSystemStopBehavior)0); } } Light[] componentsInChildren5 = ((Component)this).GetComponentsInChildren(true); foreach (Light val7 in componentsInChildren5) { if ((Object)(object)val7 != (Object)null) { ((Behaviour)val7).enabled = false; } } GameObject obj = BlueSphereVisualFactory.Create(start, PluginSettings.BluePointSize); Collider component = obj.GetComponent(); if ((Object)(object)component != (Object)null) { component.enabled = false; Object.Destroy((Object)(object)component); } obj.transform.SetParent(((Component)this).transform, true); } private void Update() { //IL_0030: 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) //IL_003c: 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) if (launched && !completed) { float num = Mathf.Clamp01((Time.time - startedAt) / 0.25f); ((Component)this).transform.position = Vector3.Lerp(start, Target, num); if (!(num < 1f)) { completed = true; HookPointManager.CompleteDelivery(Target); Object.Destroy((Object)(object)((Component)this).gameObject); } } } } internal static class HookPointManager { private const string SlingshotAddress = "Assets/Prefabs/Levels/Interactive/GrapplePointSlingshot Variant.prefab"; private const string DeleteEffectAddress = "Assets/Particles/SandboxDeleterEffect.prefab"; private const string SandboxArmAddress = "Assets/Prefabs/Weapons/Special/Spawner Arm.prefab"; private static GameObject current; private static GameObject slingshotPrefab; private static GameObject deleteEffectPrefab; private static AudioClip deleteSound; private static bool loggedMissingPrefab; private static bool creationLockedUntilGround; private static bool currentHookUsed; private static HookPoint currentHook; private static HookArm currentArm; private static float nextArmLookupAt; private static float nextHookStateCheckAt; private static readonly FieldInfo CaughtHookField = AccessTools.Field(typeof(HookArm), "caughtHook"); internal static bool TryGetDeliveryTarget(out Vector3 point) { //IL_0001: Unknown result type (might be due to invalid IL or missing references) //IL_0006: Unknown result type (might be due to invalid IL or missing references) //IL_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_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_0053: Unknown result type (might be due to invalid IL or missing references) //IL_0054: Unknown result type (might be due to invalid IL or missing references) //IL_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_0060: 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_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_00a4: 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_0084: Unknown result type (might be due to invalid IL or missing references) //IL_008b: Unknown result type (might be due to invalid IL or missing references) //IL_0095: Unknown result type (might be due to invalid IL or missing references) //IL_009a: Unknown result type (might be due to invalid IL or missing references) //IL_009f: Unknown result type (might be due to invalid IL or missing references) point = Vector3.zero; UpdateUsageLock(); if (creationLockedUntilGround) { return false; } CameraController instance = MonoSingleton.Instance; if ((Object)(object)instance == (Object)null) { return false; } Vector3 position = ((Component)instance).transform.position; Vector3 forward = ((Component)instance).transform.forward; float num = Mathf.Max(5.5f, PluginSettings.BlueDistance); point = position + forward * num; int num2 = LayerMask.op_Implicit(LayerMaskDefaults.Get((LMD)1)); RaycastHit val = default(RaycastHit); if (Physics.Raycast(position, forward, ref val, num, num2, (QueryTriggerInteraction)1)) { point = ((RaycastHit)(ref val)).point + ((RaycastHit)(ref val)).normal * 0.25f; } if (Vector3.Distance(position, point) < 5.5f) { return false; } if ((Object)(object)ResolveSlingshotPrefab() == (Object)null) { if (!loggedMissingPrefab) { loggedMissingPrefab = true; ManualLogSource logSource = Plugin.LogSource; if (logSource != null) { logSource.LogError((object)"Could not find ULTRAKILL's blue slingshot HookPoint prefab in the loaded spawnable database."); } } return false; } return true; } internal static void UpdateUsageLock() { NewMovement instance = MonoSingleton.Instance; if ((Object)(object)current == (Object)null) { creationLockedUntilGround = false; currentHookUsed = false; currentHook = null; currentArm = null; } else if (currentHookUsed) { if (creationLockedUntilGround && (Object)(object)instance != (Object)null && (Object)(object)instance.gc != (Object)null && instance.gc.onGround) { creationLockedUntilGround = false; } } else if (!(Time.unscaledTime < nextHookStateCheckAt)) { nextHookStateCheckAt = Time.unscaledTime + 0.05f; if ((Object)(object)currentHook == (Object)null) { currentHook = current.GetComponentInChildren(true); } if ((Object)(object)currentArm == (Object)null && Time.unscaledTime >= nextArmLookupAt) { nextArmLookupAt = Time.unscaledTime + 0.5f; currentArm = Object.FindObjectOfType(); } if ((Object)(object)currentHook != (Object)null && (Object)(object)currentArm != (Object)null && CaughtHookField != null && CaughtHookField.GetValue(currentArm) == currentHook) { currentHookUsed = true; creationLockedUntilGround = (Object)(object)instance == (Object)null || (Object)(object)instance.gc == (Object)null || !instance.gc.onGround; } } } internal static void CompleteDelivery(Vector3 point) { //IL_0000: 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_0051: 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_00b2: Unknown result type (might be due to invalid IL or missing references) PlayDeleteEffect(point); GameObject val = ResolveSlingshotPrefab(); if ((Object)(object)val == (Object)null) { return; } Cleanup(); current = Object.Instantiate(val, point, Quaternion.identity); ((Object)current).name = "Grenade Launcher Blue Slingshot Point"; current.AddComponent(); Transform transform = current.transform; transform.localScale *= Mathf.Max(0.25f, PluginSettings.BluePointSize); HookPoint componentInChildren = current.GetComponentInChildren(true); if ((Object)(object)componentInChildren == (Object)null) { Object.Destroy((Object)(object)current); current = null; ManualLogSource logSource = Plugin.LogSource; if (logSource != null) { logSource.LogError((object)"The resolved blue hook-point prefab did not contain a HookPoint component."); } } else { componentInChildren.active = true; componentInChildren.type = (hookPointType)1; componentInChildren.slingShotForce += PluginSettings.BlueSlingshotForce; componentInChildren.healPlayer = false; componentInChildren.Activate(); currentHook = componentInChildren; currentArm = Object.FindObjectOfType(); nextArmLookupAt = Time.unscaledTime + 0.5f; nextHookStateCheckAt = Time.unscaledTime; currentHookUsed = false; creationLockedUntilGround = false; } } private static void PlayDeleteEffect(Vector3 point) { //IL_0012: 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) //IL_0036: 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_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_00c1: Unknown result type (might be due to invalid IL or missing references) //IL_00c8: Expected O, but got Unknown //IL_00fe: Unknown result type (might be due to invalid IL or missing references) //IL_00eb: Unknown result type (might be due to invalid IL or missing references) try { if ((Object)(object)deleteEffectPrefab == (Object)null) { deleteEffectPrefab = Addressables.LoadAssetAsync((object)"Assets/Particles/SandboxDeleterEffect.prefab").WaitForCompletion(); } if ((Object)(object)deleteEffectPrefab != (Object)null) { Object.Destroy((Object)(object)Object.Instantiate(deleteEffectPrefab, point, Quaternion.identity), 5f); } if ((Object)(object)deleteSound == (Object)null) { GameObject val = Addressables.LoadAssetAsync((object)"Assets/Prefabs/Weapons/Special/Spawner Arm.prefab").WaitForCompletion(); SandboxArm val2 = (((Object)(object)val != (Object)null) ? val.GetComponentInChildren(true) : null); if ((Object)(object)val2 != (Object)null && (Object)(object)val2.destroySound != (Object)null) { deleteSound = val2.destroySound.clip; } } if ((Object)(object)deleteSound != (Object)null) { CameraController instance = MonoSingleton.Instance; GameObject val3 = new GameObject("Grenade Launcher Sandbox Delete Sound"); if ((Object)(object)instance != (Object)null) { val3.transform.SetParent(((Component)instance).transform, false); val3.transform.localPosition = Vector3.zero; } else { val3.transform.position = point; } AudioSource obj = val3.AddComponent(); obj.clip = deleteSound; obj.volume = 0.5f; obj.spatialBlend = 0f; obj.playOnAwake = false; obj.loop = false; obj.Play(); Object.Destroy((Object)(object)val3, Mathf.Max(0.1f, deleteSound.length + 0.1f)); } } catch (Exception ex) { ManualLogSource logSource = Plugin.LogSource; if (logSource != null) { logSource.LogWarning((object)("Could not play the sandbox deletion effect: " + ex.Message)); } } } private static GameObject ResolveSlingshotPrefab() { //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) if ((Object)(object)slingshotPrefab != (Object)null) { return slingshotPrefab; } try { slingshotPrefab = Addressables.LoadAssetAsync((object)"Assets/Prefabs/Levels/Interactive/GrapplePointSlingshot Variant.prefab").WaitForCompletion(); if ((Object)(object)slingshotPrefab != (Object)null) { return slingshotPrefab; } } catch (Exception ex) { ManualLogSource logSource = Plugin.LogSource; if (logSource != null) { logSource.LogWarning((object)("Could not load the blue HookPoint addressable: " + ex.Message)); } } HookPoint val = ((IEnumerable)Resources.FindObjectsOfTypeAll()).FirstOrDefault((Func)((HookPoint point) => (Object)(object)point != (Object)null && (int)point.type == 1 && (Object)(object)((Component)point).GetComponentInParent() == (Object)null)); if ((Object)(object)val != (Object)null) { slingshotPrefab = ((Component)val).gameObject; } return slingshotPrefab; } internal static void Cleanup() { if ((Object)(object)current != (Object)null) { HookPoint componentInChildren = current.GetComponentInChildren(true); HookArm val = Object.FindObjectOfType(); FieldInfo fieldInfo = AccessTools.Field(typeof(HookArm), "caughtHook"); if ((Object)(object)val != (Object)null && (Object)(object)componentInChildren != (Object)null && fieldInfo != null && fieldInfo.GetValue(val) == componentInChildren) { try { AccessTools.Method(typeof(HookArm), "StopThrow", (Type[])null, (Type[])null)?.Invoke(val, new object[2] { 0f, false }); } catch (Exception ex) { ManualLogSource logSource = Plugin.LogSource; if (logSource != null) { logSource.LogWarning((object)("Could not release the old generated hook point cleanly: " + ex.Message)); } } } Object.Destroy((Object)(object)current); } current = null; creationLockedUntilGround = false; currentHookUsed = false; currentHook = null; currentArm = null; nextArmLookupAt = 0f; nextHookStateCheckAt = 0f; } } internal sealed class GeneratedBlueHookOwnership : MonoBehaviour { } [HarmonyPatch(typeof(NewMovement), "Respawn")] internal static class GrenadeLauncherRespawnCooldownPatch { private static void Postfix() { AlternateFireController.Reset(); } } internal sealed class AlternateFireRuntime : MonoBehaviour { private bool lastGrenadeMode; private void OnEnable() { SceneManager.sceneLoaded += OnSceneLoaded; lastGrenadeMode = (Object)(object)Plugin.Instance != (Object)null && Plugin.Instance.AnyGrenadeModeEnabled; } private void OnDisable() { SceneManager.sceneLoaded -= OnSceneLoaded; } private void Update() { HookPointManager.UpdateUsageLock(); bool flag = (Object)(object)Plugin.Instance != (Object)null && Plugin.Instance.AnyGrenadeModeEnabled; if (lastGrenadeMode && !flag) { CleanupAll(); } lastGrenadeMode = flag; } private void OnSceneLoaded(Scene scene, LoadSceneMode mode) { CleanupAll(); } internal static void CleanupAll() { HookPointManager.Cleanup(); GelSystem.Cleanup(); AlternateFireController.Reset(); AlternateFireInputContext.Depth = 0; AlternateFireInputContext.SuppressedAction = null; GelSpawnContext.Depth = 0; GelStainSpawnContext.Reset(); BlueHookDeliveryContext.Reset(); GrenadeStyleAwards.ResetWalkingBombChains(); BlueHookDeliveryProjectile[] array = Object.FindObjectsOfType(); foreach (BlueHookDeliveryProjectile blueHookDeliveryProjectile in array) { if ((Object)(object)blueHookDeliveryProjectile != (Object)null) { Object.Destroy((Object)(object)((Component)blueHookDeliveryProjectile).gameObject); } } } } }