Please disclose if any significant portion of your mod was created using AI tools by adding the 'AI Generated' category. Failing to do so may result in the mod being removed from Thunderstore.
Decompiled source of BetterArmoryPlus v1.0.1
BetterArmoryPlus.dll
Decompiled 12 hours ago
The result has been truncated due to the large size, download it to view full contents!
using System; using System.Collections; using System.Collections.Generic; using System.Diagnostics; using System.Reflection; using System.Reflection.Emit; using System.Runtime.CompilerServices; using System.Text; using BepInEx; using BepInEx.Configuration; using BepInEx.Logging; using HarmonyLib; using Unity.Netcode; using UnityEngine; using UnityEngine.AI; using UnityEngine.Rendering; using UnityEngine.Rendering.HighDefinition; [assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)] [assembly: AssemblyVersion("0.0.0.0")] namespace BoltActionCrits; [BepInPlugin("grayl.boltactioncrits", "BetterArmoryPlus", "1.0.1")] [BepInDependency(/*Could not decode attribute arguments.*/)] public class Plugin : BaseUnityPlugin { private class LoopState { public object B; public object Clip; public float Start; public float End; public float Fade; public bool Fading; public double FadeStart; public float PrevT; } private class Burn { public int N; public double Carry; public double Last = -100.0; public double PrevLast; public double PrevCarry; public int PrevN; } public const string Guid = "grayl.boltactioncrits"; public const string Name = "BetterArmoryPlus"; public const string Version = "1.0.1"; internal static ManualLogSource Log; internal static ConfigEntry<bool> Enabled; internal static ConfigEntry<bool> LogCrits; internal static ConfigEntry<float> RifleAvgDamage; internal static ConfigEntry<float> RifleCritChance; internal static ConfigEntry<float> RifleCritMult; internal static ConfigEntry<float> FlameCritChance; internal static ConfigEntry<float> FlameCritMult; internal static FieldInfo IdField; internal static ConfigEntry<bool> FixGunAudio; internal static ConfigEntry<bool> AudioDiagnostics; internal static ConfigEntry<float> FlameRangeMult; internal static ConfigEntry<float> RevolverCritChance; internal static ConfigEntry<float> RevolverCritMult; internal static ConfigEntry<float> JamChance; internal static ConfigEntry<float> OverheatSeconds; internal static ConfigEntry<float> OverheatLockout; internal static ConfigEntry<bool> ShowCritPopup; internal static ConfigEntry<bool> FlameRamp; internal static ConfigEntry<bool> FlameRampLog; internal static ConfigEntry<bool> SmoothFlameLoop; internal static ConfigEntry<bool> OrangeFlame; internal static ConfigEntry<bool> FlameWalls; internal static ConfigEntry<float> FlameGlow; internal static ConfigEntry<float> FlameCustomLength; internal static ConfigEntry<float> FlameRampStep; internal static ConfigEntry<float> FlameRampCap; internal static ConfigEntry<float> FlameWidthMult; internal static ConfigEntry<float> FlameVisualMult; internal static ConfigEntry<float> FlameRampGrace; internal static ConfigEntry<string> JamWeapons; private static readonly HashSet<int> ScaledParticles = new HashSet<int>(); private static readonly HashSet<int> SeenClips = new HashSet<int>(); private static readonly HashSet<string> SeenSources = new HashSet<string>(); private static FieldInfo ShotAudioField; private static MethodInfo PrefabForMethod; private static readonly HashSet<int> RepairedWeapons = new HashSet<int>(); private static readonly string[] CopyFields = new string[14] { "FireClips", "FireMechanicalClips", "FireMechanicalClipDelaySeconds", "ReloadTacClip", "ReloadEmptyClip", "ReloadStageStartClip", "ReloadStageLoopClip", "ReloadStageEndClip", "FireClip", "DryFireClip", "ReloadStartClip", "ReloadFinishClip", "SafetyOnClip", "SafetyOffClip" }; private static readonly string[] ClipFields = new string[8] { "FireClips", "FireMechanicalClips", "ReloadTacClip", "ReloadEmptyClip", "ReloadStageStartClip", "ReloadStageLoopClip", "ReloadStageEndClip", "FireClip" }; internal static PropertyInfo FlameDamageProp; private static readonly Random Rng = new Random(); private const string RifleId = "kar98k"; private static MethodInfo PlayLocalMethod; private static MethodInfo HoldFireGateMethod; private static MethodInfo SetLocalUseMethod; private static FieldInfo TriggerHeldField; private static FieldInfo StreamAudioField; private static readonly Stopwatch Clock = Stopwatch.StartNew(); private static double _lastPopup = -10.0; private static readonly HashSet<int> Jammed = new HashSet<int>(); private static readonly Dictionary<int, double> JamTipShown = new Dictionary<int, double>(); private static readonly Dictionary<int, double> Heat = new Dictionary<int, double>(); private static readonly Dictionary<int, double> LastTick = new Dictionary<int, double>(); private static readonly Dictionary<int, double> LockedUntil = new Dictionary<int, double>(); private static bool _forcingStop; private static bool _scareWarned; private static bool _reactionsOn; private static readonly Dictionary<int, LoopState> Loops = new Dictionary<int, LoopState>(); private static bool _loopWarned; private static readonly BindingFlags PubInst = BindingFlags.Instance | BindingFlags.Public; private static bool DumpedParticles; private static readonly Dictionary<int, Burn> Burns = new Dictionary<int, Burn>(); private static PropertyInfo FlameIntervalProp; [ThreadStatic] private static Burn _tickBurn; [ThreadStatic] private static int _tickPlanned; [ThreadStatic] private static bool _tickCrit; private static double Now { [CompilerGenerated] get { return Clock.Elapsed.TotalSeconds; } } private void Awake() { //IL_0462: Unknown result type (might be due to invalid IL or missing references) //IL_0469: Expected O, but got Unknown //IL_0548: Unknown result type (might be due to invalid IL or missing references) //IL_054f: Expected O, but got Unknown //IL_0643: Unknown result type (might be due to invalid IL or missing references) //IL_065e: Unknown result type (might be due to invalid IL or missing references) //IL_066b: Expected O, but got Unknown //IL_066b: Expected O, but got Unknown //IL_06a3: Unknown result type (might be due to invalid IL or missing references) //IL_06b1: Expected O, but got Unknown //IL_0768: Unknown result type (might be due to invalid IL or missing references) //IL_076f: Expected O, but got Unknown //IL_0785: Unknown result type (might be due to invalid IL or missing references) //IL_078c: Expected O, but got Unknown //IL_0868: Unknown result type (might be due to invalid IL or missing references) //IL_0883: Unknown result type (might be due to invalid IL or missing references) //IL_0890: Expected O, but got Unknown //IL_0890: Expected O, but got Unknown //IL_08ab: Unknown result type (might be due to invalid IL or missing references) //IL_08b9: Expected O, but got Unknown //IL_0a77: Unknown result type (might be due to invalid IL or missing references) //IL_0a7e: Expected O, but got Unknown //IL_0992: Unknown result type (might be due to invalid IL or missing references) //IL_09a0: Expected O, but got Unknown //IL_09bd: Unknown result type (might be due to invalid IL or missing references) //IL_09c4: Expected O, but got Unknown //IL_0ad2: Unknown result type (might be due to invalid IL or missing references) //IL_0ad9: Expected O, but got Unknown //IL_0bb3: Unknown result type (might be due to invalid IL or missing references) //IL_0bce: Unknown result type (might be due to invalid IL or missing references) //IL_0bdb: Expected O, but got Unknown //IL_0bdb: Expected O, but got Unknown Log = ((BaseUnityPlugin)this).Logger; Enabled = ((BaseUnityPlugin)this).Config.Bind<bool>("General", "Enabled", true, "Turn this mod on or off."); LogCrits = ((BaseUnityPlugin)this).Config.Bind<bool>("General", "Log Crits", false, "Write a line to the log on every crit."); FixGunAudio = ((BaseUnityPlugin)this).Config.Bind<bool>("Audio Fix", "Preload Gun Sounds", true, "Make sure Better Armory's packed gunshot/reload sounds are loaded into memory before they play."); AudioDiagnostics = ((BaseUnityPlugin)this).Config.Bind<bool>("Audio Fix", "Log Audio Diagnostics", false, "Log each gun sound's load state once, and each gun's shot audio source settings once."); RifleAvgDamage = ((BaseUnityPlugin)this).Config.Bind<float>("Bolt-Action Rifle", "Average Damage", 3.5f, "Average damage per hit before crits. Fractions roll: 3.5 = 50% chance of 3, 50% chance of 4. 0 = use Better Armory's own Enemy Damage values."); RifleCritChance = ((BaseUnityPlugin)this).Config.Bind<float>("Bolt-Action Rifle", "Crit Chance", 0.33f, "Chance (0 to 1) a hit is critical."); RifleCritMult = ((BaseUnityPlugin)this).Config.Bind<float>("Bolt-Action Rifle", "Crit Multiplier", 2.5f, "Damage multiplier on a crit, rounded up."); RevolverCritChance = ((BaseUnityPlugin)this).Config.Bind<float>("Revolver", "Crit Chance", 0.25f, "Chance (0 to 1) a Revolver hit is critical."); RevolverCritMult = ((BaseUnityPlugin)this).Config.Bind<float>("Revolver", "Crit Multiplier", 2f, "Damage multiplier on a Revolver crit, rounded up."); ShowCritPopup = ((BaseUnityPlugin)this).Config.Bind<bool>("Feedback", "Show CRIT Popup", true, "Show an on-screen CRIT! tip (with sound) when YOUR shot or flame crits."); JamChance = ((BaseUnityPlugin)this).Config.Bind<float>("Jamming", "Jam Chance", 0.03f, "Chance (0 to 1) per shot that a gun jams. 0 = off."); JamWeapons = ((BaseUnityPlugin)this).Config.Bind<string>("Jamming", "Weapon Ids", "x18,revolver", "Which Better Armory guns can jam (x18 = Pistol, revolver, mx16a4 = Assault Rifle, kar98k = Bolt-Action, heavy shotgun id)."); OverheatSeconds = ((BaseUnityPlugin)this).Config.Bind<float>("Flame Thrower", "Overheat After Seconds", 6f, "Seconds of continuous flame before it overheats. Heat cools 1.5x faster than it builds. 0 = off."); OverheatLockout = ((BaseUnityPlugin)this).Config.Bind<float>("Flame Thrower", "Overheat Lockout Seconds", 3f, "How long the flamethrower is unusable after overheating."); FlameCritChance = ((BaseUnityPlugin)this).Config.Bind<float>("Flame Thrower", "Crit Chance", 0.15f, "Chance (0 to 1) each burn tick is critical."); FlameRamp = ((BaseUnityPlugin)this).Config.Bind<bool>("Flame Thrower", "Ramping Burn", true, "Each consecutive burn tick on the same creature does more damage: Step, 2x Step, 3x Step... Resets if the flame leaves it for a moment."); FlameRampStep = ((BaseUnityPlugin)this).Config.Bind<float>("Flame Thrower", "Ramp Step", 0.5f, "Damage added per consecutive tick (0.5 = 0.5, 1, 1.5, 2...). Fractions carry over between ticks."); FlameRampCap = ((BaseUnityPlugin)this).Config.Bind<float>("Flame Thrower", "Ramp Max Per Tick", 0f, "Highest damage a single tick can ramp to. 0 = no cap."); FlameWidthMult = ((BaseUnityPlugin)this).Config.Bind<float>("Flame Thrower", "Width Multiplier", 1.6f, "Widens the flame's hit cone (Better Armory: 0.2 m at the nozzle, 0.9 m at the tip). 1.6 = 0.32 m / 1.44 m. Makes moving or big targets easier to keep burning. Host decides."); FlameVisualMult = ((BaseUnityPlugin)this).Config.Bind<float>("Flame Thrower", "Visual Length Multiplier", 1.5f, "How much farther the visible flame reaches (scales particle speed, same timing). Tune this until the flame you see ends where it stops hurting. 1 = Better Armory default."); FlameRampGrace = ((BaseUnityPlugin)this).Config.Bind<float>("Flame Thrower", "Ramp Grace Seconds", 2.5f, "How long the flame can leave a creature before its burn ramp resets."); OrangeFlame = ((BaseUnityPlugin)this).Config.Bind<bool>("Flame Thrower", "Orange Flame", true, "Replaces the blue Old Bird flame with an orange fire stream that ends where the flame stops doing damage. Only changes what you see."); FlameCustomLength = ((BaseUnityPlugin)this).Config.Bind<float>("Flame Thrower", "Orange Flame Length", 0f, "How far the orange flame reaches in meters. 0 = match the damage range automatically (8 m x Range Multiplier)."); FlameGlow = ((BaseUnityPlugin)this).Config.Bind<float>("Flame Thrower", "Orange Flame Glow", 1f, "Brightness of the orange flame. Raise it if the flame looks dull, lower it if it washes out the screen."); FlameWalls = ((BaseUnityPlugin)this).Config.Bind<bool>("Flame Thrower", "Orange Flame Stops At Walls", true, "Fire splashes off walls and floors instead of passing through them."); SmoothFlameLoop = ((BaseUnityPlugin)this).Config.Bind<bool>("Flame Thrower", "Smooth Sound Loop", true, "Removes the silent gap when the flamethrower's looping sound restarts, by skipping the clip's silent ends and crossfading the loop point."); FlameRampLog = ((BaseUnityPlugin)this).Config.Bind<bool>("Flame Thrower", "Log Burn Ticks", false, "Log each ramping burn tick (for testing)."); FlameCritMult = ((BaseUnityPlugin)this).Config.Bind<float>("Flame Thrower", "Crit Multiplier", 2.5f, "Damage multiplier on a crit tick, rounded up (1 -> 3)."); FlameRangeMult = ((BaseUnityPlugin)this).Config.Bind<float>("Flame Thrower", "Range Multiplier", 1.5f, "Multiplies the flamethrower's reach (Better Armory default 8 m). 1.5 = 12 m. The visible flame is lengthened to match. Damage reach is decided by the host."); try { Assembly assembly = null; Assembly[] assemblies = AppDomain.CurrentDomain.GetAssemblies(); foreach (Assembly assembly2 in assemblies) { if (assembly2.GetName().Name == "BetterArmory") { assembly = assembly2; break; } } if (assembly == null) { Log.LogError((object)"BetterArmory not found; mod disabled."); return; } Harmony val = new Harmony("grayl.boltactioncrits"); try { StartSwapSounds(val, assembly); } catch (Exception ex) { Log.LogError((object)("Swap sound fix failed to start (rest of the mod still works): " + ex)); } try { StartReactions(val); } catch (Exception ex2) { Log.LogError((object)("Monster reactions failed to start (rest of the mod still works): " + ex2)); } Type type = assembly.GetType("Y4NGZUpgrades.Weapons.Y4NGZWeaponBallistics"); Type type2 = assembly.GetType("Y4NGZUpgrades.Weapons.WeaponConfig"); MethodInfo methodInfo = type?.GetMethod("ForceAtDistance", BindingFlags.Instance | BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic); IdField = type2?.GetField("Id", BindingFlags.Instance | BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic); if (methodInfo != null && IdField != null) { MethodInfo methodInfo2 = methodInfo; HarmonyMethod val2 = new HarmonyMethod(typeof(Plugin).GetMethod("ForcePostfix", BindingFlags.Instance | BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic)); val.Patch((MethodBase)methodInfo2, (HarmonyMethod)null, val2, (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null); Log.LogInfo((object)$"Rifle active: avg {RifleAvgDamage.Value}, crit {RifleCritChance.Value:P0} x{RifleCritMult.Value}."); } else { Log.LogError((object)"Rifle damage method not found (Armory version changed?); rifle changes off."); } Type type3 = assembly.GetType("Y4NGZUpgrades.Weapons.Y4NGZWeaponBase"); MethodInfo methodInfo3 = type3?.GetMethod("PlayShotAudio", BindingFlags.Instance | BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic); ShotAudioField = type3?.GetField("_shotAudio", BindingFlags.Instance | BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic); PrefabForMethod = assembly.GetType("Y4NGZUpgrades.Weapons.NativeWeaponRegistry")?.GetMethod("PrefabFor", BindingFlags.Instance | BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic); if (methodInfo3 != null) { val.Patch((MethodBase)methodInfo3, new HarmonyMethod(typeof(Plugin).GetMethod("ShotAudioPrefix", BindingFlags.Instance | BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic)), new HarmonyMethod(typeof(Plugin).GetMethod("ShotAudioPostfix", BindingFlags.Instance | BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic)), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null); MethodInfo method = type3.GetMethod("PlayLocalClip", BindingFlags.Instance | BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic); if (method != null) { val.Patch((MethodBase)method, new HarmonyMethod(typeof(Plugin).GetMethod("LocalClipPrefix", BindingFlags.Instance | BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic)), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null); } Log.LogInfo((object)"Gun audio fix active."); } else { Log.LogError((object)"Gun audio hook not found; audio fix off."); } Type type4 = assembly.GetType("Y4NGZUpgrades.Weapons.FlamethrowerStreamDriver"); MethodInfo methodInfo4 = type4?.GetMethod("TouchEnemy", BindingFlags.Instance | BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic); FlameDamageProp = type4?.GetProperty("DirectDamage", BindingFlags.Instance | BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic); if (methodInfo4 != null && FlameDamageProp != null && FlameDamageProp.GetSetMethod(nonPublic: true) != null) { MethodInfo methodInfo2 = methodInfo4; HarmonyMethod val2 = new HarmonyMethod(typeof(Plugin).GetMethod("FlamePrefix", BindingFlags.Instance | BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic)); HarmonyMethod val3 = new HarmonyMethod(typeof(Plugin).GetMethod("FlameFinalizer", BindingFlags.Instance | BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic)); val.Patch((MethodBase)methodInfo2, val2, (HarmonyMethod)null, (HarmonyMethod)null, val3, (HarmonyMethod)null); Log.LogInfo((object)$"Flame crits active: {FlameCritChance.Value:P0} x{FlameCritMult.Value}."); } else { Log.LogError((object)"Flamethrower damage hook not found; flame crits off."); } if (type3 != null) { MethodInfo method2 = type3.GetMethod("FireOnce", BindingFlags.Instance | BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic); MethodInfo method3 = type3.GetMethod("BeginReload", BindingFlags.Instance | BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic); PlayLocalMethod = type3.GetMethod("PlayLocalClip", BindingFlags.Instance | BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic); HoldFireGateMethod = type3.GetMethod("HoldFireGate", BindingFlags.Instance | BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic); if (method2 != null && method3 != null) { val.Patch((MethodBase)method2, new HarmonyMethod(typeof(Plugin).GetMethod("FireOncePrefix", BindingFlags.Instance | BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic)), new HarmonyMethod(typeof(Plugin).GetMethod("FireOncePostfix", BindingFlags.Instance | BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic)), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null); val.Patch((MethodBase)method3, new HarmonyMethod(typeof(Plugin).GetMethod("BeginReloadPrefix", BindingFlags.Instance | BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic)), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null); Log.LogInfo((object)$"Jamming active: {JamChance.Value:P0} per shot for [{JamWeapons.Value}]."); } else { Log.LogError((object)"Jam hooks not found; jamming off."); } } if (type4 != null) { MethodInfo method4 = type4.GetMethod("SetLocalUse", BindingFlags.Instance | BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic); MethodInfo method5 = type4.GetMethod("Update", BindingFlags.Instance | BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic); TriggerHeldField = type4.GetField("_localTriggerHeld", BindingFlags.Instance | BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic); StreamAudioField = type4.GetField("_streamAudio", BindingFlags.Instance | BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic); if (method4 != null && method5 != null && TriggerHeldField != null) { val.Patch((MethodBase)method4, new HarmonyMethod(typeof(Plugin).GetMethod("SetUsePrefix", BindingFlags.Instance | BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic)), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null); MethodInfo methodInfo2 = method5; HarmonyMethod val3 = new HarmonyMethod(typeof(Plugin).GetMethod("FlameUpdatePostfix", BindingFlags.Instance | BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic)); val.Patch((MethodBase)methodInfo2, (HarmonyMethod)null, val3, (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null); SetLocalUseMethod = method4; Log.LogInfo((object)$"Flame overheat active: {OverheatSeconds.Value}s burst, {OverheatLockout.Value}s lockout."); } else { Log.LogError((object)"Overheat hooks not found; overheat off."); } } Type type5 = AccessTools.TypeByName("EnemyAI"); MethodInfo methodInfo5 = ((!(type5 != null)) ? null : AccessTools.Method(type5, "HitEnemy", (Type[])null, (Type[])null)); if (methodInfo5 != null) { MethodInfo methodInfo2 = methodInfo5; HarmonyMethod val3 = new HarmonyMethod(typeof(Plugin).GetMethod("HitEnemyPostfix", BindingFlags.Instance | BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic)); val.Patch((MethodBase)methodInfo2, (HarmonyMethod)null, val3, (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null); Log.LogInfo((object)"Crit popup active."); } else { Log.LogError((object)"EnemyAI.HitEnemy not found; crit popup off."); } if (!(type4 != null)) { return; } HarmonyMethod val4 = new HarmonyMethod(typeof(Plugin).GetMethod("RangeTranspiler", BindingFlags.Instance | BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic)); int num = 0; string[] array = new string[4] { "TryTraceStream", "DamageEnemiesByCollider", "IsPointInsideCone", "AdvanceScorchDwell" }; foreach (string text in array) { MethodInfo method6 = type4.GetMethod(text, BindingFlags.Instance | BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic); if (method6 == null) { Log.LogWarning((object)("Flame range: method " + text + " not found")); continue; } MethodInfo methodInfo2 = method6; HarmonyMethod val3 = val4; val.Patch((MethodBase)methodInfo2, (HarmonyMethod)null, (HarmonyMethod)null, val3, (HarmonyMethod)null, (HarmonyMethod)null); num++; } MethodInfo method7 = type4.GetMethod("CacheStreamParticles", BindingFlags.Instance | BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic); if (method7 != null) { val.Patch((MethodBase)method7, new HarmonyMethod(typeof(Plugin).GetMethod("ParticlesPrefix", BindingFlags.Instance | BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic)), new HarmonyMethod(typeof(Plugin).GetMethod("ParticlesPostfix", BindingFlags.Instance | BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic)), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null); } Log.LogInfo((object)string.Format("Flame range x{0} active ({1}/4 hooks, visuals {2}).", FlameRangeMult.Value, num, (!(method7 != null)) ? "off" : "on")); } catch (Exception ex3) { Log.LogError((object)("Setup failed; game continues without this mod: " + ex3)); } } private static string Describe(object clip) { Type t = clip.GetType(); Func<string, object> func = delegate(string p) { try { return t.GetProperty(p)?.GetValue(clip, null); } catch { return "?"; } }; return string.Format("'{0}' state={1} type={2} preload={3} len={4}", func("name"), func("loadState"), func("loadType"), func("preloadAudioData"), func("length")); } private static void EnsureLoaded(object clip, string owner) { if (clip == null) { return; } try { int hashCode = RuntimeHelpers.GetHashCode(clip); bool flag = SeenClips.Add(hashCode); Type type = clip.GetType(); string text = type.GetProperty("loadState")?.GetValue(clip, null)?.ToString(); string text2 = ((!flag || !AudioDiagnostics.Value) ? null : Describe(clip)); bool flag2 = false; object arg = null; if (FixGunAudio.Value && text != "Loaded" && text != "Loading") { arg = type.GetMethod("LoadAudioData", Type.EmptyTypes)?.Invoke(clip, null); flag2 = true; } if (text2 != null) { Log.LogInfo((object)($"[Audio] {owner} clip {text2}" + ((!flag2) ? string.Empty : string.Format(" -> LoadAudioData={0}, now {1}", arg, type.GetProperty("loadState")?.GetValue(clip, null))))); } } catch (Exception ex) { Log.LogWarning((object)("[Audio] check failed: " + ex.Message)); } } private static void EnsureWeaponClips(object weapon) { if (weapon == null) { return; } string text = weapon.GetType().GetProperty("name")?.GetValue(weapon, null)?.ToString() ?? "weapon"; string[] clipFields = ClipFields; foreach (string text2 in clipFields) { object obj = weapon.GetType().GetField(text2, BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic)?.GetValue(weapon); if (obj is Array array) { foreach (object item in array) { EnsureLoaded(item, text + "." + text2); } } else { EnsureLoaded(obj, text + "." + text2); } } } private static int CountClips(object weapon) { int num = 0; string[] clipFields = ClipFields; foreach (string name in clipFields) { object obj = weapon.GetType().GetField(name, BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic)?.GetValue(weapon); if (obj is Array array) { foreach (object item in array) { if (item != null && !item.Equals(null)) { num++; } } } else if (obj != null && !obj.Equals(null)) { num++; } } return num; } private static void RepairFromPrefab(object weapon) { int hashCode = RuntimeHelpers.GetHashCode(weapon); if (!RepairedWeapons.Add(hashCode)) { return; } string text = weapon.GetType().GetProperty("name")?.GetValue(weapon, null)?.ToString() ?? "weapon"; try { string text2 = weapon.GetType().GetField("ConfigId", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic)?.GetValue(weapon) as string; int num = CountClips(weapon); object obj = ((!(PrefabForMethod != null) || text2 == null) ? null : PrefabForMethod.Invoke(null, new object[1] { text2 })); object obj2 = null; if (obj != null && !obj.Equals(null)) { obj2 = obj.GetType().GetMethod("GetComponent", new Type[1] { typeof(Type) })?.Invoke(obj, new object[1] { weapon.GetType() }); } int num2 = 0; if (obj2 != null && !obj2.Equals(null) && !object.ReferenceEquals(obj2, weapon)) { string[] copyFields = CopyFields; foreach (string name in copyFields) { FieldInfo field = weapon.GetType().GetField(name, BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic); if (!(field == null)) { object value = field.GetValue(weapon); object value2 = field.GetValue(obj2); Array array = value as Array; if ((value == null || value.Equals(null) || (array != null && array.Length == 0)) && value2 != null && !value2.Equals(null)) { field.SetValue(weapon, value2); num2++; } } } } if (AudioDiagnostics.Value) { Log.LogInfo((object)string.Format("[Audio] {0} (id={1}) had {2} sound clips; master prefab {3}; copied {4} empty slots; now {5}.", text, text2, num, (obj2 != null) ? ("has " + CountClips(obj2)) : "NOT FOUND", num2, CountClips(weapon))); } } catch (Exception ex) { Log.LogWarning((object)("[Audio] repair failed for " + text + ": " + ex.Message)); } } private static void ShotAudioPrefix(object __instance) { try { if (Enabled.Value && __instance != null) { if (FixGunAudio.Value) { RepairFromPrefab(__instance); } EnsureWeaponClips(__instance); } } catch (Exception ex) { Log.LogWarning((object)("[Audio] prefix failed: " + ex.Message)); } } private static void ShotAudioPostfix(object __instance) { try { if (!AudioDiagnostics.Value || ShotAudioField == null) { return; } string text = __instance.GetType().GetProperty("name")?.GetValue(__instance, null)?.ToString() ?? "weapon"; if (!SeenSources.Add(text)) { return; } object src = ShotAudioField.GetValue(__instance); if (src == null) { Log.LogInfo((object)$"[Audio] {text} shot source is NULL"); return; } Type t = src.GetType(); Func<string, object> func = delegate(string p) { try { return t.GetProperty(p)?.GetValue(src, null); } catch { return "?"; } }; object obj = func("outputAudioMixerGroup"); string text2 = ((obj == null) ? "<none>" : obj.GetType().GetProperty("name")?.GetValue(obj, null)?.ToString()); Log.LogInfo((object)string.Format("[Audio] {0} shot source: enabled={1} active={2} mute={3} volume={4} spatial={5} maxDist={6} bus={7}", text, func("enabled"), func("isActiveAndEnabled"), func("mute"), func("volume"), func("spatialBlend"), func("maxDistance"), text2)); } catch (Exception ex) { Log.LogWarning((object)("[Audio] source check failed: " + ex.Message)); } } private static void LocalClipPrefix(object __instance, object clip) { try { if (Enabled.Value && FixGunAudio.Value && __instance != null) { RepairFromPrefab(__instance); } } catch { } try { if (Enabled.Value) { EnsureLoaded(clip, (__instance?.GetType().GetProperty("name")?.GetValue(__instance, null)?.ToString() ?? "weapon") + ".local"); } } catch { } } private static void ShowTip(string header, string body, bool warning) { try { Type type = AccessTools.TypeByName("HUDManager"); object obj = type?.GetProperty("Instance", BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic)?.GetValue(null, null) ?? type?.GetField("Instance", BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic)?.GetValue(null); if (obj == null) { return; } MethodInfo methodInfo = null; MethodInfo[] methods = type.GetMethods(BindingFlags.Instance | BindingFlags.Public); foreach (MethodInfo methodInfo2 in methods) { if (methodInfo2.Name == "DisplayTip" && methodInfo2.GetParameters().Length >= 2) { methodInfo = methodInfo2; break; } } if (!(methodInfo == null)) { ParameterInfo[] parameters = methodInfo.GetParameters(); object[] array = new object[parameters.Length]; object[] array2 = new object[5] { header, body, warning, false, "LC_Tip1" }; for (int j = 0; j < parameters.Length; j++) { array[j] = ((j >= array2.Length) ? ((!parameters[j].HasDefaultValue) ? null : parameters[j].DefaultValue) : array2[j]); } methodInfo.Invoke(obj, array); } } catch (Exception ex) { Log.LogWarning((object)("Tip failed: " + ex.Message)); } } private static object LocalPlayer() { Type type = AccessTools.TypeByName("GameNetworkManager"); object obj = type?.GetProperty("Instance", BindingFlags.Static | BindingFlags.Public)?.GetValue(null, null) ?? type?.GetField("Instance", BindingFlags.Static | BindingFlags.Public)?.GetValue(null); return obj?.GetType().GetField("localPlayerController")?.GetValue(obj); } private static string WeaponIdOf(object weapon) { return weapon?.GetType().GetField("ConfigId", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic)?.GetValue(weapon) as string; } private static void HitEnemyPostfix(object[] __args) { try { if (!Enabled.Value || !ShowCritPopup.Value || __args == null || __args.Length < 4) { return; } int num = (int)__args[0]; object obj = __args[1]; int num2 = (int)__args[3]; if (obj == null || !object.ReferenceEquals(obj, LocalPlayer())) { return; } bool flag = false; string arg = null; if (num2 == -9410) { return; } object obj2 = obj.GetType().GetField("currentlyHeldObjectServer")?.GetValue(obj); string a = WeaponIdOf(obj2); if (string.Equals(a, "kar98k", StringComparison.OrdinalIgnoreCase)) { int num3 = ((!(RifleAvgDamage.Value > 0f)) ? 3 : ((int)Math.Floor(RifleAvgDamage.Value))); flag = num >= Math.Max(num3 + 2, (int)Math.Ceiling((float)num3 * RifleCritMult.Value)); arg = "Bolt-Action"; } else if (string.Equals(a, "revolver", StringComparison.OrdinalIgnoreCase)) { int num4 = 2; try { object obj3 = obj2.GetType().GetProperty("Config", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic)?.GetValue(obj2, null); object obj4 = obj3?.GetType().GetField("EnemyDamageClose")?.GetValue(obj3); if (obj4 is int) { num4 = (int)obj4; } } catch { } flag = num >= Math.Max(num4 + 1, (int)Math.Ceiling((float)num4 * RevolverCritMult.Value)); arg = "Revolver"; } if (flag && !(Now - _lastPopup < 1.2)) { _lastPopup = Now; ShowTip("CRIT!", $"{arg} hit for {num} damage", warning: false); } } catch { } } private static bool CanJam(object weapon) { string text = WeaponIdOf(weapon); if (string.IsNullOrEmpty(text) || JamChance.Value <= 0f) { return false; } string[] array = JamWeapons.Value.Split(new char[1] { ',' }); foreach (string text2 in array) { if (string.Equals(text2.Trim(), text, StringComparison.OrdinalIgnoreCase)) { return true; } } return false; } private static int MagazineOf(object w) { object obj = w.GetType().GetProperty("Magazine", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic)?.GetValue(w, null) ?? w.GetType().GetField("Magazine", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic)?.GetValue(w); return (!(obj is int)) ? (-1) : ((int)obj); } private static void PlayOn(object w, string clipField) { try { object obj = w.GetType().GetField(clipField, BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic)?.GetValue(w); if (obj != null && PlayLocalMethod != null) { PlayLocalMethod.Invoke(w, new object[2] { obj, 1f }); } } catch { } } private static bool FireOncePrefix(object __instance, out int __state) { __state = -1; try { if (!Enabled.Value || __instance == null) { return true; } int hashCode = RuntimeHelpers.GetHashCode(__instance); if (Jammed.Contains(hashCode)) { PlayOn(__instance, "DryFireClip"); if (!JamTipShown.TryGetValue(hashCode, out var value) || Now - value > 2.5) { JamTipShown[hashCode] = Now; ShowTip("JAMMED!", "Reload to clear the jam.", warning: true); } return false; } __state = MagazineOf(__instance); } catch { } return true; } private static void FireOncePostfix(object __instance, int __state) { try { if (__state >= 0 && CanJam(__instance) && MagazineOf(__instance) < __state && Roll() < (double)JamChance.Value) { int hashCode = RuntimeHelpers.GetHashCode(__instance); Jammed.Add(hashCode); JamTipShown[hashCode] = Now; ShowTip("JAMMED!", "Reload to clear the jam.", warning: true); Log.LogInfo((object)("JAM! " + WeaponIdOf(__instance))); } } catch { } } private static bool BeginReloadPrefix(object __instance) { try { if (__instance == null) { return true; } int hashCode = RuntimeHelpers.GetHashCode(__instance); if (!Jammed.Remove(hashCode)) { return true; } Log.LogInfo((object)("Jam cleared: " + WeaponIdOf(__instance))); bool flag = false; try { object obj = __instance.GetType().GetProperty("Config", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic)?.GetValue(__instance, null); object obj2 = obj?.GetType().GetField("MagazineSize")?.GetValue(obj); flag = obj2 is int && MagazineOf(__instance) >= (int)obj2; } catch { } if (flag) { PlayOn(__instance, "ReloadFinishClip"); try { if ((object)HoldFireGateMethod != null) { HoldFireGateMethod.Invoke(__instance, new object[1] { 0.8f }); } } catch { } return false; } } catch { } return true; } private static void SetUsePrefix(object __instance, ref bool firing) { try { if (firing && !_forcingStop && !(OverheatSeconds.Value <= 0f)) { int hashCode = RuntimeHelpers.GetHashCode(__instance); if (LockedUntil.TryGetValue(hashCode, out var value) && Now < value) { firing = false; ShowTip("OVERHEATED", $"Cooling down... {Math.Ceiling(value - Now)}s", warning: true); } } } catch { } } [MethodImpl(MethodImplOptions.NoInlining)] private void StartSwapSounds(Harmony harmony, Assembly armory) { SwapSounds.Bind(((BaseUnityPlugin)this).Config); SwapSounds.Patch(harmony, armory); } [MethodImpl(MethodImplOptions.NoInlining)] private void StartReactions(Harmony harmony) { MonsterReactions.Bind(((BaseUnityPlugin)this).Config); MonsterReactions.Patch(harmony); if (MonsterReactions.Replaced != 1) { Log.LogWarning((object)("Monster reactions: expected 1 AI hook, found " + MonsterReactions.Replaced + ".")); } _reactionsOn = true; } [MethodImpl(MethodImplOptions.NoInlining)] private static void ReactionsFlameTick(object driver) { MonsterReactions.FlameTick(driver, 8f * Clamp(FlameRangeMult.Value, 0.25f, 4f), FlameMuzzleRadius(), FlameEndRadius()); } private static void FlameUpdatePostfix(object __instance) { try { if (Enabled.Value && SmoothFlameLoop.Value) { TickLoop(__instance); } } catch (Exception e) { LoopWarn(e); } try { if (Enabled.Value && _reactionsOn) { ReactionsFlameTick(__instance); } } catch (Exception ex) { if (!_scareWarned) { _scareWarned = true; Log.LogWarning((object)("Flame scare error: " + ex.Message)); } } try { if (!Enabled.Value || OverheatSeconds.Value <= 0f) { return; } int hashCode = RuntimeHelpers.GetHashCode(__instance); double now = Now; double value; double num = ((!LastTick.TryGetValue(hashCode, out value)) ? 0.0 : Math.Min(0.25, now - value)); LastTick[hashCode] = now; bool flag = TriggerHeldField.GetValue(__instance) is bool && (bool)TriggerHeldField.GetValue(__instance); Heat.TryGetValue(hashCode, out var value2); value2 = ((!flag) ? Math.Max(0.0, value2 - num * 1.5) : (value2 + num)); if (flag && value2 >= (double)OverheatSeconds.Value) { value2 = 0.0; LockedUntil[hashCode] = now + (double)Math.Max(0.5f, OverheatLockout.Value); _forcingStop = true; try { SetLocalUseMethod.Invoke(__instance, new object[1] { false }); } finally { _forcingStop = false; } ShowTip("OVERHEATED", $"Flamethrower locked for {OverheatLockout.Value:0}s.", warning: true); Log.LogInfo((object)"Flamethrower overheated."); } Heat[hashCode] = value2; } catch { } } private static void LoopWarn(Exception e) { if (!_loopWarned) { _loopWarned = true; Log.LogWarning((object)("Flame loop smoothing off (error): " + e.Message)); } } private static object P(object o, string n) { PropertyInfo property = o.GetType().GetProperty(n); if (property != null) { return property.GetValue(o, null); } FieldInfo field = o.GetType().GetField(n); if (field != null) { return field.GetValue(o); } throw new MissingMemberException(o.GetType().Name, n); } private static void SP(object o, string n, object v) { PropertyInfo property = o.GetType().GetProperty(n); if (property != null) { property.SetValue(o, v, null); return; } FieldInfo field = o.GetType().GetField(n); if (field != null) { field.SetValue(o, v); return; } throw new MissingMemberException(o.GetType().Name, n); } private static void Call(object o, string n) { o.GetType().GetMethod(n, Type.EmptyTypes).Invoke(o, null); } private static void AnalyzeClip(LoopState st, object clip) { st.Clip = clip; float num = (float)P(clip, "length"); st.Start = 0f; st.End = num; try { int num2 = (int)P(clip, "samples"); int num3 = (int)P(clip, "channels"); int num4 = (int)P(clip, "frequency"); float[] array = new float[num2 * num3]; object obj = clip.GetType().GetMethod("GetData", new Type[2] { typeof(float[]), typeof(int) }).Invoke(clip, new object[2] { array, 0 }); if (obj is bool && (bool)obj) { int num5 = Math.Max(16, num4 / 100); int num6 = num5 * num3; int num7 = array.Length / num6; if (num7 < 4) { throw new Exception("short"); } float[] array2 = new float[num7]; float num8 = 0f; for (int i = 0; i < num7; i++) { double num9 = 0.0; for (int j = i * num6; j < (i + 1) * num6; j++) { num9 += (double)(array[j] * array[j]); } array2[i] = (float)Math.Sqrt(num9 / (double)num6); if (array2[i] > num8) { num8 = array2[i]; } } float num10 = num8 * 0.08f; int k; for (k = 0; k < num7 && array2[k] < num10; k++) { } int num11 = num7 - 1; while (num11 > k && array2[num11] < num10) { num11--; } float num12 = (float)k * (float)num5 / (float)num4; float num13 = (float)(num11 + 1) * (float)num5 / (float)num4; if (num13 - num12 > 0.6f) { st.Start = num12; st.End = Math.Min(num, num13); } } } catch { } st.Fade = Math.Max(0.05f, Math.Min(0.3f, (st.End - st.Start) * 0.2f)); Log.LogInfo((object)$"Flame loop: clip {num:F2}s, using {st.Start:F2}-{st.End:F2}s with {st.Fade:F2}s crossfade."); } private static object MakeHelper(object a) { object obj = P(a, "gameObject"); object obj2 = obj.GetType().GetMethod("AddComponent", new Type[1] { typeof(Type) }).Invoke(obj, new object[1] { a.GetType() }); string[] array = new string[7] { "spatialBlend", "minDistance", "maxDistance", "rolloffMode", "outputAudioMixerGroup", "dopplerLevel", "priority" }; foreach (string n in array) { try { SP(obj2, n, P(a, n)); } catch { } } SP(obj2, "loop", false); SP(obj2, "playOnAwake", false); SP(obj2, "volume", 0f); return obj2; } private static void TickLoop(object driver) { if (StreamAudioField == null) { return; } object value = StreamAudioField.GetValue(driver); int hashCode = RuntimeHelpers.GetHashCode(driver); Loops.TryGetValue(hashCode, out var value2); if (value == null || value.Equals(null)) { return; } object obj = P(value, "clip"); bool flag = (bool)P(value, "isPlaying"); if (obj == null || obj.Equals(null) || !flag) { if (value2 != null && value2.B != null && (bool)P(value2.B, "isPlaying")) { Call(value2.B, "Stop"); } if (value2 != null) { value2.Fading = false; value2.PrevT = 0f; } return; } if (value2 == null) { value2 = new LoopState(); Loops[hashCode] = value2; } if (!object.ReferenceEquals(value2.Clip, obj)) { AnalyzeClip(value2, obj); } if (value2.B == null || value2.B.Equals(null)) { value2.B = MakeHelper(value); } float num = (float)P(value, "time"); float num2 = (float)P(value, "volume"); if (!value2.Fading && num < value2.Start - 0.02f && value2.PrevT <= num) { SP(value, "time", value2.Start); num = value2.Start; } if (!value2.Fading && num >= value2.End - value2.Fade && num < value2.End) { SP(value2.B, "clip", obj); try { SP(value2.B, "pitch", P(value, "pitch")); } catch { } SP(value2.B, "time", value2.Start); SP(value2.B, "volume", 0f); Call(value2.B, "Play"); value2.Fading = true; value2.FadeStart = Now; } if (value2.Fading) { float num3 = (float)Math.Min(1.0, (Now - value2.FadeStart) / (double)value2.Fade); SP(value2.B, "volume", num2 * num3); bool flag2 = num < value2.PrevT - 0.05f; if (num >= value2.End - 0.005f || flag2 || num3 >= 1f) { SP(value, "timeSamples", P(value2.B, "timeSamples")); Call(value2.B, "Stop"); SP(value2.B, "volume", 0f); value2.Fading = false; num = (float)P(value, "time"); } } value2.PrevT = num; } public static float FlameRange() { float num = ((FlameRangeMult == null) ? 1f : FlameRangeMult.Value); if (num < 0.5f) { num = 0.5f; } if (num > 4f) { num = 4f; } return 8f * num; } public static float FlameEndRadius() { return 0.9f * Clamp((FlameWidthMult == null) ? 1f : FlameWidthMult.Value, 0.5f, 4f); } public static float FlameMuzzleRadius() { return 0.2f * Clamp((FlameWidthMult == null) ? 1f : FlameWidthMult.Value, 0.5f, 4f); } private static float Clamp(float v, float lo, float hi) { return (v < lo) ? lo : ((!(v > hi)) ? v : hi); } private static IEnumerable<CodeInstruction> RangeTranspiler(IEnumerable<CodeInstruction> instructions) { MethodInfo getter = typeof(Plugin).GetMethod("FlameRange", BindingFlags.Static | BindingFlags.Public); foreach (CodeInstruction ci in instructions) { bool isRange = ci.opcode == OpCodes.Ldc_R4 && ci.operand is float && (float)ci.operand == 8f; bool isEnd = ci.opcode == OpCodes.Ldc_R4 && ci.operand is float && Math.Abs((float)ci.operand - 0.9f) < 1E-05f; bool isMuzzle = ci.opcode == OpCodes.Ldc_R4 && ci.operand is float && Math.Abs((float)ci.operand - 0.2f) < 1E-05f; if (isEnd || isMuzzle) { CodeInstruction c2 = new CodeInstruction(OpCodes.Call, (object)typeof(Plugin).GetMethod((!isEnd) ? "FlameMuzzleRadius" : "FlameEndRadius", BindingFlags.Static | BindingFlags.Public)); c2.labels.AddRange(ci.labels); c2.blocks.AddRange(ci.blocks); yield return c2; } else if (isRange) { CodeInstruction call = new CodeInstruction(OpCodes.Call, (object)getter); call.labels.AddRange(ci.labels); call.blocks.AddRange(ci.blocks); yield return call; } else { yield return ci; } } } private static object GetP(object o, string name) { if (o == null) { return null; } PropertyInfo property = o.GetType().GetProperty(name, PubInst); return (!(property != null)) ? null : property.GetValue(o, null); } private static void SetP(object o, string name, object v) { PropertyInfo propertyInfo = o?.GetType().GetProperty(name, PubInst); if (propertyInfo != null && propertyInfo.CanWrite) { propertyInfo.SetValue(o, v, null); } } private static void ScaleCurve(object module, string prop, float m) { object p = GetP(module, prop); if (p != null) { string text = Convert.ToString(GetP(p, "mode")); if (text == "Constant") { SetP(p, "constant", (float)GetP(p, "constant") * m); } else if (text == "TwoConstants") { SetP(p, "constantMin", (float)GetP(p, "constantMin") * m); SetP(p, "constantMax", (float)GetP(p, "constantMax") * m); } else { SetP(p, "curveMultiplier", (float)GetP(p, "curveMultiplier") * m); } SetP(module, prop, p); } } private static string DescCurve(object module, string prop) { object p = GetP(module, prop); if (p == null) { return "?"; } string text = Convert.ToString(GetP(p, "mode")); if (text == "Constant") { return Convert.ToString(GetP(p, "constant")); } if (text == "TwoConstants") { return string.Concat(GetP(p, "constantMin"), "-", GetP(p, "constantMax")); } return text + "x" + GetP(p, "curveMultiplier"); } private static bool ModOn(object ps, string module) { object p = GetP(ps, module); object p2 = GetP(p, "enabled"); return p2 is bool && (bool)p2; } private static void DumpParticle(object ps, string tag) { try { object p = GetP(ps, "main"); object p2 = GetP(ps, "transform"); string text = string.Concat("[Flame visual] ", tag, " '", GetP(ps, "name"), "' life=", DescCurve(p, "startLifetime"), " speed=", DescCurve(p, "startSpeed"), " size=", DescCurve(p, "startSize"), " grav=", DescCurve(p, "gravityModifier"), " simSpeed=", GetP(p, "simulationSpeed"), " space=", GetP(p, "simulationSpace"), " scaling=", GetP(p, "scalingMode"), " lossyScale=", GetP(p2, "lossyScale"), " shape=", (!ModOn(ps, "shape")) ? "off" : string.Concat(GetP(GetP(ps, "shape"), "shapeType"), "/ang", GetP(GetP(ps, "shape"), "angle"), "/len", GetP(GetP(ps, "shape"), "length"), "/scale", GetP(GetP(ps, "shape"), "scale")), " vel=", (!ModOn(ps, "velocityOverLifetime")) ? "off" : ("on(z=" + DescCurve(GetP(ps, "velocityOverLifetime"), "z") + ",mod=" + DescCurve(GetP(ps, "velocityOverLifetime"), "speedModifier") + ")"), " limit=", (!ModOn(ps, "limitVelocityOverLifetime")) ? "off" : string.Concat("on(", DescCurve(GetP(ps, "limitVelocityOverLifetime"), "limit"), ",damp=", GetP(GetP(ps, "limitVelocityOverLifetime"), "dampen"), ",drag=", DescCurve(GetP(ps, "limitVelocityOverLifetime"), "drag"), ")"), " force=", (!ModOn(ps, "forceOverLifetime")) ? "off" : "on", " noise=", (!ModOn(ps, "noise")) ? "off" : ("on(" + DescCurve(GetP(ps, "noise"), "strength") + ")"), " collision=", (!ModOn(ps, "collision")) ? "off" : ("on(loss=" + DescCurve(GetP(ps, "collision"), "lifetimeLoss") + ")"), " sub=", (!ModOn(ps, "subEmitters")) ? "off" : "on", " trails=", (!ModOn(ps, "trails")) ? "off" : "on"); object obj = null; try { MethodInfo method = ps.GetType().GetMethod("GetComponent", Type.EmptyTypes); Type type = AccessTools.TypeByName("UnityEngine.ParticleSystemRenderer"); if (type != null) { MethodInfo method2 = ps.GetType().GetMethod("GetComponent", new Type[1] { typeof(Type) }); obj = ((!(method2 != null)) ? null : method2.Invoke(ps, new object[1] { type })); } } catch { } if (obj != null) { string text2 = text; text = string.Concat(text2, " render=", GetP(obj, "renderMode"), " lenScale=", GetP(obj, "lengthScale"), " velScale=", GetP(obj, "velocityScale")); } Log.LogInfo((object)text); } catch (Exception ex) { Log.LogWarning((object)("[Flame visual] dump failed: " + ex.Message)); } } private static void ParticlesPrefix(object __instance) { try { if (OrangeFlame != null && OrangeFlame.Value) { object? obj = __instance.GetType().GetField("_streamObject", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic)?.GetValue(__instance); GameObject val = (GameObject)((obj is GameObject) ? obj : null); if (!((Object)(object)val == (Object)null)) { float v = ((!(FlameCustomLength.Value > 0.5f)) ? (8f * Clamp(FlameRangeMult.Value, 0.25f, 4f)) : FlameCustomLength.Value); FlameFx.Build(val, Clamp(v, 1f, 40f), Clamp(FlameGlow.Value, 0f, 20f), FlameWalls.Value); } } } catch (Exception ex) { Log.LogWarning((object)("[Flame visual] orange flame failed, keeping the blue one: " + ex)); } } private static void ParticlesPostfix(object __instance) { try { float num = Clamp((FlameVisualMult == null) ? 1f : FlameVisualMult.Value, 0.25f, 6f); if (!(__instance.GetType().GetField("_streamParticles", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic)?.GetValue(__instance) is Array array)) { return; } bool flag = !DumpedParticles; DumpedParticles = true; foreach (object item in array) { if (item == null) { continue; } object obj = item.GetType().GetField("System", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic)?.GetValue(item); if (obj == null) { continue; } if (flag) { DumpParticle(obj, "before"); } if (Math.Abs(num - 1f) < 0.001f) { continue; } ParticleSystem val = (ParticleSystem)((obj is ParticleSystem) ? obj : null); if ((Object)(object)val != (Object)null && (FlameFx.IsHiddenVanilla(val) || ((Object)val).name.StartsWith("Grayl_OrangeFlame"))) { continue; } int hashCode = RuntimeHelpers.GetHashCode(obj); if (!ScaledParticles.Add(hashCode)) { continue; } object p = GetP(obj, "main"); ScaleCurve(p, "startSpeed", num); ScaleCurve(p, "gravityModifier", num); if (ModOn(obj, "velocityOverLifetime")) { object p2 = GetP(obj, "velocityOverLifetime"); ScaleCurve(p2, "x", num); ScaleCurve(p2, "y", num); ScaleCurve(p2, "z", num); } if (ModOn(obj, "limitVelocityOverLifetime")) { object p3 = GetP(obj, "limitVelocityOverLifetime"); ScaleCurve(p3, "limit", num); ScaleCurve(p3, "limitX", num); ScaleCurve(p3, "limitY", num); ScaleCurve(p3, "limitZ", num); } if (ModOn(obj, "forceOverLifetime")) { object p4 = GetP(obj, "forceOverLifetime"); ScaleCurve(p4, "x", num); ScaleCurve(p4, "y", num); ScaleCurve(p4, "z", num); } if (ModOn(obj, "shape")) { object p5 = GetP(obj, "shape"); object p6 = GetP(p5, "length"); if (p6 is float) { SetP(p5, "length", (float)p6 * num); } } if (flag) { DumpParticle(obj, "after x" + num); } } } catch (Exception ex) { Log.LogWarning((object)("Flame visuals scale failed (damage range still applies): " + ex.Message)); } } private static double Roll() { lock (Rng) { return Rng.NextDouble(); } } private static int Crit(int dmg, float mult) { return Math.Max(dmg, (int)Math.Ceiling((float)dmg * mult)); } private static void ForcePostfix(object config, ref int __result) { try { if (!Enabled.Value || config == null || __result <= 0) { return; } string a = IdField.GetValue(config) as string; if (string.Equals(a, "revolver", StringComparison.OrdinalIgnoreCase)) { if (Roll() < (double)RevolverCritChance.Value) { int num = __result; __result = Crit(num, RevolverCritMult.Value); if (LogCrits.Value) { Log.LogInfo((object)$"CRIT! Revolver {num} -> {__result}"); } } } else { if (!string.Equals(a, "kar98k", StringComparison.OrdinalIgnoreCase)) { return; } float value = RifleAvgDamage.Value; if (value > 0f) { int num2 = (int)Math.Floor(value); __result = num2 + ((Roll() < (double)(value - (float)num2)) ? 1 : 0); if (__result <= 0) { return; } } if (Roll() < (double)RifleCritChance.Value) { int num3 = __result; __result = Crit(num3, RifleCritMult.Value); if (LogCrits.Value) { Log.LogInfo((object)$"CRIT! Bolt-Action {num3} -> {__result}"); } } } } catch (Exception ex) { Log.LogWarning((object)("Rifle roll failed, normal damage used: " + ex.Message)); } } private static double FlameInterval() { try { if (FlameIntervalProp == null) { FlameIntervalProp = FlameDamageProp.DeclaringType.GetProperty("DamageInterval", BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic); } object obj = (((object)FlameIntervalProp != null) ? FlameIntervalProp.GetValue(null, null) : null); if (obj is float && (float)obj > 0f) { return (float)obj; } } catch { } return 0.57; } private static void FlamePrefix(object[] __args, out int __state) { __state = -1; _tickBurn = null; _tickPlanned = 0; _tickCrit = false; try { if (!Enabled.Value) { return; } int num = (int)FlameDamageProp.GetValue(null); if (num <= 0) { return; } object obj = ((__args == null || __args.Length <= 0) ? null : __args[0]); if (obj == null) { return; } if (!FlameRamp.Value) { if (!(Roll() >= (double)FlameCritChance.Value)) { __state = num; _tickCrit = true; FlameDamageProp.SetValue(null, Crit(num, FlameCritMult.Value)); } return; } int hashCode = RuntimeHelpers.GetHashCode(obj); if (!Burns.TryGetValue(hashCode, out var value)) { value = new Burn(); Burns[hashCode] = value; } double now = Now; double num2 = FlameInterval(); __state = num; if (now - value.Last > Math.Max(num2 * 1.5, FlameRampGrace.Value)) { value.N = 0; value.Carry = 0.0; } if (now - value.Last < num2 * 0.98) { FlameDamageProp.SetValue(null, 0); return; } value.PrevLast = value.Last; value.PrevCarry = value.Carry; value.PrevN = value.N; value.N++; double num3 = FlameRampStep.Value * (float)value.N; if (FlameRampCap.Value > 0f && num3 > (double)FlameRampCap.Value) { num3 = FlameRampCap.Value; } value.Carry += num3; int num4 = (int)Math.Floor(value.Carry + 1E-09); value.Carry -= num4; value.Last = now; if (num4 > 0 && Roll() < (double)FlameCritChance.Value) { num4 = Crit(num4, FlameCritMult.Value); _tickCrit = true; } _tickBurn = value; _tickPlanned = num4; FlameDamageProp.SetValue(null, num4); if (_tickCrit && ShowCritPopup.Value && __args.Length > 1 && __args[1] != null && object.ReferenceEquals(__args[1], LocalPlayer()) && Now - _lastPopup >= 1.2) { _lastPopup = Now; ShowTip("CRIT!", $"Flamethrower burn for {num4} damage", warning: false); } } catch (Exception ex) { Log.LogWarning((object)("Flame roll failed: " + ex.Message)); } } private static Exception FlameFinalizer(Exception __exception, int __state, bool __result) { if (__state < 0) { return __exception; } try { Burn tickBurn = _tickBurn; if (tickBurn != null && _tickPlanned > 0 && (__exception != null || !__result)) { tickBurn.Last = tickBurn.PrevLast; tickBurn.Carry = tickBurn.PrevCarry; tickBurn.N = tickBurn.PrevN; } else if (__exception == null && __result && _tickCrit && LogCrits.Value) { Log.LogInfo((object)$"CRIT! Flame tick -> {FlameDamageProp.GetValue(null)}"); } else if (tickBurn != null && __result && LogCrits.Value && FlameRampLog.Value) { Log.LogInfo((object)$"Burn tick #{tickBurn.N}: {_tickPlanned} damage"); } } catch { } try { FlameDamageProp.SetValue(null, __state); } catch (Exception ex) { Log.LogWarning((object)("Flame restore failed: " + ex.Message)); } _tickBurn = null; return __exception; } } internal static class FlameFx { private struct Layer { public string Name; public Color Col; public float Reach; public float Life; public float Size; public float Rate; public float Angle; public float Rise; public float Noise; public Layer(string n, Color c, float reach, float life, float size, float rate, float angle, float rise, float noise) { //IL_0008: Unknown result type (might be due to invalid IL or missing references) //IL_0009: Unknown result type (might be due to invalid IL or missing references) Name = n; Col = c; Reach = reach; Life = life; Size = size; Rate = rate; Angle = angle; Rise = rise; Noise = noise; } } internal const string HolderName = "Grayl_OrangeFlame"; private static readonly HashSet<int> HiddenVanilla = new HashSet<int>(); private static Texture2D _blob; private static bool _loggedMaterial; internal static bool IsHiddenVanilla(ParticleSystem ps) { return (Object)(object)ps != (Object)null && HiddenVanilla.Contains(((Object)ps).GetInstanceID()); } internal static void Build(GameObject root, float reach, float glow, bool stopAtWalls) { //IL_00a0: Unknown result type (might be due to invalid IL or missing references) //IL_00a7: Expected O, but got Unknown //IL_00ce: Unknown result type (might be due to invalid IL or missing references) //IL_00df: Unknown result type (might be due to invalid IL or missing references) //IL_00f0: Unknown result type (might be due to invalid IL or missing references) //IL_011b: Unknown result type (might be due to invalid IL or missing references) //IL_0168: Unknown result type (might be due to invalid IL or missing references) //IL_01b5: Unknown result type (might be due to invalid IL or missing references) //IL_02a8: Unknown result type (might be due to invalid IL or missing references) //IL_02ad: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)root == (Object)null || (Object)(object)root.transform.Find("Grayl_OrangeFlame") != (Object)null) { return; } ParticleSystem[] componentsInChildren = root.GetComponentsInChildren<ParticleSystem>(true); Material val = null; ParticleSystem templatePs = null; ParticleSystemRenderer templateRenderer = null; ParticleSystem[] array = componentsInChildren; foreach (ParticleSystem val2 in array) { ParticleSystemRenderer component = ((Component)val2).GetComponent<ParticleSystemRenderer>(); if ((Object)(object)val == (Object)null && (Object)(object)component != (Object)null && (Object)(object)((Renderer)component).sharedMaterial != (Object)null) { val = ((Renderer)component).sharedMaterial; templatePs = val2; templateRenderer = component; } } GameObject val3 = new GameObject("Grayl_OrangeFlame"); val3.layer = root.layer; val3.transform.SetParent(root.transform, false); val3.transform.localPosition = Vector3.zero; val3.transform.localRotation = Quaternion.identity; val3.transform.localScale = Vector3.one; Layer[] array2 = new Layer[3] { new Layer("Core", new Color(1f, 0.82f, 0.45f), 0.55f, 0.26f, 0.55f, 170f, 2f, 0.05f, 0.05f), new Layer("Body", new Color(1f, 0.42f, 0.07f), 0.9f, 0.4f, 1.6f, 230f, 4f, 0.12f, 0.3f), new Layer("Tips", new Color(0.85f, 0.16f, 0.02f), 1f, 0.48f, 2.4f, 120f, 5.5f, 0.25f, 0.45f) }; int num = 0; Layer[] array3 = array2; for (int j = 0; j < array3.Length; j++) { Layer l = array3[j]; try { BuildLayer(val3, l, reach, glow, stopAtWalls, val, templatePs, templateRenderer); num++; } catch (Exception ex) { Plugin.Log.LogWarning((object)("[Flame visual] layer " + l.Name + " failed: " + ex.Message)); } } if (num == 0) { Object.Destroy((Object)(object)val3); return; } ParticleSystem[] array4 = componentsInChildren; foreach (ParticleSystem val4 in array4) { if (!((Object)(object)val4 == (Object)null)) { HiddenVanilla.Add(((Object)val4).GetInstanceID()); EmissionModule emission = val4.emission; ((EmissionModule)(ref emission)).enabled = false; val4.Clear(false); } } Plugin.Log.LogInfo((object)("[Flame visual] orange flame built: " + num + " layers, reach " + reach.ToString("0.0") + " m, material from " + ((!((Object)(object)val != (Object)null)) ? "HDRP/Unlit fallback" : ("'" + ((Object)val).name + "' (" + ((!((Object)(object)val.shader != (Object)null)) ? "?" : ((Object)val.shader).name) + ")")) + ", stops at walls " + stopAtWalls + ".")); } private static void BuildLayer(GameObject holder, Layer l, float reach, float glow, bool stopAtWalls, Material template, ParticleSystem templatePs, ParticleSystemRenderer templateRenderer) { //IL_0011: Unknown result type (might be due to invalid IL or missing references) //IL_0017: Expected O, but got Unknown //IL_003b: 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_005b: Unknown result type (might be due to invalid IL or missing references) //IL_007f: Unknown result type (might be due to invalid IL or missing references) //IL_0084: Unknown result type (might be due to invalid IL or missing references) //IL_00aa: Unknown result type (might be due to invalid IL or missing references) //IL_00ce: Unknown result type (might be due to invalid IL or missing references) //IL_00e7: Unknown result type (might be due to invalid IL or missing references) //IL_00fd: Unknown result type (might be due to invalid IL or missing references) //IL_010b: Unknown result type (might be due to invalid IL or missing references) //IL_0110: Unknown result type (might be due to invalid IL or missing references) //IL_0124: Unknown result type (might be due to invalid IL or missing references) //IL_014b: Unknown result type (might be due to invalid IL or missing references) //IL_0150: Unknown result type (might be due to invalid IL or missing references) //IL_0163: 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_0173: Unknown result type (might be due to invalid IL or missing references) //IL_01a0: Unknown result type (might be due to invalid IL or missing references) //IL_01a5: Unknown result type (might be due to invalid IL or missing references) //IL_01cd: Unknown result type (might be due to invalid IL or missing references) //IL_01d2: Unknown result type (might be due to invalid IL or missing references) //IL_01e8: Unknown result type (might be due to invalid IL or missing references) //IL_01ed: Unknown result type (might be due to invalid IL or missing references) //IL_0203: Unknown result type (might be due to invalid IL or missing references) //IL_0208: Unknown result type (might be due to invalid IL or missing references) //IL_021e: Unknown result type (might be due to invalid IL or missing references) //IL_0223: Unknown result type (might be due to invalid IL or missing references) //IL_0228: Unknown result type (might be due to invalid IL or missing references) //IL_0232: Expected O, but got Unknown //IL_022d: Unknown result type (might be due to invalid IL or missing references) //IL_0237: Unknown result type (might be due to invalid IL or missing references) //IL_023e: Expected O, but got Unknown //IL_024d: Unknown result type (might be due to invalid IL or missing references) //IL_0257: Unknown result type (might be due to invalid IL or missing references) //IL_025c: Unknown result type (might be due to invalid IL or missing references) //IL_0277: Unknown result type (might be due to invalid IL or missing references) //IL_0281: Unknown result type (might be due to invalid IL or missing references) //IL_0286: Unknown result type (might be due to invalid IL or missing references) //IL_02a2: Unknown result type (might be due to invalid IL or missing references) //IL_02a7: Unknown result type (might be due to invalid IL or missing references) //IL_02bd: Unknown result type (might be due to invalid IL or missing references) //IL_02c2: Unknown result type (might be due to invalid IL or missing references) //IL_02d8: Unknown result type (might be due to invalid IL or missing references) //IL_02dd: Unknown result type (might be due to invalid IL or missing references) //IL_02e8: Unknown result type (might be due to invalid IL or missing references) //IL_02ed: Unknown result type (might be due to invalid IL or missing references) //IL_02fb: Unknown result type (might be due to invalid IL or missing references) //IL_0306: Unknown result type (might be due to invalid IL or missing references) //IL_030b: Unknown result type (might be due to invalid IL or missing references) //IL_0321: Unknown result type (might be due to invalid IL or missing references) //IL_033d: Unknown result type (might be due to invalid IL or missing references) //IL_0342: Unknown result type (might be due to invalid IL or missing references) //IL_0355: Unknown result type (might be due to invalid IL or missing references) //IL_0372: Unknown result type (might be due to invalid IL or missing references) //IL_0453: Unknown result type (might be due to invalid IL or missing references) //IL_0458: Unknown result type (might be due to invalid IL or missing references) //IL_03d0: Unknown result type (might be due to invalid IL or missing references) //IL_03d5: Unknown result type (might be due to invalid IL or missing references) //IL_03f3: Unknown result type (might be due to invalid IL or missing references) //IL_040c: Unknown result type (might be due to invalid IL or missing references) //IL_041d: Unknown result type (might be due to invalid IL or missing references) //IL_042e: Unknown result type (might be due to invalid IL or missing references) //IL_0468: Unknown result type (might be due to invalid IL or missing references) //IL_0551: Unknown result type (might be due to invalid IL or missing references) //IL_0473: Unknown result type (might be due to invalid IL or missing references) //IL_0478: Unknown result type (might be due to invalid IL or missing references) //IL_04aa: Unknown result type (might be due to invalid IL or missing references) //IL_04b8: Unknown result type (might be due to invalid IL or missing references) //IL_04d4: Unknown result type (might be due to invalid IL or missing references) //IL_04e2: Unknown result type (might be due to invalid IL or missing references) GameObject val = new GameObject("Grayl_OrangeFlame_" + l.Name); val.layer = holder.layer; val.transform.SetParent(holder.transform, false); val.transform.localPosition = Vector3.zero; val.transform.localRotation = Quaternion.identity; val.transform.localScale = Vector3.one; ParticleSystem val2 = val.AddComponent<ParticleSystem>(); val2.Stop(true, (ParticleSystemStopBehavior)0); float num = reach * l.Reach; MainModule main = val2.main; ((MainModule)(ref main)).duration = 1f; ((MainModule)(ref main)).loop = true; ((MainModule)(ref main)).playOnAwake = false; ((MainModule)(ref main)).startLifetime = new MinMaxCurve(l.Life); ((MainModule)(ref main)).startSpeed = new MinMaxCurve(num / l.Life * 0.92f, num / l.Life); ((MainModule)(ref main)).startSize = new MinMaxCurve(l.Size * 0.3f); ((MainModule)(ref main)).startRotation = new MinMaxCurve(0f, 6.2831f); ((MainModule)(ref main)).startColor = new MinMaxGradient(l.Col); ((MainModule)(ref main)).gravityModifier = new MinMaxCurve(0f - l.Rise); ((MainModule)(ref main)).simulationSpace = (ParticleSystemSimulationSpace)1; ((MainModule)(ref main)).scalingMode = (ParticleSystemScalingMode)1; ((MainModule)(ref main)).maxParticles = 400; EmissionModule emission = val2.emission; ((EmissionModule)(ref emission)).enabled = true; ((EmissionModule)(ref emission)).rateOverTime = new MinMaxCurve(l.Rate); ShapeModule shape = val2.shape; ((ShapeModule)(ref shape)).enabled = true; ((ShapeModule)(ref shape)).shapeType = (ParticleSystemShapeType)4; ((ShapeModule)(ref shape)).angle = l.Angle; ((ShapeModule)(ref shape)).radius = 0.04f; SizeOverLifetimeModule sizeOverLifetime = val2.sizeOverLifetime; ((SizeOverLifetimeModule)(ref sizeOverLifetime)).enabled = true; ((SizeOverLifetimeModule)(ref sizeOverLifetime)).size = new MinMaxCurve(3.3333333f, new AnimationCurve((Keyframe[])(object)new Keyframe[4] { new Keyframe(0f, 0.3f), new Keyframe(0.55f, 0.85f), new Keyframe(0.85f, 1f), new Keyframe(1f, 0.15f) })); Gradient val3 = new Gradient(); val3.SetKeys((GradientColorKey[])(object)new GradientColorKey[2] { new GradientColorKey(Color.white, 0f), new GradientColorKey(new Color(1f, 0.7f, 0.5f), 1f) }, (GradientAlphaKey[])(object)new GradientAlphaKey[3] { new GradientAlphaKey(0.9f, 0f), new GradientAlphaKey(0.75f, 0.6f), new GradientAlphaKey(0f, 1f) }); ColorOverLifetimeModule colorOverLifetime = val2.colorOverLifetime; ((ColorOverLifetimeModule)(ref colorOverLifetime)).enabled = true; ((ColorOverLifetimeModule)(ref colorOverLifetime)).color = new MinMaxGradient(val3); RotationOverLifetimeModule rotationOverLifetime = val2.rotationOverLifetime; ((RotationOverLifetimeModule)(ref rotationOverLifetime)).enabled = true; ((RotationOverLifetimeModule)(ref rotationOverLifetime)).z = new MinMaxCurve(-3f, 3f); if (l.Noise > 0f) { NoiseModule noise = val2.noise; ((NoiseModule)(ref noise)).enabled = true; ((NoiseModule)(ref noise)).strength = new MinMaxCurve(l.Noise); ((NoiseModule)(ref noise)).frequency = 1.4f; ((NoiseModule)(ref noise)).scrollSpeed = new MinMaxCurve(1.5f); ((NoiseModule)(ref noise)).damping = true; ((NoiseModule)(ref noise)).quality = (ParticleSystemNoiseQuality)0; } if (stopAtWalls) { int mask = LayerMask.GetMask(new string[5] { "Default", "Room", "Colliders", "Terrain", "Railing" }); if (mask != 0) { CollisionModule collision = val2.collision; ((CollisionModule)(ref collision)).enabled = true; ((CollisionModule)(ref collision)).type = (ParticleSystemCollisionType)1; ((CollisionModule)(ref collision)).mode = (ParticleSystemCollisionMode)0; ((CollisionModule)(ref collision)).collidesWith = LayerMask.op_Implicit(mask); ((CollisionModule)(ref collision)).quality = (ParticleSystemCollisionQuality)1; ((CollisionModule)(ref collision)).dampen = new MinMaxCurve(0.6f); ((CollisionModule)(ref collision)).bounce = new MinMaxCurve(0.05f); ((CollisionModule)(ref collision)).lifetimeLoss = new MinMaxCurve(0.35f); ((CollisionModule)(ref collision)).radiusScale = 0.25f; } } if ((Object)(object)templatePs != (Object)null) { TextureSheetAnimationModule textureSheetAnimation = templatePs.textureSheetAnimation; if (((TextureSheetAnimationModule)(ref textureSheetAnimation)).enabled && (int)((TextureSheetAnimationModule)(ref textureSheetAnimation)).mode == 0) { TextureSheetAnimationModule textureSheetAnimation2 = val2.textureSheetAnimation; ((TextureSheetAnimationModule)(ref textureSheetAnimation2)).enabled = true; ((TextureSheetAnimationModule)(ref textureSheetAnimation2)).mode = (ParticleSystemAnimationMode)0; ((TextureSheetAnimationModule)(ref textureSheetAnimation2)).numTilesX = ((TextureSheetAnimationModule)(ref textureSheetAnimation)).numTilesX; ((TextureSheetAnimationModule)(ref textureSheetAnimation2)).numTilesY = ((TextureSheetAnimationModule)(ref textureSheetAnimation)).numTilesY; ((TextureSheetAnimationModule)(ref textureSheetAnimation2)).animation = ((TextureSheetAnimationModule)(ref textureSheetAnimation)).animation; ((TextureSheetAnimationModule)(ref textureSheetAnimation2)).rowMode = ((TextureSheetAnimationModule)(ref textureSheetAnimation)).rowMode; ((TextureSheetAnimationModule)(ref textureSheetAnimation2)).rowIndex = ((TextureSheetAnimationModule)(ref textureSheetAnimation)).rowIndex; ((TextureSheetAnimationModule)(ref textureSheetAnimation2)).frameOverTime = ((TextureSheetAnimationModule)(ref textureSheetAnimation)).frameOverTime; ((TextureSheetAnimationModule)(ref textureSheetAnimation2)).startFrame = ((TextureSheetAnimationModule)(ref textureSheetAnimation)).startFrame; ((TextureSheetAnimationModule)(ref textureSheetAnimation2)).cycleCount = ((TextureSheetAnimationModule)(ref textureSheetAnimation)).cycleCount; } } ParticleSystemRenderer component = val.GetComponent<ParticleSystemRenderer>(); component.renderMode = (ParticleSystemRenderMode)0; ((Renderer)component).shadowCastingMode = (ShadowCastingMode)0; ((Renderer)component).receiveShadows = false; component.maxParticleSize = 2f; component.sortingFudge = ((!((Object)(object)templateRenderer != (Object)null)) ? 0f : templateRenderer.sortingFudge); ((Renderer)component).sharedMaterial = MakeMaterial(template, l.Col, glow, l.Name); } private static Material MakeMaterial(Material template, Color c, float glow, string name) { //IL_000d: Unknown result type (might be due to invalid IL or missing references) //IL_0013: Expected O, but got Unknown //IL_0051: Unknown result type (might be due to invalid IL or missing references) //IL_0057: Expected O, but got Unknown //IL_013b: Unknown result type (might be due to invalid IL or missing references) //IL_0140: Unknown result type (might be due to invalid IL or missing references) //IL_01ac: Unknown result type (might be due to invalid IL or missing references) //IL_01b1: Unknown result type (might be due to invalid IL or missing references) //IL_0218: Unknown result type (might be due to invalid IL or missing references) //IL_017b: Unknown result type (might be due to invalid IL or missing references) Material val; if ((Object)(object)template != (Object)null) { val = new Material(template); if (!_loggedMaterial) { _loggedMaterial = true; LogShader(template); } } else { Shader val2 = Shader.Find("HDRP/Unlit"); if ((Object)(object)val2 == (Object)null) { throw new Exception("no flame material available"); } val = new Material(val2); HDMaterial.SetSurfaceType(val, true); if (val.HasProperty("_BlendMode")) { val.SetFloat("_BlendMode", 1f); } Texture2D val3 = Blob(); string[] array = new string[2] { "_UnlitColorMap", "_MainTex" }; foreach (string text in array) { if (val.HasProperty(text)) { val.SetTexture(text, (Texture)(object)val3); } } HDMaterial.ValidateMaterial(val); } ((Object)val).name = "Grayl_OrangeFlame_" + name + "_Mat"; ((Object)val).hideFlags = (HideFlags)61; string[] array2 = new string[4] { "_UnlitColor", "_BaseColor", "_Color", "_TintColor" }; foreach (string text2 in array2) { if (val.HasProperty(text2)) { float a = val.GetColor(text2).a; val.SetColor(text2, new Color(c.r, c.g, c.b, (!(a <= 0f)) ? a : 1f)); } } if (val.HasProperty("_EmissiveColor")) { Color color = val.GetColor("_EmissiveColor"); float num = Mathf.Max(color.r, Mathf.Max(color.g, color.b)); if (num <= 0f) { num = 1f; } val.SetColor("_EmissiveColor", new Color(c.r * num * glow, c.g * num * glow, c.b * num * glow, color.a)); } return val; } private static void LogShader(Material t) { //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_00a6: Unknown result type (might be due to invalid IL or missing references) //IL_00d8: Unknown result type (might be due to invalid IL or missing references) //IL_00db: Invalid comparison between Unknown and I4 //IL_00e0: Unknown result type (might be due to invalid IL or missing references) //IL_00e3: Invalid comparison between Unknown and I4 //IL_00c3: Unknown result type (might be due to invalid IL or missing references) //IL_010e: Unknown result type (might be due to invalid IL or missing references) //IL_0111: Invalid comparison between Unknown and I4 try { Shader shader = t.shader; StringBuilder stringBuilder = new StringBuilder("[Flame visual] template material '" + ((Object)t).name + "' shader '" + ((!((Object)(object)shader != (Object)null)) ? "?" : ((Object)shader).name) + "' keywords [" + string.Join(",", t.shaderKeywords) + "] props:"); if ((Object)(object)shader != (Object)null) { for (int i = 0; i < shader.GetPropertyCount(); i++) { string propertyName = shader.GetPropertyName(i); ShaderPropertyType propertyType = shader.GetPropertyType(i); stringBuilder.Append(' ').Append(propertyName); if ((int)propertyType == 0 && t.HasProperty(propertyName)) { stringBuilder.Append('=').Append(t.GetColor(propertyName)); } else if (((int)propertyType == 2 || (int)propertyType == 3) && t.HasProperty(propertyName)) { stringBuilder.Append('=').Append(t.GetFloat(propertyName)); } else if ((int)propertyType == 4 && t.HasProperty(propertyName)) { Texture texture = t.GetTexture(propertyName); stringBuilder.Append('=').Append((!((Object)(object)texture != (Object)null)) ? "none" : ((Object)texture).name); } } } Plugin.Log.LogInfo((object)stringBuilder.ToString()); } catch (Exception ex) { Plugin.Log.LogWarning((object)("[Flame visual] shader log failed: " + ex.Message)); } } private static Texture2D Blob() { //IL_001c: Unknown result type (might be due to invalid IL or missing references) //IL_0022: Expected O, but got Unknown //IL_00e5: Unknown result type (might be due to invalid IL or missing references) //IL_00ea: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)_blob != (Object)null) { return _blob; } Texture2D val = new Texture2D(64, 64, (TextureFormat)4, false); ((Texture)val).wrapMode = (TextureWrapMode)1; Color[] array = (Color[])(object)new Color[4096]; for (int i = 0; i < 64; i++) { for (int j = 0; j < 64; j++) { float num = ((float)j + 0.5f) / 64f * 2f - 1f; float num2 = ((float)i + 0.5f) / 64f * 2f - 1f; float num3 = Mathf.Sqrt(num * num + num2 * num2); float num4 = Mathf.PerlinNoise((float)j * 0.15f, (float)i * 0.15f) * 0.35f + 0.65f; float num5 = Mathf.Clamp01(1f - num3); num5 = num5 * num5 * num4; ref Color reference = ref array[i * 64 + j]; reference = new Color(1f, 1f, 1f, num5); } } val.SetPixels(array); val.Apply(false, true); ((Object)val).hideFlags = (HideFlags)61; _blob = val; return val; } } internal static class MonsterReactions { private class Takeover { public bool Flee; public Vector3 Target; public float Until; public int StartState; } internal static ConfigEntry<bool> LureOn; internal static ConfigEntry<bool> ScareOn; internal static ConfigEntry<bool> LogReactions; internal static ConfigEntry<float> LureRadius; internal static ConfigEntry<float> LureChance; internal static ConfigEntry<float> LureSeconds; internal static ConfigEntry<float> NoiseMult; internal static ConfigEntry<float> ScareSeconds; internal static ConfigEntry<float> ScareCooldown; internal static ConfigEntry<string> Ignored; private const int GunshotNoiseId = 1840; private static readonly Dictionary<EnemyAI, Takeover> Active = new Dictionary<EnemyAI, Takeover>(); private static readonly Dictionary<EnemyAI, float> ScareImmuneUntil = new Dictionary<EnemyAI, float>(); private static HashSet<string> _ignored; private static string _ignoredRaw; private static readonly Random Rng = new Random(); private static FieldInfo _prevDestination; private static FieldInfo _streamObjectField; private static FieldInfo _streamEmittingField; private static float _nextSweep; private static int _logBudget = 200; internal static int Replaced; private static float _nextScareCheck; internal static void Bind(ConfigFile cfg) { LureOn = cfg.Bind<bool>("Monster Reactions", "Gunshots Lure Monsters", true, "Idle monsters that hear a gunshot come to investigate where it was fired."); LureRadius = cfg.Bind<float>("Monster Reactions", "Gunshot Lure Radius", 45f, "How far away (m) a monster can hear a gunshot and come looking."); LureChance = cfg.Bind<float>("Monster Reactions", "Gunshot Lure Chance", 0.6f, "Chance (0-1) each idle monster in range comes to investigate."); LureSeconds = cfg.Bind<float>("Monster Reactions", "Gunshot Lure Seconds", 12f, "Longest a monster spends walking to the gunshot before going back to normal."); NoiseMult = cfg.Bind<float>("Monster Reactions", "Gunshot Noise Multiplier", 1.5f, "Multiplies how far the game's own hearing reaches for gunshots (dogs, etc.). 1 = Better Armory default."); ScareOn = cfg.Bind<bool>("Monster Reactions", "Flame Scares Monsters", true, "Monsters caught in the flamethrower run away from it for a moment."); ScareSeconds = cfg.Bind<float>("Monster Reactions", "Flame Scare Seconds", 3f, "How long a burned monster runs away."); ScareCooldown = cfg.Bind<float>("Monster Reactions", "Flame Scare Cooldown", 6f, "After running away, how long before the same monster can be scared again."); Ignored = cfg.Bind<string>("Monster Reactions", "Ignored Monsters", "Spring,Jester,Earth Leviathan,Blob,RadMech,Girl,Lasso,RunningLasso,Butler Bees,Red Locust Bees,Docile Locust Bees,Manticoil,Centipede,Red pill,Clay Surgeon,Maneater,Bush Wolf,Cadaver Growths,Cadaver Bloom,Observer,Herobrine,SlendermanEnemy", "Monsters (internal enemy names, comma separated) that never react. Stationary or special-behaviour monsters are listed so they keep working normally."); LogReactions = cfg.Bind<bool>("Monster Reactions", "Log Monster Reactions", false, "Log when a monster is lured or scared (for testing)."); } internal static void Patch(Harmony harmony) { //IL_0049: Unknown result type (might be due to invalid IL or missing references) //IL_004f: Expected O, but got Unknown //IL_008a: Unknown result type (might be due to invalid IL or missing references) //IL_0098: Expected O, but got Unknown _prevDestination = AccessTools.Field(typeof(EnemyAI), "prevDestination"); MethodInfo methodInfo = AccessTools.Method(typeof(EnemyAI), "Update", (Type[])null, (Type[])null); MethodInfo methodInfo2 = methodInfo; HarmonyMethod val = new HarmonyMethod(typeof(MonsterReactions).GetMethod("UpdateTranspiler", BindingFlags.Static | BindingFlags.NonPublic)); harmony.Patch((MethodBase)methodInfo2, (HarmonyMethod)null, (HarmonyMethod)null, val, (HarmonyMethod)null, (HarmonyMethod)null); MethodInfo methodInfo3 = AccessTools.Method(typeof(RoundManager), "PlayAudibleNoise", (Type[])null, (Type[])null); harmony.Patch((MethodBase)methodInfo3, new HarmonyMethod(typeof(MonsterReactions).GetMethod("NoisePrefix", BindingFlags.Static | BindingFlags.NonPublic)), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null); Plugin.Log.LogInfo((object)("Monster reactions active: gunshot lure " + ((!LureOn.Value) ? "off" : "on") + ", flame scare " + ((!ScareOn.Value) ? "off" : "on") + ".")); } private static IEnumerable<CodeInstruction> UpdateTranspiler(IEnumerable<CodeInstruction> instructions) { MethodInfo target = AccessTools.Method(typeof(EnemyAI), "DoAIInterval", (Type[])null, (Type[])null); MethodInfo gate = typeof(MonsterReactions).GetMethod("Gate", BindingFlags.Static | BindingFlags.NonPublic); foreach (CodeInstruction ci in instructions) { if ((ci.opcode == OpCodes.Callvirt || ci.opcode == OpCodes.Call) && ci.operand as MethodInfo == target) { CodeInstruction c = new CodeInstruction(OpCodes.Call, (object)gate); c.labels.AddRange(ci.labels); c.blocks.AddRange(ci.blocks); Replaced++; yield return c; } else { yield return ci; } } } private static void Gate(EnemyAI ai) { if ((Object)(object)ai != (Object)null && Active.Count > 0 && Active.TryGetValue(ai, out var value)) { bool flag; try { flag = Steer(ai, value); } catch (Exception ex) { flag = false; Plugin.Log.LogWarning((object)("Monster reaction stopped: " + ex.Message)); } if (flag) { return; } Release(ai, value); } ai.DoAIInterval(); } private static bool Steer(EnemyAI ai, Takeover t) { //IL_00b4: Unknown result type (might be due to invalid IL or missing references) //IL_0077: Unknown result type (might be due to invalid IL or missing references) //IL_007d: Unknown result type (might be due to invalid IL or missing references) //IL_0082: Unknown result type (might be due to invalid IL or missing references) //IL_0087: Unknown result type (might be due to invalid IL or missing references) if (ai.isEnemyDead || Time.time > t.Until) { return false; } NavMeshAgent agent = ai.agent; if ((Object)(object)agent == (Object)null || !((Behaviour)agent).enabled || !agent.isOnNavMesh) { return false; } if (!t.Flee) { if (ai.currentBehaviourStateIndex != t.StartState || ai.movingTowardsTargetPlayer) { return false; } Vector3 val = ((Component)ai).transform.position - t.Target; val.y = 0f; if (((Vector3)(ref val)).sqrMagnitude < 9f) { return false; } } if (!ai.inSpecialAnimation) { agent.SetDestination(t.Target); } ai.SyncPositionToClients(); return true; } private static void Release(EnemyAI ai, Takeover t) { //IL_0061: Unknown result type (might be due to invalid IL or missing references) Active.Remove(ai); if (t.Flee) { ScareImmuneUntil[ai] = Time.time + Math.Max(0f, ScareCooldown.Value); } try { if (_prevDestination != null) { _prevDestination.SetValue(ai, (object)new Vector3(float.NaN, 0f, 0f)); } } catch { } if (LogReactions.Value && _logBudget-- > 0) { Plugin.Log.LogInfo((object)("[Reaction] " + Name(ai) + " back to normal.")); } } private static string Name(EnemyAI ai) { return (!((Object)(object)ai != (Object)null) || !((Object)(object)ai.enemyType != (Object)null)) ? "?" : ai.enemyType.enemyName; } private static bool IsIgnored(EnemyAI ai) { string text = Ignored.Value ?? string.Empty; if (_ignored == null || text != _ignoredRaw) { _ignoredRaw = text; _ignored = new HashSet<string>(StringComparer.OrdinalIgnoreCase); string[] array = text.Split(new char[1] { ',' }); foreach (string text2 in array) { if (text2.Trim().Length > 0) { _ignored.Add(text2.Trim()); } } } return _ignored.Contains(Name(ai)); } private static bool Usable(EnemyAI ai) { return (Object)(object)ai != (Object)null && ((NetworkBehaviour)ai).IsOwner && !ai.isEnemyDead && (Object)(object)ai.agent != (Object)null && ((Behaviour)ai.agent).enabled && (Object)(object)ai.enemyType != (Object)null && !IsIgnored(ai); } private static void Sweep() { if (Time.time < _nextSweep) { return; } _nextSweep = Time.time + 5f; List<EnemyAI> list = new List<EnemyAI>(); foreach (KeyValuePair<EnemyAI, Takeover> item in Active) { if ((Object)(object)item.Key == (Object)null) { list.Add(item.Key); } } foreach (KeyValuePair<EnemyAI, float> item2 in ScareImmuneUntil) { if ((Object)(object)item2.Key == (Object)null || item2.Value < Time.time) { list.Add(item2.Key); } } foreach (EnemyAI item3 in list) { Active.Remove(item3); ScareImmuneUntil.Remove(item3); } } private static void NoisePrefix(Vector3 noisePosition, ref float noiseRange, int noiseID) { //IL_00fb: Unknown result type (might be due to invalid IL or missing references) //IL_0100: Unknown result type (might be due to invalid IL or missing references) //IL_0101: Unknown result type (might be due to invalid IL or missing references) //IL_0106: Unknown result type (might be due to invalid IL or missing references) //IL_0178: 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_01f7: Unknown result type (might be due to invalid IL or missing references) //IL_01fc: 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_0202: Unknown result type (might be due to invalid IL or missing references) if (noiseID != 1840) { return; } try { float num = Mathf.Clamp(NoiseMult.Value, 0.25f, 5f); noiseRange *= num; if (!LureOn.Value || (Object)(object)RoundManager.Instance == (Object)null) { return; } Sweep(); bool flag = noisePosition.y < -80f; float num2 = LureRadius.Value * LureRadius.Value; foreach (EnemyAI spawnedEnemy in RoundManager.Instance.SpawnedEnemies) { if (!Usable(spawnedEnemy) || Active.ContainsKey(spawnedEnemy) || spawnedEnemy.isOutside == flag || spawnedEnemy.movingTowardsTargetPlayer || (Object)(object)spawnedEnemy.targetPlayer != (Object)null || spawnedEnemy.currentBehaviourStateIndex != 0) { continue; } Vector3 val = ((Component)spawnedEnemy).transform.position - noisePosition; if (((Vector3)(ref val)).sqrMagnitude > num2) { continue; } double num3; lock (Rng) { num3 = Rng.NextDouble(); } if (!(num3 >= (double)LureChance.Value)) { Active[spawnedEnemy] = new Takeover { Flee = false, Target = noisePosition, Until = Time.time + LureSeconds.Value, StartState = spawnedEnemy.currentBehaviourStateIndex }; if (LogReactions.Value && _logBudget-- > 0) { ManualLogSource log = Plugin.Log; string[] obj = new string[5] { "[Reaction] ", Name(spawnedEnemy), " heard a gunshot ", null, null }; Vector3 val2 = ((Component)spawnedEnemy).transform.position - noisePosition; obj[3] = Mathf.Sqrt(((Vector3)(ref val2)).sqrMagnitude).ToString("0"); obj[4] = " m away and is coming to look."; log.LogInfo((object)string.Concat(obj)); } } } } catch (Exception ex) { Plugin.Log.LogWarning((object)("Gunshot lure failed: " + ex.Message)); } } internal static void FlameTick(object driver, float reach, float muzzleRadius, float endRadius) { //IL_00fc: Unknown result type (might be due to invalid IL or missing references) //IL_0101: Unknown result type (might be due to invalid IL or missing references) //IL_0108: Unknown result type (might be due to invalid IL or missing references) //IL_010d: Unknown result type (might be due to invalid IL or missing references) //IL_018d: Unknown result type (might be due to invalid IL or missing references) //IL_0192: Unknown result type (might be due to invalid IL or missing references) //IL_019c: Unknown result type (might be due to invalid IL or missing references) //IL_01a1: Unknown result type (might be due to invalid IL or missing references) //IL_01a6: Unknown result type (might be due to invalid IL or missing references) //IL_01a8: Unknown result type (might be due to invalid IL or missing references) //IL_01aa: Unknown result type (might be due to invalid IL or missing references) //IL_01ab: Unknown result type (might be due to invalid IL or missing references) //IL_01b0: 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_01b4: Unknown result type (might be due to invalid IL or missing references) //IL_01e8: Unknown result type (might be due to invalid IL or missing references) //IL_01ea: Unknown result type (might be due to invalid IL or missing references) //IL_01ed: Unknown result type (might be due to invalid IL or missing references) //IL_01f2: Unknown result type (might be due to invalid IL or missing references) //IL_01f7: Unknown result type (might be due to invalid IL or missing references) //IL_0211: Unknown result type (might be due to invalid IL or missing references) //IL_0212: Unknown result type (might be due to invalid IL or missing references) //IL_0217: Unknown result type (might be due to invalid IL or missing references) //IL_0231: Unknown result type (might be due to invalid IL or missing references) //IL_0233: Unknown result type (might be due to invalid IL or missing references) if (!ScareOn.Value || (Object)(object)RoundManager.Instance == (Object)null) { return; } if (_streamObjectField == null) { Type type = driver.GetType(); _streamObjectField = AccessTools.Field(type, "_streamObject"); _streamEmittingField = AccessTools.Field(type, "_streamEmitting"); if (_streamObjectField == null || _streamEmittingField == null) { ScareOn.Value = false; Plugin.Log.LogWarning((object)"Flame scare: stream fields not found, turning it off."); return; } } if (!(bool)_streamEmittingField.GetValue(driver)) { return; } object? value = _streamObjectField.GetValue(driver); GameObject val = (GameObject)((value is GameObject) ? value : null); if ((Object)(object)val == (Object)null || !val.activeInHierarchy || Time.time < _nextScareCheck) { return; } _nextScareCheck = Time.time + 0.15f; Sweep(); Vector3 position = val.transform.position; Vector3 forward = val.transform.forward; foreach (EnemyAI spawnedEnemy in RoundManager.Instance.SpawnedEnemies) { if (!Usable(spawnedEnemy) || (Active.TryGetValue(spawnedEnemy, out var value2) && value2.Flee) || (ScareImmuneUntil.TryGetValue(spawnedEnemy, out var value3) && Time.time < value3)) { continue; } Vector3 val2 = ((Component)spawnedEnemy).transform.position + Vector3.up * 1f; Vector3 val3 = val2 - position; float num = Vector3.Dot(val3, forward); if (num < 0f || num > reach) { continue; } float num2 = Mathf.Lerp(muzzleRadius, endRadius, num / reach) + 0.6f; Vector3 val4 = val3 - forward * num; if (!(((Vector3)(ref val4)).sqrMagnitude > num2 * num2)) { Vector3 target = FleeTarget(spawnedEnemy, position); Active[spawnedEnemy] = new Takeover { Flee = true, Target = target, Until = Time.time + ScareSeconds.Value, StartState = spawnedEnemy.currentBehaviourStateIndex }; if (LogReactions.Value && _logBudget-- > 0) { Plugin.Log.LogInfo((object)("[Reaction] " + Name(spawnedEnemy) + " got burned and is running away.")); } } } } private static Vector3 FleeTarget(EnemyAI ai, Vector3 flame) { //IL_0006: Unknown result type (might be due to invalid IL or missing references) //IL_000b: Unknown result type (might be due to invalid IL or missing references) //IL_000c: 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_000e: 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_001c: Unknown result type (might be due to invalid IL or missing references) //IL_001d: Unknown result type (might be due to invalid IL or missing references) //IL_001e: Unknown result type (might be due to invalid IL or missing references) //IL_001f: Unknown result type (might be due to invalid IL or missing references) //IL_0024: Unknown result type (might be due to invalid IL or missing references) //IL_0028: Unknown result type (might be due to invalid IL or missing references) //IL_0032: Unknown result type (might be due to invalid IL or missing references) //IL_0037: Unknown result type (might be due to invalid IL or missing references) //IL_003c: Unknown result type (might be due to invalid IL or missing references) //IL_0104: Unknown result type (might be due to invalid IL or missing references) //IL_007f: Unknown result type (might be due to invalid IL or missing references) //IL_0084: Unknown result type (might be due to invalid IL or missing references) //IL_0086: 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_0089: Unknown result type (might be due to invalid IL or missing references) //IL_008e: Unknown result type (might be due to invalid IL or missing references) //IL_00b6: 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_00b9: 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) //IL_00f0: Unknown result type (might be due to invalid IL or missing references) //IL_00f2: Unknown result type (might be due to invalid IL or missing references) Vector3 position = ((Component)ai).transform.position; Vector3 val = position - flame; float sqrMagnitude = ((Vector3)(ref val)).sqrMagnitude; Vector3 val2 = position - flame; Vector3 result = position + ((Vector3)(ref val2)).normalized * 12f; float num = float.MinValue; if (ai.allAINodes != null) { GameObject[] allAINodes = ai.allAINodes; foreach (GameObject val3 in allAINodes) { if ((Object)(object)val3 == (Object)null) { continue; } Vector3 position2 = val3.transform.position; Vector3 val4 = position2 - position; float sqrMagnitude2 = ((Vector3)(ref val4)).sqrMagnitude; if (sqrMagnitude2 < 16f || sqrMagnitude2 > 900f) { continue; } Vector3 val5 = position2 - flame; float sqrMagnitude3 = ((Vector3)(ref val5)).sqrMagnitude; if (!(sqrMagnitude3 <= sqrMagnitude)) { float num2 = sqrMagnitude3 - sqrMagnitude2 * 0.5f; if (num2 > num) { num = num2; result = position2; } } } } return result; } } internal static class SwapSounds { internal static ConfigEntry<bool> On; internal static ConfigEntry<string> Style; internal static ConfigEntry<float> Volume; private static readonly Dictionary<AudioClip, AudioClip> Quiet = new Dictionary<AudioClip, AudioClip>(); private static AudioClip _vanillaGrab; private static AudioClip _vanillaPocket; private static bool _searchedVanilla; private static FieldInfo _ammoItems; private static bool _logged; internal static void Bind(ConfigFile cfg) { //IL_0050: Unknown result type (might be due to invalid IL or missing references) //IL_005a: Expected O, but got Unknown On = cfg.Bind<bool>("Audio Fix", "Fix Weapon Swap Sound", true, "Better Armory plays its loud 'gun dropped' sound when you switch to or away from a gun. This replaces the switch sound and keeps the real drop sound."); Style = cfg.Bind<string>("Audio Fix", "Swap Sound Style", "Vanilla", new ConfigDescription("Vanilla = the normal shotgun handling sound. Quiet = Better Armory's own sound, turned down.", (AcceptableValueBase)(object)new AcceptableValueList<string>(new string[2] { "Vanilla", "Quiet" }), Array.Empty<object>())); Volume = cfg.Bind<float>("Audio Fix", "Swap Sound Volume", 0.3f, "Volume of the Quiet style (1 = as loud as dropping the gun)."); } internal static void Patch(Harmony harmony, Assembly armory) { //IL_00a3: Unknown result type (might be due to invalid IL or missing references) //IL_00aa: Expected O, but got Unknown //IL_00f4: Unknown result type (might be due to invalid IL or missing references) //IL_00fb: Expected O, but got Unknown Type type = armory.GetType("Y4NGZUpgrades.Weapons.WeaponSoundRegistry"); Type type2 = armory.GetType("Y4NGZUpgrades.Weapons.AmmoPickupRegistry"); MethodInfo methodInfo = ((!(type != null)) ? null : AccessTools.Method(type, "ApplyFoley", (Type[])null, (Type[])null)); MethodInfo methodInfo2 = ((!(type2 != null)) ? null : AccessTools.Method(type2, "Apply