Decompiled source of ContentWarningDoom v0.3.2

BepInEx/plugins/ContentWarningDoom/ContentWarningDoom.dll

Decompiled a day ago
using System;
using System.Collections;
using System.Collections.Generic;
using System.Diagnostics;
using System.Globalization;
using System.IO;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.Versioning;
using System.Security;
using System.Security.Permissions;
using System.Text;
using BepInEx;
using BepInEx.Configuration;
using BepInEx.Logging;
using ContentWarningDoom.ActionMode;
using ContentWarningDoom.Audio;
using ContentWarningDoom.Combat;
using ContentWarningDoom.Config;
using ContentWarningDoom.Core;
using ContentWarningDoom.Debug;
using ContentWarningDoom.FX;
using ContentWarningDoom.Items;
using ContentWarningDoom.Monsters;
using ContentWarningDoom.Networking;
using ContentWarningDoom.PlayerLogic;
using ContentWarningDoom.Shop;
using ContentWarningDoom.UI;
using ContentWarningDoom.Weapons;
using ExitGames.Client.Photon;
using HarmonyLib;
using Microsoft.CodeAnalysis;
using Photon.Pun;
using Photon.Realtime;
using UnityEngine;
using UnityEngine.AI;
using UnityEngine.InputSystem;
using UnityEngine.InputSystem.Controls;
using UnityEngine.Rendering;
using UnityEngine.SceneManagement;

[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("ContentWarningDoom")]
[assembly: AssemblyConfiguration("Release")]
[assembly: AssemblyFileVersion("0.3.2.0")]
[assembly: AssemblyInformationalVersion("0.3.2")]
[assembly: AssemblyProduct("ContentWarningDoom")]
[assembly: AssemblyTitle("ContentWarningDoom")]
[assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)]
[assembly: AssemblyVersion("0.3.2.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 ContentWarningDoom
{
	public class DoomController : MonoBehaviour
	{
		public static bool ShowDebugOverlay;

		private float _bannerUntil;

		private bool _droppedShotgun;

		private bool _droppedSsg;

		private bool _droppedBfg;

		public bool BannerVisible => Time.time < _bannerUntil;

		private void OnEnable()
		{
			DoomNet.OnModeState += HandleModeState;
			DoomNet.OnMonsterDeath += HandleMonsterDeath;
			DoomNet.OnKills += HandleKills;
			DoomNet.OnHostPlayerJoined += HandleHostPlayerJoined;
		}

		private void OnDisable()
		{
			DoomNet.OnModeState -= HandleModeState;
			DoomNet.OnMonsterDeath -= HandleMonsterDeath;
			DoomNet.OnKills -= HandleKills;
			DoomNet.OnHostPlayerJoined -= HandleHostPlayerJoined;
		}

		private void Update()
		{
			Keyboard current = Keyboard.current;
			if (current == null || (!((ButtonControl)current.leftAltKey).isPressed && !((ButtonControl)current.rightAltKey).isPressed))
			{
				return;
			}
			if (((ButtonControl)current.oKey).wasPressedThisFrame)
			{
				ShowDebugOverlay = !ShowDebugOverlay;
			}
			if (((ButtonControl)current.kKey).wasPressedThisFrame)
			{
				if (!DoomNet.InRoom)
				{
					Plugin.LogMode("Alt+K ignored — not in a room yet.");
				}
				else if (!DoomNet.IsHost)
				{
					Plugin.LogMode("Alt+K ignored — only the host can toggle Doom Mode.");
				}
				else
				{
					SetDoomMode(!Plugin.DoomModeActive, broadcast: true);
				}
			}
			if (((ButtonControl)current.mKey).wasPressedThisFrame && DoomNet.IsHost && Plugin.DoomModeActive)
			{
				DebugSpawnMonster();
			}
			if (((ButtonControl)current.uKey).wasPressedThisFrame && DoomNet.IsHost && Plugin.DoomModeActive)
			{
				WeaponManager.Instance?.UnlockAll();
				WeaponManager.Instance?.GiveAmmoAll(1f);
			}
			if (((ButtonControl)current.bKey).wasPressedThisFrame && Plugin.DoomModeActive)
			{
				BuyNextSpecialWeapon();
			}
			if (((ButtonControl)current.gKey).wasPressedThisFrame && Plugin.DoomModeActive)
			{
				ReviveTeammates();
			}
			if (((ButtonControl)current.jKey).wasPressedThisFrame && Plugin.DoomModeActive)
			{
				ScrapEconomy.Add(DoomNet.LocalActor, 1000);
				Plugin.LogMode($"[Debug] +1000 scrap (now {ScrapEconomy.Local})");
			}
			if (((ButtonControl)current.pKey).wasPressedThisFrame)
			{
				WeaponShop.Instance?.PinHere();
			}
			if (((ButtonControl)current.lKey).wasPressedThisFrame)
			{
				WeaponShop.Instance?.ClearPin();
			}
			if (((ButtonControl)current.eKey).wasPressedThisFrame)
			{
				ActionRoundManager.Instance?.RequestLocalSubmit();
			}
			if (((ButtonControl)current.nKey).wasPressedThisFrame && Plugin.DoomModeActive)
			{
				EpicMusic.Instance?.Toggle();
			}
			if (((ButtonControl)current.equalsKey).wasPressedThisFrame || ((ButtonControl)current.numpadPlusKey).wasPressedThisFrame)
			{
				EpicMusic.AdjustVolume(0.05f);
			}
			else if (((ButtonControl)current.minusKey).wasPressedThisFrame || ((ButtonControl)current.numpadMinusKey).wasPressedThisFrame)
			{
				EpicMusic.AdjustVolume(-0.05f);
			}
		}

		private static void ReviveTeammates()
		{
			PlayerHandler instance = PlayerHandler.instance;
			if ((Object)(object)instance == (Object)null || instance.players == null)
			{
				Plugin.LogMode("[Revive] no PlayerHandler");
				return;
			}
			Player localPlayer = Player.localPlayer;
			int num = 0;
			for (int i = 0; i < instance.players.Count; i++)
			{
				Player val = instance.players[i];
				if (!((Object)(object)val == (Object)null) && !((Object)(object)val == (Object)(object)localPlayer) && val.data != null && val.data.dead)
				{
					try
					{
						val.CallRevive();
						num++;
					}
					catch (Exception ex)
					{
						Plugin.LogMode("[Revive] " + ((Object)val).name + ": " + ex.Message);
					}
				}
			}
			Plugin.LogMode((num > 0) ? $"[Revive] revived {num} teammate(s)" : "[Revive] no downed teammates");
		}

		private void BuyNextSpecialWeapon()
		{
			int localActor = DoomNet.LocalActor;
			WeaponId[] array = new WeaponId[2]
			{
				WeaponId.Minigun,
				WeaponId.GrenadeLauncher
			};
			foreach (WeaponId weaponId in array)
			{
				if (ActionEconomy.Purchased(localActor).Contains(weaponId))
				{
					continue;
				}
				if (ActionEconomy.TryBuy(localActor, weaponId))
				{
					Plugin.Log.LogInfo((object)$"[Shop] bought {weaponId} — carried into the next dive. Credits left: {ActionEconomy.GetCredits(localActor)}");
					if (Plugin.DoomModeActive && ActionRoundManager.Phase == ActionRoundPhase.Action)
					{
						ActionEconomy.ApplyPurchasesToLocalPlayer(localActor);
					}
				}
				else
				{
					Plugin.Log.LogInfo((object)$"[Shop] not enough ActionCredits for {weaponId} (need {ActionEconomy.PriceOf(weaponId)}, have {ActionEconomy.GetCredits(localActor)})");
				}
				return;
			}
			Plugin.Log.LogInfo((object)"[Shop] all special weapons already owned.");
		}

		public void SetDoomMode(bool on, bool broadcast)
		{
			if (Plugin.DoomModeActive != on || broadcast)
			{
				Plugin.DoomModeActive = on;
				Plugin.CurrentSpawnMultiplier = (on ? Mathf.Max(1f, DoomConfig.MonsterSpawnMultiplier.Value) : 1f);
				if (on)
				{
					Plugin.DoomEverActivated = true;
					KillCounter.ResetAll();
					ResetDrops();
					MonsterRegistry.Instance?.Clear();
					WeaponManager.Instance?.RebuildWeapons();
					WeaponManager.Instance?.OnDoomModeEnabled();
					_bannerUntil = Time.time + 2.5f;
					Plugin.Log.LogInfo((object)"========== DOOM MODE ENABLED ==========");
					ViralityCompat.Detect();
					int num = ViralityCompat.RoomMaxPlayers();
					Plugin.Log.LogInfo((object)($"[DoomMode] session: {DoomNet.PlayerCount} player(s) in room" + ((num > 0) ? $" (room cap {num})" : "") + ", virality=" + (ViralityCompat.Present ? "yes" : "no") + " — no player limit is imposed by this mod."));
					Plugin.LogMode($"spawn x{Plugin.CurrentSpawnMultiplier}, monster HP layer active, starting weapon: PISTOL");
				}
				else
				{
					WeaponManager.Instance?.OnDoomModeDisabled();
					Plugin.Log.LogInfo((object)"========== DOOM MODE DISABLED ==========");
				}
				if (broadcast && DoomNet.IsHost)
				{
					DoomNet.SendModeState(on, Plugin.CurrentSpawnMultiplier);
				}
			}
		}

		private void HandleModeState(bool enabled, float spawnMult, int hostActor)
		{
			if (DoomNet.IsHost)
			{
				return;
			}
			Plugin.CurrentSpawnMultiplier = spawnMult;
			if (enabled != Plugin.DoomModeActive)
			{
				Plugin.DoomModeActive = enabled;
				if (enabled)
				{
					Plugin.DoomEverActivated = true;
					KillCounter.ResetAll();
					ResetDrops();
					MonsterRegistry.Instance?.Clear();
					WeaponManager.Instance?.RebuildWeapons();
					WeaponManager.Instance?.OnDoomModeEnabled();
					_bannerUntil = Time.time + 2.5f;
					Plugin.LogMode("host enabled DOOM MODE — mirroring.");
				}
				else
				{
					WeaponManager.Instance?.OnDoomModeDisabled();
					Plugin.LogMode("host disabled DOOM MODE — mirroring.");
				}
			}
		}

		private void HandleHostPlayerJoined()
		{
			if (DoomNet.IsHost)
			{
				DoomNet.SendModeState(Plugin.DoomModeActive, Plugin.CurrentSpawnMultiplier);
			}
		}

		private void HandleKills(int teamKills)
		{
			KillCounter.SetTeamKillsFromNetwork(teamKills);
		}

		public void ResetDrops()
		{
			_droppedShotgun = (_droppedSsg = (_droppedBfg = false));
		}

		private void HandleMonsterDeath(int viewId, Vector3 dir, int killerActor)
		{
			//IL_005f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0064: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a3: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a8: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e4: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c8: Unknown result type (might be due to invalid IL or missing references)
			//IL_01c4: Unknown result type (might be due to invalid IL or missing references)
			//IL_01c5: Unknown result type (might be due to invalid IL or missing references)
			//IL_01cf: Unknown result type (might be due to invalid IL or missing references)
			//IL_01d4: Unknown result type (might be due to invalid IL or missing references)
			Plugin.HudKillMarker();
			if (killerActor == DoomNet.LocalActor)
			{
				Plugin.HudLocalKill();
				ScrapEconomy.AwardForKill(viewId);
			}
			KillCounter.NoteLocalCredit(killerActor);
			WeaponManager instance = WeaponManager.Instance;
			if ((Object)(object)instance != (Object)null && instance.HasWeapon)
			{
				instance.GiveAmmo(instance.CurrentDef.Id, Mathf.Max(1, instance.CurrentDef.MagSize / 3));
			}
			Vector3 val = ((Component)this).transform.position;
			int num;
			if ((Object)(object)MonsterRegistry.Instance != (Object)null && MonsterRegistry.Instance.TryGet(viewId, out var h))
			{
				num = (((Object)(object)h.Root != (Object)null) ? 1 : 0);
				if (num != 0)
				{
					MonsterRegistry.Instance.TryGet(viewId, out var h2);
					val = h2.CenterPos;
				}
			}
			else
			{
				num = 0;
			}
			if (num == 0)
			{
				return;
			}
			if (killerActor == DoomNet.LocalActor && (Object)(object)instance != (Object)null)
			{
				instance.GiveAmmoAll(0.06f);
				ImpactEffects.AmmoPickupFx(val);
				Plugin.LogWeapon("kill ammo bonus +6% all weapons");
			}
			if (Random.value < 0.4f)
			{
				AmmoPickup.Spawn(val);
			}
			if ((Object)(object)instance == (Object)null)
			{
				return;
			}
			int teamKills = KillCounter.TeamKills;
			WeaponId? weaponId = null;
			if (!_droppedShotgun && !instance.IsUnlocked(WeaponId.Shotgun) && teamKills >= 2)
			{
				weaponId = WeaponId.Shotgun;
				_droppedShotgun = true;
			}
			else if (!_droppedSsg && !instance.IsUnlocked(WeaponId.SuperShotgun) && teamKills >= 8)
			{
				weaponId = WeaponId.SuperShotgun;
				_droppedSsg = true;
			}
			else if (!_droppedBfg && !instance.IsUnlocked(WeaponId.BFG) && teamKills >= 18)
			{
				weaponId = WeaponId.BFG;
				_droppedBfg = true;
			}
			else if (Random.value < 0.12f)
			{
				if (!instance.IsUnlocked(WeaponId.Shotgun))
				{
					weaponId = WeaponId.Shotgun;
				}
				else if (!instance.IsUnlocked(WeaponId.SuperShotgun))
				{
					weaponId = WeaponId.SuperShotgun;
				}
				else if (!instance.IsUnlocked(WeaponId.BFG))
				{
					weaponId = WeaponId.BFG;
				}
			}
			if (weaponId.HasValue)
			{
				WeaponPickup.Spawn(val + Random.insideUnitSphere * 1.2f, weaponId.Value);
			}
		}

		private void DebugSpawnMonster()
		{
			//IL_0050: Unknown result type (might be due to invalid IL or missing references)
			//IL_0056: Unknown result type (might be due to invalid IL or missing references)
			//IL_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_006a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0077: Unknown result type (might be due to invalid IL or missing references)
			if ((Object)(object)MainCamera.instance == (Object)null)
			{
				return;
			}
			string[] obj = new string[6] { "Zombe", "Zombie", "Snatcho", "Larva", "Spider", "BarnacleBall" };
			Transform transform = ((Component)MainCamera.instance).transform;
			Vector3 val = transform.position + transform.forward * 8f;
			string[] array = obj;
			foreach (string text in array)
			{
				try
				{
					if ((Object)(object)MonsterSpawner.SpawnMonster(text, val) != (Object)null)
					{
						Plugin.LogSpawn("F9 spawned '" + text + "'");
						return;
					}
				}
				catch
				{
				}
			}
			Plugin.LogSpawn("F9 spawn failed — no known monster prefab name resolved.");
		}
	}
	[BepInPlugin("SchetnikovMods.ContentWarningDoom", "ContentWarningDoom", "0.3.2")]
	public class Plugin : BaseUnityPlugin
	{
		public const string Guid = "SchetnikovMods.ContentWarningDoom";

		private Harmony _harmony;

		public static bool DoomEverActivated;

		public static MonsterHealth GloryTarget;

		public static Plugin Instance { get; private set; }

		public static ManualLogSource Log { get; private set; }

		public static bool DoomModeActive { get; internal set; }

		public static float CurrentSpawnMultiplier { get; internal set; } = 1f;

		private void Awake()
		{
			//IL_003e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0048: Expected O, but got Unknown
			//IL_00d6: Unknown result type (might be due to invalid IL or missing references)
			//IL_00db: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e1: Expected O, but got Unknown
			//IL_00e1: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e8: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ef: Unknown result type (might be due to invalid IL or missing references)
			//IL_00f6: Unknown result type (might be due to invalid IL or missing references)
			//IL_00fd: Unknown result type (might be due to invalid IL or missing references)
			Instance = this;
			Log = ((BaseUnityPlugin)this).Logger;
			DoomConfig.Init(((BaseUnityPlugin)this).Config);
			if (!DoomConfig.Enabled.Value)
			{
				Log.LogWarning((object)"[DoomMode] disabled via config (General.Enabled = false).");
				return;
			}
			_harmony = new Harmony("SchetnikovMods.ContentWarningDoom");
			try
			{
				_harmony.PatchAll(typeof(Plugin).Assembly);
			}
			catch (Exception arg)
			{
				Log.LogError((object)$"[DoomMode] Harmony patch failed: {arg}");
			}
			DoomNet.Create();
			ActionNet.Create();
			MonsterRegistry.Create();
			WeaponManager.Create();
			RemotePlayerWeapons.Create();
			WeaponShop.Create();
			PvpRespawn.Create();
			HeldItemPose.Create();
			EpicMusic.Create();
			DamageSystem.HookHost();
			BfgProjectile.HookNet();
			GrenadeProjectile.HookNet();
			ActionCameraSpawner.Create();
			ActionVideoRecorder.Create();
			ActionCamera.Create();
			ActionRoundManager.Create();
			ActionContentTracker.Create();
			GameObject val = new GameObject("ContentWarningDoom.Hub");
			Object.DontDestroyOnLoad((Object)val);
			val.AddComponent<DoomController>();
			val.AddComponent<DoomHUD>();
			val.AddComponent<DoomDebugUI>();
			val.AddComponent<PlayerCombatController>();
			val.AddComponent<DoomPlayerMovement>();
			val.AddComponent<ActionHUD>();
			SceneManager.sceneLoaded += OnSceneLoaded;
			PluginInfo info = ((BaseUnityPlugin)this).Info;
			object obj;
			if (info == null)
			{
				obj = null;
			}
			else
			{
				BepInPlugin metadata = info.Metadata;
				obj = ((metadata == null) ? null : metadata.Version?.ToString());
			}
			if (obj == null)
			{
				obj = "?";
			}
			string text = (string)obj;
			Log.LogInfo((object)("[DoomMode] ContentWarningDoom " + text + " loaded. Alt+K = Doom Mode (host), Alt+O = debug overlay."));
			ViralityCompat.LogStatus();
		}

		private void OnDestroy()
		{
			SceneManager.sceneLoaded -= OnSceneLoaded;
			Harmony harmony = _harmony;
			if (harmony != null)
			{
				harmony.UnpatchSelf();
			}
		}

		private void OnSceneLoaded(Scene scene, LoadSceneMode mode)
		{
			MonsterRegistry.Instance?.Clear();
			if (DoomModeActive)
			{
				CurrentSpawnMultiplier = Mathf.Max(1f, DoomConfig.MonsterSpawnMultiplier.Value);
				WeaponManager.Instance?.OnSceneReloaded();
				LogMode("scene '" + ((Scene)(ref scene)).name + "' loaded — Doom Mode stays ON, re-arming.");
			}
		}

		public static void LogMode(string m)
		{
			if (DoomConfig.DebugLogging.Value)
			{
				Log.LogInfo((object)("[DoomMode] " + m));
			}
		}

		public static void LogWeapon(string m)
		{
			if (DoomConfig.DebugLogging.Value)
			{
				Log.LogInfo((object)("[DoomWeapon] " + m));
			}
		}

		public static void LogDamage(string m)
		{
			if (DoomConfig.DebugLogging.Value)
			{
				Log.LogInfo((object)("[DoomDamage] " + m));
			}
		}

		public static void LogMonster(string m)
		{
			if (DoomConfig.DebugLogging.Value)
			{
				Log.LogInfo((object)("[DoomMonster] " + m));
			}
		}

		public static void LogNetwork(string m)
		{
			if (DoomConfig.DebugLogging.Value)
			{
				Log.LogInfo((object)("[DoomNetwork] " + m));
			}
		}

		public static void LogSpawn(string m)
		{
			if (DoomConfig.DebugLogging.Value)
			{
				Log.LogInfo((object)("[DoomSpawn] " + m));
			}
		}

		public static void HudHitMarker()
		{
			DoomHUD.Instance?.PingHit();
		}

		public static void HudHeadshot()
		{
			DoomHUD.Instance?.PingHeadshot();
		}

		public static void HudKillMarker()
		{
			DoomHUD.Instance?.PingKill();
		}

		public static void HudLocalKill()
		{
			DoomHUD.Instance?.PingLocalKill();
		}
	}
}
namespace ContentWarningDoom.Weapons
{
	public class GrenadeProjectile : MonoBehaviour
	{
		private Vector3 _vel;

		private int _ownerActor;

		private bool _authoritative;

		private float _fuse;

		private int _bounces;

		private static bool _hooked;

		public static void HookNet()
		{
			if (_hooked)
			{
				return;
			}
			_hooked = true;
			DoomNet.OnGrenadeSpawn += delegate(int actor, Vector3 pos, Vector3 vel)
			{
				//IL_0009: 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)
				if (actor != DoomNet.LocalActor)
				{
					SpawnLocal(pos, vel, actor);
				}
			};
		}

		public static GrenadeProjectile SpawnLocal(Vector3 pos, Vector3 vel, int ownerActor)
		{
			//IL_002d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0039: 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_007c: 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_0091: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a0: Expected O, but got Unknown
			//IL_00ce: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d3: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e8: Unknown result type (might be due to invalid IL or missing references)
			//IL_00f7: Expected O, but got Unknown
			//IL_00fd: Unknown result type (might be due to invalid IL or missing references)
			//IL_00fe: Unknown result type (might be due to invalid IL or missing references)
			GameObject obj = GameObject.CreatePrimitive((PrimitiveType)0);
			((Object)obj).name = "DoomGrenade";
			Collider component = obj.GetComponent<Collider>();
			if ((Object)(object)component != (Object)null)
			{
				Object.Destroy((Object)(object)component);
			}
			obj.transform.position = pos;
			obj.transform.localScale = Vector3.one * 0.25f;
			MeshRenderer component2 = obj.GetComponent<MeshRenderer>();
			Shader val = Shader.Find("Universal Render Pipeline/Lit") ?? Shader.Find("Standard") ?? Shader.Find("Unlit/Color");
			((Renderer)component2).material = new Material(val)
			{
				color = new Color(0.15f, 0.35f, 0.1f)
			};
			((Renderer)component2).shadowCastingMode = (ShadowCastingMode)0;
			TrailRenderer obj2 = obj.AddComponent<TrailRenderer>();
			obj2.time = 0.2f;
			obj2.startWidth = 0.12f;
			obj2.endWidth = 0f;
			((Renderer)obj2).material = new Material(val)
			{
				color = new Color(1f, 0.6f, 0.2f, 0.5f)
			};
			GrenadeProjectile grenadeProjectile = obj.AddComponent<GrenadeProjectile>();
			grenadeProjectile._vel = vel;
			grenadeProjectile._ownerActor = ownerActor;
			grenadeProjectile._authoritative = DoomNet.IsHost;
			grenadeProjectile._fuse = DoomConfig.GrenadeFuse.Value;
			return grenadeProjectile;
		}

		private void Update()
		{
			//IL_0008: Unknown result type (might be due to invalid IL or missing references)
			//IL_000d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0013: Unknown result type (might be due to invalid IL or missing references)
			//IL_0018: Unknown result type (might be due to invalid IL or missing references)
			//IL_001d: Unknown result type (might be due to invalid IL or missing references)
			//IL_004f: 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_0054: Unknown result type (might be due to invalid IL or missing references)
			//IL_005b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0060: Unknown result type (might be due to invalid IL or missing references)
			//IL_0127: Unknown result type (might be due to invalid IL or missing references)
			//IL_012d: 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_0138: Unknown result type (might be due to invalid IL or missing references)
			//IL_0164: 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_00e3: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ed: Unknown result type (might be due to invalid IL or missing references)
			//IL_00f2: Unknown result type (might be due to invalid IL or missing references)
			//IL_00fe: Unknown result type (might be due to invalid IL or missing references)
			//IL_0105: Unknown result type (might be due to invalid IL or missing references)
			//IL_010a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0114: Unknown result type (might be due to invalid IL or missing references)
			//IL_0119: Unknown result type (might be due to invalid IL or missing references)
			//IL_00bb: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a4: Unknown result type (might be due to invalid IL or missing references)
			float deltaTime = Time.deltaTime;
			_vel += Physics.gravity * deltaTime;
			float num = ((Vector3)(ref _vel)).magnitude * deltaTime;
			Vector3 val = ((((Vector3)(ref _vel)).sqrMagnitude > 0.0001f) ? ((Vector3)(ref _vel)).normalized : Vector3.down);
			RaycastHit val2 = default(RaycastHit);
			if (Physics.Raycast(((Component)this).transform.position, val, ref val2, num + 0.2f, -1, (QueryTriggerInteraction)1))
			{
				if ((Object)(object)MonsterRegistry.Instance != (Object)null && MonsterRegistry.Instance.TryGetByCollider(((RaycastHit)(ref val2)).collider, out var h) && h.Alive)
				{
					Detonate(((RaycastHit)(ref val2)).point);
					return;
				}
				if (_bounces >= 1)
				{
					Detonate(((RaycastHit)(ref val2)).point);
					return;
				}
				_bounces++;
				((Component)this).transform.position = ((RaycastHit)(ref val2)).point + ((RaycastHit)(ref val2)).normal * 0.1f;
				_vel = Vector3.Reflect(_vel, ((RaycastHit)(ref val2)).normal) * 0.45f;
			}
			else
			{
				Transform transform = ((Component)this).transform;
				transform.position += _vel * deltaTime;
			}
			_fuse -= deltaTime;
			if (_fuse <= 0f)
			{
				Detonate(((Component)this).transform.position);
			}
		}

		private void Detonate(Vector3 at)
		{
			//IL_0092: 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_001b: Unknown result type (might be due to invalid IL or missing references)
			//IL_004d: Unknown result type (might be due to invalid IL or missing references)
			//IL_003c: Unknown result type (might be due to invalid IL or missing references)
			if (_authoritative)
			{
				MonsterRegistry instance = MonsterRegistry.Instance;
				if ((Object)(object)instance != (Object)null)
				{
					MonsterHealth monsterHealth = instance.Nearest(at, 1.4f);
					if (monsterHealth != null)
					{
						DamageSystem.ApplyToHealth(monsterHealth, DoomConfig.GrenadeDirectDamage.Value, ((Vector3)(ref _vel)).normalized, DamageType.Explosion, _ownerActor);
					}
					DamageSystem.ApplyRadius(at, DoomConfig.GrenadeRadius.Value, DoomConfig.GrenadeExplosionDamage.Value, DamageType.Explosion, _ownerActor);
				}
				Plugin.LogWeapon($"grenade detonated at {at} (r={DoomConfig.GrenadeRadius.Value})");
			}
			GrenadeBlast.Play(at, DoomConfig.GrenadeRadius.Value);
			Object.Destroy((Object)(object)((Component)this).gameObject);
		}
	}
	internal static class GrenadeBlast
	{
		public static void Play(Vector3 at, float radius)
		{
			//IL_0005: 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)
			//IL_0016: 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_0054: Unknown result type (might be due to invalid IL or missing references)
			//IL_0055: Unknown result type (might be due to invalid IL or missing references)
			//IL_005f: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b5: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c1: Unknown result type (might be due to invalid IL or missing references)
			//IL_00cb: 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_0108: Unknown result type (might be due to invalid IL or missing references)
			//IL_0118: Unknown result type (might be due to invalid IL or missing references)
			//IL_0123: Expected O, but got Unknown
			//IL_0150: Unknown result type (might be due to invalid IL or missing references)
			//IL_015a: Unknown result type (might be due to invalid IL or missing references)
			//IL_01b5: Unknown result type (might be due to invalid IL or missing references)
			//IL_01d0: Unknown result type (might be due to invalid IL or missing references)
			//IL_01e1: Unknown result type (might be due to invalid IL or missing references)
			//IL_01e6: Unknown result type (might be due to invalid IL or missing references)
			//IL_01fb: Unknown result type (might be due to invalid IL or missing references)
			//IL_0207: Expected O, but got Unknown
			GameObject val = new GameObject("DoomGrenadeBlast");
			val.transform.position = at;
			Light obj = val.AddComponent<Light>();
			obj.type = (LightType)2;
			obj.range = radius * 3f;
			obj.intensity = 20f;
			obj.color = new Color(1f, 0.6f, 0.25f);
			ImpactEffects.SpawnWorld(at, Vector3.up);
			BloodEffects.SpawnDeath(at);
			val.AddComponent<GrenadeBlastAnim>().life = 0.4f;
			CameraKick.Shake(3.5f, 0.25f, 18f);
			GameObject obj2 = GameObject.CreatePrimitive((PrimitiveType)0);
			((Object)obj2).name = "DoomGrenadeFireball";
			Collider component = obj2.GetComponent<Collider>();
			if ((Object)(object)component != (Object)null)
			{
				Object.Destroy((Object)(object)component);
			}
			obj2.transform.position = at;
			obj2.transform.localScale = Vector3.one * 0.15f;
			MeshRenderer component2 = obj2.GetComponent<MeshRenderer>();
			Shader val2 = Shader.Find("Universal Render Pipeline/Lit") ?? Shader.Find("Standard") ?? Shader.Find("Unlit/Color");
			Material val3 = new Material(val2)
			{
				color = new Color(1f, 0.55f, 0.15f)
			};
			if (val3.HasProperty("_EmissionColor"))
			{
				val3.EnableKeyword("_EMISSION");
				val3.SetColor("_EmissionColor", new Color(1f, 0.5f, 0.1f) * 3f);
			}
			((Renderer)component2).material = val3;
			((Renderer)component2).shadowCastingMode = (ShadowCastingMode)0;
			obj2.AddComponent<FireballAnim>().Init(radius * 0.85f, 0.28f);
			GameObject obj3 = GameObject.CreatePrimitive((PrimitiveType)0);
			((Object)obj3).name = "DoomGrenadeShockwave";
			Collider component3 = obj3.GetComponent<Collider>();
			if ((Object)(object)component3 != (Object)null)
			{
				Object.Destroy((Object)(object)component3);
			}
			obj3.transform.position = at;
			obj3.transform.localScale = new Vector3(0.15f, 0.03f, 0.15f);
			MeshRenderer component4 = obj3.GetComponent<MeshRenderer>();
			Material material = new Material(val2)
			{
				color = new Color(1f, 0.8f, 0.5f, 0.6f)
			};
			((Renderer)component4).material = material;
			((Renderer)component4).shadowCastingMode = (ShadowCastingMode)0;
			obj3.AddComponent<FireballAnim>().Init(radius * 1.6f, 0.35f, flattenY: true);
		}
	}
	internal class GrenadeBlastAnim : MonoBehaviour
	{
		public float life = 0.4f;

		private float _t;

		private Light _l;

		private void Awake()
		{
			_l = ((Component)this).GetComponent<Light>();
		}

		private void Update()
		{
			_t += Time.deltaTime;
			if ((Object)(object)_l != (Object)null)
			{
				_l.intensity = Mathf.Lerp(20f, 0f, _t / life);
			}
			if (_t >= life)
			{
				Object.Destroy((Object)(object)((Component)this).gameObject);
			}
		}
	}
	internal class FireballAnim : MonoBehaviour
	{
		private float _maxScale;

		private float _life;

		private float _t;

		private bool _flattenY;

		private MeshRenderer _mr;

		private Color _startColor;

		public void Init(float maxScale, float life, bool flattenY = false)
		{
			//IL_004f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0054: Unknown result type (might be due to invalid IL or missing references)
			_maxScale = Mathf.Max(0.05f, maxScale);
			_life = Mathf.Max(0.05f, life);
			_flattenY = flattenY;
			_mr = ((Component)this).GetComponent<MeshRenderer>();
			if ((Object)(object)_mr != (Object)null)
			{
				_startColor = ((Renderer)_mr).material.color;
			}
		}

		private void Update()
		{
			//IL_0071: 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_0061: Unknown result type (might be due to invalid IL or missing references)
			//IL_008d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0092: Unknown result type (might be due to invalid IL or missing references)
			//IL_00bb: Unknown result type (might be due to invalid IL or missing references)
			//IL_00f8: Unknown result type (might be due to invalid IL or missing references)
			//IL_0104: Unknown result type (might be due to invalid IL or missing references)
			_t += Time.deltaTime;
			float num = Mathf.Clamp01(_t / _life);
			float num2 = 1f - (1f - num) * (1f - num);
			float num3 = Mathf.Lerp(0.15f, _maxScale, num2);
			((Component)this).transform.localScale = (Vector3)(_flattenY ? new Vector3(num3, num3 * 0.2f, num3) : (Vector3.one * num3));
			if ((Object)(object)_mr != (Object)null)
			{
				Color startColor = _startColor;
				startColor.a = Mathf.Lerp(_startColor.a, 0f, num);
				((Renderer)_mr).material.color = startColor;
				if (((Renderer)_mr).material.HasProperty("_EmissionColor"))
				{
					((Renderer)_mr).material.SetColor("_EmissionColor", ((Renderer)_mr).material.GetColor("_EmissionColor") * (1f - num));
				}
			}
			if (_t >= _life)
			{
				Object.Destroy((Object)(object)((Component)this).gameObject);
			}
		}
	}
	public static class ObjModelLoader
	{
		public sealed class Model
		{
			public Mesh mesh;

			public Material[] materials;
		}

		private static readonly Dictionary<string, Model> _cache = new Dictionary<string, Model>();

		private static string _dir;

		public static string ModelsDir
		{
			get
			{
				if (_dir != null)
				{
					return _dir;
				}
				try
				{
					_dir = Path.Combine(Path.GetDirectoryName(typeof(Plugin).Assembly.Location) ?? ".", "models");
				}
				catch
				{
					_dir = "models";
				}
				return _dir;
			}
		}

		public static bool Exists(string objFileNameNoExt)
		{
			return File.Exists(Path.Combine(ModelsDir, objFileNameNoExt + ".obj"));
		}

		public static Model Load(string objFileNameNoExt)
		{
			if (_cache.TryGetValue(objFileNameNoExt, out var value))
			{
				return value;
			}
			value = null;
			try
			{
				string path = Path.Combine(ModelsDir, objFileNameNoExt + ".obj");
				if (!File.Exists(path))
				{
					_cache[objFileNameNoExt] = null;
					return null;
				}
				value = Parse(File.ReadAllLines(path), ModelsDir);
			}
			catch (Exception ex)
			{
				Plugin.Log.LogWarning((object)("[DoomWeapon] OBJ load failed for " + objFileNameNoExt + ": " + ex.Message));
				value = null;
			}
			_cache[objFileNameNoExt] = value;
			return value;
		}

		private static Model Parse(string[] lines, string dir)
		{
			//IL_0289: Unknown result type (might be due to invalid IL or missing references)
			//IL_028e: Unknown result type (might be due to invalid IL or missing references)
			//IL_029a: Expected O, but got Unknown
			//IL_012f: Unknown result type (might be due to invalid IL or missing references)
			//IL_015f: Unknown result type (might be due to invalid IL or missing references)
			//IL_038b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0384: Unknown result type (might be due to invalid IL or missing references)
			//IL_038d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0391: Unknown result type (might be due to invalid IL or missing references)
			//IL_0396: Unknown result type (might be due to invalid IL or missing references)
			//IL_03b5: Expected O, but got Unknown
			//IL_03b7: Unknown result type (might be due to invalid IL or missing references)
			//IL_03d3: Unknown result type (might be due to invalid IL or missing references)
			List<Vector3> pos = new List<Vector3>();
			List<Vector3> nrm = new List<Vector3>();
			List<string> matNames = new List<string>();
			Dictionary<string, int> matIndexByName = new Dictionary<string, int>();
			List<List<int>> tris = new List<List<int>>();
			Dictionary<long, int> vmap = new Dictionary<long, int>();
			List<Vector3> outPos = new List<Vector3>();
			List<Vector3> outNrm = new List<Vector3>();
			int num = -1;
			string text = null;
			foreach (string text2 in lines)
			{
				if (string.IsNullOrEmpty(text2) || text2[0] == '#')
				{
					continue;
				}
				string[] array = text2.Split((char[]?)null, StringSplitOptions.RemoveEmptyEntries);
				if (array.Length == 0)
				{
					continue;
				}
				switch (array[0])
				{
				case "mtllib":
					text = text2.Substring(7).Trim();
					break;
				case "v":
					pos.Add(new Vector3(F(array[1]), F(array[2]), F(array[3])));
					break;
				case "vn":
					nrm.Add(new Vector3(F(array[1]), F(array[2]), F(array[3])));
					break;
				case "usemtl":
					num = EnsureSub((array.Length > 1) ? array[1] : "default");
					break;
				case "f":
				{
					if (num < 0)
					{
						num = EnsureSub("default");
					}
					int num2 = array.Length - 1;
					if (num2 >= 3)
					{
						int[] array2 = new int[num2];
						for (int j = 0; j < num2; j++)
						{
							string[] array3 = array[j + 1].Split('/');
							int p = int.Parse(array3[0], CultureInfo.InvariantCulture);
							int n = ((array3.Length >= 3 && array3[2].Length > 0) ? int.Parse(array3[2], CultureInfo.InvariantCulture) : int.MinValue);
							array2[j] = Vert(p, n);
						}
						List<int> list = tris[num];
						for (int k = 1; k < num2 - 1; k++)
						{
							list.Add(array2[0]);
							list.Add(array2[k]);
							list.Add(array2[k + 1]);
						}
					}
					break;
				}
				}
			}
			if (outPos.Count == 0)
			{
				return null;
			}
			Mesh val = new Mesh
			{
				name = "DoomGunMesh"
			};
			if (outPos.Count > 65000)
			{
				val.indexFormat = (IndexFormat)1;
			}
			val.SetVertices(outPos);
			val.SetNormals(outNrm);
			val.subMeshCount = matNames.Count;
			for (int l = 0; l < matNames.Count; l++)
			{
				val.SetTriangles(tris[l], l, true);
			}
			val.RecalculateBounds();
			Dictionary<string, Color> dictionary = ((text != null) ? LoadMtl(Path.Combine(dir, text)) : new Dictionary<string, Color>());
			Material[] array4 = (Material[])(object)new Material[matNames.Count];
			Shader val2 = Shader.Find("Universal Render Pipeline/Lit") ?? Shader.Find("Standard") ?? Shader.Find("Unlit/Color");
			for (int m = 0; m < matNames.Count; m++)
			{
				Color value;
				Color val3 = (dictionary.TryGetValue(matNames[m], out value) ? value : Color.gray);
				Material val4 = new Material(val2)
				{
					name = "DoomGunMat_" + matNames[m]
				};
				val4.color = val3;
				if (val4.HasProperty("_BaseColor"))
				{
					val4.SetColor("_BaseColor", val3);
				}
				if (val4.HasProperty("_Metallic"))
				{
					val4.SetFloat("_Metallic", 0.5f);
				}
				if (val4.HasProperty("_Smoothness"))
				{
					val4.SetFloat("_Smoothness", 0.45f);
				}
				if (val4.HasProperty("_Glossiness"))
				{
					val4.SetFloat("_Glossiness", 0.45f);
				}
				array4[m] = val4;
			}
			return new Model
			{
				mesh = val,
				materials = array4
			};
			int EnsureSub(string name)
			{
				if (!matIndexByName.TryGetValue(name, out var value2))
				{
					value2 = matNames.Count;
					matIndexByName[name] = value2;
					matNames.Add(name);
					tris.Add(new List<int>());
				}
				return value2;
			}
			int Vert(int num3, int num4)
			{
				//IL_0096: Unknown result type (might be due to invalid IL or missing references)
				//IL_00a4: Unknown result type (might be due to invalid IL or missing references)
				//IL_00ce: Unknown result type (might be due to invalid IL or missing references)
				//IL_00dc: Unknown result type (might be due to invalid IL or missing references)
				num3 = ((num3 >= 0) ? (num3 - 1) : (pos.Count + num3));
				if (num4 != int.MinValue)
				{
					num4 = ((num4 >= 0) ? (num4 - 1) : (nrm.Count + num4));
				}
				long key = ((long)(num3 & 0xFFFFF) << 20) | (uint)((num4 == int.MinValue) ? 1048575 : (num4 & 0xFFFFF));
				if (vmap.TryGetValue(key, out var value2))
				{
					return value2;
				}
				value2 = outPos.Count;
				outPos.Add((num3 >= 0 && num3 < pos.Count) ? pos[num3] : Vector3.zero);
				outNrm.Add((num4 != int.MinValue && num4 >= 0 && num4 < nrm.Count) ? nrm[num4] : Vector3.up);
				vmap[key] = value2;
				return value2;
			}
		}

		private static Dictionary<string, Color> LoadMtl(string path)
		{
			//IL_00bc: Unknown result type (might be due to invalid IL or missing references)
			//IL_0079: Unknown result type (might be due to invalid IL or missing references)
			Dictionary<string, Color> dictionary = new Dictionary<string, Color>();
			try
			{
				if (!File.Exists(path))
				{
					return dictionary;
				}
				string text = null;
				string[] array = File.ReadAllLines(path);
				foreach (string text2 in array)
				{
					string[] array2 = text2.Split((char[]?)null, StringSplitOptions.RemoveEmptyEntries);
					if (array2.Length == 0 || text2[0] == '#')
					{
						continue;
					}
					if (array2[0] == "newmtl")
					{
						text = ((array2.Length > 1) ? array2[1] : "default");
						if (!dictionary.ContainsKey(text))
						{
							dictionary[text] = Color.gray;
						}
					}
					else if (array2[0] == "Kd" && text != null && array2.Length >= 4)
					{
						dictionary[text] = new Color(F(array2[1]), F(array2[2]), F(array2[3]));
					}
				}
			}
			catch
			{
			}
			return dictionary;
		}

		private static float F(string s)
		{
			return float.Parse(s, NumberStyles.Float, CultureInfo.InvariantCulture);
		}
	}
	public class BfgProjectile : MonoBehaviour
	{
		private Vector3 _dir;

		private int _ownerActor;

		private bool _authoritative;

		private float _life = 6f;

		private float _trackTimer;

		private static bool _netHooked;

		public static void HookNet()
		{
			if (_netHooked)
			{
				return;
			}
			_netHooked = true;
			DoomNet.OnBfgSpawn += delegate(int actor, Vector3 pos, Vector3 dir)
			{
				//IL_0009: 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)
				if (actor != DoomNet.LocalActor)
				{
					SpawnLocal(pos, dir, actor, isOwner: false);
				}
			};
			DoomNet.OnBfgExplode += delegate(Vector3 pos)
			{
				//IL_0000: Unknown result type (might be due to invalid IL or missing references)
				Explosion.Play(pos);
				BfgProjectile[] array = Object.FindObjectsOfType<BfgProjectile>();
				foreach (BfgProjectile bfgProjectile in array)
				{
					if (!bfgProjectile._authoritative)
					{
						Object.Destroy((Object)(object)((Component)bfgProjectile).gameObject);
					}
				}
			};
		}

		public static BfgProjectile SpawnLocal(Vector3 pos, Vector3 dir, int ownerActor, bool isOwner)
		{
			//IL_002d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0039: 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_007b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0080: Unknown result type (might be due to invalid IL or missing references)
			//IL_0095: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a4: Expected O, but got Unknown
			//IL_00d6: Unknown result type (might be due to invalid IL or missing references)
			//IL_0108: Unknown result type (might be due to invalid IL or missing references)
			//IL_010d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0122: Unknown result type (might be due to invalid IL or missing references)
			//IL_0131: Expected O, but got Unknown
			//IL_0139: Unknown result type (might be due to invalid IL or missing references)
			//IL_013e: Unknown result type (might be due to invalid IL or missing references)
			GameObject obj = GameObject.CreatePrimitive((PrimitiveType)0);
			((Object)obj).name = "DoomBFGOrb";
			Collider component = obj.GetComponent<Collider>();
			if ((Object)(object)component != (Object)null)
			{
				Object.Destroy((Object)(object)component);
			}
			obj.transform.position = pos;
			obj.transform.localScale = Vector3.one * 1.4f;
			MeshRenderer component2 = obj.GetComponent<MeshRenderer>();
			Shader val = Shader.Find("Unlit/Color") ?? Shader.Find("Sprites/Default") ?? Shader.Find("Standard");
			((Renderer)component2).material = new Material(val)
			{
				color = new Color(0.4f, 1f, 0.35f, 1f)
			};
			Light obj2 = obj.AddComponent<Light>();
			obj2.type = (LightType)2;
			obj2.range = 14f;
			obj2.intensity = 6f;
			obj2.color = new Color(0.4f, 1f, 0.4f);
			TrailRenderer obj3 = obj.AddComponent<TrailRenderer>();
			obj3.time = 0.35f;
			obj3.startWidth = 1.1f;
			obj3.endWidth = 0f;
			((Renderer)obj3).material = new Material(val)
			{
				color = new Color(0.4f, 1f, 0.4f, 0.6f)
			};
			BfgProjectile bfgProjectile = obj.AddComponent<BfgProjectile>();
			bfgProjectile._dir = ((Vector3)(ref dir)).normalized;
			bfgProjectile._ownerActor = ownerActor;
			bfgProjectile._authoritative = DoomNet.IsHost;
			return bfgProjectile;
		}

		private void Update()
		{
			//IL_0019: Unknown result type (might be due to invalid IL or missing references)
			//IL_001f: Unknown result type (might be due to invalid IL or missing references)
			//IL_004b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0051: Unknown result type (might be due to invalid IL or missing references)
			//IL_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_0039: Unknown result type (might be due to invalid IL or missing references)
			//IL_0088: Unknown result type (might be due to invalid IL or missing references)
			//IL_00bc: Unknown result type (might be due to invalid IL or missing references)
			float deltaTime = Time.deltaTime;
			float num = DoomConfig.BFGProjectileSpeed.Value * deltaTime;
			RaycastHit val = default(RaycastHit);
			if (Physics.Raycast(((Component)this).transform.position, _dir, ref val, num + 0.7f, -1, (QueryTriggerInteraction)1))
			{
				Detonate(((RaycastHit)(ref val)).point);
				return;
			}
			Transform transform = ((Component)this).transform;
			transform.position += _dir * num;
			_life -= deltaTime;
			if (_life <= 0f)
			{
				Detonate(((Component)this).transform.position);
			}
			else if (_authoritative)
			{
				_trackTimer += deltaTime;
				if (_trackTimer >= 0.25f)
				{
					DamageSystem.ApplyRadius(((Component)this).transform.position, DoomConfig.BFGRadius.Value * 0.6f, DoomConfig.BFGTrackingDamage.Value * _trackTimer, DamageType.BFG, _ownerActor);
					_trackTimer = 0f;
				}
			}
		}

		private void Detonate(Vector3 at)
		{
			//IL_0093: 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_0074: Unknown result type (might be due to invalid IL or missing references)
			//IL_001b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0048: Unknown result type (might be due to invalid IL or missing references)
			//IL_0037: Unknown result type (might be due to invalid IL or missing references)
			if (_authoritative)
			{
				MonsterRegistry instance = MonsterRegistry.Instance;
				if ((Object)(object)instance != (Object)null)
				{
					MonsterHealth monsterHealth = instance.Nearest(at, 3.5f);
					if (monsterHealth != null)
					{
						DamageSystem.ApplyToHealth(monsterHealth, DoomConfig.BFGDirectDamage.Value, _dir, DamageType.BFG, _ownerActor);
					}
					DamageSystem.ApplyRadius(at, DoomConfig.BFGRadius.Value, DoomConfig.BFGExplosionDamage.Value, DamageType.Explosion, _ownerActor);
				}
				DoomNet.SendBfgExplode(at);
				Plugin.LogWeapon($"BFG detonated at {at} (r={DoomConfig.BFGRadius.Value})");
			}
			Explosion.Play(at);
			Object.Destroy((Object)(object)((Component)this).gameObject);
		}
	}
	internal static class Explosion
	{
		public static void Play(Vector3 at)
		{
			//IL_0005: Unknown result type (might be due to invalid IL or missing references)
			//IL_000b: Expected O, but got Unknown
			//IL_0011: Unknown result type (might be due to invalid IL or missing references)
			//IL_0054: Unknown result type (might be due to invalid IL or missing references)
			//IL_0092: Unknown result type (might be due to invalid IL or missing references)
			//IL_009c: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d3: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d8: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ed: Unknown result type (might be due to invalid IL or missing references)
			//IL_00fc: Expected O, but got Unknown
			GameObject val = new GameObject("DoomBFGBlast");
			val.transform.position = at;
			Light obj = val.AddComponent<Light>();
			obj.type = (LightType)2;
			obj.range = DoomConfig.BFGRadius.Value * 2.5f;
			obj.intensity = 18f;
			obj.color = new Color(0.5f, 1f, 0.5f);
			GameObject obj2 = GameObject.CreatePrimitive((PrimitiveType)0);
			Collider component = obj2.GetComponent<Collider>();
			if ((Object)(object)component != (Object)null)
			{
				Object.Destroy((Object)(object)component);
			}
			obj2.transform.SetParent(val.transform, false);
			obj2.transform.localScale = Vector3.one * 0.5f;
			Shader val2 = Shader.Find("Unlit/Color") ?? Shader.Find("Sprites/Default") ?? Shader.Find("Standard");
			((Renderer)obj2.GetComponent<MeshRenderer>()).material = new Material(val2)
			{
				color = new Color(0.6f, 1f, 0.6f, 1f)
			};
			val.AddComponent<BlastAnim>().radius = DoomConfig.BFGRadius.Value;
			CameraKick.Shake(6f, 0.5f, 25f);
		}
	}
	internal class BlastAnim : MonoBehaviour
	{
		public float radius = 15f;

		private float _t;

		private Light _l;

		private Transform _ball;

		private void Awake()
		{
			_l = ((Component)this).GetComponent<Light>();
			if (((Component)this).transform.childCount > 0)
			{
				_ball = ((Component)this).transform.GetChild(0);
			}
		}

		private void Update()
		{
			//IL_0038: 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)
			_t += Time.deltaTime * 2.2f;
			float num = Mathf.Clamp01(_t);
			if ((Object)(object)_ball != (Object)null)
			{
				_ball.localScale = Vector3.one * Mathf.Lerp(0.5f, radius * 2f, num);
			}
			if ((Object)(object)_l != (Object)null)
			{
				_l.intensity = Mathf.Lerp(18f, 0f, num);
			}
			if (_t >= 1f)
			{
				Object.Destroy((Object)(object)((Component)this).gameObject);
			}
		}
	}
	public class RemotePlayerWeapons : MonoBehaviour
	{
		private sealed class Entry
		{
			public Player player;

			public GameObject go;

			public int weaponId = -1;
		}

		private readonly Dictionary<int, Entry> _byActor = new Dictionary<int, Entry>();

		private readonly List<int> _scratch = new List<int>();

		public static RemotePlayerWeapons Instance { get; private set; }

		public static void Create()
		{
			//IL_0013: Unknown result type (might be due to invalid IL or missing references)
			//IL_0018: Unknown result type (might be due to invalid IL or missing references)
			//IL_001e: Expected O, but got Unknown
			if (!((Object)(object)Instance != (Object)null))
			{
				GameObject val = new GameObject("ContentWarningDoom.RemotePlayerWeapons");
				Object.DontDestroyOnLoad((Object)val);
				Instance = val.AddComponent<RemotePlayerWeapons>();
			}
		}

		private void OnEnable()
		{
			DoomNet.OnWeaponEquip += HandleEquip;
			DoomNet.OnWeaponFire += HandleFire;
		}

		private void OnDisable()
		{
			DoomNet.OnWeaponEquip -= HandleEquip;
			DoomNet.OnWeaponFire -= HandleFire;
		}

		private void OnDestroy()
		{
			if ((Object)(object)Instance == (Object)(object)this)
			{
				Instance = null;
			}
		}

		private void HandleEquip(int actor, byte weaponId)
		{
			Apply(actor, weaponId);
		}

		private void HandleFire(int actor, byte weaponId, Vector3 origin, Vector3 dir)
		{
			//IL_000b: Unknown result type (might be due to invalid IL or missing references)
			//IL_000c: Unknown result type (might be due to invalid IL or missing references)
			Apply(actor, weaponId);
			SpawnRemoteShotFx(actor, weaponId, origin, dir);
		}

		private void SpawnRemoteShotFx(int actor, int weaponId, Vector3 origin, Vector3 dir)
		{
			//IL_0037: Unknown result type (might be due to invalid IL or missing references)
			//IL_003c: Unknown result type (might be due to invalid IL or missing references)
			//IL_003e: Unknown result type (might be due to invalid IL or missing references)
			//IL_003f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0046: 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_0097: Unknown result type (might be due to invalid IL or missing references)
			//IL_0098: Unknown result type (might be due to invalid IL or missing references)
			//IL_009b: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a0: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a5: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a6: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a7: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ae: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b3: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b8: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ce: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d4: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d5: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c8: Unknown result type (might be due to invalid IL or missing references)
			//IL_00cd: Unknown result type (might be due to invalid IL or missing references)
			//IL_007a: Unknown result type (might be due to invalid IL or missing references)
			//IL_007f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0086: Unknown result type (might be due to invalid IL or missing references)
			//IL_008b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0090: Unknown result type (might be due to invalid IL or missing references)
			if (DoomConfig.ShowRemotePlayerWeapons.Value && Plugin.DoomModeActive && actor != DoomNet.LocalActor && weaponId != 3 && weaponId != 5 && !(((Vector3)(ref dir)).sqrMagnitude < 0.0001f))
			{
				dir = ((Vector3)(ref dir)).normalized;
				Vector3 val = origin + dir * 0.5f;
				if (_byActor.TryGetValue(actor, out var value) && (Object)(object)value.go != (Object)null)
				{
					val = value.go.transform.position + dir * 0.25f;
				}
				float num = 120f;
				Vector3 to = origin + dir * num;
				RaycastHit val2 = default(RaycastHit);
				if (Physics.Raycast(origin + dir * 0.3f, dir, ref val2, num, -1, (QueryTriggerInteraction)1))
				{
					to = ((RaycastHit)(ref val2)).point;
				}
				ImpactEffects.RemoteMuzzle(val);
				ImpactEffects.Tracer(val, to);
			}
		}

		private void Apply(int actor, int weaponId)
		{
			//IL_0362: Unknown result type (might be due to invalid IL or missing references)
			//IL_0369: Expected O, but got Unknown
			//IL_0388: Unknown result type (might be due to invalid IL or missing references)
			//IL_038d: Unknown result type (might be due to invalid IL or missing references)
			//IL_038e: Unknown result type (might be due to invalid IL or missing references)
			//IL_03a9: Unknown result type (might be due to invalid IL or missing references)
			//IL_03ae: Unknown result type (might be due to invalid IL or missing references)
			//IL_03b9: Unknown result type (might be due to invalid IL or missing references)
			//IL_044c: Unknown result type (might be due to invalid IL or missing references)
			//IL_03d5: Unknown result type (might be due to invalid IL or missing references)
			//IL_03e2: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b7: Unknown result type (might be due to invalid IL or missing references)
			//IL_00bc: Unknown result type (might be due to invalid IL or missing references)
			if (!DoomConfig.ShowRemotePlayerWeapons.Value || !Plugin.DoomModeActive || actor == 0 || actor == DoomNet.LocalActor || weaponId < 0 || weaponId >= 11)
			{
				return;
			}
			if (!_byActor.TryGetValue(actor, out var value))
			{
				value = new Entry();
				_byActor[actor] = value;
			}
			if ((Object)(object)value.player == (Object)null)
			{
				value.player = ActionRoundManager.FindPlayerByActor(actor);
			}
			if ((Object)(object)value.player == (Object)null || ((Object)(object)value.go != (Object)null && value.weaponId == weaponId))
			{
				return;
			}
			if ((Object)(object)value.go != (Object)null)
			{
				Object.Destroy((Object)(object)value.go);
			}
			value.go = null;
			value.weaponId = -1;
			Transform val = null;
			Vector3 zero = Vector3.zero;
			string text = "?";
			try
			{
				if (value.player.refs != null && (Object)(object)value.player.refs.animator != (Object)null && value.player.refs.animator.isHuman)
				{
					val = value.player.refs.animator.GetBoneTransform((HumanBodyBones)18);
					if ((Object)(object)val != (Object)null)
					{
						text = "Animator.RightHand";
					}
				}
			}
			catch
			{
			}
			if ((Object)(object)val == (Object)null && value.player.refs != null && (Object)(object)value.player.refs.bodyMeshRenderer != (Object)null)
			{
				Transform[] bones = value.player.refs.bodyMeshRenderer.bones;
				if (bones != null)
				{
					Transform[] array = bones;
					foreach (Transform val2 in array)
					{
						if (!((Object)(object)val2 == (Object)null))
						{
							string text2 = ((Object)val2).name.ToLowerInvariant();
							bool num = text2.Contains("hand") || text2.Contains("wrist");
							bool flag = text2.EndsWith("_r") || text2.EndsWith(".r") || text2.EndsWith("_r_") || text2.Contains("right");
							if (num && flag)
							{
								val = val2;
								text = "bone:" + ((Object)val2).name;
								break;
							}
						}
					}
				}
			}
			if ((Object)(object)val == (Object)null && value.player.refs != null)
			{
				try
				{
					val = value.player.refs.IK_Hand_R;
				}
				catch
				{
				}
				if ((Object)(object)val != (Object)null)
				{
					text = "IK_Hand_R";
				}
			}
			if ((Object)(object)val == (Object)null)
			{
				val = PlayerHands.RightOf(value.player);
				if ((Object)(object)val != (Object)null)
				{
					text = "ragdoll.Hand_R";
				}
			}
			if ((Object)(object)val == (Object)null && value.player.refs != null && (Object)(object)value.player.refs.headPos != (Object)null)
			{
				val = value.player.refs.headPos;
				((Vector3)(ref zero))..ctor(0.24f, -0.34f, 0.22f);
				text = "headPos(fallback)";
			}
			if ((Object)(object)val == (Object)null)
			{
				Plugin.LogWeapon($"remote gun for actor {actor}: no anchor, skipped");
				return;
			}
			float muzzleForward;
			GameObject val3 = WeaponVisual.BuildGunMeshGO((WeaponId)weaponId, DoomConfig.GunModelScaleMul.Value * Mathf.Max(0.05f, DoomConfig.RemoteWeaponScaleMul.Value), out muzzleForward);
			if ((Object)(object)val3 == (Object)null)
			{
				Plugin.LogWeapon($"remote gun for actor {actor}: model {(WeaponId)weaponId} failed to load");
				return;
			}
			GameObject val4 = new GameObject("DoomRemoteGun");
			val4.transform.SetParent(val, false);
			val4.transform.localPosition = ParseVec(DoomConfig.RemoteWeaponOffset.Value) + zero;
			val4.transform.localRotation = Quaternion.Euler(ParseVec(DoomConfig.RemoteWeaponEuler.Value));
			float x = val.lossyScale.x;
			if (x > 0.0001f)
			{
				val4.transform.localScale = Vector3.one * (1f / x);
			}
			val3.transform.SetParent(val4.transform, false);
			WeaponVisual.SetLayer(val4, 0);
			value.go = val4;
			value.weaponId = weaponId;
			Plugin.LogWeapon($"remote gun for actor {actor}: {(WeaponId)weaponId} on {text} (handScale {x:0.###}, gunScale {val4.transform.localScale.x:0.###})");
		}

		private void Update()
		{
			if (!Plugin.DoomModeActive || !DoomConfig.ShowRemotePlayerWeapons.Value)
			{
				if (_byActor.Count > 0)
				{
					ClearAll();
				}
				return;
			}
			_scratch.Clear();
			foreach (KeyValuePair<int, Entry> item in _byActor)
			{
				Entry value = item.Value;
				if ((Object)(object)value.player == (Object)null || (Object)(object)value.go == (Object)null || (Object)(object)value.go.transform.parent == (Object)null)
				{
					_scratch.Add(item.Key);
				}
			}
			for (int i = 0; i < _scratch.Count; i++)
			{
				if (_byActor.TryGetValue(_scratch[i], out var value2) && (Object)(object)value2.go != (Object)null)
				{
					Object.Destroy((Object)(object)value2.go);
				}
				_byActor.Remove(_scratch[i]);
			}
		}

		private void ClearAll()
		{
			foreach (KeyValuePair<int, Entry> item in _byActor)
			{
				if ((Object)(object)item.Value.go != (Object)null)
				{
					Object.Destroy((Object)(object)item.Value.go);
				}
			}
			_byActor.Clear();
		}

		private static Vector3 ParseVec(string s)
		{
			//IL_0008: Unknown result type (might be due to invalid IL or missing references)
			//IL_0066: Unknown result type (might be due to invalid IL or missing references)
			//IL_001e: Unknown result type (might be due to invalid IL or missing references)
			if (string.IsNullOrEmpty(s))
			{
				return Vector3.zero;
			}
			string[] array = s.Split(',');
			if (array.Length != 3)
			{
				return Vector3.zero;
			}
			float.TryParse(array[0], NumberStyles.Float, CultureInfo.InvariantCulture, out var result);
			float.TryParse(array[1], NumberStyles.Float, CultureInfo.InvariantCulture, out var result2);
			float.TryParse(array[2], NumberStyles.Float, CultureInfo.InvariantCulture, out var result3);
			return new Vector3(result, result2, result3);
		}
	}
	public enum WeaponId : byte
	{
		Pistol,
		Shotgun,
		SuperShotgun,
		BFG,
		Minigun,
		GrenadeLauncher,
		Smg,
		AssaultRifle,
		Marksman,
		AutoShotgun,
		Crossbow
	}
	public class WeaponDef
	{
		public WeaponId Id;

		public string Name;

		public int MagSize;

		public int Reserve;

		public float ReloadTime;

		public float FireDelay;

		public float Range;

		public int Pellets;

		public float DamagePerShot;

		public float SpreadDeg;

		public DamageType DamageType;

		public float RecoilKick;

		public float HandRecoilForce;

		public bool Automatic;
	}
	public static class WeaponTable
	{
		public static WeaponDef Get(WeaponId id)
		{
			return id switch
			{
				WeaponId.Pistol => new WeaponDef
				{
					Id = id,
					Name = "PISTOL",
					MagSize = DoomConfig.PistolMagazine.Value,
					Reserve = DoomConfig.PistolReserve.Value,
					ReloadTime = DoomConfig.PistolReload.Value,
					FireDelay = 1f / Mathf.Max(0.1f, DoomConfig.PistolFireRate.Value),
					Range = DoomConfig.PistolRange.Value,
					Pellets = 1,
					DamagePerShot = DoomConfig.PistolDamage.Value,
					SpreadDeg = 0.4f,
					DamageType = DamageType.Bullet,
					RecoilKick = 1f,
					HandRecoilForce = 7f
				}, 
				WeaponId.Shotgun => new WeaponDef
				{
					Id = id,
					Name = "SHOTGUN",
					MagSize = DoomConfig.ShotgunMagazine.Value,
					Reserve = DoomConfig.ShotgunReserve.Value,
					ReloadTime = DoomConfig.ShotgunReload.Value,
					FireDelay = DoomConfig.ShotgunFireDelay.Value,
					Range = DoomConfig.ShotgunRange.Value,
					Pellets = DoomConfig.ShotgunPellets.Value,
					DamagePerShot = DoomConfig.ShotgunDamagePerPellet.Value,
					SpreadDeg = DoomConfig.ShotgunSpread.Value,
					DamageType = DamageType.Pellet,
					RecoilKick = 2.4f,
					HandRecoilForce = 20f
				}, 
				WeaponId.SuperShotgun => new WeaponDef
				{
					Id = id,
					Name = "SUPER SHOTGUN",
					MagSize = DoomConfig.SuperShotgunMagazine.Value,
					Reserve = DoomConfig.SuperShotgunReserve.Value,
					ReloadTime = DoomConfig.SuperShotgunReload.Value,
					FireDelay = DoomConfig.SuperShotgunFireDelay.Value,
					Range = DoomConfig.SuperShotgunRange.Value,
					Pellets = DoomConfig.SuperShotgunPellets.Value,
					DamagePerShot = DoomConfig.SuperShotgunDamagePerPellet.Value,
					SpreadDeg = DoomConfig.SuperShotgunSpread.Value,
					DamageType = DamageType.Pellet,
					RecoilKick = 4.5f,
					HandRecoilForce = 32f
				}, 
				WeaponId.Minigun => new WeaponDef
				{
					Id = id,
					Name = "MINIGUN",
					MagSize = DoomConfig.MinigunMagazine.Value,
					Reserve = DoomConfig.MinigunReserve.Value,
					ReloadTime = DoomConfig.MinigunReload.Value,
					FireDelay = 1f / Mathf.Max(1f, DoomConfig.MinigunFireRate.Value),
					Range = DoomConfig.MinigunRange.Value,
					Pellets = 1,
					DamagePerShot = DoomConfig.MinigunDamage.Value,
					SpreadDeg = DoomConfig.MinigunSpread.Value,
					DamageType = DamageType.Bullet,
					RecoilKick = 1.6f,
					HandRecoilForce = 5f
				}, 
				WeaponId.GrenadeLauncher => new WeaponDef
				{
					Id = id,
					Name = "GRENADE LAUNCHER",
					MagSize = DoomConfig.GrenadeMagazine.Value,
					Reserve = DoomConfig.GrenadeReserve.Value,
					ReloadTime = DoomConfig.GrenadeReload.Value,
					FireDelay = DoomConfig.GrenadeFireDelay.Value,
					Range = 400f,
					Pellets = 0,
					DamagePerShot = DoomConfig.GrenadeDirectDamage.Value,
					SpreadDeg = 0f,
					DamageType = DamageType.Explosion,
					RecoilKick = 3.2f,
					HandRecoilForce = 18f
				}, 
				WeaponId.Smg => new WeaponDef
				{
					Id = id,
					Name = "SMG",
					MagSize = 30,
					Reserve = 240,
					ReloadTime = 1.7f,
					FireDelay = 1f / 12f,
					Range = 60f,
					Pellets = 1,
					DamagePerShot = 13f,
					SpreadDeg = 2.4f,
					DamageType = DamageType.Bullet,
					RecoilKick = 1.1f,
					HandRecoilForce = 5f,
					Automatic = true
				}, 
				WeaponId.AssaultRifle => new WeaponDef
				{
					Id = id,
					Name = "ASSAULT RIFLE",
					MagSize = 24,
					Reserve = 180,
					ReloadTime = 2.1f,
					FireDelay = 0.125f,
					Range = 95f,
					Pellets = 1,
					DamagePerShot = 22f,
					SpreadDeg = 1.1f,
					DamageType = DamageType.Bullet,
					RecoilKick = 1.9f,
					HandRecoilForce = 10f,
					Automatic = true
				}, 
				WeaponId.Marksman => new WeaponDef
				{
					Id = id,
					Name = "MARKSMAN RIFLE",
					MagSize = 10,
					Reserve = 60,
					ReloadTime = 2.6f,
					FireDelay = 0.34f,
					Range = 160f,
					Pellets = 1,
					DamagePerShot = 68f,
					SpreadDeg = 0.12f,
					DamageType = DamageType.Bullet,
					RecoilKick = 3f,
					HandRecoilForce = 16f,
					Automatic = false
				}, 
				WeaponId.AutoShotgun => new WeaponDef
				{
					Id = id,
					Name = "AUTO SHOTGUN",
					MagSize = 8,
					Reserve = 64,
					ReloadTime = 3f,
					FireDelay = 0.5f,
					Range = 24f,
					Pellets = 9,
					DamagePerShot = 11f,
					SpreadDeg = 6.5f,
					DamageType = DamageType.Pellet,
					RecoilKick = 3f,
					HandRecoilForce = 22f,
					Automatic = false
				}, 
				WeaponId.Crossbow => new WeaponDef
				{
					Id = id,
					Name = "CROSSBOW",
					MagSize = 1,
					Reserve = 24,
					ReloadTime = 1.2f,
					FireDelay = 1f,
					Range = 130f,
					Pellets = 1,
					DamagePerShot = 130f,
					SpreadDeg = 0.05f,
					DamageType = DamageType.Bullet,
					RecoilKick = 2f,
					HandRecoilForce = 13f,
					Automatic = false
				}, 
				_ => new WeaponDef
				{
					Id = WeaponId.BFG,
					Name = "BFG 9000",
					MagSize = DoomConfig.BFGMagazine.Value,
					Reserve = DoomConfig.BFGReserve.Value,
					ReloadTime = DoomConfig.BFGReload.Value,
					FireDelay = DoomConfig.BFGFireDelay.Value,
					Range = 500f,
					Pellets = 0,
					DamagePerShot = DoomConfig.BFGDirectDamage.Value,
					SpreadDeg = 0f,
					DamageType = DamageType.BFG,
					RecoilKick = 5f,
					HandRecoilForce = 38f
				}, 
			};
		}
	}
	public abstract class WeaponBase
	{
		public WeaponDef Def;

		public int Mag;

		public int Reserve;

		private float _cooldown;

		private float _reloadTimer;

		public bool Reloading => _reloadTimer > 0f;

		public float ReloadProgress
		{
			get
			{
				if (!(Def.ReloadTime <= 0f))
				{
					return 1f - Mathf.Clamp01(_reloadTimer / Def.ReloadTime);
				}
				return 1f;
			}
		}

		public float RecoilImpulse { get; private set; }

		protected virtual bool IsAutomatic => false;

		protected WeaponBase(WeaponId id)
		{
			Def = WeaponTable.Get(id);
			Mag = Def.MagSize;
			Reserve = Def.Reserve;
		}

		public void Tick(float dt, bool firePressedThisFrame, bool fireHeld, bool reloadPressed, Vector3 origin, Vector3 dir)
		{
			//IL_009e: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a0: Unknown result type (might be due to invalid IL or missing references)
			if (_cooldown > 0f)
			{
				_cooldown -= dt;
			}
			if (_reloadTimer > 0f)
			{
				_reloadTimer -= dt;
				if (_reloadTimer <= 0f)
				{
					FinishReload();
				}
				return;
			}
			RecoilImpulse = Mathf.MoveTowards(RecoilImpulse, 0f, dt * 8f);
			if (reloadPressed)
			{
				TryStartReload();
			}
			else if ((IsAutomatic ? fireHeld : firePressedThisFrame) && _cooldown <= 0f)
			{
				if (Mag <= 0)
				{
					TryStartReload();
				}
				else
				{
					Fire(origin, dir);
				}
			}
		}

		private void Fire(Vector3 origin, Vector3 dir)
		{
			//IL_0076: Unknown result type (might be due to invalid IL or missing references)
			//IL_0077: Unknown result type (might be due to invalid IL or missing references)
			//IL_0088: Unknown result type (might be due to invalid IL or missing references)
			//IL_008f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0090: Unknown result type (might be due to invalid IL or missing references)
			Mag--;
			_cooldown = Def.FireDelay;
			RecoilImpulse = Mathf.Min(1f, RecoilImpulse + 1f);
			Plugin.LogWeapon($"{Def.Name} fired ({Mag}/{Reserve})");
			DoomNet.SendWeaponFire((byte)Def.Id, origin, dir);
			WeaponAudio.PlayFire(Def.Id, origin);
			DoFire(origin, dir);
		}

		protected abstract void DoFire(Vector3 origin, Vector3 dir);

		public void TryStartReload()
		{
			if (!(_reloadTimer > 0f) && Mag < Def.MagSize && Reserve > 0)
			{
				_reloadTimer = Def.ReloadTime;
				WeaponAudio.PlayReload(Def.Id);
				Plugin.LogWeapon(Def.Name + " reloading");
			}
		}

		private void FinishReload()
		{
			int num = Mathf.Min(Def.MagSize - Mag, Reserve);
			Mag += num;
			Reserve -= num;
			_reloadTimer = 0f;
		}

		public void AddReserve(int amount)
		{
			Reserve = Mathf.Min(Reserve + amount, Def.Reserve * 3);
		}
	}
	public class PistolWeapon : WeaponBase
	{
		public PistolWeapon()
			: base(WeaponId.Pistol)
		{
		}

		protected override void DoFire(Vector3 o, Vector3 d)
		{
			//IL_0000: Unknown result type (might be due to invalid IL or missing references)
			//IL_0001: Unknown result type (might be due to invalid IL or missing references)
			Hitscan.Shot(o, d, Def.Range, Def.DamagePerShot, Def.DamageType, (byte)Def.Id, Def.SpreadDeg, 1);
		}
	}
	public class ShotgunWeapon : WeaponBase
	{
		public ShotgunWeapon()
			: base(WeaponId.Shotgun)
		{
		}

		protected override void DoFire(Vector3 o, Vector3 d)
		{
			//IL_0000: Unknown result type (might be due to invalid IL or missing references)
			//IL_0001: Unknown result type (might be due to invalid IL or missing references)
			Hitscan.Shot(o, d, Def.Range, Def.DamagePerShot, Def.DamageType, (byte)Def.Id, Def.SpreadDeg, Def.Pellets);
		}
	}
	public class SuperShotgunWeapon : WeaponBase
	{
		public SuperShotgunWeapon()
			: base(WeaponId.SuperShotgun)
		{
		}

		protected override void DoFire(Vector3 o, Vector3 d)
		{
			//IL_0000: Unknown result type (might be due to invalid IL or missing references)
			//IL_0001: Unknown result type (might be due to invalid IL or missing references)
			Hitscan.Shot(o, d, Def.Range, Def.DamagePerShot, Def.DamageType, (byte)Def.Id, Def.SpreadDeg, Def.Pellets);
		}
	}
	public class BFGWeapon : WeaponBase
	{
		public BFGWeapon()
			: base(WeaponId.BFG)
		{
		}

		protected override void DoFire(Vector3 o, Vector3 d)
		{
			//IL_0000: Unknown result type (might be due to invalid IL or missing references)
			//IL_0001: Unknown result type (might be due to invalid IL or missing references)
			//IL_0007: Unknown result type (might be due to invalid IL or missing references)
			//IL_000c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0011: Unknown result type (might be due to invalid IL or missing references)
			//IL_001e: Unknown result type (might be due to invalid IL or missing references)
			//IL_001f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0025: Unknown result type (might be due to invalid IL or missing references)
			//IL_002a: Unknown result type (might be due to invalid IL or missing references)
			//IL_002f: Unknown result type (might be due to invalid IL or missing references)
			BfgProjectile.SpawnLocal(o + d * 1.2f, d, DoomNet.LocalActor, isOwner: true);
			DoomNet.SendBfgSpawn(o + d * 1.2f, d);
		}
	}
	public class MinigunWeapon : WeaponBase
	{
		protected override bool IsAutomatic => true;

		public MinigunWeapon()
			: base(WeaponId.Minigun)
		{
		}

		protected override void DoFire(Vector3 o, Vector3 d)
		{
			//IL_0000: Unknown result type (might be due to invalid IL or missing references)
			//IL_0001: Unknown result type (might be due to invalid IL or missing references)
			Hitscan.Shot(o, d, Def.Range, Def.DamagePerShot, Def.DamageType, (byte)Def.Id, Def.SpreadDeg, 1);
		}
	}
	public class GrenadeLauncherWeapon : WeaponBase
	{
		public GrenadeLauncherWeapon()
			: base(WeaponId.GrenadeLauncher)
		{
		}

		protected override void DoFire(Vector3 o, Vector3 d)
		{
			//IL_0000: Unknown result type (might be due to invalid IL or missing references)
			//IL_0001: Unknown result type (might be due to invalid IL or missing references)
			//IL_0007: Unknown result type (might be due to invalid IL or missing references)
			//IL_000c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0011: Unknown result type (might be due to invalid IL or missing references)
			//IL_001c: Unknown result type (might be due to invalid IL or missing references)
			//IL_002c: Unknown result type (might be due to invalid IL or missing references)
			//IL_002d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0033: Unknown result type (might be due to invalid IL or missing references)
			//IL_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_0048: Unknown result type (might be due to invalid IL or missing references)
			GrenadeProjectile.SpawnLocal(o + d * 1f, d * DoomConfig.GrenadeSpeed.Value, DoomNet.LocalActor);
			DoomNet.SendGrenadeSpawn(o + d * 1f, d * DoomConfig.GrenadeSpeed.Value);
		}
	}
	public class GenericHitscanWeapon : WeaponBase
	{
		private readonly bool _auto;

		protected override bool IsAutomatic => _auto;

		public GenericHitscanWeapon(WeaponId id)
			: base(id)
		{
			_auto = Def.Automatic;
		}

		protected override void DoFire(Vector3 o, Vector3 d)
		{
			//IL_0000: Unknown result type (might be due to invalid IL or missing references)
			//IL_0001: Unknown result type (might be due to invalid IL or missing references)
			Hitscan.Shot(o, d, Def.Range, Def.DamagePerShot, Def.DamageType, (byte)Def.Id, Def.SpreadDeg, Mathf.Max(1, Def.Pellets));
		}
	}
	public static class Hitscan
	{
		private class HitComparer : IComparer<RaycastHit>
		{
			public static readonly HitComparer Instance = new HitComparer();

			public int Compare(RaycastHit a, RaycastHit b)
			{
				float num = (((Object)(object)((RaycastHit)(ref a)).collider == (Object)null) ? float.MaxValue : ((RaycastHit)(ref a)).distance);
				float value = (((Object)(object)((RaycastHit)(ref b)).collider == (Object)null) ? float.MaxValue : ((RaycastHit)(ref b)).distance);
				return num.CompareTo(value);
			}
		}

		private static readonly RaycastHit[] _buf = (RaycastHit[])(object)new RaycastHit[24];

		public static void Shot(Vector3 origin, Vector3 dir, float range, float damagePerPellet, DamageType type, byte weaponId, float spreadDeg, int pellets)
		{
			//IL_0019: 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_0016: Unknown result type (might be due to invalid IL or missing references)
			//IL_0021: Unknown result type (might be due to invalid IL or missing references)
			//IL_0022: 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)
			int num = Mathf.Max(1, pellets);
			for (int i = 0; i < num; i++)
			{
				Vector3 dir2 = ((spreadDeg > 0f) ? Cone(dir, spreadDeg) : dir);
				ResolveOne(origin, dir2, range, damagePerPellet, type, weaponId, i == 0);
			}
		}

		private static void ResolveOne(Vector3 camOrigin, Vector3 dir, float range, float damage, DamageType type, byte weaponId, bool log)
		{
			//IL_001e: Unknown result type (might be due to invalid IL or missing references)
			//IL_001f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0025: Unknown result type (might be due to invalid IL or missing references)
			//IL_002a: Unknown result type (might be due to invalid IL or missing references)
			//IL_002f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0030: Unknown result type (might be due to invalid IL or missing references)
			//IL_0031: Unknown result type (might be due to invalid IL or missing references)
			//IL_0052: Unknown result type (might be due to invalid IL or missing references)
			//IL_0053: Unknown result type (might be due to invalid IL or missing references)
			//IL_0054: Unknown result type (might be due to invalid IL or missing references)
			//IL_0056: Unknown result type (might be due to invalid IL or missing references)
			//IL_005b: Unknown result type (might be due to invalid IL or missing references)
			//IL_031a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0321: Unknown result type (might be due to invalid IL or missing references)
			//IL_0086: Unknown result type (might be due to invalid IL or missing references)
			//IL_008b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0431: Unknown result type (might be due to invalid IL or missing references)
			//IL_0432: Unknown result type (might be due to invalid IL or missing references)
			//IL_0433: Unknown result type (might be due to invalid IL or missing references)
			//IL_0435: Unknown result type (might be due to invalid IL or missing references)
			//IL_043a: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e6: 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_0176: Unknown result type (might be due to invalid IL or missing references)
			//IL_0186: Unknown result type (might be due to invalid IL or missing references)
			//IL_018d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0192: Unknown result type (might be due to invalid IL or missing references)
			//IL_024e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0251: Unknown result type (might be due to invalid IL or missing references)
			//IL_03f4: Unknown result type (might be due to invalid IL or missing references)
			//IL_03f7: Unknown result type (might be due to invalid IL or missing references)
			//IL_0403: Unknown result type (might be due to invalid IL or missing references)
			//IL_040a: Unknown result type (might be due to invalid IL or missing references)
			Player localPlayer = Player.localPlayer;
			Transform val = (((Object)(object)localPlayer != (Object)null) ? ((Component)localPlayer).transform.root : null);
			Vector3 val2 = camOrigin + dir * 0.6f;
			int num = Physics.RaycastNonAlloc(val2, dir, _buf, range, -1, (QueryTriggerInteraction)2);
			if (num <= 0)
			{
				if (log)
				{
					Plugin.LogWeapon("shot hit nothing (open air)");
				}
				ImpactEffects.Tracer(camOrigin, val2 + dir * range);
				return;
			}
			Array.Sort(_buf, 0, num, HitComparer.Instance);
			for (int i = 0; i < num; i++)
			{
				RaycastHit val3 = _buf[i];
				Collider collider = ((RaycastHit)(ref val3)).collider;
				if ((Object)(object)collider == (Object)null)
				{
					continue;
				}
				Transform root = ((Component)collider).transform.root;
				if ((Object)(object)MonsterRegistry.Instance != (Object)null && MonsterRegistry.Instance.TryGetByCollider(collider, out var h))
				{
					if (h.Alive)
					{
						HitZone hitZone = MonsterHitZoneResolver.Resolve(h, collider, ((RaycastHit)(ref val3)).point);
						float num2 = damage;
						if (hitZone == HitZone.Head)
						{
							num2 *= Mathf.Max(1f, DoomConfig.HeadshotDamageMultiplier.Value);
							ActionEvents.RaiseLocalHeadshot();
						}
						ActionEvents.RaiseLocalHitDealt(h.ViewId, hitZone, (byte)type);
						if (log)
						{
							Plugin.LogWeapon($"shot hit {h.MonsterName} id={h.ViewId} zone={hitZone} @ {((RaycastHit)(ref val3)).distance:0.0}m");
						}
						ImpactEffects.Tracer(camOrigin, ((RaycastHit)(ref val3)).point);
						DamageSystem.ReportHit(h, num2, ((RaycastHit)(ref val3)).point, ((RaycastHit)(ref val3)).normal, dir, type, weaponId, hitZone);
						return;
					}
				}
				else
				{
					if ((Object)(object)root == (Object)(object)val)
					{
						continue;
					}
					Player componentInParent = ((Component)collider).GetComponentInParent<Player>();
					if (((Object)(object)componentInParent != (Object)null && ((Object)(object)componentInParent == (Object)(object)localPlayer || (componentInParent.refs != null && (Object)(object)componentInParent.refs.view != (Object)null && componentInParent.refs.view.IsMine))) || (Object)(object)((Component)collider).GetComponentInParent<ItemInstance>() != (Object)null || (Object)(object)((Component)collider).GetComponentInParent<Bot>() != (Object)null || (Object)(object)((Component)root).GetComponentInChildren<Bot>() != (Object)null || collider.isTrigger)
					{
						continue;
					}
					if ((Object)(object)componentInParent != (Object)null)
					{
						ImpactEffects.Tracer(camOrigin, ((RaycastHit)(ref val3)).point);
						if (!DamageSystem.FriendlyFireLive())
						{
							if (log)
							{
								Plugin.LogWeapon("hit teammate '" + ((Object)componentInParent).name + "' — friendly fire not live yet (surface or pre-Action)");
							}
							return;
						}
						int num3 = 0;
						try
						{
							if (componentInParent.refs != null && (Object)(object)componentInParent.refs.view != (Object)null && componentInParent.refs.view.Owner != null)
							{
								num3 = componentInParent.refs.view.Owner.ActorNumber;
							}
						}
						catch
						{
						}
						if (num3 == 0 && (Object)(object)((MonoBehaviourPun)componentInParent).photonView != (Object)null)
						{
							num3 = ((MonoBehaviourPun)componentInParent).photonView.OwnerActorNr;
						}
						float num4 = damage * Mathf.Max(0f, DoomConfig.FriendlyFireDamageMultiplier.Value);
						if (num3 != 0 && num4 > 0f)
						{
							BloodEffects.SpawnHit(((RaycastHit)(ref val3)).point, ((RaycastHit)(ref val3)).normal);
							DoomNet.SendFriendlyHit(num3, num4);
							if (log)
							{
								Plugin.LogWeapon($"friendly fire {num4:0} -> actor {num3} ('{((Object)componentInParent).name}') @ {((RaycastHit)(ref val3)).distance:0.0}m");
							}
						}
						else if (log)
						{
							Plugin.LogWeapon($"friendly fire NOT sent: targetActor={num3} ff={num4:0.0} ('{((Object)componentInParent).name}')");
						}
					}
					else
					{
						if (log)
						{
							Plugin.LogWeapon($"shot blocked by world: '{((Object)collider).name}' root='{((Object)root).name}' layer={LayerMask.LayerToName(((Component)collider).gameObject.layer)} @ {((RaycastHit)(ref val3)).distance:0.0}m");
						}
						ImpactEffects.Tracer(camOrigin, ((RaycastHit)(ref val3)).point);
						DamageSystem.ReportWorldImpact(((RaycastHit)(ref val3)).point, ((RaycastHit)(ref val3)).normal);
					}
					return;
				}
			}
			if (log)
			{
				Plugin.LogWeapon("shot passed through everything (no solid hit)");
			}
			ImpactEffects.Tracer(camOrigin, val2 + dir * range);
		}

		public static Vector3 Cone(Vector3 forward, float halfAngleDeg)
		{
			//IL_0008: 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_0018: 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_001a: Unknown result type (might be due to invalid IL or missing references)
			//IL_001f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0025: Unknown result type (might be due to invalid IL or missing references)
			//IL_0030: Unknown result type (might be due to invalid IL or missing references)
			//IL_0035: Unknown result type (might be due to invalid IL or missing references)
			//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_003e: Unknown result type (might be due to invalid IL or missing references)
			//IL_003f: Unknown result type (might be due to invalid IL or missing references)
			float num = halfAngleDeg * (MathF.PI / 180f);
			Vector2 val = Random.insideUnitCircle * Mathf.Tan(num);
			Quaternion val2 = Quaternion.LookRotation(forward);
			Vector3 val3 = new Vector3(val.x, val.y, 1f);
			Vector3 normalized = ((Vector3)(ref val3)).normalized;
			return val2 * normalized;
		}
	}
	public class WeaponManager : MonoBehaviour
	{
		public const int Count = 6;

		public const int WeaponIdCount = 11;

		private static readonly WeaponId[] SlotDefaults = new WeaponId[6]
		{
			WeaponId.Pistol,
			WeaponId.Shotgun,
			WeaponId.SuperShotgun,
			WeaponId.BFG,
			WeaponId.Minigun,
			WeaponId.GrenadeLauncher
		};

		private readonly WeaponBase[] _weapons = new WeaponBase[6];

		private readonly bool[] _unlocked = new bool[6];

		private readonly WeaponId[] _slot = (WeaponId[])SlotDefaults.Clone();

		private readonly bool[] _slotBought = new bool[6];

		private int _current = -1;

		private WeaponVisual _visual;

		private int _lastMag;

		private float _lastEquipBroadcast;

		public static WeaponManager Instance { get; private set; }

		public bool HasWeapon
		{
			get
			{
				if (_current >= 0)
				{
					return _weapons[_current] != null;
				}
				return false;
			}
		}

		public WeaponBase Current
		{
			get
			{
				if (!HasWeapon)
				{
					return null;
				}
				return _weapons[_current];
			}
		}

		public WeaponDef CurrentDef
		{
			get
			{
				if (!HasWeapon)
				{
					return null;
				}
				return _weapons[_current].Def;
			}
		}

		public int Mag
		{
			get
			{
				if (!HasWeapon)
				{
					return 0;
				}
				return _weapons[_current].Mag;
			}
		}

		public int Reserve
		{
			get
			{
				if (!HasWeapon)
				{
					return 0;
				}
				return _weapons[_current].Reserve;
			}
		}

		public bool Reloading
		{
			get
			{
				if (HasWeapon)
				{
					return _weapons[_current].Reloading;
				}
				return false;
			}
		}

		public float ReloadProgress
		{
			get
			{
				if (!HasWeapon)
				{
					return 1f;
				}
				return _weapons[_current].ReloadProgress;
			}
		}

		public static void Create()
		{
			//IL_0013: Unknown result type (might be due to invalid IL or missing references)
			//IL_0018: Unknown result type (might be due to invalid IL or missing references)
			//IL_001e: Expected O, but got Unknown
			if (!((Object)(object)Instance != (Object)null))
			{
				GameObject val = new GameObject("ContentWarningDoom.WeaponManager");
				Object.DontDestroyOnLoad((Object)val);
				Instance = val.AddComponent<WeaponManager>();
			}
		}

		private static WeaponBase Make(WeaponId id)
		{
			return id switch
			{
				WeaponId.Pistol => new PistolWeapon(), 
				WeaponId.Shotgun => new ShotgunWeapon(), 
				WeaponId.SuperShotgun => new SuperShotgunWeapon(), 
				WeaponId.BFG => new BFGWeapon(), 
				WeaponId.Minigun => new MinigunWeapon(), 
				WeaponId.GrenadeLauncher => new GrenadeLauncherWeapon(), 
				_ => new GenericHitscanWeapon(id), 
			};
		}

		private void Awake()
		{
			for (int i = 0; i < 6; i++)
			{
				_weapons[i] = Make(_slot[i]);
			}
		}

		public void OnDoomModeEnabled()
		{
			RebuildWeapons();
			_unlocked[0] = true;
			for (int i = 1; i < 6; i++)
			{
				_unlocked[i] = _slotBought[i];
			}
			Select(0);
		}

		public void OnDoomModeDisabled()
		{
			for (int i = 0; i < 6; i++)
			{
				_unlocked[i] = false;
			}
			_current = -1;
			DestroyVisual();
		}

		public void RebuildWeapons()
		{
			for (int i = 0; i < 6; i++)
			{
				WeaponBase weaponBase = _weapons[i];
				WeaponBase weaponBase2 = Make(_slot[i]);
				if (weaponBase != null && weaponBase.Def.Id == weaponBase2.Def.Id)
				{
					weaponBase2.Mag = Mathf.Min(weaponBase.Mag, weaponBase2.Def.MagSize);
					weaponBase2.Reserve = weaponBase.Reserve;
				}
				_weapons[i] = weaponBase2;
			}
		}

		public WeaponId SlotWeapon(int slot)
		{
			if (slot < 0 || slot >= 6)
			{
				return WeaponId.Pistol;
			}
			return _slot[slot];
		}

		public WeaponId SlotDefault(int slot)
		{
			if (slot < 0 || slot >= 6)
			{
				return WeaponId.Pistol;
			}
			return SlotDefaults[slot];
		}

		public bool SlotIsCustom(int slot)
		{
			if (slot >= 0 && slot < 6)
			{
				return _slot[slot] != SlotDefaults[slot];
			}
			return false;
		}

		public void SetSlotWeapon(int slot, WeaponId id)
		{
			if (slot >= 0 && slot < 6)
			{
				_slot[slot] = id;
				bool flag = id != SlotDefaults[slot];
				_slotBought[slot] = flag;
				WeaponBase weaponBase = Make(id);
				weaponBase.Reserve = weaponBase.Def.Reserve;
				_weapons[slot] = weaponBase;
				if (flag)
				{
					_unlocked[slot] = true;
				}
				if (_current == slot && Plugin.DoomModeActive)
				{
					_lastMag = weaponBase.Mag;
					BuildVisual();
					BroadcastEquip();
				}
				Plugin.LogWeapon(string.Format("slot {0} -> {1}{2}", slot + 1, id, flag ? " (bench)" : " (default)"));
			}
		}

		public void ResetSlot(int slot)
		{
			SetSlotWeapon(slot, SlotDefault(slot));
		}

		public void UnlockAll()
		{
			for (int i = 0; i < 6; i++)
			{
				_unlocked[i] = true;
			}
			Plugin.LogWeapon("All weapons unlocked (debug)");
		}

		public void Unlock(WeaponId id)
		{
			if ((int)id < 6)
			{
				_unlocked[(uint)id] = true;
				Plugin.LogWeapon($"{id} unlocked");
			}
		}

		public bool IsUnlocked(WeaponId id)
		{
			if ((int)id < 6)
			{
				return _unlocked[(uint)id];
			}
			return false;
		}

		public void SelectById(WeaponId id)
		{
			if ((int)id < 6 && _unlocked[(uint)id])
			{
				Select((int)id);
			}
		}

		public void GiveAmmo(WeaponId id, int amount)
		{
			for (int i = 0; i < 6; i++)
			{
				if (_weapons[i] != null && _weapons[i].Def.Id == id)
				{
					_weapons[i].AddReserve(amount);
					break;
				}
			}
		}

		public void GiveAmmoAll(float frac)
		{
			WeaponBase[] weapons = _weapons;
			foreach (WeaponBase weaponBase in weapons)
			{
				weaponBase?.AddReserve(Mathf.RoundToInt((float)weaponBase.Def.Reserve * frac));
			}
		}

		private void Select(int idx)
		{
			if (idx >= 0 && idx < 6 && _weapons[idx] != null && _unlocked[idx])
			{
				_current = idx;
				_lastMag = _weapons[idx].Mag;
				BuildVisual();
				BroadcastEquip();
				Plugin.LogWeapon("Selected " + _weapons[idx].Def.Name);
			}
		}

		public void OnSceneReloaded()
		{
			_visual = null;
			if (_current < 0 || !_unlocked[_current])
			{
				_current = -1;
				for (int i = 0; i < 6; i++)
				{
					if (_unlocked[i])
					{
						_current = i;
						break;
					}
				}
			}
			if (_current < 0 && Plugin.DoomModeActive)
			{
				_unlocked[0] = true;
				_current = 0;
			}
			if (HasWeapon)
			{
				_lastMag = _weapons[_current].Mag;
			}
		}

		private void Update()
		{
			//IL_00fa: Unknown result type (might be due to invalid IL or missing references)
			//IL_0100: Invalid comparison between Unknown and I4
			//IL_0237: Unknown result type (might be due to invalid IL or missing references)
			//IL_023e: Unknown result type (might be due to invalid IL or missing references)
			//IL_029e: Unknown result type (might be due to invalid IL or missing references)
			if (!Plugin.DoomModeActive)
			{
				DestroyVisual();
				return;
			}
			Player localPlayer = Player.localPlayer;
			if ((Object)(object)localPlayer == (Object)null || localPlayer.data == null || localPlayer.data.dead || (Object)(object)MainCamera.instance == (Object)null)
			{
				return;
			}
			if (!HasWeapon)
			{
				for (int i = 0; i < 6; i++)
				{
					if (_unlocked[i])
					{
						_current = i;
						_lastMag = _weapons[i].Mag;
						break;
					}
				}
				if (!HasWeapon)
				{
					_unlocked[0] = true;
					_current = 0;
					_lastMag = _weapons[0].Mag;
				}
			}
			if ((Object)(object)_visual == (Object)null)
			{
				BuildVisual();
			}
			else if (DoomConfig.AttachToRealHands.Value)
			{
				Transform val = PlayerHands.Right();
				if ((Object)(object)val != (Object)null && (Object)(object)_visual.ParentedTo != (Object)(object)val)
				{
					BuildVisual();
				}
			}
			bool num = (int)Cursor.lockState == 1;
			Keyboard current = Keyboard.current;
			Mouse current2 = Mouse.current;
			if (num && current != null)
			{
				if (((ButtonControl)current.digit1Key).wasPressedThisFrame)
				{
					Select(0);
				}
				else if (((ButtonControl)current.digit2Key).wasPressedThisFrame)
				{
					Select(1);
				}
				else if (((ButtonControl)current.digit3Key).wasPressedThisFrame)
				{
					Select(2);
				}
				else if (((ButtonControl)current.digit4Key).wasPressedThisFrame)
				{
					Select(3);
				}
				else if (((ButtonControl)current.digit5Key).wasPressedThisFrame)
				{
					Select(4);
				}
				else if (((ButtonControl)current.digit6Key).wasPressedThisFrame)
				{
					Select(5);
				}
				else if (((ButtonControl)current.leftBracketKey).wasPressedThisFrame)
				{
					Cycle(-1);
				}
				else if (((ButtonControl)current.rightBracketKey).wasPressedThisFrame)
				{
					Cycle(1);
				}
			}
			bool firePressedThisFrame = num && current2 != null && current2.leftButton.wasPressedThisFrame;
			bool fireHeld = num && current2 != null && current2.leftButton.isPressed;
			bool reloadPressed = num && current != null && ((ButtonControl)current.rKey).wasPressedThisFrame;
			Transform transform = ((Component)MainCamera.instance).transform;
			WeaponBase weaponBase = _weapons[_current];
			weaponBase.Tick(Time.deltaTime, firePressedThisFrame, fireHeld, reloadPressed, transform.position, transform.forward);
			if (weaponBase.Mag < _lastMag)
			{
				WeaponDef def = weaponBase.Def;
				CameraKick.Shake(def.RecoilKick, 0.14f, 10f + def.RecoilKick * 3f);
				_visual?.OnFired(def.RecoilKick);
				HandRecoil.Kick(transform.forward, def.HandRecoilForce);
			}
			_lastMag = weaponBase.Mag;
			_visual?.Tick(weaponBase.RecoilImpulse, weaponBase.Reloading);
			if (Time.time - _lastEquipBroadcast > 2f)
			{
				BroadcastEquip();
			}
		}

		private void BroadcastEquip()
		{
			if (HasWeapon)
			{
				_lastEquipBroadcast = Time.time;
				DoomNet.SendWeaponEquip((byte)_weapons[_current].Def.Id);
			}
		}

		private void Cycle(int step)
		{
			for (int i = 1; i <= 6; i++)
			{
				int num = ((_current + step * i) % 6 + 6) % 6;
				if (_unlocked[num])
				{
					Select(num);
					break;
				}
			}
		}

		public void RefreshVisual()
		{
			if (Plugin.DoomModeActive && HasWeapon)
			{
				BuildVisual();
			}
		}

		private void BuildVisual()
		{
			DestroyVisual();
			if (!((Object)(object)MainCamera.instance == (Object)null) && CurrentDef != null)
			{
				Transform val = (DoomConfig.AttachToRealHands.Value ? PlayerHands.Right() : null);
				Transform parent = (((Object)(object)val != (Object)null) ? val : ((Component)MainCamera.instance).transform);
				_visual = WeaponVisual.Build(parent, CurrentDef.Id, (Object)(object)val != (Object)null);
			}
		}

		private void DestroyVisual()
		{
			if ((Object)(object)_visual != (Object)null)
			{
				Object.Destroy((Object)(object)((Component)_visual).gameObject);
				_visual = null;
			}
		}

		public bool[] UnlockedSnapshot()
		{
			return (bool[])_unlocked.Clone();
		}
	}
	public class WeaponVisual : MonoBehaviour
	{
		private Transform _model;

		private Transform _muzzle;

		private Transform _grip;

		private MuzzleFlash _flash;

		private Vector3 _restPos;

		private Quaternion _restRot;

		private float _recoilPos;

		private float _recoilRot;

		private bool _handAttached;

		private static string _eulerSrc;

		private static readonly Dictionary<WeaponId, Vector3> _eulerMap = new Dictionary<WeaponId, Vector3>();

		public Transform ParentedTo => ((Component)this).transform.parent;

		public static WeaponVisual Build(Transform parent, WeaponId id, bool handAttached)
		{
			//IL_0005: 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)
			GameObject val = new GameObject("DoomWeaponVisual");
			val.transform.SetParent(parent, false);
			WeaponVisual weaponVisual = val.AddComponent<WeaponVisual>();
			weaponVisual._handAttached = handAttached;
			weaponVisual.Construct(id);
			return weaponVisual;
		}

		private static string ModelName(WeaponId id)
		{
			return id switch
			{
				WeaponId.Pistol => "Pistol_1", 
				WeaponId.Shotgun => "AR_4", 
				WeaponId.SuperShotgun => "AR_5", 
				WeaponId.BFG => "Sniper_3", 
				WeaponId.Minigun => "AR_3", 
				WeaponId.GrenadeLauncher => "Grenade_1", 
				WeaponId.Smg => "SMG_1", 
				WeaponId.AssaultRifle => "AR_1", 
				WeaponId.Marksman => "Sniper_1", 
				WeaponId.AutoShotgun => "AR_6", 
				WeaponId.Crossbow => "Crossbow_1", 
				_ => "Pistol_1", 
			};
		}

		private static Color MainAccent(WeaponId id)
		{
			//IL_0046: 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_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_007a: Unknown result type (might be due to invalid IL or missing references)
			//IL_007f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0094: Unknown result type (might be due to invalid IL or missing references)
			//IL_0099: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ae: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b3: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c8: Unknown result type (might be due to invalid IL or missing references)
			//IL_00cd: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e2: 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_00f9: Unknown result type (might be due to invalid IL or missing references)
			//IL_00fe: Unknown result type (might be due to invalid IL or missing references)
			//IL_0110: Unknown result type (might be due to invalid IL or missing references)
			//IL_0115: Unknown result type (might be due to invalid IL or missing references)
			//IL_0127: Unknown result type (might be due to invalid IL or missing references)
			//IL_012c: Unknown result type (might be due to invalid IL or missing references)
			//IL_013e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0143: Unknown result type (might be due to invalid IL or missing references)
			//IL_015b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0155: Unknown result type (might be due to invalid IL or missing references)
			//IL_015a: Unknown result type (might be due to invalid IL or missing references)
			return (Color)(id switch
			{
				WeaponId.Pistol => new Color(0.6f, 0.6f, 0.66f), 
				WeaponId.Shotgun => new Color(0.55f, 0.35f, 0.15f), 
				WeaponId.SuperShotgun => new Color(0.5f, 0.3f, 0.12f), 
				WeaponId.BFG => new Color(0.2f, 0.95f, 0.4f), 
				WeaponId.Minigun => new Color(0.36f, 0.38f, 0.42f), 
				WeaponId.GrenadeLauncher => new Color(0.38f, 0.42f, 0.2f), 
				WeaponId.Smg => new Color(0.45f, 0.47f, 0.52f), 
				WeaponId.AssaultRifle => new Color(0.3f, 0.34f, 0.3f), 
				WeaponId.Marksman => new Color(0.24f, 0.3f, 0.4f), 
				WeaponId.AutoShotgun => new Color(0.42f, 0.26f, 0.14f), 
				WeaponId.Crossbow => new Color(0.32f, 0.22f, 0.14f), 
				_ => new Color(0.6f, 0.6f, 0.6f), 
			});
		}

		internal static Vector3 PerModelEulerFix(WeaponId id)
		{
			//IL_00a8: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a2: 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_0074: Unknown result type (might be due to invalid IL or missing references)
			//IL_0079: Unknown result type (might be due to invalid IL or missing references)
			//IL_0082: Unknown result type (might be due to invalid IL or missing references)
			string text = DoomConfig.PerWeaponEulerOverrides.Value ?? "";
			if (text != _eulerSrc)
			{
				_eulerSrc = text;
				_eulerMap.Clear();
				string[] array = text.Split(';');
				for (int i = 0; i < array.Length; i++)
				{
					string[] array2 = array[i].