Decompiled source of Risk of ULTRAKILL v0.7.5

patchers/ROUK.Patcher.dll

Decompiled 12 hours ago
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.Versioning;
using BepInEx;
using BepInEx.Logging;
using Microsoft.CodeAnalysis;
using Mono.Cecil;
using ROUK.Common;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)]
[assembly: TargetFramework(".NETStandard,Version=v2.1", FrameworkDisplayName = ".NET Standard 2.1")]
[assembly: AssemblyCompany("ROUK.Patcher")]
[assembly: AssemblyConfiguration("Release")]
[assembly: AssemblyFileVersion("1.0.0.0")]
[assembly: AssemblyInformationalVersion("1.0.0")]
[assembly: AssemblyProduct("ROUK.Patcher")]
[assembly: AssemblyTitle("ROUK.Patcher")]
[assembly: AssemblyVersion("1.0.0.0")]
[module: RefSafetyRules(11)]
namespace Microsoft.CodeAnalysis
{
	[CompilerGenerated]
	[Embedded]
	internal sealed class EmbeddedAttribute : Attribute
	{
	}
}
namespace System.Runtime.CompilerServices
{
	[CompilerGenerated]
	[Embedded]
	[AttributeUsage(AttributeTargets.Module, AllowMultiple = false, Inherited = false)]
	internal sealed class RefSafetyRulesAttribute : Attribute
	{
		public readonly int Version;

		public RefSafetyRulesAttribute(int P_0)
		{
			Version = P_0;
		}
	}
}
namespace ROUK.Common
{
	internal static class AudioFlag
	{
		public enum Result
		{
			AlreadySet,
			Changed,
			NotFound
		}

		private static readonly byte[] head = new byte[12]
		{
			0, 0, 128, 63, 0, 0, 128, 63, 0, 0,
			128, 63
		};

		private const int DisableFlagOffset = 40;

		public static Result Set(string path, string backup, bool enable)
		{
			if (!File.Exists(path))
			{
				return Result.NotFound;
			}
			byte[] array = File.ReadAllBytes(path);
			int num = Find(array);
			if (num < 0)
			{
				return Result.NotFound;
			}
			byte b = ((!enable) ? ((byte)1) : ((byte)0));
			if (array[num + 40] == b)
			{
				return Result.AlreadySet;
			}
			Directory.CreateDirectory(Path.GetDirectoryName(backup));
			if (enable && !File.Exists(backup))
			{
				File.Copy(path, backup);
			}
			array[num + 40] = b;
			File.WriteAllBytes(path, array);
			return Result.Changed;
		}

		private static int Find(byte[] d)
		{
			int result = -1;
			int num = 0;
			for (int i = 0; i + 40 + 2 < d.Length; i++)
			{
				bool flag = true;
				for (int j = 0; j < head.Length && flag; j++)
				{
					flag = d[i + j] == head[j];
				}
				if (flag && d[i + 12] <= 7 && d[i + 13] == 0 && d[i + 14] == 0 && d[i + 15] == 0)
				{
					for (int k = 32; k < 40 && flag; k++)
					{
						flag = d[i + k] == 0;
					}
					if (flag && d[i + 40] <= 1 && d[i + 41] <= 1)
					{
						result = i;
						num++;
					}
				}
			}
			if (num != 1)
			{
				return -1;
			}
			return result;
		}
	}
}
namespace ROUK.Patcher
{
	public static class AudioPatcher
	{
		public static IEnumerable<string> TargetDLLs { get; } = new string[0];

		public static void Patch(AssemblyDefinition assembly)
		{
		}

		public static void Initialize()
		{
			ManualLogSource val = Logger.CreateLogSource("ROUK.Patcher");
			try
			{
				bool flag = ConfigEnabled();
				string path = Path.Combine(Directory.GetParent(Paths.ManagedPath).FullName, "globalgamemanagers");
				string backup = Path.Combine(Paths.ConfigPath, "ROUK", "globalgamemanagers.original");
				switch (AudioFlag.Set(path, backup, flag))
				{
				case AudioFlag.Result.Changed:
					val.LogInfo((object)(flag ? "Enabled Unity audio for ULTRAKILL sounds." : "Restored Risk of Rain 2's original audio setting."));
					break;
				case AudioFlag.Result.NotFound:
					val.LogWarning((object)"Could not locate Risk of Rain 2's audio settings.");
					break;
				}
			}
			catch (Exception ex)
			{
				val.LogWarning((object)("Could not change Risk of Rain 2's audio setting: " + ex.Message));
			}
			Logger.Sources.Remove((ILogSource)(object)val);
		}

		private static bool ConfigEnabled()
		{
			string path = Path.Combine(Paths.ConfigPath, "com.sethly.rouk.cfg");
			if (!File.Exists(path))
			{
				return true;
			}
			string[] array = File.ReadAllLines(path);
			for (int i = 0; i < array.Length; i++)
			{
				string[] array2 = array[i].Split('=');
				if (array2.Length == 2 && array2[0].Trim() == "EnableUltrakillAudio")
				{
					return !array2[1].Trim().Equals("false", StringComparison.OrdinalIgnoreCase);
				}
			}
			return true;
		}
	}
}

plugins/ROUK.dll

Decompiled 12 hours ago
using System;
using System.Collections;
using System.Collections.Generic;
using System.Diagnostics;
using System.Globalization;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.Versioning;
using System.Security;
using System.Security.Permissions;
using System.Text;
using System.Text.RegularExpressions;
using BepInEx;
using BepInEx.Configuration;
using BepInEx.Logging;
using EntityStates;
using EntityStates.BrotherMonster;
using EntityStates.ClayGrenadier;
using EntityStates.FalseSon;
using EntityStates.GolemMonster;
using EntityStates.ImpBossMonster;
using EntityStates.Loader;
using EntityStates.ParentMonster;
using HG.BlendableTypes;
using KinematicCharacterController;
using Microsoft.CodeAnalysis;
using On.EntityStates.FalseSon;
using On.EntityStates.GolemMonster;
using On.EntityStates.Loader;
using On.RoR2;
using On.RoR2.Projectile;
using On.RoR2.UI.MainMenu;
using R2API;
using R2API.Networking;
using R2API.Networking.Interfaces;
using ROUK.Arms;
using ROUK.Common;
using ROUK.Debugging;
using ROUK.Hook;
using ROUK.Movement;
using ROUK.Music;
using ROUK.Net;
using ROUK.Projectiles;
using ROUK.Shop;
using ROUK.States;
using ROUK.Style;
using ROUK.Survivor;
using ROUK.UkAssets;
using ROUK.Visuals;
using ROUK.Weapons;
using ROUK.Weapons.States;
using Rebindables;
using Rewired;
using RoR2;
using RoR2.CameraModes;
using RoR2.ConVar;
using RoR2.Projectile;
using RoR2.Skills;
using RoR2.UI;
using RoR2.UI.MainMenu;
using TMPro;
using ThreeEyedGames;
using UnityEngine;
using UnityEngine.AddressableAssets;
using UnityEngine.Animations;
using UnityEngine.EventSystems;
using UnityEngine.Networking;
using UnityEngine.Playables;
using UnityEngine.Rendering;
using UnityEngine.SceneManagement;
using UnityEngine.UI;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)]
[assembly: TargetFramework(".NETStandard,Version=v2.1", FrameworkDisplayName = ".NET Standard 2.1")]
[assembly: AssemblyCompany("ROUK")]
[assembly: AssemblyConfiguration("Release")]
[assembly: AssemblyFileVersion("1.0.0.0")]
[assembly: AssemblyInformationalVersion("1.0.0")]
[assembly: AssemblyProduct("ROUK")]
[assembly: AssemblyTitle("ROUK")]
[assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)]
[assembly: AssemblyVersion("1.0.0.0")]
[module: UnverifiableCode]
[module: RefSafetyRules(11)]
namespace Microsoft.CodeAnalysis
{
	[CompilerGenerated]
	[Embedded]
	internal sealed class EmbeddedAttribute : Attribute
	{
	}
}
namespace System.Runtime.CompilerServices
{
	[CompilerGenerated]
	[Embedded]
	[AttributeUsage(AttributeTargets.Module, AllowMultiple = false, Inherited = false)]
	internal sealed class RefSafetyRulesAttribute : Attribute
	{
		public readonly int Version;

		public RefSafetyRulesAttribute(int P_0)
		{
			Version = P_0;
		}
	}
}
namespace ROUK
{
	[BepInPlugin("com.sethly.rouk", "ROUK", "0.7.5")]
	[BepInDependency(/*Could not decode attribute arguments.*/)]
	[BepInDependency(/*Could not decode attribute arguments.*/)]
	[BepInDependency(/*Could not decode attribute arguments.*/)]
	[BepInDependency(/*Could not decode attribute arguments.*/)]
	[BepInDependency(/*Could not decode attribute arguments.*/)]
	[BepInDependency(/*Could not decode attribute arguments.*/)]
	public class Plugin : BaseUnityPlugin
	{
		public const string Guid = "com.sethly.rouk";

		public const string Name = "ROUK";

		public const string Version = "0.7.5";

		internal static Plugin Instance;

		internal static ManualLogSource Log;

		private void Update()
		{
			V1Sound.UpdateVolume();
		}

		private void Awake()
		{
			Instance = this;
			Log = ((BaseUnityPlugin)this).Logger;
			V1Config.Init(((BaseUnityPlugin)this).Config);
			AudioEnabler.Apply(V1Config.EnableUltrakillAudio.Value);
			V1Keybinds.Init();
			NetMessages.Init();
			ItemCompat.Init();
			V1Conductor.Init();
			V1Landing.Init();
			V1Jukebox.Init();
			UltrakillMissingNotice.Init();
			PrefabDump.Init();
			V1Content.Init();
			((Component)this).gameObject.AddComponent<DebugTools>();
			Log.LogInfo((object)"ROUK loaded");
		}
	}
	internal static class V1Config
	{
		public static ConfigEntry<string> UltrakillPath;

		public static ConfigEntry<float> WorldScale;

		public static ConfigEntry<float> Size;

		public static ConfigEntry<float> MoveSpeed;

		public static ConfigEntry<float> DamageScale;

		public static ConfigEntry<bool> WhiplashGrabsTerrain;

		public static ConfigEntry<bool> WhiplashGrabsInteractables;

		public static ConfigEntry<bool> SpikedFistGrabsRockets;

		public static ConfigEntry<bool> HitStop;

		public static ConfigEntry<bool> WeaponProgression;

		public static ConfigEntry<bool> ScrollWheelWeapons;

		public static ConfigEntry<bool> ScrollWheelReverse;

		public static ConfigEntry<float> ExplosionSelfDamage;

		public static ConfigEntry<float> ViewmodelFov;

		public static ConfigEntry<float> Fov;

		public static ConfigEntry<bool> CameraTilt;

		public static ConfigEntry<bool> UseUltrakillAssets;

		public static ConfigEntry<bool> EnableUltrakillAudio;

		public static ConfigEntry<float> UltrakillVolume;

		public static ConfigEntry<bool> ShopMusic;

		public static ConfigEntry<bool> LandingIntroCue;

		public static ConfigEntry<bool> DebugAutoStart;

		public static ConfigEntry<bool> DebugAutoTest;

		public static ConfigEntry<string> DebugScreenshotDir;

		public static void Init(ConfigFile config)
		{
			UltrakillPath = config.Bind<string>("General", "UltrakillPath", "", "Path to your ULTRAKILL install (the folder containing ULTRAKILL_Data). Leave empty to auto-detect from Steam.");
			UseUltrakillAssets = config.Bind<bool>("General", "UseUltrakillAssets", true, "Load V1's model, arms and weapon models from your local ULTRAKILL install.");
			EnableUltrakillAudio = config.Bind<bool>("General", "EnableUltrakillAudio", true, "Play ULTRAKILL's own sounds. Risk of Rain 2 ships with Unity's audio engine switched off, so this flips that one setting in Risk of Rain 2_Data/globalgamemanagers (a backup is kept in BepInEx/config/ROUK). Needs a game restart. Turning it off restores the original.");
			UltrakillVolume = config.Bind<float>("General", "UltrakillVolume", 0.5f, "Volume of ULTRAKILL's sounds, on top of the game's master and sound-effect volume.");
			LandingIntroCue = config.Bind<bool>("General", "LandingIntroCue", true, "Play V2's intro music cue from 1-4 when V1 lands at the start of a stage. Needs EnableUltrakillAudio.");
			ShopMusic = config.Bind<bool>("General", "ShopMusic", true, "At the shop terminal, play ULTRAKILL's shop jingle and music (following the game's music volume) and fade out the level's music, as ULTRAKILL does. Needs EnableUltrakillAudio.");
			WorldScale = config.Bind<float>("Movement", "WorldScale", 0.6f, "ULTRAKILL distances/speeds are multiplied by this to fit Risk of Rain 2's scale (V1 is 3.5 units tall in ULTRAKILL). 1 = raw ULTRAKILL values.");
			MoveSpeed = config.Bind<float>("Movement", "MoveSpeed", 0.8f, "Multiplier on V1's walking, air-strafing, dash and slide speed (1 = ULTRAKILL's). Jumps and slams are unaffected.");
			Size = config.Bind<float>("Movement", "Size", 2f, "V1's size relative to Commando (affects hitbox and model, not movement speed). Requires a restart.");
			DamageScale = config.Bind<float>("Combat", "DamageScale", 1f, "Multiplier applied to every V1 damage coefficient.");
			WhiplashGrabsTerrain = config.Bind<bool>("Combat", "WhiplashGrabsTerrain", false, "If true the ULTRAKILL whiplash also latches onto terrain (ULTRAKILL itself only grabs enemies and hook points).");
			WhiplashGrabsInteractables = config.Bind<bool>("Combat", "WhiplashGrabsInteractables", false, "If true the whiplash also latches onto interactables (chests, shrines, terminals, the teleporter...) and pulls V1 to them.");
			SpikedFistGrabsRockets = config.Bind<bool>("Combat", "SpikedFistGrabsRockets", true, "If true, V1's Spiked Whiplash (Loader's Spiked Fist) also grabs onto V1's own rockets in flight and drags V1 after them.");
			HitStop = config.Bind<bool>("Combat", "HitStop", false, "ULTRAKILL's hit-stop: the game freezes for a split second on parries and jackhammer hits. Singleplayer only: it never happens in multiplayer.");
			ScrollWheelWeapons = config.Bind<bool>("Controls", "ScrollWheelWeapons", true, "Scroll the mouse wheel to switch to the next / previous weapon (every variant of every slot, in order), like ULTRAKILL.");
			ScrollWheelReverse = config.Bind<bool>("Controls", "ScrollWheelReverse", false, "Reverse the mouse wheel's weapon direction (by default scrolling up goes to the next weapon).");
			WeaponProgression = config.Bind<bool>("Combat", "WeaponProgression", true, "If true, V1 starts each run with only the Piercer revolver, gets one more standard weapon for every boss beaten, and buys the variants and alternate weapons at the shop terminal that goes up near V1 each stage. If false, every weapon's three colours are available from the start, and the shop terminal is used to switch colours to their alternate weapons and to reorder them.");
			ExplosionSelfDamage = config.Bind<float>("Combat", "ExplosionSelfDamage", 0.25f, "Fraction of V1's max health that its own self-damaging explosions (core eject, over-pump, jackhammer pump, projectile boost, malicious railcannon, cannonball) take when V1 is caught in them, like ULTRAKILL. 0 turns it off; the launch still happens.");
			Fov = config.Bind<float>("Visuals", "FirstPersonFov", 90f, "Vertical field of view of V1's first-person camera (Risk of Rain 2's default camera uses 60).");
			DebugAutoStart = config.Bind<bool>("Debug", "AutoStartRun", false, "Development: skip the menus and start a singleplayer run as V1.");
			DebugAutoTest = config.Bind<bool>("Debug", "AutoTest", false, "Development: drive V1 through its moves and weapons after spawning and log the results.");
			DebugScreenshotDir = config.Bind<string>("Debug", "ScreenshotDir", "", "Development: if set, the auto-test saves in-game screenshots (game frame only) here.");
			CameraTilt = config.Bind<bool>("Visuals", "CameraTilt", true, "ULTRAKILL's camera tilt when strafing (stronger while dashing).");
			ViewmodelFov = config.Bind<float>("Visuals", "ViewmodelFov", 90f, "Field of view used to render V1's arms and weapons in first person.");
		}
	}
	internal static class V1Keybinds
	{
		public static ModKeybind Slide;

		public static ModKeybind Punch;

		public static ModKeybind SwitchArm;

		public static ModKeybind ToggleCamera;

		public static readonly ModKeybind[] Weapons = (ModKeybind[])(object)new ModKeybind[5];

		public static void Init()
		{
			//IL_00b7: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c1: Expected O, but got Unknown
			//IL_011c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0126: Expected O, but got Unknown
			//IL_0142: Unknown result type (might be due to invalid IL or missing references)
			//IL_014c: Expected O, but got Unknown
			//IL_0161: Unknown result type (might be due to invalid IL or missing references)
			//IL_016b: Expected O, but got Unknown
			//IL_0182: Unknown result type (might be due to invalid IL or missing references)
			//IL_018c: Expected O, but got Unknown
			LanguageAPI.Add("ROUK_KEY_SLIDE", "V1 Slide / Slam");
			LanguageAPI.Add("ROUK_KEY_PUNCH", "V1 Punch");
			LanguageAPI.Add("ROUK_KEY_SWITCHARM", "V1 Switch Arm");
			LanguageAPI.Add("ROUK_KEY_CAMERA", "V1 Toggle First/Third Person");
			string[] array = new string[5] { "Revolver", "Shotgun", "Nailgun", "Railcannon", "Rocket Launcher" };
			for (int i = 0; i < 5; i++)
			{
				LanguageAPI.Add("ROUK_KEY_WEAPON" + (i + 1), $"V1 Weapon {i + 1} ({array[i]})");
			}
			ToggleCamera = RebindAPI.RegisterModKeybind(new ModKeybind("ROUK_KEY_CAMERA", (KeyCode)118, 13, "Jump", (InputActionType)1, (AxisRange)0));
			KeyCode[] array2 = new KeyCode[5];
			RuntimeHelpers.InitializeArray(array2, (RuntimeFieldHandle)/*OpCode not supported: LdMemberToken*/);
			KeyCode[] array3 = (KeyCode[])(object)array2;
			int[] array4 = new int[5] { 16, 17, 18, 19, 12 };
			for (int num = 4; num >= 0; num--)
			{
				Weapons[num] = RebindAPI.RegisterModKeybind(new ModKeybind("ROUK_KEY_WEAPON" + (num + 1), array3[num], array4[num], "Jump", (InputActionType)1, (AxisRange)0));
			}
			SwitchArm = RebindAPI.RegisterModKeybind(new ModKeybind("ROUK_KEY_SWITCHARM", (KeyCode)103, 9, "Jump", (InputActionType)1, (AxisRange)0));
			Punch = RebindAPI.RegisterModKeybind(new ModKeybind("ROUK_KEY_PUNCH", (KeyCode)102, 15, "Jump", (InputActionType)1, (AxisRange)0));
			Slide = RebindAPI.RegisterModKeybind(new ModKeybind("ROUK_KEY_SLIDE", (KeyCode)306, 7, "Jump", (InputActionType)1, (AxisRange)0));
		}

		public static ButtonState Get(InputBankTest bank, ModKeybind bind)
		{
			//IL_0014: Unknown result type (might be due to invalid IL or missing references)
			//IL_000a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0010: Unknown result type (might be due to invalid IL or missing references)
			if (!Object.op_Implicit((Object)(object)bank))
			{
				return default(ButtonState);
			}
			return InputBankExtensions.GetButtonState(bank, bind);
		}
	}
}
namespace ROUK.Weapons
{
	internal static class CoinChargeback
	{
		[Serializable]
		[CompilerGenerated]
		private sealed class <>c
		{
			public static readonly <>c <>9 = new <>c();

			public static hook_Fire <>9__0_0;

			public static hook_OnEnter <>9__0_1;

			public static hook_Fire <>9__0_2;

			public static hook_SpawnEffect_GameObject_EffectData_bool <>9__0_3;

			internal void <Init>b__0_0(orig_Fire orig, BulletAttack self)
			{
				//IL_0027: Unknown result type (might be due to invalid IL or missing references)
				//IL_002d: Unknown result type (might be due to invalid IL or missing references)
				//IL_0032: Unknown result type (might be due to invalid IL or missing references)
				//IL_0036: Unknown result type (might be due to invalid IL or missing references)
				//IL_003b: Unknown result type (might be due to invalid IL or missing references)
				//IL_0047: 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_0050: Unknown result type (might be due to invalid IL or missing references)
				//IL_0054: Unknown result type (might be due to invalid IL or missing references)
				V1Coin v1Coin = null;
				if (NetworkServer.active && V1Coin.instances.Count > 0 && Object.op_Implicit((Object)(object)self.owner))
				{
					Vector3 origin = self.origin;
					Vector3 aimVector = self.aimVector;
					Ray val = new Ray(origin, ((Vector3)(ref aimVector)).normalized);
					float num = self.maxDistance;
					float num2 = num;
					LayerIndex world = LayerIndex.world;
					RaycastHit val2 = default(RaycastHit);
					if (Physics.Raycast(val, ref val2, num2, LayerMask.op_Implicit(((LayerIndex)(ref world)).mask), (QueryTriggerInteraction)1))
					{
						num = ((RaycastHit)(ref val2)).distance;
					}
					float distance;
					V1Coin v1Coin2 = V1Coin.FindOnRay(val, num, out distance);
					if (Object.op_Implicit((Object)(object)v1Coin2) && IsEnemyOf(self.owner, v1Coin2))
					{
						v1Coin = v1Coin2;
						self.maxDistance = distance;
					}
				}
				orig.Invoke(self);
				if (Object.op_Implicit((Object)(object)v1Coin))
				{
					Reflect(v1Coin, self.owner, self.damage);
				}
			}

			internal void <Init>b__0_1(orig_OnEnter orig, FireLaser self)
			{
				CoinChargeback.laserCoin = null;
				CharacterBody val = (Object.op_Implicit((Object)(object)((EntityState)self).outer) ? ((EntityState)self).outer.commonComponents.characterBody : null);
				if (NetworkServer.active && Object.op_Implicit((Object)(object)val) && Object.op_Implicit((Object)(object)val.inputBank) && val.hasEffectiveAuthority && V1Coin.instances.Count > 0)
				{
					laser = self;
				}
				try
				{
					orig.Invoke(self);
				}
				finally
				{
					V1Coin laserCoin = CoinChargeback.laserCoin;
					laser = null;
					CoinChargeback.laserCoin = null;
					if (Object.op_Implicit((Object)(object)laserCoin))
					{
						Reflect(laserCoin, ((Component)val).gameObject, val.damage * FireLaser.damageCoefficient);
					}
				}
			}

			internal Result <Init>b__0_2(orig_Fire orig, BlastAttack self)
			{
				//IL_00f3: Unknown result type (might be due to invalid IL or missing references)
				//IL_0057: Unknown result type (might be due to invalid IL or missing references)
				//IL_005c: Unknown result type (might be due to invalid IL or missing references)
				//IL_0060: Unknown result type (might be due to invalid IL or missing references)
				//IL_006f: Unknown result type (might be due to invalid IL or missing references)
				//IL_007a: Unknown result type (might be due to invalid IL or missing references)
				//IL_0081: Unknown result type (might be due to invalid IL or missing references)
				//IL_0086: Unknown result type (might be due to invalid IL or missing references)
				//IL_008d: Unknown result type (might be due to invalid IL or missing references)
				//IL_00af: Unknown result type (might be due to invalid IL or missing references)
				//IL_00dc: Unknown result type (might be due to invalid IL or missing references)
				//IL_00e1: Unknown result type (might be due to invalid IL or missing references)
				//IL_00e7: Unknown result type (might be due to invalid IL or missing references)
				//IL_00ec: Unknown result type (might be due to invalid IL or missing references)
				CharacterBody val = ((laser != null) ? ((EntityState)laser).outer.commonComponents.characterBody : null);
				if (Object.op_Implicit((Object)(object)val) && !Object.op_Implicit((Object)(object)laserCoin) && (Object)(object)self.attacker == (Object)(object)((Component)val).gameObject)
				{
					Ray aimRay = val.inputBank.GetAimRay();
					Ray ray = default(Ray);
					((Ray)(ref ray))..ctor(((Ray)(ref aimRay)).origin, ((Vector3)(ref laser.laserDirection)).normalized);
					float num = Vector3.Dot(self.position - ((Ray)(ref ray)).origin, ((Ray)(ref ray)).direction) + 0.1f;
					float distance = 0f;
					V1Coin v1Coin = ((num > 0f) ? V1Coin.FindOnRay(ray, num, out distance) : null);
					if (Object.op_Implicit((Object)(object)v1Coin) && IsEnemyOf(((Component)val).gameObject, v1Coin))
					{
						laserCoin = v1Coin;
						laserEnd = ((Ray)(ref ray)).GetPoint(distance);
						self.position = laserEnd;
					}
				}
				return orig.Invoke(self);
			}

			internal void <Init>b__0_3(orig_SpawnEffect_GameObject_EffectData_bool orig, GameObject prefab, EffectData data, bool transmit)
			{
				//IL_0017: Unknown result type (might be due to invalid IL or missing references)
				if (laser != null && Object.op_Implicit((Object)(object)laserCoin) && data != null)
				{
					data.origin = laserEnd;
				}
				orig.Invoke(prefab, data, transmit);
			}
		}

		private static FireLaser laser;

		private static V1Coin laserCoin;

		private static Vector3 laserEnd;

		public static void Init()
		{
			//IL_0014: Unknown result type (might be due to invalid IL or missing references)
			//IL_0019: Unknown result type (might be due to invalid IL or missing references)
			//IL_001f: Expected O, but got Unknown
			//IL_0038: Unknown result type (might be due to invalid IL or missing references)
			//IL_003d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0043: Expected O, but got Unknown
			//IL_005c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0061: Unknown result type (might be due to invalid IL or missing references)
			//IL_0067: Expected O, but got Unknown
			//IL_0080: Unknown result type (might be due to invalid IL or missing references)
			//IL_0085: Unknown result type (might be due to invalid IL or missing references)
			//IL_008b: Expected O, but got Unknown
			object obj = <>c.<>9__0_0;
			if (obj == null)
			{
				hook_Fire val = delegate(orig_Fire orig, BulletAttack self)
				{
					//IL_0027: Unknown result type (might be due to invalid IL or missing references)
					//IL_002d: Unknown result type (might be due to invalid IL or missing references)
					//IL_0032: Unknown result type (might be due to invalid IL or missing references)
					//IL_0036: Unknown result type (might be due to invalid IL or missing references)
					//IL_003b: Unknown result type (might be due to invalid IL or missing references)
					//IL_0047: 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_0050: Unknown result type (might be due to invalid IL or missing references)
					//IL_0054: Unknown result type (might be due to invalid IL or missing references)
					V1Coin v1Coin = null;
					if (NetworkServer.active && V1Coin.instances.Count > 0 && Object.op_Implicit((Object)(object)self.owner))
					{
						Vector3 origin = self.origin;
						Vector3 aimVector = self.aimVector;
						Ray val5 = new Ray(origin, ((Vector3)(ref aimVector)).normalized);
						float num = self.maxDistance;
						float num2 = num;
						LayerIndex world = LayerIndex.world;
						RaycastHit val6 = default(RaycastHit);
						if (Physics.Raycast(val5, ref val6, num2, LayerMask.op_Implicit(((LayerIndex)(ref world)).mask), (QueryTriggerInteraction)1))
						{
							num = ((RaycastHit)(ref val6)).distance;
						}
						float distance;
						V1Coin v1Coin2 = V1Coin.FindOnRay(val5, num, out distance);
						if (Object.op_Implicit((Object)(object)v1Coin2) && IsEnemyOf(self.owner, v1Coin2))
						{
							v1Coin = v1Coin2;
							self.maxDistance = distance;
						}
					}
					orig.Invoke(self);
					if (Object.op_Implicit((Object)(object)v1Coin))
					{
						Reflect(v1Coin, self.owner, self.damage);
					}
				};
				<>c.<>9__0_0 = val;
				obj = (object)val;
			}
			BulletAttack.Fire += (hook_Fire)obj;
			object obj2 = <>c.<>9__0_1;
			if (obj2 == null)
			{
				hook_OnEnter val2 = delegate(orig_OnEnter orig, FireLaser self)
				{
					laserCoin = null;
					CharacterBody val5 = (Object.op_Implicit((Object)(object)((EntityState)self).outer) ? ((EntityState)self).outer.commonComponents.characterBody : null);
					if (NetworkServer.active && Object.op_Implicit((Object)(object)val5) && Object.op_Implicit((Object)(object)val5.inputBank) && val5.hasEffectiveAuthority && V1Coin.instances.Count > 0)
					{
						laser = self;
					}
					try
					{
						orig.Invoke(self);
					}
					finally
					{
						V1Coin v1Coin = laserCoin;
						laser = null;
						laserCoin = null;
						if (Object.op_Implicit((Object)(object)v1Coin))
						{
							Reflect(v1Coin, ((Component)val5).gameObject, val5.damage * FireLaser.damageCoefficient);
						}
					}
				};
				<>c.<>9__0_1 = val2;
				obj2 = (object)val2;
			}
			FireLaser.OnEnter += (hook_OnEnter)obj2;
			object obj3 = <>c.<>9__0_2;
			if (obj3 == null)
			{
				hook_Fire val3 = delegate(orig_Fire orig, BlastAttack self)
				{
					//IL_00f3: Unknown result type (might be due to invalid IL or missing references)
					//IL_0057: Unknown result type (might be due to invalid IL or missing references)
					//IL_005c: Unknown result type (might be due to invalid IL or missing references)
					//IL_0060: Unknown result type (might be due to invalid IL or missing references)
					//IL_006f: Unknown result type (might be due to invalid IL or missing references)
					//IL_007a: Unknown result type (might be due to invalid IL or missing references)
					//IL_0081: Unknown result type (might be due to invalid IL or missing references)
					//IL_0086: Unknown result type (might be due to invalid IL or missing references)
					//IL_008d: Unknown result type (might be due to invalid IL or missing references)
					//IL_00af: Unknown result type (might be due to invalid IL or missing references)
					//IL_00dc: Unknown result type (might be due to invalid IL or missing references)
					//IL_00e1: Unknown result type (might be due to invalid IL or missing references)
					//IL_00e7: Unknown result type (might be due to invalid IL or missing references)
					//IL_00ec: Unknown result type (might be due to invalid IL or missing references)
					CharacterBody val5 = ((laser != null) ? ((EntityState)laser).outer.commonComponents.characterBody : null);
					if (Object.op_Implicit((Object)(object)val5) && !Object.op_Implicit((Object)(object)laserCoin) && (Object)(object)self.attacker == (Object)(object)((Component)val5).gameObject)
					{
						Ray aimRay = val5.inputBank.GetAimRay();
						Ray ray = default(Ray);
						((Ray)(ref ray))..ctor(((Ray)(ref aimRay)).origin, ((Vector3)(ref laser.laserDirection)).normalized);
						float num = Vector3.Dot(self.position - ((Ray)(ref ray)).origin, ((Ray)(ref ray)).direction) + 0.1f;
						float distance = 0f;
						V1Coin v1Coin = ((num > 0f) ? V1Coin.FindOnRay(ray, num, out distance) : null);
						if (Object.op_Implicit((Object)(object)v1Coin) && IsEnemyOf(((Component)val5).gameObject, v1Coin))
						{
							laserCoin = v1Coin;
							laserEnd = ((Ray)(ref ray)).GetPoint(distance);
							self.position = laserEnd;
						}
					}
					return orig.Invoke(self);
				};
				<>c.<>9__0_2 = val3;
				obj3 = (object)val3;
			}
			BlastAttack.Fire += (hook_Fire)obj3;
			object obj4 = <>c.<>9__0_3;
			if (obj4 == null)
			{
				hook_SpawnEffect_GameObject_EffectData_bool val4 = delegate(orig_SpawnEffect_GameObject_EffectData_bool orig, GameObject prefab, EffectData data, bool transmit)
				{
					//IL_0017: Unknown result type (might be due to invalid IL or missing references)
					if (laser != null && Object.op_Implicit((Object)(object)laserCoin) && data != null)
					{
						data.origin = laserEnd;
					}
					orig.Invoke(prefab, data, transmit);
				};
				<>c.<>9__0_3 = val4;
				obj4 = (object)val4;
			}
			EffectManager.SpawnEffect_GameObject_EffectData_bool += (hook_SpawnEffect_GameObject_EffectData_bool)obj4;
		}

		private static CharacterBody CoinOwner(V1Coin coin)
		{
			ProjectileController val = (Object.op_Implicit((Object)(object)coin) ? ((Component)coin).GetComponent<ProjectileController>() : null);
			if (!Object.op_Implicit((Object)(object)val) || !Object.op_Implicit((Object)(object)val.owner))
			{
				return null;
			}
			return val.owner.GetComponent<CharacterBody>();
		}

		private static bool IsEnemyOf(GameObject shooter, V1Coin coin)
		{
			//IL_003b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0046: Unknown result type (might be due to invalid IL or missing references)
			CharacterBody val = CoinOwner(coin);
			if (!Object.op_Implicit((Object)(object)val) || !Object.op_Implicit((Object)(object)((Component)val).GetComponent<V1Motor>()) || !Object.op_Implicit((Object)(object)val.teamComponent))
			{
				return false;
			}
			TeamComponent component = shooter.GetComponent<TeamComponent>();
			if (Object.op_Implicit((Object)(object)component))
			{
				return component.teamIndex != val.teamComponent.teamIndex;
			}
			return false;
		}

		private static void Reflect(V1Coin coin, GameObject shooterObject, float shotDamage)
		{
			//IL_001e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0023: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d0: 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_010c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0111: Unknown result type (might be due to invalid IL or missing references)
			//IL_0112: Unknown result type (might be due to invalid IL or missing references)
			//IL_0117: 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_0103: Unknown result type (might be due to invalid IL or missing references)
			//IL_009f: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a1: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a6: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ab: Unknown result type (might be due to invalid IL or missing references)
			//IL_00af: Unknown result type (might be due to invalid IL or missing references)
			//IL_0120: Unknown result type (might be due to invalid IL or missing references)
			//IL_0122: Unknown result type (might be due to invalid IL or missing references)
			//IL_0127: Unknown result type (might be due to invalid IL or missing references)
			//IL_0133: Unknown result type (might be due to invalid IL or missing references)
			//IL_013f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0140: Unknown result type (might be due to invalid IL or missing references)
			//IL_0141: Unknown result type (might be due to invalid IL or missing references)
			//IL_0146: Unknown result type (might be due to invalid IL or missing references)
			//IL_0147: Unknown result type (might be due to invalid IL or missing references)
			//IL_014e: 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_017a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0185: Unknown result type (might be due to invalid IL or missing references)
			//IL_0190: Unknown result type (might be due to invalid IL or missing references)
			//IL_0191: Unknown result type (might be due to invalid IL or missing references)
			//IL_0196: Unknown result type (might be due to invalid IL or missing references)
			//IL_019b: Unknown result type (might be due to invalid IL or missing references)
			//IL_019d: Unknown result type (might be due to invalid IL or missing references)
			//IL_01a2: Unknown result type (might be due to invalid IL or missing references)
			//IL_01ad: Unknown result type (might be due to invalid IL or missing references)
			//IL_01b8: Unknown result type (might be due to invalid IL or missing references)
			//IL_01c3: Unknown result type (might be due to invalid IL or missing references)
			//IL_01ce: Unknown result type (might be due to invalid IL or missing references)
			//IL_01d7: Expected O, but got Unknown
			//IL_01d9: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c4: Unknown result type (might be due to invalid IL or missing references)
			CharacterBody val = CoinOwner(coin);
			if (!Object.op_Implicit((Object)(object)val) || coin.consumed)
			{
				return;
			}
			Vector3 position = ((Component)coin).transform.position;
			coin.Consume(val);
			V1Sound.Play("Play_railgunner_m2_headshot", ((Component)coin).gameObject);
			V1Sound.Play("ROUK_CoinHitRing", ((Component)coin).gameObject);
			CharacterBody val2 = (Object.op_Implicit((Object)(object)shooterObject) ? shooterObject.GetComponent<CharacterBody>() : null);
			Vector3? val3 = null;
			if (Object.op_Implicit((Object)(object)val2) && Object.op_Implicit((Object)(object)val2.healthComponent) && val2.healthComponent.alive)
			{
				Vector3 corePosition = val2.corePosition;
				LayerIndex world = LayerIndex.world;
				if (!Physics.Linecast(position, corePosition, LayerMask.op_Implicit(((LayerIndex)(ref world)).mask), (QueryTriggerInteraction)1))
				{
					val3 = val2.corePosition;
					goto IL_00fa;
				}
			}
			HurtBox val4 = RevolverStates.FindTarget(position, val, 150f);
			if (Object.op_Implicit((Object)(object)val4))
			{
				val3 = ((Component)val4).transform.position;
			}
			goto IL_00fa;
			IL_00fa:
			Vector3 val5;
			if (!val3.HasValue)
			{
				val5 = Random.onUnitSphere;
			}
			else
			{
				Vector3 val6 = val3.Value - position;
				val5 = ((Vector3)(ref val6)).normalized;
			}
			Vector3 aimVector = val5;
			BulletAttack val7 = new BulletAttack
			{
				owner = ((Component)val).gameObject,
				weapon = ((Component)coin).gameObject,
				origin = position,
				aimVector = aimVector,
				damage = val.damage * 3f * 2f * V1Config.DamageScale.Value + shotDamage,
				isCrit = false,
				force = 400f,
				procCoefficient = 1f,
				damageType = DT.Primary,
				falloffModel = (FalloffModel)0,
				tracerEffectPrefab = V1Assets.tracerRevolver,
				hitEffectPrefab = V1Assets.hitsparkHeavy,
				maxDistance = 1000f,
				radius = 0.35f,
				smartCollision = true
			};
			DamageAPI.AddModdedDamageType(val7, ItemCompat.CoinShot);
			V1StyleServer.hitterOverride = "chargeback";
			try
			{
				val7.Fire();
			}
			finally
			{
				V1StyleServer.hitterOverride = null;
			}
		}
	}
	internal static class V1Arsenal
	{
		private class Loadout
		{
			public ulong owned;

			public int alternates;

			public int orders;
		}

		public const int LargeChestCost = 50;

		public const int LegendaryChestCost = 400;

		private static readonly Dictionary<NetworkInstanceId, Loadout> loadouts = new Dictionary<NetworkInstanceId, Loadout>();

		private static readonly int[][] permutations = new int[6][]
		{
			new int[3] { 0, 1, 2 },
			new int[3] { 0, 2, 1 },
			new int[3] { 1, 0, 2 },
			new int[3] { 1, 2, 0 },
			new int[3] { 2, 0, 1 },
			new int[3] { 2, 1, 0 }
		};

		public static bool enabled => V1Config.WeaponProgression.Value;

		private static ulong Starting => Bit(Find(WeaponType.Revolver, WeaponVariant.Blue));

		public static void Init()
		{
			Run.onRunStartGlobal += delegate
			{
				loadouts.Clear();
			};
			BossGroup.onBossGroupDefeatedServer += delegate
			{
				UnlockForAll();
			};
		}

		private static ulong Bit(WeaponDef w)
		{
			return (ulong)(1L << w.index);
		}

		public static WeaponDef Find(WeaponType type, WeaponVariant variant)
		{
			foreach (WeaponDef item in WeaponCatalog.all)
			{
				if (item.type == type && item.variant == variant)
				{
					return item;
				}
			}
			return null;
		}

		private static Loadout Of(CharacterMaster master)
		{
			//IL_0010: 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)
			if (!Object.op_Implicit((Object)(object)master))
			{
				return null;
			}
			if (!loadouts.TryGetValue(((NetworkBehaviour)master).netId, out var value))
			{
				Dictionary<NetworkInstanceId, Loadout> dictionary = loadouts;
				NetworkInstanceId netId = ((NetworkBehaviour)master).netId;
				Loadout obj = new Loadout
				{
					owned = Starting
				};
				value = obj;
				dictionary[netId] = obj;
			}
			return value;
		}

		public static bool Owns(CharacterMaster master, WeaponDef w)
		{
			if (!enabled || w == null)
			{
				return true;
			}
			Loadout loadout = Of(master);
			if (loadout == null)
			{
				return (Starting & Bit(w)) != 0;
			}
			return (loadout.owned & Bit(w)) != 0;
		}

		public static WeaponType? BaseOf(WeaponType t)
		{
			return t switch
			{
				WeaponType.SlabRevolver => WeaponType.Revolver, 
				WeaponType.Jackhammer => WeaponType.Shotgun, 
				WeaponType.SawbladeLauncher => WeaponType.Nailgun, 
				_ => null, 
			};
		}

		public static WeaponType? AlternateOf(WeaponType t)
		{
			return t switch
			{
				WeaponType.Revolver => WeaponType.SlabRevolver, 
				WeaponType.Shotgun => WeaponType.Jackhammer, 
				WeaponType.Nailgun => WeaponType.SawbladeLauncher, 
				_ => null, 
			};
		}

		public static WeaponType StandardOf(int slot)
		{
			return slot switch
			{
				0 => WeaponType.Revolver, 
				1 => WeaponType.Shotgun, 
				2 => WeaponType.Nailgun, 
				3 => WeaponType.Railcannon, 
				_ => WeaponType.RocketLauncher, 
			};
		}

		public static bool ForSale(WeaponDef w)
		{
			if (!BaseOf(w.type).HasValue)
			{
				return w.variant != WeaponVariant.Blue;
			}
			return true;
		}

		public static WeaponDef Prerequisite(WeaponDef w)
		{
			WeaponType weaponType = BaseOf(w.type) ?? w.type;
			if (w.type == weaponType && w.variant == WeaponVariant.Blue)
			{
				return null;
			}
			return Find(weaponType, WeaponVariant.Blue);
		}

		public static int PriceOf(WeaponDef w)
		{
			int num = ((w != null && w.type == WeaponType.Railcannon) ? 400 : 50);
			if (!Object.op_Implicit((Object)(object)Run.instance))
			{
				return num;
			}
			return Run.instance.GetDifficultyScaledCost(num);
		}

		public static bool AlternateEquipped(CharacterMaster master, int slot, WeaponVariant variant)
		{
			Loadout loadout = Of(master);
			if (loadout != null)
			{
				return (loadout.alternates & (1 << (int)(slot * 3 + variant))) != 0;
			}
			return false;
		}

		public static int[] Order(CharacterMaster master, int slot)
		{
			Loadout loadout = Of(master);
			int num = ((loadout != null) ? ((loadout.orders >> slot * 3) & 7) : 0);
			return permutations[(num < permutations.Length) ? num : 0];
		}

		public static void Slot(CharacterMaster master, int slot, List<WeaponDef> into)
		{
			into.Clear();
			WeaponType weaponType = StandardOf(slot);
			WeaponType? weaponType2 = AlternateOf(weaponType);
			int[] array = Order(master, slot);
			for (int i = 0; i < array.Length; i++)
			{
				WeaponVariant variant = (WeaponVariant)array[i];
				WeaponDef weaponDef = Find((weaponType2.HasValue && AlternateEquipped(master, slot, variant)) ? weaponType2.Value : weaponType, variant);
				if (weaponDef != null && Owns(master, weaponDef))
				{
					into.Add(weaponDef);
				}
			}
		}

		private static void Send(CharacterMaster master)
		{
			//IL_0012: Unknown result type (might be due to invalid IL or missing references)
			//IL_0017: Unknown result type (might be due to invalid IL or missing references)
			Loadout loadout = Of(master);
			NetMessages.Send((INetMessage)(object)new ClientArsenal
			{
				master = ((NetworkBehaviour)master).netId,
				mask = loadout.owned,
				alternates = loadout.alternates,
				orders = loadout.orders
			}, toServer: false);
		}

		public static void Sync(CharacterMaster master)
		{
			if (NetworkServer.active && Object.op_Implicit((Object)(object)master))
			{
				Send(master);
			}
		}

		public static bool TryEquip(CharacterMaster master, int slot, WeaponVariant variant, bool alternate)
		{
			if (!NetworkServer.active || !Object.op_Implicit((Object)(object)master) || slot < 0 || slot > 2)
			{
				return false;
			}
			WeaponType weaponType = StandardOf(slot);
			WeaponType? weaponType2 = (alternate ? AlternateOf(weaponType) : new WeaponType?(weaponType));
			if (!weaponType2.HasValue || !Owns(master, Find(weaponType2.Value, variant)))
			{
				return false;
			}
			Loadout loadout = Of(master);
			int num = 1 << (int)(slot * 3 + variant);
			loadout.alternates = (alternate ? (loadout.alternates | num) : (loadout.alternates & ~num));
			Send(master);
			return true;
		}

		public static bool TryMove(CharacterMaster master, int slot, WeaponVariant variant, int direction)
		{
			if (!NetworkServer.active || !Object.op_Implicit((Object)(object)master) || slot < 0 || slot > 4)
			{
				return false;
			}
			int[] array = (int[])Order(master, slot).Clone();
			int num = Array.IndexOf(array, (int)variant);
			int num2 = num + direction;
			if (num < 0 || num2 < 0 || num2 > 2)
			{
				return false;
			}
			ref int reference = ref array[num];
			ref int reference2 = ref array[num2];
			int num3 = array[num2];
			int num4 = array[num];
			reference = num3;
			reference2 = num4;
			int num5 = 0;
			for (int i = 0; i < permutations.Length; i++)
			{
				if (permutations[i][0] == array[0] && permutations[i][1] == array[1])
				{
					num5 = i;
					break;
				}
			}
			Loadout loadout = Of(master);
			loadout.orders = (loadout.orders & ~(7 << slot * 3)) | (num5 << slot * 3);
			Send(master);
			return true;
		}

		private static IEnumerable<CharacterMaster> V1Masters()
		{
			GameObject v1 = V1Content.bodyPrefab;
			if (!Object.op_Implicit((Object)(object)v1))
			{
				yield break;
			}
			foreach (PlayerCharacterMasterController instance in PlayerCharacterMasterController.instances)
			{
				CharacterMaster val = (Object.op_Implicit((Object)(object)instance) ? instance.master : null);
				if (Object.op_Implicit((Object)(object)val))
				{
					NetworkUser networkUser = instance.networkUser;
					if (IsV1(val.bodyPrefab, v1) || IsV1(val.originalBodyPrefab, v1) || (Object.op_Implicit((Object)(object)networkUser) && (int)networkUser.bodyIndexPreference != -1 && IsV1(BodyCatalog.GetBodyPrefab(networkUser.bodyIndexPreference), v1)))
					{
						yield return val;
					}
				}
			}
		}

		private static bool IsV1(GameObject prefab, GameObject v1)
		{
			if (Object.op_Implicit((Object)(object)prefab))
			{
				return ((Object)prefab).name == ((Object)v1).name;
			}
			return false;
		}

		public static void DebugUnlockForAll()
		{
			UnlockForAll();
		}

		private static void UnlockForAll()
		{
			//IL_00d8: Unknown result type (might be due to invalid IL or missing references)
			//IL_00df: Expected O, but got Unknown
			if (!enabled || !NetworkServer.active)
			{
				return;
			}
			foreach (CharacterMaster item in V1Masters())
			{
				Loadout loadout = Of(item);
				List<WeaponDef> list = new List<WeaponDef>();
				WeaponType[] array = new WeaponType[4]
				{
					WeaponType.Shotgun,
					WeaponType.Nailgun,
					WeaponType.Railcannon,
					WeaponType.RocketLauncher
				};
				for (int i = 0; i < array.Length; i++)
				{
					WeaponDef weaponDef = Find(array[i], WeaponVariant.Blue);
					if (weaponDef != null && (loadout.owned & Bit(weaponDef)) == 0L)
					{
						list.Add(weaponDef);
					}
				}
				if (list.Count != 0)
				{
					WeaponDef weaponDef2 = list[Random.Range(0, list.Count)];
					loadout.owned |= Bit(weaponDef2);
					Send(item);
					NetworkUser val = (Object.op_Implicit((Object)(object)item.playerCharacterMasterController) ? item.playerCharacterMasterController.networkUser : null);
					SimpleChatMessage val2 = new SimpleChatMessage();
					val2.baseToken = "<color=#40e7ff>{0}</color> unlocked the <color=#40e7ff>{1}</color>!";
					val2.paramTokens = new string[2]
					{
						Object.op_Implicit((Object)(object)val) ? val.userName : "V1",
						weaponDef2.name
					};
					Chat.SendBroadcastChat((ChatMessageBase)(object)val2);
				}
			}
		}

		public static string WeaponFamilyName(WeaponType t)
		{
			return t switch
			{
				WeaponType.Revolver => "Revolver", 
				WeaponType.SlabRevolver => "Slab Revolver", 
				WeaponType.Shotgun => "Shotgun", 
				WeaponType.Jackhammer => "Jackhammer", 
				WeaponType.Nailgun => "Nailgun", 
				WeaponType.SawbladeLauncher => "Sawblade Launcher", 
				WeaponType.Railcannon => "Railcannon", 
				_ => "Rocket Launcher", 
			};
		}

		public static bool TryBuy(CharacterMaster master, WeaponDef w)
		{
			if (!NetworkServer.active || !enabled || !Object.op_Implicit((Object)(object)master) || w == null || !ForSale(w))
			{
				return false;
			}
			Loadout loadout = Of(master);
			if ((loadout.owned & Bit(w)) != 0L)
			{
				return false;
			}
			WeaponDef weaponDef = Prerequisite(w);
			if (weaponDef != null && (loadout.owned & Bit(weaponDef)) == 0L)
			{
				return false;
			}
			uint num = (uint)PriceOf(w);
			if (master.money < num)
			{
				return false;
			}
			master.money -= num;
			loadout.owned |= Bit(w);
			Send(master);
			return true;
		}

		public static void Received(NetworkInstanceId master, ulong mask, int alternates, int orders)
		{
			//IL_0005: Unknown result type (might be due to invalid IL or missing references)
			loadouts[master] = new Loadout
			{
				owned = mask,
				alternates = alternates,
				orders = orders
			};
		}
	}
	public abstract class V1DynamicSkillDef : SkillDef
	{
		protected static V1WeaponController Ctrl(GenericSkill slot)
		{
			if (!Object.op_Implicit((Object)(object)slot) || !Object.op_Implicit((Object)(object)slot.characterBody))
			{
				return null;
			}
			return ((Component)slot.characterBody).GetComponent<V1WeaponController>();
		}

		protected static void ShowPool(GenericSkill slot, V1WeaponController ctrl, WeaponCharges.Pool? pool, float? cost = null)
		{
			if (!pool.HasValue)
			{
				slot.stock = slot.maxStock;
				slot.rechargeStopwatch = 0f;
				return;
			}
			WeaponCharges.Pool value = pool.Value;
			WeaponCharges charges = ctrl.charges;
			float num = cost ?? charges.Unit(value);
			int num2 = (slot.stock = Mathf.Min(Mathf.FloorToInt((charges.Value(value) + 0.0001f) / num), slot.maxStock));
			slot.rechargeStopwatch = ((num2 >= slot.maxStock) ? 0f : (Mathf.Repeat(charges.Value(value), num) / num * slot.CalculateFinalRechargeInterval()));
		}
	}
	public class V1WeaponSkillDef : V1DynamicSkillDef
	{
		private WeaponDef Resolve(GenericSkill slot)
		{
			return V1DynamicSkillDef.Ctrl(slot)?.active;
		}

		public override Sprite GetCurrentIcon(GenericSkill skillSlot)
		{
			return Resolve(skillSlot)?.icon ?? ((SkillDef)this).icon;
		}

		public override string GetCurrentNameToken(GenericSkill skillSlot)
		{
			return Resolve(skillSlot)?.nameToken ?? ((SkillDef)this).skillNameToken;
		}

		public override string GetCurrentDescriptionToken(GenericSkill skillSlot)
		{
			return Resolve(skillSlot)?.descToken ?? ((SkillDef)this).skillDescriptionToken;
		}

		public override bool IsReady(GenericSkill skillSlot)
		{
			V1WeaponController v1WeaponController = V1DynamicSkillDef.Ctrl(skillSlot);
			WeaponDef weaponDef = Resolve(skillSlot);
			bool flag = Object.op_Implicit((Object)(object)v1WeaponController) && (v1WeaponController.gunReady || (weaponDef != null && weaponDef.type == WeaponType.Jackhammer));
			if (!Object.op_Implicit((Object)(object)v1WeaponController))
			{
				return true;
			}
			if (flag)
			{
				return v1WeaponController.CanFirePrimary(weaponDef);
			}
			return false;
		}

		public override bool CanExecute(GenericSkill skillSlot)
		{
			//IL_002a: Unknown result type (might be due to invalid IL or missing references)
			if (((SkillDef)this).IsReady(skillSlot) && Object.op_Implicit((Object)(object)skillSlot.stateMachine) && !skillSlot.stateMachine.HasPendingState())
			{
				return skillSlot.stateMachine.CanInterruptState(((SkillDef)this).interruptPriority);
			}
			return false;
		}

		protected override EntityState InstantiateNextState(GenericSkill skillSlot)
		{
			//IL_0023: Unknown result type (might be due to invalid IL or missing references)
			object obj = ((object)Resolve(skillSlot)?.primaryState?.Invoke()) ?? ((object)new Idle());
			ISkillState val = (ISkillState)((obj is ISkillState) ? obj : null);
			if (val != null)
			{
				val.activatorSkillSlot = skillSlot;
			}
			return (EntityState)obj;
		}

		public override void OnExecute(GenericSkill skillSlot)
		{
			//IL_000e: Unknown result type (might be due to invalid IL or missing references)
			skillSlot.stateMachine.SetInterruptState(((SkillDef)this).InstantiateNextState(skillSlot), ((SkillDef)this).interruptPriority);
			if (Object.op_Implicit((Object)(object)skillSlot.characterBody))
			{
				skillSlot.characterBody.OnSkillActivated(skillSlot);
			}
		}

		public override int GetMaxStock(GenericSkill skillSlot)
		{
			V1WeaponController v1WeaponController = V1DynamicSkillDef.Ctrl(skillSlot);
			WeaponDef weaponDef = Resolve(skillSlot);
			if (Object.op_Implicit((Object)(object)v1WeaponController) && weaponDef != null && weaponDef.primaryPool.HasValue)
			{
				return v1WeaponController.charges.MaxStock(weaponDef.primaryPool.Value);
			}
			return 1;
		}

		public override float GetRechargeInterval(GenericSkill skillSlot)
		{
			V1WeaponController v1WeaponController = V1DynamicSkillDef.Ctrl(skillSlot);
			WeaponDef weaponDef = Resolve(skillSlot);
			if (Object.op_Implicit((Object)(object)v1WeaponController) && weaponDef != null && weaponDef.primaryPool.HasValue)
			{
				return v1WeaponController.charges.SecondsPerUnit(weaponDef.primaryPool.Value);
			}
			return 0f;
		}

		public override void OnFixedUpdate(GenericSkill skillSlot, float deltaTime)
		{
			V1WeaponController v1WeaponController = V1DynamicSkillDef.Ctrl(skillSlot);
			if (Object.op_Implicit((Object)(object)v1WeaponController) && !((Object)(object)skillSlot != (Object)(object)v1WeaponController.skillLocator.primary))
			{
				WeaponDef weaponDef = Resolve(skillSlot);
				if (skillSlot.maxStock != ((SkillDef)this).GetMaxStock(skillSlot))
				{
					skillSlot.RecalculateValues();
				}
				V1DynamicSkillDef.ShowPool(skillSlot, v1WeaponController, weaponDef?.primaryPool);
			}
		}
	}
	public class V1AltFireSkillDef : V1DynamicSkillDef
	{
		public static bool AltWaitsForGun(WeaponDef w)
		{
			if (w == null)
			{
				return true;
			}
			switch (w.type)
			{
			case WeaponType.Shotgun:
				return w.variant != WeaponVariant.Blue;
			case WeaponType.Jackhammer:
				return true;
			case WeaponType.Revolver:
			case WeaponType.SlabRevolver:
				return w.variant != WeaponVariant.Green;
			default:
				return false;
			}
		}

		private static WeaponDef Active(GenericSkill slot)
		{
			return V1DynamicSkillDef.Ctrl(slot)?.active;
		}

		public override Sprite GetCurrentIcon(GenericSkill skillSlot)
		{
			return Active(skillSlot)?.altIcon ?? ((SkillDef)this).icon;
		}

		public override string GetCurrentNameToken(GenericSkill skillSlot)
		{
			return Active(skillSlot)?.altNameToken ?? ((SkillDef)this).skillNameToken;
		}

		public override string GetCurrentDescriptionToken(GenericSkill skillSlot)
		{
			return Active(skillSlot)?.altDescToken ?? ((SkillDef)this).skillDescriptionToken;
		}

		public override bool IsReady(GenericSkill skillSlot)
		{
			V1WeaponController v1WeaponController = V1DynamicSkillDef.Ctrl(skillSlot);
			if (Object.op_Implicit((Object)(object)v1WeaponController) && (v1WeaponController.gunReady || !AltWaitsForGun(v1WeaponController.active)))
			{
				return v1WeaponController.CanFireAlt(v1WeaponController.active);
			}
			return false;
		}

		public override bool CanExecute(GenericSkill skillSlot)
		{
			//IL_002a: Unknown result type (might be due to invalid IL or missing references)
			if (((SkillDef)this).IsReady(skillSlot) && Object.op_Implicit((Object)(object)skillSlot.stateMachine) && !skillSlot.stateMachine.HasPendingState())
			{
				return skillSlot.stateMachine.CanInterruptState(((SkillDef)this).interruptPriority);
			}
			return false;
		}

		protected override EntityState InstantiateNextState(GenericSkill skillSlot)
		{
			//IL_0022: Unknown result type (might be due to invalid IL or missing references)
			object obj = ((object)Active(skillSlot)?.altState?.Invoke()) ?? ((object)new Idle());
			ISkillState val = (ISkillState)((obj is ISkillState) ? obj : null);
			if (val != null)
			{
				val.activatorSkillSlot = skillSlot;
			}
			return (EntityState)obj;
		}

		public override void OnExecute(GenericSkill skillSlot)
		{
			//IL_000e: Unknown result type (might be due to invalid IL or missing references)
			skillSlot.stateMachine.SetInterruptState(((SkillDef)this).InstantiateNextState(skillSlot), ((SkillDef)this).interruptPriority);
			if (Object.op_Implicit((Object)(object)skillSlot.characterBody))
			{
				skillSlot.characterBody.OnSkillActivated(skillSlot);
			}
		}

		public override int GetMaxStock(GenericSkill skillSlot)
		{
			V1WeaponController v1WeaponController = V1DynamicSkillDef.Ctrl(skillSlot);
			WeaponDef weaponDef = (Object.op_Implicit((Object)(object)v1WeaponController) ? v1WeaponController.active : null);
			if (weaponDef != null && weaponDef.altPool.HasValue)
			{
				if (weaponDef.altCost.HasValue)
				{
					return Mathf.Max(1, Mathf.FloorToInt(v1WeaponController.charges.Max(weaponDef.altPool.Value) / weaponDef.altCost.Value + 0.0001f) - v1WeaponController.charges.bonusAltStock);
				}
				return v1WeaponController.charges.MaxStock(weaponDef.altPool.Value) - v1WeaponController.charges.bonusAltStock;
			}
			return 1;
		}

		public override float GetRechargeInterval(GenericSkill skillSlot)
		{
			V1WeaponController v1WeaponController = V1DynamicSkillDef.Ctrl(skillSlot);
			WeaponDef weaponDef = (Object.op_Implicit((Object)(object)v1WeaponController) ? v1WeaponController.active : null);
			if (weaponDef != null && weaponDef.altPool.HasValue)
			{
				return v1WeaponController.charges.SecondsPerUnit(weaponDef.altPool.Value) * (weaponDef.altCost.HasValue ? (weaponDef.altCost.Value / v1WeaponController.charges.Unit(weaponDef.altPool.Value)) : 1f) * Mathf.Max(skillSlot.cooldownScale, 0.05f);
			}
			return 0f;
		}

		public override void OnFixedUpdate(GenericSkill skillSlot, float deltaTime)
		{
			V1WeaponController v1WeaponController = V1DynamicSkillDef.Ctrl(skillSlot);
			if (Object.op_Implicit((Object)(object)v1WeaponController))
			{
				if (skillSlot.maxStock != ((SkillDef)this).GetMaxStock(skillSlot) + skillSlot.bonusStockFromBody)
				{
					skillSlot.RecalculateValues();
				}
				V1DynamicSkillDef.ShowPool(skillSlot, v1WeaponController, v1WeaponController.active?.altPool, v1WeaponController.active?.altCost);
			}
		}
	}
	public class V1DashSkillDef : SkillDef
	{
		private static V1Motor Motor(GenericSkill slot)
		{
			if (!Object.op_Implicit((Object)(object)slot) || !Object.op_Implicit((Object)(object)slot.characterBody))
			{
				return null;
			}
			return ((Component)slot.characterBody).GetComponent<V1Motor>();
		}

		public override bool IsReady(GenericSkill skillSlot)
		{
			V1Motor v1Motor = Motor(skillSlot);
			if (Object.op_Implicit((Object)(object)v1Motor))
			{
				return v1Motor.CanDash;
			}
			return false;
		}

		public override bool CanExecute(GenericSkill skillSlot)
		{
			if (((SkillDef)this).IsReady(skillSlot) && Object.op_Implicit((Object)(object)skillSlot.stateMachine))
			{
				return !skillSlot.stateMachine.HasPendingState();
			}
			return false;
		}

		public override float GetRechargeInterval(GenericSkill skillSlot)
		{
			return 1.4285715f;
		}

		public override void OnFixedUpdate(GenericSkill skillSlot, float deltaTime)
		{
			V1Motor v1Motor = Motor(skillSlot);
			if (Object.op_Implicit((Object)(object)v1Motor))
			{
				v1Motor.staminaMax = 100f * (float)skillSlot.maxStock;
				v1Motor.staminaRegenMultiplier = 1f / Mathf.Max(skillSlot.cooldownScale, 0.05f);
				int num = (skillSlot.stock = Mathf.Min(Mathf.FloorToInt(v1Motor.stamina / 100f + 0.001f), skillSlot.maxStock));
				float num3 = Mathf.Repeat(v1Motor.stamina, 100f) / 100f;
				skillSlot.rechargeStopwatch = ((num >= skillSlot.maxStock) ? 0f : (num3 * skillSlot.CalculateFinalRechargeInterval()));
			}
		}
	}
	public class V1WeaponController : MonoBehaviour
	{
		public readonly WeaponCharges charges = new WeaponCharges();

		private readonly int[] variantInSlot = new int[5];

		[NonSerialized]
		public int pumpCount;

		[NonSerialized]
		public bool rocketsFrozen;

		[NonSerialized]
		public float overheatTimer;

		[NonSerialized]
		public float zoomAmount;

		[NonSerialized]
		public float altCharge;

		[NonSerialized]
		public bool hammerCharging;

		[NonSerialized]
		public bool sawCharging;

		[NonSerialized]
		public bool napalmSpraying;

		private float nextWarningBeep;

		[NonSerialized]
		public int hammerTier;

		[NonSerialized]
		public float lastShotgunTime = -10f;

		[NonSerialized]
		public int lastShotgunPumps;

		[NonSerialized]
		public float readyAt;

		[NonSerialized]
		public float hammerSpeed;

		[NonSerialized]
		public float hammerSwing;

		[NonSerialized]
		public float hammerOverheat;

		[NonSerialized]
		public int hammerYellows;

		[NonSerialized]
		public float hammerYellowTimer;

		[NonSerialized]
		public float hammerCooldownUntil;

		private float hammerTierDownTime;

		private readonly Dictionary<WeaponDef, float> nailHeats = new Dictionary<WeaponDef, float>();

		private readonly List<WeaponDef> heatKeys = new List<WeaponDef>();

		[NonSerialized]
		public bool nailBurnout;

		[NonSerialized]
		public float nailFireCooldown;

		[NonSerialized]
		public bool nailFiring;

		[NonSerialized]
		public bool zapperAttached;

		[NonSerialized]
		public float zapperCharge;

		[NonSerialized]
		public WeaponDef debugWeapon;

		private readonly List<WeaponDef> ownedBuffer = new List<WeaponDef>();

		[NonSerialized]
		public bool inShop;

		private WeaponDef lastSent;

		public CharacterBody body { get; private set; }

		public SkillLocator skillLocator { get; private set; }

		public int slot { get; private set; }

		public int remoteWeaponIndex { get; private set; } = -1;

		public bool gunReady => Time.time >= readyAt;

		public int hammerMeterTier { get; private set; }

		public float nailHeat
		{
			get
			{
				WeaponDef weaponDef = active;
				if (weaponDef == null || !nailHeats.TryGetValue(weaponDef, out var value))
				{
					return 0f;
				}
				return value;
			}
			set
			{
				WeaponDef weaponDef = active;
				if (weaponDef != null)
				{
					nailHeats[weaponDef] = value;
				}
			}
		}

		public WeaponDef active
		{
			get
			{
				if (debugWeapon != null)
				{
					return debugWeapon;
				}
				List<WeaponDef> list = Owned(slot);
				if (list.Count <= 0)
				{
					return null;
				}
				return list[variantInSlot[slot] % list.Count];
			}
		}

		public WeaponDef visibleWeapon
		{
			get
			{
				if (!hasAuthority && remoteWeaponIndex >= 0)
				{
					return WeaponCatalog.Get(remoteWeaponIndex);
				}
				return active;
			}
		}

		public bool hasAuthority
		{
			get
			{
				if (Object.op_Implicit((Object)(object)body))
				{
					return body.hasEffectiveAuthority;
				}
				return false;
			}
		}

		public event Action<WeaponDef> onWeaponChanged;

		public event Action<WeaponDef> onPrimaryFired;

		public event Action<WeaponDef> onAltFired;

		public event Action onShopTap;

		public void Delay(float seconds)
		{
			readyAt = Mathf.Max(readyAt, Time.time + seconds);
		}

		public List<WeaponDef> Owned(int s)
		{
			ownedBuffer.Clear();
			V1Arsenal.Slot(Object.op_Implicit((Object)(object)body) ? body.master : null, s, ownedBuffer);
			return ownedBuffer;
		}

		private void Awake()
		{
			body = ((Component)this).GetComponent<CharacterBody>();
			skillLocator = ((Component)this).GetComponent<SkillLocator>();
			charges.onRestock += delegate(WeaponCharges.Pool pool, int units, float seconds)
			{
				if (hasAuthority)
				{
					ItemCompat.SkillRecharged(body, seconds, units);
				}
			};
		}

		private void Start()
		{
			if (NetworkServer.active && Object.op_Implicit((Object)(object)body))
			{
				V1Arsenal.Sync(body.master);
			}
		}

		private void FixedUpdate()
		{
			//IL_0205: Unknown result type (might be due to invalid IL or missing references)
			//IL_020a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0279: Unknown result type (might be due to invalid IL or missing references)
			//IL_0267: Unknown result type (might be due to invalid IL or missing references)
			//IL_027e: Unknown result type (might be due to invalid IL or missing references)
			if (!Object.op_Implicit((Object)(object)body))
			{
				return;
			}
			float num = ((Object.op_Implicit((Object)(object)skillLocator) && Object.op_Implicit((Object)(object)skillLocator.secondary)) ? Mathf.Max(skillLocator.secondary.cooldownScale, 0.05f) : 1f);
			charges.regenMultiplier = 1f / num;
			charges.bonusAltStock = ((Object.op_Implicit((Object)(object)skillLocator) && Object.op_Implicit((Object)(object)skillLocator.secondary)) ? skillLocator.secondary.bonusStockFromBody : 0);
			bool flag = charges.HasUnit(WeaponCharges.Pool.Railcannon);
			charges.Tick(Time.fixedDeltaTime);
			if (hasAuthority && !flag && charges.HasUnit(WeaponCharges.Pool.Railcannon))
			{
				V1Sound.Play("Play_railgunner_R_gun_ready", ((Component)this).gameObject);
			}
			if (overheatTimer > 0f)
			{
				overheatTimer -= Time.fixedDeltaTime;
			}
			if (hammerOverheat > 0f)
			{
				hammerOverheat = Mathf.Max(0f, hammerOverheat - Time.fixedDeltaTime);
			}
			if (hammerYellowTimer > 0f)
			{
				hammerYellowTimer -= Time.fixedDeltaTime;
				if (hammerYellowTimer <= 0f)
				{
					hammerYellows = 0;
				}
			}
			if (nailFireCooldown > 0f)
			{
				nailFireCooldown = Mathf.Max(0f, nailFireCooldown - Time.fixedDeltaTime);
			}
			TickNailHeat(Time.fixedDeltaTime);
			if (rocketsFrozen && hasAuthority)
			{
				charges.Drain(WeaponCharges.Pool.Freeze, Time.fixedDeltaTime);
				charges.BlockRegen(WeaponCharges.Pool.Freeze, 0.1f);
				if (!charges.Has(WeaponCharges.Pool.Freeze, 0.01f))
				{
					rocketsFrozen = false;
					NetMessages.Send((INetMessage)(object)new ServerFreezeRockets
					{
						owner = body.networkIdentity.netId,
						frozen = false
					});
				}
			}
			if (hasAuthority && active != lastSent)
			{
				lastSent = active;
				NetMessages.Send((INetMessage)(object)new SyncWeaponVisual
				{
					body = (Object.op_Implicit((Object)(object)body.networkIdentity) ? body.networkIdentity.netId : NetworkInstanceId.Invalid),
					weaponIndex = ((active != null) ? active.index : (-1))
				});
				this.onWeaponChanged?.Invoke(active);
			}
		}

		private void Update()
		{
			//IL_0052: Unknown result type (might be due to invalid IL or missing references)
			if (!Object.op_Implicit((Object)(object)body))
			{
				return;
			}
			if (hasAuthority && V1Config.ScrollWheelWeapons.Value && !PauseManager.isPaused && !inShop)
			{
				LocalUser firstLocalUser = LocalUserManager.GetFirstLocalUser();
				float num = ((firstLocalUser != null && !firstLocalUser.isUIFocused) ? Input.mouseScrollDelta.y : 0f);
				if (num != 0f)
				{
					Cycle((!(num > 0f)) ? (V1Config.ScrollWheelReverse.Value ? 1 : (-1)) : ((!V1Config.ScrollWheelReverse.Value) ? 1 : (-1)));
					V1Sound.Play("Play_railgunner_R_gun_swap", ((Component)this).gameObject);
				}
			}
			float num2 = (Object.op_Implicit((Object)(object)body.characterMotor) ? Mathf.Min(((Vector3)(ref body.characterMotor.velocity)).magnitude / (60f * V1Motor.Scale), 1f) : 0f);
			hammerSpeed = ((hammerOverheat > 0f) ? 0f : Mathf.MoveTowards(hammerSpeed, num2, Time.deltaTime * 2f));
			int num3 = ((hammerSpeed > 0.66f) ? 2 : ((hammerSpeed > 0.33f) ? 1 : 0));
			if (num3 < hammerMeterTier && Time.time - hammerTierDownTime <= 0.5f)
			{
				num3 = hammerMeterTier;
			}
			else if (num3 >= hammerMeterTier)
			{
				hammerTierDownTime = Time.time;
			}
			hammerMeterTier = num3;
			WeaponDef weaponDef = active;
			if (hasAuthority && pumpCount >= 3 && weaponDef != null && weaponDef.variant == WeaponVariant.Green && (weaponDef.type == WeaponType.Shotgun || weaponDef.type == WeaponType.Jackhammer) && Time.time >= nextWarningBeep)
			{
				nextWarningBeep = Time.time + 0.2f;
				V1Sound.Play("ROUK_WarningBeep", ((Component)this).gameObject);
			}
		}

		private void TickNailHeat(float dt)
		{
			WeaponDef weaponDef = active;
			bool flag = weaponDef != null && (weaponDef.type == WeaponType.Nailgun || weaponDef.type == WeaponType.SawbladeLauncher);
			bool flag2 = weaponDef != null && weaponDef.type == WeaponType.SawbladeLauncher;
			if (nailBurnout)
			{
				nailHeat = Mathf.MoveTowards(nailHeat, 0f, dt);
				if (nailHeat <= 0f)
				{
					nailBurnout = false;
				}
			}
			else if (flag && nailFiring && gunReady)
			{
				if (weaponDef.variant == WeaponVariant.Red)
				{
					nailHeat = (zapperAttached ? 1f : 0.33f);
				}
				else if (weaponDef.variant == WeaponVariant.Blue)
				{
					nailHeat = 1f;
				}
				else if (!flag2)
				{
					nailHeat = Mathf.MoveTowards(nailHeat, 1f, dt * 0.55f);
				}
			}
			else if (nailHeat > 0f)
			{
				nailHeat = Mathf.MoveTowards(nailHeat, 0f, dt * ((!flag2) ? 0.3f : ((nailFireCooldown <= 0f) ? 0.2f : 0.03f)));
			}
			heatKeys.Clear();
			heatKeys.AddRange(nailHeats.Keys);
			foreach (WeaponDef heatKey in heatKeys)
			{
				if (heatKey != weaponDef && nailHeats[heatKey] > 0f)
				{
					nailHeats[heatKey] = Mathf.MoveTowards(nailHeats[heatKey], 0f, dt * ((heatKey.type == WeaponType.SawbladeLauncher) ? 0.2f : 0.3f));
				}
			}
		}

		public void SelectSlot(int newSlot)
		{
			if (newSlot < 0 || newSlot >= WeaponCatalog.slots.Length)
			{
				return;
			}
			int count = Owned(newSlot).Count;
			if (count == 0)
			{
				return;
			}
			if (newSlot == slot)
			{
				if (count < 2)
				{
					return;
				}
				variantInSlot[slot] = (variantInSlot[slot] + 1) % count;
			}
			else
			{
				slot = newSlot;
				variantInSlot[slot] = 0;
			}
			OnSwitched();
		}

		public void Cycle(int direction)
		{
			List<(int, int)> list = new List<(int, int)>();
			for (int i = 0; i < WeaponCatalog.slots.Length; i++)
			{
				int count = Owned(i).Count;
				for (int j = 0; j < count; j++)
				{
					list.Add((i, j));
				}
			}
			if (list.Count >= 2)
			{
				int count2 = Owned(slot).Count;
				int num = list.IndexOf((slot, (count2 > 0) ? (variantInSlot[slot] % count2) : 0));
				(int, int) tuple = list[(((num >= 0) ? num : 0) + direction + list.Count) % list.Count];
				(slot, _) = tuple;
				variantInSlot[slot] = tuple.Item2;
				OnSwitched();
			}
		}

		private void OnSwitched()
		{
			pumpCount = 0;
			hammerSwing = 0f;
			readyAt = Time.time + WeaponTiming.Equip(active);
			zoomAmount = 0f;
			EntityStateMachine val = EntityStateMachine.FindByCustomName(((Component)this).gameObject, "Weapon");
			if (Object.op_Implicit((Object)(object)val))
			{
				val.SetNextStateToMain();
			}
			EntityStateMachine val2 = EntityStateMachine.FindByCustomName(((Component)this).gameObject, "WeaponAlt");
			if (Object.op_Implicit((Object)(object)val2))
			{
				val2.SetNextStateToMain();
			}
			if (Object.op_Implicit((Object)(object)skillLocator))
			{
				GenericSkill primary = skillLocator.primary;
				if (primary != null)
				{
					primary.RecalculateValues();
				}
				GenericSkill secondary = skillLocator.secondary;
				if (secondary != null)
				{
					secondary.RecalculateValues();
				}
			}
		}

		public void OnRemoteWeaponChanged(int index)
		{
			if (!hasAuthority)
			{
				remoteWeaponIndex = index;
				this.onWeaponChanged?.Invoke(WeaponCatalog.Get(index));
			}
		}

		public void NotifyPrimaryFired()
		{
			this.onPrimaryFired?.Invoke(active);
		}

		public void NotifyAltFired()
		{
			this.onAltFired?.Invoke(active);
		}

		public void NotifyShopTap()
		{
			this.onShopTap?.Invoke();
		}

		public bool CanFirePrimary(WeaponDef w)
		{
			if (w == null || inShop)
			{
				return false;
			}
			if (w.type == WeaponType.Jackhammer && hammerOverheat > 0f)
			{
				return false;
			}
			if (w.type == WeaponType.Nailgun || w.type == WeaponType.SawbladeLauncher)
			{
				return true;
			}
			if (w.primaryPool.HasValue)
			{
				return charges.HasUnit(w.primaryPool.Value);
			}
			return true;
		}

		public bool CanFireAlt(WeaponDef w)
		{
			if (inShop)
			{
				return false;
			}
			if (w == null)
			{
				return false;
			}
			if (w.type == WeaponType.RocketLauncher && w.variant == WeaponVariant.Blue && rocketsFrozen)
			{
				return true;
			}
			if (w.altPool.HasValue)
			{
				if (!w.altCost.HasValue)
				{
					return charges.HasUnit(w.altPool.Value);
				}
				return charges.Has(w.altPool.Value, w.altCost.Value);
			}
			return true;
		}
	}
	public enum WeaponType
	{
		Revolver,
		SlabRevolver,
		Shotgun,
		Jackhammer,
		Nailgun,
		SawbladeLauncher,
		Railcannon,
		RocketLauncher
	}
	public enum WeaponVariant
	{
		Blue,
		Green,
		Red
	}
	public class WeaponDef
	{
		public int index;

		public string id;

		public WeaponType type;

		public WeaponVariant variant;

		public string name;

		public string description;

		public string altName;

		public string altDescription;

		public Func<EntityState> primaryState;

		public Func<EntityState> altState;

		public WeaponCharges.Pool? altPool;

		public WeaponCharges.Pool? primaryPool;

		public float? altCost;

		public Sprite icon;

		public Sprite altIcon;

		public string nameToken => "ROUK_WEAPON_" + id.ToUpperInvariant() + "_NAME";

		public string descToken => "ROUK_WEAPON_" + id.ToUpperInvariant() + "_DESC";

		public string altNameToken => "ROUK_WEAPON_" + id.ToUpperInvariant() + "_ALT_NAME";

		public string altDescToken => "ROUK_WEAPON_" + id.ToUpperInvariant() + "_ALT_DESC";

		public Color color => V1WeaponScreens.variantColors[(int)variant];
	}
	public static class WeaponCatalog
	{
		public static readonly List<WeaponDef> all = new List<WeaponDef>();

		public static readonly List<WeaponDef>[] slots = new List<WeaponDef>[5]
		{
			new List<WeaponDef>(),
			new List<WeaponDef>(),
			new List<WeaponDef>(),
			new List<WeaponDef>(),
			new List<WeaponDef>()
		};

		public static WeaponDef Get(int index)
		{
			if (index < 0 || index >= all.Count)
			{
				return null;
			}
			return all[index];
		}

		public static int SlotOf(WeaponType t)
		{
			switch (t)
			{
			case WeaponType.Revolver:
			case WeaponType.SlabRevolver:
				return 0;
			case WeaponType.Shotgun:
			case WeaponType.Jackhammer:
				return 1;
			case WeaponType.Nailgun:
			case WeaponType.SawbladeLauncher:
				return 2;
			case WeaponType.Railcannon:
				return 3;
			default:
				return 4;
			}
		}

		private static void Add(WeaponDef def)
		{
			def.index = all.Count;
			all.Add(def);
			slots[SlotOf(def.type)].Add(def);
		}

		public static void Init()
		{
			if (all.Count <= 0)
			{
				Add(new WeaponDef
				{
					id = "RevolverPiercer",
					type = WeaponType.Revolver,
					variant = WeaponVariant.Blue,
					name = "Piercer Revolver",
					description = $"Fire a precise hitscan shot for <style=cIsDamage>{300f}% damage</style>.",
					altName = "Piercing Shot",
					altDescription = "Hold to charge, release to fire a beam that <style=cIsDamage>pierces</style> up to 3 enemies for <style=cIsDamage>" + 600f + "% damage</style>.",
					primaryState = () => (EntityState)(object)new RevolverStates.Fire(),
					altState = () => (EntityState)(object)new RevolverStates.ChargePierce(),
					altPool = WeaponCharges.Pool.Piercer
				});
				Add(new WeaponDef
				{
					id = "RevolverMarksman",
					type = WeaponType.Revolver,
					variant = WeaponVariant.Green,
					name = "Marksman Revolver",
					description = $"Fire a precise hitscan shot for <style=cIsDamage>{300f}% damage</style>.",
					altName = "Coin Toss",
					altDescription = "Toss a coin. <style=cIsUtility>Shoot it</style> to ricochet the shot into the nearest enemy for <style=cIsDamage>+50% damage per coin</style>.",
					primaryState = () => (EntityState)(object)new RevolverStates.Fire(),
					altState = () => (EntityState)(object)new RevolverStates.ThrowCoin(),
					altPool = WeaponCharges.Pool.Coins
				});
				Add(new WeaponDef
				{
					id = "RevolverSharpshooter",
					type = WeaponType.Revolver,
					variant = WeaponVariant.Red,
					name = "Sharpshooter Revolver",
					description = $"Fire a precise hitscan shot for <style=cIsDamage>{300f}% damage</style>.",
					altName = "Spin Shot",
					altDescription = $"Hold to spin, release to fire a beam that <style=cIsDamage>ricochets</style> up to 3 times, homing on enemies, for <style=cIsDamage>{450f}% damage</style>.",
					primaryState = () => (EntityState)(object)new RevolverStates.Fire(),
					altState = () => (EntityState)(object)new RevolverStates.ChargeSharp(),
					altPool = WeaponCharges.Pool.Sharpshooter
				});
				Add(new WeaponDef
				{
					id = "SlabPiercer",
					type = WeaponType.SlabRevolver,
					variant = WeaponVariant.Blue,
					name = "Piercer Slab Revolver",
					description = $"Fire a slow, heavy shot for <style=cIsDamage>{450f}% damage</style> that <style=cIsDamage>pierces</style> one enemy.",
					altName = "Piercing Shot",
					altDescription = "Hold to charge, release to fire a huge beam that <style=cIsDamage>pierces</style> up to 6 enemies for <style=cIsDamage>" + 1000f + "% damage</style>.",
					primaryState = () => (EntityState)(object)new RevolverStates.Fire
					{
						slab = true
					},
					altState = () => (EntityState)(object)new RevolverStates.ChargePierce
					{
						slab = true
					},
					altPool = WeaponCharges.Pool.Piercer
				});
				Add(new WeaponDef
				{
					id = "SlabMarksman",
					type = WeaponType.SlabRevolver,
					variant = WeaponVariant.Green,
					name = "Marksman Slab Revolver",
					description = $"Fire a slow, heavy shot for <style=cIsDamage>{450f}% damage</style> that <style=cIsDamage>pierces</style> one enemy.",
					altName = "Coin Toss",
					altDescription = "Toss a coin. <style=cIsUtility>Shoot it</style> to ricochet the shot into the nearest enemy for <style=cIsDamage>+50% damage per coin</style>. Thrown farther than the revolver's.",
					primaryState = () => (EntityState)(object)new RevolverStates.Fire
					{
						slab = true
					},
					altState = () => (EntityState)(object)new RevolverStates.ThrowCoin
					{
						slab = true
					},
					altPool = WeaponCharges.Pool.Coins
				});
				Add(new WeaponDef
				{
					id = "SlabSharpshooter",
					type = WeaponType.SlabRevolver,
					variant = WeaponVariant.Red,
					name = "Sharpshooter Slab Revolver",
					description = $"Fire a slow, heavy shot for <style=cIsDamage>{450f}% damage</style> that <style=cIsDamage>pierces</style> one enemy.",
					altName = "Spin Shot",
					altDescription = $"Hold to spin, release to fire a beam that <style=cIsDamage>ricochets</style> up to 3 times, homing on enemies, for <style=cIsDamage>{675f}% damage</style>." + " Recharges in " + 8.571428f.ToString("0.#") + "s.",
					primaryState = () => (EntityState)(object)new RevolverStates.Fire
					{
						slab = true
					},
					altState = () => (EntityState)(object)new RevolverStates.ChargeSharp
					{
						slab = true
					},
					altPool = WeaponCharges.Pool.SlabSharpshooter
				});
				string altDescription = "Hold to charge, release to launch the core. It <style=cIsDamage>explodes</style> on impact for <style=cIsDamage>" + 400f + "% damage</style>.";
				string altDescription2 = "Throw the chainsaw. It <style=cIsDamage>shreds</style> everything in its path for <style=cIsDamage>" + 75f + "% damage</style> per hit, then comes back.";
				string description = "Fire " + 12 + " pellets for <style=cIsDamage>" + 50f + "% damage</style> each.";
				Add(new WeaponDef
				{
					id = "ShotgunCoreEject",
					type = WeaponType.Shotgun,
					variant = WeaponVariant.Blue,
					name = "Core Eject Shotgun",
					description = description,
					altName = "Core Eject",
					altDescription = altDescription,
					primaryState = () => (EntityState)(object)new ShotgunStates.Fire(),
					altState = () => (EntityState)(object)new ShotgunStates.ChargeCore(),
					altPool = WeaponCharges.Pool.ShotgunCore
				});
				Add(new WeaponDef
				{
					id = "ShotgunPump",
					type = WeaponType.Shotgun,
					variant = WeaponVariant.Green,
					name = "Pump Charge Shotgun",
					description = description,
					altName = "Pump Charge",
					altDescription = "Pump up to twice to add <style=cIsDamage>pellets and damage</style> to the next shot. A third pump <style=cDeath>overloads</style> into an explosion.",
					primaryState = () => (EntityState)(object)new ShotgunStates.Fire(),
					altState = () => (EntityState)(object)new ShotgunStates.Pump()
				});
				Add(new WeaponDef
				{
					id = "ShotgunSawedOn",
					type = WeaponType.Shotgun,
					variant = WeaponVariant.Red,
					name = "Sawed-On Shotgun",
					description = description,
					altName = "Chainsaw",
					altDescription = altDescription2,
					primaryState = () => (EntityState)(object)new ShotgunStates.Fire(),
					altState = () => (EntityState)(object)new ShotgunStates.ThrowSaw(),
					altPool = WeaponCharges.Pool.ShotgunSaw
				});
				string description2 = "Hold to pull back, release to smash for <style=cIsDamage>" + ShotgunStates.HammerDamage[0] * 100f + "%-" + ShotgunStates.HammerDamage[2] * 100f + "% damage</style>. The faster you move, the harder it hits; a red hit overheats it.";
				Add(new WeaponDef
				{
					id = "HammerCoreEject",
					type = WeaponType.Jackhammer,
					variant = WeaponVariant.Blue,
					name = "Core Eject Jackhammer",
					description = description2,
					altName = "Core Eject",
					altDescription = altDescription,
					primaryState = () => (EntityState)(object)new ShotgunStates.Hammer(),
					altState = () => (EntityState)(object)new ShotgunStates.ChargeCore(),
					altPool = WeaponCharges.Pool.ShotgunCore
				});
				Add(new WeaponDef
				{
					id = "HammerPump",
					type = WeaponType.Jackhammer,
					variant = WeaponVariant.Green,
					name = "Pump Charge Jackhammer",
					description = description2,
					altName = "Pump Charge",
					altDescription = "Pump up to twice to <style=cIsDamage>strengthen</style> the next smash. A third pump <style=cDeath>overloads</style> into an explosion.",
					primaryState = () => (EntityState)(object)new ShotgunStates.Hammer(),
					altState = () => (EntityState)(object)new ShotgunStates.Pump()
				});
				Add(new WeaponDef
				{
					id = "HammerSawedOn",
					type = WeaponType.Jackhammer,
					variant = WeaponVariant.Red,
					name = "Sawed-On Jackhammer",
					description = description2,
					altName = "Chainsaw",
					altDescription = altDescription2,
					primaryState = () => (EntityState)(object)new ShotgunStates.Hammer(),
					altState = () => (EntityState)(object)new ShotgunStates.ThrowSaw(),
					altPool = WeaponCharges.Pool.ShotgunSaw
				});
				string text = "Throw a <style=cIsUtility>zapper</style> on a cable. It latches onto an enemy and <style=cIsDamage>zaps it for " + 3000f + "% damage</style> after 5 seconds, unless the cable snaps from range or lost sight.";
				string description3 = "Rapidly fire nails for <style=cIsDamage>" + 35f + "% damage</style> each. Ammo refills when you stop firing.";
				Add(new WeaponDef
				{
					id = "NailgunAttractor",
					type = WeaponType.Nailgun,
					variant = WeaponVariant.Blue,
					name = "Attractor Nailgun",
					description = description3,
					altName = "Magnet",
					altDescription = "Throw a magnet that sticks to surfaces and enemies. Nails <style=cIsUtility>curve toward it</style>.",
					primaryState = () => (EntityState)(object)new NailgunStates.Fire(),
					altState = () => (EntityState)(object)new NailgunStates.ThrowMagnet(),
					altPool = WeaponCharges.Pool.Magnets,
					primaryPool = WeaponCharges.Pool.NailAmmo
				});
				Add(new WeaponDef
				{
					id = "NailgunOverheat",
					type = WeaponType.Nailgun,
					variant = WeaponVariant.Green,
					name = "Overheat Nailgun",
					description = description3,
					altName = "Heatsink",
					altDescription = "Vent a heatsink: for 2 seconds, nails fire <style=cIsDamage>twice as fast</style> and <style=cIsDamage>ignite</style>.",
					primaryState = () => (EntityState)(object)new NailgunStates.Fire(),
					altState = () => (EntityState)(object)new NailgunStates.Overheat(),
					altPool = WeaponCharges.Pool.Heatsinks
				});
				Add(new WeaponDef
				{
					id = "NailgunJumpStart",
					type = WeaponType.Nailgun,
					variant = WeaponVariant.Red,
					name = "Jumpstart Nailgun",
					description = description3,
					altName = "Zapper",
					altDescription = text + " While it's attached, nails fire at full speed.",
					primaryState = () => (EntityState)(object)new NailgunStates.Fire(),
					altState = () => (EntityState)(object)new NailgunStates.ShootZapper(),
					altPool = WeaponCharges.Pool.Zapper
				});
				string description4 = "Fire bouncing sawblades that <style=cIsDamage>pierce</style> for <style=cIsDamage>" + 75f + "% damage</style>.";
				Add(new WeaponDef
				{
					id = "SawAttractor",
					type = WeaponType.SawbladeLauncher,
					variant = WeaponVariant.Blue,
					name = "Attractor Sawblade Launcher",
					description = description4,
					altName = "Magnet",
					altDescription = "Throw a magnet that sticks to surfaces and enemies. Sawblades <style=cIsUtility>orbit it</style>.",
					primaryState = () => (EntityState)(object)new NailgunStates.FireSawblade(),
					altState = () => (EntityState)(object)new NailgunStates.ThrowMagnet(),
					altPool = WeaponCharges.Pool.Magnets,
					primaryPool = WeaponCharges.Pool.Saws
				});
				Add(new WeaponDef
				{
					id = "SawOverheat",
					type = WeaponType.SawbladeLauncher,
					variant = WeaponVariant.Green,
					name = "Overheat Sawblade Launcher",
					description = description4,
					altName = "Heatsink",
					altDescription = "Vent a heatsink: for 2 seconds, sawblades fire <style=cIsDamage>faster</style> and <style=cIsDamage>ignite</style>.",
					primaryState = () => (EntityState)(object)new NailgunStates.FireSawblade(),
					altState = () => (EntityState)(object)new NailgunStates.Overheat(),
					altPool = WeaponCharges.Pool.Heatsinks
				});
				Add(new WeaponDef
				{
					id = "SawJumpStart",
					type = WeaponType.SawbladeLauncher,
					variant = WeaponVariant.Red,
					name = "Jumpstart Sawblade Launcher",
					description = description4,
					altName = "Zapper",
					altDescription = text + " Sawblades that hit the enemy charge it <style=cIsDamage>faster and harder</style>.",
					primaryState = () => (EntityState)(object)new NailgunStates.FireSawblade(),
					altState = () => (EntityState)(object)new NailgunStates.ShootZapper(),
					altPool = WeaponCharges.Pool.Zapper
				});
				Add(new WeaponDef
				{
					id = "RailElectric",
					type = WeaponType.Railcannon,
					variant = WeaponVariant.Blue,
					name = "Electric Railcannon",
					description = "Fire a beam that <style=cIsDamage>pierces everything</style> for <style=cIsDamage>" + 4000f + "% damage</style>. Recharges in 45s, shared by all railcannons.",
					altName = "Zoom",
					altDescription = "Hold to zoom in.",
					primaryState = () => (EntityState)(object)new RailcannonStates.FireElectric(),
					altState = () => (EntityState)(object)new RailcannonStates.Zoom(),
					primaryPool = WeaponCharges.Pool.Railcannon
				});
				Add(new WeaponDef
				{
					id = "RailScrewdriver",
					type = WeaponType.Railcannon,
					variant = WeaponVariant.Green,
					name = "Screwdriver Railcannon",
					description = "Fire a drill that embeds in an enemy and <style=cIsDamage>drills for " + 2000f + "% damage</style> over time. Recharges in 45s, shared by all railcannons.",
					altName = "Zoom",
					altDescription = "Hold to zoom in.",
					primaryState = () => (EntityState)(object)new RailcannonStates.FireScrewdriver(),
					altState = () => (EntityState)(object)new RailcannonStates.Zoom(),
					primaryPool = WeaponCharges.Pool.Railcannon
				});
				Add(new WeaponDef
				{
					id = "RailMalicious",
					type = WeaponType.Railcannon,
					variant = WeaponVariant.Red,
					name = "Malicious Railcannon",
					description = "Fire a beam that <style=cIsDamage>explodes</style> on impact for <style=cIsDamage>" + 2800f + "% damage</style>. Recharges in 45s, shared by all railcannons.",
					altName = "Zoom",
					altDescription = "Hold to zoom in.",
					primaryState = () => (EntityState)(object)new RailcannonStates.FireMalicious(),
					altState = () => (EntityState)(object)new RailcannonStates.Zoom(),
					primaryPool = WeaponCharges.Pool.Railcannon
				});
				string description5 = "Fire a rocket that <style=cIsDamage>explodes</style> for <style=cIsDamage>" + 400f + "% damage</style>. The blast can launch V1.";
				Add(new WeaponDef
				{
					id = "RocketFreezeframe",
					type = WeaponType.RocketLauncher,
					variant = WeaponVariant.Blue,
					name = "Freezeframe Rocket Launcher",
					description = description5,
					altName = "Freezeframe",
					altDescription = "Toggle to <style=cIsUtility>freeze</style> your rockets in mid-air for up to 5 seconds. Frozen rockets deal <style=cIsDamage>double damage</style>.",
					primaryState = () => (EntityState)(object)new RocketStates.Fire(),
					altState = () => (EntityState)(object)new RocketStates.Freeze(),
					altPool = WeaponCharges.Pool.Freeze
				});
				Add(new WeaponDef
				{
					id = "RocketCannonball",
					type = WeaponType.RocketLauncher,
					variant = WeaponVariant.Green,
					name = "S.R.S. Cannon Rocket Launcher",
					description = description5,
					altName = "Cannonball",
					altDescription = "Hold to charge, release to fire a heavy cannonball that bounces once, for <style=cIsDamage>" + 1000f + "% damage</style>.",
					primaryState = () => (EntityState)(object)new RocketStates.Fire(),
					altState = () => (EntityState)(object)new RocketStates.ChargeCannonball(),
					altPool = WeaponCharges.Pool.Cannonball
				});
				Add(new WeaponDef
				{
					id = "RocketFirestarter",
					type = WeaponType.RocketLauncher,
					variant = WeaponVariant.Red,
					name = "Firestarter Rocket Launcher",
					description = description5,
					altName = "Napalm",
					altDescription = "Hold to spray napalm that <style=cIsDamage>ignites</style> enemies for <style=cIsDamage>" + 50f + "% damage</style> per tick, using fuel.",
					primaryState = () => (EntityState)(object)new RocketStates.Fire(),
					altState = () => (EntityState)(object)new RocketStates.Napalm(),
					altPool = WeaponCharges.Pool.Napalm
				});
			}
		}
	}
	public class WeaponCharges
	{
		public enum Pool
		{
			Piercer,
			Coins,
			Sharpshooter,
			ShotgunCore,
			ShotgunSaw,
			NailAmmo,
			Saws,
			Magnets,
			Heatsinks,
			Zapper,
			Railcannon,
			Freeze,
			Cannonball,
			Napalm,
			SlabSharpshooter,
			Count
		}

		private struct PoolInfo
		{
			public float max;

			public float unit;

			public float regen;

			public PoolInfo(float max, float unit, float regen)
			{
				this.max = max;
				this.unit = unit;
				this.regen = regen;
			}
		}

		private static readonly PoolInfo[] infos = new PoolInfo[15]
		{
			new PoolInfo(100f, 100f, 40f),
			new PoolInfo(100f, 100f, 25f),
			new PoolInfo(100f, 100f, 35f),
			new PoolInfo(1f, 1f, 0.5f),
			new PoolInfo(1f, 1f, 0.25f),
			new PoolInfo(100f, 1f, 5f),
			new PoolInfo(10f, 1f, 1f),
			new PoolInfo(1f, 1f, 0.2f),
			new PoolInfo(1f, 1f, 0.125f),
			new PoolInfo(1f, 1f, 0.2f),
			new PoolInfo(1f, 1f, 1f / 45f),
			new PoolInfo(5f, 1f, 0.5f),
			new PoolInfo(1f, 1f, 0.125f),
			new PoolInfo(1f, 0.01f, 0.125f),
			new PoolInfo(300f, 300f, 35f)
		};

		private readonly float[] values = new float[15];

		private readonly float[] blockedRegen = new float[15];

		public int bonusAltStock;

		public float regenMultiplier = 1f;

		public event Action<Pool, int, float> onRestock;

		public WeaponCharges()
		{
			for (int i = 0; i < values.Length; i++)
			{
				values[i] = infos[i].max;
			}
		}

		public float Max(Pool p)
		{
			return infos[(int)p].max + (IsAltPool(p) ? ((float)bonusAltStock * infos[(int)p].unit) : 0f);
		}

		public float Unit(Pool p)
		{
			return infos[(int)p].unit;
		}

		public float Value(Pool p)
		{
			return values[(int)p];
		}

		public float Fraction(Pool p)
		{
			return Value(p) / Max(p);
		}

		public bool Has(Pool p, float amount)
		{
			return values[(int)p] >= amount - 0.0001f;
		}

		public bool HasUnit(Pool p)
		{
			return Has(p, Unit(p));
		}

		public int Stock(Pool p)
		{
			return Mathf.FloorToInt((values[(int)p] + 0.0001f) / Unit(p));
		}

		public int MaxStock(Pool p)
		{
			return Mathf.FloorToInt(Max(p) / Unit(p) + 0.0001f);
		}

		public float SecondsPerUnit(Pool p)
		{
			return Unit(p) / (infos[(int)p].regen * regenMultiplier);
		}

		public float PartialUnit(Pool p)
		{
			return Mathf.Repeat(values[(int)p], Unit(p)) / Unit(p);
		}

		private static bool IsAltPool(Pool p)
		{
			if (p != Pool.NailAmmo && p != Pool.Saws && p != Pool.Railcannon && p != Pool.Napalm)
			{
				return p != Pool.Freeze;
			}
			return false;
		}

		public bool Consume(Pool p, float amount)
		{
			if (!Has(p, amount))
			{
				return false;
			}
			values[(int)p] = Mathf.Max(0f, values[(int)p] - amount);
			return true;
		}

		public void ConsumeUnit(Pool p)
		{
			Consume(p, Unit(p));
		}

		public void Drain(Pool p, float amount)
		{
			values[(int)p] = Mathf.Max(0f, values[(int)p] - amount);
		}

		public void Empty(Pool p)
		{
			values[(int)p] = 0f;
		}

		public void BlockRegen(Pool p, float seconds)
		{
			blockedRegen[(int)p] = Mathf.Max(blockedRegen[(int)p], seconds);
		}

		private static bool IsCooldown(Pool p)
		{
			if (p != Pool.NailAmmo && p != Pool.Saws && p != Pool.Napalm)
			{
				return p != Pool.Freeze;
			}
			return false;
		}

		public void Tick(float dt)
		{
			for (int i = 0; i < values.Length; i++)
			{
				if (blockedRegen[i] > 0f)
				{
					blockedRegen[i] -= dt;
					continue;
				}
				Pool pool = (Pool)i;
				int num = Stock(pool);
				values[i] = Mathf.MoveTowards(values[i], Max(pool), infos[i].regen * regenMultiplier * dt);
				int num2 = Stock(pool) - num;
				if (num2 > 0 && IsCooldown(pool))
				{
					this.onRestock?.Invoke(pool, num2, infos[i].unit / infos[i].regen);
				}
			}
		}

		public void RefillAll()
		{
			for (int i = 0; i < values.Length; i++)
			{
				values[i] = Max((Pool)i);
			}
		}
	}
	public static class WeaponTiming
	{
		public const float RevolverShot = 0.514f;

		public const float SlabShot = 1.189f;

		public const float SlabClick = 0.89f;

		public const float SharpshooterShot = 0.467f;

		public const float ShotgunShot = 1.212f;

		public const float ShotgunHeat = 0.386f;

		public const float ShotgunClick = 1.057f;

		public const float PumpShot = 0.903f;

		public const float PumpShotPump1 = 0.402f;

		public const float PumpShotPump2 = 0.677f;

		public const float Pump = 0.388f;

		public const float PumpPump1 = 0.061f;

		public const float PumpPump2 = 0.305f;

		public const float CoreThrow = 2.057f;

		public const float CoreHeat = 0.279f;

		public const float CoreSmack1 = 1.507f;

		public const float CoreSmack2 = 1.543f;

		public const float CoreClick = 1.708f;

		public const float SawThrow = 0.667f;

		public const float HammerSwingRate = 2f;

		public const float HammerCooldown = 0.5f;

		public const float HammerPumpReady = 0.5f;

		public const float HammerPump2 = 0.127f;

		public const float HammerOverheat = 7f;

		public const float NailgunFireRate = 4f;

		public const float SawFireRate = 24f;

		public const float Rocket = 1f;

		public const float RocketClunk1 = 0.043f;

		public const float RocketClunk2 = 0.759f;

		public const float FeedbackerReady = 0.33f;

		public const float KnuckleBlastCheck = 0.489f;

		public const float KnuckleReady = 0.88f;

		public const float KnuckleEject = 0.783f;

		public const float KnuckleBlastReady = 1.391f;

		public static float Equip(WeaponDef w)
		{
			if (w == null)
			{
				return 0f;
			}
			return w.type switch
			{
				WeaponType.Revolver => 0.364f, 
				WeaponType.SlabRevolver => 0.388f, 
				WeaponType.Shotgun => 0.438f, 
				WeaponType.Jackhammer => 0.5f, 
				WeaponType.Nailgun => 0.308f, 
				WeaponType.SawbladeLauncher => 0.3f, 
				WeaponType.RocketLauncher => 0.25f, 
				_ => 0f, 
			};
		}
	}
}
namespace ROUK.Weapons.States
{
	public static class NailgunStates
	{
		public class Fire : V1WeaponState
		{
			private WeaponDef def;

			private bool saw;

			private bool shotSuccessfully;

			public override void OnEnter()
			{
				base.OnEnter();
				def = (Object.op_Implicit((Object)(object)weapons) ? weapons.active : null);
				saw = def != null && def.type == WeaponType.SawbladeLauncher;
				if (Object.op_Implicit((Object)(object)weapons))
				{
					weapons.nailFiring = true;
				}
			}

			public override void OnExit()
			{
				if (Object.op_Implicit((Object)(object)weapons))
				{
					weapons.nailFiring = false;
				}
				base.OnExit();
			}

			public override void FixedUpdate()
			{
				((EntityState)this).FixedUpdate();
				if (!Object.op_Implicit((Object)(object)weapons) || def == null || weapons.active != def)
				{
					if (((EntityState)this).isAuthority)
					{
						((EntityState)this).outer.SetNextStateToMain();
					}
				}
				else
				{
					if (!((EntityState)this).isAuthority)
					{
						return;
					}
					bool flag = weapons.nailBurnout && !saw;
					if (!base.PrimaryDown && !flag)
					{
						((EntityState)this).outer.SetNextStateToMain();
						return;
					}
					for (int i = 0; i < 3; i++)
					{
						if (!(weapons.nailFireCooldown <= 0f))
						{
							break;
						}
						float num = FireRate(weapons, def) / 100f / ((BaseState)this).attackSpeedStat;
						weapons.nailFireCooldown += Mathf.Max(num, 0.005f);
						Shoot();
					}
				}
			}

			private void Shoot()
			{
				V1WeaponController v1WeaponController = weapons;
				bool flag = def.variant == WeaponVariant.Green;
				bool nailBurnout = v1WeaponController.nailBurnout;
				bool flag2 = v1WeaponController.charges.HasUnit(WeaponCharges.Pool.Heatsinks);
				if (def.variant == WeaponVariant.Blue)
				{
					WeaponCharges.Pool p = (saw ? WeaponCharges.Pool.Saws : WeaponCharges.Pool.NailAmmo);
					if (!v1WeaponController.charges.HasUnit(p))
					{
						v1WeaponController.nailFireCooldown += FireRate(v1WeaponController, def) / 100f / ((BaseState)this).attackSpeedStat;
						V1Sound.Play(shotSuccessfully ? "ROUK_NailLastShot" : "ROUK_NailNoAmmo", ((EntityState)this).gameObject);
						shotSuccessfully = false;
						return;
					}
					v1WeaponController.charges.ConsumeUnit(p);
					v1WeaponController.charges.BlockRegen(p, 0.5f);
				}
				shotSuccessfully = true;
				v1WeaponController.NotifyPrimaryFired();
				if (saw)
				{
					V1Sound.Play("Play_MULT_m1_sawblade_start#SawShot", ((EntityState)this).gameObject);
					float spread = ((!flag) ? 0f : (flag2 ? Mathf.Lerp(0f, 45f, Mathf.Max(0f, v1WeaponController.nailHeat - 0.25f)) : 45f));
					float num = ((flag && flag2) ? Mathf.Lerp(3f, 1f, v1WeaponController.nailHeat) : 1f);
					FireBullet(this, V1Projectiles.saw, 0.75f * num, spread, hot: false);
					if (flag && flag2)
					{
						v1WeaponController.nailHeat = Mathf.MoveTowards(v1WeaponController.nailHeat, 1f, 0.125f);
					}
					Recoil(0.6f);
				}
				else
				{
					if (nailBurnout)
					{
						V1Sound.Play("Play_MULT_m1_smg_shoot", ((EntityState)this).gameObject, 1f, 2f, absolutePitch: true);
					}
					else if (flag && !flag2)
					{
						V1Sound.Play("Play_MULT_m1_smg_shoot", ((EntityState)this).gameObject, 0.3846154f, 0.75f, absolutePitch: true);
					}
					else
					{
						V1Sound.Play("Play_MULT_m1_smg_shoot", ((EntityState)this).gameObject);
					}
					float spread2 = (flag ? 20f : 10f) * (nailBurnout ? 2f : 1f);
					FireBullet(this, nailBurnout ? V1Projectiles.nailHeated : V1Projectiles.nail, 0.35f * (nailBurnout ? 1.5f : 1f), spread2, nailBurnout);
					Recoil(nailBurnout ? 0.4f : 0.25f);
				}
				Muzzleflash(V1Assets.muzzleSmall);
			}

			public override InterruptPriority GetMinimumInterruptPriority()
			{
				return (InterruptPriority)0;
			}
		}

		public class FireSawblade : Fire
		{
		}

		public class ThrowMagnet : V1WeaponState
		{
			public override void OnEnter()
			{
				//IL_004e: Unknown result type (might be due to invalid IL or missing references)
				//IL_0053: Unknown result type (might be due to invalid IL or missing references)
				//IL_005b: Unknown result type (might be due to invalid IL or missing references)
				//IL_0071: Unknown result type (might be due to invalid IL or missing references)
				//IL_0076: Unknown result type (might be due to invalid IL or missing references)
				//IL_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_0089: Unknown result type (might be due to invalid IL or missing references)
				//IL_00c1: Unknown result type (might be due to invalid IL or missing references)
				base.OnEnter();
				V1Sound.Play("Play_engi_M2_throw", ((EntityState)this).gameObject);
				weapons?.NotifyAltFired();
				if (((EntityState)this).isAuthority)
				{
					weapons.charges.ConsumeUnit(WeaponCharges.Pool.Magnets);
					Ray aimRay = ((BaseState)this).GetAimRay();
					ProjectileManager instance = ProjectileManager.instance;
					FireProjectileInfo val = new FireProjectileInfo
					{
						projectilePrefab = V1Projectiles.magnet,
						position = ((Ray)(ref aimRay)).origin,
						rotation = Util.QuaternionSafeLookRotation(((Ray)(ref aimRay)).direction),
						owner = ((EntityState)this).gameObject,
						damage = 0f,
						useSpeedOverride = true
					};
					((FireProjectileInfo)(ref val)).speedOverride = 100f * V1WeaponState.K;
					instance.FireProjectile(val);
					((EntityState)this).outer.SetNextStateToMain();
				}
			}
		}

		public class Overheat : V1WeaponState
		{
			public override void OnEnter()
			{
				base.OnEnter();
				V1WeaponController v1WeaponController = weapons;
				WeaponDef weaponDef = (Object.op_Implicit((Object)(object)v1WeaponController) ? v1WeaponController.active : null);
				bool flag = weaponDef != null && weaponDef.type == WeaponType.SawbladeLauncher;
				if (!Object.op_Implicit((Object)(object)v1WeaponController) || v1WeaponController.nailBurnout || v1WeaponController.nailHeat < 0.1f || !v1WeaponController.charges.HasUnit(WeaponCharges.Pool.Heatsinks))
				{
					if (((EntityState)this).isAuthority)
					{
						((EntityState)this).outer.SetNextStateToMain();
					}
					return;
				}
				v1WeaponController.NotifyAltFired();
				if (flag)
				{
					V1Sound.Play("Play_MULT_m1_sawblade_start#SawShot", ((EntityState)this).gameObject, 1f, 0.8f);
					V1Sound.Play("ROUK_SawShotHeated", ((EntityState)this).gameObject);
					if (((EntityState)this).isAuthority)
					{
						v1WeaponController.charges.ConsumeUnit(WeaponCharges.Pool.Heatsinks);
						v1WeaponController.nailFireCooldown = FireRate(v1WeaponController, weaponDef) / 100f / ((BaseState)this).attackSpeedStat;
						FireBullet(this, V1Projectiles.sawHeated, 8f, 0f, hot: true);
						Recoil(2f);
					}
				}
				else
				{
					V1Sound.Play("Play_MULT_R_variant_activate", ((EntityState)this).gameObject);
					if (((EntityState)this).isAuthority)
					{
						v1WeaponController.charges.ConsumeUnit(WeaponCharges.Pool.Heatsinks);
						v1WeaponController.nailBurnout = true;
						v1WeaponController.nailFireCooldown = 0f;
						((EntityState)this).outer.SetNextState((EntityState)(object)new Fire());
						return;
					}
				}
				if (((EntityState)this).isAuthority)
				{
					((EntityState)this).outer.SetNextStateToMain();
				}
			}
		}

		public class ShootZapper : V1WeaponState
		{
			public override void OnEnter()
			{
				//IL_003d: Unknown result type (might be due to invalid IL or missing references)
				//IL_0042: Unknown result type (might be due to invalid IL or missing references)
				//IL_004a: Unknown result type (might be due to invalid IL or missing references)
				//IL_0060: Unknown result type (might be due to invalid IL or missing references)
				//IL_0065: Unknown result type (might be due to invalid IL or missing references)
				//IL_006e: Unknown result type (might be due to invalid IL or missing references)
				//IL_0073: Unknown result type (might be due to invalid IL or missing references)
				//IL_0078: Unknown result type (might be due to invalid IL or missing references)
				//IL_00b0: Unknown result type (might be due to invalid IL or missing references)
				base.OnEnter();
				V1Sound.Play("Play_engi_M2_throw", ((EntityState)this).gameObject);
				weapons?.NotifyAltFired();
				if (((EntityState)this).isAuthority)
				{
					Ray aimRay = ((BaseState)this).GetAimRay();
					ProjectileManager.instance.FireProjectile(new FireProjectileInfo
					{
						projectilePrefab = V1Projectiles.zapper,
						position = ((Ray)(ref aimRay)).origin,
						rotation = Util.QuaternionSafeLookRotation(((Ray)(ref aimRay)).direction),
						owner = ((EntityState)this).gameObject,
						damage = ((BaseState)this).damageStat,
						crit = ((BaseState)this).RollCrit(),
						force = 0f
					});
					((EntityState)this).outer.SetNextState((EntityState)(object)new Cooldown
					{
						duration = 0.3f
					});
				}
			}
		}

		public const float NailDamage = 0.35f;

		public const float SawbladeDamage = 0.75f;

		public const float SuperSawDamage = 8f;

		public static float FireRate(V1WeaponController w, WeaponDef d)
		{
			bool flag = d.type == WeaponType.SawbladeLauncher;
			float num = (flag ? 24f : 4f);
			float nailHeat = w.nailHeat;
			if (d.variant != WeaponVariant.Green)
			{
				return num + 3.5f - nailHeat * 3.5f;
			}
			if (w.nailBurnout)
			{
				if (!flag)
				{
					return num - 2.5f;
				}
				return 3f;
			}
			if (w.charges.HasUnit(WeaponCharges.Pool.Heatsinks))
			{
				if (!(nailHeat < 0.5f))
				{
					return num + (nailHeat - 0.5f) * (flag ? 65f : 7f);
				}
				return num;
			}
			return num + (flag ? 50f : 10f);
		}

		private static void FireBullet(V1WeaponState state, GameObject prefab, float coefficient, float spread, bool hot)
		{
			//IL_0001: Unknown result type (might be due to invalid IL or missing references)
			//IL_0006: Unknown result type (might be due to invalid IL or missing references)
			//IL_0009: 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_0050: Unknown result type (might be due to invalid IL or missing references)
			//IL_0062: Unknown result type (might be due to invalid IL or missing references)
			//IL_0069: Unknown result type (might be due to invalid IL or missing references)
			//IL_0073: Unknown result type (might be due to invalid IL or missing references)
			//IL_0078: Unknown result type (might be due to invalid IL or missing references)
			//IL_007d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0084: Unknown result type (might be due to invalid IL or missing references)
			//IL_0085: Unknown result type (might be due to invalid IL or missing references)
			//IL_001c: Unknown result type (might be due to invalid IL or missing references)
			//IL_003e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0043: Unknown result type (might be due to invalid IL or missing references)
			//IL_0048: Unknown result type (might be due to invalid IL or missing references)
			//IL_00f3: Unknown result type (might be due to invalid IL or missing references)
			//IL_00fa: Unknown result type (might be due to invalid IL or missing references)
			//IL_0109: Unknown result type (might be due to invalid IL or missing references)
			Ray val = state.AimRayPublic();
			Quaternion val2 = Util.QuaternionSafeLookRotation((