Decompiled source of HostVeteranSurvivor v1.7.2

BepInEx/plugins/HostRoleSeries/HostRoleSelector.dll

Decompiled 2 days ago
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.Versioning;
using BepInEx;
using BepInEx.Configuration;
using UnityEngine;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)]
[assembly: AssemblyFileVersion("1.0.0.0")]
[assembly: TargetFramework(".NETStandard,Version=v2.1")]
[assembly: AssemblyVersion("1.0.0.0")]
namespace HostRoleSeries;

[BepInPlugin("local.bei.hostroleselector", "Host Role Selector", "1.0.0")]
public sealed class RoleMenu : BaseUnityPlugin
{
	public const string PluginId = "local.bei.hostroleselector";

	private static RoleMenu instance;

	private readonly RoleRegistry roles = new RoleRegistry();

	private ConfigEntry<KeyboardShortcut> menuKey;

	private ConfigEntry<string> preferred;

	private readonly List<InputKey> blockInputs = new List<InputKey>();

	private bool open;

	private bool initialized;

	private int highlighted;

	private string pending;

	private string notice = "";

	private float noticeUntil;

	private GUIStyle title;

	private GUIStyle text;

	private GUIStyle small;

	private GUIStyle button;

	private Texture2D pointer;

	private static readonly FieldInfo dead = typeof(PlayerAvatar).GetField("deadSet", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);

	private static readonly FieldInfo spawned = typeof(PlayerAvatar).GetField("spawned", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);

	private static readonly FieldInfo chat = typeof(ChatManager).GetField("chatActive", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);

	private static readonly FieldInfo menuState = typeof(MenuManager).GetField("currentMenuState", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);

	public static bool InputBlocked
	{
		get
		{
			if (Object.op_Implicit((Object)(object)instance))
			{
				return instance.open;
			}
			return false;
		}
	}

	private void Awake()
	{
		//IL_001b: Unknown result type (might be due to invalid IL or missing references)
		menuKey = ((BaseUnityPlugin)this).Config.Bind<KeyboardShortcut>("Controls", "RoleMenuKey", new KeyboardShortcut((KeyCode)286, Array.Empty<KeyCode>()), "Open the shared host-role menu. Arrows: select; Enter: apply; Escape: cancel.");
		preferred = ((BaseUnityPlugin)this).Config.Bind<string>("Selection", "SelectedRole", "", "Last selected role ID, or none. Empty selects the first installed enabled role on startup.");
		instance = this;
	}

	public static void Register(string id, string name, string description, int order, Func<bool> available, Action<bool> apply)
	{
		if (!Object.op_Implicit((Object)(object)instance))
		{
			throw new InvalidOperationException("Host Role Selector is not loaded.");
		}
		instance.roles.Register(new RoleEntry(id, name, description, order, available, apply));
	}

	public static void Unregister(string id)
	{
		if (Object.op_Implicit((Object)(object)instance))
		{
			instance.roles.Remove(id);
		}
	}

	public static bool IsSelected(string id)
	{
		if (Object.op_Implicit((Object)(object)instance) && ((Behaviour)instance).isActiveAndEnabled && WorldReady())
		{
			return instance.roles.ActiveId == id;
		}
		return false;
	}

	private static bool WorldReady()
	{
		if (Object.op_Implicit((Object)(object)GameManager.instance) && Object.op_Implicit((Object)(object)RunManager.instance) && SemiFunc.IsMasterClientOrSingleplayer() && !SemiFunc.MenuLevel() && (Object)(object)LevelGenerator.Instance != (Object)null)
		{
			return LevelGenerator.Instance.Generated;
		}
		return false;
	}

	private static bool MenuReady()
	{
		//IL_0073: Unknown result type (might be due to invalid IL or missing references)
		//IL_0079: Invalid comparison between Unknown and I4
		PlayerAvatar val = PlayerAvatar.instance;
		if (WorldReady() && Object.op_Implicit((Object)(object)val) && dead != null && spawned != null && (bool)spawned.GetValue(val) && !(bool)dead.GetValue(val) && Object.op_Implicit((Object)(object)GameDirector.instance) && (int)GameDirector.instance.currentState == 2 && (!Object.op_Implicit((Object)(object)ChatManager.instance) || chat == null || !(bool)chat.GetValue(ChatManager.instance)))
		{
			if (Object.op_Implicit((Object)(object)MenuManager.instance) && !(menuState == null))
			{
				return (int)menuState.GetValue(MenuManager.instance) != 0;
			}
			return true;
		}
		return false;
	}

	private bool MenuPressed()
	{
		//IL_0006: Unknown result type (might be due to invalid IL or missing references)
		//IL_000b: Unknown result type (might be due to invalid IL or missing references)
		//IL_000e: 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_003a: Unknown result type (might be due to invalid IL or missing references)
		//IL_003f: Unknown result type (might be due to invalid IL or missing references)
		//IL_0045: Unknown result type (might be due to invalid IL or missing references)
		KeyboardShortcut value = menuKey.Value;
		if ((int)((KeyboardShortcut)(ref value)).MainKey == 0 || !UnityInput.Current.GetKeyDown(((KeyboardShortcut)(ref value)).MainKey))
		{
			return false;
		}
		foreach (KeyCode modifier in ((KeyboardShortcut)(ref value)).Modifiers)
		{
			if (!UnityInput.Current.GetKey(modifier))
			{
				return false;
			}
		}
		return true;
	}

	private void Update()
	{
		try
		{
			if (!WorldReady())
			{
				open = false;
				pending = null;
				roles.Select("none");
				initialized = false;
				return;
			}
			if (!initialized)
			{
				roles.Select(roles.Initial(preferred.Value));
				initialized = true;
			}
			roles.Validate();
			if (!MenuReady())
			{
				open = false;
				pending = null;
				return;
			}
			RoleEntry[] entries = roles.Entries;
			if (MenuPressed())
			{
				open = !open;
				pending = null;
				highlighted = Array.FindIndex(entries, (RoleEntry e) => e.Id == roles.ActiveId) + 1;
			}
			if (!open)
			{
				return;
			}
			if (UnityInput.Current.GetKeyDown((KeyCode)27))
			{
				open = false;
				pending = null;
				return;
			}
			if (Object.op_Implicit((Object)(object)CursorManager.instance))
			{
				SemiFunc.CursorUnlock(0.1f);
			}
			if (Object.op_Implicit((Object)(object)CameraAim.Instance))
			{
				CameraAim.Instance.OverrideAimStop();
			}
			if (Object.op_Implicit((Object)(object)InputManager.instance))
			{
				InputManager.instance.DisableControlsExcept(0.1f, blockInputs);
			}
			int num = entries.Length + 1;
			highlighted = Mathf.Clamp(highlighted, 0, num - 1);
			if (UnityInput.Current.GetKeyDown((KeyCode)276) || UnityInput.Current.GetKeyDown((KeyCode)273))
			{
				highlighted = (highlighted + num - 1) % num;
			}
			if (UnityInput.Current.GetKeyDown((KeyCode)275) || UnityInput.Current.GetKeyDown((KeyCode)274))
			{
				highlighted = (highlighted + 1) % num;
			}
			if (UnityInput.Current.GetKeyDown((KeyCode)8))
			{
				pending = "none";
			}
			if (UnityInput.Current.GetKeyDown((KeyCode)13))
			{
				pending = ((highlighted == 0) ? "none" : entries[highlighted - 1].Id);
			}
			if (pending == null)
			{
				return;
			}
			string requested = pending;
			pending = null;
			if (!roles.Select(requested))
			{
				notice = "This role is disabled in its config.";
				return;
			}
			preferred.Value = requested;
			if (!((BaseUnityPlugin)this).Config.SaveOnConfigSet)
			{
				((BaseUnityPlugin)this).Config.Save();
			}
			notice = "Role: " + ((requested == "none") ? "NONE" : Array.Find(entries, (RoleEntry e) => e.Id == requested).Name);
			noticeUntil = Time.unscaledTime + 4f;
			open = false;
		}
		catch (Exception ex)
		{
			open = false;
			pending = null;
			((BaseUnityPlugin)this).Logger.LogError((object)("Role selection failed: " + ex));
		}
	}

	private static void Fill(Rect rect, Color color)
	{
		//IL_0000: Unknown result type (might be due to invalid IL or missing references)
		//IL_0005: Unknown result type (might be due to invalid IL or missing references)
		//IL_000b: Unknown result type (might be due to invalid IL or missing references)
		Color color2 = GUI.color;
		GUI.color = color;
		GUI.DrawTexture(rect, (Texture)(object)Texture2D.whiteTexture);
		GUI.color = color2;
	}

	private void OnGUI()
	{
		//IL_0532: Unknown result type (might be due to invalid IL or missing references)
		//IL_0538: 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_0023: Unknown result type (might be due to invalid IL or missing references)
		//IL_002b: Unknown result type (might be due to invalid IL or missing references)
		//IL_0032: Unknown result type (might be due to invalid IL or missing references)
		//IL_003e: Expected O, but got Unknown
		//IL_0049: Unknown result type (might be due to invalid IL or missing references)
		//IL_005a: Unknown result type (might be due to invalid IL or missing references)
		//IL_005f: Unknown result type (might be due to invalid IL or missing references)
		//IL_0067: Unknown result type (might be due to invalid IL or missing references)
		//IL_0073: Expected O, but got Unknown
		//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_008c: Expected O, but got Unknown
		//IL_0097: 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_00a4: Unknown result type (might be due to invalid IL or missing references)
		//IL_00ab: Unknown result type (might be due to invalid IL or missing references)
		//IL_00b2: Unknown result type (might be due to invalid IL or missing references)
		//IL_00bc: Expected O, but got Unknown
		//IL_00c1: Expected O, but got Unknown
		//IL_0138: Unknown result type (might be due to invalid IL or missing references)
		//IL_013d: 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_01a8: Unknown result type (might be due to invalid IL or missing references)
		//IL_01ad: Unknown result type (might be due to invalid IL or missing references)
		//IL_01b2: Unknown result type (might be due to invalid IL or missing references)
		//IL_01b9: Unknown result type (might be due to invalid IL or missing references)
		//IL_01be: Unknown result type (might be due to invalid IL or missing references)
		//IL_01fe: Unknown result type (might be due to invalid IL or missing references)
		//IL_0217: Unknown result type (might be due to invalid IL or missing references)
		//IL_022f: Unknown result type (might be due to invalid IL or missing references)
		//IL_0243: Unknown result type (might be due to invalid IL or missing references)
		//IL_0267: Unknown result type (might be due to invalid IL or missing references)
		//IL_0296: Unknown result type (might be due to invalid IL or missing references)
		//IL_00ea: Unknown result type (might be due to invalid IL or missing references)
		//IL_0103: Unknown result type (might be due to invalid IL or missing references)
		//IL_0121: Unknown result type (might be due to invalid IL or missing references)
		//IL_044b: Unknown result type (might be due to invalid IL or missing references)
		//IL_049c: Unknown result type (might be due to invalid IL or missing references)
		//IL_04f7: Unknown result type (might be due to invalid IL or missing references)
		//IL_0507: Unknown result type (might be due to invalid IL or missing references)
		//IL_050c: 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_0367: Unknown result type (might be due to invalid IL or missing references)
		//IL_037b: Unknown result type (might be due to invalid IL or missing references)
		//IL_0552: Unknown result type (might be due to invalid IL or missing references)
		//IL_0558: Invalid comparison between Unknown and I4
		if (!MenuReady())
		{
			return;
		}
		if (this.text == null)
		{
			this.text = new GUIStyle(GUI.skin.label)
			{
				fontSize = 19,
				wordWrap = true,
				richText = false
			};
			this.text.normal.textColor = Color.white;
			title = new GUIStyle(this.text)
			{
				fontSize = 26,
				fontStyle = (FontStyle)1
			};
			small = new GUIStyle(this.text)
			{
				fontSize = 15
			};
			button = new GUIStyle(GUI.skin.button)
			{
				fontSize = 20,
				alignment = (TextAnchor)3,
				padding = new RectOffset(18, 12, 8, 8)
			};
		}
		if (!open)
		{
			if (Time.unscaledTime < noticeUntil)
			{
				Fill(new Rect(22f, 22f, 460f, 55f), new Color(0.08f, 0.1f, 0.14f, 0.95f));
				GUI.Label(new Rect(34f, 33f, 438f, 35f), notice, this.text);
			}
			return;
		}
		Matrix4x4 matrix = GUI.matrix;
		Color color = GUI.color;
		bool enabled = GUI.enabled;
		try
		{
			RoleEntry[] entries = roles.Entries;
			highlighted = Mathf.Clamp(highlighted, 0, entries.Length);
			float num = 230 + 62 * (entries.Length + 1);
			float num2 = Mathf.Min(1.1f, Mathf.Min((float)Screen.width / 820f, (float)Screen.height / (num + 60f)));
			GUI.matrix = Matrix4x4.TRS(Vector3.zero, Quaternion.identity, Vector3.one * num2);
			float num3 = ((float)Screen.width / num2 - 760f) / 2f;
			float num4 = ((float)Screen.height / num2 - num) / 2f;
			Fill(new Rect(num3, num4, 760f, num), new Color(0.1f, 0.12f, 0.16f, 0.98f));
			Fill(new Rect(num3, num4, 760f, 58f), new Color(0.12f, 0.32f, 0.55f));
			GUI.Label(new Rect(num3 + 22f, num4 + 14f, 660f, 40f), "HOST ROLES / SELECT YOUR ROLE", title);
			if (GUI.Button(new Rect(num3 + 702f, num4 + 12f, 40f, 34f), "X"))
			{
				open = false;
				pending = null;
			}
			Rect val = default(Rect);
			for (int i = 0; i <= entries.Length; i++)
			{
				string text = ((i == 0) ? "none" : entries[i - 1].Id);
				string text2 = ((i == 0) ? "NONE" : entries[i - 1].Name);
				bool flag = i == 0 || entries[i - 1].IsAvailable;
				((Rect)(ref val))..ctor(num3 + 22f, num4 + 76f + (float)(i * 62), 716f, 52f);
				if (highlighted == i)
				{
					Fill(new Rect(((Rect)(ref val)).x - 4f, ((Rect)(ref val)).y - 3f, ((Rect)(ref val)).width + 8f, ((Rect)(ref val)).height + 6f), new Color(0.23f, 0.57f, 0.95f));
				}
				GUI.enabled = enabled && flag;
				if (GUI.Button(val, text2 + ((text == roles.ActiveId) ? "   [ACTIVE]" : "") + (flag ? "" : "   [CFG OFF]"), button))
				{
					highlighted = i;
				}
			}
			GUI.enabled = enabled;
			float num5 = num4 + 76f + (float)((entries.Length + 1) * 62);
			string text3 = ((highlighted == 0) ? "No host-role abilities. Stored resources are kept." : entries[Mathf.Clamp(highlighted - 1, 0, entries.Length - 1)].Description);
			GUI.Label(new Rect(num3 + 24f, num5 + 4f, 712f, 52f), text3, small);
			GUI.enabled = enabled && (highlighted == 0 || entries[highlighted - 1].IsAvailable);
			if (GUI.Button(new Rect(num3 + 22f, num5 + 62f, 716f, 43f), "APPLY SELECTED ROLE", button))
			{
				pending = ((highlighted == 0) ? "none" : entries[highlighted - 1].Id);
			}
			GUI.enabled = enabled;
			GUI.Label(new Rect(num3 + 24f, num5 + 117f, 714f, 25f), "Arrows: select   Enter: apply   Backspace: none   " + ((object)menuKey.Value/*cast due to .constrained prefix*/).ToString() + " / Esc: close", small);
		}
		finally
		{
			GUI.matrix = matrix;
			GUI.color = color;
			GUI.enabled = enabled;
		}
		if (open && (int)Event.current.type == 7)
		{
			DrawPointer();
		}
	}

	private void DrawPointer()
	{
		//IL_00a1: Unknown result type (might be due to invalid IL or missing references)
		//IL_00a6: Unknown result type (might be due to invalid IL or missing references)
		//IL_00a7: 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_00c4: Unknown result type (might be due to invalid IL or missing references)
		//IL_0017: Unknown result type (might be due to invalid IL or missing references)
		//IL_0021: Expected O, but got Unknown
		//IL_004a: Unknown result type (might be due to invalid IL or missing references)
		//IL_0067: Unknown result type (might be due to invalid IL or missing references)
		//IL_0073: Unknown result type (might be due to invalid IL or missing references)
		//IL_006e: Unknown result type (might be due to invalid IL or missing references)
		if (!Object.op_Implicit((Object)(object)pointer))
		{
			pointer = new Texture2D(20, 28, (TextureFormat)4, false);
			Color[] array = (Color[])(object)new Color[560];
			for (int i = 0; i < 28; i++)
			{
				for (int j = 0; j < 20; j++)
				{
					array[(27 - i) * 20 + j] = (((float)j <= (float)i * 0.6f) ? ((j > 1 && (float)j < (float)i * 0.6f - 2f) ? Color.white : Color.black) : Color.clear);
				}
			}
			pointer.SetPixels(array);
			pointer.Apply();
		}
		Vector3 mousePosition = Input.mousePosition;
		GUI.DrawTexture(new Rect(mousePosition.x, (float)Screen.height - mousePosition.y, 20f, 28f), (Texture)(object)pointer);
	}

	private void OnDisable()
	{
		open = false;
		pending = null;
		roles.Select("none");
		initialized = false;
	}

	private void OnDestroy()
	{
		try
		{
			roles.Select("none");
		}
		finally
		{
			if (Object.op_Implicit((Object)(object)pointer))
			{
				Object.Destroy((Object)(object)pointer);
			}
			if ((Object)(object)instance == (Object)(object)this)
			{
				instance = null;
			}
		}
	}
}
public sealed class RoleEntry
{
	public string Id { get; }

	public string Name { get; }

	public string Description { get; }

	internal int Order { get; }

	internal Func<bool> Available { get; }

	internal Action<bool> Apply { get; }

	public bool IsAvailable => Available();

	public RoleEntry(string id, string name, string description, int order, Func<bool> available, Action<bool> apply)
	{
		Id = id;
		Name = name;
		Description = description;
		Order = order;
		Available = available;
		Apply = apply;
	}
}
public sealed class RoleRegistry
{
	public const string None = "none";

	private readonly Dictionary<string, RoleEntry> entries = new Dictionary<string, RoleEntry>();

	public string ActiveId { get; private set; } = "none";

	public RoleEntry[] Entries => entries.Values.OrderBy((RoleEntry r) => r.Order).ThenBy<RoleEntry, string>((RoleEntry r) => r.Id, StringComparer.Ordinal).ToArray();

	public void Register(RoleEntry entry)
	{
		if (entry == null || string.IsNullOrWhiteSpace(entry.Id) || entry.Id == "none" || entries.ContainsKey(entry.Id))
		{
			throw new ArgumentException("Duplicate or invalid role registration.");
		}
		entries.Add(entry.Id, entry);
	}

	public bool Select(string id)
	{
		if (id == ActiveId)
		{
			return true;
		}
		RoleEntry value = null;
		if (id != "none" && (!entries.TryGetValue(id, out value) || !value.IsAvailable))
		{
			return false;
		}
		string activeId = ActiveId;
		ActiveId = "none";
		if (entries.TryGetValue(activeId, out var value2))
		{
			value2.Apply(obj: false);
		}
		if (value == null)
		{
			return true;
		}
		try
		{
			ActiveId = id;
			value.Apply(obj: true);
		}
		catch
		{
			ActiveId = "none";
			value.Apply(obj: false);
			throw;
		}
		return true;
	}

	public void Remove(string id)
	{
		if (ActiveId == id)
		{
			Select("none");
		}
		entries.Remove(id);
	}

	public string Initial(string preferred)
	{
		if (preferred == "none")
		{
			return "none";
		}
		if (preferred == null || !entries.TryGetValue(preferred, out var value))
		{
			return Entries.FirstOrDefault((RoleEntry e) => e.IsAvailable)?.Id ?? "none";
		}
		if (!value.IsAvailable)
		{
			return "none";
		}
		return preferred;
	}

	public void Validate()
	{
		if (entries.TryGetValue(ActiveId, out var value) && !value.IsAvailable)
		{
			Select("none");
		}
	}
}

BepInEx/plugins/HostVeteranSurvivor/HostVeteranSurvivor.dll

Decompiled 2 days ago
using System;
using System.Collections;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Reflection.Emit;
using System.Runtime.CompilerServices;
using System.Runtime.Versioning;
using BepInEx;
using BepInEx.Configuration;
using BepInEx.Logging;
using HarmonyLib;
using HostRoleSeries;
using Photon.Pun;
using REPOLib.Modules;
using UnityEngine;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)]
[assembly: AssemblyFileVersion("1.7.2.0")]
[assembly: TargetFramework(".NETStandard,Version=v2.1")]
[assembly: AssemblyVersion("1.7.2.0")]
namespace HostVeteranSurvivor;

[BepInPlugin("local.bei.hostveteransurvivor", "Host Veteran Survivor", "1.7.2")]
[BepInDependency("REPOLib", "4.2.0")]
[BepInDependency("local.bei.hostroleselector", "1.0.0")]
[BepInIncompatibility("local.bei.hostunarmedshotgun")]
[BepInIncompatibility("local.bei.hostsurvivalbenefits")]
public sealed class Plugin : BaseUnityPlugin
{
	private sealed class FadingGun
	{
		internal GameObject Target;

		internal float DestroyAt;
	}

	private readonly AmmoRules ammo = new AmmoRules();

	private readonly DodgeEnergyRules dodgeEnergy = new DodgeEnergyRules();

	private readonly List<GameObject> dodgeEnergyBars = new List<GameObject>();

	private GameObject ammoHud;

	private Canvas ammoCanvas;

	private readonly List<GameObject> ammoBars = new List<GameObject>();

	private Component ammoNumber;

	private float nextHudAttempt;

	private float nextHudWarning;

	private readonly ControlDodgeWindow controlDodge = new ControlDodgeWindow();

	private readonly DeathExplosionRules deathExplosionUses = new DeathExplosionRules();

	private Item deathGrenadeItem;

	private GameObject deathGrenadeProxy;

	private object deathGrenadeStage;

	private object deathGrenadeRoom;

	private string deathGrenadeRoster;

	private float deathGrenadeReadyAt;

	private float deathGrenadeRetryAt;

	private bool deathExplosionPending;

	private PlayerAvatar deathExplosionPlayer;

	private Vector3 deathExplosionPosition;

	private float deathExplosionDeadline;

	private object deathExplosionStage;

	private object deathExplosionRoom;

	private ConfigEntry<bool> dodgeEnabled;

	private ConfigEntry<float> dodgeInvincibilitySeconds;

	private ConfigEntry<float> dodgeDistanceMultiplier;

	private ConfigEntry<KeyboardShortcut> dodgeKey;

	private int lastDodgeFrame = -1;

	private FieldInfo dodgeHealth;

	private FieldInfo dodgeInvincible;

	private FieldInfo dodgeGodMode;

	private FieldInfo dodgeKinematic;

	private FieldInfo dodgeMoveForce;

	private FieldInfo dodgeCanSlide;

	private FieldInfo dodgeSlideTimer;

	private FieldInfo dodgeSlideDirection;

	private FieldInfo dodgeSlideCurrent;

	private FieldInfo dodgeCrouchActive;

	private FieldInfo dodgeCrouchInactive;

	private FieldInfo dodgeSprinted;

	private FieldInfo dodgeRecharge;

	public const string PluginId = "local.bei.hostveteransurvivor";

	internal const float ProxyScale = 0.0001f;

	internal const float MuzzleEffectSeconds = 2.5f;

	internal static Plugin Current;

	private ConfigEntry<bool> modEnabled;

	private ConfigEntry<int> selfDamagePerShot;

	private ConfigEntry<float> cooldownOverride;

	private ConfigEntry<float> warmupSeconds;

	private ConfigEntry<float> poseSeconds;

	private ConfigEntry<float> handForwardOffset;

	private ConfigEntry<float> poseLeadSeconds;

	private ConfigEntry<float> iconWarmupSeconds;

	private readonly IconWarmupGate iconGate = new IconWarmupGate();

	private GameObject iconPrimer;

	private float nextIconNotice;

	private ConfigEntry<string> shotgunPrefabName;

	private Item shotgunItem;

	private ItemGun shotgunTemplate;

	private FieldInfo avatarDisabled;

	private FieldInfo avatarTumbling;

	private FieldInfo avatarDead;

	private FieldInfo avatarSpawned;

	private FieldInfo menuState;

	private FieldInfo chatActive;

	private FieldInfo mapActive;

	private FieldInfo grabCamera;

	private FieldInfo inputDisabled;

	private FieldInfo lastGrabber;

	private FieldInfo gunPhys;

	private FieldInfo disabledPosition;

	private readonly InteractionFireGate interactionGate = new InteractionFireGate();

	private int interactionBlockedLogCount;

	private NativeNetwork network;

	private Harmony harmony;

	private float nextShotAt;

	private float nextCatalogAttempt;

	private bool busy;

	private bool remotePoseSent;

	private GameObject temporaryGun;

	private float temporaryGunDestroyAt;

	private readonly List<FadingGun> fadingGuns = new List<FadingGun>();

	private PhysGrabber posingGrabber;

	private PlayerAvatar shotShooter;

	private PlayerAvatarRightArm posingArm;

	private float nextPlacementWarning;

	private static readonly FieldInfo bonusAvatarTumble = AccessTools.Field(typeof(PlayerAvatar), "tumble");

	private static readonly FieldInfo bonusLaunch = AccessTools.Field(typeof(PlayerTumble), "tumbleLaunch");

	private static readonly FieldInfo bonusJump = AccessTools.Field(typeof(PlayerController), "JumpExtra");

	private static readonly FieldInfo bonusJumpRemaining = AccessTools.Field(typeof(PlayerController), "JumpExtraCurrent");

	private static readonly FieldInfo bonusTumbleReady = AccessTools.Field(typeof(PlayerTumble), "setup");

	private PlayerAvatar bonusPlayer;

	private PlayerController bonusController;

	private PlayerTumble bonusTumble;

	private string bonusSteamId;

	private bool bonusFailed;

	private PlayerAvatarVisuals suppressedLaunchVisual;

	private GameObject tumbleSmokeProxy;

	private PhysGrabObjectImpactDetector tumbleSmokeDetector;

	private PhysGrabObject tumbleSmokePhys;

	private object tumbleSmokeStage;

	private object tumbleSmokeRoom;

	private float tumbleSmokeReadyAt;

	private float tumbleSmokeRetryAt;

	private string tumbleSmokeRoster;

	private bool tumbleSmokeValueInitialized;

	private float smokeDiagnosticAt;

	private bool smokeHookLogged;

	private bool smokeSentLogged;

	private GameObject localSmokePrefab;

	private readonly SmokeTrailRules smokeTrail = new SmokeTrailRules();

	private PlayerAvatar smokeTrailPlayer;

	private object smokeTrailStage;

	private Vector3 smokeTrailPosition;

	private ConfigEntry<int> reloadValueCost;

	private readonly ReloadRules reloadRules = new ReloadRules();

	private bool reloadFailed;

	private bool reloadEffectFailed;

	private object reloadSession;

	private object reloadStage;

	private static readonly FieldInfo reloadHeld = AccessTools.Field(typeof(PhysGrabber), "grabbedPhysGrabObject");

	private static readonly FieldInfo reloadValuable = AccessTools.Field(typeof(PhysGrabObjectImpactDetector), "valuableObject");

	private static readonly FieldInfo reloadValue = AccessTools.Field(typeof(ValuableObject), "dollarValueCurrent");

	private static readonly FieldInfo reloadReady = AccessTools.Field(typeof(ValuableObject), "dollarValueSet");

	private static readonly MethodInfo reloadLogic = AccessTools.Method(typeof(PhysGrabObjectImpactDetector), "HealLogic", new Type[2]
	{
		typeof(float),
		typeof(Vector3)
	}, (Type[])null);

	private static readonly FieldInfo reloadBreakLevel = AccessTools.Field(typeof(PhysGrabObjectImpactDetector), "breakLevelLight");

	private static readonly FieldInfo reloadToggleList = AccessTools.Field(typeof(PlayerExpression), "inputToggleList");

	private static readonly FieldInfo reloadTogglePending = AccessTools.Field(typeof(PlayerExpression), "inputToggleListNew");

	private bool RoleEnabled
	{
		get
		{
			if (((Behaviour)this).isActiveAndEnabled && modEnabled != null && modEnabled.Value)
			{
				return RoleMenu.IsSelected("local.bei.hostveteransurvivor");
			}
			return false;
		}
	}

	private void UpdateAmmoContext()
	{
		if (!Object.op_Implicit((Object)(object)GameManager.instance) || !Object.op_Implicit((Object)(object)RunManager.instance) || SemiFunc.MenuLevel() || !SemiFunc.IsMasterClientOrSingleplayer())
		{
			ammo.Reset();
			dodgeEnergy.Reset();
			DestroyAmmoHud();
		}
		else if (LevelGenerator.Instance == null || !LevelGenerator.Instance.Generated)
		{
			HideAmmoHud();
		}
		else
		{
			object currentSession = ((!SemiFunc.IsMultiplayer()) ? RunManager.instance : network?.Room);
			ammo.Observe(currentSession, SemiFunc.RunIsLevel() ? LevelGenerator.Instance : null);
			dodgeEnergy.Observe(currentSession, SemiFunc.RunIsLevel() ? LevelGenerator.Instance : null);
		}
	}

	private void HideAmmoHud()
	{
		if (Object.op_Implicit((Object)(object)ammoHud))
		{
			ammoHud.SetActive(false);
		}
	}

	private void DestroyAmmoHud()
	{
		if (Object.op_Implicit((Object)(object)ammoCanvas))
		{
			Object.Destroy((Object)(object)((Component)ammoCanvas).gameObject);
		}
		else if (Object.op_Implicit((Object)(object)ammoHud))
		{
			Object.Destroy((Object)(object)ammoHud);
		}
		ammoHud = null;
		ammoCanvas = null;
		ammoNumber = null;
		ammoBars.Clear();
		dodgeEnergyBars.Clear();
	}

	private void UpdateAmmoHud()
	{
		//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)
		//IL_0174: Unknown result type (might be due to invalid IL or missing references)
		//IL_0179: Unknown result type (might be due to invalid IL or missing references)
		//IL_017a: 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_019e: 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)
		try
		{
			PlayerAvatar instance = PlayerAvatar.instance;
			if (!((Behaviour)this).isActiveAndEnabled || !RoleEnabled || !Object.op_Implicit((Object)(object)GameManager.instance) || !Object.op_Implicit((Object)(object)RunManager.instance) || !SemiFunc.IsMasterClientOrSingleplayer() || SemiFunc.MenuLevel() || LevelGenerator.Instance == null || !LevelGenerator.Instance.Generated || !Object.op_Implicit((Object)(object)instance) || (bool)avatarDead.GetValue(instance) || (bool)avatarDisabled.GetValue(instance) || !(bool)avatarSpawned.GetValue(instance) || (Object.op_Implicit((Object)(object)MenuManager.instance) && (int)menuState.GetValue(MenuManager.instance) == 0))
			{
				HideAmmoHud();
				return;
			}
			if (!Object.op_Implicit((Object)(object)ammoHud))
			{
				if (Time.unscaledTime < nextHudAttempt)
				{
					return;
				}
				nextHudAttempt = Time.unscaledTime + 1f;
				if (!BuildAmmoHud())
				{
					return;
				}
			}
			ammoHud.SetActive(true);
			Transform transform = ((Component)ammoCanvas).transform;
			RectTransform val = (RectTransform)(object)((transform is RectTransform) ? transform : null);
			float num;
			if (Object.op_Implicit((Object)(object)val))
			{
				Rect rect = val.rect;
				if (((Rect)(ref rect)).width > 0f)
				{
					rect = val.rect;
					num = ((Rect)(ref rect)).width / 1920f;
					goto IL_0168;
				}
			}
			num = 1f;
			goto IL_0168;
			IL_0168:
			float num2 = num;
			RectTransform val2 = (RectTransform)ammoHud.transform;
			((Transform)val2).localScale = Vector3.one * (num2 * 0.7f);
			val2.anchoredPosition = new Vector2(-110f * num2, 28f * num2);
			for (int i = 0; i < ammoBars.Count; i++)
			{
				ammoBars[i].SetActive(i < ammo.Remaining);
			}
			for (int j = 0; j < dodgeEnergyBars.Count; j++)
			{
				dodgeEnergyBars[j].SetActive(j < dodgeEnergy.Remaining);
			}
			if (Object.op_Implicit((Object)(object)ammoNumber))
			{
				SetHudProperty(ammoNumber, "text", ammo.Remaining + " / " + 8);
			}
		}
		catch (Exception ex)
		{
			DestroyAmmoHud();
			if (Time.unscaledTime >= nextHudWarning)
			{
				nextHudWarning = Time.unscaledTime + 30f;
				((BaseUnityPlugin)this).Logger.LogWarning((object)("Ammo HUD unavailable: " + ex.GetBaseException().Message));
			}
		}
	}

	private static void SetHudProperty(Component target, string name, object value)
	{
		((object)target).GetType().GetProperty(name, BindingFlags.Instance | BindingFlags.Public)?.SetValue(target, value);
	}

	private bool BuildAmmoHud()
	{
		//IL_0031: Unknown result type (might be due to invalid IL or missing references)
		//IL_0037: Expected O, but got Unknown
		//IL_0075: Unknown result type (might be due to invalid IL or missing references)
		//IL_007f: Expected O, but got Unknown
		//IL_0096: Unknown result type (might be due to invalid IL or missing references)
		//IL_009c: Expected O, but got Unknown
		//IL_00bc: Unknown result type (might be due to invalid IL or missing references)
		//IL_00c3: 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_00ea: Unknown result type (might be due to invalid IL or missing references)
		//IL_0116: Unknown result type (might be due to invalid IL or missing references)
		//IL_0125: Unknown result type (might be due to invalid IL or missing references)
		//IL_013e: Unknown result type (might be due to invalid IL or missing references)
		//IL_0150: Unknown result type (might be due to invalid IL or missing references)
		//IL_015f: 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_017c: Unknown result type (might be due to invalid IL or missing references)
		//IL_018b: Unknown result type (might be due to invalid IL or missing references)
		//IL_0190: Unknown result type (might be due to invalid IL or missing references)
		//IL_01a8: Unknown result type (might be due to invalid IL or missing references)
		//IL_01b7: Unknown result type (might be due to invalid IL or missing references)
		//IL_01bc: Unknown result type (might be due to invalid IL or missing references)
		//IL_01d4: Unknown result type (might be due to invalid IL or missing references)
		//IL_01e3: Unknown result type (might be due to invalid IL or missing references)
		//IL_01e8: Unknown result type (might be due to invalid IL or missing references)
		//IL_0227: Unknown result type (might be due to invalid IL or missing references)
		//IL_0236: Unknown result type (might be due to invalid IL or missing references)
		//IL_023b: Unknown result type (might be due to invalid IL or missing references)
		//IL_027d: Unknown result type (might be due to invalid IL or missing references)
		//IL_028c: Unknown result type (might be due to invalid IL or missing references)
		//IL_02a5: Unknown result type (might be due to invalid IL or missing references)
		//IL_02c1: Unknown result type (might be due to invalid IL or missing references)
		//IL_02d0: Unknown result type (might be due to invalid IL or missing references)
		//IL_02d5: Unknown result type (might be due to invalid IL or missing references)
		//IL_02ee: Unknown result type (might be due to invalid IL or missing references)
		//IL_02fd: Unknown result type (might be due to invalid IL or missing references)
		//IL_0302: Unknown result type (might be due to invalid IL or missing references)
		//IL_031b: Unknown result type (might be due to invalid IL or missing references)
		//IL_032a: Unknown result type (might be due to invalid IL or missing references)
		//IL_032f: Unknown result type (might be due to invalid IL or missing references)
		//IL_0348: Unknown result type (might be due to invalid IL or missing references)
		//IL_0357: Unknown result type (might be due to invalid IL or missing references)
		//IL_035c: Unknown result type (might be due to invalid IL or missing references)
		//IL_039c: Unknown result type (might be due to invalid IL or missing references)
		//IL_03ab: Unknown result type (might be due to invalid IL or missing references)
		//IL_03b0: 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)
		//IL_0411: Expected O, but got Unknown
		//IL_0418: Unknown result type (might be due to invalid IL or missing references)
		//IL_041d: Unknown result type (might be due to invalid IL or missing references)
		//IL_0425: Unknown result type (might be due to invalid IL or missing references)
		//IL_0426: Unknown result type (might be due to invalid IL or missing references)
		//IL_0427: Unknown result type (might be due to invalid IL or missing references)
		//IL_0428: Unknown result type (might be due to invalid IL or missing references)
		//IL_042d: Unknown result type (might be due to invalid IL or missing references)
		//IL_042e: Unknown result type (might be due to invalid IL or missing references)
		//IL_0435: Unknown result type (might be due to invalid IL or missing references)
		//IL_0437: Unknown result type (might be due to invalid IL or missing references)
		//IL_0438: Unknown result type (might be due to invalid IL or missing references)
		//IL_043f: Unknown result type (might be due to invalid IL or missing references)
		//IL_0446: Unknown result type (might be due to invalid IL or missing references)
		//IL_0451: Unknown result type (might be due to invalid IL or missing references)
		//IL_0465: Unknown result type (might be due to invalid IL or missing references)
		//IL_04c8: Unknown result type (might be due to invalid IL or missing references)
		Type type = Type.GetType("UnityEngine.UI.RawImage, UnityEngine.UI", throwOnError: true);
		GameObject val = new GameObject("HostVeteranSurvivor Ammo Canvas", new Type[2]
		{
			typeof(RectTransform),
			typeof(Canvas)
		});
		ammoCanvas = val.GetComponent<Canvas>();
		ammoCanvas.renderMode = (RenderMode)0;
		ammoCanvas.sortingOrder = 100;
		ammoHud = new GameObject("HostVeteranSurvivor Ammo", new Type[1] { typeof(RectTransform) });
		ammoHud.SetActive(false);
		RectTransform val2 = (RectTransform)ammoHud.transform;
		((Transform)val2).SetParent(val.transform, false);
		Vector2 val3 = default(Vector2);
		((Vector2)(ref val3))..ctor(1f, 0f);
		val2.anchorMax = val3;
		val2.anchorMin = val3;
		val2.pivot = new Vector2(1f, 0f);
		val2.sizeDelta = new Vector2(210f, 198f);
		Color val4 = default(Color);
		((Color)(ref val4))..ctor(0.5019608f, 0.5019608f, 0.5019608f, 1f);
		CreateAmmoGraphic(type, "Background", Vector2.zero, new Vector2(210f, 62f), new Color(0.06f, 0.06f, 0.06f, 0.9f));
		CreateAmmoGraphic(type, "Bottom border", Vector2.zero, new Vector2(210f, 4f), val4);
		CreateAmmoGraphic(type, "Top border", new Vector2(0f, 58f), new Vector2(210f, 4f), val4);
		CreateAmmoGraphic(type, "Left border", new Vector2(0f, 4f), new Vector2(4f, 54f), val4);
		CreateAmmoGraphic(type, "Right border", new Vector2(206f, 4f), new Vector2(4f, 54f), val4);
		for (int i = 0; i < 8; i++)
		{
			ammoBars.Add(CreateAmmoGraphic(type, "Round " + (i + 1), new Vector2(14f + (float)i * 22.875f, 15f), new Vector2(20.575f, 32f), val4));
		}
		Color color = default(Color);
		((Color)(ref color))..ctor(40f / 51f, 31f / 85f, 0.3529412f, 1f);
		CreateAmmoGraphic(type, "Dodge background", new Vector2(-123f, 0f), new Vector2(105f, 31f), new Color(0.06f, 0.06f, 0.06f, 0.9f));
		CreateAmmoGraphic(type, "Dodge bottom border", new Vector2(-123f, 0f), new Vector2(105f, 2f), color);
		CreateAmmoGraphic(type, "Dodge top border", new Vector2(-123f, 29f), new Vector2(105f, 2f), color);
		CreateAmmoGraphic(type, "Dodge left border", new Vector2(-123f, 2f), new Vector2(2f, 27f), color);
		CreateAmmoGraphic(type, "Dodge right border", new Vector2(-20f, 2f), new Vector2(2f, 27f), color);
		for (int j = 0; j < 8; j++)
		{
			dodgeEnergyBars.Add(CreateAmmoGraphic(type, "Dodge charge " + (j + 1), new Vector2(-116f + (float)j * 11.4375f, 7.5f), new Vector2(10.2875f, 16f), color));
		}
		Type type2 = Type.GetType("TMPro.TextMeshProUGUI, Unity.TextMeshPro", throwOnError: false);
		if (type2 != null)
		{
			Object[] array = Object.FindObjectsOfType(type2);
			if (array.Length != 0)
			{
				GameObject val5 = new GameObject("Ammo count", new Type[1] { typeof(RectTransform) });
				RectTransform val6 = (RectTransform)val5.transform;
				((Transform)val6).SetParent((Transform)(object)val2, false);
				Vector2 val7 = (val6.pivot = Vector2.zero);
				val3 = (val6.anchorMin = (val6.anchorMax = val7));
				val6.anchoredPosition = new Vector2(0f, 64f);
				val6.sizeDelta = new Vector2(210f, 30f);
				ammoNumber = val5.AddComponent(type2);
				SetHudProperty(ammoNumber, "font", type2.GetProperty("font").GetValue(array[0]));
				SetHudProperty(ammoNumber, "fontSize", 24f);
				SetHudProperty(ammoNumber, "color", val4);
				SetHudProperty(ammoNumber, "raycastTarget", false);
				PropertyInfo property = type2.GetProperty("alignment");
				property.SetValue(ammoNumber, Enum.Parse(property.PropertyType, "Right"));
			}
		}
		((Transform)val2).SetAsLastSibling();
		return true;
	}

	private GameObject CreateAmmoGraphic(Type rawType, string name, Vector2 position, Vector2 size, Color color)
	{
		//IL_0014: Unknown result type (might be due to invalid IL or missing references)
		//IL_0019: Unknown result type (might be due to invalid IL or missing references)
		//IL_001f: Unknown result type (might be due to invalid IL or missing references)
		//IL_0024: Unknown result type (might be due to invalid IL or missing references)
		//IL_0036: Unknown result type (might be due to invalid IL or missing references)
		//IL_0037: Unknown result type (might be due to invalid IL or missing references)
		//IL_0038: 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_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_0045: Unknown result type (might be due to invalid IL or missing references)
		//IL_0046: Unknown result type (might be due to invalid IL or missing references)
		//IL_0047: 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_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_005e: 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_0069: 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_0070: 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_0085: Unknown result type (might be due to invalid IL or missing references)
		//IL_008c: Unknown result type (might be due to invalid IL or missing references)
		//IL_00bd: Unknown result type (might be due to invalid IL or missing references)
		//IL_00de: Unknown result type (might be due to invalid IL or missing references)
		//IL_00fb: Expected O, but got Unknown
		GameObject val = new GameObject(name, new Type[1] { typeof(RectTransform) });
		RectTransform val2 = (RectTransform)val.transform;
		((Transform)val2).SetParent(ammoHud.transform, false);
		Vector2 val3 = (val2.pivot = Vector2.zero);
		Vector2 anchorMin = (val2.anchorMax = val3);
		val2.anchorMin = anchorMin;
		((Transform)val2).localScale = Vector3.one;
		((Transform)val2).localRotation = Quaternion.identity;
		val2.anchoredPosition3D = new Vector3(position.x, position.y, 0f);
		val2.sizeDelta = size;
		Component target = val.AddComponent(rawType);
		SetHudProperty(target, "texture", Texture2D.whiteTexture);
		SetHudProperty(target, "uvRect", (object)new Rect(0f, 0f, 1f, 1f));
		SetHudProperty(target, "material", null);
		SetHudProperty(target, "color", color);
		SetHudProperty(target, "raycastTarget", false);
		return val;
	}

	private void ImportLegacySettings(IReadOnlyDictionary<string, string> previous)
	{
		ConfigEntry<bool> val = ((BaseUnityPlugin)this).Config.Bind<bool>("Migration", "LegacySettingsImported", false, "Internal one-time import marker. Keep true to preserve your integrated settings.");
		if (val.Value)
		{
			return;
		}
		Dictionary<string, string> shotgun = LegacySettings.ReadFile(Path.Combine(Paths.ConfigPath, "local.bei.hostunarmedshotgun.cfg"));
		Dictionary<string, string> benefits = LegacySettings.ReadFile(Path.Combine(Paths.ConfigPath, "local.bei.hostsurvivalbenefits.cfg"));
		Dictionary<string, string> dictionary = LegacySettings.SelectImports(previous, shotgun, benefits, completed: false);
		foreach (KeyValuePair<ConfigDefinition, ConfigEntryBase> item in ((BaseUnityPlugin)this).Config)
		{
			if (dictionary.TryGetValue(item.Key.Section + "/" + item.Key.Key, out var value))
			{
				item.Value.SetSerializedValue(value);
			}
		}
		val.Value = true;
		((BaseUnityPlugin)this).Logger.LogInfo((object)("Imported " + dictionary.Count + " legacy settings. Old cfg files were read only; future edits belong in local.bei.hostveteransurvivor.cfg."));
	}

	private void ProtectControlDodge(PlayerAvatar player, float slideSeconds, float invincibleSeconds)
	{
		controlDodge.Begin(player, LevelGenerator.Instance, Time.time, slideSeconds, invincibleSeconds);
	}

	private void ClearControlDodge()
	{
		controlDodge.Clear();
	}

	internal bool TryAvoidControlAttack(PlayerAvatar target)
	{
		if (!Object.op_Implicit((Object)(object)target) || (Object)(object)target != (Object)(object)PlayerAvatar.instance || !((Behaviour)this).isActiveAndEnabled || !RoleEnabled || RoleMenu.InputBlocked || !dodgeEnabled.Value || !Object.op_Implicit((Object)(object)GameManager.instance) || !SemiFunc.IsMasterClientOrSingleplayer() || !Object.op_Implicit((Object)(object)target.playerHealth) || (int)dodgeHealth.GetValue(target.playerHealth) <= 0 || (bool)avatarDisabled.GetValue(target) || (bool)avatarDead.GetValue(target) || (bool)avatarTumbling.GetValue(target))
		{
			return false;
		}
		if (controlDodge.Active(target, LevelGenerator.Instance, Time.time))
		{
			return true;
		}
		return TryEmergencyDodge(target.playerHealth);
	}

	private bool DeathExplosionEnabled()
	{
		if (((Behaviour)this).isActiveAndEnabled && RoleEnabled && Object.op_Implicit((Object)(object)GameManager.instance) && Object.op_Implicit((Object)(object)RunManager.instance) && SemiFunc.IsMasterClientOrSingleplayer())
		{
			return !SemiFunc.MenuLevel();
		}
		return false;
	}

	private Item FindDeathGrenade()
	{
		if (Object.op_Implicit((Object)(object)deathGrenadeItem))
		{
			return deathGrenadeItem;
		}
		deathGrenadeItem = ((IEnumerable<Item>)Items.AllItems).FirstOrDefault((Func<Item, bool>)((Item item) => Object.op_Implicit((Object)(object)item) && item.prefab != null && ((PrefabRef<GameObject>)(object)item.prefab).IsValid() && Object.op_Implicit((Object)(object)((PrefabRef<GameObject>)(object)item.prefab).Prefab) && Object.op_Implicit((Object)(object)((PrefabRef<GameObject>)(object)item.prefab).Prefab.GetComponent<ItemGrenadeExplosive>()) && Object.op_Implicit((Object)(object)((PrefabRef<GameObject>)(object)item.prefab).Prefab.GetComponent<ItemGrenade>()) && Object.op_Implicit((Object)(object)((PrefabRef<GameObject>)(object)item.prefab).Prefab.GetComponent<ParticleScriptExplosion>())));
		if (!Object.op_Implicit((Object)(object)deathGrenadeItem))
		{
			throw new MissingMemberException("Standard explosive grenade prefab missing.");
		}
		return deathGrenadeItem;
	}

	internal void TriggerDeathExplosion(PlayerAvatar player, Vector3 position)
	{
		//IL_0032: Unknown result type (might be due to invalid IL or missing references)
		//IL_0084: Unknown result type (might be due to invalid IL or missing references)
		//IL_0098: Unknown result type (might be due to invalid IL or missing references)
		//IL_00b6: Unknown result type (might be due to invalid IL or missing references)
		//IL_00b7: Unknown result type (might be due to invalid IL or missing references)
		try
		{
			if (!DeathExplosionEnabled() || !Object.op_Implicit((Object)(object)player) || player != PlayerAvatar.instance || !Object.op_Implicit((Object)(object)player.playerHealth) || player.playerHealth.isMenuAvatar || !ShotGeometry.Finite(position) || !Object.op_Implicit((Object)(object)LevelGenerator.Instance) || !LevelGenerator.Instance.Generated)
			{
				return;
			}
			object room = (SemiFunc.IsMultiplayer() ? network.Room : RunManager.instance);
			if (deathExplosionUses.TryConsume(LevelGenerator.Instance, room, HasNearbyLivingAlly(player, position)))
			{
				EmitLocalDeathExplosion(player, position);
				if (SemiFunc.IsMultiplayer())
				{
					deathExplosionPending = true;
					deathExplosionPlayer = player;
					deathExplosionPosition = position;
					deathExplosionStage = LevelGenerator.Instance;
					deathExplosionRoom = network.Room;
					deathExplosionDeadline = Time.unscaledTime + 5f;
					UpdateDeathExplosionProxy();
				}
			}
		}
		catch (Exception ex)
		{
			((BaseUnityPlugin)this).Logger.LogError((object)("[DeathExplosion] Could not emit death explosion: " + ex));
		}
	}

	private bool HasNearbyLivingAlly(PlayerAvatar player, Vector3 deathPosition)
	{
		//IL_0054: Unknown result type (might be due to invalid IL or missing references)
		//IL_0059: Unknown result type (might be due to invalid IL or missing references)
		//IL_005a: Unknown result type (might be due to invalid IL or missing references)
		//IL_0062: Unknown result type (might be due to invalid IL or missing references)
		//IL_0063: 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_0069: Unknown result type (might be due to invalid IL or missing references)
		foreach (PlayerAvatar item in SemiFunc.PlayerGetAll())
		{
			if (!Object.op_Implicit((Object)(object)item) || item == player || !Object.op_Implicit((Object)(object)item.playerHealth) || item.playerHealth.isMenuAvatar || (bool)avatarDead.GetValue(item))
			{
				continue;
			}
			Vector3 position = ((Component)item).transform.position;
			if (ShotGeometry.Finite(position))
			{
				Vector3 val = position - deathPosition;
				if (!DeathExplosionRules.AllyWithinExclusionRadius(((Vector3)(ref val)).sqrMagnitude))
				{
					continue;
				}
			}
			return true;
		}
		return false;
	}

	private void EmitLocalDeathExplosion(PlayerAvatar player, Vector3 position)
	{
		//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_0056: Expected O, but got Unknown
		//IL_0056: 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_0062: Unknown result type (might be due to invalid IL or missing references)
		ParticleScriptExplosion component = ((PrefabRef<GameObject>)(object)FindDeathGrenade().prefab).Prefab.GetComponent<ParticleScriptExplosion>();
		GameObject val = Resources.Load<GameObject>("Effects/Part Prefab Explosion");
		if (!Object.op_Implicit((Object)(object)val) || !Object.op_Implicit((Object)(object)component.explosionPreset))
		{
			throw new MissingMemberException("Grenade explosion resources missing.");
		}
		GameObject val2 = new GameObject("HostVeteranSurvivor.DeathExplosion");
		Object.Destroy((Object)val2, 1f);
		val2.transform.position = position;
		ParticleScriptExplosion val3 = val2.AddComponent<ParticleScriptExplosion>();
		((Behaviour)val3).enabled = false;
		val3.explosionPreset = component.explosionPreset;
		NeedField(typeof(ParticleScriptExplosion), "explosionPrefab", typeof(GameObject)).SetValue(val3, val);
		NeedField(typeof(ParticleScriptExplosion), "playerCausingHurtOverride", typeof(PlayerAvatar)).SetValue(val3, player);
		ItemGrenadeExplosive val4 = val2.AddComponent<ItemGrenadeExplosive>();
		((Behaviour)val4).enabled = false;
		NeedField(typeof(ItemGrenadeExplosive), "particleScriptExplosion", typeof(ParticleScriptExplosion)).SetValue(val4, val3);
		val4.Explosion();
	}

	private void UpdateDeathExplosionProxy()
	{
		//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)
		//IL_014c: Unknown result type (might be due to invalid IL or missing references)
		//IL_014e: Unknown result type (might be due to invalid IL or missing references)
		//IL_0329: Unknown result type (might be due to invalid IL or missing references)
		//IL_0336: Unknown result type (might be due to invalid IL or missing references)
		if (!DeathExplosionEnabled() || !SemiFunc.IsMultiplayer() || !Object.op_Implicit((Object)(object)LevelGenerator.Instance) || !LevelGenerator.Instance.Generated || !Object.op_Implicit((Object)(object)PlayerAvatar.instance))
		{
			CleanupDeathExplosion();
			return;
		}
		try
		{
			object instance = LevelGenerator.Instance;
			object room = network.Room;
			if (deathGrenadeStage != instance || deathGrenadeRoom != room)
			{
				if (deathExplosionPending && (deathExplosionStage != instance || deathExplosionRoom != room))
				{
					deathExplosionPending = false;
				}
				DestroyDeathGrenadeProxy();
				deathGrenadeStage = instance;
				deathGrenadeRoom = room;
				deathGrenadeRetryAt = 0f;
			}
			if (deathExplosionPending && Time.unscaledTime > deathExplosionDeadline)
			{
				deathExplosionPending = false;
				deathExplosionPlayer = null;
				((BaseUnityPlugin)this).Logger.LogWarning((object)"[DeathExplosion] Guest explosion preparation timed out; host explosion already occurred.");
			}
			if (!deathExplosionPending && (bool)avatarDead.GetValue(PlayerAvatar.instance))
			{
				return;
			}
			int i;
			if (!Object.op_Implicit((Object)(object)deathGrenadeProxy))
			{
				if (Time.unscaledTime < deathGrenadeRetryAt)
				{
					return;
				}
				deathGrenadeRetryAt = Time.unscaledTime + 3f;
				Vector3 val = (Vector3)disabledPosition.GetValue(AssetManager.instance);
				deathGrenadeProxy = NetworkPrefabs.SpawnNetworkPrefab(FindDeathGrenade().prefab, val, Quaternion.identity, (byte)0, new object[3] { 1f, 1f, 1f });
				if (!Object.op_Implicit((Object)(object)deathGrenadeProxy))
				{
					throw new InvalidOperationException("Death grenade carrier spawn failed.");
				}
				MonoBehaviour[] componentsInChildren = deathGrenadeProxy.GetComponentsInChildren<MonoBehaviour>(true);
				foreach (MonoBehaviour val2 in componentsInChildren)
				{
					if (Object.op_Implicit((Object)(object)val2) && ((object)val2).GetType().Name != "PhotonView" && ((object)val2).GetType().Name != "PhotonTransformView")
					{
						((Behaviour)val2).enabled = false;
					}
				}
				Collider[] componentsInChildren2 = deathGrenadeProxy.GetComponentsInChildren<Collider>(true);
				for (i = 0; i < componentsInChildren2.Length; i++)
				{
					componentsInChildren2[i].enabled = false;
				}
				Rigidbody component = deathGrenadeProxy.GetComponent<Rigidbody>();
				component.isKinematic = true;
				component.useGravity = false;
				component.detectCollisions = false;
				deathGrenadeReadyAt = Time.unscaledTime + 0.75f;
			}
			string text = network.Roster(out i);
			if (text != deathGrenadeRoster)
			{
				deathGrenadeRoster = text;
				deathGrenadeReadyAt = Time.unscaledTime + 0.75f;
			}
			if (deathExplosionPending && !(Time.unscaledTime < deathGrenadeReadyAt))
			{
				int num = (Object.op_Implicit((Object)(object)deathExplosionPlayer) ? network.ViewId(((Component)deathExplosionPlayer).gameObject) : 0);
				deathExplosionPending = false;
				if (num > 0)
				{
					network.Rpc(deathGrenadeProxy, "SetActivatorRPC", true, num);
				}
				network.Rpc(deathGrenadeProxy, "SetPositionRPC", true, deathExplosionPosition, Quaternion.identity);
				network.Rpc(deathGrenadeProxy, "TickEndRPC", true);
				deathExplosionPlayer = null;
				DestroyDeathGrenadeProxy();
			}
		}
		catch (Exception ex)
		{
			DestroyDeathGrenadeProxy();
			deathGrenadeRetryAt = Time.unscaledTime + 3f;
			((BaseUnityPlugin)this).Logger.LogWarning((object)("[DeathExplosion] Guest explosion carrier failed: " + ex));
		}
	}

	private void DestroyDeathGrenadeProxy()
	{
		GameObject val = deathGrenadeProxy;
		deathGrenadeProxy = null;
		deathGrenadeRoster = null;
		if (!Object.op_Implicit((Object)(object)val))
		{
			return;
		}
		try
		{
			network.Destroy(val);
		}
		catch (Exception ex)
		{
			((BaseUnityPlugin)this).Logger.LogWarning((object)("[DeathExplosion] Carrier cleanup failed: " + ex.Message));
		}
	}

	private void CleanupDeathExplosion()
	{
		deathExplosionPending = false;
		deathExplosionPlayer = null;
		DestroyDeathGrenadeProxy();
		deathGrenadeStage = (deathGrenadeRoom = null);
		deathGrenadeRetryAt = 0f;
	}

	private void BindDodgeSettings()
	{
		//IL_0050: Unknown result type (might be due to invalid IL or missing references)
		//IL_005a: Expected O, but got Unknown
		//IL_008e: Unknown result type (might be due to invalid IL or missing references)
		//IL_0098: Expected O, but got Unknown
		//IL_00b5: Unknown result type (might be due to invalid IL or missing references)
		dodgeEnabled = ((BaseUnityPlugin)this).Config.Bind<bool>("EmergencyDodge", "Enabled", true, "Enable emergency sliding while HoldKey is held. Also requires General.Enabled. Host/solo only.");
		dodgeInvincibilitySeconds = ((BaseUnityPlugin)this).Config.Bind<float>("EmergencyDodge", "InvincibilitySeconds", 0.5f, new ConfigDescription("Native invincibility after a successful dodge, in game seconds. 0 disables it. Also affects other damage handled by native invincibility, including shotgun self-damage.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0f, 10f), Array.Empty<object>()));
		dodgeDistanceMultiplier = ((BaseUnityPlugin)this).Config.Bind<float>("EmergencyDodge", "DistanceMultiplier", 1.3f, new ConfigDescription("Scale the automatic dodge's initial slide velocity and decay vector. 1 restores previous distance; 1.3 is approximately 30% farther. Obstacles, input and physics affect actual travel. Does not change normal slides or duration.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0.1f, 3f), Array.Empty<object>()));
		dodgeKey = ((BaseUnityPlugin)this).Config.Bind<KeyboardShortcut>("EmergencyDodge", "HoldKey", new KeyboardShortcut((KeyCode)114, Array.Empty<KeyCode>()), "Hold to evade incoming attacks, including while airborne or crouching. No activation while tumbling or already sliding; release to stop accepting attacks. Replaces ActivationKey/WindowSeconds from 1.1.0. Default R. This key also arms the unarmed shotgun (hold + Interact). None disables both key-triggered actions.");
	}

	[MethodImpl(MethodImplOptions.NoInlining)]
	internal float DodgeStaminaCost(PlayerController controller)
	{
		return 5f;
	}

	private void InitializeDodge()
	{
		dodgeHealth = NeedField(typeof(PlayerHealth), "health", typeof(int));
		dodgeInvincible = NeedField(typeof(PlayerHealth), "invincibleTimer", typeof(float));
		dodgeGodMode = NeedField(typeof(PlayerHealth), "godMode", typeof(bool));
		dodgeKinematic = NeedField(typeof(PlayerController), "kinematicTimer", typeof(float));
		dodgeMoveForce = NeedField(typeof(PlayerController), "MoveForceTimer", typeof(float));
		dodgeCanSlide = NeedField(typeof(PlayerController), "CanSlide", typeof(bool));
		dodgeSlideTimer = NeedField(typeof(PlayerController), "SlideTimer", typeof(float));
		dodgeSlideDirection = NeedField(typeof(PlayerController), "SlideDirection", typeof(Vector3));
		dodgeSlideCurrent = NeedField(typeof(PlayerController), "SlideDirectionCurrent", typeof(Vector3));
		dodgeCrouchActive = NeedField(typeof(PlayerController), "CrouchActiveTimer", typeof(float));
		dodgeCrouchInactive = NeedField(typeof(PlayerController), "CrouchInactiveTimer", typeof(float));
		dodgeSprinted = NeedField(typeof(PlayerController), "SprintedTimer", typeof(float));
		dodgeRecharge = NeedField(typeof(PlayerController), "sprintRechargeTimer", typeof(float));
	}

	private bool CanEmergencyDodge(PlayerHealth health)
	{
		//IL_0073: Unknown result type (might be due to invalid IL or missing references)
		//IL_0079: Invalid comparison between Unknown and I4
		if (!((Behaviour)this).isActiveAndEnabled || !RoleEnabled || RoleMenu.InputBlocked || !dodgeEnabled.Value || !Object.op_Implicit((Object)(object)GameManager.instance) || !Object.op_Implicit((Object)(object)RunManager.instance) || !Object.op_Implicit((Object)(object)InputManager.instance) || !SemiFunc.IsMasterClientOrSingleplayer() || SemiFunc.MenuLevel() || !Object.op_Implicit((Object)(object)GameDirector.instance) || GameDirector.instance.DisableInput || (int)GameDirector.instance.currentState != 2 || Time.timeScale <= 0f)
		{
			return false;
		}
		PlayerAvatar instance = PlayerAvatar.instance;
		PlayerController instance2 = PlayerController.instance;
		if (!Object.op_Implicit((Object)(object)health) || !Object.op_Implicit((Object)(object)instance) || (Object)(object)instance.playerHealth != (Object)(object)health || !Object.op_Implicit((Object)(object)instance2) || (Object)(object)instance2.playerAvatarScript != (Object)(object)instance || !Object.op_Implicit((Object)(object)instance2.rb) || instance2.rb.isKinematic || !Object.op_Implicit((Object)(object)instance2.CollisionController) || instance2.Sliding || (!instance2.DebugEnergy && instance2.EnergyCurrent <= 0f) || (float)inputDisabled.GetValue(instance2) > 0f || (float)dodgeKinematic.GetValue(instance2) > 0f || (float)dodgeMoveForce.GetValue(instance2) > 0f || (int)dodgeHealth.GetValue(health) <= 0)
		{
			return false;
		}
		if (LevelGenerator.Instance == null || !LevelGenerator.Instance.Generated || (bool)avatarDisabled.GetValue(instance) || (bool)avatarDead.GetValue(instance) || (bool)avatarTumbling.GetValue(instance) || !(bool)avatarSpawned.GetValue(instance))
		{
			return false;
		}
		if (Object.op_Implicit((Object)(object)instance.mapToolController) && (bool)mapActive.GetValue(instance.mapToolController))
		{
			return false;
		}
		if (Object.op_Implicit((Object)(object)MenuManager.instance) && (int)menuState.GetValue(MenuManager.instance) == 0)
		{
			return false;
		}
		if (Object.op_Implicit((Object)(object)ChatManager.instance) && (bool)chatActive.GetValue(ChatManager.instance))
		{
			return false;
		}
		return GUIUtility.keyboardControl == 0;
	}

	private bool DodgeKeyHeld()
	{
		//IL_0006: Unknown result type (might be due to invalid IL or missing references)
		//IL_000b: Unknown result type (might be due to invalid IL or missing references)
		//IL_000e: 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_003a: Unknown result type (might be due to invalid IL or missing references)
		//IL_003f: Unknown result type (might be due to invalid IL or missing references)
		//IL_0045: Unknown result type (might be due to invalid IL or missing references)
		KeyboardShortcut value = dodgeKey.Value;
		if ((int)((KeyboardShortcut)(ref value)).MainKey == 0 || !UnityInput.Current.GetKey(((KeyboardShortcut)(ref value)).MainKey))
		{
			return false;
		}
		foreach (KeyCode modifier in ((KeyboardShortcut)(ref value)).Modifiers)
		{
			if (!UnityInput.Current.GetKey(modifier))
			{
				return false;
			}
		}
		return true;
	}

	internal bool TryDirectEmergencyDodge(PlayerHealth health, int damage, int enemyIndex)
	{
		if (enemyIndex >= 0 && damage > 0)
		{
			return TryEmergencyDodge(health);
		}
		return false;
	}

	internal bool TryEmergencyDodge(PlayerHealth health)
	{
		//IL_00d8: 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_00f0: 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_0155: Unknown result type (might be due to invalid IL or missing references)
		//IL_0157: Unknown result type (might be due to invalid IL or missing references)
		//IL_016d: Unknown result type (might be due to invalid IL or missing references)
		//IL_016f: Unknown result type (might be due to invalid IL or missing references)
		UpdateAmmoContext();
		if (dodgeEnergy.Remaining <= 0 || !CanEmergencyDodge(health) || !DodgeKeyHeld() || lastDodgeFrame == Time.frameCount || (float)dodgeInvincible.GetValue(health) > 0f || (bool)dodgeGodMode.GetValue(health))
		{
			return false;
		}
		PlayerController instance = PlayerController.instance;
		float slideTime = instance.SlideTime;
		float num = Mathf.Max(instance.MoveSpeed, instance.SprintSpeed);
		if (float.IsNaN(slideTime) || float.IsInfinity(slideTime) || slideTime <= 0f || float.IsNaN(num) || float.IsInfinity(num) || num <= 0f)
		{
			return false;
		}
		num = DodgeMotion.ScaleSpeed(num, dodgeDistanceMultiplier.Value);
		Vector3 val = default(Vector3);
		((Vector3)(ref val))..ctor(SemiFunc.InputMovementX(), 0f, SemiFunc.InputMovementY());
		if (!ShotGeometry.Finite(val))
		{
			return false;
		}
		val = ((((Vector3)(ref val)).sqrMagnitude > 0.01f) ? ((Vector3)(ref val)).normalized : Vector3.back);
		lastDodgeFrame = Time.frameCount;
		if (busy)
		{
			((MonoBehaviour)this).StopAllCoroutines();
			CleanupShot();
			busy = false;
		}
		dodgeCanSlide.SetValue(instance, false);
		dodgeSprinted.SetValue(instance, 0f);
		dodgeSlideDirection.SetValue(instance, val * num);
		dodgeSlideCurrent.SetValue(instance, val * num);
		dodgeSlideTimer.SetValue(instance, slideTime);
		dodgeCrouchInactive.SetValue(instance, 0f);
		dodgeCrouchActive.SetValue(instance, Mathf.Max(slideTime, instance.CrouchTimeMin));
		instance.CrouchOverride(slideTime);
		instance.Crouching = true;
		instance.sprinting = false;
		instance.Sliding = true;
		dodgeEnergy.TryConsume();
		instance.moving = true;
		instance.CanInteract = false;
		if (!instance.DebugEnergy)
		{
			instance.EnergyCurrent = Mathf.Max(0f, instance.EnergyCurrent - DodgeStaminaCost(instance));
		}
		dodgeRecharge.SetValue(instance, Mathf.Max(1f, (float)dodgeRecharge.GetValue(instance)));
		float value = dodgeInvincibilitySeconds.Value;
		ProtectControlDodge(instance.playerAvatarScript, slideTime, value);
		if (!float.IsNaN(value) && !float.IsInfinity(value) && value > 0f)
		{
			health.InvincibleSet(Mathf.Max((float)dodgeInvincible.GetValue(health), Mathf.Clamp(value, 0f, 10f)));
		}
		instance.ChangeState();
		try
		{
			instance.playerAvatarScript.Slide();
		}
		catch (Exception ex)
		{
			((BaseUnityPlugin)this).Logger.LogWarning((object)("Emergency slide effect failed: " + ex.Message));
		}
		try
		{
			EmitTumbleBreakSmoke(instance.playerAvatarScript, follow: false);
		}
		catch (Exception ex2)
		{
			((BaseUnityPlugin)this).Logger.LogWarning((object)("Emergency dodge smoke failed: " + ex2.Message));
		}
		return true;
	}

	private void Awake()
	{
		bool saveOnConfigSet = ((BaseUnityPlugin)this).Config.SaveOnConfigSet;
		((BaseUnityPlugin)this).Config.SaveOnConfigSet = false;
		try
		{
			Dictionary<string, string> previous = LegacySettings.ReadFile(((BaseUnityPlugin)this).Config.ConfigFilePath);
			BindShotgunSettings();
			BindDodgeSettings();
			BindReloadSettings();
			ImportLegacySettings(previous);
		}
		catch (Exception ex)
		{
			((Behaviour)this).enabled = false;
			((BaseUnityPlugin)this).Logger.LogError((object)("Configuration could not be loaded; original config files were not modified: " + ex));
			return;
		}
		finally
		{
			((BaseUnityPlugin)this).Config.SaveOnConfigSet = saveOnConfigSet;
		}
		try
		{
			((BaseUnityPlugin)this).Config.Save();
		}
		catch (Exception ex2)
		{
			((BaseUnityPlugin)this).Logger.LogWarning((object)("Could not save integrated settings: " + ex2.Message));
		}
		InitializePlugin();
	}

	private void BindShotgunSettings()
	{
		//IL_0049: Unknown result type (might be due to invalid IL or missing references)
		//IL_0053: Expected O, but got Unknown
		//IL_0087: Unknown result type (might be due to invalid IL or missing references)
		//IL_0091: Expected O, but got Unknown
		//IL_010a: Unknown result type (might be due to invalid IL or missing references)
		//IL_0114: Expected O, but got Unknown
		//IL_0148: Unknown result type (might be due to invalid IL or missing references)
		//IL_0152: Expected O, but got Unknown
		//IL_0186: Unknown result type (might be due to invalid IL or missing references)
		//IL_0190: Expected O, but got Unknown
		//IL_01c4: Unknown result type (might be due to invalid IL or missing references)
		//IL_01ce: Expected O, but got Unknown
		//IL_0202: Unknown result type (might be due to invalid IL or missing references)
		//IL_020c: Expected O, but got Unknown
		modEnabled = ((BaseUnityPlugin)this).Config.Bind<bool>("General", "Enabled", true, "Enable all integrated features, including the once-per-stage death explosion, for the local host or single-player only.");
		selfDamagePerShot = ((BaseUnityPlugin)this).Config.Bind<int>("Shooting", "SelfDamagePerShot", 10, new ConfigDescription("Health cost per fired shot. 0 disables self-damage. Applied through the vanilla health-donation damage path.", (AcceptableValueBase)(object)new AcceptableValueRange<int>(0, 1000), Array.Empty<object>()));
		cooldownOverride = ((BaseUnityPlugin)this).Config.Bind<float>("Shooting", "CooldownSeconds", 0f, new ConfigDescription("0 uses the vanilla shotgun cooldown. The temporary shot lifecycle must also finish before the next shot.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0f, 60f), Array.Empty<object>()));
		shotgunPrefabName = ((BaseUnityPlugin)this).Config.Bind<string>("Shooting", "ShotgunPrefabName", "", "Optional exact vanilla shotgun PrefabName. Empty searches the catalog.");
		((BaseUnityPlugin)this).Config.Bind<float>("Shooting", "MuzzleRightOffset", 0.3f, "Legacy setting, unused since 1.3.1. The muzzle now follows the actual right hand. Use HandForwardOffset for adjustment.");
		handForwardOffset = ((BaseUnityPlugin)this).Config.Bind<float>("Shooting", "HandForwardOffset", 0.08f, new ConfigDescription("Distance ahead of the actual right-hand grabber, along the viewing direction, in game units.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0f, 0.4f), Array.Empty<object>()));
		warmupSeconds = ((BaseUnityPlugin)this).Config.Bind<float>("Network", "SpawnWarmupSeconds", 0.2f, new ConfigDescription("Time for the temporary vanilla gun to initialize before firing. Live multiplayer timing is unverified.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0.1f, 2f), Array.Empty<object>()));
		iconWarmupSeconds = ((BaseUnityPlugin)this).Config.Bind<float>("Network", "IconWarmupSeconds", 5f, new ConfigDescription("Wait after spawning a full-size offscreen shotgun so guests can cache a normal inventory icon before tiny emitters. Repeated after map/roster changes. This is a timed safeguard, not a remote completion acknowledgement. Existing blank PNGs must first be removed on affected PCs.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(1f, 30f), Array.Empty<object>()));
		poseSeconds = ((BaseUnityPlugin)this).Config.Bind<float>("Visuals", "ArmHoldSeconds", 0.9f, new ConfigDescription("Game seconds to keep the arm raised AFTER firing. Replaces GrabPoseSeconds from 1.8 and earlier.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0.1f, 3f), Array.Empty<object>()));
		poseLeadSeconds = ((BaseUnityPlugin)this).Config.Bind<float>("Visuals", "ArmRaiseSeconds", 0.65f, new ConfigDescription("Minimum game seconds between notifying observers to raise the arm and firing. Automatically extended for the native pose speed. Replaces PoseLeadSeconds from 1.8 and earlier.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0.1f, 3f), Array.Empty<object>()));
	}

	private void InitializePlugin()
	{
		//IL_01c7: Unknown result type (might be due to invalid IL or missing references)
		//IL_01d1: Expected O, but got Unknown
		//IL_0218: Unknown result type (might be due to invalid IL or missing references)
		try
		{
			avatarDisabled = NeedField(typeof(PlayerAvatar), "isDisabled", typeof(bool));
			avatarTumbling = NeedField(typeof(PlayerAvatar), "isTumbling", typeof(bool));
			avatarDead = NeedField(typeof(PlayerAvatar), "deadSet", typeof(bool));
			avatarSpawned = NeedField(typeof(PlayerAvatar), "spawned", typeof(bool));
			menuState = NeedField(typeof(MenuManager), "currentMenuState", typeof(int));
			chatActive = NeedField(typeof(ChatManager), "chatActive", typeof(bool));
			mapActive = NeedField(typeof(MapToolController), "Active", typeof(bool));
			grabCamera = NeedField(typeof(PhysGrabber), "playerCamera", typeof(Camera));
			inputDisabled = NeedField(typeof(PlayerController), "InputDisableTimer", typeof(float));
			lastGrabber = NeedField(typeof(PhysGrabObject), "lastPlayerGrabbing", typeof(PlayerAvatar));
			gunPhys = NeedField(typeof(ItemGun), "physGrabObject", typeof(PhysGrabObject));
			disabledPosition = NeedField(typeof(AssetManager), "physDisabledPosition", typeof(Vector3));
			InitializeDodge();
			network = new NativeNetwork();
			harmony = new Harmony("local.bei.hostveteransurvivor");
			harmony.PatchAll(typeof(Plugin).Assembly);
			Current = this;
			RegisterRole();
			((BaseUnityPlugin)this).Logger.LogInfo((object)$"Host Veteran Survivor 1.7.2 loaded: role menu=F5; Enabled={modEnabled.Value}; dodge=hold {dodgeKey.Value}; self-damage={selfDamagePerShot.Value}.");
		}
		catch (Exception ex)
		{
			try
			{
				Harmony obj = harmony;
				if (obj != null)
				{
					obj.UnpatchSelf();
				}
			}
			catch
			{
			}
			((Behaviour)this).enabled = false;
			((BaseUnityPlugin)this).Logger.LogError((object)("Unsupported game/network API; mod disabled: " + ex));
		}
	}

	private static FieldInfo NeedField(Type owner, string name, Type expected)
	{
		FieldInfo field = owner.GetField(name, BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);
		if (field == null || field.FieldType != expected)
		{
			throw new MissingFieldException(owner.FullName, name);
		}
		return field;
	}

	private void LateUpdate()
	{
		UpdateValuableReload();
		CleanupFadingGuns(!RoleEnabled);
		try
		{
			UpdateIconPreparation();
		}
		catch (Exception ex)
		{
			iconGate.Reset();
			((Behaviour)this).enabled = false;
			((BaseUnityPlugin)this).Logger.LogError((object)("Icon preparation failed; unarmed shotgun disabled for this run: " + ex));
			return;
		}
		if (!RoleEnabled || busy || Time.timeScale <= 0f || Time.time < nextShotAt || !Object.op_Implicit((Object)(object)GameManager.instance) || !Object.op_Implicit((Object)(object)RunManager.instance) || !Object.op_Implicit((Object)(object)InputManager.instance))
		{
			return;
		}
		try
		{
			if (!DodgeKeyHeld() || !InputManager.instance.KeyDown((InputKey)2))
			{
				return;
			}
			if (InteractionBlocksFire())
			{
				if (interactionBlockedLogCount++ < 10)
				{
					((BaseUnityPlugin)this).Logger.LogInfo((object)"Unarmed fire skipped: interaction prompt/action has priority.");
				}
			}
			else if (!iconGate.Ready(Time.unscaledTime))
			{
				if (Time.unscaledTime >= nextIconNotice)
				{
					nextIconNotice = Time.unscaledTime + 3f;
					((BaseUnityPlugin)this).Logger.LogInfo((object)"Shot skipped: preparing normal shotgun icons. Press E again after preparation.");
				}
			}
			else if (CanFire() && FindShotgun())
			{
				busy = true;
				float num = ((cooldownOverride.Value > 0f) ? cooldownOverride.Value : shotgunTemplate.shootCooldown);
				nextShotAt = Time.time + Mathf.Max(0.1f, num);
				((MonoBehaviour)this).StartCoroutine(GuardedShot());
			}
		}
		catch (Exception ex2)
		{
			busy = false;
			nextShotAt = Time.time + 2f;
			((BaseUnityPlugin)this).Logger.LogError((object)("Could not start unarmed shot: " + ex2));
		}
	}

	private void Update()
	{
		//IL_0050: Unknown result type (might be due to invalid IL or missing references)
		//IL_0056: Invalid comparison between Unknown and I4
		UpdateAmmoContext();
		if (Object.op_Implicit((Object)(object)GameManager.instance) && Object.op_Implicit((Object)(object)RunManager.instance) && !SemiFunc.MenuLevel() && SemiFunc.IsMasterClientOrSingleplayer() && LevelGenerator.Instance != null && LevelGenerator.Instance.Generated && Object.op_Implicit((Object)(object)GameDirector.instance) && (int)GameDirector.instance.currentState == 2)
		{
			dodgeEnergy.Advance(Time.deltaTime);
		}
		UpdateTumbleBonuses();
		UpdateTumbleSmokeProxy();
		UpdateDeathExplosionProxy();
		UpdateSmokeTrail();
		UpdateAmmoHud();
	}

	internal void ObserveInteractionPrompt(string rawText, string localizedText)
	{
		if (InteractionFireGate.IsInteractionPrompt(rawText, localizedText))
		{
			ObserveLocalInteraction();
		}
	}

	internal void ObserveLocalInteraction()
	{
		interactionGate.Observe(Time.frameCount, Time.time);
	}

	private bool InteractionBlocksFire()
	{
		return interactionGate.IsBlocked(Time.frameCount, Time.time);
	}

	private bool CanFire()
	{
		//IL_00b6: Unknown result type (might be due to invalid IL or missing references)
		//IL_00c0: Expected O, but got Unknown
		if (RoleMenu.InputBlocked || ammo.Remaining <= 0)
		{
			return false;
		}
		if (!Object.op_Implicit((Object)(object)iconPrimer) || !iconGate.Ready(Time.unscaledTime))
		{
			return false;
		}
		if (!Object.op_Implicit((Object)(object)GameManager.instance) || !Object.op_Implicit((Object)(object)RunManager.instance) || !RoleEnabled || !SemiFunc.IsMasterClientOrSingleplayer() || SemiFunc.MenuLevel())
		{
			return false;
		}
		if (InteractionBlocksFire())
		{
			return false;
		}
		PlayerAvatar instance = PlayerAvatar.instance;
		PlayerController instance2 = PlayerController.instance;
		PhysGrabber instance3 = PhysGrabber.instance;
		if (!Object.op_Implicit((Object)(object)instance) || !Object.op_Implicit((Object)(object)instance.playerHealth) || !Object.op_Implicit((Object)(object)instance2) || !Object.op_Implicit((Object)(object)instance3) || !Object.op_Implicit((Object)(Camera)grabCamera.GetValue(instance3)))
		{
			return false;
		}
		if (LevelGenerator.Instance == null || !LevelGenerator.Instance.Generated || (float)inputDisabled.GetValue(instance2) > 0f)
		{
			return false;
		}
		if ((bool)avatarDisabled.GetValue(instance) || (bool)avatarTumbling.GetValue(instance) || (bool)avatarDead.GetValue(instance) || !(bool)avatarSpawned.GetValue(instance))
		{
			return false;
		}
		if (instance3.grabbed || Object.op_Implicit((Object)(object)instance3.grabbedObjectTransform) || Object.op_Implicit((Object)(object)instance2.physGrabObject))
		{
			return false;
		}
		if (Object.op_Implicit((Object)(object)instance.mapToolController) && (bool)mapActive.GetValue(instance.mapToolController))
		{
			return false;
		}
		if (Object.op_Implicit((Object)(object)MenuManager.instance) && (int)menuState.GetValue(MenuManager.instance) == 0)
		{
			return false;
		}
		if (Object.op_Implicit((Object)(object)ChatManager.instance) && (bool)chatActive.GetValue(ChatManager.instance))
		{
			return false;
		}
		return GUIUtility.keyboardControl == 0;
	}

	private void UpdateIconPreparation()
	{
		//IL_0161: Unknown result type (might be due to invalid IL or missing references)
		//IL_0166: Unknown result type (might be due to invalid IL or missing references)
		//IL_0174: Unknown result type (might be due to invalid IL or missing references)
		//IL_0176: Unknown result type (might be due to invalid IL or missing references)
		if (!RoleEnabled || !Object.op_Implicit((Object)(object)GameManager.instance) || !Object.op_Implicit((Object)(object)RunManager.instance) || !SemiFunc.IsMasterClientOrSingleplayer() || SemiFunc.MenuLevel() || LevelGenerator.Instance == null || !LevelGenerator.Instance.Generated)
		{
			iconGate.Reset();
			CleanupIconPrimer();
			return;
		}
		bool flag = SemiFunc.IsMultiplayer();
		int count = 1;
		string text = (flag ? network.Roster(out count) : "solo");
		List<PlayerAvatar> list = SemiFunc.PlayerGetList();
		bool flag2 = list != null && list.Count >= count && list.All((PlayerAvatar a) => Object.op_Implicit((Object)(object)a) && (bool)avatarSpawned.GetValue(a));
		if (iconGate.Refresh(LevelGenerator.Instance, flag ? network.Room : null, text, flag2))
		{
			CleanupShot(keepMuzzleEffects: false);
			CleanupFadingGuns(force: true);
			((MonoBehaviour)this).StopAllCoroutines();
			busy = false;
			CleanupIconPrimer();
		}
		if (!flag2 || (iconGate.Started && Object.op_Implicit((Object)(object)iconPrimer)))
		{
			return;
		}
		if (Object.op_Implicit((Object)(object)iconPrimer))
		{
			CleanupIconPrimer();
		}
		iconGate.Reset();
		iconGate.Refresh(LevelGenerator.Instance, flag ? network.Room : null, text, flag2);
		if (FindShotgun())
		{
			Vector3 val = (Vector3)disabledPosition.GetValue(AssetManager.instance);
			iconPrimer = NetworkPrefabs.SpawnNetworkPrefab(shotgunItem.prefab, val, Quaternion.identity, (byte)0, new object[3] { 1f, 1f, 1f });
			if (!Object.op_Implicit((Object)(object)iconPrimer))
			{
				throw new InvalidOperationException("Normal-size icon primer did not spawn.");
			}
			ItemAttributes component = iconPrimer.GetComponent<ItemAttributes>();
			PhysGrabObject component2 = iconPrimer.GetComponent<PhysGrabObject>();
			Rigidbody component3 = iconPrimer.GetComponent<Rigidbody>();
			if (!Object.op_Implicit((Object)(object)component) || !Object.op_Implicit((Object)(object)component2) || !Object.op_Implicit((Object)(object)component3))
			{
				throw new InvalidOperationException("Icon primer components missing.");
			}
			((Behaviour)component).enabled = false;
			((Behaviour)component2).enabled = false;
			Collider[] componentsInChildren = iconPrimer.GetComponentsInChildren<Collider>(true);
			for (int num = 0; num < componentsInChildren.Length; num++)
			{
				componentsInChildren[num].enabled = false;
			}
			component3.useGravity = false;
			component3.detectCollisions = false;
			component3.isKinematic = true;
			iconGate.Begin(Time.unscaledTime, iconWarmupSeconds.Value);
			((BaseUnityPlugin)this).Logger.LogInfo((object)("Normal-size shotgun icon preparation started; wait=" + iconWarmupSeconds.Value + "s; peers=" + text));
		}
	}

	private void CleanupIconPrimer()
	{
		if (!Object.op_Implicit((Object)(object)iconPrimer))
		{
			iconPrimer = null;
			return;
		}
		if (DestroyProxy(iconPrimer))
		{
			iconPrimer = null;
			return;
		}
		throw new InvalidOperationException("Could not remove the previous icon primer.");
	}

	private bool FindShotgun()
	{
		if (Object.op_Implicit((Object)(object)shotgunTemplate) && Object.op_Implicit((Object)(object)shotgunItem))
		{
			return true;
		}
		if (!Object.op_Implicit((Object)(object)StatsManager.instance) || Time.unscaledTime < nextCatalogAttempt)
		{
			return false;
		}
		nextCatalogAttempt = Time.unscaledTime + 2f;
		string exact = shotgunPrefabName.Value.Trim();
		foreach (Item item in (from item in Items.AllItems
			where Object.op_Implicit((Object)(object)item) && item.prefab != null && ((PrefabRef<GameObject>)(object)item.prefab).IsValid()
			where (exact.Length <= 0) ? (ContainsShotgun(((PrefabRef<GameObject>)(object)item.prefab).PrefabName) || ContainsShotgun(((Object)item).name)) : string.Equals(((PrefabRef<GameObject>)(object)item.prefab).PrefabName, exact, StringComparison.OrdinalIgnoreCase)
			orderby (!(NormalizeName(((PrefabRef<GameObject>)(object)item.prefab).PrefabName) == "itemgunshotgun")) ? 1 : 0
			select item).ThenBy<Item, string>((Item item) => ((PrefabRef<GameObject>)(object)item.prefab).PrefabName, StringComparer.Ordinal))
		{
			GameObject prefab = ((PrefabRef<GameObject>)(object)item.prefab).Prefab;
			if (Object.op_Implicit((Object)(object)prefab))
			{
				ItemGun component = prefab.GetComponent<ItemGun>();
				if (Object.op_Implicit((Object)(object)component) && Object.op_Implicit((Object)(object)component.gunMuzzle) && Object.op_Implicit((Object)(object)component.bulletPrefab) && component.numberOfBullets > 0 && !(component.gunRange <= 0f))
				{
					shotgunItem = item;
					shotgunTemplate = component;
					((BaseUnityPlugin)this).Logger.LogInfo((object)$"Vanilla shot source: {((PrefabRef<GameObject>)(object)item.prefab).PrefabName}; path={((PrefabRef<GameObject>)(object)item.prefab).ResourcePath}; pellets={component.numberOfBullets}; range={component.gunRange}; cooldown={component.shootCooldown}");
					return true;
				}
			}
		}
		((BaseUnityPlugin)this).Logger.LogWarning((object)"Vanilla shotgun data is not available yet. Try after level loading, or set its exact ShotgunPrefabName.");
		return false;
	}

	private static bool ContainsShotgun(string name)
	{
		if (name != null)
		{
			return name.IndexOf("shotgun", StringComparison.OrdinalIgnoreCase) >= 0;
		}
		return false;
	}

	private static string NormalizeName(string name)
	{
		return new string((name ?? "").Where(char.IsLetterOrDigit).ToArray()).ToLowerInvariant();
	}

	private IEnumerator GuardedShot()
	{
		IEnumerator shot = ShotSequence();
		try
		{
			while (true)
			{
				object current;
				try
				{
					if (!shot.MoveNext())
					{
						break;
					}
					current = shot.Current;
				}
				catch (Exception ex)
				{
					nextShotAt = Time.time + 2f;
					((BaseUnityPlugin)this).Logger.LogError((object)("Unarmed shot failed: " + ex));
					break;
				}
				yield return current;
			}
		}
		finally
		{
			Plugin plugin = this;
			(shot as IDisposable)?.Dispose();
			plugin.CleanupShot();
			plugin.busy = false;
		}
	}

	private IEnumerator ShotSequence()
	{
		PlayerAvatar shooter = PlayerAvatar.instance;
		posingGrabber = PhysGrabber.instance;
		Camera aimCamera = (Camera)grabCamera.GetValue(posingGrabber);
		posingArm = (Object.op_Implicit((Object)(object)shooter.playerAvatarVisuals) ? ((Component)shooter.playerAvatarVisuals).GetComponentInChildren<PlayerAvatarRightArm>(true) : null);
		if (!Object.op_Implicit((Object)(object)posingArm) || !Object.op_Implicit((Object)(object)posingArm.grabberTransform) || !Object.op_Implicit((Object)(object)posingArm.rightArmParentTransform))
		{
			throw new InvalidOperationException("Right-hand transforms are unavailable. Shot canceled.");
		}
		shotShooter = shooter;
		float raiseSeconds = ArmPoseTiming.RaiseDuration(poseLeadSeconds.Value, posingArm.poseSpeed);
		float holdSeconds = poseSeconds.Value;
		posingArm.GrabberPoseOverride(0.25f);
		Vector3 val = (Vector3)disabledPosition.GetValue(AssetManager.instance);
		temporaryGun = NetworkPrefabs.SpawnNetworkPrefab(shotgunItem.prefab, val, Quaternion.identity, (byte)0, new object[3] { 0.0001f, 0.0001f, 0.0001f });
		temporaryGunDestroyAt = 0f;
		if (!Object.op_Implicit((Object)(object)temporaryGun))
		{
			throw new InvalidOperationException("The temporary vanilla shotgun did not spawn.");
		}
		temporaryGun.transform.localScale = Vector3.one * 0.0001f;
		ItemGun gun = temporaryGun.GetComponent<ItemGun>();
		PhysGrabObject phys = temporaryGun.GetComponent<PhysGrabObject>();
		Rigidbody body = temporaryGun.GetComponent<Rigidbody>();
		if (!Object.op_Implicit((Object)(object)gun) || !Object.op_Implicit((Object)(object)phys) || !Object.op_Implicit((Object)(object)body))
		{
			throw new InvalidOperationException("Shotgun components are missing.");
		}
		ItemAttributes component = temporaryGun.GetComponent<ItemAttributes>();
		if (Object.op_Implicit((Object)(object)component))
		{
			((Behaviour)component).enabled = false;
		}
		((Behaviour)phys).enabled = false;
		Transform val2 = (Object.op_Implicit((Object)(object)gun.muzzleFlashPrefab) ? gun.muzzleFlashPrefab.transform : null);
		Renderer[] componentsInChildren = temporaryGun.GetComponentsInChildren<Renderer>(true);
		foreach (Renderer val3 in componentsInChildren)
		{
			if (!Object.op_Implicit((Object)(object)val2) || !((Component)val3).transform.IsChildOf(val2))
			{
				val3.enabled = false;
			}
		}
		Collider[] componentsInChildren2 = temporaryGun.GetComponentsInChildren<Collider>(true);
		for (int i = 0; i < componentsInChildren2.Length; i++)
		{
			componentsInChildren2[i].enabled = false;
		}
		body.useGravity = false;
		body.detectCollisions = false;
		body.isKinematic = true;
		lastGrabber.SetValue(phys, shooter);
		float readyAt = Time.unscaledTime + warmupSeconds.Value;
		float timeoutAt = readyAt + 5f;
		do
		{
			yield return null;
			if (!Object.op_Implicit((Object)(object)temporaryGun) || !Object.op_Implicit((Object)(object)shooter) || !CanFire())
			{
				yield break;
			}
			posingArm.GrabberPoseOverride(0.25f);
			if (Time.unscaledTime >= timeoutAt)
			{
				throw new TimeoutException("Vanilla shotgun Start did not finish.");
			}
		}
		while (Time.unscaledTime < readyAt || gunPhys.GetValue(gun) == null);
		((Behaviour)gun).enabled = false;
		gun.gunRecoilForce = 0f;
		body.isKinematic = false;
		ItemBattery component2 = temporaryGun.GetComponent<ItemBattery>();
		if (Object.op_Implicit((Object)(object)component2))
		{
			component2.SetBatteryLife(100);
		}
		if (!MoveEmitter(phys, aimCamera))
		{
			yield break;
		}
		yield return null;
		if (!Object.op_Implicit((Object)(object)temporaryGun) || !CanFire())
		{
			yield break;
		}
		if (SemiFunc.IsMultiplayer())
		{
			int num = network.ViewId(((Component)posingGrabber).gameObject);
			remotePoseSent = true;
			network.Rpc(temporaryGun, "GrabLinkRPC", true, num, -1, gun.gunMuzzle.position, Vector3.forward, Vector3.up);
			network.Rpc(((Component)posingGrabber).gameObject, "PhysGrabBeamActivateRPC", true);
		}
		for (float raisedFor = 0f; raisedFor < raiseSeconds; raisedFor += Time.deltaTime)
		{
			if (!Object.op_Implicit((Object)(object)temporaryGun) || !Object.op_Implicit((Object)(object)posingArm) || !CanFire())
			{
				yield break;
			}
			posingArm.GrabberPoseOverride(0.25f);
			if (!MoveEmitter(phys, aimCamera))
			{
				yield break;
			}
			yield return null;
		}
		yield return (object)new WaitForEndOfFrame();
		if (!Object.op_Implicit((Object)(object)temporaryGun) || !CanFire() || !MoveEmitter(phys, aimCamera))
		{
			yield break;
		}
		posingArm.GrabberPoseOverride(0.25f);
		if (!ammo.TryConsume())
		{
			yield break;
		}
		network.Rpc(temporaryGun, "ShootRPC", false);
		temporaryGunDestroyAt = Time.time + 2.5f;
		if (selfDamagePerShot.Value > 0)
		{
			shooter.playerHealth.Hurt(selfDamagePerShot.Value, false, -1, true);
		}
		float heldFor = 0f;
		float moveAt = Time.unscaledTime;
		for (; heldFor < holdSeconds; heldFor += Time.deltaTime)
		{
			if (!Object.op_Implicit((Object)(object)temporaryGun))
			{
				break;
			}
			if (!Object.op_Implicit((Object)(object)shooter))
			{
				break;
			}
			if (!Object.op_Implicit((Object)(object)posingGrabber))
			{
				break;
			}
			if (!Object.op_Implicit((Object)(object)posingArm))
			{
				break;
			}
			if (!RoleEnabled)
			{
				break;
			}
			if (posingGrabber.grabbed)
			{
				break;
			}
			if (Object.op_Implicit((Object)(object)posingGrabber.grabbedObjectTransform))
			{
				break;
			}
			if ((bool)avatarDead.GetValue(shooter))
			{
				break;
			}
			if ((bool)avatarTumbling.GetValue(shooter))
			{
				break;
			}
			if (Object.op_Implicit((Object)(object)shooter.mapToolController) && (bool)mapActive.GetValue(shooter.mapToolController))
			{
				break;
			}
			posingArm.GrabberPoseOverride(0.25f);
			if (Time.unscaledTime >= moveAt && Object.op_Implicit((Object)(object)aimCamera))
			{
				if (!MoveEmitter(phys, aimCamera))
				{
					break;
				}
				moveAt = Time.unscaledTime + 0.1f;
			}
			yield return null;
		}
	}

	internal bool TryObserverAim(PhysGrabber grabber, out Vector3 target)
	{
		//IL_0001: 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_0091: Expected O, but got Unknown
		//IL_00b9: Unknown result type (might be due to invalid IL or missing references)
		//IL_00c4: Unknown result type (might be due to invalid IL or missing references)
		//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_00d8: Unknown result type (might be due to invalid IL or missing references)
		//IL_00de: Unknown result type (might be due to invalid IL or missing references)
		target = default(Vector3);
		if (!((Behaviour)this).isActiveAndEnabled || !RoleEnabled || !remotePoseSent || !Object.op_Implicit((Object)(object)temporaryGun) || !Object.op_Implicit((Object)(object)posingArm) || !Object.op_Implicit((Object)(object)shotShooter) || (Object)(object)grabber != (Object)(object)posingGrabber || (Object)(object)grabber != (Object)(object)PhysGrabber.instance || grabber.grabbed || Object.op_Implicit((Object)(object)grabber.grabbedObjectTransform) || !SemiFunc.IsMasterClientOrSingleplayer())
		{
			return false;
		}
		Camera val = (Camera)grabCamera.GetValue(grabber);
		if (!Object.op_Implicit((Object)(object)val) || !Object.op_Implicit((Object)(object)posingArm.grabberTransform))
		{
			return false;
		}
		target = posingArm.grabberTransform.position + ((Component)val).transform.forward * 0.35f;
		return ShotGeometry.Finite(target);
	}

	private bool MoveEmitter(PhysGrabObject phys, Camera aimCamera)
	{
		//IL_0053: Unknown result type (might be due to invalid IL or missing references)
		//IL_0058: 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_0069: Unknown result type (might be due to invalid IL or missing references)
		//IL_0070: Unknown result type (might be due to invalid IL or missing references)
		//IL_0075: Unknown result type (might be due to invalid IL or missing references)
		//IL_0076: Unknown result type (might be due to invalid IL or missing references)
		//IL_007e: 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_008e: 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)
		//IL_0095: Unknown result type (might be due to invalid IL or missing references)
		//IL_00ac: Unknown result type (might be due to invalid IL or missing references)
		//IL_00ad: Unknown result type (might be due to invalid IL or missing references)
		//IL_00b9: Unknown result type (might be due to invalid IL or missing references)
		//IL_00be: Unknown result type (might be due to invalid IL or missing references)
		//IL_00bf: Unknown result type (might be due to invalid IL or missing references)
		//IL_00db: Unknown result type (might be due to invalid IL or missing references)
		//IL_00e0: Unknown result type (might be due to invalid IL or missing references)
		//IL_00e5: Unknown result type (might be due to invalid IL or missing references)
		//IL_00e9: Unknown result type (might be due to invalid IL or missing references)
		//IL_00f7: Unknown result type (might be due to invalid IL or missing references)
		//IL_0112: Unknown result type (might be due to invalid IL or missing references)
		//IL_0117: Unknown result type (might be due to invalid IL or missing references)
		//IL_0120: Unknown result type (might be due to invalid IL or missing references)
		//IL_0121: Unknown result type (might be due to invalid IL or missing references)
		//IL_012d: Unknown result type (might be due to invalid IL or missing references)
		//IL_0132: Unknown result type (might be due to invalid IL or missing references)
		//IL_0137: Unknown result type (might be due to invalid IL or missing references)
		//IL_013c: 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_0173: Unknown result type (might be due to invalid IL or missing references)
		//IL_0174: Unknown result type (might be due to invalid IL or missing references)
		//IL_0175: Unknown result type (might be due to invalid IL or missing references)
		//IL_0177: Unknown result type (might be due to invalid IL or missing references)
		//IL_0182: Unknown result type (might be due to invalid IL or missing references)
		//IL_0187: Unknown result type (might be due to invalid IL or missing references)
		//IL_0197: Unknown result type (might be due to invalid IL or missing references)
		//IL_019c: Unknown result type (might be due to invalid IL or missing references)
		//IL_01ac: Unknown result type (might be due to invalid IL or missing references)
		//IL_01b1: Unknown result type (might be due to invalid IL or missing references)
		//IL_01b6: Unknown result type (might be due to invalid IL or missing references)
		//IL_01b8: Unknown result type (might be due to invalid IL or missing references)
		//IL_01ba: Unknown result type (might be due to invalid IL or missing references)
		//IL_01bf: 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_01dc: 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_01e9: Unknown result type (might be due to invalid IL or missing references)
		//IL_01ea: Unknown result type (might be due to invalid IL or missing references)
		//IL_01ec: Unknown result type (might be due to invalid IL or missing references)
		//IL_01f3: Unknown result type (might be due to invalid IL or missing references)
		//IL_01f8: Unknown result type (might be due to invalid IL or missing references)
		//IL_01fd: Unknown result type (might be due to invalid IL or missing references)
		//IL_0202: Unknown result type (might be due to invalid IL or missing references)
		//IL_016c: Unknown result type (might be due to invalid IL or missing references)
		//IL_0171: Unknown result type (might be due to invalid IL or missing references)
		if (!Object.op_Implicit((Object)(object)posingArm) || !Object.op_Implicit((Object)(object)posingArm.grabberTransform) || !Object.op_Implicit((Object)(object)posingArm.rightArmParentTransform) || !Object.op_Implicit((Object)(object)aimCamera) || !Object.op_Implicit((Object)(object)shotShooter))
		{
			return false;
		}
		Vector3 position = posingArm.grabberTransform.position;
		Vector3 position2 = posingArm.rightArmParentTransform.position;
		Vector3 forward = ((Component)aimCamera).transform.forward;
		if (ShotGeometry.Finite(position) && ShotGeometry.Finite(position2) && ShotGeometry.Finite(forward))
		{
			Vector3 val = position - position2;
			if (!(((Vector3)(ref val)).sqrMagnitude > 36f))
			{
				Vector3 val2 = ShotGeometry.MuzzlePosition(position, forward, handForwardOffset.Value);
				int num = LayerMask.op_Implicit(SemiFunc.LayerMaskGetVisionObstruct());
				Ray val3 = aimCamera.ViewportPointToRay(new Vector3(0.5f, 0.5f, 0f));
				if (!ShotGeometry.Finite(((Ray)(ref val3)).origin) || !ShotGeometry.Finite(((Ray)(ref val3)).direction))
				{
					return false;
				}
				float distance = shotgunTemplate.gunRange + Vector3.Distance(((Ray)(ref val3)).origin, val2);
				Vector3 target = val2 + forward * shotgunTemplate.gunRange;
				if (RaycastWithoutShooter(((Ray)(ref val3)).origin, ((Ray)(ref val3)).direction, out var hit, distance, num | LayerMask.GetMask(new string[1] { "Enemy" }), (QueryTriggerInteraction)0))
				{
					target = ((RaycastHit)(ref hit)).point;
				}
				Quaternion val4 = Quaternion.LookRotation(ShotGeometry.FiringDirection(val2, forward, target), ((Component)aimCamera).transform.up);
				Quaternion val5 = Quaternion.Inverse(((Component)shotgunTemplate).transform.rotation) * shotgunTemplate.gunMuzzle.rotation;
				Quaternion val6 = val4 * Quaternion.Inverse(val5);
				Vector3 val7 = ((Component)shotgunTemplate).transform.InverseTransformPoint(shotgunTemplate.gunMuzzle.position);
				phys.Teleport(val2 - val6 * (val7 * 0.0001f), val6);
				return true;
			}
		}
		return PlacementBlocked();
	}

	private bool PlacementBlocked()
	{
		if (Time.unscaledTime >= nextPlacementWarning)
		{
			nextPlacementWarning = Time.unscaledTime + 2f;
			((BaseUnityPlugin)this).Logger.LogWarning((object)"Right-hand muzzle pose is invalid. Shot canceled; waiting for a valid arm pose.");
		}
		return false;
	}

	private bool IgnoreCollider(Collider collider)
	{
		if (!Object.op_Implicit((Object)(object)collider))
		{
			return true;
		}
		if (Object.op_Implicit((Object)(object)temporaryGun) && ((Component)collider).transform.IsChildOf(temporaryGun.transform))
		{
			return true;
		}
		PlayerAvatar componentInParent = ((Component)collider).GetComponentInParent<PlayerAvatar>();
		if (Object.op_Implicit((Object)(object)componentInParent))
		{
			return (Object)(object)componentInParent == (Object)(object)shotShooter;
		}
		PlayerController componentInParent2 = ((Component)collider).GetComponentInParent<PlayerController>();
		if (Object.op_Implicit((Object)(object)componentInParent2) && (Object)(object)componentInParent2.playerAvatarScript == (Object)(object)shotShooter)
		{
			return true;
		}
		PlayerAvatarVisuals componentInParent3 = ((Component)collider).GetComponentInParent<PlayerAvatarVisuals>();
		if (Object.op_Implicit((Object)(object)componentInParent3) && (Object)(object)componentInParent3.playerAvatar == (Object)(object)shotShooter)
		{
			return true;
		}
		PlayerTumble componentInParent4 = ((Component)collider).GetComponentInParent<PlayerTumble>();
		if (Object.op_Implicit((Object)(object)componentInParent4))
		{
			return (Object)(object)componentInParent4.playerAvatar == (Object)(object)shotShooter;
		}
		return false;
	}

	internal bool RaycastWithoutShooter(Vector3 origin, Vector3 direction, out RaycastHit hit, float distance, int mask, QueryTriggerInteraction triggers)
	{
		//IL_0001: Unknown result type (might be due to invalid IL or missing references)
		//IL_000c: Unknown result type (might be due to invalid IL or missing references)
		//IL_000d: Unknown result type (might be due to invalid IL or missing references)
		//IL_0012: Unknown result type (might be due to invalid IL or missing references)
		//IL_0020: 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_004b: 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)
		hit = default(RaycastHit);
		bool result = false;
		float num = distance;
		RaycastHit[] array = Physics.RaycastAll(origin, direction, distance, mask, triggers);
		for (int i = 0; i < array.Length; i++)
		{
			RaycastHit val = array[i];
			if (!IgnoreCollider(((RaycastHit)(ref val)).collider) && !(((RaycastHit)(ref val)).distance > num))
			{
				result = true;
				num = ((RaycastHit)(ref val)).distance;
				hit = val;
			}
		}
		return result;
	}

	internal bool OwnsEmitter(ItemGun gun)
	{
		if (((Behaviour)this).enabled && Object.op_Implicit((Object)(object)shotShooter) && Object.op_Implicit((Object)(object)temporaryGun) && Object.op_Implicit((Object)(object)gun))
		{
			return (Object)(object)((Component)gun).gameObject == (Object)(object)temporaryGun;
		}
		return false;
	}

	internal void ProtectShooter(ItemGun gun, HurtCollider hurt)
	{
		if (OwnsEmitter(gun) && Object.op_Implicit((Object)(object)hurt) && !hurt.ignorePlayers.Contains(shotShooter))
		{
			hurt.ignorePlayers.Add(shotShooter);
		}
	}

	internal bool OwnsProxy(GameObject target)
	{
		if (Object.op_Implicit((Object)(object)target))
		{
			if (!((Object)(object)target == (Object)(object)tumbleSmokeProxy) && !((Object)(object)target == (Object)(object)temporaryGun))
			{
				return fadingGuns.Any((FadingGun gun) => Object.op_Implicit((Object)(object)gun.Target) && (Object)(object)gun.Target == (Object)(object)target);
			}
			return true;
		}
		return false;
	}

	internal void CancelProxyGrab(GameObject target)
	{
		if (!OwnsProxy(target))
		{
			return;
		}
		if ((Object)(object)target == (Object)(object)tumbleSmokeProxy)
		{
			CleanupTumbleSmokeProxy();
			return;
		}
		if (DestroyProxy(target))
		{
			fadingGuns.RemoveAll((FadingGun gun) => (Object)(object)gun.Target == (Object)(object)target);
		}
		else
		{
			FadingGun fadingGun = fadingGuns.FirstOrDefault((FadingGun gun) => (Object)(object)gun.Target == (Object)(object)target);
			if (fadingGun != null)
			{
				fadingGun.DestroyAt = Time.time + 1f;
			}
			else
			{
				fadingGuns.Add(new FadingGun
				{
					Target = target,
					DestroyAt = Time.time + 1f
				});
			}
		}
		if ((Object)(object)temporaryGun == (Object)(object)target)
		{
			temporaryGun = null;
			temporaryGunDestroyAt = 0f;
		}
	}

	private void CleanupShot(bool keepMuzzleEffects = true)
	{
		//IL_013f: Unknown result type (might be due to invalid IL or missing references)
		//IL_014b: Unknown result type (might be due to invalid IL or missing references)
		GameObject val = temporaryGun;
		float num = temporaryGunDestroyAt;
		PhysGrabber val2 = posingGrabber;
		PlayerAvatarRightArm val3 = posingArm;
		bool flag = remotePoseSent;
		temporaryGun = null;
		temporaryGunDestroyAt = 0f;
		posingGrabber = null;
		posingArm = null;
		shotShooter = null;
		remotePoseSent = false;
		try
		{
			if (Object.op_Implicit((Object)(object)val3))
			{
				val3.GrabberPoseOverride(0f);
			}
			if (flag && Object.op_Implicit((Object)(object)val2) && !val2.grabbed && !Object.op_Implicit((Object)(object)val2.grabbedObjectTransform) && Object.op_Implicit((Object)(object)GameManager.instance) && SemiFunc.IsMultiplayer() && network.InRoom)
			{
				network.Rpc(((Component)val2).gameObject, "GrabClimbEndedRPC", true);
				network.Rpc(((Component)val2).gameObject, "PhysGrabBeamDeactivateRPC", true);
			}
		}
		catch (Exception ex)
		{
			((BaseUnityPlugin)this).Logger.LogWarning((object)("Temporary grab-pose cleanup failed: " + ex.Message));
		}
		finally
		{
			if (Object.op_Implicit((Object)(object)val))
			{
				if (keepMuzzleEffects && ((Behaviour)this).isActiveAndEnabled && RoleEnabled && num > Time.time)
				{
					Rigidbody component = val.GetComponent<Rigidbody>();
					if (Object.op_Implicit((Object)(object)component))
					{
						component.velocity = Vector3.zero;
						component.angularVelocity = Vector3.zero;
						component.isKinematic = true;
					}
					fadingGuns.Add(new FadingGun
					{
						Target = val,
						DestroyAt = num
					});
				}
				else if (!DestroyProxy(val))
				{
					fadingGuns.Add(new FadingGun
					{
						Target = val,
						DestroyAt = Time.time + 1f
					});
				}
			}
		}
	}

	private void CleanupFadingGuns(bool force)
	{
		for (int num = fadingGuns.Count - 1; num >= 0; num--)
		{
			FadingGun fadingGun = fadingGuns[num];
			if (!Object.op_Implicit((Object)(object)fadingGun.Target) || force || !(Time.time < fadingGun.DestroyAt))
			{
				if (!Object.op_Implicit((Object)(object)fadingGun.Target) || DestroyProxy(fadingGun.Target))
				{
					fadingGuns.RemoveAt(num);
				}
				else
				{
					fadingGun.DestroyAt = Time.time + 1f;
				}
			}
		}
	}

	private bool DestroyProxy(GameObject gun)
	{
		if (!Object.op_Implicit((Object)(object)gun))
		{
			return true;
		}
		try
		{
			network.Destroy(gun);
			return true;
		}
		catch (Exception ex)
		{
			((BaseUnityPlugin)this).Logger.LogError((object)("Temporary network gun cleanup failed: " + ex));
			if (network == null || !network.InRoom)
			{
				Object.Destroy((Object)(object)gun);
				return true;
			}
			return false;
		}
	}

	private void StopAndCleanup()
	{
		CleanupDeathExplosion();
		ResetSmokeTrail();
		CleanupTumbleSmokeProxy();
		ReleaseTumbleBonuses();
		ClearControlDodge();
		((MonoBehaviour)this).StopAllCoroutines();
		HideAmmoHud();
		iconGate.Reset();
		try
		{
			CleanupIconPrimer();
		}
		catch (Exception ex)
		{
			((BaseUnityPlugin)this).Logger.LogWarning((object)ex);
		}
		CleanupShot(keepMuzzleEffects: false);
		CleanupFadingGuns(force: true);
		busy = false;
	}

	private void OnDisable()
	{
		StopAndCleanup();
	}

	private void OnDestroy()
	{
		RoleMenu.Unregister("local.bei.hostveteransurvivor");
		CleanupDeathExplosion();
		ResetSmokeTrail();
		CleanupTumbleSmokeProxy();
		ReleaseTumbleBonuses();
		DestroyAmmoHud();
		iconGate.Reset();
		try
		{
			CleanupIconPrimer();
		}
		catch (Exception ex)
		{
			((BaseUnityPlugin)this).Logger.LogWarning((object)ex);
		}
		CleanupShot(keepMuzzleEffects: false);
		CleanupFadingGuns(force: true);
		if (Current == this)
		{
			Current = null;
		}
		Harmony obj = harmony;
		if (obj != null)
		{
			obj.UnpatchSelf();
		}
	}

	private void RegisterRole()
	{
		RoleMenu.Register("local.bei.hostveteransurvivor", "Veteran Survivor", "Shotgun, emergency dodge and extra jumps. Ammo and stage explosion use are kept when switching.", 0, (Func<bool>)(() => ((Behaviour)this).isActiveAndEnabled && modEnabled.Value), (Action<bool>)ApplyRole);
	}

	private void ApplyRole(bool active)
	{
		if (!active)
		{
			StopAndCleanup();
		}
	}

	internal bool TumbleBenefitsFor(PlayerAvatar player)
	{
		if (!bonusFailed && ((Behaviour)this).isActiveAndEnabled && RoleEnabled && Object.op_Implicit((Object)(object)GameManager.instance) && SemiFunc.IsMasterClientOrSingleplayer() && !SemiFunc.MenuLevel() && Object.op_Implicit((Object)(object)player) && (Object)(object)player == (Object)(object)PlayerAvatar.instance && (Object)(object)bonusPlayer == (Object)(object)player)
		{
			return Object.op_Implicit((Object)(object)bonusTumble);
		}
		return false;
	}

	private void UpdateTumbleBonuses()
	{
		if (bonusFailed)
		{
			return;
		}
		try
		{
			PlayerAvatar instance = PlayerAvatar.instance;
			PlayerController instance2 = PlayerController.instance;
			if (!((Behaviour)this).isActiveAndEnabled || !RoleEnabled || !Object.op_Implicit((Object)(object)GameManager.instance) || !SemiFunc.IsMasterClientOrSingleplayer() || SemiFunc.MenuLevel() || !Object.op_Implicit((Object)(object)StatsManager.instance) || !Object.op_Implicit((Object)(object)instance) || !Object.op_Implicit((Object)(object)instance2) || (Object)(object)instance2.playerAvatarScript != (Object)(object)instance)
			{
				ReleaseTumbleBonuses();
				return;
			}
			object? value = bonusAvatarTumble.GetValue(instance);
			PlayerTumble val = (PlayerTumble)((value is PlayerTumble) ? value : null);
			if (!Object.op_Implicit((Object)(object)val) || !(bool)bonusTumbleReady.GetValue(val) || !(bool)avatarSpawned.GetValue(instance))
			{
				return;
			}
			if ((Object)(object)bonusPlayer != (Object)(object)instance || (Object)(object)bonusController != (Object)(object)instance2 || (Object)(object)bonusTumble != (Object)(object)val)
			{
				ReleaseTumbleBonuses();
				bonusSteamId = SemiFunc.PlayerGetSteamID(instance);
				if (string.IsNullOrEmpty(bonusSteamId))
				{
					return;
				}
				bonusPlayer = instance;
				bonusController = instance2;
				bonusTumble = val;
			}
			bonusLaunch.SetValue(val, 1);
			bonusJump.SetValue(instance2, 1);
			bonusJumpRemaining.SetValue(instance2, Math.Min((int)bonusJumpRemaining.GetValue(instance2), 1));
		}
		catch (Exception ex)
		{
			bonusFailed = true;
			((BaseUnityPlugin)this).Logger.LogError((object)("Initial tumble/jump bonus unavailable: " + ex));
			ReleaseTumbleBonuses();
		}
	}

	private void ReleaseTumbleBonuses()
	{
		try
		{
			if (Object.op_Implicit((Object)(object)bonusPlayer) && (Object)(object)bonusPlayer == (Object)(object)PlayerAvatar.instance && Object.op_Implicit((Object)(object)StatsManager.instance) && Object.op_Implicit((Object)(object)GameManager.instance) && SemiFunc.IsMasterClientOrSingleplayer() && !string.IsNullOrEmpty(bonusSteamId))
			{
				StatsManager.instance.playerUpgradeLaunch.TryGetValue(bonusSteamId, out var value);
				StatsManager.instance.playerUpgradeExtraJump.TryGetValue(bonusSteamId, out var value2);
				if (Object.op_Implicit((Object)(object)bonusTumble))
				{
					bonusLaunch.SetValue(bonusTumble, Math.Max(0, value));
				}
				if (Object.op_Implicit((Object)(object)bonusController))
				{
					bonusJump.SetValue(bonusController, Math.Max(0, value2));
					bonusJumpRemaining.SetValue(bonusController, Math.Min((int)bonusJumpRemaining.GetValue(bonusController), Math.Max(0, value2)));
				}
			}
		}
		catch (Exception ex)
		{
			((BaseUnityPlugin)this).Logger.LogWarning((object)("Could not restore purchased tumble/jump levels: " + ex));
		}
		finally
		{
			bonusPlayer = null;
			bonusController = null;
			bonusTumble = null;
			bonusSteamId = null;
		}
	}

	internal void EnforceVeteranUpgradeCap(PlayerAvatar player)
	{
		if (Object.op_Implicit((Object)(object)player) && (Object)(object)player == (Object)(object)PlayerAvatar.instance)
		{
			UpdateTumbleBonuses();
		}
	}

	internal bool SuppressPowerup(PlayerAvatarVisuals visuals)
	{
		if (Object.op_Implicit((Object)(object)visuals))
		{
			return (Object)(object)visuals == (Object)(object)suppressedLaunchVisual;
		}
		return false;
	}

	internal PlayerAvatarVisuals BeginLaunchVisualScope(PlayerAvatar player)
	{
		PlayerAvatarVisuals result = suppressedLaunchVisual;
		suppressedLaunchVisual = player.playerAvatarVisuals;
		return result;
	}

	internal void EndLaunchVisualScope(PlayerAvatarVisuals old)
	{
		suppressedLaunchVisual = old;
	}

	private void ResetSmokeTrail()
	{
		smokeTrail.Reset();
		smokeTrailPlayer = null;
		smokeTrailStage = null;
	}

	private void UpdateSmokeTrail()
	{
		//IL_0085: Unknown result type (might be due to invalid IL or missing references)
		//IL_008a: Unknown result type (might be due to invalid IL or missing references)
		//IL_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_009e: Unknown result type (might be due to invalid IL or missing references)
		//IL_00aa: Unknown result type (might be due to invalid IL or missing references)
		//IL_00ac: Unknown result type (might be due to invalid IL or missing references)
		//IL_00b1: Unknown result type (might be due to invalid IL or missing references)
		//IL_00b6: Unknown result type (might be due to invalid IL or missing references)
		//IL_00ca: Unknown result type (might be due to invalid IL or missing references)
		//IL_00d2: 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)
		if (!smokeTrail.Active)
		{
			return;
		}
		if (!Object.op_Implicit((Object)(object)smokeTrailPlayer) || !TumbleBenefitsFor(smokeTrailPlayer) || smokeTrailStage != LevelGenerator.Instance || (bool)avatarDead.GetValue(smokeTrailPlayer) || (bool)avatarDisabled.GetValue(smokeTrailPlayer))
		{
			ResetSmokeTrail();
		}
		else if (!(Time.timeScale <= 0f))
		{
			Vector3 val = ((Component)smokeTrailPlayer).transform.position + Vector3.up * 0.3f;
			SmokeTrailRules smokeTrailRules = smokeTrail;
			double timeAsDouble = Time.timeAsDouble;
			Vector3 val2 = val - smokeTrailPosition;
			int num = smokeTrailRules.Tick(timeAsDouble, ((Vector3)(ref val2)).sqrMagnitude);
			if (num >= 0)
			{
				EmitSmokeCluster(val, num);
				smokeTrailPosition = val;
			}
		}
	}

	private void UpdateTumbleSmokeProxy()
	{
		//IL_00c6: Unknown result type (might be due to invalid IL or missing references)
		//IL_00cc: Expected O, but got Unknown
		//IL_019d: Unknown result type (might be due to invalid IL or missing references)
		//IL_01a2: Unknown result type (might be due to invalid IL or missing references)
		//IL_01a6: Unknown result type (might be due to invalid IL or missing references)
		//IL_01a8: Unknown result type (might be due to invalid IL or missing references)
		//IL_0208: Unknown result type (might be due to invalid IL or missing references)
		//IL_0212: Unknown result type (might be due to invalid IL or missing references)
		if (!TumbleBenefitsFor(PlayerAvatar.instance) || !Object.op_Implicit((Object)(object)LevelGenerator.Instance) || !LevelGenerator.Instance.Generated)
		{
			CleanupTumbleSmokeProxy();
			return;
		}
		try
		{
			object obj = (SemiFunc.IsMultiplayer() ? network.Room : RunManager.instance);
			if (tumbleSmokeStage != LevelGenerator.Instance || tumbleSmokeRoom != obj)
			{
				CleanupTumbleSmokeProxy();
				tumbleSmokeStage = LevelGenerator.Instance;
				tumbleSmokeRoom = obj;
			}
			int num;
			if (!Object.op_Implicit((Object)(object)tumbleSmokeProxy))
			{
				if (Time.unscaledTime < tumbleSmokeRetryAt)
				{
					return;
				}
				tumbleSmokeRetryAt = Time.unscaledTime + 3f;
				GameObject val = Resources.Load<GameObject>("Valuables/03 Medium/Valuable Manor Vase");
				if (!Object.op_Implicit((Object)(object)val))
				{
					throw new MissingMemberException("Smoke carrier resource missing: Valuables/03 Medium/Valuable Manor Vase");
				}
				PrefabRef val2 = new PrefabRef();
				((PrefabRef<GameObject>)(object)val2).SetPrefab(val, "Valuables/03 Medium/Valuable Manor Vase");
				PhysGrabObjectImpactDetector val3 = (Object.op_Implicit((Object)(object)val) ? val.GetComponent<PhysGrabObjectImpactDetector>() : null);
				if (!Object.op_Implicit((Object)(object)val3) || val3.particleDisable || val3.particleBreakSmokeDisable)
				{
					throw new InvalidOperationException("Smoke proxy prefab has no enabled break-smoke emitter.");
				}
				string[] array = (from c in val.GetComponentsInChildren<MonoBehaviour>(true)
					select (!Object.op_Implicit((Object)(object)c)) ? "<missing script>" : ((object)c).GetType().Name into name
					where !SmokeProxyRules.Allows(name)
					select name).Distinct().ToArray();
				if (array.Length != 0)
				{
					throw new InvalidOperationException("Unsupported smoke proxy scripts: " + string.Join(", ", array));
				}
				Vector3 val4 = (Vector3)disabledPosition.GetValue(AssetManager.instance);
				tumbleSmokeProxy = NetworkPrefabs.SpawnNetworkPrefab(val2, val4, Quaternion.identity, (byte)0, new object[3] { 0.0001f, 0.0001f, 0.0001f });
				if (!Object.op_Implicit((Object)(object)tumbleSmokeProxy))
				{
					throw new InvalidOperationException("Smoke proxy spawn failed.");
				}
				tumbleSmokeProxy.transform.localScale = Vector3.one * 0.0001f;
				((Behaviour)tumbleSmokeProxy.GetComponent<ValuableObject>()).enabled = false;
				tumbleSmokePhys = tumbleSmokeProxy.GetComponent<PhysGrabObject>();
				((Behaviour)tumbleSmokePhys).enabled = false;
				Rigidbody component = tumbleSmokeProxy.GetComponent<Rigidbody>();
				component.isKinematic = true;
				component.useGravity = false;
				component.detectCollisions = false;
				MeshRenderer[] componentsInChildren = tumbleSmokeProxy.GetComponentsInChildren<MeshRenderer>(true);
				for (num = 0; num < componentsInChildren.Length; num++)
				{
					((Renderer)componentsInChildren[num]).enabled = false;
				}
				Collider[] componentsInChildren2 = tumbleSmokeProxy.GetComponentsInChildren<Collider>(true);
				for (num = 0; num < componentsInChildren2.Length; num++)
				{
					componentsInChildren2[num].enabled = false;
				}
				tumbleSmokeDetector = tumbleSmokeProxy.GetComponent<PhysGrabObjectImpactDetector>();
				tumbleSmokeValueInitialized = false;
				tumbleSmokeReadyAt = Time.unscaledTime + 0.75f;
				ManualLogSource logger = ((BaseUnityPlugin)this).Logger;
				num = network.ViewId(tumbleSmokeProxy);
				logger.LogInfo((object)("[TumbleSmoke] Carrier spawned from Valuables/03 Medium/Valuable Manor Vase; view=" + num));
			}
			string text = (SemiFunc.IsMultiplayer() ? network.Roster(out num) : "solo");
			if (text != tumbleSmokeRoster)
			{
				tumbleSmokeRoster = text;
				tumbleSmokeReadyAt = Time.unscaledTime + 0.75f;
				tumbleSmokeValueInitialized = false;
			}
			if (Time.unscaledTime >= tumbleSmokeReadyAt && Object.op_Implicit((Object)(object)tumbleSmokeDetector) && Object.op_Implicit((Object)(object)tumbleSmokeDetector.particles) && !tumbleSmokeValueInitialized)
			{
				network.Rpc(tumbleSmokeProxy, "DollarValueSetRPC", false, 0f);
				tumbleSmokeValueInitialized = true;
				((BaseUnityPlugin)this).Logger.LogInfo((object)("[TumbleSmoke] Network smoke carrier ready; view=" + network.ViewId(tumbleSmokeProxy)));
			}
		}
		catch (Exception ex)
		{
			CleanupTumbleSmokeProxy();
			tumbleSmokeRetryAt = Time.unscaledTime + 10f;
			((BaseUnityPlugin)this).Logger.LogWarning((object)("Tumble smoke could not be prepared: " + ex));
		}
	}

	private void EmitLocalTumbleSmoke(Vector3 position)
	{
		//IL_003b: 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_0057: 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_00a2: Unknown result type (might be due to invalid IL or missing references)
		if (!Object.op_Implicit((Object)(object)localSmokePrefab))
		{
			localSmokePrefab = Resources.Load<GameObject>("Phys Object Particles");
		}
		if (!Object.op_Implicit((Object)(object)localSmokePrefab))
		{
			throw new MissingMemberException("Phys Object Particles resource missing.");
		}
		GameObject obj = Object.Instantiate<GameObject>(localSmokePrefab, position, Quaternion.identity);
		Object.Destroy((Object)(object)obj, 3f);
		obj.transform.localScale = Vector3.one;
		obj.SetActive(true);
		PhysObjectParticles component = obj.GetComponent<PhysObjectParticles>();
		if (!Object.op_Implicit((Object)(object)component))
		{
			throw new MissingComponentException("PhysObjectParticles component missing.");
		}
		Renderer[] componentsInChildren = obj.GetComponentsInChildren<Renderer>(true);
		for (int i = 0; i < componentsInChildren.Length; i++)
		{
			componentsInChildren[i].enabled = true;
		}
		component.ImpactSmoke(5, position, 0.7f);
	}

	private PhysGrabObjectImpactDetector GetReadySmokeCarrier()
	{
		if (Object.op_Implicit((Object)(object)tumbleSmokeProxy) && Object.o