using System; using System.Collections.Generic; using System.Diagnostics; using System.Reflection; using System.Runtime.CompilerServices; using System.Runtime.Versioning; using System.Security; using System.Security.Permissions; using System.Text; using BepInEx; using BepInEx.Configuration; using BepInEx.Logging; using HarmonyLib; using Microsoft.CodeAnalysis; using Pigeon.Math; using Pigeon.Movement; using Unity.Netcode; using UnityEngine; [assembly: CompilationRelaxations(8)] [assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)] [assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)] [assembly: IgnoresAccessChecksTo("Assembly-CSharp")] [assembly: TargetFramework(".NETStandard,Version=v2.1", FrameworkDisplayName = ".NET Standard 2.1")] [assembly: AssemblyCompany("SparrohsTurbocharges")] [assembly: AssemblyConfiguration("Release")] [assembly: AssemblyFileVersion("1.0.0.0")] [assembly: AssemblyInformationalVersion("1.0.0")] [assembly: AssemblyProduct("SparrohsTurbocharges")] [assembly: AssemblyTitle("SparrohsTurbocharges")] [assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)] [assembly: AssemblyVersion("1.0.0.0")] [module: UnverifiableCode] [module: RefSafetyRules(11)] namespace Microsoft.CodeAnalysis { [CompilerGenerated] [Embedded] internal sealed class EmbeddedAttribute : Attribute { } } namespace System.Runtime.CompilerServices { [CompilerGenerated] [Embedded] [AttributeUsage(AttributeTargets.Module, AllowMultiple = false, Inherited = false)] internal sealed class RefSafetyRulesAttribute : Attribute { public readonly int Version; public RefSafetyRulesAttribute(int P_0) { Version = P_0; } } } public static class AugerSubroutineTurbo { public const float DamageMult = 1.5f; public const float DurationMult = 1.25f; internal static readonly HashSet Armed = new HashSet(); internal static readonly HashSet BuffActive = new HashSet(); internal static readonly Dictionary SavedAugerMult = new Dictionary(); internal static readonly Dictionary SavedDuration = new Dictionary(); internal static readonly Dictionary SavedForwardBoostDamage = new Dictionary(); internal static readonly FieldInfo AugerMultField = typeof(Shocklance).GetField("augerAddedDamageMultiplier", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic) ?? AccessTools.Field(typeof(Shocklance), "augerAddedDamageMultiplier"); internal static readonly FieldInfo ForwardBoostTimeField = typeof(Shocklance).GetField("forwardBoostTime", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic) ?? AccessTools.Field(typeof(Shocklance), "forwardBoostTime"); internal static readonly FieldInfo IsBoostingField = typeof(Shocklance).GetField("isBoosting", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic) ?? AccessTools.Field(typeof(Shocklance), "isBoosting"); public static bool HasTurbo(Shocklance s) { if ((Object)(object)s != (Object)null) { if (!TurboHelpers.GearHasTurboNamed((IGear)(object)s, "Auger Subroutine")) { return TurboHelpers.GearHasTurboNamed((IGear)(object)s, "DrillBoost"); } return true; } return false; } public static void Arm(Shocklance s) { if ((Object)(object)s == (Object)null || !HasTurbo(s)) { return; } try { if (s.IsAugerActive) { return; } } catch { } int instanceID = ((Object)s).GetInstanceID(); Armed.Add(instanceID); try { Player player = ((Gun)s).Player; if ((Object)(object)player != (Object)null) { player.UpdateStackDisplay((object)typeof(UpgradeProperty_Shocklance_ForwardBoost), "Auger Boost", (Sprite)null, 1, 30f); } } catch { } ManualLogSource logger = SparrohPlugin.Logger; if (logger != null) { logger.LogInfo((object)"[Turbo] Auger Subroutine: armed for next Auger charge"); } } public static void BeginBuff(Shocklance s) { if ((Object)(object)s == (Object)null) { return; } int instanceID = ((Object)s).GetInstanceID(); if (!Armed.Contains(instanceID) || BuffActive.Contains(instanceID)) { return; } Armed.Remove(instanceID); BuffActive.Add(instanceID); float num = Mathf.Max(1.25f, TurboHelpers.Scale(1.5f)); float num2 = Mathf.Max(1.1f, TurboHelpers.Scale(1.25f)); try { float forwardBoostDamage = s.ShocklanceData.forwardBoostDamage; SavedForwardBoostDamage[instanceID] = forwardBoostDamage; s.ShocklanceData.forwardBoostDamage = forwardBoostDamage * num; ManualLogSource logger = SparrohPlugin.Logger; if (logger != null) { logger.LogInfo((object)$"[Turbo] Auger Subroutine: forwardBoostDamage {forwardBoostDamage:0.##} -> {forwardBoostDamage * num:0.##}"); } } catch { } try { if (AugerMultField != null) { float num3 = (float)AugerMultField.GetValue(s); SavedAugerMult[instanceID] = num3; AugerMultField.SetValue(s, num3 * num); } } catch { } try { float forwardBoostDuration = s.ShocklanceData.forwardBoostDuration; if (forwardBoostDuration > 0f) { SavedDuration[instanceID] = forwardBoostDuration; s.ShocklanceData.forwardBoostDuration = forwardBoostDuration * num2; if (ForwardBoostTimeField != null) { float num4 = (float)ForwardBoostTimeField.GetValue(s); ForwardBoostTimeField.SetValue(s, Mathf.Min(1f, num4 * num2)); } if (IsBoostingField != null) { float num5 = (float)IsBoostingField.GetValue(s); if (num5 > 0f) { IsBoostingField.SetValue(s, Mathf.Min(1f, num5 * num2)); } } } } catch { } try { Player player = ((Gun)s).Player; if (player != null) { player.RemoveStackDisplay((object)typeof(UpgradeProperty_Shocklance_ForwardBoost)); } } catch { } ManualLogSource logger2 = SparrohPlugin.Logger; if (logger2 != null) { logger2.LogInfo((object)$"[Turbo] Auger Subroutine: buff active dmg x{num:0.##} dur x{num2:0.##}"); } } public static void EndBuff(Shocklance s) { if ((Object)(object)s == (Object)null) { return; } int instanceID = ((Object)s).GetInstanceID(); if (!BuffActive.Contains(instanceID)) { return; } BuffActive.Remove(instanceID); try { if (SavedForwardBoostDamage.TryGetValue(instanceID, out var value)) { s.ShocklanceData.forwardBoostDamage = value; SavedForwardBoostDamage.Remove(instanceID); } } catch { } try { if (AugerMultField != null && SavedAugerMult.TryGetValue(instanceID, out var value2)) { AugerMultField.SetValue(s, value2); SavedAugerMult.Remove(instanceID); } } catch { } try { if (SavedDuration.TryGetValue(instanceID, out var value3)) { s.ShocklanceData.forwardBoostDuration = value3; SavedDuration.Remove(instanceID); } } catch { } ManualLogSource logger = SparrohPlugin.Logger; if (logger != null) { logger.LogInfo((object)"[Turbo] Auger Subroutine: buff consumed/restored"); } } } [HarmonyPatch(typeof(Shocklance), "OnFire")] public static class Shocklance_OnFire_AugerArm_Patch { [HarmonyPostfix] private static void Postfix(Shocklance __instance, int numBullets) { if (TurboHelpers.MasterEnabled && !((Object)(object)__instance == (Object)null)) { AugerSubroutineTurbo.Arm(__instance); } } } [HarmonyPatch(typeof(Shocklance), "OnActiveUpdate")] public static class Shocklance_OnActiveUpdate_AugerBuff_Patch { [HarmonyPostfix] private static void Postfix(Shocklance __instance) { if (TurboHelpers.MasterEnabled && !((Object)(object)__instance == (Object)null) && AugerSubroutineTurbo.HasTurbo(__instance)) { bool isAugerActive; try { isAugerActive = __instance.IsAugerActive; } catch { return; } if (isAugerActive) { AugerSubroutineTurbo.BeginBuff(__instance); } else { AugerSubroutineTurbo.EndBuff(__instance); } } } } [HarmonyPatch(typeof(Shocklance), "FixedUpdate")] public static class Shocklance_FixedUpdate_AugerBuff_Patch { [HarmonyPostfix] private static void Postfix(Shocklance __instance) { if (!TurboHelpers.MasterEnabled || (Object)(object)__instance == (Object)null || !AugerSubroutineTurbo.HasTurbo(__instance)) { return; } try { if (!__instance.IsAugerActive) { AugerSubroutineTurbo.EndBuff(__instance); } } catch { } } } public static class CarverTurbos { public const float DeflectChance = 0.35f; public const float NutritionAreaMult = 2.15f; public const float NutritionRangeMult = 2.15f; public const float NutritionDuration = 3f; public const float LockdownRotAmount = 12f; public const float RageDecayIntervalHeld = 0.55f; public const float RageDecayIntervalStowed = 1.35f; internal static readonly Dictionary NutritionExpiry = new Dictionary(); internal static readonly Dictionary RageNextDecay = new Dictionary(); private static readonly Dictionary FireSavedArea = new Dictionary(); private static readonly Dictionary FireSavedRange = new Dictionary(); internal static readonly FieldInfo RageField = AccessTools.Field(typeof(TheCarver), "rage"); private static readonly FieldInfo FullSaturationDurationField = typeof(StatusEffect).GetField("FullSaturationDuration", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic) ?? typeof(StatusEffect).GetField("fullSaturationDuration", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic); private static readonly FieldInfo LastAddTimeField = typeof(StatusEffect).GetField("lastAddTime", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic); internal static float LockdownArmUntil; public static bool HasNutritionTurbo(TheCarver carver) { return TurboHelpers.GearHasTurboNamed((IGear)(object)carver, "Nutrition Sampler"); } public static bool HasRageTurbo(TheCarver carver) { return TurboHelpers.GearHasTurboNamed((IGear)(object)carver, "Rage"); } public static bool HasLockdownTurbo(TheCarver carver) { return TurboHelpers.GearHasTurboNamed((IGear)(object)carver, "Lockdown"); } public static void ApplyRotToShackledEnemies(Vector3 position, float radius, float duration, IDamageSource source) { //IL_003b: Unknown result type (might be due to invalid IL or missing references) //IL_0052: Unknown result type (might be due to invalid IL or missing references) if (radius <= 0f || duration <= 0f || source == null) { return; } float num = Mathf.Max(15f, TurboHelpers.Scale(12f)); float num2 = Mathf.Max(0.5f, duration); try { List list = new List(); if (!IDamageSource.GetTargetsInSphere(position, radius, 344192, list, (TargetType)1)) { HashSet hashSet = new HashSet(); if (!IDamageSource.GetEnemiesInSphere(position, radius, 344192, hashSet)) { return; } foreach (EnemyBrain item in hashSet) { if ((Object)(object)((item != null) ? item.Core : null) != (Object)null && ((EnemyPart)item.Core).IsAlive) { list.Add((ITarget)(object)item.Core); } } } HashSet hashSet2 = new HashSet(); for (int i = 0; i < list.Count; i++) { ITarget val = list[i]; if (val == null || !val.IsAlive || val.IsPlayer() || !hashSet2.Add(val)) { continue; } try { ITarget.ApplyStatusEffect(val, (EffectType)7, num, source, (DamageFlags)0); SetRotDuration(val, num2); } catch { try { val.ApplyStatusEffect((EffectType)7, num, source, (DamageFlags)0); SetRotDuration(val, num2); } catch { } } } if (hashSet2.Count > 0) { ManualLogSource logger = SparrohPlugin.Logger; if (logger != null) { logger.LogInfo((object)$"[Turbo] Lockdown: applied Rot to {hashSet2.Count} target(s) for {num2:0.##}s"); } } } catch (Exception ex) { ManualLogSource logger2 = SparrohPlugin.Logger; if (logger2 != null) { logger2.LogWarning((object)("[Turbo] Lockdown Rot apply failed: " + ex.Message)); } } } private static void SetRotDuration(ITarget target, float duration) { if (target == null) { return; } try { Dictionary statusEffects = ITarget.GetStatusEffects(target); if (statusEffects != null && statusEffects.TryGetValue((EffectType)7, out var value) && value != null) { FullSaturationDurationField?.SetValue(value, duration); LastAddTimeField?.SetValue(value, Time.time); } } catch { } } public static bool IsNutritionActive(TheCarver carver) { if ((Object)(object)carver == (Object)null) { return false; } int instanceID = ((Object)carver).GetInstanceID(); if (NutritionExpiry.TryGetValue(instanceID, out var value)) { return Time.time < value; } return false; } public static float NutritionMult() { return Mathf.Max(1.5f, TurboHelpers.Scale(2.15f)); } public static float NutritionReachMult() { return Mathf.Max(1.5f, TurboHelpers.Scale(2.15f)); } public static void StartNutritionBuff(TheCarver carver) { if ((Object)(object)carver == (Object)null) { return; } int instanceID = ((Object)carver).GetInstanceID(); float num = Mathf.Max(1f, TurboHelpers.Scale(3f)); num = 3f; NutritionExpiry[instanceID] = Time.time + num; try { Player player = ((Gun)carver).Player; if ((Object)(object)player != (Object)null) { player.UpdateStackDisplay((object)typeof(UpgradeProperty_Carver_HealthDrop), "Nutrition", (Sprite)null, 1, num); } } catch { } ManualLogSource logger = SparrohPlugin.Logger; if (logger != null) { logger.LogInfo((object)$"[Turbo] Nutrition Sampler: saw area/reach x{NutritionMult():0.##} for {num:0.#}s"); } } public static void TickNutrition(TheCarver carver) { if ((Object)(object)carver == (Object)null) { return; } int instanceID = ((Object)carver).GetInstanceID(); if (!NutritionExpiry.TryGetValue(instanceID, out var value) || Time.time < value) { return; } NutritionExpiry.Remove(instanceID); try { Player player = ((Gun)carver).Player; if (player != null) { player.RemoveStackDisplay((object)typeof(UpgradeProperty_Carver_HealthDrop)); } } catch { } } public static void BeginFireNutritionScale(TheCarver carver) { //IL_002b: 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_0037: Unknown result type (might be due to invalid IL or missing references) //IL_0043: Unknown result type (might be due to invalid IL or missing references) //IL_004b: 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_005b: Unknown result type (might be due to invalid IL or missing references) //IL_0060: Unknown result type (might be due to invalid IL or missing references) //IL_006b: Unknown result type (might be due to invalid IL or missing references) //IL_0070: Unknown result type (might be due to invalid IL or missing references) //IL_0078: Unknown result type (might be due to invalid IL or missing references) //IL_00a9: Unknown result type (might be due to invalid IL or missing references) //IL_00ab: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)carver == (Object)null || !IsNutritionActive(carver)) { return; } int instanceID = ((Object)carver).GetInstanceID(); float num = NutritionMult(); float num2 = NutritionReachMult(); try { Vector3 damageArea = carver.Data.damageArea; FireSavedArea[instanceID] = damageArea; carver.Data.damageArea = new Vector3(damageArea.x * num, damageArea.y * num, damageArea.z * num); RangeData rangeData = ((Gun)carver).GunData.rangeData; FireSavedRange[instanceID] = rangeData; rangeData.falloffStartDistance *= num2; rangeData.falloffEndDistance *= num2; rangeData.maxDamageRange *= num2; ((Gun)carver).GunData.rangeData = rangeData; } catch { FireSavedArea.Remove(instanceID); FireSavedRange.Remove(instanceID); } } public static void EndFireNutritionScale(TheCarver carver) { //IL_0026: Unknown result type (might be due to invalid IL or missing references) //IL_0027: Unknown result type (might be due to invalid IL or missing references) //IL_0041: Unknown result type (might be due to invalid IL or missing references) //IL_0042: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)carver == (Object)null) { return; } int instanceID = ((Object)carver).GetInstanceID(); try { if (FireSavedArea.TryGetValue(instanceID, out var value)) { carver.Data.damageArea = value; } if (FireSavedRange.TryGetValue(instanceID, out var value2)) { ((Gun)carver).GunData.rangeData = value2; } } catch { } FireSavedArea.Remove(instanceID); FireSavedRange.Remove(instanceID); } } [HarmonyPatch(typeof(Gun), "OnUpgradesEnabled")] public static class Carver_Gun_OnUpgradesEnabled_Patch { [HarmonyPostfix] private static void Postfix(Gun __instance) { if (!TurboHelpers.MasterEnabled || (Object)(object)__instance == (Object)null) { return; } _ = __instance is TheCarver; TheCarver val = (TheCarver)(object)((__instance is TheCarver) ? __instance : null); if (val != null && (CarverTurbos.HasNutritionTurbo(val) || CarverTurbos.HasRageTurbo(val) || CarverTurbos.HasLockdownTurbo(val))) { ((Gun)val).SetUpgradeFlag_Owner((GearUpgradeFlags)268435456, true); } if (TurboHelpers.GearHasTurboNamed((IGear)(object)__instance, "Super Magnet")) { __instance.SetUpgradeFlag_Owner((GearUpgradeFlags)268435456, true); } if (TurboHelpers.GearHasTurboNamed((IGear)(object)__instance, "Deflector")) { Player player = __instance.Player; if ((Object)(object)player != (Object)null) { player.OnBeforeTakeDamage += OnDeflectIncoming; } } } private static void OnDeflectIncoming(ref DamageData damage, ref IDamageSource source) { if (!(Random.value > Mathf.Clamp01(TurboHelpers.Scale(0.35f)))) { damage.damage = 0f; damage.effectAmount = 0f; } } } [HarmonyPatch(typeof(TheCarver), "OnActiveUpdate")] public static class TheCarver_OnActiveUpdate_LockdownArm_Patch { [HarmonyPrefix] private static void Prefix(TheCarver __instance) { //IL_0051: Unknown result type (might be due to invalid IL or missing references) //IL_0056: Unknown result type (might be due to invalid IL or missing references) if (!TurboHelpers.MasterEnabled || (Object)(object)__instance == (Object)null || !CarverTurbos.HasLockdownTurbo(__instance)) { return; } try { if (!((Object)(object)((Gun)__instance).Player == (Object)null) && ((NetworkBehaviour)((Gun)__instance).Player).IsLocalPlayer && !(__instance.Data.shackleDuration <= 0f)) { PlayerActions player = PlayerInput.Controls.Player; if (((PlayerActions)(ref player)).Aim.WasPerformedThisFrame()) { CarverTurbos.LockdownArmUntil = Time.time + 0.2f; } } } catch { } } } [HarmonyPatch(typeof(GameManager), "FloatEnemies_Rpc")] public static class GameManager_FloatEnemies_Lockdown_Patch { [HarmonyPostfix] private static void Postfix(Vector3 position, float radius, float duration, float detachChance) { //IL_0079: Unknown result type (might be due to invalid IL or missing references) if (!TurboHelpers.MasterEnabled || Time.time > CarverTurbos.LockdownArmUntil) { return; } CarverTurbos.LockdownArmUntil = 0f; TheCarver val = FindLocalLockdownCarver(); if ((Object)(object)val == (Object)null) { return; } float duration2 = duration; try { if (val.Data.shackleDuration > 0f) { duration2 = val.Data.shackleDuration; } } catch { } float radius2 = radius; try { if (val.Data.shackleRadius > 0f) { radius2 = val.Data.shackleRadius; } } catch { } CarverTurbos.ApplyRotToShackledEnemies(position, radius2, duration2, (IDamageSource)(object)val); } private static TheCarver FindLocalLockdownCarver() { try { Player localPlayer = Player.LocalPlayer; if ((Object)(object)localPlayer == (Object)null || localPlayer.Gear == null) { return null; } for (int i = 0; i < localPlayer.Gear.Length; i++) { IGear obj = localPlayer.Gear[i]; TheCarver val = (TheCarver)(object)((obj is TheCarver) ? obj : null); if (val != null && CarverTurbos.HasLockdownTurbo(val)) { return val; } } } catch { } return null; } } [HarmonyPatch(typeof(Player), "HealFromCollectable")] public static class Player_HealFromCollectable_Nutrition_Patch { [HarmonyPostfix] private static void Postfix(Player __instance) { TryStartNutrition(__instance); } internal static void TryStartNutrition(Player player) { if (TurboHelpers.MasterEnabled && !((Object)(object)player == (Object)null)) { TheCarver val = FindCarverWithNutrition(player); if (!((Object)(object)val == (Object)null)) { CarverTurbos.StartNutritionBuff(val); } } } internal static TheCarver FindCarverWithNutrition(Player player) { try { if (player.Gear == null) { return null; } for (int i = 0; i < player.Gear.Length; i++) { IGear obj = player.Gear[i]; TheCarver val = (TheCarver)(object)((obj is TheCarver) ? obj : null); if (val != null && CarverTurbos.HasNutritionTurbo(val)) { return val; } } } catch { } return null; } } [HarmonyPatch(typeof(HealingCollectable), "TryCollect")] public static class HealingCollectable_TryCollect_Nutrition_Patch { [HarmonyPostfix] private static void Postfix(HealingCollectable __instance, Player player, bool __result) { if (__result && !((Object)(object)player == (Object)null)) { Player_HealFromCollectable_Nutrition_Patch.TryStartNutrition(player); } } } [HarmonyPatch(typeof(Player), "Heal")] public static class Player_Heal_NutritionSampler_Patch { [HarmonyPostfix] private static void Postfix(Player __instance) { Player_HealFromCollectable_Nutrition_Patch.TryStartNutrition(__instance); } } [HarmonyPatch(typeof(TheCarver), "Update")] public static class TheCarver_Update_Nutrition_Patch { [HarmonyPostfix] private static void Postfix(TheCarver __instance) { if (TurboHelpers.MasterEnabled && !((Object)(object)__instance == (Object)null)) { CarverTurbos.TickNutrition(__instance); } } } [HarmonyPatch(typeof(TheCarver), "FireBullet")] public static class TheCarver_FireBullet_Nutrition_Patch { [HarmonyPrefix] private static void Prefix(TheCarver __instance) { if (TurboHelpers.MasterEnabled && !((Object)(object)__instance == (Object)null)) { CarverTurbos.BeginFireNutritionScale(__instance); } } [HarmonyPostfix] private static void Postfix(TheCarver __instance) { if (!((Object)(object)__instance == (Object)null)) { CarverTurbos.EndFireNutritionScale(__instance); } } } [HarmonyPatch(typeof(TheCarver), "UpdateRageStacks")] public static class TheCarver_UpdateRageStacks_Turbo_Patch { [HarmonyPrefix] private static bool Prefix(TheCarver __instance) { if (!TurboHelpers.MasterEnabled || (Object)(object)__instance == (Object)null) { return true; } if (!CarverTurbos.HasRageTurbo(__instance)) { return true; } if (CarverTurbos.RageField == null) { return true; } float num; try { num = (float)CarverTurbos.RageField.GetValue(__instance); } catch { return true; } if (num <= 0f) { return false; } float lastFireTime; try { lastFireTime = ((Gun)__instance).LastFireTime; } catch { return true; } if (Time.time - lastFireTime <= 5f) { return false; } int instanceID = ((Object)__instance).GetInstanceID(); float num2 = (((Gun)__instance).Active ? 0.55f : 1.35f); num2 = Mathf.Max(0.25f, num2 / Mathf.Max(0.5f, TurboHelpers.Strength)); if (!CarverTurbos.RageNextDecay.TryGetValue(instanceID, out var value)) { value = 0f; } if (Time.time < value) { return false; } CarverTurbos.RageNextDecay[instanceID] = Time.time + num2; num = Mathf.Max(0f, num - 1f); try { CarverTurbos.RageField.SetValue(__instance, num); } catch { return false; } Player player = ((Gun)__instance).Player; if ((Object)(object)player == (Object)null) { return false; } if (num <= 0f) { player.RemoveStackDisplay((object)typeof(UpgradeProperty_Carver_Rage)); CarverTurbos.RageNextDecay.Remove(instanceID); } else { try { player.UpdateStackDisplay((object)typeof(UpgradeProperty_Carver_Rage), TextBlocks.GetString("Rage", 0), UpgradeProperty_Carver_Rage.Icon, (int)num, 0f); } catch { } } return false; } } public static class CyclerTurbos { private static readonly FieldInfo MaxBulletsFromSiphonField = AccessTools.Field(typeof(CartridgeSMG), "maxBulletsFromSiphon"); public static EffectType GetScorchingTurboTrigger(UpgradeInstance upgrade) { if (upgrade != null) { Random val = default(Random); ((Random)(ref val))..ctor(upgrade.Seed ^ 0x5C0C4D37); if (((Random)(ref val)).Next(0, 2) == 0) { return (EffectType)2; } return (EffectType)3; } return (EffectType)2; } public static string GetScorchingElementLabel(UpgradeInstance upgrade) { //IL_0001: Unknown result type (might be due to invalid IL or missing references) //IL_0007: Invalid comparison between Unknown and I4 if ((int)GetScorchingTurboTrigger(upgrade) != 3) { return "Shock"; } return "Acid"; } public static void UncapSiphonMagazine(CartridgeSMG smg) { if ((Object)(object)smg == (Object)null || MaxBulletsFromSiphonField == null) { return; } try { MaxBulletsFromSiphonField.SetValue(smg, 999999); } catch { } } } [HarmonyPatch(typeof(CartridgeSMG), "OnUpgradesEnabled")] public static class CartridgeSMG_OnUpgradesEnabled_Turbo_Patch { [HarmonyPostfix] private static void Postfix(CartridgeSMG __instance) { if (TurboHelpers.MasterEnabled && !((Object)(object)__instance == (Object)null) && TurboHelpers.GearHasTurboNamed((IGear)(object)__instance, "Corrode Siphon")) { CyclerTurbos.UncapSiphonMagazine(__instance); } } } [HarmonyPatch(typeof(CartridgeSMG), "HandleOnBeforeDamageUpgrades")] public static class ScorchingDetonation_BeforeDamage_Turbo_Patch { [HarmonyPostfix] private static void Postfix(CartridgeSMG __instance, ref DamageCallbackData data) { //IL_0093: Unknown result type (might be due to invalid IL or missing references) //IL_0098: Unknown result type (might be due to invalid IL or missing references) //IL_00bf: Unknown result type (might be due to invalid IL or missing references) if (!TurboHelpers.MasterEnabled || (Object)(object)__instance == (Object)null || !TurboHelpers.GearHasTurboNamed((IGear)(object)__instance, "Scorching Detonation")) { return; } UpgradeInstance upgrade = null; try { foreach (UpgradeInstance activeUpgrade in ((Gun)__instance).ActiveUpgrades) { if (activeUpgrade != null && activeUpgrade.IsTurbocharged && (TurboHelpers.ApiMatches(activeUpgrade.Upgrade, "Scorching Detonation") || TurboHelpers.HasPropertyType(activeUpgrade.Upgrade))) { upgrade = activeUpgrade; break; } } } catch { } EffectType scorchingTurboTrigger = CyclerTurbos.GetScorchingTurboTrigger(upgrade); FieldInfo fieldInfo = AccessTools.Field(typeof(CartridgeSMG), "isDamagedTargetIgnited"); if (fieldInfo != null) { fieldInfo.SetValue(__instance, ITarget.IsSaturated(data.target, scorchingTurboTrigger)); } } } [HarmonyPatch(typeof(CartridgeSMG), "ApplyFireOnIgnite")] public static class ViolentIgnition_ApplyFireOnIgnite_Turbo_Patch { [HarmonyPrefix] private static bool Prefix(CartridgeSMG __instance, in EffectCallbackData effectData) { //IL_002b: Unknown result type (might be due to invalid IL or missing references) //IL_0031: Invalid comparison between Unknown and I4 //IL_0036: Unknown result type (might be due to invalid IL or missing references) //IL_003c: Unknown result type (might be due to invalid IL or missing references) //IL_008c: Unknown result type (might be due to invalid IL or missing references) //IL_008e: Unknown result type (might be due to invalid IL or missing references) if (!TurboHelpers.MasterEnabled || (Object)(object)__instance == (Object)null) { return true; } if (!TurboHelpers.GearHasTurboNamed((IGear)(object)__instance, "Violent Ignition")) { return true; } if ((int)effectData.effect != 1) { return true; } if ((effectData.flags & 4) != 0) { return true; } ITarget target = effectData.target; if (target != null) { float value = Mathf.Max(__instance.Data.applyFireOnIgniteAmount * 8f, ((Gun)__instance).GunData.damage * 2f); value = TurboHelpers.Scale(value); DamageData val = default(DamageData); ((DamageData)(ref val))..ctor(value, (EffectType)1, 0f, (DamageFlags)20); IDamageSource.DamageTarget((IDamageSource)(object)__instance, target, val, effectData.position, (Collider)null); } return true; } } public static class FlashStormTurbo { public const float FlatStrikeDamage = 40f; private static readonly FieldInfo BulletDataField = AccessTools.Field(typeof(SimpleProjectileBullet), "data") ?? typeof(SimpleProjectileBullet).GetField("data", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic); private static readonly Dictionary SavedDamage = new Dictionary(); private static int _logCount; public static float BonusDamage() { return Mathf.Max(10f, TurboHelpers.Scale(40f)); } public static bool GearHasFlashStorm(IGear gear) { if (gear != null) { if (!TurboHelpers.GearHasTurboNamed(gear, "Flash Storm")) { return TurboHelpers.GearHasTurboNamed(gear, "DownStrike"); } return true; } return false; } public static bool TryGetVoltaicWithTurbo(VoltaicGrenadeBullet bullet, out VoltaicGrenade grenade) { //IL_0037: Unknown result type (might be due to invalid IL or missing references) grenade = null; if (!TurboHelpers.MasterEnabled || (Object)(object)bullet == (Object)null) { return false; } try { IDamageSource parentSource = ((SimpleProjectileBullet)bullet).ParentSource; VoltaicGrenade val = (VoltaicGrenade)(object)((parentSource is VoltaicGrenade) ? parentSource : null); if (val == null) { return false; } if (!GearHasFlashStorm((IGear)(object)val)) { return false; } try { if (!UpgradeFlagsExtensions.IsEnabled(((SimpleProjectileBullet)bullet).UpgradeFlags, (VoltaicGrenadeUpgradeFlags)8)) { return false; } } catch { } grenade = val; return true; } catch { return false; } } public static void BeginStrikeBoost(VoltaicGrenadeBullet bullet) { //IL_0038: Unknown result type (might be due to invalid IL or missing references) //IL_003d: Unknown result type (might be due to invalid IL or missing references) //IL_005d: Unknown result type (might be due to invalid IL or missing references) //IL_006f: Unknown result type (might be due to invalid IL or missing references) //IL_008a: Unknown result type (might be due to invalid IL or missing references) //IL_00c0: Unknown result type (might be due to invalid IL or missing references) if (BulletDataField == null || (Object)(object)bullet == (Object)null || !TryGetVoltaicWithTurbo(bullet, out var _)) { return; } try { object value = BulletDataField.GetValue(bullet); if (value == null) { return; } BulletData val = (BulletData)value; int instanceID = ((Object)bullet).GetInstanceID(); if (SavedDamage.ContainsKey(instanceID)) { return; } SavedDamage[instanceID] = val.damage; float num = BonusDamage(); float damage = val.damage; val.damage += num; BulletDataField.SetValue(bullet, val); if (_logCount < 8) { _logCount++; ManualLogSource logger = SparrohPlugin.Logger; if (logger != null) { logger.LogInfo((object)$"[Turbo] Flash Storm: strike data.damage {damage:0.#} -> {val.damage:0.#} (+{num:0.#})"); } } } catch (Exception ex) { ManualLogSource logger2 = SparrohPlugin.Logger; if (logger2 != null) { logger2.LogWarning((object)("[Turbo] Flash Storm begin boost failed: " + ex.Message)); } } } public static void EndStrikeBoost(VoltaicGrenadeBullet bullet) { //IL_004c: Unknown result type (might be due to invalid IL or missing references) //IL_0051: Unknown result type (might be due to invalid IL or missing references) //IL_0060: Unknown result type (might be due to invalid IL or missing references) if (BulletDataField == null || (Object)(object)bullet == (Object)null) { return; } int instanceID = ((Object)bullet).GetInstanceID(); if (!SavedDamage.TryGetValue(instanceID, out var value)) { return; } SavedDamage.Remove(instanceID); try { object value2 = BulletDataField.GetValue(bullet); if (value2 != null) { BulletData val = (BulletData)value2; val.damage = value; BulletDataField.SetValue(bullet, val); } } catch { } } } [HarmonyPatch(typeof(VoltaicGrenadeBullet), "HandleCollisions")] public static class VoltaicGrenadeBullet_HandleCollisions_FlashStorm_Patch { [HarmonyPrefix] private static void Prefix(VoltaicGrenadeBullet __instance) { FlashStormTurbo.BeginStrikeBoost(__instance); } [HarmonyPostfix] private static void Postfix(VoltaicGrenadeBullet __instance) { FlashStormTurbo.EndStrikeBoost(__instance); } [HarmonyFinalizer] private static void Finalizer(VoltaicGrenadeBullet __instance) { FlashStormTurbo.EndStrikeBoost(__instance); } } public static class GenericStatTurbos { public const float HeavyMunitionsFlatDamage = 85f; public const float HeavyMunitionsKnockback = 22f; public const float MissileBayFireIntervalMult = 0.65f; public const float MissileBayRecoilMult = 0.35f; public const float TinderboxMaxDamageMult = 2f; public const float BatteryRecursionChargeMult = 1.75f; public const int ClusterBombCountBonus = 3; public const float HarmonizerChanceBonus = 0.25f; public const int GrenadeBeltExtraCharges = 1; public const float OverclockSizeMult = 1.5f; public const float OverclockDamageMult = 1.5f; public const float FlashStormFlatDamage = 40f; public const float LinkedListPerTumbleDamage = 0.12f; public const float LinkedListPerTumbleSize = 0.1f; public const float PocketGrenadeRechargeChance = 0.35f; public const float ExplosivePelletsSizeAdd = 1.35f; public const float AugerDamageMult = 1.75f; public const float SlipspaceStackConsumeMult = 0.5f; public const float HeavySupportMagMult = 2f; public const float CableShareMult = 1.5f; internal static readonly HashSet OneShotApplied = new HashSet(); } [HarmonyPatch(typeof(Gun), "OnUpgradesEnabled")] public static class Gun_OnUpgradesEnabled_GenericTurbo_Patch { [HarmonyPostfix] private static void Postfix(Gun __instance) { if (!TurboHelpers.MasterEnabled || (Object)(object)__instance == (Object)null) { return; } try { ApplyGunTurbos(__instance); } catch (Exception ex) { ManualLogSource logger = SparrohPlugin.Logger; if (logger != null) { logger.LogWarning((object)("[Turbo] Gun turbo apply failed on " + ((object)__instance).GetType().Name + ": " + ex.Message)); } } } private static void ApplyGunTurbos(Gun gun) { //IL_0067: Unknown result type (might be due to invalid IL or missing references) //IL_006d: Unknown result type (might be due to invalid IL or missing references) //IL_0072: Unknown result type (might be due to invalid IL or missing references) //IL_0088: Unknown result type (might be due to invalid IL or missing references) //IL_008e: Unknown result type (might be due to invalid IL or missing references) //IL_0093: Unknown result type (might be due to invalid IL or missing references) //IL_00a9: Unknown result type (might be due to invalid IL or missing references) //IL_00af: Unknown result type (might be due to invalid IL or missing references) //IL_00b4: Unknown result type (might be due to invalid IL or missing references) //IL_00ca: Unknown result type (might be due to invalid IL or missing references) //IL_00d0: Unknown result type (might be due to invalid IL or missing references) //IL_00d5: Unknown result type (might be due to invalid IL or missing references) if (TurboHelpers.GearHasTurboNamed((IGear)(object)gun, "Missile Bay")) { gun.GunData.fireInterval *= Mathf.Max(0.35f, TurboHelpers.Scale(0.65f)); float num = Mathf.Clamp(TurboHelpers.Scale(0.35f), 0.1f, 1f); ref Vector2 recoilX = ref gun.GunData.recoilData.recoilX; recoilX *= num; ref Vector2 recoilY = ref gun.GunData.recoilData.recoilY; recoilY *= num; ref Vector2 recoilZ = ref gun.GunData.recoilData.recoilZ; recoilZ *= num; ref Vector2 translateZ = ref gun.GunData.recoilData.translateZ; translateZ *= num; } if (TurboHelpers.GearHasTurboNamed((IGear)(object)gun, "Battery Recursion") && gun.GunData.chargeData.duration > 0f) { gun.GunData.chargeData.duration /= TurboHelpers.Scale(1.75f); } if (TurboHelpers.GearHasTurboNamed((IGear)(object)gun, "Explosive Pellets")) { gun.GunData.hitVFXSize *= TurboHelpers.Scale(1.35f); gun.GunData.bulletMagnetismTarget *= TurboHelpers.Scale(1.25f); } Shocklance val = (Shocklance)(object)((gun is Shocklance) ? gun : null); if (val != null && TurboHelpers.GearHasTurboNamed((IGear)(object)gun, "Laying Cable")) { float num2 = TurboHelpers.Scale(1.5f); val.ShocklanceData.cableDistance *= num2; val.ShocklanceData.cableDamageMult *= num2; val.ShocklanceData.cableDamageResist *= num2; val.ShocklanceData.cableAbilityRecharge *= num2; } } } [HarmonyPatch(typeof(Throwable), "OnUpgradesEnabled")] public static class Throwable_OnUpgradesEnabled_GenericTurbo_Patch { [HarmonyPostfix] private static void Postfix(Throwable __instance) { if (!TurboHelpers.MasterEnabled || (Object)(object)__instance == (Object)null) { return; } try { ApplyThrowableTurbos(__instance); } catch (Exception ex) { ManualLogSource logger = SparrohPlugin.Logger; if (logger != null) { logger.LogWarning((object)("[Turbo] Throwable turbo apply failed on " + ((object)__instance).GetType().Name + ": " + ex.Message)); } } } private static void ApplyThrowableTurbos(Throwable gear) { if (TurboHelpers.GearHasTurboNamed((IGear)(object)gear, "Grenade Belt")) { gear.CooldownData.maxCharges += TurboHelpers.ScaleInt(1); ((CooldownData)(ref gear.CooldownData)).AddCharge(TurboHelpers.Scale(1f)); } IncendiaryGrenade val = (IncendiaryGrenade)(object)((gear is IncendiaryGrenade) ? gear : null); if (val != null && TurboHelpers.GearHasTurboNamed((IGear)(object)gear, "Cluster Bomb")) { val.GrenadeData.clusterSplitCount += TurboHelpers.ScaleInt(3); } AcidGrenade val2 = (AcidGrenade)(object)((gear is AcidGrenade) ? gear : null); if (val2 != null) { if (TurboHelpers.GearHasTurboNamed((IGear)(object)gear, "Overclock")) { ((Throwable)val2).GunData.damage *= TurboHelpers.Scale(1.5f); ((Throwable)val2).GunData.hitVFXSize *= TurboHelpers.Scale(1.5f); } if (TurboHelpers.GearHasTurboNamed((IGear)(object)gear, "Heavy Support")) { ((Throwable)val2).SetUpgradeFlag_Owner((GearUpgradeFlags)268435456, true); } } PhotonDisc val3 = (PhotonDisc)(object)((gear is PhotonDisc) ? gear : null); if (val3 != null) { if (TurboHelpers.GearHasTurboNamed((IGear)(object)gear, "Harmonizer")) { val3.GrenadeData.switchDmgToAttunedElementChance += TurboHelpers.Scale(0.25f); } if (TurboHelpers.GearHasTurboNamed((IGear)(object)gear, "Linked List")) { int num = Mathf.Max(1, val3.GrenadeData.linkedListCount); ((Throwable)val3).GunData.damage *= 1f + (float)num * TurboHelpers.Scale(0.12f); ((Throwable)val3).GunData.hitVFXSize *= 1f + (float)num * TurboHelpers.Scale(0.1f); } if (TurboHelpers.GearHasTurboNamed((IGear)(object)gear, "Pocket Grenade")) { gear.SetUpgradeFlag_Owner((GearUpgradeFlags)268435456, true); } } if (TurboHelpers.GearHasTurboNamed((IGear)(object)gear, "Live Wire")) { gear.SetUpgradeFlag_Owner((GearUpgradeFlags)268435456, true); } } } [HarmonyPatch(typeof(Throwable), "Fire")] public static class Throwable_Fire_PocketGrenade_Patch { [HarmonyPostfix] private static void Postfix(Throwable __instance) { if (!TurboHelpers.MasterEnabled || (Object)(object)__instance == (Object)null || !(__instance is PhotonDisc) || (!TurboHelpers.GearHasTurboNamed((IGear)(object)__instance, "Pocket Grenade") && !TurboHelpers.GearHasTurboNamed((IGear)(object)__instance, "MiniDisc"))) { return; } float num = Mathf.Clamp01(TurboHelpers.Scale(0.35f)); if (Random.value > num) { return; } try { __instance.AddCharge(1f); ManualLogSource logger = SparrohPlugin.Logger; if (logger != null) { logger.LogInfo((object)"[Turbo] Pocket Grenade: refunded 1 disc charge"); } } catch { try { ((CooldownData)(ref __instance.CooldownData)).AddCharge(1f); } catch { } } } } [HarmonyPatch(typeof(Gun), "OnUpgradesEnabled")] public static class Gun_HeavySupport_Turbo_Patch { [HarmonyPostfix] private static void Postfix(Gun __instance) { if (TurboHelpers.MasterEnabled && !((Object)(object)__instance == (Object)null) && IsHeavyWeapon(__instance) && (TurboHelpers.PlayerHasTurboNamed(__instance.Player, "Heavy Support") || PlayerHasHeavySupportTurbo(__instance))) { __instance.GunData.magazineSize = Mathf.RoundToInt((float)__instance.GunData.magazineSize * TurboHelpers.Scale(2f)); __instance.RemainingAmmo = __instance.GunData.magazineSize; } } private static bool IsHeavyWeapon(Gun gun) { try { if (((object)gun).GetType().Name.IndexOf("heavy", StringComparison.OrdinalIgnoreCase) >= 0) { return true; } } catch { } try { GearInfo info = gun.Info; string text = ((info != null) ? info.Name : null); if (!string.IsNullOrEmpty(text) && text.IndexOf("heavy", StringComparison.OrdinalIgnoreCase) >= 0) { return true; } } catch { } return false; } private static bool PlayerHasHeavySupportTurbo(Gun gun) { try { Player player = gun.Player; if ((Object)(object)player == (Object)null || player.Gear == null) { return false; } for (int i = 0; i < player.Gear.Length; i++) { IGear val = player.Gear[i]; if (val != null && TurboHelpers.GearHasTurboNamed(val, "Heavy Support")) { return true; } } } catch { } return false; } } public static class GlobulousSiphonTurbo { public const float ChargeCostMult = 0.75f; public static float RefundFraction { get { float num = Mathf.Clamp(0.75f / Mathf.Max(0.5f, TurboHelpers.Strength), 0.5f, 0.95f); return Mathf.Clamp01(1f - num); } } } [HarmonyPatch(typeof(Globbler), "OnActiveUpdate")] public static class Globbler_OnActiveUpdate_GlobulousSiphon_Patch { private static readonly FieldInfo IsSiphoningField = AccessTools.Field(typeof(Globbler), "isSiphoningGrenade"); private static readonly Dictionary ChargeBeforeByInstance = new Dictionary(); [HarmonyPrefix] private static void Prefix(Globbler __instance) { if (!TurboHelpers.MasterEnabled || (Object)(object)__instance == (Object)null || !TurboHelpers.GearHasTurboNamed((IGear)(object)__instance, "Globulous Siphon")) { return; } try { IActivatedAbility ability; if (!IsSiphoning(__instance)) { ChargeBeforeByInstance.Remove(((Object)__instance).GetInstanceID()); } else if (TryGetThrowableAbility(__instance, out ability)) { ChargeBeforeByInstance[((Object)__instance).GetInstanceID()] = ability.Charge; } } catch { } } [HarmonyPostfix] private static void Postfix(Globbler __instance) { if (!TurboHelpers.MasterEnabled || (Object)(object)__instance == (Object)null) { return; } int instanceID = ((Object)__instance).GetInstanceID(); if (!ChargeBeforeByInstance.TryGetValue(instanceID, out var value)) { return; } ChargeBeforeByInstance.Remove(instanceID); if (!TurboHelpers.GearHasTurboNamed((IGear)(object)__instance, "Globulous Siphon")) { return; } try { if (!TryGetThrowableAbility(__instance, out var ability)) { return; } float charge = ability.Charge; float num = value - charge; if (!(num <= 0.0001f)) { float num2 = num * GlobulousSiphonTurbo.RefundFraction; if (!(num2 <= 0f)) { ability.AddCharge(num2); } } } catch { } } private static bool IsSiphoning(Globbler globbler) { if (IsSiphoningField == null) { return false; } try { return (bool)IsSiphoningField.GetValue(globbler); } catch { return false; } } private static bool TryGetThrowableAbility(Globbler gun, out IActivatedAbility ability) { ability = null; try { Player player = ((Gun)gun).Player; if ((Object)(object)player == (Object)null) { return false; } IGear throwableGear = player.ThrowableGear; IActivatedAbility val = (IActivatedAbility)(object)((throwableGear is IActivatedAbility) ? throwableGear : null); if (val != null) { ability = val; return true; } } catch { } return false; } } public static class HearthAndHomeTurbo { public const float HealPerSecond = 12f; public const float HealTickInterval = 0.25f; private static readonly FieldInfo FireAreaField = typeof(IncendiaryGrenade).GetField("fireArea", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic); private static readonly Dictionary NextHealTime = new Dictionary(); public static bool HasTurbo(IncendiaryGrenade g) { if (!TurboHelpers.GearHasTurboNamed((IGear)(object)g, "Hearth and Home")) { return TurboHelpers.GearHasTurboNamed((IGear)(object)g, "FireArea"); } return true; } public static bool TryGetFireArea(IncendiaryGrenade g, out MeshRenderer area) { area = null; if (FireAreaField == null || (Object)(object)g == (Object)null) { return false; } try { object? value = FireAreaField.GetValue(g); area = (MeshRenderer)((value is MeshRenderer) ? value : null); return (Object)(object)area != (Object)null && (Object)(object)((Component)area).gameObject != (Object)null && ((Component)area).gameObject.activeSelf; } catch { return false; } } public static float GetFireAreaRadius(IncendiaryGrenade g) { try { return ((Throwable)g).GunData.hitForce * g.GrenadeData.fireAreaRadius; } catch { return 0f; } } public static void TickHeal(IncendiaryGrenade g) { //IL_00d4: Unknown result type (might be due to invalid IL or missing references) //IL_00d9: Unknown result type (might be due to invalid IL or missing references) //IL_00db: Unknown result type (might be due to invalid IL or missing references) //IL_00e0: Unknown result type (might be due to invalid IL or missing references) //IL_00a5: Unknown result type (might be due to invalid IL or missing references) //IL_00aa: Unknown result type (might be due to invalid IL or missing references) if (!TurboHelpers.MasterEnabled || (Object)(object)g == (Object)null || !((NetworkBehaviour)g).IsOwner || !HasTurbo(g) || !TryGetFireArea(g, out var area)) { return; } float fireAreaRadius = GetFireAreaRadius(g); if (fireAreaRadius <= 0f) { return; } int instanceID = ((Object)g).GetInstanceID(); if (!NextHealTime.TryGetValue(instanceID, out var value)) { value = 0f; } if (Time.time < value) { return; } float num = Mathf.Max(0.1f, 0.25f); NextHealTime[instanceID] = Time.time + num; float num2 = Mathf.Max(1f, TurboHelpers.Scale(12f) * num); Vector3 localPosition = ((Component)area).transform.localPosition; try { IDamageSource.HealTargetsInSphere((IDamageSource)(object)g, ref localPosition, fireAreaRadius, (TargetType)2, num2, 0f); } catch { try { Player player = ((Throwable)g).Player; if ((Object)(object)player != (Object)null) { Vector3 val = player.InterpolatedPosition - localPosition; if (((Vector3)(ref val)).sqrMagnitude < fireAreaRadius * fireAreaRadius) { player.Heal(num2, (IDamageSource)(object)g); } } } catch { } } } } [HarmonyPatch(typeof(IncendiaryGrenade), "Update")] public static class IncendiaryGrenade_Update_HearthAndHome_Patch { [HarmonyPostfix] private static void Postfix(IncendiaryGrenade __instance) { HearthAndHomeTurbo.TickHeal(__instance); } } public static class HeavyMunitionsTurbo { public const float FlatDamage = 85f; public const float KnockbackForce = 22f; public const float UpwardBias = 0.4f; private static readonly PropertyInfo RigidbodyVelocityProp = typeof(Rigidbody).GetProperty("linearVelocity", BindingFlags.Instance | BindingFlags.Public) ?? typeof(Rigidbody).GetProperty("velocity", BindingFlags.Instance | BindingFlags.Public); public static bool TryGetHeavyMunitionsGun(IDamageSource source, out Gun gun) { gun = null; IDamageSource val = source; int num = 0; while (val != null && num++ < 8) { Gun val2 = (Gun)(object)((val is Gun) ? val : null); if (val2 != null && TurboHelpers.GearHasTurboNamed((IGear)(object)val2, "Heavy Munitions")) { gun = val2; return true; } try { val = val.ParentSource; } catch { break; } } return false; } public static bool Qualifies(Gun gun) { if ((Object)(object)gun == (Object)null) { return false; } try { return gun.GunData.magazineSize > 1; } catch { return false; } } public static void SetRigidbodyVelocity(Rigidbody rb, Vector3 force) { //IL_001e: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)rb == (Object)null || RigidbodyVelocityProp == null) { return; } try { RigidbodyVelocityProp.SetValue(rb, force, null); } catch { } } public static void EnsureNonKinematic(EnemyBrain brain) { if ((Object)(object)brain == (Object)null) { return; } try { Rigidbody rigidbody = brain.Rigidbody; if ((Object)(object)rigidbody != (Object)null && rigidbody.isKinematic) { rigidbody.isKinematic = false; } } catch { } } public static void EnsureRagdollVelocity(EnemyBrain brain, Vector3 force) { //IL_0009: Unknown result type (might be due to invalid IL or missing references) //IL_000c: Unknown result type (might be due to invalid IL or missing references) //IL_0012: Unknown result type (might be due to invalid IL or missing references) //IL_003b: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)brain == (Object)null || force == default(Vector3)) { return; } try { EnsureNonKinematic(brain); Rigidbody rigidbody = brain.Rigidbody; if ((Object)(object)rigidbody != (Object)null && !rigidbody.isKinematic) { SetRigidbodyVelocity(rigidbody, force); } } catch { } } public static void ApplyKnockback(in DamageCallbackData data, Gun gun) { //IL_0029: Unknown result type (might be due to invalid IL or missing references) //IL_002e: Unknown result type (might be due to invalid IL or missing references) //IL_0045: Unknown result type (might be due to invalid IL or missing references) //IL_0046: Unknown result type (might be due to invalid IL or missing references) //IL_0050: Unknown result type (might be due to invalid IL or missing references) //IL_0055: Unknown result type (might be due to invalid IL or missing references) //IL_005a: Unknown result type (might be due to invalid IL or missing references) //IL_005e: Unknown result type (might be due to invalid IL or missing references) //IL_0063: Unknown result type (might be due to invalid IL or missing references) //IL_0079: Unknown result type (might be due to invalid IL or missing references) //IL_007b: Unknown result type (might be due to invalid IL or missing references) //IL_0080: Unknown result type (might be due to invalid IL or missing references) //IL_0091: Unknown result type (might be due to invalid IL or missing references) //IL_0099: Unknown result type (might be due to invalid IL or missing references) //IL_00bb: Unknown result type (might be due to invalid IL or missing references) //IL_00b0: Unknown result type (might be due to invalid IL or missing references) ITarget target = data.target; if (target == null || !target.IsAlive || !target.IsEnemy() || !TryGetBrain(target, out var brain)) { return; } Vector3 val = ResolveKnockbackDirection(in data, gun); if (((Vector3)(ref val)).sqrMagnitude < 0.0001f) { return; } ((Vector3)(ref val)).Normalize(); Vector3 val2 = val + Vector3.up * 0.4f; val = ((Vector3)(ref val2)).normalized; float num = Mathf.Max(1f, TurboHelpers.Scale(22f)); Vector3 val3 = val * num; try { if (((NetworkBehaviour)brain).IsServer) { EnsureNonKinematic(brain); brain.Ragdoll_Server(val3); EnsureRagdollVelocity(brain, val3); return; } EnemyPart val4 = (EnemyPart)(object)((target is EnemyPart) ? target : null); if (val4 != null) { val4.AddImpulseForce(val3, (IDamageSource)(object)gun); } else { brain.AddImpulseForce_Client(val3); } } catch { } } private static bool TryGetBrain(ITarget target, out EnemyBrain brain) { brain = null; try { EnemyPart val = (EnemyPart)(object)((target is EnemyPart) ? target : null); if (val != null) { brain = val.Brain; if ((Object)(object)brain != (Object)null) { return true; } } Component val2 = (Component)(object)((target is Component) ? target : null); if (val2 != null) { brain = val2.GetComponentInParent(); if ((Object)(object)brain != (Object)null) { return true; } } } catch { } return false; } private static Vector3 ResolveKnockbackDirection(in DamageCallbackData data, Gun gun) { //IL_0017: Unknown result type (might be due to invalid IL or missing references) //IL_001c: Unknown result type (might be due to invalid IL or missing references) //IL_001f: Unknown result type (might be due to invalid IL or missing references) //IL_002a: Unknown result type (might be due to invalid IL or missing references) //IL_0090: 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_0096: Unknown result type (might be due to invalid IL or missing references) //IL_009b: Unknown result type (might be due to invalid IL or missing references) //IL_00b5: Unknown result type (might be due to invalid IL or missing references) //IL_0043: Unknown result type (might be due to invalid IL or missing references) //IL_0044: Unknown result type (might be due to invalid IL or missing references) //IL_0065: Unknown result type (might be due to invalid IL or missing references) //IL_006a: Unknown result type (might be due to invalid IL or missing references) //IL_00ab: Unknown result type (might be due to invalid IL or missing references) //IL_00ad: Unknown result type (might be due to invalid IL or missing references) //IL_0055: Unknown result type (might be due to invalid IL or missing references) //IL_0056: Unknown result type (might be due to invalid IL or missing references) //IL_00bb: Unknown result type (might be due to invalid IL or missing references) //IL_0084: Unknown result type (might be due to invalid IL or missing references) //IL_0089: Unknown result type (might be due to invalid IL or missing references) try { if ((Object)(object)PlayerLook.Instance != (Object)null) { Vector3 forward = ((Component)PlayerLook.Instance).transform.forward; Vector3 result = default(Vector3); ((Vector3)(ref result))..ctor(forward.x, 0f, forward.z); if (((Vector3)(ref result)).sqrMagnitude > 0.0001f) { return result; } if (((Vector3)(ref forward)).sqrMagnitude > 0.0001f) { return forward; } } } catch { } try { Vector3 position = ((Component)gun).transform.position; Player player = gun.Player; if ((Object)(object)player != (Object)null) { try { position = ((Component)player).transform.position; } catch { } } Vector3 result2 = data.position - position; if (((Vector3)(ref result2)).sqrMagnitude > 0.0001f) { return result2; } } catch { } return Vector3.forward; } } [HarmonyPatch(typeof(EnemyBrain), "AddRagdollForce_Server")] public static class EnemyBrain_AddRagdollForce_Server_KinematicFix_Patch { [HarmonyPrefix] private static void Prefix(EnemyBrain __instance) { if (TurboHelpers.MasterEnabled && !((Object)(object)__instance == (Object)null)) { HeavyMunitionsTurbo.EnsureNonKinematic(__instance); } } [HarmonyPostfix] private static void Postfix(EnemyBrain __instance, Vector3 force) { //IL_0012: Unknown result type (might be due to invalid IL or missing references) if (TurboHelpers.MasterEnabled && !((Object)(object)__instance == (Object)null)) { HeavyMunitionsTurbo.EnsureRagdollVelocity(__instance, force); } } } [HarmonyPatch(typeof(EnemyBrain), "Ragdoll_Server")] public static class EnemyBrain_Ragdoll_Server_KinematicFix_Patch { [HarmonyPrefix] private static void Prefix(EnemyBrain __instance) { if (TurboHelpers.MasterEnabled && !((Object)(object)__instance == (Object)null)) { HeavyMunitionsTurbo.EnsureNonKinematic(__instance); } } [HarmonyPostfix] private static void Postfix(EnemyBrain __instance, Vector3 force) { //IL_0021: Unknown result type (might be due to invalid IL or missing references) if (TurboHelpers.MasterEnabled && !((Object)(object)__instance == (Object)null) && !(((Vector3)(ref force)).sqrMagnitude < 0.01f)) { HeavyMunitionsTurbo.EnsureRagdollVelocity(__instance, force); } } } [HarmonyPatch(typeof(Gun), "OnUpgradesEnabled")] public static class Gun_OnUpgradesEnabled_HeavyMunitions_Patch { [HarmonyPostfix] private static void Postfix(Gun __instance) { //IL_0061: Unknown result type (might be due to invalid IL or missing references) //IL_006b: Expected O, but got Unknown //IL_006b: Unknown result type (might be due to invalid IL or missing references) //IL_0075: Expected O, but got Unknown if (TurboHelpers.MasterEnabled && !((Object)(object)__instance == (Object)null) && __instance is MiniCannon && TurboHelpers.GearHasTurboNamed((IGear)(object)__instance, "Heavy Munitions") && HeavyMunitionsTurbo.Qualifies(__instance)) { __instance.GunData.damage += TurboHelpers.Scale(85f); __instance.OnDamageTarget = (DamageCallback)Delegate.Combine((Delegate?)(object)__instance.OnDamageTarget, (Delegate?)new DamageCallback(OnDamageTarget)); } } private static void OnDamageTarget(in DamageCallbackData data) { if (HeavyMunitionsTurbo.TryGetHeavyMunitionsGun(data.source, out var gun) && HeavyMunitionsTurbo.Qualifies(gun)) { HeavyMunitionsTurbo.ApplyKnockback(in data, gun); } } } public static class ImmolatorTurbo { public const float AuraRadius = 12f; public const float LingerDuration = 3f; internal static readonly Dictionary FireBuffExpiry = new Dictionary(); public static bool HasImmolatorTurbo(BounceShotgun shotgun) { return TurboHelpers.GearHasTurboNamed((IGear)(object)shotgun, "Immolator"); } public static void ApplyFireElement(Gun gun) { //IL_0011: Unknown result type (might be due to invalid IL or missing references) if (!((Object)(object)gun == (Object)null)) { gun.GunData.damageEffect = (EffectType)1; if (gun.GunData.damageEffectAmount < 5f) { gun.GunData.damageEffectAmount = TurboHelpers.Scale(8f); } } } } [HarmonyPatch(typeof(BounceShotgun), "OnActiveUpdate")] public static class BounceShotgun_OnActiveUpdate_Immolator_Patch { [HarmonyPostfix] private static void Postfix(BounceShotgun __instance) { //IL_003a: Unknown result type (might be due to invalid IL or missing references) //IL_003f: Unknown result type (might be due to invalid IL or missing references) //IL_00a0: Unknown result type (might be due to invalid IL or missing references) //IL_00a5: Unknown result type (might be due to invalid IL or missing references) //IL_00a6: Unknown result type (might be due to invalid IL or missing references) //IL_00ab: Unknown result type (might be due to invalid IL or missing references) if (!TurboHelpers.MasterEnabled || (Object)(object)__instance == (Object)null || !((NetworkBehaviour)__instance).IsOwner || !ImmolatorTurbo.HasImmolatorTurbo(__instance)) { return; } Player player = ((Gun)__instance).Player; if ((Object)(object)player == (Object)null) { return; } Vector3 position = ((Component)player).transform.position; float num = TurboHelpers.Scale(12f); float value = Time.time + 3f; int instanceID = ((Object)player).GetInstanceID(); ImmolatorTurbo.FireBuffExpiry[instanceID] = value; ApplyFireToPlayerGuns(player); try { Player[] array = Object.FindObjectsOfType(); foreach (Player val in array) { if (!((Object)(object)val == (Object)null) && !((Object)(object)val == (Object)(object)player)) { Vector3 val2 = ((Component)val).transform.position - position; if (!(((Vector3)(ref val2)).sqrMagnitude > num * num)) { ImmolatorTurbo.FireBuffExpiry[((Object)val).GetInstanceID()] = value; ApplyFireToPlayerGuns(val); } } } } catch { } } private static void ApplyFireToPlayerGuns(Player player) { if ((Object)(object)player == (Object)null) { return; } try { if (player.Gear == null) { return; } for (int i = 0; i < player.Gear.Length && i < 2; i++) { IGear obj = player.Gear[i]; Gun val = (Gun)(object)((obj is Gun) ? obj : null); if (val != null) { ImmolatorTurbo.ApplyFireElement(val); } } } catch { } } } public static class InternalCombustionTurbo { private struct FireZone { public Vector3 Position; public float Radius; public float EndTime; public float NextTick; public IncendiaryGrenade Source; } public const float PuddleLifetime = 6f; public const float FireDamagePerSecond = 20f; public const float FireEffectPerSecond = 25f; public const float TickInterval = 0.25f; private static readonly List Zones = new List(8); private static readonly FieldInfo PositionNextField = AccessTools.Field(typeof(SimpleProjectileBullet), "positionNext"); private static readonly FieldInfo BulletDataField = AccessTools.Field(typeof(SimpleProjectileBullet), "data"); private static bool _loggedTickOnce; public static bool HasTurbo(IncendiaryGrenade g) { if ((Object)(object)g != (Object)null) { if (!TurboHelpers.GearHasTurboNamed((IGear)(object)g, "Internal Combustion")) { return TurboHelpers.GearHasTurboNamed((IGear)(object)g, "Combustion"); } return true; } return false; } public static void SpawnFireZone(IncendiaryGrenade grenade, Vector3 position, float size) { //IL_00d6: Unknown result type (might be due to invalid IL or missing references) //IL_00d7: Unknown result type (might be due to invalid IL or missing references) //IL_0043: Unknown result type (might be due to invalid IL or missing references) //IL_0048: Unknown result type (might be due to invalid IL or missing references) //IL_012a: Unknown result type (might be due to invalid IL or missing references) //IL_00b8: Unknown result type (might be due to invalid IL or missing references) //IL_0089: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)grenade == (Object)null) { return; } float num = Mathf.Max(3f, TurboHelpers.Scale(6f)); float num2 = Mathf.Clamp(size, 2f, 12f); try { if ((Object)(object)GameManager.Instance != (Object)null) { GameManager.Instance.SpawnAcidPuddle_Rpc(IDamageSource.GetNetworkRef((IDamageSource)(object)grenade), position, num, (TargetType)5, num2); } } catch (Exception ex) { ManualLogSource logger = SparrohPlugin.Logger; if (logger != null) { logger.LogWarning((object)("[Turbo] IC puddle VFX: " + ex.Message)); } } try { if ((Object)(object)GameManager.Instance != (Object)null) { GameManager.Instance.SpawnExplosionVisualNoSound(position, num2, (EffectType)1); } } catch { try { StatusEffectData effect = Global.GetEffect((EffectType)1); if ((Object)(object)effect != (Object)null && (Object)(object)effect.explosionEffect != (Object)null) { BurstEffect.InitializeObjectPosition(effect.explosionEffect, position, num2); } } catch { } } Zones.Add(new FireZone { Position = position, Radius = num2, EndTime = Time.time + num, NextTick = Time.time, Source = grenade }); _loggedTickOnce = false; ManualLogSource logger2 = SparrohPlugin.Logger; if (logger2 != null) { logger2.LogInfo((object)$"[Turbo] Internal Combustion: fire zone at {position} r={num2:0.#} for {num:0.#}s (zones={Zones.Count})"); } } public static void TickZones() { //IL_01e8: Unknown result type (might be due to invalid IL or missing references) //IL_01ea: Unknown result type (might be due to invalid IL or missing references) //IL_00f6: Unknown result type (might be due to invalid IL or missing references) //IL_011e: Unknown result type (might be due to invalid IL or missing references) //IL_015c: Unknown result type (might be due to invalid IL or missing references) //IL_01cf: Unknown result type (might be due to invalid IL or missing references) //IL_01d4: Unknown result type (might be due to invalid IL or missing references) //IL_01d8: Unknown result type (might be due to invalid IL or missing references) //IL_01dd: Unknown result type (might be due to invalid IL or missing references) if (Zones.Count == 0) { return; } float time = Time.time; float num = Mathf.Max(10f, TurboHelpers.Scale(20f)); float num2 = Mathf.Max(12f, TurboHelpers.Scale(25f)); DamageData val2 = default(DamageData); for (int num3 = Zones.Count - 1; num3 >= 0; num3--) { FireZone value = Zones[num3]; if (time >= value.EndTime) { Zones.RemoveAt(num3); } else if ((Object)(object)value.Source == (Object)null) { Zones.RemoveAt(num3); } else if (!(time < value.NextTick)) { value.NextTick = time + 0.25f; Zones[num3] = value; IDamageSource val = (IDamageSource)(object)value.Source; try { if (val == null && (Object)(object)Player.LocalPlayer != (Object)null) { val = (IDamageSource)(object)Player.LocalPlayer; } } catch { } if (val != null) { int num4 = 0; try { List list = new List(); bool targetsInSphere = IDamageSource.GetTargetsInSphere(value.Position, value.Radius, 344192, list, (TargetType)5); if (!targetsInSphere) { list.Clear(); targetsInSphere = IDamageSource.GetTargetsInSphere(value.Position, value.Radius, 345224, list, (TargetType)5); } if (!targetsInSphere) { if (!_loggedTickOnce) { _loggedTickOnce = true; ManualLogSource logger = SparrohPlugin.Logger; if (logger != null) { logger.LogInfo((object)$"[Turbo] IC zone tick: 0 targets at {value.Position} r={value.Radius:0.#}"); } } } else { ((DamageData)(ref val2))..ctor(num * 0.25f, (EffectType)1, num2 * 0.25f, (DamageFlags)16); for (int i = 0; i < list.Count; i++) { ITarget val3 = list[i]; if (val3 == null) { continue; } try { if (!val3.IsAlive || val3.IsPlayer()) { continue; } goto IL_01c8; } catch { } continue; IL_01c8: try { Vector3 val4 = ((ISelectable)val3).transform.position; try { val4 = ((IFollowable)val3).GetHealthbarPosition(); } catch { } IDamageSource.DamageTarget(val, val3, val2, val4, (Collider)null); num4++; } catch { } } if (num4 > 0 && !_loggedTickOnce) { _loggedTickOnce = true; ManualLogSource logger2 = SparrohPlugin.Logger; if (logger2 != null) { logger2.LogInfo((object)$"[Turbo] IC zone hit {num4} enem(ies)"); } } } } catch (Exception ex) { ManualLogSource logger3 = SparrohPlugin.Logger; if (logger3 != null) { logger3.LogWarning((object)("[Turbo] IC zone tick failed: " + ex.Message)); } } } } } } public static void TrySpawnFromBullet(IncendiaryGrenadeBullet bullet) { //IL_00ee: Unknown result type (might be due to invalid IL or missing references) //IL_0073: Unknown result type (might be due to invalid IL or missing references) //IL_0066: Unknown result type (might be due to invalid IL or missing references) //IL_0013: Unknown result type (might be due to invalid IL or missing references) //IL_0078: Unknown result type (might be due to invalid IL or missing references) //IL_0091: Unknown result type (might be due to invalid IL or missing references) //IL_0096: Unknown result type (might be due to invalid IL or missing references) if (!TurboHelpers.MasterEnabled || (Object)(object)bullet == (Object)null) { return; } try { if (!BulletFlagsExtensions.IsOwner(((SimpleProjectileBullet)bullet).Flags)) { return; } IDamageSource parentSource = ((SimpleProjectileBullet)bullet).ParentSource; IncendiaryGrenade val = (IncendiaryGrenade)(object)((parentSource is IncendiaryGrenade) ? parentSource : null); if (val == null || !HasTurbo(val)) { return; } try { if (bullet.IsClusterBomb) { return; } } catch { } Vector3 position = (((Object)(object)((Component)bullet).transform != (Object)null) ? ((Component)bullet).transform.position : Vector3.zero); if (PositionNextField != null) { try { position = (Vector3)PositionNextField.GetValue(bullet); } catch { } } float size = 4f; if (BulletDataField != null) { try { object value = BulletDataField.GetValue(bullet); if (value != null) { FieldInfo fieldInfo = AccessTools.Field(value.GetType(), "force"); if (fieldInfo != null) { size = (float)fieldInfo.GetValue(value); } } } catch { } } SpawnFireZone(val, position, size); } catch (Exception ex) { ManualLogSource logger = SparrohPlugin.Logger; if (logger != null) { logger.LogWarning((object)("[Turbo] Internal Combustion detonate: " + ex.Message)); } } } } [HarmonyPatch(typeof(IncendiaryGrenadeBullet), "Detonate")] public static class IncendiaryGrenadeBullet_Detonate_InternalCombustion_Patch { [HarmonyPostfix] private static void Postfix(IncendiaryGrenadeBullet __instance) { InternalCombustionTurbo.TrySpawnFromBullet(__instance); } } [HarmonyPatch(typeof(Player), "Update")] public static class Player_Update_InternalCombustion_Patch { [HarmonyPostfix] private static void Postfix(Player __instance) { if (TurboHelpers.MasterEnabled && !((Object)(object)__instance == (Object)null) && ((NetworkBehaviour)__instance).IsLocalPlayer) { InternalCombustionTurbo.TickZones(); } } } public static class JackrabbitTurbos { public const float PesticideRangeMult = 2f; public const float PesticideMissingHpMult = 1.25f; public const float PummelerChargeSpeedMult = 1.75f; } [HarmonyPatch(typeof(BounceShotgun), "OnUpgradesEnabled")] public static class BounceShotgun_OnUpgradesEnabled_Turbo_Patch { [HarmonyPostfix] private static void Postfix(BounceShotgun __instance) { //IL_0060: Unknown result type (might be due to invalid IL or missing references) //IL_006a: Expected O, but got Unknown //IL_006a: Unknown result type (might be due to invalid IL or missing references) //IL_0074: Expected O, but got Unknown if (TurboHelpers.MasterEnabled && !((Object)(object)__instance == (Object)null)) { if (__instance.ShotgunData.flamethrowerRange > 0f && TurboHelpers.GearHasTurboNamed((IGear)(object)__instance, "Flamethrower")) { __instance.ShotgunData.flamethrowerRange *= TurboHelpers.Scale(2f); ((Gun)__instance).OnBeforeDamage = (MutableDamageCallback)Delegate.Combine((Delegate?)(object)((Gun)__instance).OnBeforeDamage, (Delegate?)new MutableDamageCallback(OnBeforePesticideDamage)); } if (__instance.ShotgunData.bulletChargeSpeed > 0f && TurboHelpers.GearHasTurboNamed((IGear)(object)__instance, "BulletCharge")) { __instance.ShotgunData.bulletChargeSpeed *= TurboHelpers.Scale(1.75f); } } } private static void OnBeforePesticideDamage(ref DamageCallbackData data) { //IL_0006: Unknown result type (might be due to invalid IL or missing references) //IL_000d: Unknown result type (might be due to invalid IL or missing references) //IL_0010: Invalid comparison between Unknown and I4 if ((data.damageData.damageFlags & 0x11) == 17) { IDamageSource source = data.source; BounceShotgun val = (BounceShotgun)(object)((source is BounceShotgun) ? source : null); if (val != null && TurboHelpers.GearHasTurboNamed((IGear)(object)val, "Flamethrower") && data.target != null && !(data.target.MaxHealth <= 0f)) { float num = 1f - ((ISelectable)data.target).Health / data.target.MaxHealth; data.damageData.damage *= 1f + num * TurboHelpers.Scale(1.25f); } } } } [HarmonyPatch(typeof(UpgradeProperty_BounceShotgun_BulletCharge), "Apply")] public static class Pummeler_Apply_Turbo_Patch { [HarmonyPostfix] private static void Postfix(IGear gear, UpgradeInstance upgrade) { if (TurboHelpers.MasterEnabled && TurboHelpers.IsTurbo(upgrade)) { BounceShotgun val = (BounceShotgun)(object)((gear is BounceShotgun) ? gear : null); if (val != null && (TurboHelpers.ApiMatches(upgrade.Upgrade, "BulletCharge") || TurboHelpers.HasPropertyType(upgrade.Upgrade))) { val.ShotgunData.bulletChargeSpeed *= TurboHelpers.Scale(1.75f); } } } } public static class LagrangeHaloTurbo { public const float Interval = 1.15f; private static readonly List Registered = new List(); private static readonly Dictionary NextFireTime = new Dictionary(); private static readonly FieldInfo MiniDataField = AccessTools.Field(typeof(MiniCannon), "miniCannonData"); private static readonly FieldInfo FireDataField = AccessTools.Field(typeof(Gun), "fireData"); private static readonly FieldInfo OrbitalSpreadHeightField = AccessTools.Field(typeof(MiniCannon), "orbitalSpreadHeightMultiplier"); private static readonly FieldInfo ReleaseBulletField = AccessTools.Field(typeof(Gun), "releaseBulletToPool"); private static readonly FieldInfo ShotsFiredField = AccessTools.Field(typeof(Gun), "shotsFiredSinceStartedFiring"); private static readonly MethodInfo GetBulletMethod = AccessTools.Method(typeof(Gun), "GetBullet", Type.EmptyTypes, (Type[])null) ?? AccessTools.Method(typeof(Gun), "GetBullet", (Type[])null, (Type[])null); private static readonly MethodInfo GetSpreadMethod = AccessTools.Method(typeof(Gun), "GetSpread", new Type[1] { typeof(int) }, (Type[])null); private static readonly MethodInfo OnFiredBulletMethod = AccessTools.Method(typeof(Gun), "OnFiredBullet", (Type[])null, (Type[])null); private static readonly MethodInfo AfterBulletFiredMethod = AccessTools.Method(typeof(Gun), "AfterBulletFired", (Type[])null, (Type[])null); private static bool _loggedFail; public static void Register(Gun gun) { MiniCannon val = (MiniCannon)(object)((gun is MiniCannon) ? gun : null); if (val != null) { Register(val); } } public static void Register(MiniCannon gun) { if (!((Object)(object)gun == (Object)null)) { if (!Registered.Contains(gun)) { Registered.Add(gun); } int instanceID = ((Object)gun).GetInstanceID(); if (!NextFireTime.ContainsKey(instanceID)) { NextFireTime[instanceID] = 0f; } } } public static void Unregister(MiniCannon gun) { if (!((Object)(object)gun == (Object)null)) { Registered.Remove(gun); NextFireTime.Remove(((Object)gun).GetInstanceID()); } } public static void Tick() { if (!TurboHelpers.MasterEnabled) { return; } for (int num = Registered.Count - 1; num >= 0; num--) { MiniCannon val = Registered[num]; if ((Object)(object)val == (Object)null) { Registered.RemoveAt(num); } else if (TurboHelpers.GearHasTurboNamed((IGear)(object)val, "Orbital")) { Player player = ((Gun)val).Player; if (!((Object)(object)player == (Object)null)) { bool flag = false; try { flag = player.IsSprinting; } catch { } if (flag) { int instanceID = ((Object)val).GetInstanceID(); float num2 = Mathf.Max(0.4f, 1.15f / Mathf.Max(0.5f, TurboHelpers.Strength)); if (!NextFireTime.TryGetValue(instanceID, out var value)) { value = 0f; } if (!(Time.time < value)) { NextFireTime[instanceID] = Time.time + num2; FireOrbitalVolley(val, player); } } } } } } private static void FireOrbitalVolley(MiniCannon gun, Player player) { try { ((Gun)gun).PrepareFireData(); float lifetime = ReadOrbitalLifetime(gun); float heightSpread = ReadHeightSpread(gun); int num = 1; try { num = Mathf.Max(1, ((Gun)gun).GunData.bulletsPerShot); } catch { num = 1; } int num2 = 0; for (int i = 0; i < num; i++) { if (TrySpawnOrbitalShot(gun, player, lifetime, heightSpread, i)) { num2++; } } if (num2 == 0 && !_loggedFail) { _loggedFail = true; ManualLogSource logger = SparrohPlugin.Logger; if (logger != null) { logger.LogWarning((object)"[Turbo] Lagrange Halo: failed to spawn OrbitalBullet (GetBullet/Setup)."); } } } catch (Exception ex) { if (!_loggedFail) { _loggedFail = true; ManualLogSource logger2 = SparrohPlugin.Logger; if (logger2 != null) { logger2.LogWarning((object)("[Turbo] Lagrange Halo fire error: " + ex.Message)); } } } } private static float ReadOrbitalLifetime(MiniCannon gun) { try { object obj = MiniDataField?.GetValue(gun); if (obj != null) { FieldInfo fieldInfo = AccessTools.Field(obj.GetType(), "orbitalLifetime"); if (fieldInfo != null) { float num = (float)fieldInfo.GetValue(obj); if (num > 0f) { return num; } } } } catch { } return 1.3f; } private static float ReadHeightSpread(MiniCannon gun) { try { float num = Mathf.Max(((Gun)gun).GunData.spreadData.spreadSize.x, ((Gun)gun).GunData.spreadData.spreadSize.y) - 2f; float num2 = 1f; if (OrbitalSpreadHeightField != null) { num2 = (float)OrbitalSpreadHeightField.GetValue(gun); } return Mathf.Max(0f, num) * num2; } catch { return 0f; } } private static bool TrySpawnOrbitalShot(MiniCannon gun, Player player, float lifetime, float heightSpread, int shotIndex) { //IL_0161: Unknown result type (might be due to invalid IL or missing references) //IL_0162: Unknown result type (might be due to invalid IL or missing references) //IL_00bc: Unknown result type (might be due to invalid IL or missing references) //IL_00bd: Unknown result type (might be due to invalid IL or missing references) //IL_013a: 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_0155: Unknown result type (might be due to invalid IL or missing references) //IL_0157: Unknown result type (might be due to invalid IL or missing references) //IL_015c: Unknown result type (might be due to invalid IL or missing references) //IL_0168: Unknown result type (might be due to invalid IL or missing references) //IL_0174: Unknown result type (might be due to invalid IL or missing references) //IL_0179: Unknown result type (might be due to invalid IL or missing references) //IL_0274: Unknown result type (might be due to invalid IL or missing references) //IL_0279: Unknown result type (might be due to invalid IL or missing references) //IL_002c: Unknown result type (might be due to invalid IL or missing references) //IL_0031: Unknown result type (might be due to invalid IL or missing references) //IL_003b: Unknown result type (might be due to invalid IL or missing references) //IL_0040: Unknown result type (might be due to invalid IL or missing references) //IL_0045: Unknown result type (might be due to invalid IL or missing references) //IL_004c: Unknown result type (might be due to invalid IL or missing references) //IL_0051: Unknown result type (might be due to invalid IL or missing references) //IL_00c1: Unknown result type (might be due to invalid IL or missing references) //IL_00c6: Unknown result type (might be due to invalid IL or missing references) //IL_00c8: Unknown result type (might be due to invalid IL or missing references) //IL_00cd: Unknown result type (might be due to invalid IL or missing references) //IL_01a2: Unknown result type (might be due to invalid IL or missing references) //IL_00f7: Unknown result type (might be due to invalid IL or missing references) //IL_00fc: Unknown result type (might be due to invalid IL or missing references) //IL_01fd: Unknown result type (might be due to invalid IL or missing references) //IL_0226: Unknown result type (might be due to invalid IL or missing references) //IL_023a: Unknown result type (might be due to invalid IL or missing references) //IL_0298: Unknown result type (might be due to invalid IL or missing references) //IL_0263: Unknown result type (might be due to invalid IL or missing references) //IL_0268: Unknown result type (might be due to invalid IL or missing references) //IL_026a: Unknown result type (might be due to invalid IL or missing references) //IL_026c: Unknown result type (might be due to invalid IL or missing references) //IL_0121: Unknown result type (might be due to invalid IL or missing references) //IL_0125: Unknown result type (might be due to invalid IL or missing references) //IL_012a: Unknown result type (might be due to invalid IL or missing references) //IL_0099: Unknown result type (might be due to invalid IL or missing references) //IL_009e: Unknown result type (might be due to invalid IL or missing references) //IL_00b1: Unknown result type (might be due to invalid IL or missing references) //IL_00b6: Unknown result type (might be due to invalid IL or missing references) if (GetBulletMethod == null) { return false; } object? obj = GetBulletMethod.Invoke(gun, null); IBullet val = (IBullet)((obj is IBullet) ? obj : null); if (val == null) { return false; } Vector3 val2 = ((Component)player).transform.position + Vector3.up * 1.1f; Quaternion val3 = ((Component)player).transform.rotation; object obj2 = FireDataField?.GetValue(gun); try { if (obj2 != null) { Type type = obj2.GetType(); FieldInfo fieldInfo = AccessTools.Field(type, "firePosition"); FieldInfo fieldInfo2 = AccessTools.Field(type, "bulletRotation"); if (fieldInfo != null) { val2 = (Vector3)fieldInfo.GetValue(obj2); } if (fieldInfo2 != null) { val3 = (Quaternion)fieldInfo2.GetValue(obj2); } } } catch { } Quaternion val4 = val3; try { Vector3 eulerAngles = ((Quaternion)(ref val3)).eulerAngles; Vector2 val5 = Vector2.zero; if (GetSpreadMethod != null) { val5 = (Vector2)GetSpreadMethod.Invoke(gun, new object[1] { shotIndex }); } if (shotIndex == 0) { try { float firstShotSpreadMultiplier = ((Gun)gun).GunData.firstShotSpreadMultiplier; if (firstShotSpreadMultiplier > 0f && firstShotSpreadMultiplier != 1f) { val5 *= firstShotSpreadMultiplier; } } catch { } } eulerAngles.y += val5.x; eulerAngles.x += val5.y; val4 = Quaternion.Euler(eulerAngles); } catch { val4 = val3; } BulletFlags val6 = (BulletFlags)11; BulletData val7 = ((GunData)(ref ((Gun)gun).GunData)).GetBulletData(ref val2, ref val4); val7.gravity = ((Gun)gun).GunData.bulletGravity; val7.speed = ((Gun)gun).GunData.bulletSpeed; try { ((Gun)gun).ModifyBulletData(ref val7, val6); } catch { } Action action = null; try { if (ReleaseBulletField != null) { action = ReleaseBulletField.GetValue(gun) as Action; } } catch { } if (action == null) { action = delegate { }; } try { val.UpgradeFlags = ((Gun)gun).UpgradeFlags; } catch { } try { if (OnFiredBulletMethod != null) { object[] array = new object[4] { val, val6, shotIndex, val7 }; OnFiredBulletMethod.Invoke(gun, array); if (array[3] is BulletData val8) { val7 = val8; } } } catch { } val.Initialize(val7, (IDamageSource)(object)gun, action, val6); try { AfterBulletFiredMethod?.Invoke(gun, new object[3] { val, val6, shotIndex }); } catch { } OrbitalBullet val9 = (OrbitalBullet)(object)((val is OrbitalBullet) ? val : null); if (val9 != null) { try { val9.Setup(((Component)player).transform, heightSpread, lifetime); } catch { } return true; } return val != null; } } [HarmonyPatch(typeof(MiniCannon), "OnUpgradesEnabled")] public static class MiniCannon_OnUpgradesEnabled_Lagrange_Patch { [HarmonyPostfix] private static void Postfix(MiniCannon __instance) { if (TurboHelpers.MasterEnabled && !((Object)(object)__instance == (Object)null) && TurboHelpers.GearHasTurboNamed((IGear)(object)__instance, "Orbital")) { LagrangeHaloTurbo.Register(__instance); ((Gun)__instance).SetUpgradeFlag_Owner((GearUpgradeFlags)268435456, true); } } } [HarmonyPatch(typeof(Gun), "OnUpgradesEnabled")] public static class Gun_OnUpgradesEnabled_Lagrange_Patch { [HarmonyPostfix] private static void Postfix(Gun __instance) { if (TurboHelpers.MasterEnabled && !((Object)(object)__instance == (Object)null)) { MiniCannon val = (MiniCannon)(object)((__instance is MiniCannon) ? __instance : null); if (val != null && TurboHelpers.GearHasTurboNamed((IGear)(object)val, "Orbital")) { LagrangeHaloTurbo.Register(val); } } } } public static class LiveWireTurbo { public const float ArcRadius = 8f; public const int MaxTargets = 3; public const float ArcInterval = 0.7f; public const float ShockDamage = 25f; public const float ShockEffectAmount = 8f; private static float _nextArcTime; public static void ResetArcCooldown() { _nextArcTime = 0f; } public static bool LocalPlayerHasLiveWireTurbo() { if (!TurboHelpers.PlayerHasTurboNamed(Player.LocalPlayer, "Live Wire")) { return TurboHelpers.PlayerHasTurboNamed(Player.LocalPlayer, "Livewire"); } return true; } public static bool IsLocalPlayerShocked() { try { Player localPlayer = Player.LocalPlayer; if ((Object)(object)localPlayer == (Object)null) { return false; } return ITarget.IsSaturated((ITarget)(object)localPlayer, (EffectType)2); } catch { return false; } } public static void CollectNearestTargets(Vector3 origin, float radius, List outTargets) { //IL_0007: Unknown result type (might be due to invalid IL or missing references) //IL_0008: Unknown result type (might be due to invalid IL or missing references) //IL_001a: Unknown result type (might be due to invalid IL or missing references) outTargets.Clear(); try { List list = new List(); if (!IDamageSource.GetTargetsInSphere(origin, radius, 344192, list, (TargetType)5)) { return; } list.Sort(delegate(ITarget a, ITarget b) { //IL_0006: Unknown result type (might be due to invalid IL or missing references) //IL_000c: Unknown result type (might be due to invalid IL or missing references) //IL_0011: Unknown result type (might be due to invalid IL or missing references) //IL_0016: Unknown result type (might be due to invalid IL or missing references) //IL_0025: Unknown result type (might be due to invalid IL or missing references) //IL_002b: Unknown result type (might be due to invalid IL or missing references) //IL_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) Vector3 val2 = ((ISelectable)a).transform.position - origin; float sqrMagnitude = ((Vector3)(ref val2)).sqrMagnitude; val2 = ((ISelectable)b).transform.position - origin; float sqrMagnitude2 = ((Vector3)(ref val2)).sqrMagnitude; return sqrMagnitude.CompareTo(sqrMagnitude2); }); HashSet hashSet = new HashSet(); for (int num = 0; num < list.Count; num++) { if (outTargets.Count >= 3) { break; } ITarget val = list[num]; if (val != null && val.IsAlive && !val.IsPlayer() && hashSet.Add(val)) { outTargets.Add(val); } } } catch { } } public static void TryArc(Player player) { //IL_012e: Unknown result type (might be due to invalid IL or missing references) //IL_0133: Unknown result type (might be due to invalid IL or missing references) //IL_01a7: Unknown result type (might be due to invalid IL or missing references) //IL_01bc: Unknown result type (might be due to invalid IL or missing references) //IL_0147: Unknown result type (might be due to invalid IL or missing references) //IL_0149: Unknown result type (might be due to invalid IL or missing references) //IL_017e: Unknown result type (might be due to invalid IL or missing references) //IL_0193: Unknown result type (might be due to invalid IL or missing references) //IL_016a: Unknown result type (might be due to invalid IL or missing references) //IL_016b: Unknown result type (might be due to invalid IL or missing references) //IL_011d: Unknown result type (might be due to invalid IL or missing references) //IL_0122: Unknown result type (might be due to invalid IL or missing references) //IL_0062: Unknown result type (might be due to invalid IL or missing references) //IL_0067: Unknown result type (might be due to invalid IL or missing references) //IL_006f: Unknown result type (might be due to invalid IL or missing references) if (!TurboHelpers.MasterEnabled || (Object)(object)player == (Object)null || !((NetworkBehaviour)player).IsLocalPlayer || !LocalPlayerHasLiveWireTurbo() || !IsLocalPlayerShocked() || Time.time < _nextArcTime) { return; } _nextArcTime = Time.time + Mathf.Max(0.35f, 0.7f / Mathf.Max(0.5f, TurboHelpers.Strength)); Vector3 interpolatedPosition = player.InterpolatedPosition; List list = new List(3); CollectNearestTargets(interpolatedPosition, 8f, list); if (list.Count == 0) { return; } float num = Mathf.Max(10f, TurboHelpers.Scale(25f)); float num2 = Mathf.Max(4f, TurboHelpers.Scale(8f)); IDamageSource val = (IDamageSource)(object)player; try { IGear throwableGear = player.ThrowableGear; if (throwableGear != null && (TurboHelpers.GearHasTurboNamed(throwableGear, "Live Wire") || TurboHelpers.GearHasTurboNamed(throwableGear, "Livewire"))) { val = (IDamageSource)(((object)((throwableGear is IDamageSource) ? throwableGear : null)) ?? ((object)player)); } } catch { } int num3 = 0; DamageData val4 = default(DamageData); for (int i = 0; i < list.Count; i++) { ITarget val2 = list[i]; if (val2 == null) { continue; } Vector3 val3; try { val3 = ((IFollowable)val2).GetHealthbarPosition(); } catch { val3 = ((ISelectable)val2).transform.position; } try { ((DamageData)(ref val4))..ctor(num, (EffectType)2, num2, (DamageFlags)0); IDamageSource.DamageTarget(val, val2, val4, val3, (Collider)null); } catch { } try { if ((Object)(object)GameManager.Instance != (Object)null) { GameManager.Instance.SpawnLightningEffect_Rpc(interpolatedPosition, val3); } else { BurstEffect.InitializeObjectPosition(Global.Instance.GenericLightningEffect, interpolatedPosition, 1f).Effect.SetVector3(BurstEffect.Position, val3); } } catch { try { BurstEffect.InitializeObjectPosition(Global.Instance.GenericLightningEffect, interpolatedPosition, 1f).Effect.SetVector3(BurstEffect.Position, val3); } catch { } } num3++; } if (num3 > 0) { ManualLogSource logger = SparrohPlugin.Logger; if (logger != null) { logger.LogInfo((object)$"[Turbo] Live Wire: arced to {num3} target(s)"); } } } } [HarmonyPatch(typeof(Player), "Update")] public static class Player_Update_LiveWire_Patch { [HarmonyPostfix] private static void Postfix(Player __instance) { if (TurboHelpers.MasterEnabled && !((Object)(object)__instance == (Object)null) && ((NetworkBehaviour)__instance).IsLocalPlayer) { LiveWireTurbo.TryArc(__instance); } } } [HarmonyPatch(typeof(Player), "OnFullySaturated")] public static class Player_OnFullySaturated_LiveWire_Patch { [HarmonyPostfix] private static void Postfix(Player __instance, IDamageSource source, EffectType effect) { //IL_001a: Unknown result type (might be due to invalid IL or missing references) //IL_001c: Invalid comparison between Unknown and I4 if (TurboHelpers.MasterEnabled && !((Object)(object)__instance == (Object)null) && ((NetworkBehaviour)__instance).IsLocalPlayer && (int)effect == 2 && LiveWireTurbo.LocalPlayerHasLiveWireTurbo()) { LiveWireTurbo.ResetArcCooldown(); } } } [HarmonyPatch(typeof(AcceleratorGun), "FireAutoMissile")] public static class AcceleratorGun_FireAutoMissile_Payback_Patch { private static readonly FieldInfo AccelDataField = AccessTools.Field(typeof(AcceleratorGun), "acceleratorData"); private static readonly MethodInfo FireMissileBulletMethod = AccessTools.Method(typeof(AcceleratorGun), "FireMissileBullet", new Type[4] { typeof(float), typeof(float), typeof(float), typeof(int) }, (Type[])null); private static readonly MethodInfo PrepareFireDataMethod = AccessTools.Method(typeof(Gun), "PrepareFireData", (Type[])null, (Type[])null); [HarmonyPrefix] private static bool Prefix(AcceleratorGun __instance) { if (!TurboHelpers.MasterEnabled || (Object)(object)__instance == (Object)null) { return true; } if (((Gun)__instance).Active) { return true; } if (!TurboHelpers.GearHasTurboNamed((IGear)(object)__instance, "Payback")) { return true; } try { FirePaybackMissileWhileStowed(__instance); } catch { } return false; } private static void FirePaybackMissileWhileStowed(AcceleratorGun gun) { if (!(FireMissileBulletMethod == null) && !(AccelDataField == null)) { PrepareFireDataMethod?.Invoke(gun, null); object value = AccelDataField.GetValue(gun); if (value != null) { float num = (float)AccessTools.Field(value.GetType(), "dmgMissileDamage").GetValue(value); float num2 = (float)AccessTools.Field(value.GetType(), "dmgExplosionSize").GetValue(value); FireMissileBulletMethod.Invoke(gun, new object[4] { num, num2, 0.5f, 0 }); } } } } public static class SlipspaceTurbo { public const float StackConsumeFraction = 0.5f; } [HarmonyPatch(typeof(AcceleratorGun), "OnBurstFinished")] public static class AcceleratorGun_OnBurstFinished_Slipspace_Patch { private static readonly FieldInfo StacksField = AccessTools.Field(typeof(AcceleratorGun), "saturatedTargetsSinceReload"); [HarmonyPrefix] private static void Prefix(AcceleratorGun __instance, out float __state) { __state = 0f; if (!TurboHelpers.MasterEnabled || (Object)(object)__instance == (Object)null || StacksField == null || !TurboHelpers.GearHasTurboNamed((IGear)(object)__instance, "Slipspace Bullet Transfer")) { return; } try { __state = (float)StacksField.GetValue(__instance); } catch { __state = 0f; } } [HarmonyPostfix] private static void Postfix(AcceleratorGun __instance, float __state) { if (!TurboHelpers.MasterEnabled || (Object)(object)__instance == (Object)null || StacksField == null || __state <= 0f || !TurboHelpers.GearHasTurboNamed((IGear)(object)__instance, "Slipspace Bullet Transfer")) { return; } try { if (!((float)StacksField.GetValue(__instance) <= 0f) || !(__state > 0f)) { return; } float num = __state * (1f - Mathf.Clamp01(TurboHelpers.Scale(0.5f))); float num2 = Mathf.Clamp(0.5f / Mathf.Max(0.5f, TurboHelpers.Strength), 0.15f, 0.85f); num = __state * (1f - num2); if (!(num > 0.01f)) { return; } StacksField.SetValue(__instance, num); try { Player player = ((Gun)__instance).Player; if (player != null) { player.UpdateStackDisplay((object)typeof(UpgradeProperty_Accelerator_RefundBurst), TextBlocks.GetString("RefundBurst", 0), UpgradeProperty_Accelerator_RefundBurst.Icon, (int)num, 0f); } } catch { } } catch { } } } public static class SuperMagnetTurbo { public static bool HasTurbo(TheCarver c) { if ((Object)(object)c != (Object)null) { if (!TurboHelpers.GearHasTurboNamed((IGear)(object)c, "Super Magnet")) { return TurboHelpers.GearHasTurboNamed((IGear)(object)c, "PullGrunts"); } return true; } return false; } public static void PullLimbs(TheCarver carver) { //IL_013f: Unknown result type (might be due to invalid IL or missing references) //IL_0144: Unknown result type (might be due to invalid IL or missing references) //IL_0147: 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_014e: Unknown result type (might be due to invalid IL or missing references) //IL_0153: Unknown result type (might be due to invalid IL or missing references) //IL_016e: Unknown result type (might be due to invalid IL or missing references) //IL_0171: Unknown result type (might be due to invalid IL or missing references) //IL_0198: Unknown result type (might be due to invalid IL or missing references) //IL_01a4: Unknown result type (might be due to invalid IL or missing references) //IL_01a9: Unknown result type (might be due to invalid IL or missing references) //IL_01ae: Unknown result type (might be due to invalid IL or missing references) //IL_01b2: Unknown result type (might be due to invalid IL or missing references) //IL_01b7: Unknown result type (might be due to invalid IL or missing references) //IL_01bb: Unknown result type (might be due to invalid IL or missing references) //IL_01be: Unknown result type (might be due to invalid IL or missing references) //IL_0075: Unknown result type (might be due to invalid IL or missing references) //IL_007b: Unknown result type (might be due to invalid IL or missing references) //IL_0081: Unknown result type (might be due to invalid IL or missing references) //IL_0086: Unknown result type (might be due to invalid IL or missing references) if (!TurboHelpers.MasterEnabled || (Object)(object)carver == (Object)null || !HasTurbo(carver)) { return; } float pullInTargetForce = carver.Data.pullInTargetForce; float pullInTargetSize = carver.Data.pullInTargetSize; if (pullInTargetForce <= 0f || pullInTargetSize <= 0f) { return; } pullInTargetForce = Mathf.Max(pullInTargetForce, TurboHelpers.Scale(pullInTargetForce)); float num = pullInTargetSize * Mathf.Max(1f, TurboHelpers.Scale(1.15f)); try { ((Gun)carver).PrepareFireData(); ref FireData fireData = ref ((Gun)carver).FireData; Vector3 val = fireData.firePosition + fireData.bulletDirection * pullInTargetSize; HashSet hashSet = new HashSet(); Collider[] array = ArrayPool.Get(); int num2 = Physics.OverlapSphereNonAlloc(val, num, array, 344192); Rigidbody val5 = default(Rigidbody); for (int i = 0; i < num2; i++) { ITarget target = IDamageSource.GetTarget((Component)(object)array[i]); if (target == null) { continue; } IPullable val2 = null; IEnemyComponent val3 = (IEnemyComponent)(object)((target is IEnemyComponent) ? target : null); if (val3 != null) { if ((Object)(object)val3.Brain != (Object)null || (!val3.IsAlive && !(val3 is IPullable))) { continue; } val2 = (IPullable)(object)((val3 is IPullable) ? val3 : null); } else { val2 = (IPullable)(object)((target is IPullable) ? target : null); } if (val2 == null || !hashSet.Add(val2)) { continue; } try { if (!val2.CanPull) { continue; } } catch { } try { Vector3 position = val2.transform.position; Vector3 val4 = fireData.firePosition - position; if (!(((Vector3)(ref val4)).sqrMagnitude < 0.0001f)) { ((Vector3)(ref val4)).Normalize(); val2.AddImpulseForce_Client(val4 * pullInTargetForce); } } catch { try { if (((Component)val2.transform).TryGetComponent(ref val5) && !val5.isKinematic) { Vector3 val6 = fireData.firePosition - val2.transform.position; Vector3 normalized = ((Vector3)(ref val6)).normalized; val5.AddForce(normalized * pullInTargetForce, (ForceMode)1); } } catch { } } } ArrayPool.Release(array, num2); } catch (Exception ex) { ManualLogSource logger = SparrohPlugin.Logger; if (logger != null) { logger.LogWarning((object)("[Turbo] Super Magnet pull failed: " + ex.Message)); } } } } [HarmonyPatch(typeof(TheCarver), "PullInTargets")] public static class TheCarver_PullInTargets_SuperMagnet_Patch { [HarmonyPostfix] private static void Postfix(TheCarver __instance) { SuperMagnetTurbo.PullLimbs(__instance); } } public static class SwarmLauncherTurbos { public const float ExplosivePelletsSizeMult = 1.6f; public const float MitosisFireIntervalMult = 0.7f; public const float MunitionSiphonGrenadeRefund = 0.35f; } [HarmonyPatch(typeof(UpgradeProperty_SwarmGun_Mitosis), "Apply")] public static class Mitosis_Apply_Turbo_Patch { [HarmonyPostfix] private static void Postfix(IGear gear, UpgradeInstance upgrade) { if (TurboHelpers.MasterEnabled && TurboHelpers.IsTurbo(upgrade)) { SwarmGun val = (SwarmGun)(object)((gear is SwarmGun) ? gear : null); if (val != null) { ((Gun)val).GunData.fireInterval *= Mathf.Max(0.35f, TurboHelpers.Scale(0.7f)); } } } } [HarmonyPatch(typeof(SwarmGun), "OnUpgradesEnabled")] public static class SwarmGun_OnUpgradesEnabled_Turbo_Patch { [HarmonyPostfix] private static void Postfix(SwarmGun __instance) { //IL_007d: Unknown result type (might be due to invalid IL or missing references) //IL_0087: Expected O, but got Unknown //IL_0087: Unknown result type (might be due to invalid IL or missing references) //IL_0091: Expected O, but got Unknown if (TurboHelpers.MasterEnabled && !((Object)(object)__instance == (Object)null)) { if (TurboHelpers.GearHasTurboNamed((IGear)(object)__instance, "Explosive Pellets")) { ((Gun)__instance).GunData.hitVFXSize *= TurboHelpers.Scale(1.6f); ((Gun)__instance).GunData.bulletMagnetismTarget *= TurboHelpers.Scale(1.2f); } if (TurboHelpers.GearHasTurboNamed((IGear)(object)__instance, "Munition Siphon")) { ((Gun)__instance).OnKillTarget = (KillCallback)Delegate.Combine((Delegate?)(object)((Gun)__instance).OnKillTarget, (Delegate?)new KillCallback(OnMunitionSiphonKill)); } } } private static void OnMunitionSiphonKill(in KillCallbackData data) { IDamageSource source = data.source; SwarmGun val = (SwarmGun)(object)((source is SwarmGun) ? source : null); if (val == null || !TurboHelpers.GearHasTurboNamed((IGear)(object)val, "Munition Siphon")) { return; } Player player = ((Gun)val).Player; if ((Object)(object)player == (Object)null) { return; } try { Throwable[] componentsInChildren = ((Component)player).GetComponentsInChildren(true); foreach (Throwable val2 in componentsInChildren) { if (!((Object)(object)val2 == (Object)null)) { ((CooldownData)(ref val2.CooldownData)).AddCharge(TurboHelpers.Scale(0.35f)); break; } } } catch { } } } public static class TinderboxTurbo { public const float MaxDamageMult = 2f; public static bool TryGetTinderboxGun(IDamageSource source, out Gun gun) { gun = null; IDamageSource val = source; int num = 0; while (val != null && num++ < 8) { Gun val2 = (Gun)(object)((val is Gun) ? val : null); if (val2 != null && TurboHelpers.GearHasTurboNamed((IGear)(object)val2, "Tinderbox")) { gun = val2; return true; } try { val = val.ParentSource; } catch { break; } } return false; } public static float MissingMagMult(Gun gun) { float num = gun.GunData.magazineSize; if (num <= 1f) { return 1f; } float remainingAmmo = gun.RemainingAmmo; float num2 = 1f - Mathf.Clamp01(remainingAmmo / num); float num3 = Mathf.Max(1.1f, TurboHelpers.Scale(2f)); return 1f + num2 * (num3 - 1f); } public static void NeutralizeVanillaMashFireDamage(Gun gun) { MiniCannon val = (MiniCannon)(object)((gun is MiniCannon) ? gun : null); if (val == null) { return; } try { if (val.MiniCannonData.mashFireDamage > 0f) { val.MiniCannonData.mashFireDamage = 1f; } } catch { } } } [HarmonyPatch(typeof(Gun), "OnUpgradesEnabled")] public static class Gun_OnUpgradesEnabled_Tinderbox_Patch { [HarmonyPostfix] private static void Postfix(Gun __instance) { //IL_003c: Unknown result type (might be due to invalid IL or missing references) //IL_0046: Expected O, but got Unknown //IL_0046: Unknown result type (might be due to invalid IL or missing references) //IL_0050: Expected O, but got Unknown if (TurboHelpers.MasterEnabled && !((Object)(object)__instance == (Object)null) && TurboHelpers.GearHasTurboNamed((IGear)(object)__instance, "Tinderbox")) { TinderboxTurbo.NeutralizeVanillaMashFireDamage(__instance); __instance.OnBeforeDamage = (MutableDamageCallback)Delegate.Combine((Delegate?)(object)__instance.OnBeforeDamage, (Delegate?)new MutableDamageCallback(OnBeforeDamage)); } } private static void OnBeforeDamage(ref DamageCallbackData data) { if (TinderboxTurbo.TryGetTinderboxGun(data.source, out var gun)) { data.damageData.damage *= TinderboxTurbo.MissingMagMult(gun); } } } [HarmonyPatch(typeof(Upgrade), "get_Flags")] public static class Upgrade_Flags_Getter_Patch { [HarmonyPostfix] private static void Postfix(Upgrade __instance, ref UpgradeFlags __result) { //IL_0012: Unknown result type (might be due to invalid IL or missing references) //IL_0018: Invalid comparison between Unknown and I4 if (TurboHelpers.MasterEnabled && !((Object)(object)__instance == (Object)null) && (int)__instance.Rarity == 3 && TurboRegistry.IsTracked(__instance)) { __result = (UpgradeFlags)((uint)__result | 0x2000u); } } } [HarmonyPatch(typeof(UpgradeProperty), "GetTurbochargedInfo")] public static class UpgradeProperty_GetTurbochargedInfo_Patch { [HarmonyPostfix] private static void Postfix(UpgradeProperty __instance, ref string __result, Random rand, IUpgradable gear, UpgradeInstance upgrade) { if (!TurboHelpers.MasterEnabled) { return; } Upgrade val = ((upgrade != null) ? upgrade.Upgrade : null); if ((Object)(object)val == (Object)null) { return; } IUpgradable gearContext = gear; try { if (((upgrade != null) ? upgrade.Gear : null) != null) { gearContext = upgrade.Gear; } } catch { } TurboRegistry.TurboDef turboDef = TurboRegistry.Find(val, gearContext); if (turboDef == null || turboDef.EnableExistingOnly) { return; } if (!string.IsNullOrEmpty(__result)) { __result = TurboText.AppendPreview(__result, turboDef, upgrade); } else if (IsFirstProperty(val, __instance)) { string text = TurboText.BuildPreview(turboDef, upgrade); if (!string.IsNullOrEmpty(text)) { __result = text; } } } private static bool IsFirstProperty(Upgrade upgrade, UpgradeProperty property) { //IL_0001: Unknown result type (might be due to invalid IL or missing references) //IL_0006: Unknown result type (might be due to invalid IL or missing references) try { UpgradePropertyList properties = upgrade.Properties; if (!((UpgradePropertyList)(ref properties)).HasProperties || ((UpgradePropertyList)(ref properties)).Count == 0) { return true; } return ((UpgradePropertyList)(ref properties))[0] == property; } catch { return true; } } } [HarmonyPatch(typeof(Upgrade), "GetStatList")] public static class Upgrade_GetStatList_Turbo_Patch { [HarmonyPostfix] private static void Postfix(Upgrade __instance, ref string __result, int seed, UpgradeInstance instance) { //IL_001e: Unknown result type (might be due to invalid IL or missing references) //IL_0024: Invalid comparison between Unknown and I4 //IL_006c: Unknown result type (might be due to invalid IL or missing references) //IL_0071: Unknown result type (might be due to invalid IL or missing references) if (!TurboHelpers.MasterEnabled || instance == null || !instance.IsTurbocharged || (Object)(object)__instance == (Object)null || (int)__instance.Rarity != 3) { return; } IUpgradable gearContext = null; try { gearContext = instance.Gear; } catch { } TurboRegistry.TurboDef turboDef = TurboRegistry.Find(__instance, gearContext); if (turboDef == null || turboDef.EnableExistingOnly) { return; } string text = TurboText.BuildBody(turboDef, instance); if (string.IsNullOrEmpty(text) || (__result != null && __result.IndexOf(text, StringComparison.OrdinalIgnoreCase) >= 0)) { return; } StatData val = UpgradeProperty.AddTurbochargedProperty(instance); StringBuilder stringBuilder = new StringBuilder(); if (!string.IsNullOrEmpty(__result)) { stringBuilder.Append(__result); } if ((__result == null || __result.IndexOf("turbo", StringComparison.OrdinalIgnoreCase) < 0) && ((StatData)(ref val)).IsValid) { string text2 = ((StatData)(ref val)).ToString(instance, false); if (!string.IsNullOrEmpty(text2)) { if (stringBuilder.Length > 0 && !text2.StartsWith("\n")) { stringBuilder.Append('\n'); } stringBuilder.Append(text2); } } string[] array = text.Split(new char[2] { '\n', '\r' }, StringSplitOptions.RemoveEmptyEntries); for (int i = 0; i < array.Length; i++) { string text3 = array[i].Trim(); if (text3.Length != 0 && (__result == null || __result.IndexOf(text3, StringComparison.OrdinalIgnoreCase) < 0)) { if (stringBuilder.Length > 0) { stringBuilder.Append('\n'); } stringBuilder.Append(text3); } } __result = stringBuilder.ToString(); } } [BepInPlugin("sparroh.sparrohsturbocharges", "SparrohsTurbocharges", "1.0.0")] [MycoMod(/*Could not decode attribute arguments.*/)] public class SparrohPlugin : BaseUnityPlugin { public const string PluginGUID = "sparroh.sparrohsturbocharges"; public const string PluginName = "SparrohsTurbocharges"; public const string PluginVersion = "1.0.0"; internal static ManualLogSource Logger; internal static SparrohPlugin Instance; internal static ConfigEntry EnableAll; internal static ConfigEntry DumpExoticsOnLoad; internal static ConfigEntry StrengthMultiplier; private Harmony harmony; private void Awake() { //IL_007b: Unknown result type (might be due to invalid IL or missing references) //IL_0085: Expected O, but got Unknown Instance = this; Logger = ((BaseUnityPlugin)this).Logger; EnableAll = ((BaseUnityPlugin)this).Config.Bind("General", "Enable All Turbocharges", true, "Master toggle for all turbocharge effects in this mod."); DumpExoticsOnLoad = ((BaseUnityPlugin)this).Config.Bind("Debug", "Dump Exotic Upgrades On Load", true, "Logs every Exotic upgrade (gear, display name, API name, properties, flags) once upgrades register."); StrengthMultiplier = ((BaseUnityPlugin)this).Config.Bind("Balance", "Strength Multiplier", 1f, "Global multiplier for numeric turbo bonuses. Lower this if turbos feel too strong."); harmony = new Harmony("sparroh.sparrohsturbocharges"); PatchAllSafe(harmony); PlayerData.AddRegisterUpgradesCallback((Action)OnUpgradesRegistered); Logger.LogInfo((object)"SparrohsTurbocharges v1.0.0 loaded."); } private void Update() { try { if (EnableAll == null || EnableAll.Value) { LagrangeHaloTurbo.Tick(); } } catch { } } private void OnDestroy() { Harmony obj = harmony; if (obj != null) { obj.UnpatchSelf(); } Instance = null; } private static void OnUpgradesRegistered() { try { TurboRegistry.BuildCache(); if (DumpExoticsOnLoad.Value) { TurboRegistry.DumpExotics(Logger); } Logger.LogInfo((object)$"[SparrohsTurbocharges] Registry ready. Tracked turbos: {TurboRegistry.TrackedCount}"); } catch (Exception arg) { Logger.LogError((object)$"[SparrohsTurbocharges] Registry build failed: {arg}"); } } private static void PatchAllSafe(Harmony harmony) { Assembly assembly = typeof(SparrohPlugin).Assembly; int num = 0; int num2 = 0; Type[] types = assembly.GetTypes(); foreach (Type type in types) { object[] customAttributes = type.GetCustomAttributes(typeof(HarmonyPatch), inherit: false); if (customAttributes != null && customAttributes.Length != 0) { try { harmony.CreateClassProcessor(type).Patch(); num++; } catch (Exception ex) { num2++; Logger.LogError((object)("[SparrohsTurbocharges] Failed to patch " + type.Name + ": " + ex.Message)); } } } Logger.LogInfo((object)$"[SparrohsTurbocharges] Harmony patches applied: {num} ok, {num2} failed."); } } public static class TurboHelpers { public static float Strength => SparrohPlugin.StrengthMultiplier?.Value ?? 1f; public static bool MasterEnabled { get { if (SparrohPlugin.EnableAll != null) { return SparrohPlugin.EnableAll.Value; } return true; } } public static bool IsTurbo(UpgradeInstance instance) { if (instance != null) { return instance.IsTurbocharged; } return false; } public static string NormalizeName(string name) { if (string.IsNullOrEmpty(name)) { return string.Empty; } StringBuilder stringBuilder = new StringBuilder(name.Length); bool flag = false; foreach (char c in name) { if (c == '&') { if (!flag && stringBuilder.Length > 0) { stringBuilder.Append(' '); } stringBuilder.Append("and"); flag = false; } else if (char.IsLetterOrDigit(c)) { stringBuilder.Append(char.ToLowerInvariant(c)); flag = false; } else if ((char.IsWhiteSpace(c) || c == '-' || c == '_' || c == '\'') && !flag && stringBuilder.Length > 0) { stringBuilder.Append(' '); flag = true; } } int num = stringBuilder.Length; while (num > 0 && stringBuilder[num - 1] == ' ') { num--; } if (num != stringBuilder.Length) { return stringBuilder.ToString(0, num); } return stringBuilder.ToString(); } public static string NormalizeApi(string api) { return NormalizeName(api).Replace(" ", ""); } public static bool NamesEqual(string a, string b) { if (string.IsNullOrEmpty(a) || string.IsNullOrEmpty(b)) { return false; } return string.Equals(NormalizeName(a), NormalizeName(b), StringComparison.Ordinal); } public static bool ApiEqual(string a, string b) { if (string.IsNullOrEmpty(a) || string.IsNullOrEmpty(b)) { return false; } return string.Equals(NormalizeApi(a), NormalizeApi(b), StringComparison.Ordinal); } public static bool ApiMatches(Upgrade upgrade, string apiName) { if ((Object)(object)upgrade == (Object)null || string.IsNullOrEmpty(apiName)) { return false; } try { return ApiEqual(upgrade.APIName, apiName); } catch { return false; } } public static bool NameMatches(Upgrade upgrade, string displayName) { if ((Object)(object)upgrade == (Object)null || string.IsNullOrEmpty(displayName)) { return false; } try { return NamesEqual(upgrade.Name, displayName); } catch { return false; } } public static bool HasPropertyType(Upgrade upgrade, Type propertyType) { //IL_0016: Unknown result type (might be due to invalid IL or missing references) //IL_001b: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)upgrade == (Object)null || propertyType == null) { return false; } try { UpgradePropertyList properties = upgrade.Properties; if (!((UpgradePropertyList)(ref properties)).HasProperties) { return false; } for (int i = 0; i < ((UpgradePropertyList)(ref properties)).Count; i++) { UpgradeProperty val = ((UpgradePropertyList)(ref properties))[i]; if (val != null && propertyType.IsInstanceOfType(val)) { return true; } } } catch { } return false; } public static bool HasPropertyType(Upgrade upgrade) where T : UpgradeProperty { return HasPropertyType(upgrade, typeof(T)); } public static IUpgradable TryGetUpgradeGear(Upgrade upgrade) { if ((Object)(object)upgrade == (Object)null) { return null; } try { GearInfo val = PlayerData.FindGearInfo(upgrade); if ((Object)(object)val != (Object)null) { return PlayerData.GetGearFromID(val.ID); } } catch { } return null; } public static bool GearTypeAllowed(IUpgradable gear, Type[] requiredGearTypes) { if (requiredGearTypes == null || requiredGearTypes.Length == 0) { return true; } if (gear == null) { return true; } Type type = ((object)gear).GetType(); foreach (Type type2 in requiredGearTypes) { if (type2 != null && type2.IsAssignableFrom(type)) { return true; } } return false; } public static bool GearHasTurbo(IGear gear, Func predicate) { if (!MasterEnabled || gear == null || predicate == null) { return false; } try { foreach (UpgradeInstance activeUpgrade in gear.ActiveUpgrades) { if (activeUpgrade != null && activeUpgrade.IsTurbocharged) { Upgrade upgrade = activeUpgrade.Upgrade; if ((Object)(object)upgrade != (Object)null && predicate(upgrade)) { return true; } } } } catch { } return false; } public static bool GearHasTurboNamed(IGear gear, params string[] keys) { if (keys == null || keys.Length == 0) { return false; } return GearHasTurbo(gear, delegate(Upgrade u) { TurboRegistry.TurboDef turboDef = TurboRegistry.Find(u, (IUpgradable)(object)gear); if (turboDef == null) { return false; } foreach (string text in keys) { if (!string.IsNullOrEmpty(text)) { if (ApiEqual(turboDef.ApiName, text)) { return true; } if (NamesEqual(turboDef.DisplayName, text)) { return true; } } } return false; }); } public static bool PlayerHasTurboNamed(Player player, params string[] keys) { if (!MasterEnabled || (Object)(object)player == (Object)null) { return false; } try { if (player.Gear != null) { for (int i = 0; i < player.Gear.Length; i++) { IGear val = player.Gear[i]; if (val != null && GearHasTurboNamed(val, keys)) { return true; } } } } catch { } return false; } public static float Scale(float value) { return value * Strength; } public static int ScaleInt(int value) { return Math.Max(1, (int)Math.Round((float)value * Strength)); } } public static class TurboIds { public const string CorrodeSiphon = "Corrode Siphon"; public const string ScorchingDetonation = "Scorching Detonation"; public const string ViolentIgnition = "Violent Ignition"; public const string AllPowderedUp = "FBoost"; public const string Immolator = "Immolator"; public const string Pesticide = "Flamethrower"; public const string Pummeler = "BulletCharge"; public const string BreedingSeason = "FriendFire"; public const string ExplosivePellets = "Explosive Pellets"; public const string Mitosis = "Mitosis"; public const string MunitionSiphon = "GrenadeSiphon"; public const string HeavyMunitions = "Heavy Munitions"; public const string LagrangeHalo = "Orbital"; public const string MissileBay = "Missiles"; public const string Tinderbox = "Tinderbox"; public const string GlobulousSiphon = "GlobSiphon"; public const string Deflector = "SawShield"; public const string NutritionSampler = "Nutritious"; public const string Rage = "Rage"; public const string SuperMagnet = "PullGrunts"; public const string Lockdown = "Shackle"; public const string AugerSubroutine = "DrillBoost"; public const string BatteryRecursion = "Battery Recursion"; public const string LayingCable = "LayCable"; public const string Payback = "DmgMissile"; public const string Slipspace = "RefundBurst"; public const string GrenadeBelt = "SlideGrenade"; public const string ClusterBomb = "Cluster Bomb"; public const string HearthAndHome = "FireArea"; public const string InternalCombustion = "Combustion"; public const string FlashStorm = "DownStrike"; public const string LiveWire = "Livewire"; public const string HeavySupport = "Heavy Support"; public const string Overclock = "OverclockCharge"; public const string Harmonizer = "AttunnEleChance"; public const string LinkedList = "LinkedList"; public const string PocketGrenade = "MiniDisc"; } public static class TurboRegistry { public sealed class TurboStatLine { public string Label; public string TextBlockKey; public float Value; public OverrideType Type = (OverrideType)1; } public sealed class TurboDef { public string DisplayName; public string ApiName; public string Family; public string TurboInfo; public bool EnableExistingOnly; public Type PropertyType; public Type[] RequiredGearTypes; public TurboStatLine[] TurboStats; } private static readonly List defs = new List(); private static readonly HashSet trackedApis = new HashSet(StringComparer.OrdinalIgnoreCase); public static int TrackedCount => defs.Count; public static IReadOnlyList All => defs; public static void BuildCache() { defs.Clear(); trackedApis.Clear(); Add("Corrode Siphon", "Corrode Siphon", "Cycler", "Refunded ammo can exceed the 200 magazine siphon cap.", enableExistingOnly: false, typeof(CartridgeSMG)); Add("Scorching Detonation", "Scorching Detonation", "Cycler", "Detonation triggers on Electrocute or Corrode (seed-locked) instead of Ignite.", enableExistingOnly: false, typeof(CartridgeSMG), typeof(UpgradeProperty_SMG_ScorchingDetonation)); Add("Violent Ignition", "Violent Ignition", "Cycler", "If stacks would ignite a target, deal the entire fire DoT as one fire damage hit.", enableExistingOnly: false, typeof(CartridgeSMG), typeof(UpgradeProperty_SMG_ViolentIgnition)); Add("All Powdered Up", "FBoost", "Jackrabbit", null, enableExistingOnly: true, typeof(BounceShotgun)); Add("Immolator", "Immolator", "Jackrabbit", "Creates an aura: teammates gain fire element on weapons while inside and for 3s after.", enableExistingOnly: false, typeof(BounceShotgun)); Add("Pesticide", "Flamethrower", "Jackrabbit", "Damage increases as target health decreases. Range increased.", enableExistingOnly: false, typeof(BounceShotgun), typeof(UpgradeProperty_BounceShotgun_Flamethrower), new TurboStatLine[2] { Stat("Range", 2f, (OverrideType)2, "range"), Stat("Missing HP Damage", 2.25f, (OverrideType)2) }); Add("Pummeler", "BulletCharge", "Jackrabbit", "Charge speed greatly increased.", enableExistingOnly: false, typeof(BounceShotgun), typeof(UpgradeProperty_BounceShotgun_BulletCharge), new TurboStatLine[1] { Stat("Charge Speed", 1.75f, (OverrideType)2, "charge_s") }); Add("Breeding Season", "FriendFire", "Swarm Launcher", null, enableExistingOnly: true, typeof(SwarmGun)); Add("Explosive Pellets", "Explosive Pellets", "Swarm Launcher", "Explosion size increased.", enableExistingOnly: false, typeof(SwarmGun), null, new TurboStatLine[1] { Stat("Explosion Size", 1.35f, (OverrideType)2) }); Add("Mitosis", "Mitosis", "Swarm Launcher", "Fire Rate increased.", enableExistingOnly: false, typeof(SwarmGun), typeof(UpgradeProperty_SwarmGun_Mitosis), new TurboStatLine[1] { Stat("Fire Rate", 1.35f, (OverrideType)2, "firerate") }); Add("Munition Siphon", "GrenadeSiphon", "Swarm Launcher", "Killing targets refunds grenade charge.", enableExistingOnly: false, typeof(SwarmGun)); Add("Heavy Munitions", "Heavy Munitions", "Gunship Cannon", "If maximum magazine size is greater than 1: massive flat damage and knockback.", enableExistingOnly: false, typeof(MiniCannon), null, new TurboStatLine[2] { Stat("Damage", 85f, (OverrideType)1, "damage"), Stat("Knockback", 22f, (OverrideType)1) }); Add("Lagrange Halo", "Orbital", "Gunship Cannon", "While sprinting, fires periodic OrbitalBullets (works while not held).", enableExistingOnly: false, typeof(MiniCannon), typeof(UpgradeProperty_MiniCannon_Orbital)); Add("Missile Bay", "Missiles", "Gunship Cannon", "Converts recoil into increased fire rate.", enableExistingOnly: false, typeof(MiniCannon), null, new TurboStatLine[2] { Stat("Fire Rate", 1.5384616f, (OverrideType)2, "firerate"), Stat("Recoil", 0.35f, (OverrideType)2) }); Add("Tinderbox", "Tinderbox", "Gunship Cannon", "Damage scales with % missing magazine (replaces vanilla mash-fire damage bonus).", enableExistingOnly: false, typeof(MiniCannon), null, new TurboStatLine[1] { Stat("Max Damage (Empty Mag)", 2f, (OverrideType)2, "damage") }); Add("Globulous Siphon", "GlobSiphon", "Globbler", "Grenade siphon charge cost reduced 25% (size per charge unchanged).", enableExistingOnly: false, typeof(Globbler), null, new TurboStatLine[1] { Stat("Charge Cost", 0.75f, (OverrideType)2) }); Add("Deflector", "SawShield", "Carver", "Chance to reflect projectiles back at the attacker.", enableExistingOnly: false, typeof(TheCarver), null, new TurboStatLine[1] { Stat("Deflect Chance", 1.35f, (OverrideType)2, "chance") }); Add("Nutrition Sampler", "Nutritious", "Carver", "After a health chunk: saw area and reach greatly increased for 3 seconds.", enableExistingOnly: false, typeof(TheCarver), typeof(UpgradeProperty_Carver_HealthDrop), new TurboStatLine[3] { Stat("Saw Area", 2.15f, (OverrideType)2), Stat("Saw Reach", 2.15f, (OverrideType)2), Stat("Duration (s)", 3f, (OverrideType)3) }); Add("Rage", "Rage", "Carver", "Rage stacks fall off one at a time (slower while not held).", enableExistingOnly: false, typeof(TheCarver), typeof(UpgradeProperty_Carver_Rage)); Add("Super Magnet", "PullGrunts", "Carver", "While sawing: also pulls fallen limbs and body parts toward the saw.", enableExistingOnly: false, typeof(TheCarver), typeof(UpgradeProperty_Carver_PullIn)); Add("Lockdown", "Shackle", "Carver", "Shackled targets also receive Rot for the full shackle duration.", enableExistingOnly: false, typeof(TheCarver)); Add("Auger Subroutine", "DrillBoost", "Shocklance", "After a normal shot: next Auger charge +50% drill damage and +25% launch duration (consumed on use).", enableExistingOnly: false, typeof(Shocklance), typeof(UpgradeProperty_Shocklance_ForwardBoost), new TurboStatLine[2] { Stat("Auger Damage", 1.5f, (OverrideType)2, "damage"), Stat("Launch Duration", 1.25f, (OverrideType)2) }); Add("Battery Recursion", "Battery Recursion", "Shocklance", "Charge speed increased.", enableExistingOnly: false, typeof(Shocklance), null, new TurboStatLine[1] { Stat("Charge Speed", 1.75f, (OverrideType)2, "charge_s") }); Add("Laying Cable", "LayCable", "Shocklance", "All benefits are shared.", enableExistingOnly: false, typeof(Shocklance), null, new TurboStatLine[1] { Stat("Cable Share", 1.5f, (OverrideType)2) }); Add("Payback", "DmgMissile", "Accelerator", "Payback can trigger while the weapon is not held.", enableExistingOnly: false, typeof(AcceleratorGun)); Add("Slipspace Bullet Transfer", "RefundBurst", "Accelerator", "Stacks consumed are reduced.", enableExistingOnly: false, typeof(AcceleratorGun), null, new TurboStatLine[1] { Stat("Stacks Consumed", 0.5f, (OverrideType)2) }); Add("Grenade Belt", "SlideGrenade", "Grenade", "Extra charge.", enableExistingOnly: false, null, null, new TurboStatLine[1] { Stat("Charges", 1f, (OverrideType)1) }); Add("Cluster Bomb", "Cluster Bomb", "Incendiary Grenade", "Cluster count increased.", enableExistingOnly: false, typeof(IncendiaryGrenade), null, new TurboStatLine[1] { Stat("Cluster Count", 3f, (OverrideType)1) }); Add("Hearth and Home", "FireArea", "Incendiary Grenade", "Lingering fire area also heals allies inside (plus normal recharge).", enableExistingOnly: false, typeof(IncendiaryGrenade), typeof(UpgradeProperty_IncendiaryGrenade_FireArea), new TurboStatLine[1] { Stat("Heal / s", 12f, (OverrideType)1, "health") }); Add("Internal Combustion", "Combustion", "Incendiary Grenade", "Detonation leaves a 6s fire puddle that ignites enemies on contact.", enableExistingOnly: false, typeof(IncendiaryGrenade), typeof(UpgradeProperty_IncendiaryGrenade_Combustion), new TurboStatLine[1] { Stat("Puddle Duration (s)", 6f, (OverrideType)3) }); Add("Flash Storm", "DownStrike", "Shock Grenade", "In-flight lightning strikes deal +40 flat damage (not electrocute DoT / not explosion).", enableExistingOnly: false, typeof(VoltaicGrenade), null, new TurboStatLine[1] { Stat("Strike Damage", 40f, (OverrideType)1, "damage") }); Add("Live Wire", "Livewire", "Shock Grenade", "While self-shocked: lightning arcs to the nearest 3 enemies within 8 m.", enableExistingOnly: false, null, null, new TurboStatLine[3] { Stat("Arc Radius (m)", 8f, (OverrideType)3), Stat("Targets", 3f, (OverrideType)3), Stat("Shock Damage", 25f, (OverrideType)1, "damage") }); Add("Heavy Support", "Heavy Support", "Acid Grenade", "Heavy weapons (API name contains \"heavy\"): magazine size +100%, come fully loaded.", enableExistingOnly: false, typeof(AcidGrenade), null, new TurboStatLine[1] { Stat("Heavy Mag Size", 2f, (OverrideType)2) }); Add("Overclock", "OverclockCharge", "Acid Grenade", "After the overclocked explosion: explosion size and damage increased.", enableExistingOnly: false, typeof(AcidGrenade), null, new TurboStatLine[2] { Stat("Damage", 1.5f, (OverrideType)2, "damage"), Stat("Explosion Size", 1.5f, (OverrideType)2) }); Add("Harmonizer", "AttunnEleChance", "Photon Disc", "Chance increased.", enableExistingOnly: false, typeof(PhotonDisc), null, new TurboStatLine[1] { Stat("Chance", 1.25f, (OverrideType)2, "chance") }); Add("Linked List", "LinkedList", "Photon Disc", "Damage and explosion size increase for each tumble.", enableExistingOnly: false, typeof(PhotonDisc), typeof(UpgradeProperty_PhotonDisc_LinkedList), new TurboStatLine[2] { Stat("Damage / Tumble", 1.12f, (OverrideType)2, "damage"), Stat("Size / Tumble", 1.1f, (OverrideType)2) }); Add("Pocket Grenade", "MiniDisc", "Photon Disc", "After each throw: chance to immediately regain one disc charge.", enableExistingOnly: false, typeof(PhotonDisc), null, new TurboStatLine[1] { Stat("Recharge Chance", 0.35f, (OverrideType)2, "chance") }); } private static TurboStatLine Stat(string label, float value, OverrideType type, string textBlockKey = null) { //IL_0014: Unknown result type (might be due to invalid IL or missing references) //IL_0015: Unknown result type (might be due to invalid IL or missing references) return new TurboStatLine { Label = label, Value = value, Type = type, TextBlockKey = textBlockKey }; } private static void Add(string displayName, string apiName, string family, string turboInfo, bool enableExistingOnly = false, Type gear = null, Type prop = null, TurboStatLine[] stats = null) { if (!string.IsNullOrEmpty(apiName) && trackedApis.Add(TurboHelpers.NormalizeApi(apiName))) { defs.Add(new TurboDef { DisplayName = displayName, ApiName = apiName, Family = family, TurboInfo = turboInfo, EnableExistingOnly = enableExistingOnly, PropertyType = prop, RequiredGearTypes = ((!(gear != null)) ? null : new Type[1] { gear }), TurboStats = stats }); } } public static TurboDef Find(Upgrade upgrade) { return Find(upgrade, null); } public static TurboDef Find(Upgrade upgrade, IUpgradable gearContext) { if ((Object)(object)upgrade == (Object)null) { return null; } IUpgradable gear = gearContext ?? TurboHelpers.TryGetUpgradeGear(upgrade); string text = null; try { text = upgrade.APIName; } catch { } if (!string.IsNullOrEmpty(text)) { for (int i = 0; i < defs.Count; i++) { TurboDef turboDef = defs[i]; if (TurboHelpers.ApiEqual(turboDef.ApiName, text) && TurboHelpers.GearTypeAllowed(gear, turboDef.RequiredGearTypes)) { return turboDef; } } } for (int j = 0; j < defs.Count; j++) { TurboDef turboDef2 = defs[j]; if (!(turboDef2.PropertyType == null) && TurboHelpers.HasPropertyType(upgrade, turboDef2.PropertyType) && TurboHelpers.GearTypeAllowed(gear, turboDef2.RequiredGearTypes)) { return turboDef2; } } for (int k = 0; k < defs.Count; k++) { TurboDef turboDef3 = defs[k]; if (TurboHelpers.GearTypeAllowed(gear, turboDef3.RequiredGearTypes) && TurboHelpers.NameMatches(upgrade, turboDef3.DisplayName)) { return turboDef3; } } return null; } public static bool IsTracked(Upgrade upgrade) { return Find(upgrade) != null; } public static bool IsTracked(Upgrade upgrade, IUpgradable gear) { return Find(upgrade, gear) != null; } public static string GetTurboInfo(Upgrade upgrade) { return Find(upgrade)?.TurboInfo; } public static void DumpExotics(ManualLogSource log) { if (log == null) { return; } try { StringBuilder stringBuilder = new StringBuilder(); stringBuilder.AppendLine("[SparrohsTurbocharges] === Tracked Turbo Definitions ==="); stringBuilder.AppendLine($"Tracked turbo definitions: {defs.Count}"); for (int i = 0; i < defs.Count; i++) { TurboDef turboDef = defs[i]; stringBuilder.Append(" - [" + turboDef.Family + "] " + turboDef.DisplayName + " api=\"" + turboDef.ApiName + "\""); if (turboDef.EnableExistingOnly) { stringBuilder.Append(" (enable-existing)"); } if (turboDef.PropertyType != null) { stringBuilder.Append(" prop=" + turboDef.PropertyType.Name); } if (turboDef.TurboStats != null && turboDef.TurboStats.Length != 0) { stringBuilder.Append($" stats={turboDef.TurboStats.Length}"); } if (turboDef.RequiredGearTypes != null && turboDef.RequiredGearTypes.Length != 0) { stringBuilder.Append(" gear="); for (int j = 0; j < turboDef.RequiredGearTypes.Length; j++) { if (j > 0) { stringBuilder.Append('|'); } stringBuilder.Append(turboDef.RequiredGearTypes[j]?.Name ?? "?"); } } stringBuilder.AppendLine(); } log.LogInfo((object)stringBuilder.ToString()); } catch (Exception ex) { log.LogWarning((object)("[SparrohsTurbocharges] Dump failed: " + ex.Message)); } } } public static class TurboRuntime { public static bool LogEnabled; public static void Log(string message) { if (LogEnabled) { ManualLogSource logger = SparrohPlugin.Logger; if (logger != null) { logger.LogInfo((object)("[Turbo] " + message)); } } } public static void LogWarn(string message) { ManualLogSource logger = SparrohPlugin.Logger; if (logger != null) { logger.LogWarning((object)("[Turbo] " + message)); } } public static void DumpGearUpgrades(IGear gear, string context) { if (!LogEnabled || gear == null) { return; } try { StringBuilder stringBuilder = new StringBuilder(); stringBuilder.Append(context).Append(" gear=").Append(((object)gear).GetType().Name); try { StringBuilder stringBuilder2 = stringBuilder.Append(" info="); GearInfo info = ((IUpgradable)gear).Info; stringBuilder2.Append(((info != null) ? info.Name : null) ?? "?"); } catch { } int num = 0; foreach (UpgradeInstance activeUpgrade in gear.ActiveUpgrades) { if (activeUpgrade != null) { Upgrade upgrade = activeUpgrade.Upgrade; string value = "?"; string value2 = "?"; try { value = ((upgrade != null) ? upgrade.Name : null) ?? "?"; } catch { } try { value2 = ((upgrade != null) ? upgrade.APIName : null) ?? "?"; } catch { } stringBuilder.Append(" | [").Append(num++).Append("] name=\"") .Append(value) .Append("\" api=\"") .Append(value2) .Append("\" turbo=") .Append(activeUpgrade.IsTurbocharged); TurboRegistry.TurboDef turboDef = TurboRegistry.Find(upgrade, (IUpgradable)(object)gear); if (turboDef != null) { stringBuilder.Append(" DEF=").Append(turboDef.DisplayName); } else { stringBuilder.Append(" DEF=null"); } } } Log(stringBuilder.ToString()); } catch (Exception ex) { LogWarn("DumpGearUpgrades failed: " + ex.Message); } } public static void OnBecameTurbocharged(UpgradeInstance instance) { if (instance == null || !instance.IsTurbocharged) { return; } Upgrade upgrade = instance.Upgrade; string arg = "?"; try { arg = ((upgrade != null) ? upgrade.Name : null) ?? "?"; } catch { } Log($"IsTurbocharged=true for \"{arg}\" (id={((object)instance).GetHashCode()})"); try { IUpgradable gear = instance.Gear; IGear val = (IGear)(object)((gear is IGear) ? gear : null); if (val != null) { Log("Refresh prefab gear type=" + ((object)val).GetType().Name); TryApplyUpgrades(val, "prefab"); } Player localPlayer = Player.LocalPlayer; if (((localPlayer != null) ? localPlayer.Gear : null) == null) { return; } for (int i = 0; i < localPlayer.Gear.Length; i++) { IGear val2 = localPlayer.Gear[i]; if (val2 != null && LiveGearHasInstance(val2, instance)) { Log($"Refresh live gear slot={i} type={((object)val2).GetType().Name}"); TryApplyUpgrades(val2, "live"); } } } catch (Exception ex) { LogWarn("OnBecameTurbocharged failed: " + ex.Message); } } private static bool LiveGearHasInstance(IGear gear, UpgradeInstance instance) { try { foreach (UpgradeInstance activeUpgrade in gear.ActiveUpgrades) { if (activeUpgrade == instance) { return true; } if (activeUpgrade != null && instance != null && activeUpgrade.IsTurbocharged && (Object)(object)activeUpgrade.Upgrade != (Object)null && (Object)(object)instance.Upgrade != (Object)null && activeUpgrade.Upgrade == instance.Upgrade) { return true; } } } catch { } return false; } private static void TryApplyUpgrades(IGear gear, string tag) { try { DumpGearUpgrades(gear, "BEFORE ApplyUpgrades(" + tag + ")"); gear.ApplyUpgrades(); DumpGearUpgrades(gear, "AFTER ApplyUpgrades(" + tag + ")"); } catch (Exception ex) { LogWarn("ApplyUpgrades(" + tag + ") failed: " + ex.Message); try { gear.OnUpgradesEnabled(); Log("Fallback OnUpgradesEnabled(" + tag + ") ok"); } catch (Exception ex2) { LogWarn("OnUpgradesEnabled fallback failed: " + ex2.Message); } } } } [HarmonyPatch(typeof(UpgradeInstance), "set_IsTurbocharged")] public static class UpgradeInstance_set_IsTurbocharged_Patch { [HarmonyPostfix] private static void Postfix(UpgradeInstance __instance, bool value) { if (value && TurboHelpers.MasterEnabled) { TurboRuntime.OnBecameTurbocharged(__instance); } } } [HarmonyPatch(typeof(Gun), "OnUpgradesEnabled")] public static class Gun_OnUpgradesEnabled_TurboDiag_Patch { [HarmonyPostfix] private static void Postfix(Gun __instance) { if (TurboHelpers.MasterEnabled && !((Object)(object)__instance == (Object)null)) { TurboRuntime.DumpGearUpgrades((IGear)(object)__instance, "Gun.OnUpgradesEnabled"); } } } public static class TurboText { public static string BuildBody(TurboRegistry.TurboDef def, UpgradeInstance instance = null) { if (def == null || def.EnableExistingOnly) { return null; } StringBuilder stringBuilder = new StringBuilder(); if (!string.IsNullOrEmpty(def.TurboInfo)) { stringBuilder.Append(def.TurboInfo.Trim()); } AppendStatLines(stringBuilder, def, instance); AppendDynamicLines(stringBuilder, def, instance); if (stringBuilder.Length == 0) { return null; } return stringBuilder.ToString(); } public static string BuildPreview(TurboRegistry.TurboDef def, UpgradeInstance instance = null) { return BuildBody(def, instance); } public static string AppendPreview(string existing, TurboRegistry.TurboDef def, UpgradeInstance instance = null) { string text = BuildPreview(def, instance); if (string.IsNullOrEmpty(text)) { return existing; } if (string.IsNullOrEmpty(existing)) { return text; } if (!string.IsNullOrEmpty(def.TurboInfo) && existing.IndexOf(def.TurboInfo.Trim(), StringComparison.OrdinalIgnoreCase) >= 0) { StringBuilder stringBuilder = new StringBuilder(existing); AppendStatLines(stringBuilder, def, instance, skipIfAlreadyPresent: true); AppendDynamicLines(stringBuilder, def, instance); return stringBuilder.ToString(); } if (existing.IndexOf(text, StringComparison.OrdinalIgnoreCase) >= 0) { return existing; } return existing + "\n" + text; } public static string FormatStatLine(TurboRegistry.TurboStatLine stat, UpgradeInstance instance = null) { //IL_0023: Unknown result type (might be due to invalid IL or missing references) //IL_0029: Invalid comparison between Unknown and I4 //IL_007a: Unknown result type (might be due to invalid IL or missing references) //IL_0080: Invalid comparison between Unknown and I4 //IL_0088: Unknown result type (might be due to invalid IL or missing references) //IL_00b0: Unknown result type (might be due to invalid IL or missing references) //IL_00b8: Unknown result type (might be due to invalid IL or missing references) //IL_00be: Unknown result type (might be due to invalid IL or missing references) if (stat == null) { return null; } string text = ResolveLabel(stat); if (string.IsNullOrEmpty(text)) { return null; } float num = TurboHelpers.Scale(stat.Value); if ((int)stat.Type == 2 && stat.Value > 0f) { num = ((!(stat.Value >= 1f)) ? (1f - (1f - stat.Value) * TurboHelpers.Strength) : (1f + (stat.Value - 1f) * TurboHelpers.Strength)); } int num2 = (((int)stat.Type != 2) ? 2 : 0); string text2 = StatData.GetValueString(stat.Type, num, num2, (string)null); if (string.IsNullOrEmpty(text2)) { text2 = num.ToString("0.##"); } StatData val = default(StatData); ((StatData)(ref val))..ctor(text, text2, stat.Type, (LabelType)1, default(BoostParams)); try { return ((StatData)(ref val)).ToString(instance, false); } catch { return text + ": " + text2; } } private static void AppendStatLines(StringBuilder sb, TurboRegistry.TurboDef def, UpgradeInstance instance, bool skipIfAlreadyPresent = false) { if (def.TurboStats == null || def.TurboStats.Length == 0) { return; } for (int i = 0; i < def.TurboStats.Length; i++) { string value = FormatStatLine(def.TurboStats[i], instance); if (!string.IsNullOrEmpty(value) && (!skipIfAlreadyPresent || sb.ToString().IndexOf(value, StringComparison.OrdinalIgnoreCase) < 0)) { if (sb.Length > 0) { sb.Append('\n'); } sb.Append(value); } } } private static void AppendDynamicLines(StringBuilder sb, TurboRegistry.TurboDef def, UpgradeInstance instance) { if (def == null || (!TurboHelpers.ApiEqual(def.ApiName, "Scorching Detonation") && !TurboHelpers.NamesEqual(def.DisplayName, "Scorching Detonation"))) { return; } string text = ((instance == null) ? "Shock or Acid" : CyclerTurbos.GetScorchingElementLabel(instance)); string value = "Element: " + text; if (sb.ToString().IndexOf(value, StringComparison.OrdinalIgnoreCase) < 0) { if (sb.Length > 0) { sb.Append('\n'); } sb.Append(value); } } private static string ResolveLabel(TurboRegistry.TurboStatLine stat) { if (!string.IsNullOrEmpty(stat.TextBlockKey)) { try { string text = TextBlocks.GetString(stat.TextBlockKey, 0); if (!string.IsNullOrEmpty(text) && text.IndexOf("MISSING", StringComparison.OrdinalIgnoreCase) < 0) { return text; } } catch { } } return stat.Label; } } namespace SparrohsTurbocharges { public static class MyPluginInfo { public const string PLUGIN_GUID = "SparrohsTurbocharges"; public const string PLUGIN_NAME = "SparrohsTurbocharges"; public const string PLUGIN_VERSION = "1.0.0"; } } namespace System.Runtime.CompilerServices { [AttributeUsage(AttributeTargets.Assembly, AllowMultiple = true)] internal sealed class IgnoresAccessChecksToAttribute : Attribute { public IgnoresAccessChecksToAttribute(string assemblyName) { } } }