Decompiled source of Grenade Launcher v2.0.1
BepInEx\plugins\DocValentyne-GrenadeLauncher\GrenadeLauncher.dll
Decompiled 2 weeks ago
The result has been truncated due to the large size, download it to view full contents!
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.Logging; using HarmonyLib; using Microsoft.CodeAnalysis; using PluginConfig.API; using PluginConfig.API.Decorators; using PluginConfig.API.Fields; using PluginConfig.API.Functionals; 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("2.0.1.0")] [assembly: AssemblyInformationalVersion("2.0.1+3b87a19006529226179cb616ee205c962c6b369c")] [assembly: AssemblyProduct("GrenadeLauncher")] [assembly: AssemblyTitle("GrenadeLauncher")] [assembly: AssemblyVersion("2.0.1.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", "2.0.1")] [BepInDependency(/*Could not decode attribute arguments.*/)] [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 = "2.0.1"; private GrenadeLauncherState state; private Harmony harmony; private GameObject runtimeHost; internal static Plugin Instance { get; private set; } internal static ManualLogSource LogSource { get; private set; } internal GrenadeLauncherState State => state; internal bool AnyGrenadeModeEnabled { get { int slot = Math.Max(0, GameProgressSaver.currentSlot); SlotLoadoutState slotState = GetSlotState(slot); if (!slotState.Migrated) { return slotState.LegacyEnabled; } if (!slotState.GetVariant(0) && !slotState.GetVariant(1)) { return slotState.GetVariant(2); } return true; } } internal bool IsGrenadeModeEnabled(int variation) { if (variation < 0 || variation > 2) { return false; } int slot = Math.Max(0, GameProgressSaver.currentSlot); SlotLoadoutState slotState = GetSlotState(slot); if (!slotState.Migrated) { return slotState.LegacyEnabled; } return slotState.GetVariant(variation); } 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(); GetSlotState(slot).SetVariant(variation, enabled); state.Save(); } } internal void EnsureVariantMigration() { int slot = Math.Max(0, GameProgressSaver.currentSlot); SlotLoadoutState slotState = GetSlotState(slot); if (!slotState.Migrated) { bool legacyEnabled = slotState.LegacyEnabled; for (int i = 0; i < 3; i++) { slotState.SetVariant(i, legacyEnabled); } slotState.Migrated = true; state.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_0032: Unknown result type (might be due to invalid IL or missing references) //IL_003c: Expected O, but got Unknown //IL_005c: Unknown result type (might be due to invalid IL or missing references) //IL_0066: Expected O, but got Unknown Instance = this; LogSource = ((BaseUnityPlugin)this).Logger; state = GrenadeLauncherState.Load(((BaseUnityPlugin)this).Config.ConfigFilePath); 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<TerminalIntegration>(); runtimeHost.AddComponent<AlternateFireRuntime>(); runtimeHost.AddComponent<WeaponVisualRuntime>(); ((BaseUnityPlugin)this).Logger.LogInfo((object)"Grenade Launcher v2.0.1 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 SlotLoadoutState GetSlotState(int slot) { return state.GetSlot(Math.Max(0, slot)); } } [Serializable] internal sealed class SlotLoadoutState { public int Slot; public bool LegacyEnabled; public bool Migrated; public bool Blue; public bool Green; public bool Red; internal bool GetVariant(int variation) { return variation switch { 1 => Green, 0 => Blue, _ => Red, }; } internal void SetVariant(int variation, bool value) { switch (variation) { case 0: Blue = value; break; case 1: Green = value; break; case 2: Red = value; break; } } } [Serializable] internal sealed class GrenadeLauncherState { public int BalanceDefaultsVersion; public int VisualCalibrationDefaultsVersion; public List<SlotLoadoutState> Slots = new List<SlotLoadoutState>(); [NonSerialized] private string statePath; internal static GrenadeLauncherState Load(string oldConfigPath) { string path = Path.Combine(Path.GetDirectoryName(oldConfigPath) ?? Paths.ConfigPath, "docvalentyne.ultrakill.grenadelauncher.state.json"); GrenadeLauncherState grenadeLauncherState = null; try { if (File.Exists(path)) { grenadeLauncherState = JsonUtility.FromJson<GrenadeLauncherState>(File.ReadAllText(path)); } } catch (Exception ex) { ManualLogSource logSource = Plugin.LogSource; if (logSource != null) { logSource.LogWarning((object)("Could not read Grenade Launcher internal state: " + ex.Message)); } } if (grenadeLauncherState == null) { grenadeLauncherState = new GrenadeLauncherState(); grenadeLauncherState.ImportOldConfig(oldConfigPath); } grenadeLauncherState.statePath = path; grenadeLauncherState.Save(); return grenadeLauncherState; } internal SlotLoadoutState GetSlot(int slot) { SlotLoadoutState slotLoadoutState = Slots.FirstOrDefault((SlotLoadoutState item) => item != null && item.Slot == slot); if (slotLoadoutState != null) { return slotLoadoutState; } slotLoadoutState = new SlotLoadoutState { Slot = slot }; Slots.Add(slotLoadoutState); return slotLoadoutState; } internal void Save() { if (string.IsNullOrEmpty(statePath)) { return; } try { File.WriteAllText(statePath, JsonUtility.ToJson((object)this, true)); } catch (Exception ex) { ManualLogSource logSource = Plugin.LogSource; if (logSource != null) { logSource.LogWarning((object)("Could not save Grenade Launcher internal state: " + ex.Message)); } } } private void ImportOldConfig(string oldConfigPath) { if (!File.Exists(oldConfigPath)) { return; } try { string text = string.Empty; string[] array = File.ReadAllLines(oldConfigPath); for (int i = 0; i < array.Length; i++) { string text2 = array[i].Trim(); if (text2.StartsWith("[") && text2.EndsWith("]")) { text = text2.Substring(1, text2.Length - 2); } else { if (text != "Loadout" || !text2.Contains("=")) { continue; } string[] array2 = text2.Split(new char[1] { '=' }, 2); string text3 = array2[0].Trim(); if (!bool.TryParse(array2[1].Trim(), out var result) || !text3.StartsWith("SaveSlot")) { continue; } int length = "SaveSlot".Length; int num = text3.IndexOfAny(new char[3] { 'U', 'R', 'P' }, length); if (num <= length || !int.TryParse(text3.Substring(length, num - length), out var result2)) { continue; } SlotLoadoutState slot = GetSlot(result2); if (text3.EndsWith("UsesGrenadeLauncher")) { if (text3.Contains("RocketVariant0")) { slot.Blue = result; } else if (text3.Contains("RocketVariant1")) { slot.Green = result; } else if (text3.Contains("RocketVariant2")) { slot.Red = result; } else { slot.LegacyEnabled = result; } } else if (text3.EndsWith("PerVariantLoadoutMigrated")) { slot.Migrated = result; } } } } catch (Exception ex) { ManualLogSource logSource = Plugin.LogSource; if (logSource != null) { logSource.LogWarning((object)("Could not migrate old Grenade Launcher loadout config: " + ex.Message)); } } } } [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, RedBurst, 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 RocketCooldownSync { private const float EquipDrawDelay = 0.25f; private static readonly FieldRef<RocketLauncher, float> Cooldown = AccessTools.FieldRefAccess<RocketLauncher, float>("cooldown"); private static float standardReadyAt; private static float grenadeReadyAt; internal static bool Ready(RocketLauncher launcher) { if (!CooldownRules.NoWeaponCooldown && !((Object)(object)launcher == (Object)null)) { return Cooldown.Invoke(launcher) <= 0f; } return true; } internal static void ApplyAfterShot(RocketLauncher firedLauncher, bool grenadeShot) { if (CooldownRules.NoWeaponCooldown) { Reset(); return; } float num = Mathf.Max(0f, PluginSettings.FireInterval); grenadeReadyAt = Time.time + num; standardReadyAt = Time.time + (grenadeShot ? num : Mathf.Max(0f, ((Object)(object)firedLauncher != (Object)null) ? firedLauncher.rateOfFire : 1f)); } internal static void ApplyWhenEquipped(RocketLauncher launcher) { if (!((Object)(object)launcher == (Object)null)) { if (CooldownRules.NoWeaponCooldown) { Reset(); Cooldown.Invoke(launcher) = 0f; } else { float num = (((Object)(object)Plugin.Instance != (Object)null && Plugin.Instance.IsGrenadeModeEnabled(launcher)) ? grenadeReadyAt : standardReadyAt); Cooldown.Invoke(launcher) = Mathf.Max(0.25f, num - Time.time); } } } internal static void Reset() { standardReadyAt = 0f; grenadeReadyAt = 0f; } } internal static class CooldownRules { internal static bool NoWeaponCooldown => NoWeaponCooldown.NoCooldown; } [HarmonyPatch(typeof(RocketLauncher), "OnEnable")] internal static class RocketLauncherEquipCooldownPatch { [HarmonyPriority(0)] private static void Postfix(RocketLauncher __instance) { RocketCooldownSync.ApplyWhenEquipped(__instance); WeaponVisualRuntime.RegisterLauncher(__instance); } } [HarmonyPatch(typeof(RocketLauncher), "Shoot")] internal static class RocketLauncherShootPatch { private struct State { internal bool Active; internal bool EnteredContext; internal bool DualWieldDuplicate; internal bool NotifyGreenPrimary; internal bool NotifyBluePrimary; internal GrenadeProjectileProfile ProjectileProfile; internal float RateOfFire; internal AudioSource VanillaShotAudio; internal bool VanillaShotAudioMuted; internal bool VanillaShotAudioOriginalMute; } private static readonly FieldRef<RocketLauncher, WeaponIdentifier> WeaponId = AccessTools.FieldRefAccess<RocketLauncher, WeaponIdentifier>("wid"); private static bool Prefix(RocketLauncher __instance, out State __state) { bool active = (Object)(object)Plugin.Instance != (Object)null && Plugin.Instance.IsGrenadeModeEnabled(__instance); WeaponIdentifier val = WeaponId.Invoke(__instance); bool dualWieldDuplicate = (Object)(object)val != (Object)null && val.duplicate; __state = new State { Active = active, DualWieldDuplicate = dualWieldDuplicate, ProjectileProfile = (GrenadeSpawnContext.Active ? GrenadeSpawnContext.Profile : GrenadeProjectileProfile.Primary), RateOfFire = __instance.rateOfFire }; if (!__state.Active) { return true; } if (WeaponVisualRuntime.ShouldReplaceVanillaShotFeedback(__instance)) { __state.VanillaShotAudio = WeaponVisualRuntime.GetVanillaShotAudio(__instance); if ((Object)(object)__state.VanillaShotAudio != (Object)null) { __state.VanillaShotAudioOriginalMute = __state.VanillaShotAudio.mute; __state.VanillaShotAudio.mute = true; __state.VanillaShotAudioMuted = 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 (__state.VanillaShotAudioMuted && (Object)(object)__state.VanillaShotAudio != (Object)null) { __state.VanillaShotAudio.Stop(); __state.VanillaShotAudio.mute = __state.VanillaShotAudioOriginalMute; } if (__exception == null && !__state.DualWieldDuplicate) { RocketCooldownSync.ApplyAfterShot(__instance, __state.Active); } if (__exception == null && __state.Active) { WeaponVisualRuntime.NotifyShot(__instance, __state.ProjectileProfile); } 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(RocketLauncher), "Clunk")] internal static class GrenadeLauncherClunkPatch { private static bool Prefix(RocketLauncher __instance) { return !WeaponVisualRuntime.ShouldReplaceVanillaShotFeedback(__instance); } } [HarmonyPatch(typeof(Grenade), "GrenadeBeam")] internal static class GrenadeLauncherJackhammerGrenadeBeamTagPatch { private struct State { internal bool Tagged; internal string OriginalHitter; } private const string TagPrefix = "grenadelauncher-jackhammer|"; private static void Prefix(Grenade __instance, GameObject newSourceWeapon, out State __state) { __state = default(State); if (!((Object)(object)__instance == (Object)null) && !((Object)(object)((Component)__instance).GetComponent<GrenadeLauncherProjectile>() == (Object)null) && !((Object)(object)newSourceWeapon == (Object)null) && !((Object)(object)newSourceWeapon.GetComponentInParent<ShotgunHammer>() == (Object)null)) { __state.Tagged = true; __state.OriginalHitter = __instance.hitterWeapon; __instance.hitterWeapon = "grenadelauncher-jackhammer|" + (__state.OriginalHitter ?? string.Empty); } } private static void Postfix(Grenade __instance, State __state) { if (__state.Tagged && (Object)(object)__instance != (Object)null) { __instance.hitterWeapon = __state.OriginalHitter; } } internal static bool TryApply(RevolverBeam beam) { if ((Object)(object)beam == (Object)null || string.IsNullOrEmpty(beam.hitterOverride) || !beam.hitterOverride.StartsWith("grenadelauncher-jackhammer|", StringComparison.Ordinal)) { return false; } beam.hitterOverride = beam.hitterOverride.Substring("grenadelauncher-jackhammer|".Length); int num = Mathf.RoundToInt(Mathf.Max(0f, PluginSettings.JackhammerGrenadeSelfDamage)); ((Component)beam).gameObject.AddComponent<GrenadeLauncherJackhammerBeamMarker>().SelfDamage = num; beam.damage = (float)num / 10f; beam.enemyDamageOverride = Mathf.Max(0f, PluginSettings.JackhammerGrenadeDamage); return true; } } internal sealed class GrenadeLauncherJackhammerBeamMarker : MonoBehaviour { internal int SelfDamage; } internal static class GrenadeLauncherJackhammerBeamDamageContext { private static readonly Stack<int> selfDamageStack = new Stack<int>(); private static float delayedExplosionOverrideEndsAt; internal static bool Active => selfDamageStack.Count > 0; internal static int SelfDamage { get { if (!Active) { return 0; } return selfDamageStack.Peek(); } } internal static bool IsDelayedExplosionOverrideActive => Time.time <= delayedExplosionOverrideEndsAt; internal static void StartDelayedExplosionOverride() { delayedExplosionOverrideEndsAt = Time.time + 2f; } internal static bool Enter(RevolverBeam beam) { GrenadeLauncherJackhammerBeamMarker grenadeLauncherJackhammerBeamMarker = (((Object)(object)beam != (Object)null) ? ((Component)beam).GetComponent<GrenadeLauncherJackhammerBeamMarker>() : null); if ((Object)(object)grenadeLauncherJackhammerBeamMarker == (Object)null) { return false; } selfDamageStack.Push(grenadeLauncherJackhammerBeamMarker.SelfDamage); StartDelayedExplosionOverride(); return true; } internal static void Exit(bool entered) { if (entered && selfDamageStack.Count > 0) { selfDamageStack.Pop(); } } } [HarmonyPatch(typeof(RevolverBeam), "Start")] internal static class GrenadeLauncherJackhammerGrenadeBeamDamagePatch { private static void Prefix(RevolverBeam __instance) { GrenadeLauncherJackhammerGrenadeBeamTagPatch.TryApply(__instance); } } [HarmonyPatch(typeof(RevolverBeam), "ExecuteHits")] internal static class GrenadeLauncherJackhammerBeamDamageContextPatch { private static void Prefix(RevolverBeam __instance, out bool __state) { __state = GrenadeLauncherJackhammerBeamDamageContext.Enter(__instance); } private static Exception Finalizer(bool __state, Exception __exception) { GrenadeLauncherJackhammerBeamDamageContext.Exit(__state); return __exception; } } [HarmonyPatch(typeof(NewMovement), "GetHurt")] internal static class GrenadeLauncherJackhammerSelfDamagePatch { [HarmonyPriority(0)] private static void Prefix(ref int damage) { if (GrenadeLauncherJackhammerBeamDamageContext.Active) { damage = GrenadeLauncherJackhammerBeamDamageContext.SelfDamage; } } } [HarmonyPatch(typeof(Explosion), "Collide")] internal static class GrenadeLauncherJackhammerDelayedExplosionDamagePatch { private static void Prefix(Explosion __instance, Collider other) { if (!((Object)(object)__instance == (Object)null) && !((Object)(object)other == (Object)null) && ((Component)other).CompareTag("Player")) { string text = (((Object)(object)__instance.sourceWeapon != (Object)null) ? ((Object)__instance.sourceWeapon).name : "<none>"); bool flag = __instance.rocketExplosion && text.StartsWith("Hammer Saw", StringComparison.Ordinal); if (GrenadeLauncherJackhammerBeamDamageContext.IsDelayedExplosionOverrideActive && flag) { int playerDamageOverride = Mathf.RoundToInt(Mathf.Max(0f, PluginSettings.JackhammerGrenadeSelfDamage)); __instance.playerDamageOverride = playerDamageOverride; } } } } [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<GrenadeLauncherProjectile>(); if ((Object)(object)component != (Object)null && !component.CanBeWhiplashed) { __result = null; } if ((Object)(object)__result != (Object)null && (Object)(object)((Component)__result).GetComponent<BlueHookDeliveryProjectile>() != (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<BlueHookDeliveryProjectile>() != (Object)null) { return false; } GrenadeLauncherProjectile component = ((Component)__instance).GetComponent<GrenadeLauncherProjectile>(); 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 ArcCustom = "Custom gravity"; private static StringListField arcPreset; private static FloatSliderField damage; private static FloatSliderField airshotDamage; private static FloatSliderField airshotExplosionSize; 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 stuckLifetime; 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 FloatSliderField jackhammerGrenadeDamage; private static FloatSliderField jackhammerGrenadeSelfDamage; private static Texture2D configuratorIconTexture; private static Sprite configuratorIconSprite; private static readonly Dictionary<EnemyType, FloatSliderField> enemyDamageMultipliers = new Dictionary<EnemyType, FloatSliderField>(); private static readonly Dictionary<EnemyType, float> releaseEnemyDamageDefaults = new Dictionary<EnemyType, float> { { (EnemyType)0, 100f }, { (EnemyType)33, 120f }, { (EnemyType)34, 100f }, { (EnemyType)2, 100f }, { (EnemyType)4, 100f }, { (EnemyType)31, 200f }, { (EnemyType)38, 175f }, { (EnemyType)14, 125f } }; internal static readonly bool EyeHeightScaling = true; internal const float FallbackEyeHeight = 2.9f; private static FloatSliderField greenCooldown; private static FloatSliderField greenSpeed; private static FloatSliderField greenUpwardVelocity; private static FloatSliderField greenGravity; private static FloatSliderField greenDirectDamage; private static FloatSliderField greenAirshotDamage; private static FloatSliderField greenSurfaceDamage; private static FloatSliderField greenDirectExplosionSize; private static FloatSliderField greenAirshotExplosionSize; 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 BoolField terrainStuckDetonatesOnEnemyWalkover; private static FloatSliderField gelEnemyFireRadius; private static FloatSliderField gelEnemyFireBaseDuration; private static FloatSliderField gelEnemyFireExtraDuration; private static FloatSliderField gelEnemyFireMaximumDuration; private static FloatSliderField redBurstDirectDamage; private static FloatSliderField redBurstTerrainDamage; private static FloatSliderField redBurstEnemyDamage; private static FloatSliderField redBurstAirshotDamage; private static FloatSliderField redBurstShotCount; private static FloatSliderField redBurstDuration; private static FloatSliderField redBurstCooldown; private static FloatSliderField redBurstKnockback; private static FloatSliderField blueDistance; private static FloatSliderField blueCooldown; private static FloatSliderField blueSlingshotForce; private static FloatSliderField bluePointSize; private static FloatSliderField blueReplacementDamage; private static FloatSliderField blueReplacementExplosionSize; private static FloatSliderField blueReplacementForce; private static FloatSliderField pinkArmingDelay; private static FloatSliderField pinkConductionArmingDelay; private static FloatSliderField pinkConductionRearmDelay; private static FloatSliderField pinkPullDelay; private static FloatSliderField pinkPullRange; private static FloatSliderField pinkPullSpeed; private static FloatSliderField blueMaximumHookPoints; private static FloatSliderField blueGreenHookPoints; private static BoolField blueRequireGroundAfterUse; private static BoolField blueKnuckleblasterRefundsCooldown; private static readonly Dictionary<EnemyType, FloatSliderField> pinkBlastEnemyDamageMultipliers = new Dictionary<EnemyType, FloatSliderField>(); 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 directHitStylePoints; private static FloatSliderField pipeDreamDamageMultiplier; private static FloatSliderField pipeDreamExplosionSizeMultiplier; private static FloatSliderField moonShotDamageMultiplier; private static FloatSliderField moonShotExplosionSizeMultiplier; internal static float Damage { get { FloatSliderField obj = damage; if (obj == null) { return 4.5f; } return obj.value; } } internal static float AirshotDamage { get { FloatSliderField obj = airshotDamage; if (obj == null) { return 7f; } return obj.value; } } internal static float AirshotExplosionSize { get { FloatSliderField obj = airshotExplosionSize; if (obj == null) { return 1f; } 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 StuckLifetime { get { FloatSliderField obj = stuckLifetime; if (obj == null) { return 60f; } 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 3f; } 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 float JackhammerGrenadeDamage { get { FloatSliderField obj = jackhammerGrenadeDamage; if (obj == null) { return 10f; } return obj.value; } } internal static float JackhammerGrenadeSelfDamage { get { FloatSliderField obj = jackhammerGrenadeSelfDamage; if (obj == null) { return 35f; } return obj.value; } } internal static float GravityMultiplier { get { StringListField obj = arcPreset; if ((((obj != null) ? obj.value : null) ?? "Original TF2-scaled arc") == "Original TF2-scaled arc") { return 1f; } 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 GreenAirshotDamage { get { FloatSliderField obj = greenAirshotDamage; if (obj == null) { return 8f; } return obj.value; } } internal static float GreenSurfaceDamage { get { FloatSliderField obj = greenSurfaceDamage; if (obj == null) { return 4.5f; } return obj.value; } } internal static float GreenDirectExplosionSize { get { FloatSliderField obj = greenDirectExplosionSize; if (obj == null) { return 1.4f; } return obj.value; } } internal static float GreenAirshotExplosionSize { get { FloatSliderField obj = greenAirshotExplosionSize; if (obj == null) { return 1.5f; } 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 4.5f; } 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 35f; } 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 false; } return obj.value; } } internal static bool TimedFuseDetonatesStuck { get { BoolField obj = timedFuseDetonatesStuck; if (obj == null) { return false; } return obj.value; } } internal static bool TerrainStuckDetonatesOnEnemyWalkover { get { BoolField obj = terrainStuckDetonatesOnEnemyWalkover; if (obj == null) { return false; } return obj.value; } } internal static float GelEnemyFireRadiusMultiplier { get { FloatSliderField obj = gelEnemyFireRadius; if (obj == null) { return 2.5f; } return obj.value; } } internal static float GelEnemyFireBaseDuration { get { FloatSliderField obj = gelEnemyFireBaseDuration; if (obj == null) { return 3f; } return obj.value; } } internal static float GelEnemyFireExtraDuration { get { FloatSliderField obj = gelEnemyFireExtraDuration; if (obj == null) { return 1f; } return obj.value; } } internal static float GelEnemyFireMaximumDuration { get { FloatSliderField obj = gelEnemyFireMaximumDuration; if (obj == null) { return 8f; } return obj.value; } } internal static float RedBurstDirectDamage { get { FloatSliderField obj = redBurstDirectDamage; if (obj == null) { return 2.5f; } return obj.value; } } internal static float RedBurstTerrainDamage { get { FloatSliderField obj = redBurstTerrainDamage; if (obj == null) { return 3f; } return obj.value; } } internal static float RedBurstEnemyDamage { get { FloatSliderField obj = redBurstEnemyDamage; if (obj == null) { return 2.5f; } return obj.value; } } internal static float RedBurstAirshotDamage { get { FloatSliderField obj = redBurstAirshotDamage; if (obj == null) { return 3.5f; } return obj.value; } } internal static int RedBurstShotCount { get { FloatSliderField obj = redBurstShotCount; return Mathf.Max(1, Mathf.RoundToInt((obj != null) ? obj.value : 3f)); } } internal static float RedBurstDuration { get { FloatSliderField obj = redBurstDuration; if (obj == null) { return 0.3f; } return obj.value; } } internal static float RedBurstCooldown { get { FloatSliderField obj = redBurstCooldown; if (obj == null) { return 4.5f; } return obj.value; } } internal static float RedBurstKnockbackMultiplier { get { FloatSliderField obj = redBurstKnockback; if (obj == null) { return 0.4f; } return obj.value; } } internal static float BlueDistance { get { FloatSliderField obj = blueDistance; if (obj == null) { return 20f; } return obj.value; } } internal static float BlueCooldown { get { FloatSliderField obj = blueCooldown; if (obj == null) { return 4f; } 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 BlueReplacementDamage { get { FloatSliderField obj = blueReplacementDamage; if (obj == null) { return 3.5f; } return obj.value; } } internal static float BlueReplacementExplosionSize { get { FloatSliderField obj = blueReplacementExplosionSize; if (obj == null) { return 1.2f; } return obj.value; } } internal static float BlueReplacementForce { get { FloatSliderField obj = blueReplacementForce; if (obj == null) { return 20000f; } return obj.value; } } internal static float PinkFirstArmDelay { get { FloatSliderField obj = pinkArmingDelay; if (obj == null) { return 2.25f; } return obj.value; } } internal static float PinkRearmDelay { get { FloatSliderField obj = pinkConductionArmingDelay; if (obj == null) { return 3.5f; } return obj.value; } } internal static float PinkConductionRearmDelay { get { FloatSliderField obj = pinkConductionRearmDelay; if (obj == null) { return 5f; } return obj.value; } } internal static int BlueMaximumHookPoints { get { FloatSliderField obj = blueMaximumHookPoints; return Mathf.Max(1, Mathf.RoundToInt((obj != null) ? obj.value : 1f)); } } internal static int BlueGreenHookPoints { get { FloatSliderField obj = blueGreenHookPoints; return Mathf.Max(0, Mathf.RoundToInt((obj != null) ? obj.value : 0f)); } } internal static bool BlueRequireGroundAfterUse { get { BoolField obj = blueRequireGroundAfterUse; if (obj == null) { return false; } return obj.value; } } internal static bool BlueKnuckleblasterRefundsCooldown { get { BoolField obj = blueKnuckleblasterRefundsCooldown; if (obj == null) { return true; } return obj.value; } } internal static float PinkPullDelay { get { FloatSliderField obj = pinkPullDelay; if (obj == null) { return 0.5f; } return obj.value; } } internal static float PinkPullRange { get { FloatSliderField obj = pinkPullRange; if (obj == null) { return 30f; } return obj.value; } } internal static float PinkPullSpeed { get { FloatSliderField obj = pinkPullSpeed; if (obj == null) { return 50f; } 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 : 150f); } } internal static int MoonShotStylePoints { get { FloatSliderField obj = moonShotStylePoints; return Mathf.RoundToInt((obj != null) ? obj.value : 550f); } } internal static int OutSnipedStylePoints { get { FloatSliderField obj = outSnipedStylePoints; return Mathf.RoundToInt((obj != null) ? obj.value : 550f); } } internal static int WalkingBombStylePoints { get { FloatSliderField obj = walkingBombStylePoints; return Mathf.RoundToInt((obj != null) ? obj.value : 90f); } } internal static int DirectHitStylePoints { get { FloatSliderField obj = directHitStylePoints; return Mathf.RoundToInt((obj != null) ? obj.value : 35f); } } 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 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_0082: Unknown result type (might be due to invalid IL or missing references) //IL_008c: Expected O, but got Unknown //IL_042f: Unknown result type (might be due to invalid IL or missing references) //IL_0435: Expected O, but got Unknown //IL_049d: Unknown result type (might be due to invalid IL or missing references) //IL_04a2: Unknown result type (might be due to invalid IL or missing references) //IL_04a8: Unknown result type (might be due to invalid IL or missing references) //IL_04aa: Unknown result type (might be due to invalid IL or missing references) //IL_04e0: 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, "Detailed weapon documentation available on the Wiki tab in the Thunderstore mod page.", 24); AddPageResetButton(val.rootPanel, "Reset all pages to default", "resetAllPages", allPages: true, val); AddPageResetButton(val.rootPanel, "Reset this page to default", "resetMainPage", allPages: false, val); arcPreset = new StringListField(val.rootPanel, "Arc preset", "arcPreset", new string[2] { "Original TF2-scaled arc", "Custom gravity" }, "Original TF2-scaled arc"); damage = Slider(val, "Damage", "damage", 0f, 10f, 4.5f, 2); airshotDamage = Slider(val, "Airshot damage", "airshotDamage", 0f, 20f, 7f, 2); airshotExplosionSize = Slider(val, "Airshot explosion size", "airshotExplosionSize", 0.1f, 5f, 1f, 2); 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, "Blast knockback (Rocket = 1)", "knockbackMultiplier", 0f, 3f, 1f, 2); lifetime = Slider(val, "Silent projectile lifetime", "projectileLifetime", 1f, 60f, 15f, 1); stuckLifetime = Slider(val, "Stuck lifetime (seconds)", "stuckLifetime", 1f, 300f, 60f, 1); surfaceFuse = Slider(val, "Surface fuse (seconds)", "surfaceFuse", 0.1f, 10f, 1f, 2); hookFuseGrace = Slider(val, "Fuse time per Whiplash (s)", "hookFuseGrace", 0f, 2f, 0.1f, 2); surfaceDamage = Slider(val, "Surface detonation damage", "surfaceDamage", 0f, 10f, 3f, 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 blast size (Rocket = 1)", "parryExplosionSize", 0.25f, 5f, 1f, 2); parrySpeed = Slider(val, "Parried speed multiplier", "parrySpeedMultiplier", 0.1f, 5f, 3f, 2); directSelfDamage = Slider(val, "Direct self-damage (HP)", "directSelfDamage", 0f, 100f, 35f, 0); surfaceSelfDamage = Slider(val, "Timed self-damage (HP)", "surfaceSelfDamage", 0f, 100f, 25f, 0); parrySelfDamage = Slider(val, "Parried self-damage (HP)", "parrySelfDamage", 0f, 100f, 30f, 0); jackhammerGrenadeDamage = Slider(val, "Jackhammer hit damage", "jackhammerGrenadeDamage", 0f, 50f, 10f, 2); jackhammerGrenadeSelfDamage = Slider(val, "Jackhammer self-damage (HP)", "jackhammerGrenadeSelfDamage", 0f, 100f, 35f, 0); if (arcPreset.value == "Current snappier arc") { arcPreset.value = "Custom gravity"; customGravity.value = 2f; } InitializeAlternateSettings(val); WeaponVisualRuntime.InitializeConfiguration(val); ConfigPanel val2 = new ConfigPanel(val.rootPanel, "Enemy grenade damage", "enemyDamageMultipliers"); val2.headerText = "Damage percentage is applied after ULTRAKILL's normal explosive weakness or resistance."; AddPageResetButton(val2, "Reset this page to default", "resetEnemyDamageMultipliers"); enemyDamageMultipliers.Clear(); foreach (EnemyType item in from EnemyType val3 in Enum.GetValues(typeof(EnemyType)) orderby ((object)(*(EnemyType*)(&val3))/*cast due to .constrained prefix*/).ToString() select val3) { enemyDamageMultipliers[item] = Slider(val2, FriendlyEnemyName(item) + " damage (%)", "enemyDamage_" + ((object)(*(EnemyType*)(&item))/*cast due to .constrained prefix*/).ToString(), 0f, 500f, releaseEnemyDamageDefaults.TryGetValue(item, out var value) ? value : 100f, 0); } MigrateBalanceDefaults(val); } 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 void AddPageResetButton(ConfigPanel panel, string text, string guid, bool allPages = false, PluginConfigurator configurator = null) { //IL_0024: Unknown result type (might be due to invalid IL or missing references) //IL_0030: Unknown result type (might be due to invalid IL or missing references) //IL_003a: Expected O, but got Unknown new ButtonField(panel, text, guid).onClick += (OnClick)delegate { PluginConfigurator configurator2 = configurator ?? ((ConfigField)panel).rootConfig; if (allPages) { ResetAllPages(configurator2); } else { ResetPage(panel, configurator2); } }; } private static void ResetPage(ConfigPanel panel, PluginConfigurator configurator) { foreach (ConfigField directField in GetDirectFields(panel, configurator)) { if (directField != null && !(directField is ConfigPanel) && !(directField is ButtonField)) { ReloadFieldDefault(directField); } } FlushConfigurator(configurator); } private static IEnumerable<ConfigField> GetDirectFields(ConfigPanel panel, PluginConfigurator configurator) { IDictionary dictionary = AccessTools.Field(typeof(PluginConfigurator), "fields")?.GetValue(configurator) as IDictionary; PropertyInfo parentPanel = AccessTools.Property(typeof(ConfigField), "parentPanel"); if (dictionary != null && parentPanel != null) { foreach (object value in dictionary.Values) { ConfigField val = (ConfigField)((value is ConfigField) ? value : null); if (val != null && parentPanel.GetValue(val, null) == panel) { yield return val; } } } else { ConfigField[] allFields = panel.GetAllFields(); for (int i = 0; i < allFields.Length; i++) { yield return allFields[i]; } } } private static void ResetAllPages(PluginConfigurator configurator) { if (AccessTools.Field(typeof(PluginConfigurator), "fields")?.GetValue(configurator) is IDictionary dictionary) { foreach (object value in dictionary.Values) { ConfigField val = (ConfigField)((value is ConfigField) ? value : null); if (val != null && !(val is ConfigPanel) && !(val is ButtonField)) { ReloadFieldDefault(val); } } } else { ResetPage(configurator.rootPanel, configurator); } FlushConfigurator(configurator); } private static void ReloadFieldDefault(ConfigField field) { AccessTools.Method(((object)field).GetType(), "ReloadDefault", (Type[])null, (Type[])null)?.Invoke(field, null); } private static void FlushConfigurator(PluginConfigurator configurator) { if (configurator != null) { AccessTools.Method(typeof(PluginConfigurator), "FlushAll", (Type[])null, (Type[])null)?.Invoke(configurator, null); Plugin instance = Plugin.Instance; if (instance != null) { ((BaseUnityPlugin)instance).Config.Save(); } } } 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<float, float>(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<float, float>(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 MigrateBalanceDefaults(PluginConfigurator configurator) { GrenadeLauncherState grenadeLauncherState = (((Object)(object)Plugin.Instance != (Object)null) ? Plugin.Instance.State : null); if (grenadeLauncherState != null) { if (grenadeLauncherState.BalanceDefaultsVersion < 4) { ReplaceReleasedDefault(damage, 4.5f, 3f, 4f); ReplaceReleasedDefault(airshotDamage, 7f, 6f); ReplaceReleasedDefault(surfaceDamage, 3f, 2.5f); ReplaceReleasedDefault(greenAirshotDamage, 8f, 7.5f); ReplaceReleasedDefault(greenSurfaceDamage, 4.5f, 4f); ReplaceReleasedDefault(stuckDamage, 4.5f, 4f); ReplaceReleasedDefault(stuckSelfDamage, 35f, 45f); ReplaceReleasedDefault(blueDistance, 20f, 27f); ReplaceEnemyReleasedDefault((EnemyType)33, 120f, 100f, 110f); ReplaceEnemyReleasedDefault((EnemyType)34, 120f, 100f); ReplaceEnemyReleasedDefault((EnemyType)2, 100f, 80f, 85f, 90f); ReplaceReleasedDefault(pinkArmingDelay, 2.5f, 2f); ReplaceReleasedDefault(enemyCarrierDirectDamage, false, true); grenadeLauncherState.BalanceDefaultsVersion = 4; } if (grenadeLauncherState.BalanceDefaultsVersion < 5) { ReplaceReleasedDefault(pinkArmingDelay, 2.25f, 2f, 2.5f); ReplaceReleasedDefault(pinkConductionArmingDelay, 3f, 4f); grenadeLauncherState.BalanceDefaultsVersion = 5; } if (grenadeLauncherState.BalanceDefaultsVersion < 6) { ReplaceReleasedDefault(gelEnemyFireRadius, 2.5f, 3f); ReplaceReleasedDefault(redBurstCooldown, 4.5f, 5f); ReplaceReleasedDefault(blueMaximumHookPoints, 1f, 3f); ReplaceReleasedDefault(blueGreenHookPoints, 0f, 1f); ReplaceReleasedDefault(blueKnuckleblasterRefundsCooldown, true, default(bool)); ReplaceReleasedDefault(pinkConductionArmingDelay, 3.5f, 3f); ReplaceReleasedDefault(pinkConductionRearmDelay, 5f, 4f); ReplacePinkBlastReleasedDefault((EnemyType)1, 50f, 100f); ReplacePinkBlastReleasedDefault((EnemyType)15, 60f, 100f); ReplacePinkBlastReleasedDefault((EnemyType)12, 75f, 100f); ReplacePinkBlastReleasedDefault((EnemyType)13, 35f, 100f); grenadeLauncherState.BalanceDefaultsVersion = 6; } if (grenadeLauncherState.BalanceDefaultsVersion < 7) { ReplaceEnemyReleasedDefault((EnemyType)0, 100f, 120f); ReplaceEnemyReleasedDefault((EnemyType)34, 100f, 120f); grenadeLauncherState.BalanceDefaultsVersion = 7; } if (configurator != null) { configurator.FlushAll(); } grenadeLauncherState.Save(); } } private static void ReplaceReleasedDefault(FloatSliderField field, float replacement, params float[] releasedValues) { if (field != null && releasedValues.Any((float value) => Mathf.Approximately(field.value, value))) { field.value = replacement; } } private static void ReplaceReleasedDefault(BoolField field, bool replacement, params bool[] releasedValues) { if (field != null && releasedValues.Contains(field.value)) { field.value = replacement; } } private static void ReplaceEnemyReleasedDefault(EnemyType enemyType, float replacement, params float[] releasedValues) { //IL_0005: Unknown result type (might be due to invalid IL or missing references) if (enemyDamageMultipliers.TryGetValue(enemyType, out var value)) { ReplaceReleasedDefault(value, replacement, releasedValues); } } private static void ReplacePinkBlastReleasedDefault(EnemyType enemyType, float replacement, params float[] releasedValues) { //IL_0005: Unknown result type (might be due to invalid IL or missing references) if (pinkBlastEnemyDamageMultipliers.TryGetValue(enemyType, out var value)) { ReplaceReleasedDefault(value, replacement, releasedValues); } } internal static float GetPinkBlastEnemyDamageMultiplier(EnemyType enemyType) { //IL_0005: Unknown result type (might be due to invalid IL or missing references) //IL_000f: Unknown result type (might be due to invalid IL or missing references) if (!pinkBlastEnemyDamageMultipliers.TryGetValue(enemyType, out var value)) { return GetPinkBlastDefaultDamagePercent(enemyType) / 100f; } return Mathf.Max(0f, value.value) / 100f; } internal static float GetPinkBlastDefaultDamagePercent(EnemyType enemyType) { //IL_0000: Unknown result type (might be due to invalid IL or missing references) //IL_0002: Invalid comparison between Unknown and I4 //IL_0004: Unknown result type (might be due to invalid IL or missing references) //IL_0007: Unknown result type (might be due to invalid IL or missing references) //IL_001d: Expected I4, but got Unknown if ((int)enemyType != 1) { return (enemyType - 12) switch { 3 => 60f, 0 => 75f, 1 => 35f, _ => 100f, }; } return 50f; } private unsafe 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_0027: Expected O, but got Unknown //IL_0027: Unknown result type (might be due to invalid IL or missing references) //IL_0047: Expected O, but got Unknown //IL_004c: Unknown result type (might be due to invalid IL or missing references) //IL_006c: Expected O, but got Unknown //IL_0071: Unknown result type (might be due to invalid IL or missing references) //IL_0091: Expected O, but got Unknown //IL_0096: Unknown result type (might be due to invalid IL or missing references) //IL_00b6: Expected O, but got Unknown //IL_00bb: Unknown result type (might be due to invalid IL or missing references) //IL_00db: Expected O, but got Unknown //IL_00e0: Unknown result type (might be due to invalid IL or missing references) //IL_0100: Expected O, but got Unknown //IL_0105: Unknown result type (might be due to invalid IL or missing references) //IL_0125: Expected O, but got Unknown //IL_012a: Unknown result type (might be due to invalid IL or missing references) //IL_014a: Expected O, but got Unknown //IL_014f: Unknown result type (might be due to invalid IL or missing references) //IL_016f: Expected O, but got Unknown //IL_0174: Unknown result type (might be due to invalid IL or missing references) //IL_0194: Expected O, but got Unknown //IL_0199: Unknown result type (might be due to invalid IL or missing references) //IL_01b9: Expected O, but got Unknown //IL_01be: Unknown result type (might be due to invalid IL or missing references) //IL_01de: Expected O, but got Unknown //IL_01e3: Unknown result type (might be due to invalid IL or missing references) //IL_0203: Expected O, but got Unknown //IL_0227: Expected O, but got Unknown //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_0253: Expected O, but got Unknown //IL_0253: Unknown result type (might be due to invalid IL or missing references) //IL_0273: Expected O, but got Unknown //IL_0278: Unknown result type (might be due to invalid IL or missing references) //IL_0298: Expected O, but got Unknown //IL_029d: Unknown result type (might be due to invalid IL or missing references) //IL_02bd: Expected O, but got Unknown //IL_02c2: Unknown result type (might be due to invalid IL or missing references) //IL_02e2: Expected O, but got Unknown //IL_02e7: Unknown result type (might be due to invalid IL or missing references) //IL_0307: Expected O, but got Unknown //IL_030c: Unknown result type (might be due to invalid IL or missing references) //IL_032c: Expected O, but got Unknown //IL_0331: Unknown result type (might be due to invalid IL or missing references) //IL_0351: Expected O, but got Unknown //IL_0356: Unknown result type (might be due to invalid IL or missing references) //IL_0376: Expected O, but got Unknown //IL_037b: Unknown result type (might be due to invalid IL or missing references) //IL_039b: Expected O, but got Unknown //IL_03a0: Unknown result type (might be due to invalid IL or missing references) //IL_03c0: Expected O, but got Unknown //IL_03c5: Unknown result type (might be due to invalid IL or missing references) //IL_03e5: Expected O, but got Unknown //IL_03ea: Unknown result type (might be due to invalid IL or missing references) //IL_03fb: Expected O, but got Unknown //IL_03f6: Unknown result type (might be due to invalid IL or missing references) //IL_0400: Expected O, but got Unknown //IL_0400: Unknown result type (might be due to invalid IL or missing references) //IL_0411: Expected O, but got Unknown //IL_040c: Unknown result type (might be due to invalid IL or missing references) //IL_0416: Expected O, but got Unknown //IL_0416: Unknown result type (might be due to invalid IL or missing references) //IL_0427: Expected O, but got Unknown //IL_0422: Unknown result type (might be due to invalid IL or missing references) //IL_042c: Expected O, but got Unknown //IL_042c: Unknown result type (might be due to invalid IL or missing references) //IL_044c: Expected O, but got Unknown //IL_0451: Unknown result type (might be due to invalid IL or missing references) //IL_0471: Expected O, but got Unknown //IL_0476: Unknown result type (might be due to invalid IL or missing references) //IL_0496: Expected O, but got Unknown //IL_049b: Unknown result type (might be due to invalid IL or missing references) //IL_04bb: Expected O, but got Unknown //IL_04cf: Expected O, but got Unknown //IL_04ca: Unknown result type (might be due to invalid IL or missing references) //IL_04cf: Unknown result type (might be due to invalid IL or missing references) //IL_04e1: Expected O, but got Unknown //IL_04e1: Unknown result type (might be due to invalid IL or missing references) //IL_0501: Expected O, but got Unknown //IL_0506: Unknown result type (might be due to invalid IL or missing references) //IL_0526: Expected O, but got Unknown //IL_052b: Unknown result type (might be due to invalid IL or missing references) //IL_054b: Expected O, but got Unknown //IL_0550: Unknown result type (might be due to invalid IL or missing references) //IL_0570: Expected O, but got Unknown //IL_0575: Unknown result type (might be due to invalid IL or missing references) //IL_0595: Expected O, but got Unknown //IL_059a: Unknown result type (might be due to invalid IL or missing references) //IL_05ba: Expected O, but got Unknown //IL_05bf: Unknown result type (might be due to invalid IL or missing references) //IL_05df: Expected O, but got Unknown //IL_0603: Expected O, but got Unknown //IL_0618: Unknown result type (might be due to invalid IL or missing references) //IL_061d: Unknown result type (might be due to invalid IL or missing references) //IL_062f: Expected O, but got Unknown //IL_062f: Unknown result type (might be due to invalid IL or missing references) //IL_064f: Expected O, but got Unknown //IL_0654: Unknown result type (might be due to invalid IL or missing references) //IL_0674: Expected O, but got Unknown //IL_0679: Unknown result type (might be due to invalid IL or missing references) //IL_0699: Expected O, but got Unknown //IL_069e: Unknown result type (might be due to invalid IL or missing references) //IL_06be: Expected O, but got Unknown //IL_06c3: Unknown result type (might be due to invalid IL or missing references) //IL_06e3: Expected O, but got Unknown //IL_06e8: Unknown result type (might be due to invalid IL or missing references) //IL_0708: Expected O, but got Unknown //IL_070d: Unknown result type (might be due to invalid IL or missing references) //IL_071e: Expected O, but got Unknown //IL_0719: Unknown result type (might be due to invalid IL or missing references) //IL_0723: Expected O, but got Unknown //IL_0723: Unknown result type (might be due to invalid IL or missing references) //IL_0734: Expected O, but got Unknown //IL_072f: Unknown result type (might be due to invalid IL or missing references) //IL_0739: Expected O, but got Unknown //IL_0739: Unknown result type (might be due to invalid IL or missing references) //IL_0759: Expected O, but got Unknown //IL_075e: Unknown result type (might be due to invalid IL or missing references) //IL_077e: Expected O, but got Unknown //IL_0783: Unknown result type (might be due to invalid IL or missing references) //IL_07a3: Expected O, but got Unknown //IL_07a8: Unknown result type (might be due to invalid IL or missing references) //IL_07c8: Expected O, but got Unknown //IL_07cd: Unknown result type (might be due to invalid IL or missing references) //IL_07ed: Expected O, but got Unknown //IL_07f2: Unknown result type (might be due to invalid IL or missing references) //IL_0812: Expected O, but got Unknown //IL_0817: Unknown result type (might be due to invalid IL or missing references) //IL_0837: Expected O, but got Unknown //IL_083c: Unknown result type (might be due to invalid IL or missing references) //IL_085c: Expected O, but got Unknown //IL_0861: Unknown result type (might be due to invalid IL or missing references) //IL_0881: Expected O, but got Unknown //IL_0895: Expected O, but got Unknown //IL_0890: Unknown result type (might be due to invalid IL or missing references) //IL_0896: Expected O, but got Unknown //IL_08fe: Unknown result type (might be due to invalid IL or missing references) //IL_0903: Unknown result type (might be due to invalid IL or missing references) //IL_0909: Unknown result type (might be due to invalid IL or missing references) //IL_090b: Unknown result type (might be due to invalid IL or missing references) //IL_093c: Unknown result type (might be due to invalid IL or missing references) //IL_0971: Unknown result type (might be due to invalid IL or missing references) //IL_0976: Unknown result type (might be due to invalid IL or missing references) //IL_0988: Expected O, but got Unknown //IL_0988: Unknown result type (might be due to invalid IL or missing references) //IL_09a8: Expected O, but got Unknown //IL_09ad: Unknown result type (might be due to invalid IL or missing references) //IL_09cd: Expected O, but got Unknown //IL_09d2: Unknown result type (might be due to invalid IL or missing references) //IL_09f2: Expected O, but got Unknown //IL_09f7: Unknown result type (might be due to invalid IL or missing references) //IL_0a17: Expected O, but got Unknown //IL_0a1c: Unknown result type (might be due to invalid IL or missing references) //IL_0a3c: Expected O, but got Unknown //IL_0a41: Unknown result type (might be due to invalid IL or missing references) //IL_0a61: Expected O, but got Unknown //IL_0a66: Unknown result type (might be due to invalid IL or missing references) //IL_0a86: Expected O, but got Unknown //IL_0a8b: Unknown result type (might be due to invalid IL or missing references) //IL_0aab: Expected O, but got Unknown //IL_0ab0: Unknown result type (might be due to invalid IL or missing references) //IL_0ad0: Expected O, but got Unknown //IL_0ad5: Unknown result type (might be due to invalid IL or missing references) //IL_0af5: Expected O, but got Unknown //IL_0b19: Expected O, but got Unknown ConfigPanel val = new ConfigPanel(configurator.rootPanel, "Green contact grenade", "greenContactGrenade"); AddPageResetButton(val, "Reset this page to default", "resetGreenContactGrenade"); 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); greenAirshotDamage = Slider(val, "Airshot damage", "greenAirshotDamage", 0f, 25f, 8f, 2); greenSurfaceDamage = Slider(val, "Surface contact damage", "greenSurfaceDamage", 0f, 20f, 4.5f, 2); greenDirectExplosionSize = Slider(val, "Direct blast size (Rocket = 1)", "greenDirectExplosionSize", 0.1f, 5f, 1.4f, 2); greenAirshotExplosionSize = Slider(val, "Airshot explosion size", "greenAirshotExplosionSize", 0.1f, 5f, 1.5f, 2); greenSurfaceExplosionSize = Slider(val, "Surface blast 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, "Blast 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"); AddPageResetButton(val2, "Reset this page to default", "resetRedGelSystem"); 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, 4.5f, 2); greenStuckDamage = Slider(val2, "Green stuck grenade damage", "greenStuckDamage", 0f, 20f, 6f, 2); stuckExplosionSize = Slider(val2, "Stuck blast size (Rocket = 1)", "stuckExplosionSize", 0.1f, 5f, 1.3f, 2); stuckSelfDamage = Slider(val2, "Stuck self-damage (HP)", "stuckSelfDamage", 0f, 100f, 35f, 0); stuckKnockback = Slider(val2, "Stuck knockback (Rocket = 1)", "stuckKnockbackMultiplier", 0f, 5f, 1f, 2); stuckChainRadius = Slider(val2, "Stuck chain range mult.", "stuckChainRadiusMultiplier", 0f, 10f, 2f, 2); stuckChainPropagationSpeed = Slider(val2, "Chain speed (units/s)", "stuckChainPropagationSpeed", 1f, 200f, 50f, 1); enemyCarrierDirectDamage = new BoolField(val2, "Carrier takes direct damage", "enemyCarrierDirectDamage", false); timedFuseDetonatesStuck = new BoolField(val2, "Non-stuck nades detonate stuck", "timedFuseDetonatesStuck", false); terrainStuckDetonatesOnEnemyWalkover = new BoolField(val2, "Enemy walk triggers traps", "terrainStuckDetonatesOnEnemyWalkover", false); gelEnemyFireRadius = Slider(val2, "Enemy fire radius (blast = 1)", "gelEnemyFireRadius", 0f, 10f, 2.5f, 2); gelEnemyFireBaseDuration = Slider(val2, "Enemy fire base time (s)", "gelEnemyFireBaseDuration", 0f, 20f, 3f, 2); gelEnemyFireExtraDuration = Slider(val2, "Extra time per grenade (s)", "gelEnemyFireExtraDuration", 0f, 20f, 1f, 2); gelEnemyFireMaximumDuration = Slider(val2, "Enemy fire max time (s)", "gelEnemyFireMaximumDuration", 0f, 60f, 8f, 2); ConfigPanel val3 = new ConfigPanel(val2, "Red gel burst", "redGelBurst"); AddPageResetButton(val3, "Reset this page to default", "resetRedGelBurst"); redBurstDirectDamage = Slider(val3, "Direct hit damage", "redBurstDirectDamage", 0f, 20f, 2.5f, 2); redBurstTerrainDamage = Slider(val3, "Terrain-stuck grenade damage", "redBurstTerrainDamage", 0f, 20f, 3f, 2); redBurstEnemyDamage = Slider(val3, "Enemy-stuck grenade damage", "redBurstEnemyDamage", 0f, 20f, 2.5f, 2); redBurstAirshotDamage = Slider(val3, "Airshot damage", "redBurstAirshotDamage", 0f, 20f, 3.5f, 2); redBurstShotCount = Slider(val3, "Shot count", "redBurstShotCount", 1f, 10f, 3f, 0); redBurstDuration = Slider(val3, "Burst duration (seconds)", "redBurstDuration", 0f, 5f, 0.3f, 2); redBurstCooldown = Slider(val3, "Primary cooldown (seconds)", "redBurstCooldown", 0f, 30f, 4.5f, 2); redBurstKnockback = Slider(val3, "Blast knockback (Rocket = 1)", "redBurstKnockback", 0f, 5f, 0.4f, 2); ConfigPanel val4 = new ConfigPanel(configurator.rootPanel, "Blue slingshot point", "blueSlingshotPoint"); AddPageResetButton(val4, "Reset this page to default", "resetBlueSlingshotPoint"); blueDistance = Slider(val4, "Placement distance", "bluePlacementDistance", 5.5f, 200f, 20f, 1); blueCooldown = Slider(val4, "Cooldown (seconds)", "blueCooldown", 0.05f, 10f, 4f, 2); blueSlingshotForce = Slider(val4, "Extra slingshot force", "blueSlingshotForce", -50f, 200f, 0f, 1); bluePointSize = Slider(val4, "Hook point size multiplier", "bluePointSize", 0.25f, 4f, 1f, 2); blueMaximumHookPoints = Slider(val4, "Maximum created hook points", "blueMaximumHookPoints", 1f, 10f, 1f, 0); blueGreenHookPoints = Slider(val4, "Created green hook points", "blueGreenHookPoints", 0f, 10f, 0f, 0); blueRequireGroundAfterUse = new BoolField(val4, "Must land after hook use", "blueRequireGroundAfterUse", false); blueKnuckleblasterRefundsCooldown = new BoolField(val4, "Knuckleblast refunds cooldown", "blueKnuckleblasterRefundsCooldown", true); pinkArmingDelay = Slider(val4, "Pink first arm time (s)", "pinkArmingDelay", 0f, 30f, 2.25f, 2); pinkConductionArmingDelay = Slider(val4, "Pink re-arm time (s)", "pinkConductionArmingDelay", 0f, 30f, 3.5f, 2); pinkConductionRearmDelay = Slider(val4, "Pink re-arm after zap (s)", "pinkConductionRearmDelay", 0f, 30f, 5f, 2); pinkPullDelay = Slider(val4, "Pink pull delay (seconds)", "pinkPullDelay", 0f, 5f, 0.5f, 2); pinkPullRange = Slider(val4, "Pink pull range (units)", "pinkPullRange", 0f, 200f, 30f, 1); pinkPullSpeed = Slider(val4, "Pink pull speed (units/second)", "pinkPullSpeed", 0f, 200f, 50f, 1); blueReplacementDamage = Slider(val4, "Pink explosion damage", "blueReplacementDamage", 0f, 20f, 3.5f, 2); blueReplacementExplosionSize = Slider(val4, "Pink blast size (Providence = 1)", "blueReplacementExplosionSize", 0.1f, 5f, 1.2f, 2); blueReplacementForce = Slider(val4, "Pink enemy launch force", "blueReplacementForceRaw", 0f, 50000f, 20000f, 0); ConfigPanel val5 = new ConfigPanel(val4, "Pink blast enemy damage", "pinkBlastEnemyDamage"); val5.headerText = "Extra damage percentage for pink explosion only. 100% = unchanged. Native explosive resistance remains active."; AddPageResetButton(val5, "Reset this page to default", "resetPinkBlastEnemyDamage"); pinkBlastEnemyDamageMultipliers.Clear(); foreach (EnemyType item in from EnemyType value in Enum.GetValues(typeof(EnemyType)) orderby ((object)(*(EnemyType*)(&value))/*cast due to .constrained prefix*/).ToString() select value) { pinkBlastEnemyDamageMultipliers[item] = Slider(val5, FriendlyEnemyName(item) + " damage (%)", "pinkBlastDamage_" + ((object)(*(EnemyType*)(&item))/*cast due to .constrained prefix*/).ToString(), 0f, 500f, GetPinkBlastDefaultDamagePercent(item), 0); } ConfigPanel val6 = new ConfigPanel(configurator.rootPanel, "Style bonuses", "styleBonuses"); AddPageResetButton(val6, "Reset this page to default", "resetStyleBonuses"); pipeDreamDistance = Slider(val6, "PIPE DREAM minimum distance", "pipeDreamMinimumDistance", 1f, 250f, 56f, 1); moonShotDistance = Slider(val6, "MOON/OUT-SNIPED range", "moonShotMinimumDistance", 1f, 400f, 125f, 1); pipeDreamStylePoints = Slider(val6, "PIPE DREAM style points", "pipeDreamStylePoints", 0f, 10000f, 150f, 0); moonShotStylePoints = Slider(val6, "MOON SHOT style points", "moonShotStylePoints", 0f, 10000f, 550f, 0); outSnipedStylePoints = Slider(val6, "OUT-SNIPED style points", "outSnipedStylePoints", 0f, 10000f, 550f, 0); walkingBombStylePoints = Slider(val6, "WALKING BOMB style points", "walkingBombStylePoints", 0f, 5000f, 90f, 0); directHitStylePoints = Slider(val6, "Direct-hit base style points", "directHitStylePoints", 0f, 5000f, 35f, 0); pipeDreamDamageMultiplier = Slider(val6, "PIPE DREAM damage multiplier", "pipeDreamDamageMultiplier", 0f, 10f, 1f, 2); pipeDreamExplosionSizeMultiplier = Slider(val6, "PIPE DREAM blast mult.", "pipeDreamExplosionSizeMultiplier", 0.1f, 10f, 1f, 2); moonShotDamageMultiplier = Slider(val6, "MOON SHOT damage multiplier", "moonShotDamageMultiplier", 0f, 10f, 1.15f, 2); moonShotExplosionSizeMultiplier = Slider(val6, "MOON SHOT blast mult.", "moonShotExplosionSizeMultiplier", 0.1f, 10f, 1.15f, 2); } } [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<BlueHookDeliveryProjectile>() == (Object)null) { BlueHookDeliveryProjectile blueHookDeliveryProjectile = ((Component)__instance).gameObject.AddComponent<BlueHookDeliveryProjectile>(); blueHookDeliveryProjectile.Grenade = __instance; blueHookDeliveryProjectile.Target = BlueHookDeliveryContext.Target; } } else if ((Object)(object)((Component)__instance).GetComponent<GrenadeLauncherProjectile>() == (Object)null) { GrenadeLauncherProjectile grenadeLauncherProjectile = ((Component)__instance).gameObject.AddComponent<GrenadeLauncherProjectile>(); grenadeLauncherProjectile.Grenade = __instance; grenadeLauncherProjectile.Profile = GrenadeSpawnContext.Profile; WeaponVisualRuntime.AttachProjectileVisual(__instance, GrenadeSpawnContext.Profile); } } } [HarmonyPatch(typeof(Grenade), "FixedUpdate")] internal static class GrenadeFixedUpdatePatch { private static bool Prefix(Grenade __instance) { if ((Object)(object)((Component)__instance).GetComponent<GrenadeLauncherProjectile>() == (Object)null) { return (Object)(object)((Component)__instance).GetComponent<BlueHookDeliveryProjectile>() == (Object)null; } return false; } } [HarmonyPatch(typeof(CustomGravity), "FixedUpdate")] internal static class GrenadeCustomGravityPatch { private static bool Prefix(CustomGravity __instance) { if ((Object)(object)((Component)__instance).GetComponent<GrenadeLauncherProjectile>() == (Object)null) { return (Object)(object)((Component)__instance).GetComponent<BlueHookDeliveryProjectile>() == (Object)null; } return false; } } [HarmonyPatch(typeof(Grenade), "Start")] internal static class GrenadeStartPatch { private static void Postfix(Grenade __instance) { ((Component)__instance).GetComponent<GrenadeLauncherProjectile>()?.Launch(); ((Component)__instance).GetComponent<BlueHookDeliveryProjectile>()?.Launch(); } } [HarmonyPatch(typeof(Grenade), "OnCollisionEnter")] internal static class GrenadeOnCollisionEnterPatch { private static bool Prefix(Grenade __instance, Collision collision) { //IL_005f: Unknown result type (might be due to invalid IL or missing references) //IL_0053: Unknown result type (might be due to invalid IL or missing references) //IL_0059: Unknown result type (might be due to invalid IL or missing references) //IL_0064: 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_006e: Unknown result type (might be due to invalid IL or missing references) //IL_007c: Unknown result type (might be due to invalid IL or missing references) //IL_0095: Unknown result type (might be due to invalid IL or missing references) //IL_008c: Unknown result type (might be due to invalid IL or missing references) //IL_009a: Unknown result type (might be due to invalid IL or missing references) //IL_00a3: Unknown result type (might be due to invalid IL or missing references) //IL_00a8: Unknown result type (might be due to invalid IL or missing references) //IL_00ad: Unknown result type (might be due to invalid IL or missing references) //IL_00ae: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)((Component)__instance).GetComponent<BlueHookDeliveryProjectile>() != (Object)null) { return false; } if (collision != null && (Object)(object)collision.collider != (Object)null && (Object)(object)((Component)collision.collider).GetComponentInParent<PinkHookPointMarker>() != (Object)null) { return false; } GrenadeLauncherProjectile component = ((Component)__instance).GetComponent<GrenadeLauncherProjectile>(); 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_003d: Unknown result type (might be due to invalid IL or missing references) //IL_003e: Unknown result type (might be due to invalid IL or missing references) //IL_0049: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)((Component)__instance).GetComponent<BlueHookDeliveryProjectile>() != (Object)null) { return false; } if ((Object)(object)other != (Object)null && (Object)(object)((Component)other).GetComponentInParent<PinkHookPointMarker>() != (Object)null) { return false; } GrenadeLauncherProjectile component = ((Component)__instance).GetComponent<GrenadeLauncherProjectile>(); if ((Object)(object)component == (Object)null) { return true; } component.HandleCollision(other, velocity, Vector3.zero, ((Component)__instance).transform.position); return false; } } [HarmonyPatch(typeof(Grenade), "OnTriggerEnter")] internal static class PinkHookGrenadeTriggerIgnorePatch { private static bool Prefix(Collider other) { if (!((Object)(object)other == (Object)null)) { return (Object)(object)((Component)other).GetComponentInParent<PinkHookPointMarker>() == (Object)null; } return true; } } [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; internal bool ReplacesDirectHitBaseStyle; } private static bool Prefix(Explosion __instance, Collider other, out State __state) { //IL_0179: 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_0152: Invalid comparison between Unknown and I4 __state = default(State); GrenadeLauncherExplosionMarker grenadeLauncherExplosionMarker = GrenadeLauncherExplosionMarker.TryGet(__instance); GrenadeLauncherProjectile grenadeLauncherProjectile = GrenadeLauncherProjectile.TryGetStuckProjectile(other); if ((Object)(object)grenadeLauncherProjectile != (Object)null && grenadeLauncherProjectile.IsStuck) { if ((Object)(object)grenadeLauncherExplosionMarker != (Object)null && (grenadeLauncherExplosionMarker.Mode == GrenadeExplosionMode.Surface || grenadeLauncherExplosionMarker.Mode == GrenadeExplosionMode.GreenSurface) && !PluginSettings.TimedFuseDetonatesStuck) { return false; } if (IsPlayerExplosion(__instance)) { grenadeLauncherProjectile.DetonateStuck(); } return false; } if ((Object)(object)grenadeLauncherExplosionMarker == (Object)null) { return true; } if (grenadeLauncherExplosionMarker.BlueHookReplacement) { if ((Object)(object)other != (Object)null && ((Component)other).CompareTag("Player")) { return false; } return (Object)(object)GrenadeLauncherProjectile.TryGetLivingEnemy(other) == (Object)null; } EnemyIdentifier val = GrenadeLauncherProjectile.TryGetLivingEnemy(other); if ((Object)(object)val == (Object)null) { return true; } __state.Marker = grenadeLauncherExplosionMarker; __state.Enemy = val; __state.ReplacesDirectHitBaseStyle = grenadeLauncherExplosionMarker.DirectEnemyId == ((Object)val).GetInstanceID() && !grenadeLauncherExplosionMarker.Parried && (grenadeLauncherExplosionMarker.Mode == GrenadeExplosionMode.Direct || grenadeLauncherExplosionMarker.Mode == GrenadeExplosionMode.GreenDirect); if (__state.ReplacesDirectHitBaseStyle) { GrenadeDirectHitStyleContext.Enter(); } if (PluginSettings.EnemyCarrierTakesDirectDamage && grenadeLauncherExplosionMarker.StuckHostEnemyId != 0 && ((Object)val).GetInstanceID() == grenadeLauncherExplosionMarker.StuckHostEnemyId) { __state.ChangedDamage = true; __state.Damage = __instance.damage; __instance.damage = Mathf.RoundToInt(Mathf.Max(0f, grenadeLauncherExplosionMarker.StuckCarrierDamage) * 10f); } if (grenadeLauncherExplosionMarker.Parried && (int)val.enemyType == 4) { grenadeLauncherExplosionMarker.DamageBlockedEnemy(val, other); return false; } __state.ChangedMultiplier = true; __state.EnemyDamageMultiplier = __instance.enemyDamageMultiplier; __instance.enemyDamageMultiplier *= PluginSettings.GetEnemyDamageMultiplier(val.enemyType); return true; } private static bool IsPlayerExplosion(Explosion explosion) { if ((Object)(object)explosion == (Object)null || explosion.enemy) { return false; } if ((Object)(object)StuckDetonationContext.Current != (Object)null && StuckDetonationContext.CanCurrentBeamDetonate) { return true; } if ((Object)(object)explosion.sourceWeapon == (Object)null) { return false; } GameObject sourceWeapon = explosion.sourceWeapon; NewMovement instance = MonoSingleton<NewMovement>.Instance; if (!((Object)(object)instance != (Object)null) || (!((Object)(object)sourceWeapon == (Object)(object)((Component)instance).gameObject) && !sourceWeapon.transform.IsChildOf(((Component)instance).transform))) { return (Object)(object)sourceWeapon.GetComponentInParent<NewMovement>() != (Object)null; } return true; } private static Exception Finalizer(Explosion __instance, State __state, Exception __exception) { if (__state.ReplacesDirectHitBaseStyle) { GrenadeDirectHitStyleContext.Exit(); } 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); } return __exception; } } internal static class GrenadeDirectHitStyleContext { 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); } } [HarmonyPatch(typeof(StyleCalculator), "AddPoints")] internal static class GrenadeDirectHitBaseStylePatch { private static void Prefix(ref int points, string pointName) { if (GrenadeDirectHitStyleContext.Active && pointName == "ultrakill.explosionhit") { points = PluginSettings.DirectHitStylePoints; } } } internal sealed class GrenadeLauncherBlueShockwaveMarker : MonoBehaviour { } internal static class GrenadeLauncherBlueShockwaveContext { private static int depth; internal static bool Active => depth > 0; internal static void Enter() { depth++; } internal static void Exit() { if (depth > 0) { depth--; } } } [HarmonyPatch(typeof(PhysicalShockwave), "CheckCollision")] internal static class GrenadeLauncherPhysicalShockwavePatch { private static bool Prefix(PhysicalShockwave __instance, out bool __state) { __state = (Object)(object)__instance != (Object)null && (Object)(object)((Component)__instance).GetComponentInParent<GrenadeLauncherBlueShockwaveMarker>() != (Object)null; return !__state; } private static Exception Finalizer(bool __state, Exception __exception) { return __exception; } } [HarmonyPatch(typeof(Enemy), "HandleBloodSelection")] internal static class GrenadeLauncherBloodSelectionPatch { private static bool Prefix(ref GameObject __result) { if (!GrenadeLauncherBlueShockwaveContext.Active) { return true; } __result = null; return false; } } [HarmonyPatch(typeof(Enemy), "ProcessBloodEffects")] internal static class GrenadeLauncherBloodEffectsPatch { private static bool Prefix() { return !GrenadeLauncherBlueShockwaveContext.Active; } } [HarmonyPatch(typeof(Enemy), "PlayHurtSound")] internal static class GrenadeLauncherHurtSoundPatch { private static bool Prefix() { return !GrenadeLauncherBlueShockwaveContext.Active; } } [HarmonyPatch(typeof(Enemy), "BloodExplosion")] internal static class GrenadeLauncherBloodExplosionPatch { private static bool Prefix() { return !GrenadeLauncherBlueShockwaveContext.Active; } } [HarmonyPatch(typeof(BloodsplatterManager), "PlayBloodSound")] internal static class GrenadeLauncherBloodSoundPatch { private static bool Prefix() { return !GrenadeLauncherBlueShockwaveContext.Active; } } 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<int> walkingBombAwardedChains = new HashSet<int>(); 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<StyleHUD>.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", "<color=#00ffffff>PIPE DREAM</color>"); instance.RegisterStyleItem("grenadelauncher.moon_shot", "<color=#FFD700>MOON SHOT</color>"); instance.RegisterStyleItem("grenadelauncher.out_sniped", "<color=#FFD700>OUT-SNIPED</color>"); instance.RegisterStyleItem("grenadelauncher.walking_bomb", "<color=#00ffffff>WALKING BOMB</color>"); registeredHud = instance; } return instance; } } internal sealed class GrenadeLauncherExplosionMarker : MonoBehaviour { private static readonly Dictionary<int, GrenadeLauncherExplosionMarker> ActiveRoots = new Dictionary<int, GrenadeLauncherExplosionMarker>(); private readonly HashSet<int> manuallyDamagedEnemies = new HashSet<int>(); private readonly HashSet<int> styleAwardedEnemies = new HashSet<int>(); private bool walkingBombAwarded; 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 bool Airshot; internal bool BlueHookReplacement; private int rootId; private void Awake() { rootId = (((Object)(object)((Component)this).transform.root != (Object)null) ? ((Object)((Component)this).transform.root).GetInstanceID() : ((Object)((Component)this).gameObject).GetInstanceID()); ActiveRoots[rootId] = this; } private void OnDestroy() { if (rootId != 0 && ActiveRoots.TryGetValue(rootId, out var value) && (Object)(object)value == (Object)(object)this) { ActiveRoots.Remove(rootId); } } internal static GrenadeLauncherExplosionMarker TryGet(Explosion explosion) { if ((Object)(object)explosion == (Object)null) { return null; } int key = (((Object)(object)((Component)explosion).transform.root != (Object)null) ? ((Object)((Component)explosion).transform.root).GetInstanceID() : ((Object