Decompiled source of RepoRPG v1.0.38

RepoRPG.dll

Decompiled a day ago
using System;
using System.Collections;
using System.Collections.Generic;
using System.Diagnostics;
using System.Globalization;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Reflection.Emit;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
using System.Runtime.Versioning;
using System.Security;
using System.Security.Permissions;
using System.Text;
using System.Text.RegularExpressions;
using System.Threading;
using BepInEx;
using BepInEx.Bootstrap;
using BepInEx.Configuration;
using BepInEx.Logging;
using ExitGames.Client.Photon;
using HarmonyLib;
using MenuLib;
using MenuLib.MonoBehaviors;
using MenuLib.Structs;
using Microsoft.CodeAnalysis;
using Photon.Pun;
using Photon.Realtime;
using TMPro;
using UnityEngine;
using UnityEngine.AI;
using UnityEngine.Audio;
using UnityEngine.Rendering;
using UnityEngine.SceneManagement;
using UnityEngine.UI;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)]
[assembly: IgnoresAccessChecksTo("Assembly-CSharp")]
[assembly: TargetFramework(".NETStandard,Version=v2.1", FrameworkDisplayName = ".NET Standard 2.1")]
[assembly: AssemblyCompany("RepoRPG")]
[assembly: AssemblyConfiguration("Release")]
[assembly: AssemblyFileVersion("1.0.38.0")]
[assembly: AssemblyInformationalVersion("1.0.38")]
[assembly: AssemblyProduct("RepoRPG")]
[assembly: AssemblyTitle("RepoRPG")]
[assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)]
[assembly: AssemblyVersion("1.0.38.0")]
[module: UnverifiableCode]
[module: RefSafetyRules(11)]
namespace Microsoft.CodeAnalysis
{
	[CompilerGenerated]
	[Embedded]
	internal sealed class EmbeddedAttribute : Attribute
	{
	}
}
namespace System.Runtime.CompilerServices
{
	[CompilerGenerated]
	[Embedded]
	[AttributeUsage(AttributeTargets.Class | AttributeTargets.Property | AttributeTargets.Field | AttributeTargets.Event | AttributeTargets.Parameter | AttributeTargets.ReturnValue | AttributeTargets.GenericParameter, AllowMultiple = false, Inherited = false)]
	internal sealed class NullableAttribute : Attribute
	{
		public readonly byte[] NullableFlags;

		public NullableAttribute(byte P_0)
		{
			NullableFlags = new byte[1] { P_0 };
		}

		public NullableAttribute(byte[] P_0)
		{
			NullableFlags = P_0;
		}
	}
	[CompilerGenerated]
	[Embedded]
	[AttributeUsage(AttributeTargets.Class | AttributeTargets.Struct | AttributeTargets.Method | AttributeTargets.Interface | AttributeTargets.Delegate, AllowMultiple = false, Inherited = false)]
	internal sealed class NullableContextAttribute : Attribute
	{
		public readonly byte Flag;

		public NullableContextAttribute(byte P_0)
		{
			Flag = P_0;
		}
	}
	[CompilerGenerated]
	[Embedded]
	[AttributeUsage(AttributeTargets.Module, AllowMultiple = false, Inherited = false)]
	internal sealed class RefSafetyRulesAttribute : Attribute
	{
		public readonly int Version;

		public RefSafetyRulesAttribute(int P_0)
		{
			Version = P_0;
		}
	}
}
namespace RepoRPG
{
	internal sealed class RpgRuntime : MonoBehaviour
	{
		private sealed class BetMark
		{
			public int Actor;

			public float Mult;

			public float Remaining;

			public float Armed;

			public float At;

			public string Text = "";

			public Transform? Target;

			public float LookedUp;
		}

		private struct TimedBuff
		{
			public float Speed;

			public float Grip;

			public float Guard;

			public float Until;

			public string Source;
		}

		private enum PullPhase
		{
			Travel,
			Cling,
			Kick
		}

		private sealed class Pull
		{
			public readonly List<Vector3> Points = new List<Vector3>();

			public int Index;

			public float Start;

			public float LastProgressAt;

			public float Speed;

			public float FeetOffset;

			public float Timeout;

			public Vector3 Anchor;

			public float BestDist = float.MaxValue;

			public int HealthAtStart;

			public HookAim Kind;

			public PullPhase Phase;

			public Vector3 Face;

			public Vector3 Hand;

			public float ClingSeconds;

			public float ClingUntil;

			public float ClingStart;

			public float Drain;

			public float KickUntil;

			public Vector3 KickDir;

			public bool CanMantle;

			public Vector3 MantleTop;

			public Vector3 MantleLip;

			public void Reset()
			{
				//IL_0047: Unknown result type (might be due to invalid IL or missing references)
				//IL_004c: Unknown result type (might be due to invalid IL or missing references)
				//IL_004d: Unknown result type (might be due to invalid IL or missing references)
				//IL_004e: Unknown result type (might be due to invalid IL or missing references)
				//IL_0053: Unknown result type (might be due to invalid IL or missing references)
				//IL_0054: Unknown result type (might be due to invalid IL or missing references)
				//IL_0055: Unknown result type (might be due to invalid IL or missing references)
				//IL_0056: Unknown result type (might be due to invalid IL or missing references)
				//IL_005b: Unknown result type (might be due to invalid IL or missing references)
				//IL_005c: Unknown result type (might be due to invalid IL or missing references)
				//IL_005d: Unknown result type (might be due to invalid IL or missing references)
				//IL_005e: Unknown result type (might be due to invalid IL or missing references)
				//IL_0063: Unknown result type (might be due to invalid IL or missing references)
				//IL_0064: Unknown result type (might be due to invalid IL or missing references)
				//IL_0065: Unknown result type (might be due to invalid IL or missing references)
				//IL_0066: Unknown result type (might be due to invalid IL or missing references)
				//IL_006b: Unknown result type (might be due to invalid IL or missing references)
				//IL_006c: Unknown result type (might be due to invalid IL or missing references)
				//IL_006d: Unknown result type (might be due to invalid IL or missing references)
				//IL_006e: Unknown result type (might be due to invalid IL or missing references)
				//IL_0073: Unknown result type (might be due to invalid IL or missing references)
				//IL_0074: Unknown result type (might be due to invalid IL or missing references)
				Points.Clear();
				Index = 0;
				Start = (LastProgressAt = (Speed = (FeetOffset = (Timeout = 0f))));
				Anchor = (Face = (Hand = (KickDir = (MantleTop = (MantleLip = Vector3.zero)))));
				BestDist = float.MaxValue;
				HealthAtStart = 0;
				Kind = HookAim.None;
				Phase = PullPhase.Travel;
				ClingSeconds = (ClingUntil = (ClingStart = (Drain = (KickUntil = 0f))));
				CanMantle = false;
			}
		}

		private enum HookAim
		{
			None,
			Item,
			Ledge,
			Floor,
			Wall,
			Ceiling,
			Invalid
		}

		private struct RoomMark
		{
			public Vector3 Pos;

			public int Monsters;

			public int Loot;

			public float Until;
		}

		private struct Ping
		{
			public Vector3 Pos;

			public string Name;

			public float Until;
		}

		private struct Glint
		{
			public Transform T;

			public Vector3 Center;

			public float Radius;

			public float Until;

			public float Phase;
		}

		private struct Threat
		{
			public EnemyHealth Eh;

			public string Text;

			public Color Col;
		}

		private sealed class CtRequest
		{
			public byte What;

			public string Uid = "";

			public float SentAt;

			public int Tries;

			public Action Resend;
		}

		private sealed class PendingBuy
		{
			public string Label = "";

			public string Item = "";

			public Action OnPaid;

			public float SentAt;

			public int Cost;

			public bool Retried;
		}

		public struct Aura
		{
			public float Guard;

			public float GuardRadius;

			public float Stabilize;

			public float StabilizeRadius;

			public float Link;

			public float LinkRadius;

			public float Inspire;

			public float InspireRadius;

			public float InspireSpeed;

			public float InspireGrip;

			public float At;

			public int Actor;
		}

		private sealed class WorldMark
		{
			public string Id = "";

			public Vector3 Pos;

			public string Text = "";

			public Color Color;

			public float Until;
		}

		private sealed class PartDrop
		{
			public Vector3 Pos;

			public int[] Counts = new int[4];

			public float Until;

			public float AskedAt = -99f;

			public bool Taken;
		}

		internal enum Recipe
		{
			Reroll,
			Raise,
			Upgrade,
			Legendary
		}

		private sealed class PendingSalvage
		{
			public string Uid = "";

			public string Name = "";

			public int Rarity;

			public float SentAt;

			public bool Retried;

			public bool Bulk;
		}

		private sealed class CallOut
		{
			public int Actor;

			public string Name = "";

			public Vector3 Pos;

			public float Until;
		}

		private enum DialogChoice
		{
			Confirm,
			Discard,
			Cancel
		}

		private sealed class HudBlock
		{
			public readonly List<(string text, Color color)> Lines = new List<(string, Color)>();

			public GUIStyle? Style;

			public string Shape = "";

			public float StyleFor = -1f;

			public GUIStyle? Base;
		}

		private enum Rebind
		{
			None,
			KeyMenu,
			KeyAbility,
			KeyConfirm,
			KeyBack,
			KeyTabL,
			KeyTabR,
			KeySecondary,
			KeyAttrConfirm,
			KeyAttrReset,
			KeyHum,
			KeyHandOff,
			KeyMimicSwap,
			KeyCartFollow,
			KeySalvage,
			KeyCallOut,
			KeyHighlights,
			PadMenu,
			PadAbility,
			PadConfirm,
			PadBack,
			PadTabL,
			PadTabR,
			PadSecondary,
			PadAttrConfirm,
			PadAttrReset,
			PadHum,
			PadHandOff,
			PadMimicSwap,
			PadCartFollow,
			PadSalvage,
			PadCallOut,
			PadHighlights
		}

		private enum GKind
		{
			Head,
			Text,
			Bullet,
			Tip,
			Note,
			Term,
			Goto,
			Walk,
			Filter,
			ClassRow,
			Row,
			Space
		}

		private sealed class GItem
		{
			public GKind Kind;

			public string Text = "";

			public string Text2 = "";

			public string Arg = "";

			public Color Color = Color.white;

			public float H;
		}

		public enum HealKind : byte
		{
			OverTime,
			Instant,
			Revive
		}

		private struct FocusItem
		{
			public int Key;

			public Rect Screen;

			public int ScrollId;

			public Rect Local;
		}

		private enum NavDevice
		{
			Mouse,
			Keyboard,
			Pad
		}

		private sealed class InFlight
		{
			public int Id;

			public float SentAt;

			public string Payload = "";

			public string ClassId = "";

			public bool Retried;
		}

		private enum HostChecks
		{
			Unknown,
			Yes,
			No
		}

		private enum DialogKind
		{
			Leave,
			PlayAs,
			Salvage,
			Compare,
			Craft,
			HostApply,
			Purchase
		}

		public enum PopupKind
		{
			Xp,
			Level,
			Loot,
			Contract,
			Perk,
			Other,
			Currency
		}

		private sealed class Popup
		{
			public bool Active;

			public PopupKind Kind;

			public string Key = "";

			public string Label = "";

			public string Text = "";

			public Color Color;

			public int Amount;

			public int Count;

			public double Total;

			public float Start;

			public float End;

			public float Y = -1f;

			public long Seq;

			public bool Fading;
		}

		private enum UndoKind : byte
		{
			Talent,
			Attribute
		}

		private sealed class Tracked
		{
			public ValuableObject Obj;

			public Renderer[] Rends = Array.Empty<Renderer>();

			public MeshFilter?[] Filters = Array.Empty<MeshFilter>();

			public Color Col;

			public float Value;

			public float Until;

			public string Tag = "";

			public Bounds B;

			public bool HasB;

			public bool Own;

			public PhysGrabObject? Pgo;

			public Component? Det;
		}

		private sealed class PoolItem
		{
			public ValuableObject Obj;

			public PhysGrabObject? Pgo;

			public Component? Det;

			public float Value;
		}

		private sealed class AbilityNums
		{
			public float Cd;

			public float Cdr;

			public float Power;

			public float HealPower;

			public float Dur;

			public float Radius;

			public float Scale = 1f;

			public int Charges;

			public bool CdrCapped;

			public readonly List<(string label, float value)> Acts = new List<(string, float)>();

			public readonly List<string> Riders = new List<string>();
		}

		private sealed class Mate
		{
			public int Actor;

			public int Hp;

			public int Max = 100;

			public bool Down;

			public string Name = "";

			public string BarText = "";

			public string ListText = "";

			public float CriticalSince = -1f;

			public float LastCriticalPop = -99f;

			public PlayerAvatar? Avatar;
		}

		internal enum UiSound
		{
			Hover,
			Click,
			Confirm,
			Back,
			Error,
			Tick
		}

		private int _supplyLeft = -1;

		private int _supplyCharges;

		private int _supplyPrice = -1;

		private int _betLeft = -1;

		private int _betUses;

		private int _limitsLevel = -1;

		private readonly Dictionary<int, BetMark> _betMarks = new Dictionary<int, BetMark>();

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

		private float _classStatsSendAt;

		private readonly Dictionary<string, float> _classStatsBuf = new Dictionary<string, float>();

		private readonly Dictionary<string, float> _setStatsBuf = new Dictionary<string, float>();

		private float _sentGrab = -9f;

		private float _sentThrow = -9f;

		private float _nextGripCheck;

		private readonly List<TimedBuff> _buffs = new List<TimedBuff>();

		private readonly List<(Stat stat, float value, float until)> _selfDyn = new List<(Stat, float, float)>();

		private float _pendingHealthPct;

		private float _pendingHealthAt;

		private float _inspire;

		private float _lastInspireSent = -99f;

		private float _nextInspireSend;

		private float _nextNearCheck;

		private bool _talking;

		private bool _monsterNear;

		private static readonly Lazy<Func<object?>> VoiceInstance = new Lazy<Func<object>>(delegate
		{
			Type type = AccessTools.TypeByName("PlayerVoiceChat");
			FieldInfo f = ((type == null) ? null : AccessTools.Field(type, "instance"));
			return delegate
			{
				try
				{
					return f?.GetValue(null);
				}
				catch
				{
					return (object?)null;
				}
			};
		});

		private float _pactEnd;

		private float _pactDrain;

		private float _drainAcc;

		private float _lastBloodWeapon;

		private float _nextCartLook;

		private PhysGrabCart[] _cartsNear = Array.Empty<PhysGrabCart>();

		private (float speed, float grip) _inspireFromAllies;

		private float _nextAudienceCheck;

		private bool _audience;

		private bool _whisperTalk;

		private float _nextVoiceDraw;

		private bool _inspireWasFull;

		private float _rallyRefund;

		private readonly string[] _copies = new string[2] { "", "" };

		private readonly string[] _copyFrom = new string[2] { "", "" };

		private int _copySlot;

		private int _copyCandidate = -1;

		private float _copyTimer;

		private float _nextCopyLook;

		private readonly (int charges, float cdEnd)[] _slotState = new(int, float)[2]
		{
			(1, 0f),
			(1, 0f)
		};

		private float _lastCopyLook = -1f;

		private bool _freshUsed;

		private float _gambleCheckAt;

		private float _bloodAcc;

		private bool _inActive;

		private bool _refundAfterUse;

		private string _cartState = "";

		private float _windReadyAt;

		private KeyCode _queuedClassKey;

		private bool _cartFollowOn = true;

		private readonly List<(string, Color)> _headLines = new List<(string, Color)>();

		private float _headLinesAt = -9f;

		private int _headLinesSig;

		private Pull? _pull;

		private int _hookChain;

		private readonly Pull _aimPlan = new Pull();

		private static readonly Collider[] HookOverlap = (Collider[])(object)new Collider[16];

		private static readonly RaycastHit[] HookHits = (RaycastHit[])(object)new RaycastHit[16];

		private static readonly Vector3[] FloorProbes = (Vector3[])(object)new Vector3[5]
		{
			Vector3.zero,
			Vector3.forward * 0.25f,
			Vector3.back * 0.25f,
			Vector3.left * 0.25f,
			Vector3.right * 0.25f
		};

		private const float WallStandoff = 0.45f;

		private const float CeilingDrop = 2.05f;

		private const float MantleReach = 1.5f;

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

		private static readonly HashSet<string> ThirdWaveActions = new HashSet<string> { "Bypass", "Echo", "Mend", "Rummage", "Policy", "Watchpost", "Overclock", "Pacify", "Hook", "Flare" };

		private HookAim _hookTextAim = (HookAim)(-1);

		private int _hookTextDist = -1;

		private string _hookTextWhy = "";

		private string _hookTextCling = "";

		private string _hookText = "";

		private HookAim _hookAim;

		private string _hookAimWhy = "";

		private float _hookAimDist;

		private float _nextHookAim;

		private bool _reachTarget;

		private float _rummageStart;

		private float _rummageEnd;

		private float _rummageCount;

		private Vector3 _rummagePos;

		private float _nextThrow;

		private bool _voiceThrown;

		private float _bypassSeconds = 8f;

		private readonly List<RoomMark> _roomMarks = new List<RoomMark>();

		private readonly List<Ping> _pings = new List<Ping>();

		private readonly List<Glint> _glints = new List<Glint>();

		private readonly List<Threat> _threats = new List<Threat>();

		private float _nextThreat;

		private float _thickSkinUntil;

		private float _patchUpUntil;

		private float _patchUpPct;

		private float _secondBreathUntil;

		private float _firmUntil;

		private float _rhythmAt;

		private float _nextAttrTick;

		private float _airVy;

		private int _clearHeadLevel = -1;

		private int _secondBreathLevel = -1;

		private int _featherLevel = -1;

		private HashSet<string>? _attrKnownActive;

		private string _attrKnownFor = "~";

		private readonly Dictionary<string, float> _attrFlash = new Dictionary<string, float>();

		private bool _classWindowOpen;

		private bool _classPickDropped;

		private bool _classlessToldThisLevel;

		private float _nextClassWindowCheck;

		private readonly Dictionary<int, CtRequest> _ctRequests = new Dictionary<int, CtRequest>();

		private int _ctNextReq = new Random().Next(1, 1073741824);

		private float _ctNextTick;

		private readonly List<float> _ctKillTimes = new List<float>();

		private readonly HashSet<string> _ctCopied = new HashSet<string>();

		private Vector3 _ctLastPos;

		private bool _ctHavePos;

		private readonly Dictionary<string, float> _ctFlash = new Dictionary<string, float>();

		private readonly Dictionary<string, float> _ctClaimRetry = new Dictionary<string, float>();

		private readonly HashSet<string> _ctRefused = new HashSet<string>();

		private readonly HashSet<int> _ctScanned = new HashSet<int>();

		private float _ctJugAcc;

		private string _ctModulePick = "";

		private static readonly Color CtGood = new Color(0.55f, 1f, 0.55f);

		private static readonly Color CtBad = new Color(1f, 0.45f, 0.4f);

		private static readonly Color CtGold = new Color(1f, 0.8f, 0.35f);

		private readonly Queue<(string key, float amount, int a, int b)> _ctEvQueue = new Queue<(string, float, int, int)>();

		private bool _ctInEv;

		private const int CtEvBurstLimit = 64;

		private readonly HashSet<string> _ctPaid = new HashSet<string>();

		private bool _selfHurt;

		private bool _fallHandled;

		private int _neverDieLevel = -1;

		private RunSave? _deathSavesTagged;

		private float _sprintStart = -1f;

		private float _nextHoldCheck;

		private float _nextVigil;

		private float _airImpulseVy;

		private float _prevVy;

		private bool _holdingValuable;

		private bool _gearWasSprinting;

		private bool _featherFree;

		private int _vigilLevel = -1;

		private int _freeFirstLevel = -1;

		private int _bellLevel = -1;

		private readonly Dictionary<string, float> _gearFlash = new Dictionary<string, float>();

		private int _chargedLevel = -1;

		private static readonly int[] ModuleRandomCost = new int[4] { 2, 1, 0, 0 };

		private static readonly int[] ModuleChosenCost = new int[4] { 0, 0, 1, 0 };

		public const int LoadoutCount = 3;

		private float _ljShieldUntil;

		private bool _ljJoining;

		private float _ljSince;

		private float _ljNextAsk;

		private int _ljAsks;

		private bool _ljToldSlow;

		private readonly Dictionary<string, float> _perkFlash = new Dictionary<string, float>();

		private readonly Dictionary<string, float> _tagFlash = new Dictionary<string, float>();

		private float _perkRevealAt = -99f;

		private int _perkRevealKey;

		private int _encoreCount;

		private int _ghostLevel = -1;

		private float _nextPerkTick;

		private float _sprintSampled;

		private bool _teamNear;

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

		private readonly RunStore _store = new RunStore();

		private float _waitForHostSince = -1f;

		private float _levelStartTime;

		private float _nextCombatSend;

		private float _settingsDirtyAt;

		private int _extractionsThisLevel;

		private readonly StatSheet _stats = new StatSheet();

		private bool _statsDirty = true;

		private PlayerHealth? _hpFilledFor;

		internal static bool KillHit;

		private readonly TrackedField _maxHealth = new TrackedField(typeof(PlayerHealth), "maxHealth", TrackedField.Mode.Rebase, HealthReady);

		private readonly TrackedField _move = new TrackedField(typeof(PlayerController), "MoveSpeed", TrackedField.Mode.Additive, PcReady, PcOverridden, (object pc) => Game.Get(pc, "playerOriginalMoveSpeed", 0f));

		private readonly TrackedField _sprint = new TrackedField(typeof(PlayerController), "SprintSpeed", TrackedField.Mode.Additive, PcReady, PcOverridden, (object pc) => Game.Get(pc, "playerOriginalSprintSpeed", 0f));

		private readonly TrackedField _crouch = new TrackedField(typeof(PlayerController), "CrouchSpeed", TrackedField.Mode.Additive, PcReady, PcOverridden, (object pc) => Game.Get(pc, "playerOriginalCrouchSpeed", 0f));

		private readonly TrackedField _jumpForce = new TrackedField(typeof(PlayerController), "JumpForce", TrackedField.Mode.Additive, PcReady);

		private readonly TrackedField _jumpExtra = new TrackedField(typeof(PlayerController), "JumpExtra", TrackedField.Mode.Rebase, PcReady);

		private readonly TrackedField _energyMax = new TrackedField(typeof(PlayerController), "EnergyStart", TrackedField.Mode.Additive, PcReady);

		private readonly TrackedField _grabStrength = new TrackedField(typeof(PhysGrabber), "grabStrength");

		private readonly TrackedField _grabRange = new TrackedField(typeof(PhysGrabber), "grabRange");

		private readonly TrackedField _throw = new TrackedField(typeof(PhysGrabber), "throwStrength");

		private float _cooldownEnd;

		private int _charges = 1;

		private float _buffEnd;

		private float _hotEnd;

		private float _hotPerSecond;

		private float _hotAcc;

		private float _scanEnd;

		private float _scanRadius;

		private int _scanCount;

		private float _invulnUntil;

		private float _lastDamageTime = -999f;

		private float _regenAcc;

		private int _lastSeenHp = -1;

		private float _nextAuraPulse;

		private readonly Dictionary<int, float> _allyHealAcc = new Dictionary<int, float>();

		private float _teamXpDedupeUntil;

		private Net.TeamXp _lastTeamXp;

		private float _nextSense;

		private int _senseCount;

		private float _senseNearest;

		private float _nextScan;

		private readonly List<(Vector3 pos, float value, float dist)> _scanHits = new List<(Vector3, float, float)>();

		private string _askKey = "";

		private float _askSince;

		private float _askNext;

		private string _gotKey = "";

		private RunSave? _gotData;

		private string _fellBackKey = "";

		private bool _reloadFromHost;

		private float _bulwarkReadyAt;

		private bool _specialistPending;

		private int _mirrorLevel = -1;

		private int _crescendoLevel = -1;

		private static readonly HashSet<string> HostActions = new HashSet<string>
		{
			"RallyCry", "Reboot", "CartOverdrive", "ZeroGField", "DecoyBeacon", "BreachCharge", "Resupply", "DoubleOrNothing", "Bypass", "Echo",
			"Mend", "Policy", "Watchpost", "Pacify", "Flare"
		};

		private int _lastCharged;

		private readonly Dictionary<int, PendingBuy> _pendingBuys = new Dictionary<int, PendingBuy>();

		private readonly Dictionary<int, PendingBuy> _lateBuys = new Dictionary<int, PendingBuy>();

		private int _nextBuyId = new Random().Next(1, 1073741824);

		private float _nextPerkReport;

		private bool _shopRotatedScene;

		private float _nextShopTick;

		private float _nextCartBuy;

		private float _medPatchLevel = -1f;

		private string _vendorLine = ShopX.VendorBrowse[0];

		private float _vendorLineAt;

		private readonly List<(string label, string key, int price, Action buy)> _cart = new List<(string, string, int, Action)>();

		private readonly Queue<Action> _cartQueue = new Queue<Action>();

		private readonly Dictionary<string, float> _shopFlash = new Dictionary<string, float>();

		private string _purchaseTitle = "";

		private string _purchaseBody = "";

		private Action? _purchaseAction;

		private static readonly int[] PartsUpCost = new int[4] { 0, 2, 0, 0 };

		private int _momentum;

		private int _frenzy;

		private float _momentumNext;

		private float _lastSprint;

		private float _frenzyEnd;

		private float _shadowstepEnd;

		private float _scar;

		private bool _wasSprinting;

		private float _lastDynWeapon;

		private readonly Dictionary<int, Aura> _auras = new Dictionary<int, Aura>();

		private bool _auraSentNonZero;

		private float _nextAuraLook;

		private float _guardedBy;

		private float _linkRegen;

		private int _guardActor = -1;

		private float _guardPct;

		private const float FrenzySeconds = 15f;

		private const float ShadowstepSeconds = 3f;

		private float _lastDodgeRefund = -9f;

		private float _rallyEnd;

		private float _saveHealAt;

		private int _saveHeal;

		private float _stDiagAt;

		private float _stDiagStartE = -1f;

		private float _stDiagStartT;

		private float _stDiagFrames;

		private string _banner = "";

		private Color _bannerColor = Color.white;

		private float _bannerUntil;

		private string _bossShown = "";

		private readonly List<WorldMark> _worldMarks = new List<WorldMark>();

		private readonly Dictionary<int, PartDrop> _partDrops = new Dictionary<int, PartDrop>();

		private float _nextPartCheck;

		private string _craftUid = "";

		private string _craftTarget = "";

		private int _craftLine;

		private Recipe? _craftPick;

		private readonly Dictionary<ConfigEntryBase, object> _hostPending = new Dictionary<ConfigEntryBase, object>();

		private Vector2 _hostScroll;

		private readonly HashSet<string> _hostOpen = new HashSet<string>();

		private string _presetName = "";

		private bool _namingPreset;

		private string _hostToast = "";

		private float _settingsWaitSince = -1f;

		private float _nextSettingsAsk;

		private bool _settingsTimeoutSaid;

		private string _hostHead = "";

		private float _hostHeadAt = -10f;

		private float _hostHeadW = -1f;

		private float _hostHeadH;

		private const int ScrollHost = 10;

		private readonly Dictionary<int, PendingSalvage> _pendingSalvage = new Dictionary<int, PendingSalvage>();

		private int _salvageSeq = new Random().Next(1, 1073741824);

		private GearItem? _salvageAsk;

		private List<GearItem>? _salvageAskBulk;

		private TeamContractDef? _tcDef;

		private int _tcState = -1;

		private int _tcTarget;

		private int _tcYes;

		private int _tcVotes;

		private int _tcLevel = -1;

		private float _tcScale = 1f;

		private float _tcVoteEnd;

		private int[] _tcParticipants = Array.Empty<int>();

		private int[] _tcYesBy = Array.Empty<int>();

		private int[] _tcNoBy = Array.Empty<int>();

		private bool _tcBoardVote;

		private bool _tcVoted;

		private bool _tcRewarded;

		private float _tcHoldStart = -1f;

		private int _notTodaySaves;

		private bool _notTodayUsed;

		private readonly List<CallOut> _callOuts = new List<CallOut>();

		private readonly HashSet<int> _callOutSeen = new HashSet<int>();

		private readonly Dictionary<int, float> _callOutLast = new Dictionary<int, float>();

		private int _callOutsThisDeath;

		private float _nextCallOut;

		private readonly List<SynergyDef> _synActive = new List<SynergyDef>();

		private readonly List<(string text, Color a, Color b)> _synLines = new List<(string, Color, Color)>();

		private string _synSig = "";

		private float _synNext;

		private List<TeamPlay.Entry>? _card;

		private List<TeamPlay.Entry>? _cardWaiting;

		private float _cardWaitingSecs;

		private int _cardCountedLevel = -1;

		private float _cardUntil;

		private float _cardShownAt;

		private float _cardSecs;

		private float _cardKeyDownAt = -1f;

		private bool _cardPaused;

		private string _cardPrompt = "";

		private string _cardPromptKey = "";

		private int _accountPage;

		private int _unlockFilter;

		private Vector2 _accountScroll;

		private const int ScrollAccount = 11;

		private float _summaryAt = 0.5f;

		private string _summarySent = "";

		private int _summaryPlayers;

		private Dictionary<string, int>? _attrInFlight;

		private int _attrRequestId = new Random().Next(1, 1073741824);

		private float _attrSentAt;

		private string _attrRunKey = "";

		private bool _attrLateOk;

		private bool _attrRetried;

		private bool _dialogOpen;

		private bool _inDialog;

		private bool _dialogFocusSet;

		private Action? _dialogAfter;

		private int _dialogReturnFocus;

		private Vector2 _attrSideScroll;

		private const int ScrollAttrSide = 13;

		private int _attrCacheKey = int.MinValue;

		private readonly HashSet<string> _attrActiveNow = new HashSet<string>();

		private readonly HashSet<string> _attrActiveAfter = new HashSet<string>();

		private readonly List<string> _attrTotalLines = new List<string>();

		private string _attrTitleNow = "";

		private string _attrTitleAfter = "";

		private int _attrSideKey = int.MinValue;

		private int _attrSideLayoutKey = int.MinValue;

		private string _sHead = "";

		private string _sNow = "";

		private string _sAfter = "";

		private string _sNext = "";

		private readonly List<(string full, string brief)> _sMiles = new List<(string, string)>();

		private readonly List<(string full, string brief)> _sPairs = new List<(string, string)>();

		private readonly List<(string full, string brief)> _sTotals = new List<(string, string)>();

		private int _sFont;

		private int _sHeadFont;

		private bool _sTwoCol;

		private bool _sBrief;

		private float _sChartH;

		private int _attrDetailCache = int.MinValue;

		private Texture2D? _radarTex;

		private int _radarKey = int.MinValue;

		private Rect _radarRect;

		private bool _hudForce;

		private string _hudTraceClass = "-";

		private bool _menuOpen;

		private int _menuClosedFrame = -10;

		private Texture2D? _cursorTex;

		private CursorLockMode _cursorLockBefore;

		private bool _cursorVisibleBefore = true;

		private ClassDef? _viewClass;

		private Vector2 _classScroll;

		private Vector2 _treeScroll;

		private readonly List<(string text, Color color, float until)> _toasts = new List<(string, Color, float)>();

		private bool _abilityKeyQueued;

		private readonly HashSet<KeyCode> _held = new HashSet<KeyCode>();

		private bool _stylesReady;

		private GUIStyle _title;

		private GUIStyle _h2;

		private GUIStyle _body;

		private GUIStyle _small;

		private GUIStyle _btn;

		private GUIStyle _tabStyle;

		private GUIStyle _smallRight;

		private GUIStyle _hud;

		private GUIStyle _toast;

		private GUIStyle _promptStyle;

		private GUIStyle _smallLine;

		private GUIStyle _smallCenter;

		private GUIStyle _bodyB;

		private GUIStyle _bodyCenterB;

		private GUIStyle _h2Center;

		private Texture2D _texPanel;

		private Texture2D _texDim;

		private Texture2D _texNode;

		private Texture2D _texNodeOn;

		private Texture2D _texNodeLocked;

		private Texture2D _texBar;

		private Texture2D _texBarBg;

		private const float VW = 1600f;

		private const float VH = 900f;

		private readonly Dictionary<KeyCode, float> _keyDownAt = new Dictionary<KeyCode, float>();

		private static readonly Lazy<Func<bool>> ChatOpen = new Lazy<Func<bool>>(delegate
		{
			Type type = AccessTools.TypeByName("ChatManager");
			FieldInfo inst = ((type == null) ? null : AccessTools.Field(type, "instance"));
			FieldInfo active = ((type == null) ? null : AccessTools.Field(type, "chatActive"));
			return (inst == null || active == null) ? ((Func<bool>)(() => false)) : ((Func<bool>)delegate
			{
				try
				{
					object value = inst.GetValue(null);
					bool flag = default(bool);
					int num;
					if (value != null)
					{
						object value2 = active.GetValue(value);
						if (value2 is bool)
						{
							flag = (bool)value2;
							num = 1;
						}
						else
						{
							num = 0;
						}
					}
					else
					{
						num = 0;
					}
					return (byte)((uint)num & (flag ? 1u : 0u)) != 0;
				}
				catch
				{
					return false;
				}
			});
		});

		private static Type? _esType;

		private static bool _esLooked;

		private readonly List<Behaviour> _esDisabled = new List<Behaviour>();

		private float _esNextScan;

		private static FieldInfo? _mbHovering;

		private static MethodInfo? _mbHoverEnd;

		private static PropertyInfo? _mehHovering;

		private float _hudTopY = -1f;

		private float _menuOpenedAt;

		private Rect _menuWin;

		private float _lastUiScale = -1f;

		private float _lastGrow = -1f;

		private float _builtFontMul = -1f;

		private int _builtStyle = -1;

		private bool _lastFit;

		public const float MinTextPx = 14f;

		private const float SmallestFont = 15f;

		private float _fontMul = 1f;

		private float _lastFontMul = -1f;

		private readonly List<(string, Color)> _hudLeft = new List<(string, Color)>();

		private float _nextHudBuild;

		private bool _hudRebuild;

		private readonly List<(string, Color)> _hudLeftNext = new List<(string, Color)>();

		private string _classBlockDiag = "";

		private int _classBlockRebuilds;

		private readonly Dictionary<PassiveDef, string> _passiveHead = new Dictionary<PassiveDef, string>();

		private static readonly string[] GroupOrder = new string[6] { "Combat", "Support", "Control", "Utility", "Mobility", "Economy" };

		private List<(string name, List<ClassDef> list)>? _classGroups;

		private int _classGroupsCount = -1;

		private readonly Dictionary<NodeDef, string> _nodeText = new Dictionary<NodeDef, string>();

		private int _paletteApplied = -1;

		private bool _contrastChecked;

		private float _contentBottom;

		private static int _instances;

		private readonly HudBlock _contractsBlock = new HudBlock();

		private readonly HudBlock _rightBlock = new HudBlock();

		private string _contractSig = "";

		private string _contractLevelKey = "";

		private float _contractNextCheck;

		private float _contractLastHave = -99f;

		private float _contractsAlpha;

		private readonly StringBuilder _sigSb = new StringBuilder(256);

		private readonly List<(string, Color)> _teamLines = new List<(string, Color)>();

		private float _teamLinesNext;

		private string _cDiagLast = "";

		private int _cDiagFrame = -1;

		private int _cDiagDraws;

		private int _cDiagFontAt;

		private float _cDiagNextScan;

		private float _cDiagNextInstances;

		private string _overlapLast = "";

		private Rect _cDiagPanelScreen;

		private readonly List<string> _overlapParts = new List<string>();

		private readonly Vector3[] _hudCorners = (Vector3[])(object)new Vector3[4];

		private int _ctSection;

		private Vector2 _ctScroll;

		private const int ScrollCtBoard = 18;

		private const int ScrollCtActive = 19;

		private const int ScrollCtChains = 20;

		private const int ScrollCtHistory = 21;

		private const int ScrollCtGivers = 22;

		private const int ScrollCtModules = 23;

		private static readonly string[] CtSections = new string[5] { "Board", "Active", "Chains", "History", "Givers" };

		private Rebind _rebind;

		private float _rebindStarted;

		private bool _padCaptureArmed;

		private readonly HashSet<string> _padCapture = new HashSet<string>();

		private float _controlsContentH = 1600f;

		private Vector2 _controlsScroll;

		private readonly List<float> _flowW = new List<float>();

		private readonly List<Rect> _flowR = new List<Rect>();

		private List<string>? _treeCheck;

		private int _debugPage;

		private int _dbgClass;

		private int _dbgStat;

		private readonly Dictionary<string, float> _dbgCustom = new Dictionary<string, float>();

		private string _gearFilter = "";

		private int _gearRarityF = -1;

		private int _gearKindF;

		private int _gearSort;

		private string _gearQuery = "";

		private static readonly string[] GearSorts = new string[4] { "Rarity", "Slot", "Newest", "Attunement" };

		private static readonly string[] GearKinds = new string[6] { "All kinds", "Set pieces", "Uniques", "New", "Behavior", "Attuned" };

		private string _gearCompare = "";

		private string _gearCompareNext = "";

		private string _gearSel = "";

		private int _gearSig = int.MinValue;

		private readonly List<GearItem> _gearItems = new List<GearItem>();

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

		private readonly Dictionary<string, string[]> _rowLabels = new Dictionary<string, string[]>();

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

		private readonly float[] _gearTotals = new float[StatInfo.Count];

		private readonly float[] _gearAfter = new float[StatInfo.Count];

		private string _gearSideText = "";

		private int _modPick = -1;

		private int _craftModChoice;

		private float _gearRevealAt = -99f;

		private int _gearNewCount;

		private Vector2 _gearInspectScroll;

		private Vector2 _gearSideScroll;

		private const int ScrollGearInspect = 14;

		private const int ScrollGearSide = 15;

		private static readonly Dictionary<string, string> SlotDescFallback = new Dictionary<string, string>
		{
			["weapon"] = "Your hits: damage, stuns, bleeds, throws.",
			["plating"] = "Survival: health, armour, healing, dodging.",
			["servos"] = "Movement: speed, jumps and stamina.",
			["core"] = "Your ability: cooldown, power, area, XP."
		};

		private const int ScrollGuideCats = 9;

		private Vector2 _helpScroll;

		private Vector2 _guideCatScroll;

		private string _guideTopic = "";

		private string _guideQuery = "";

		private int _guideRole;

		private bool _guideWalk;

		private int _guideStep;

		private static int _cfgVersion;

		private static bool _cfgHooked;

		private readonly List<GItem> _gItems = new List<GItem>();

		private string _gKey = "";

		private float _gTotalH;

		private float _gNextStats;

		private List<GuideTopic>? _gVisible;

		private string _gVisibleKey = "~";

		private static readonly Regex GuideToken = new Regex("\\{([a-z]+):([^{}]*)\\}", RegexOptions.Compiled);

		private Dictionary<string, ConfigEntryBase>? _cfgCache;

		private static readonly Color HealGreen = new Color(0.42f, 0.95f, 0.52f);

		private int _healSampleHp = -1;

		private int _healCount;

		private float _healNextSample;

		private float _healLastAt = -99f;

		private float _healGlow;

		private Rect _healthUiRect;

		private float _nextHealthUiLook;

		private Component? _healthUi;

		private const string HudChars = " !\"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_`abcdefghijklmnopqrstuvwxyz{|}~·•→★×–—…‘’“”";

		private readonly HashSet<char> _hudExtra = new HashSet<char>();

		private string _hudExtraText = "";

		private readonly HashSet<(int, FontStyle)> _hudSizes = new HashSet<(int, FontStyle)>();

		private bool _prewarmDirty = true;

		private bool _inHud;

		private bool _fontHooked;

		private bool _hudHadClass;

		private Font? _prewarmedFont;

		private float _noPlayerSince = -1f;

		private float _hudBadSince = -1f;

		private int _diagFontRebuilds;

		private int _diagHides;

		private int _diagHolds;

		private int _diagReloads;

		private int _diagThemeAt = -1;

		private float _diagNext;

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

		private readonly StringBuilder _shapeSb = new StringBuilder(64);

		private const float PadIn = 12f;

		private const float GapLine = 4f;

		private const float GapItem = 8f;

		private const float GapSection = 16f;

		private readonly Dictionary<GUIStyle, float> _lineH = new Dictionary<GUIStyle, float>();

		private readonly Dictionary<(GUIStyle, string, int), float> _textHCache = new Dictionary<(GUIStyle, string, int), float>();

		private readonly Dictionary<(GUIStyle, string), float> _textWCache = new Dictionary<(GUIStyle, string), float>();

		private readonly Dictionary<(GUIStyle, int, int, bool), (GUIStyle, float, int)> _fitLines = new Dictionary<(GUIStyle, int, int, bool), (GUIStyle, float, int)>();

		private int _layoutVersion;

		private string _hintKey = "";

		private string _hintLabel = "";

		private string _hintGlyph = "";

		private bool _hintDot;

		private float _hintW;

		private float _nextHintDotCheck;

		private float _nextHintPageCheck;

		private bool _hintPageOk = true;

		private string _bannerShown = "";

		private float _bannerW;

		private float _bannerH;

		private float _bannerMul;

		private static bool _transitioning;

		private static float _transitionAt = -99f;

		private static bool _sceneLoadedSinceTransition;

		private bool _discardedNotice;

		private bool _blockedNoticeShown;

		private readonly List<FocusItem> _focusItems = new List<FocusItem>();

		private readonly List<FocusItem> _focusBuilding = new List<FocusItem>();

		private readonly HashSet<int> _focusKeysThisPass = new HashSet<int>();

		private readonly Dictionary<int, float> _scrollViewHeights = new Dictionary<int, float>();

		private readonly Dictionary<int, Rect> _scrollViewScreen = new Dictionary<int, Rect>();

		private float _tabRowBottom;

		private int _focusKey;

		private bool _padMode;

		private NavDevice _device;

		private NavDevice _promptDevice = NavDevice.Keyboard;

		private bool _padActivate;

		private int _currentScrollId;

		private float _navRepeatAt;

		private Vector2 _lastMouse;

		private float _menuHoldStart = -1f;

		private bool _menuHoldFired;

		private int _lastHoverKey;

		private Rect _lastFocusScreen;

		private bool _hasLastFocus;

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

		private readonly int[] _tabKeys = new int[16];

		private readonly HashSet<KeyCode> _kbPressed = new HashSet<KeyCode>();

		private bool _kbShift;

		private int _adjustKey;

		private Action? _adjDec;

		private Action? _adjInc;

		private Action? _adjConfirm;

		private int _secondaryKey;

		private string _secondaryLabel = "";

		private Action? _secondaryAction;

		private const int ScrollClasses = 1;

		private const int ScrollTree = 2;

		private const int ScrollGear = 3;

		private const int ScrollPerks = 4;

		private const int ScrollControls = 5;

		private const int ScrollShop = 6;

		private const int ScrollAttributes = 7;

		private const int ScrollHelp = 8;

		private static readonly KeyCode[] NavKeysUp = (KeyCode[])(object)new KeyCode[2]
		{
			(KeyCode)119,
			(KeyCode)273
		};

		private static readonly KeyCode[] NavKeysDown = (KeyCode[])(object)new KeyCode[2]
		{
			(KeyCode)115,
			(KeyCode)274
		};

		private static readonly KeyCode[] NavKeysLeft = (KeyCode[])(object)new KeyCode[2]
		{
			(KeyCode)97,
			(KeyCode)276
		};

		private static readonly KeyCode[] NavKeysRight = (KeyCode[])(object)new KeyCode[2]
		{
			(KeyCode)100,
			(KeyCode)275
		};

		private readonly List<(string[] glyphs, string label)> _prompts = new List<(string[], string)>();

		private float _promptStripH = 44f;

		private const float PromptGap = 22f;

		private const float PromptGapTight = 10f;

		private const float PromptPad = 22f;

		private readonly Dictionary<string, int> _talentPending = new Dictionary<string, int>();

		private string _talentPendingClass = "";

		private readonly Dictionary<int, string> _perkPending = new Dictionary<int, string>();

		private readonly Dictionary<byte, InFlight> _commits = new Dictionary<byte, InFlight>();

		private int _commitSeq = new Random().Next(1, 1073741824);

		private readonly Dictionary<int, (byte type, InFlight f)> _lateCommits = new Dictionary<int, (byte, InFlight)>();

		private HostChecks _hostChecks;

		private ClassDef? _playAsTarget;

		private DialogKind _dialogKind;

		private int _perkView = -1;

		private int _perkSort;

		private int _perkRarityF = -1;

		private int _perkTagF = -1;

		private int _perkOwnF;

		private string _perkQuery = "";

		private Vector2 _perkSideScroll;

		private string _banishArmed = "";

		private float _banishArmedUntil;

		private const int ScrollPerkSide = 12;

		private static readonly string[] PerkViewNames = new string[3] { "PICK", "OWNED", "ALL PERKS" };

		private static readonly string[] PerkSortNames = new string[3] { "Rarity", "Tag", "When picked" };

		private static readonly string[] PerkOwnNames = new string[4] { "Everything", "Owned", "Not owned", "Banished" };

		private readonly List<PerkDef> _ownedList = new List<PerkDef>();

		private readonly List<PerkDef> _allList = new List<PerkDef>();

		private (int, int, int, int, int) _ownedKey = (-1, 0, 0, 0, 0);

		private (int, int, int, int, int, int, string) _allKey = (-1, 0, 0, 0, 0, 0, "~");

		private const string SilhouetteText = "<color=#9a9ca0>Not discovered yet. A Legendary perk shows here once it has been offered to you.</color>";

		private const int PoolSize = 8;

		private readonly Popup[] _popups = CreatePool();

		private long _popupSeq;

		private float _xpPulseUntil;

		private static readonly Color PopXp = new Color(0.62f, 0.86f, 1f);

		private static readonly Color PopLevel = new Color(1f, 0.85f, 0.3f);

		private static readonly Color PopContract = new Color(0.95f, 0.83f, 0.55f);

		private static readonly Color PopPerk = new Color(1f, 0.7f, 0.12f);

		private static readonly Color PopOther = new Color(0.86f, 0.87f, 0.89f);

		private readonly List<Popup> _drawOrder = new List<Popup>(8);

		private float _blockedTopPx = -1f;

		private float _nextBlockScan;

		private readonly List<CanvasRenderer> _crs = new List<CanvasRenderer>(256);

		private readonly Vector3[] _corners = (Vector3[])(object)new Vector3[4];

		private static readonly string[] RoleFilters = new string[7] { "All", "Combat", "Support", "Control", "Utility", "Mobility", "Economy" };

		private int _roleFilter;

		private string _classQuery = "";

		private bool _searching;

		private List<(string name, List<ClassDef> list)>? _visibleGroups;

		private string _visibleKey = "";

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

		private ClassDef? _comparePick;

		private ClassDef? _compareA;

		private ClassDef? _compareB;

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

		private readonly Dictionary<(NodeDef, int), string> _nodeValueText = new Dictionary<(NodeDef, int), string>();

		private float _tabSwitchedAt = -9f;

		private bool _tabMemoryRestored;

		private readonly List<(UndoKind kind, string id)> _undo = new List<(UndoKind, string)>();

		private readonly HashSet<string> _seenGear = new HashSet<string>();

		private readonly HashSet<string> _newThisView = new HashSet<string>();

		private int _seenContractLevel = int.MinValue;

		private string _seenRunKey = "";

		private int _seenBoardLevel = int.MinValue;

		private int _tab;

		private static readonly string[] TabsBase = new string[10] { "Class", "Attributes", "Gear", "Perks", "Contracts", "Shop", "Account", "Settings", "Host", "Guide" };

		private static readonly string[] TabsDebug = new string[11]
		{
			"Class", "Attributes", "Gear", "Perks", "Contracts", "Shop", "Account", "Settings", "Host", "Guide",
			"Debug"
		};

		private Vector2 _gearScroll;

		private Vector2 _perkScroll;

		private readonly List<(string text, Color color)> _eliteLines = new List<(string, Color)>();

		private float _nextEliteHud;

		private int _heldUpgradeId = int.MinValue;

		private float _heldUpgradeRefresh;

		private readonly List<(string, Color)> _heldUpgradeLines = new List<(string, Color)>();

		private Vector2 _attrScroll;

		private AttributeDef? _attrFocus;

		private readonly Dictionary<string, int> _attrPending = new Dictionary<string, int>();

		private static readonly string[] AttrCategories = new string[3] { "Combat", "Physical", "Utility" };

		private (string, int, int) _attrDetailKey = ("", -1, -1);

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

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

		private Vector2 _shopScroll;

		private string _svcTarget = "";

		private int _svcLine = -1;

		private float _shopContentH = 820f;

		private readonly List<(string, Color)> _hudRight = new List<(string, Color)>();

		private readonly List<PoolItem> _scanPool = new List<PoolItem>();

		private int _scanWant;

		private float _scanTill;

		private float _cartCheckAt;

		private float _cartListAt;

		private bool _scanSharing;

		private PhysGrabCart[] _carts = Array.Empty<PhysGrabCart>();

		private HashSet<int> _inCarts = new HashSet<int>();

		private HashSet<int> _inCartsNext = new HashSet<int>();

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

		private readonly List<Tracked> _tracked = new List<Tracked>();

		private Material? _outlineMat;

		private MaterialPropertyBlock? _outlineMpb;

		private Texture2D? _texTri;

		private Texture2D? _texDiamond;

		private float _scanHudAt;

		private bool _scanCopied;

		private readonly List<Rect> _keepClear = new List<Rect>();

		private Rect _contractsRect;

		private Rect _rightRect;

		private GUIStyle? _scanStyle;

		private GUIStyle? _scanStyleFrom;

		private int _shopSection;

		private int _shopSel = -1;

		private Vector2 _shopGridScroll;

		private Vector2 _shopInspectScroll;

		private const int ScrollShopGrid = 16;

		private const int ScrollShopInspect = 17;

		private static readonly string[] ShopSections = new string[8] { "Featured", "Gear", "Modules", "Consumables", "Services", "Crates", "Buyback", "Wishlist" };

		private int _effectsSplit;

		private float _effectsLeftH;

		private float _effectsRightH;

		private bool _effectsTwoCols;

		private Vector2 _effectsScroll;

		private const int ScrollEffects = 24;

		private string _effectsSig = "";

		private readonly List<(string text, GUIStyle style, float h)> _effectsLines = new List<(string, GUIStyle, float)>();

		private float _effectsH;

		private int _statsVersion;

		private static readonly Dictionary<Stat, string> Caps = new Dictionary<Stat, string>
		{
			{
				Stat.DodgeChance,
				"MaxDodgeChance"
			},
			{
				Stat.CooldownReduction,
				"MaxCooldownReduction"
			},
			{
				Stat.DamageTaken,
				"MaxDamageReduction"
			},
			{
				Stat.HeldItemProtection,
				"MaxHeldItemProtection"
			},
			{
				Stat.AppraiseValue,
				"MaxAppraiseBonus"
			},
			{
				Stat.AppraiseRareBonus,
				"MaxAppraiseBonus"
			},
			{
				Stat.GuardAura,
				"MaxShieldWall"
			},
			{
				Stat.StabilizeAura,
				"MaxStabilize"
			},
			{
				Stat.ScarTissueMax,
				"MaxScarTissue"
			},
			{
				Stat.MarkDamage,
				"MaxMarkDamage"
			},
			{
				Stat.NoiseReduction,
				"MaxNoiseReduction"
			},
			{
				Stat.ScrapBonus,
				"MaxScrapBonus"
			},
			{
				Stat.HealOnKill,
				"MaxHealOnKill"
			},
			{
				Stat.HealthRegen,
				"MaxHealthRegen"
			},
			{
				Stat.Lifesteal,
				"MaxLifesteal"
			},
			{
				Stat.ExtractionHeal,
				"MaxExtractionHeal"
			},
			{
				Stat.MoveSpeed,
				"MaxSpeedBonus"
			},
			{
				Stat.SprintSpeed,
				"MaxSpeedBonus"
			},
			{
				Stat.MaxStamina,
				"MaxStaminaBonus"
			},
			{
				Stat.StaminaRegen,
				"MaxStaminaRegenBonus"
			},
			{
				Stat.StaminaDrain,
				"MaxStaminaDrainReduction"
			},
			{
				Stat.HoldingStaminaDrain,
				"MaxStaminaDrainReduction"
			}
		};

		private static readonly Regex Num = new Regex("\\d+(\\.\\d+)?", RegexOptions.Compiled);

		private readonly Dictionary<int, Mate> _mates = new Dictionary<int, Mate>();

		private readonly List<Mate> _mateOrder = new List<Mate>();

		private float _matesAt = -99f;

		private float _mateAvatarsAt;

		private bool _mateOrderDirty;

		private Rect _triageRect;

		private float _triageDiagAt;

		private bool _triageDiagOn;

		private readonly List<string> _triageDiag = new List<string>();

		private int _moreN = -1;

		private string _moreText = "";

		private static readonly Color Good = new Color(0.45f, 1f, 0.4f);

		private static readonly Color Bad = new Color(1f, 0.38f, 0.32f);

		private Font? _font;

		private Texture2D _texWhite;

		private Texture2D _texAccent;

		private int _hoverId = -1;

		private int _hoverIdThisFrame = -1;

		private static readonly Regex ColorTags = new Regex("</?color[^>]*>", RegexOptions.Compiled);

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

		private readonly Dictionary<(GUIStyle, int), GUIStyle> _sizedStyles = new Dictionary<(GUIStyle, int), GUIStyle>();

		private readonly Dictionary<(GUIStyle, string, int, int), GUIStyle> _fitCache = new Dictionary<(GUIStyle, string, int, int), GUIStyle>();

		private readonly GUIContent _measure = new GUIContent();

		private bool _onFill;

		private readonly Dictionary<(Color, bool), Color> _readable = new Dictionary<(Color, bool), Color>();

		private int _readableVersion = -1;

		private static readonly Regex SizeTag = new Regex("<size=(\\d+)>", RegexOptions.Compiled);

		private static readonly Regex ColorTag = new Regex("<color=#([0-9a-fA-F]{6})([0-9a-fA-F]{2})?>", RegexOptions.Compiled);

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

		private int _tagVersion = -1;

		private static MethodInfo? _clickMethod;

		private static MethodInfo? _hoverMethod;

		private static bool _soundLookupDone;

		private static FieldInfo? _mmInstance;

		private static readonly Dictionary<UiSound, object?[]?> SoundArgs = new Dictionary<UiSound, object[]>();

		private static readonly Dictionary<UiSound, string[]> SoundNames = new Dictionary<UiSound, string[]>
		{
			[UiSound.Click] = new string[3] { "Action", "Click", "Confirm" },
			[UiSound.Confirm] = new string[3] { "Confirm", "Buy", "Action" },
			[UiSound.Back] = new string[4] { "Back", "Cancel", "Deny", "Action" },
			[UiSound.Error] = new string[5] { "Deny", "Error", "Fail", "Back", "Action" },
			[UiSound.Tick] = new string[3] { "Tick", "Move", "Action" }
		};

		private bool LimitsKnown => _limitsLevel == RunInfo.LevelIndex;

		public string CurrentId => Current?.id ?? "";

		private float SmallMass => Plugin.Cfg.GrapplerSmallMass.Value + Mathf.Clamp(ClassStat("grappler.heavy"), 0f, 10f);

		private bool FirmHold => _stats.Custom("attr.firm_hold") > 0f;

		private float RegenDelayCut => Mathf.Clamp(_stats.Custom("attr.resilient"), 0f, 3f);

		private RunSave CtRun => _store.Data;

		public bool ContractBoardOpen => Game.ClassSelectionOpen();

		private int CtUsedSlots => CtRun.accepted.Count + PendingAccepts();

		public int RerollPrice => ContractBoard.RerollPrice((CtRun.boardLevel == RunInfo.LevelIndex) ? CtRun.boardRerolls : 0);

		private int DeathSavesUsedThisLevel
		{
			get
			{
				RunSave data = _store.Data;
				int levelIndex = RunInfo.LevelIndex;
				if (data.deathSavesLevel != levelIndex)
				{
					bool flag = _deathSavesTagged == data && levelIndex > data.deathSavesLevel;
					if (data.deathSavesLevel != -1 && !flag)
					{
						data.deathSavesUsed = 0;
					}
					data.deathSavesLevel = levelIndex;
				}
				_deathSavesTagged = data;
				return data.deathSavesUsed;
			}
		}

		private int DeathSavesLeft
		{
			get
			{
				int num = Mathf.Max(0, Mathf.FloorToInt(_stats[Stat.DeathSaves]) + _notTodaySaves - DeathSavesUsedThisLevel);
				if (Difficulty.Hardcore)
				{
					num = Mathf.Min(num, Mathf.Max(0, Difficulty.SaveCost - DeathSavesUsedThisLevel));
				}
				return num / Difficulty.SaveCost;
			}
		}

		public static bool LoadoutSwapAllowed
		{
			get
			{
				if (Game.InLevel())
				{
					return Shop.OpenNow;
				}
				return true;
			}
		}

		public bool LateJoinShielded => Time.time < _ljShieldUntil;

		private float HealMoreMult => 1f + Mathf.Clamp(_stats.Custom("perk.heal_more"), 0f, 30f) / 100f;

		public int InventoryCap => Mathf.Max(4, Plugin.Cfg.InventorySize.Value - Mathf.RoundToInt(Mathf.Clamp(_stats.Custom("perk.hoarder"), 0f, 10f)));

		public static RpgRuntime? Instance { get; private set; }

		public RunSave Run => _store.Data;

		public ClassDef? Current { get; private set; }

		public ClassProgress? CurrentProgress { get; private set; }

		private TrackedField[] AllTracked => new TrackedField[10] { _maxHealth, _move, _sprint, _crouch, _jumpForce, _jumpExtra, _energyMax, _grabStrength, _grabRange, _throw };

		public bool RunReady
		{
			get
			{
				if (_store.Loaded)
				{
					return _store.RunKey == RunInfo.Key;
				}
				return false;
			}
		}

		public float CooldownRemaining
		{
			get
			{
				if (_charges <= 0)
				{
					return Mathf.Max(0f, _cooldownEnd - Time.time);
				}
				return 0f;
			}
		}

		public int Charges => _charges;

		public int MaxCharges => 1 + Mathf.Max(0, Mathf.FloorToInt(_stats[Stat.AbilityCharges] + _stats.Custom(Current?.active.mods.charges)));

		public float BuffRemaining => Mathf.Max(0f, _buffEnd - Time.time);

		public float StaminaRegenBonus
		{
			get
			{
				if (Current != null)
				{
					return Mathf.Clamp((_stats[Stat.StaminaRegen] + _linkRegen) * Plugin.Cfg.StaminaRegenBonusScale.Value, 0f, Plugin.Cfg.MaxStaminaRegenBonus.Value);
				}
				return 0f;
			}
		}

		public float LevelElapsed => Time.time - _levelStartTime;

		public int ShopTier => ShopX.Tier(Account.Active("loyalty_card") ? Mathf.Max(_store.Data.shopRep, ShopX.TierAt[1]) : _store.Data.shopRep);

		private int[] Parts
		{
			get
			{
				RunSave data = _store.Data;
				if (data.parts == null || data.parts.Length < 4)
				{
					int[] array = new int[4];
					if (data.parts != null)
					{
						Array.Copy(data.parts, array, data.parts.Length);
					}
					data.parts = array;
				}
				return data.parts;
			}
		}

		private bool CanEditHost
		{
			get
			{
				if (Game.IsMultiplayer())
				{
					return Game.IsMaster();
				}
				return true;
			}
		}

		public bool HostHasPending => _hostPending.Count > 0;

		public RunSave? HostRun => _store?.Data;

		private bool TeamVoting
		{
			get
			{
				if (_tcDef != null && _tcState == 0 && _tcLevel == RunInfo.LevelIndex)
				{
					if (!Game.InLevel())
					{
						return Game.ClassSelectionOpen();
					}
					return true;
				}
				return false;
			}
		}

		private bool GoldFrame
		{
			get
			{
				if (Account.Has("gold_frame"))
				{
					return Account.Data.goldFrame;
				}
				return false;
			}
		}

		private bool AttrHasPending => _attrPending.Count > 0;

		private bool AttrBusy => _attrInFlight != null;

		public static bool MenuOpen
		{
			get
			{
				if ((Object)(object)Instance != (Object)null)
				{
					if (!Instance._menuOpen)
					{
						return Time.frameCount <= Instance._menuClosedFrame + 2;
					}
					return true;
				}
				return false;
			}
		}

		public string MenuPrompt
		{
			get
			{
				//IL_0011: Unknown result type (might be due to invalid IL or missing references)
				//IL_0016: Unknown result type (might be due to invalid IL or missing references)
				if (!Pad.Connected)
				{
					return ((object)Plugin.Cfg.MenuKey.Value/*cast due to .constrained prefix*/).ToString();
				}
				return ((Plugin.Cfg.PadMenuHoldSeconds.Value > 0.01f) ? "HOLD " : "") + PadButtons(Plugin.Cfg.PadMenuButton.Value);
			}
		}

		public string AbilityPrompt
		{
			get
			{
				//IL_0011: Unknown result type (might be due to invalid IL or missing references)
				//IL_0016: Unknown result type (might be due to invalid IL or missing references)
				if (!Pad.Connected)
				{
					return ((object)Plugin.Cfg.AbilityKey.Value/*cast due to .constrained prefix*/).ToString();
				}
				return PadButtons(Plugin.Cfg.PadAbilityButton.Value);
			}
		}

		private float PmW => Mathf.Max(50f, TextW("> +", _btn) + 24f);

		public bool DebugAvailable
		{
			get
			{
				if (Plugin.Cfg.DebugTools.Value)
				{
					return Game.IsMaster();
				}
				return false;
			}
		}

		private static HealFeedbackLevel HealLevel => Plugin.Cfg.HealFeedback.Value;

		private static bool HudDiag => Plugin.Cfg.HudDiagnostics.Value;

		private float HeaderH => LineH(_h2) + 6f;

		private float BtnH => Mathf.Max(36f, LineH(_btn) + 12f);

		private float GlyphRowH => Mathf.Max(24f, LineH(_tabStyle) + 6f);

		private float PendingBarH => BtnH + 8f + 4f;

		public static bool MenuBlocksGame
		{
			get
			{
				if (MenuOpen)
				{
					return !_transitioning;
				}
				return false;
			}
		}

		private float ScrollbarW
		{
			get
			{
				GUIStyle val = (((Object)(object)GUI.skin != (Object)null) ? GUI.skin.verticalScrollbar : null);
				if (val != null)
				{
					return Mathf.Max(16f, val.fixedWidth + (float)val.margin.horizontal);
				}
				return 16f;
			}
		}

		private float PromptRowH => 26f * _fontMul;

		private bool TalentsHavePending => _talentPending.Count > 0;

		private bool PerksHavePending => _perkPending.Count > 0;

		private bool TalentsBusy => _commits.ContainsKey(1);

		private bool PerksBusy => _commits.ContainsKey(2);

		private bool ClaimBusy => _commits.ContainsKey(3);

		private bool DecideLocally
		{
			get
			{
				if (Game.IsMultiplayer() && !Game.IsMaster() && !RunStore.IsTempKey(RunInfo.Key))
				{
					return _hostChecks == HostChecks.No;
				}
				return true;
			}
		}

		private bool AnyPending
		{
			get
			{
				if (!TalentsHavePending && !AttrHasPending)
				{
					return PerksHavePending;
				}
				return true;
			}
		}

		private bool Reduced => Plugin.Cfg.ReducedEffects.Value;

		private bool ReducedMotion
		{
			get
			{
				if (!Plugin.Cfg.ReducedMotion.Value)
				{
					return Plugin.Cfg.ReducedEffects.Value;
				}
				return true;
			}
		}

		private bool CanUndo
		{
			get
			{
				string text = ((_tab < TabNames.Length) ? TabNames[_tab] : "");
				foreach (var (undoKind, key) in _undo)
				{
					if ((text == "Class" && undoKind == UndoKind.Talent && _talentPending.ContainsKey(key)) || (text == "Attributes" && undoKind == UndoKind.Attribute && _attrPending.ContainsKey(key)))
					{
						return true;
					}
				}
				return false;
			}
		}

		private string[] TabNames
		{
			get
			{
				if (!DebugAvailable)
				{
					return TabsBase;
				}
				return TabsDebug;
			}
		}

		private bool _showEffects
		{
			get
			{
				return EffectsPrefs.Get();
			}
			set
			{
				EffectsPrefs.Set(value);
			}
		}

		private bool SeesTeamHealth
		{
			get
			{
				if (!(CurrentId == "medic"))
				{
					if (CurrentId == "mimic")
					{
						return ClassStat("mimic.triage") > 0f;
					}
					return false;
				}
				return true;
			}
		}

		private static Color Accent => ClassTheme.Cur.Accent;

		private static Color AccentSoft => Color.Lerp(ClassTheme.Cur.Accent, Color.white, 0.35f);

		private static Color TextMain => ClassTheme.Cur.Text;

		private static Color TextMuted => ClassTheme.Cur.Muted;

		private static Color TextSecondary => ClassTheme.Cur.TextSec;

		public static event Action<ClassDef?>? ClassChanged;

		private void OnAbilityState(string text)
		{
			string[] array = text.Split('|');
			if (array.Length >= 6)
			{
				int.TryParse(array[0], out _supplyLeft);
				int.TryParse(array[1], out _supplyCharges);
				int.TryParse(array[2], out _supplyPrice);
				int.TryParse(array[3], out _betLeft);
				int.TryParse(array[4], out _betUses);
				int.TryParse(array[5], out _limitsLevel);
				_nextHudBuild = 0f;
			}
		}

		private void ClearAbilityLimits()
		{
			_betMarks.Clear();
			_cartState = "";
		}

		private string EffectiveAbilityClass()
		{
			if (Current == null)
			{
				return "";
			}
			if (Current.id == "mimic")
			{
				return MimicCopy()?.id ?? "";
			}
			return Current.id;
		}

		private BetMark? MyBet()
		{
			int localActor = ClassClaims.LocalActor;
			foreach (KeyValuePair<int, BetMark> betMark in _betMarks)
			{
				if (betMark.Value.Actor == localActor || !Game.IsMultiplayer())
				{
					return betMark.Value;
				}
			}
			return null;
		}

		private string AbilityLimitText()
		{
			string text = EffectiveAbilityClass();
			if (!(text == "quartermaster"))
			{
				if (text == "gambler")
				{
					BetMark betMark = MyBet();
					if (betMark != null)
					{
						return $"  x{betMark.Mult:0.0}  {Mathf.CeilToInt(betMark.Remaining)}s" + ((betMark.Armed < 1f) ? "  (arming)" : "");
					}
					int num = (LimitsKnown ? _betUses : Plugin.Cfg.BetUsesPerLevel.Value);
					int num2 = (LimitsKnown ? _betLeft : num);
					return $"  {num2}/{num} this level";
				}
				return "";
			}
			int num3 = (LimitsKnown ? _supplyCharges : (Plugin.Cfg.ResupplyCharges.Value + ((Current?.id == "quartermaster") ? Mathf.FloorToInt(ClassStat("quartermaster.supply_extra") + 0.001f) : 0)));
			int num4 = (LimitsKnown ? _supplyLeft : num3);
			string text2 = $"  {num4}/{num3} this level";
			if (num4 == 0 && LimitsKnown && _supplyPrice >= 0)
			{
				text2 = text2 + "  - next " + Scrap.Price(_supplyPrice);
			}
			return text2;
		}

		private bool ResupplyAllowedLocally()
		{
			//IL_001f: Unknown result type (might be due to invalid IL or missing references)
			if (LimitsKnown && _supplyLeft == 0 && _supplyPrice < 0)
			{
				Toast("Resupply: no charges left this level", Color.gray);
				MenuSound(UiSound.Error);
				return false;
			}
			return true;
		}

		private bool BetAllowedLocally()
		{
			//IL_000e: Unknown result type (might be due to invalid IL or missing references)
			//IL_003b: Unknown result type (might be due to invalid IL or missing references)
			if (MyBet() != null)
			{
				Toast("You already have a bet running", Color.gray);
				MenuSound(UiSound.Error);
				return false;
			}
			if (LimitsKnown && _betLeft == 0)
			{
				Toast("Double or Nothing: already used this level", Color.gray);
				MenuSound(UiSound.Error);
				return false;
			}
			return true;
		}

		public void OnBetState(int viewId, int actor, float mult, float remaining, float armed, string message)
		{
			//IL_0066: Unknown result type (might be due to invalid IL or missing references)
			//IL_006b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0070: Unknown result type (might be due to invalid IL or missing references)
			//IL_0050: 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)
			if (message != "")
			{
				_betMarks.Remove(viewId);
				Color value = ((mult <= 0f) ? new Color(1f, 0.42f, 0.38f) : ((mult <= 1.001f) ? new Color(0.7f, 0.7f, 0.72f) : new Color(1f, 0.18f, 0.6f)));
				Notify(PopupKind.Other, message, value);
				_nextHudBuild = 0f;
				return;
			}
			if (!_betMarks.TryGetValue(viewId, out BetMark value2))
			{
				value2 = (_betMarks[viewId] = new BetMark());
			}
			value2.Actor = actor;
			value2.Mult = mult;
			value2.Remaining = remaining;
			value2.Armed = armed;
			value2.At = Time.unscaledTime;
			value2.Text = ((armed < 1f) ? $"x{mult:0.0}  {Mathf.CeilToInt(remaining)}s  ARMING" : $"x{mult:0.0}  {Mathf.CeilToInt(remaining)}s");
		}

		private void DrawBetMarks()
		{
			//IL_0012: Unknown result type (might be due to invalid IL or missing references)
			//IL_0018: Invalid comparison between Unknown and I4
			//IL_0101: Unknown result type (might be due to invalid IL or missing references)
			//IL_0106: Unknown result type (might be due to invalid IL or missing references)
			//IL_0110: Unknown result type (might be due to invalid IL or missing references)
			//IL_0115: Unknown result type (might be due to invalid IL or missing references)
			//IL_011a: Unknown result type (might be due to invalid IL or missing references)
			//IL_011f: 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_012f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0140: Unknown result type (might be due to invalid IL or missing references)
			//IL_017d: 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)
			if (_betMarks.Count == 0 || (int)Event.current.type != 7)
			{
				return;
			}
			Camera main = Camera.main;
			if ((Object)(object)main == (Object)null)
			{
				return;
			}
			float unscaledTime = Time.unscaledTime;
			float num = Mathf.Max(0.01f, _lastUiScale);
			_betGone.Clear();
			foreach (KeyValuePair<int, BetMark> betMark in _betMarks)
			{
				BetMark value = betMark.Value;
				if (unscaledTime - value.At > 4f)
				{
					_betGone.Add(betMark.Key);
					continue;
				}
				if ((Object)(object)value.Target == (Object)null && unscaledTime >= value.LookedUp)
				{
					value.LookedUp = unscaledTime + 1f;
					PhotonView val = PhotonView.Find(betMark.Key);
					value.Target = (((Object)(object)val != (Object)null) ? ((Component)val).transform : null);
				}
				if (!((Object)(object)value.Target == (Object)null))
				{
					Vector3 val2 = Game.ToScreen(main, value.Target.position + Vector3.up * 0.7f);
					if (!(val2.z <= 0f))
					{
						float num2 = val2.x / num;
						float num3 = ((float)Screen.height - val2.y) / num;
						float num4 = 260f * _fontMul;
						float num5 = LineH(_h2Center);
						ShadowLabel(new Rect(num2 - num4 / 2f, num3 - num5, num4, num5), value.Text, _h2Center, new Color(1f, 0.18f, 0.6f));
					}
				}
			}
			foreach (int item in _betGone)
			{
				_betMarks.Remove(item);
			}
		}

		public float ClassStat(string name)
		{
			return _stats.Custom(name);
		}

		private void TickClassStatsSend()
		{
			if (!Game.IsMultiplayer())
			{
				return;
			}
			PhysGrabber instance = PhysGrabber.instance;
			float num = (((Object)(object)instance != (Object)null) ? instance.grabStrength : (-1f));
			float num2 = (((Object)(object)instance != (Object)null) ? instance.throwStrength : (-10f));
			if (Time.unscaledTime >= _nextGripCheck)
			{
				_nextGripCheck = Time.unscaledTime + 0.5f;
				if (Mathf.Abs(num - _sentGrab) > 0.02f || Mathf.Abs(num2 - _sentThrow) > 0.02f)
				{
					_classStatsSendAt = 0f;
				}
			}
			if (Time.unscaledTime < _classStatsSendAt)
			{
				return;
			}
			_classStatsSendAt = Time.unscaledTime + 10f;
			string currentId = CurrentId;
			if (currentId != "")
			{
				_stats.CustomWithPrefix(currentId + ".", _classStatsBuf);
			}
			else
			{
				_classStatsBuf.Clear();
			}
			_stats.CustomWithPrefix("set.", _setStatsBuf);
			foreach (KeyValuePair<string, float> item in _setStatsBuf)
			{
				_classStatsBuf[item.Key] = item.Value;
			}
			_stats.CustomWithPrefix("perk.", _setStatsBuf);
			foreach (KeyValuePair<string, float> item2 in _setStatsBuf)
			{
				_classStatsBuf[item2.Key] = item2.Value;
			}
			_stats.CustomWithPrefix("attr.", _setStatsBuf);
			foreach (KeyValuePair<string, float> item3 in _setStatsBuf)
			{
				_classStatsBuf[item3.Key] = item3.Value;
			}
			_stats.CustomWithPrefix("gear.", _setStatsBuf);
			foreach (KeyValuePair<string, float> item4 in _setStatsBuf)
			{
				_classStatsBuf[item4.Key] = item4.Value;
			}
			_stats.CustomWithPrefix("shop.", _setStatsBuf);
			foreach (KeyValuePair<string, float> item5 in _setStatsBuf)
			{
				_classStatsBuf[item5.Key] = item5.Value;
			}
			_sentGrab = num;
			_sentThrow = num2;
			Net.SendClassStats(ClassStats.Encode(currentId, _classStatsBuf), num, num2);
		}

		public void OnAllyBuff(AllyBuff b)
		{
			//IL_01f7: Unknown result type (might be due to invalid IL or missing references)
			if (b.Speed > 0f || b.Grip > 0f || b.Guard > 0f)
			{
				_buffs.Add(new TimedBuff
				{
					Speed = b.Speed,
					Grip = b.Grip,
					Guard = b.Guard,
					Until = Time.time + Mathf.Max(0.5f, b.Duration),
					Source = (b.Source ?? "")
				});
			}
			if (b.Source == "Rally Cry" && CurrentId == "brute" && Synergies.Has(Game.LocalPlayer(), "war_cry"))
			{
				for (int i = 0; i < Mathf.Clamp(Mathf.RoundToInt(Synergies.V("war_cry")), 0, 3); i++)
				{
					AddFrenzy();
				}
			}
			if (b.HealthPct > 0f)
			{
				_pendingHealthPct = b.HealthPct;
				_pendingHealthAt = Time.time + 0.6f;
			}
			if (b.StaminaPct > 0f)
			{
				PlayerController instance = PlayerController.instance;
				if ((Object)(object)instance != (Object)null)
				{
					float num = Game.Get(instance, "EnergyStart", 0f);
					float num2 = Game.Get(instance, "EnergyCurrent", 0f);
					Game.Set(instance, "EnergyCurrent", Mathf.Min(num, num2 + num * b.StaminaPct / 100f));
				}
			}
			if (!string.IsNullOrEmpty(b.Source) && (b.Speed > 0f || b.Guard > 0f || b.Grip > 0f))
			{
				Notify(PopupKind.Other, b.Source + ": " + BuffText(b.Speed, b.Grip, b.Guard), ParseColor(Current?.color ?? "#FFFFFF"), "buff:" + b.Source);
			}
		}

		private static string BuffText(float speed, float grip, float guard)
		{
			List<string> list = new List<string>();
			if (speed > 0f)
			{
				list.Add($"+{speed:0}% speed");
			}
			if (grip > 0f)
			{
				list.Add($"+{grip:0}% grip");
			}
			if (guard > 0f)
			{
				list.Add($"-{guard:0}% damage");
			}
			return string.Join(", ", list);
		}

		private void AddSelfBuff(AllyBuff b)
		{
			OnAllyBuff(b);
		}

		private void AddSelfDyn(Stat s, float v, float seconds)
		{
			_selfDyn.Add((s, v, Time.time + seconds));
		}

		private void TickNewClasses(PlayerAvatar local)
		{
			//IL_01bb: Unknown result type (might be due to invalid IL or missing references)
			//IL_01c6: Unknown result type (might be due to invalid IL or missing references)
			//IL_01cb: Unknown result type (might be due to invalid IL or missing references)
			//IL_01d0: Unknown result type (might be due to invalid IL or missing references)
			float time = Time.time;
			string currentId = CurrentId;
			for (int num = _buffs.Count - 1; num >= 0; num--)
			{
				if (time >= _buffs[num].Until)
				{
					_buffs.RemoveAt(num);
				}
			}
			for (int num2 = _selfDyn.Count - 1; num2 >= 0; num2--)
			{
				if (time >= _selfDyn[num2].until)
				{
					_selfDyn.RemoveAt(num2);
				}
			}
			float num3 = 0f;
			float num4 = 0f;
			foreach (TimedBuff buff in _buffs)
			{
				num3 = Mathf.Max(num3, buff.Speed);
				num4 = Mathf.Max(num4, buff.Grip);
			}
			if (num3 > 0f)
			{
				_stats.AddDyn(Stat.MoveSpeed, num3);
				_stats.AddDyn(Stat.SprintSpeed, num3);
			}
			if (num4 > 0f)
			{
				_stats.AddDyn(Stat.GrabStrength, num4);
			}
			foreach (var item in _selfDyn)
			{
				_stats.AddDyn(item.stat, item.value);
			}
			if (_pendingHealthPct > 0f && time >= _pendingHealthAt)
			{
				ApplyPendingHealth(local);
			}
			if (time >= _nextNearCheck)
			{
				_nextNearCheck = time + 0.5f;
				_monsterNear = false;
				foreach (EnemyHealth item2 in Game.LivingEnemies())
				{
					Vector3 val = ((Component)item2).transform.position - ((Component)local).transform.position;
					if (((Vector3)(ref val)).sqrMagnitude < 100f)
					{
						_monsterNear = true;
						break;
					}
				}
				float num5 = 0f;
				float num6 = 0f;
				foreach (var (aura, num7) in NearbyAuras(local))
				{
					if (!(aura.Inspire <= 0f) && !(num7 > aura.InspireRadius))
					{
						num5 = Mathf.Max(num5, aura.InspireSpeed * aura.Inspire / 100f);
						num6 = Mathf.Max(num6, aura.InspireGrip * aura.Inspire / 100f);
					}
				}
				_inspireFromAllies = (speed: num5, grip: num6);
			}
			if (_inspireFromAllies.speed > 0f)
			{
				_stats.AddDyn(Stat.MoveSpeed, _inspireFromAllies.speed);
				_stats.AddDyn(Stat.SprintSpeed, _inspireFromAllies.speed);
			}
			if (_inspireFromAllies.grip > 0f)
			{
				_stats.AddDyn(Stat.GrabStrength, _inspireFromAllies.grip);
			}
			if (currentId != "bloodbound")
			{
				TickPactDrain(local);
			}
			if (currentId == "gambler" && time >= _gambleCheckAt)
			{
				_gambleCheckAt = time + 2f;
				EnsureGambleRoll();
			}
			switch (currentId)
			{
			case "herald":
				TickHerald(local);
				break;
			case "mimic":
				TickMimic(local);
				break;
			case "undertaker":
				TickUndertaker(local);
				break;
			case "physicist":
				_stats.AddDyn(Stat.ThrowStrength, ClassStat("physicist.throw"));
				break;
			case "bloodbound":
				TickBloodbound(local);
				break;
			}
			TickThirdWave(local, currentId);
			TickThreats(local);
			TickAltPassives(local, currentId, time);
		}

		private float NewClassDamageMult()
		{
			//IL_01ab: Unknown result type (might be due to invalid IL or missing references)
			//IL_01b0: Unknown result type (might be due to invalid IL or missing references)
			float num = 0f;
			foreach (TimedBuff buff in _buffs)
			{
				num = Mathf.Max(num, buff.Guard);
			}
			float num2 = 1f - Mathf.Clamp(num, 0f, 50f) / 100f;
			switch (CurrentId)
			{
			case "herald":
				if (_monsterNear)
				{
					num2 *= 1f - Mathf.Clamp(ClassStat("herald.near_guard"), 0f, 40f) / 100f;
				}
				if (_inspire > 50f)
				{
					num2 *= 1f - Mathf.Clamp(ClassStat("herald.rod_guard"), 0f, 40f) / 100f;
				}
				break;
			case "undertaker":
				if (HoldingHead())
				{
					num2 *= 1f - Mathf.Clamp(ClassStat("undertaker.carry_guard"), 0f, 40f) / 100f;
				}
				break;
			case "juggernaut":
			{
				float num4 = Mathf.Clamp(ClassStat("juggernaut.alt_anchor"), 0f, 30f);
				PlayerController instance = PlayerController.instance;
				Rigidbody val = (((Object)(object)instance != (Object)null) ? Game.Get<Rigidbody>(instance, "rb", null) : null);
				if (num4 > 0f && (Object)(object)val != (Object)null)
				{
					Vector3 linearVelocity = val.linearVelocity;
					if (((Vector3)(ref linearVelocity)).sqrMagnitude < 0.25f)
					{
						num2 *= 1f - num4 / 100f;
					}
				}
				break;
			}
			case "cartwright":
			{
				float num3 = ClassStat("cartwright.cart_shelter");
				if (num3 > 0f && CartNear(4f))
				{
					num2 *= 1f - Mathf.Clamp(num3, 0f, 40f) / 100f;
				}
				break;
			}
			}
			PlayerAvatar val2 = Game.LocalPlayer();
			if ((Object)(object)val2 != (Object)null)
			{
				num2 *= ThirdWaveDamageMult(val2);
			}
			if ((Object)(object)val2 != (Object)null)
			{
				num2 *= SynergyDamageMult(val2);
			}
			return num2;
		}

		private void OnHitTaken()
		{
			float num = Mathf.Clamp(ClassStat("brute.alt_grudge"), 0f, 60f);
			if (num > 0f && CurrentId == "brute")
			{
				AddSelfDyn(Stat.WeaponDamage, num, 3f);
				_nextCombatSend = 0f;
			}
			if (CurrentId == "herald")
			{
				_inspire = Mathf.Min(100f, _inspire + Mathf.Max(0f, ClassStat("herald.hurt_gain")));
			}
		}

		private bool CartNear(float range)
		{
			//IL_0069: Unknown result type (might be due to invalid IL or missing references)
			//IL_0074: Unknown result type (might be due to invalid IL or missing references)
			//IL_0079: 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)
			PlayerAvatar val = Game.LocalPlayer();
			if ((Object)(object)val == (Object)null)
			{
				return false;
			}
			if (Time.time >= _nextCartLook)
			{
				_nextCartLook = Time.time + 2f;
				try
				{
					_cartsNear = Object.FindObjectsByType<PhysGrabCart>((FindObjectsSortMode)0);
				}
				catch
				{
					_cartsNear = Array.Empty<PhysGrabCart>();
				}
			}
			PhysGrabCart[] cartsNear = _cartsNear;
			foreach (PhysGrabCart val2 in cartsNear)
			{
				if ((Object)(object)val2 != (Object)null)
				{
					Vector3 val3 = ((Component)val2).transform.position - ((Component)val).transform.position;
					if (((Vector3)(ref val3)).sqrMagnitude <= range * range)
					{
						return true;
					}
				}
			}
			return false;
		}

		private void TickHerald(PlayerAvatar local)
		{
			//IL_0065: Unknown result type (might be due to invalid IL or missing references)
			//IL_0124: Unknown result type (might be due to invalid IL or missing references)
			//IL_0129: Unknown result type (might be due to invalid IL or missing references)
			//IL_019a: 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_0151: 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_0173: Unknown result type (might be due to invalid IL or missing references)
			//IL_0178: Unknown result type (might be due to invalid IL or missing references)
			//IL_0192: Unknown result type (might be due to invalid IL or missing references)
			//IL_018c: 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_0266: Unknown result type (might be due to invalid IL or missing references)
			//IL_0271: Unknown result type (might be due to invalid IL or missing references)
			//IL_0276: Unknown result type (might be due to invalid IL or missing references)
			//IL_027b: Unknown result type (might be due to invalid IL or missing references)
			float deltaTime = Time.deltaTime;
			if (!Game.IsAlive(local))
			{
				_talking = false;
				return;
			}
			bool flag = false;
			object obj = VoiceInstance.Value();
			if (obj != null)
			{
				flag = Game.Get(obj, "clipLoudness", 0f) > Plugin.Cfg.HeraldVoiceThreshold.Value;
			}
			bool flag2 = !_menuOpen && ((_held.Contains(Plugin.Cfg.HumKey.Value) && !ChatOpen.Value()) || (Pad.Connected && Pad.ChordHeld(Plugin.Cfg.PadHumButton.Value)));
			_talking = flag || flag2;
			bool flag3 = ClassStat("herald.alt_whisper") > 0f;
			float num = (flag3 ? 0f : ClassStat("herald.voice_draw"));
			if (_talking && num > 0f && Time.time >= _nextVoiceDraw && Game.InLevel())
			{
				_nextVoiceDraw = Time.time + 2f;
				Vector3 val = ((Component)local).transform.position;
				if (Synergies.Has(local, "chorus"))
				{
					Vector3 forward = ((Component)local).transform.forward;
					forward.y = 0f;
					NavMeshHit val2 = default(NavMeshHit);
					val = (NavMesh.SamplePosition(val + ((Vector3)(ref forward)).normalized * Mathf.Clamp(Synergies.V("chorus"), 0f, 12f), ref val2, 3f, -1) ? ((NavMeshHit)(ref val2)).position : val);
				}
				Net.SendClassAction(ClassHost.Act.Investigate, val, new float[1] { Mathf.Min(num, 30f) }, 0, usesCharge: false);
			}
			float num2 = Mathf.Max(0f, ClassStat("herald.inspire_gain")) * (flag ? 1f : 0.4f);
			if (Time.time >= _nextAudienceCheck)
			{
				_nextAudienceCheck = Time.time + 0.5f;
				float num3 = Mathf.Max(1f, ClassStat("herald.inspire_radius"));
				_audience = false;
				_whisperTalk = false;
				foreach (PlayerAvatar item in Game.Players())
				{
					if ((Object)(object)item == (Object)null || (Object)(object)item == (Object)(object)local || !Game.IsAlive(item))
					{
						continue;
					}
					Vector3 val3 = ((Component)item).transform.position - ((Component)local).transform.position;
					if (((Vector3)(ref val3)).sqrMagnitude > num3 * num3)
					{
						continue;
					}
					_audience = true;
					if (ClassStat("herald.alt_whisper") > 0f)
					{
						object obj2 = Game.Get<object>(item, "voiceChat", null);
						if (obj2 != null && Game.Get(obj2, "isTalking", fallback: false))
						{
							_whisperTalk = true;
						}
					}
				}
			}
			if (_talking && _audience)
			{
				_inspire += num2 * deltaTime;
			}
			else if (flag3 && _whisperTalk)
			{
				_inspire += Mathf.Max(0f, ClassStat("herald.inspire_gain")) * 0.5f * deltaTime;
			}
			else
			{
				float num4 = Mathf.Max(0f, ClassStat("herald.silent_cap"));
				float num5 = Mathf.Max(0f, ClassStat("herald.silent_gain"));
				if (num5 > 0f && _inspire < num4)
				{
					_inspire = Mathf.Min(num4, _inspire + num5 * deltaTime);
				}
				else
				{
					_inspire -= Mathf.Max(0.5f, ClassStat("herald.inspire_decay")) * deltaTime;
				}
			}
			_inspire = Mathf.Clamp(_inspire, 0f, 100f);
			if (_inspire >= 100f && !_inspireWasFull)
			{
				CEv("cls.herald");
			}
			_inspireWasFull = _inspire >= 100f;
			bool flag4 = (_inspire <= 0f && _lastInspireSent > 0f) || (_inspire >= 100f && _lastInspireSent < 100f);
			if (Time.unscaledTime >= _nextInspireSend && (Mathf.Abs(_inspire - _lastInspireSent) >= 2f || flag4))
			{
				_nextInspireSend = Time.unscaledTime + ((PlayerScaling.RoomPlayers() > 10) ? 0.5f : 0.3f);
				_lastInspireSent = _inspire;
				_auraSentNonZero = true;
				Net.SendAura(LocalAura());
			}
		}

		private void RallyCry(Vector3 pos, float speedPct, float duration, float radius, bool copied, float durMult)
		{
			//IL_006d: Unknown result type (might be due to invalid IL or missing references)
			float num = ((copied || CurrentId != "herald") ? 50f : _inspire);
			float num2 = 0.5f + 0.5f * num / 100f;
			float num3 = speedPct * num2;
			float num4 = num3 * 1.25f;
			float num5 = num3 * 0.83f;
			float num6 = 0f;
			float num7 = (copied ? 0f : ClassStat("herald.rally_taunt"));
			Net.SendClassAction(ClassHost.Act.Rally, pos, new float[7] { radius, num3, num4, num5, duration, num6, num7 });
			if (!copied && !(CurrentId != "herald"))
			{
				float num8 = ClassStat("herald.full_refund");
				if (num8 > 0f && _inspire >= 80f)
				{
					_rallyRefund = num8;
				}
				else
				{
					_inspire *= 0.5f;
				}
			}
		}

		public ClassDef? MimicCopy()
		{
			string text = _copies[_copySlot];
			if (!(text == ""))
			{
				return Plugin.Db.Get(text);
			}
			return null;
		}

		private void TickMimic(PlayerAvatar local)
		{
			//IL_0100: Unknown result type (might be due to invalid IL or missing references)
			//IL_010b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0110: Unknown result type (might be due to invalid IL or missing references)
			//IL_0115: Unknown result type (might be due to invalid IL or missing references)
			if (!Game.IsAlive(local))
			{
				_copyCandidate = -1;
				_copyTimer = 0f;
			}
			else
			{
				if (Time.time < _nextCopyLook)
				{
					return;
				}
				float num = ((_lastCopyLook < 0f) ? 0.25f : Mathf.Min(1f, Time.time - _lastCopyLook));
				_lastCopyLook = Time.time;
				_nextCopyLook = Time.time + 0.25f;
				float num2 = Mathf.Max(1f, ClassStat("mimic.copy_range"));
				float num3 = Mathf.Max(0f, ClassStat("mimic.copy_time"));
				PlayerAvatar val = null;
				float num4 = num2 * num2;
				foreach (PlayerAvatar item in Game.Players())
				{
					if ((Object)(object)item == (Object)null || (Object)(object)item == (Object)(object)local || !Game.IsAlive(item))
					{
						continue;
					}
					string text = ClassStats.ClassOf(item);
					if (!(text == "") && !(text == "mimic"))
					{
						Vector3 val2 = ((Component)item).transform.position - ((Component)local).transform.position;
						float sqrMagnitude = ((Vector3)(ref val2)).sqrMagnitude;
						if (sqrMagnitude < num4)
						{
							num4 = sqrMagnitude;
							val = item;
						}
					}
				}
				if ((Object)(object)val == (Object)null)
				{
					_copyCandidate = -1;
					_copyTimer = 0f;
					return;
				}
				int num5 = Game.ActorNumber(val);
				if (num5 != _copyCandidate)
				{
					_copyCandidate = num5;
					_copyTimer = 0f;
				}
				_copyTimer += num;
				string text2 = ClassStats.ClassOf(val);
				if (!(_copyTimer < num3) && !(text2 == _copies[_copySlot]))
				{
					LearnCopy(text2, Game.Get(val, "playerName", "a teammate"));
				}
			}
		}

		private void LearnCopy(string classId, string from)
		{
			//IL_022f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0290: Unknown result type (might be due to invalid IL or missing references)
			ClassDef classDef = Plugin.Db.Get(classId);
			if (classDef == null)
			{
				return;
			}
			bool flag = ClassStat("mimic.dual") > 0f;
			if (flag && _copies[1 - _copySlot] == classId)
			{
				return;
			}
			float num = ((_copies[_copySlot] != "") ? CooldownSeconds() : 0f);
			bool flag2 = ClassStat("mimic.split") > 0f;
			if (flag && _copies[_copySlot] != "")
			{
				int num2 = 1 - _copySlot;
				(int, float) tuple = _slotState[num2];
				_copies[num2] = _copies[_copySlot];
				_copyFrom[num2] = _copyFrom[_copySlot];
				_slotState[num2] = (charges: _charges, cdEnd: _cooldownEnd);
				if (flag2 && (tuple.Item1 < _charges || (tuple.Item1 == _charges && tuple.Item2 > _cooldownEnd)))
				{
					(_charges, _cooldownEnd) = tuple;
				}
			}
			_copies[_copySlot] = classId;
			_copyFrom[_copySlot] = from;
			if (num > 0f && _cooldownEnd > Time.time)
			{
				float num3 = CooldownSeconds();
				_cooldownEnd = Time.time + (_cooldownEnd - Time.time) * num3 / num;
			}
			float num4 = Mathf.Clamp(ClassStat("mimic.fresh"), 0f, 100f);
			if (_charges <= 0 && _cooldownEnd > Time.time && num4 > 0f && !_freshUsed)
			{
				_cooldownEnd -= (_cooldownEnd - Time.time) * num4 / 100f;
				_freshUsed = true;
			}
			Toast("Copied " + classDef.active.name + " from " + from, ParseColor(classDef.color));
			Notify(PopupKind.Other, "Copied: " + classDef.active.name + " (" + from + ")", ParseColor(Current?.color ?? "#FFFFFF"), "mimic");
			_nextCombatSend = 0f;
		}

		private void MimicSwap()
		{
			//IL_0048: Unknown result type (might be due to invalid IL or missing references)
			//IL_012e: Unknown result type (might be due to invalid IL or missing references)
			if (CurrentId != "mimic" || ClassStat("mimic.dual") <= 0f)
			{
				return;
			}
			int num = 1 - _copySlot;
			if (_copies[num] == "")
			{
				Toast("No second copy yet", Color.gray);
				return;
			}
			float num2 = CooldownSeconds();
			if (ClassStat("mimic.split") > 0f)
			{
				(int, float) tuple = (_charges, _cooldownEnd);
				(_charges, _cooldownEnd) = _slotState[num];
				_slotState[_copySlot] = tuple;
				_copySlot = num;
			}
			else
			{
				_copySlot = num;
				float num3 = CooldownSeconds();
				if (_cooldownEnd > Time.time && num2 > 0f)
				{
					_cooldownEnd = Time.time + (_cooldownEnd - Time.time) * num3 / num2;
				}
			}
			ClassDef classDef = MimicCopy();
			if (classDef != null)
			{
				Toast("Ready: " + classDef.active.name, ParseColor(classDef.color));
			}
			MenuSound(UiSound.Tick);
		}

		private void MimicAfterUse()
		{
			float num = Mathf.Clamp(ClassStat("mimic.refund"), 0f, 60f);
			if (num > 0f && _cooldownEnd > Time.time)
			{
				_cooldownEnd -= CooldownSeconds() * num / 100f;
			}
			float num2 = Mathf.Clamp(ClassStat("mimic.cross"), 0f, 60f);
			if (num2 > 0f && ClassStat("mimic.split") > 0f)
			{
				int num3 = 1 - _copySlot;
				(int, float) tuple = _slotState[num3];
				if (tuple.Item2 > Time.time)
				{
					_slotState[num3] = (charges: tuple.Item1, cdEnd: tuple.Item2 - (tuple.Item2 - Time.time) * num2 / 100f);
				}
			}
		}

		private bool HoldingHead()
		{
			return (Object)(object)Game.HeldComponent<PlayerDeathHead>() != (Object)null;
		}

		private void TickUndertaker(PlayerAvatar local)
		{
			if (HoldingHead())
			{
				float num = ClassStat("undertaker.head_speed");
				if (num > 0f)
				{
					_stats.AddDyn(Stat.MoveSpeed, num);
					_stats.AddDyn(Stat.SprintSpeed, num);
				}
				float num2 = ClassStat("undertaker.head_grip");
				if (num2 > 0f)
				{
					_stats.AddDyn(Stat.GrabStrength, num2);
				}
			}
		}

		private void ApplyPendingHealth(PlayerAvatar local)
		{
			PlayerHealth playerHealth = local.playerHealth;
			if ((Object)(object)playerHealth == (Object)null || Game.Get(local, "isDisabled", fallback: false))
			{
				if (Time.time - _pendingHealthAt > 5f)
				{
					_pendingHealthPct = 0f;
				}
				return;
			}
			int num = Game.MaxHealth(playerHealth);
			int num2 = Game.Health(playerHealth);
			int num3 = Mathf.RoundToInt((float)num * Mathf.Clamp(_pendingHealthPct, 0f, 100f) / 100f);
			_pendingHealthPct = 0f;
			if (num3 > num2)
			{
				playerHealth.Heal(num3 - num2, false);
			}
		}

		private bool TryBet(float power)
		{
			//IL_0015: Unknown result type (might be due to invalid IL or missing references)
			//IL_004a: Unknown result type (might be due to invalid IL or missing references)
			ValuableObject val = Game.HeldValuable();
			if ((Object)(object)val == (Object)null)
			{
				Toast("Hold a valuable to bet on it", Color.gray);
				MenuSound(UiSound.Error);
				return false;
			}
			if (!BetAllowedLocally())
			{
				return false;
			}
			int num = ClassHost.ViewId((Component?)(object)val);
			if (num == 0)
			{
				return false;
			}
			Net.SendClassAction(ClassHost.Act.Bet, ((Component)val).transform.position, Array.Empty<float>(), num);
			return true;
		}

		private void EnsureGambleRoll()
		{
			//IL_0280: Unknown result type (might be due to invalid IL or missing references)
			//IL_0285: Unknown result type (might be due to invalid IL or missing references)
			//IL_0295: Unknown result type (might be due to invalid IL or missing references)
			//IL_02e1: Unknown result type (might be due to invalid IL or missing references)
			if (CurrentId != "gambler" || !Game.InLevel())
			{
				return;
			}
			RunSave data = _store.Data;
			string text = RunInfo.Key + ":" + RunInfo.LevelIndex;
			if (data.gambleKey == text)
			{
				return;
			}
			RpgData rpg = Plugin.Rpg;
			if (rpg.blessings.Length == 0 || rpg.curses.Length == 0)
			{
				return;
			}
			Random random = new Random(StableHash(text + ":" + Game.SteamId(Game.LocalPlayer())));
			data.gambleKey = text;
			data.gambleBless.Clear();
			int num = random.Next(rpg.blessings.Length);
			data.gambleBless.Add(rpg.blessings[num].id);
			if (random.NextDouble() * 100.0 < (double)ClassStat("gambler.extra_bless") && rpg.blessings.Length > 1)
			{
				int num2 = (num + 1 + random.Next(rpg.blessings.Length - 1)) % rpg.blessings.Length;
				data.gambleBless.Add(rpg.blessings[num2].id);
			}
			data.gambleCurse = ((random.NextDouble() * 100.0 < (double)ClassStat("gambler.no_curse")) ? "" : rpg.curses[random.Next(rpg.curses.Length)].id);
			_store.MarkDirty();
			_statsDirty = true;
			List<string> list = new List<string>();
			foreach (string item in data.gambleBless)
			{
				PerkDef perkDef = Find(rpg.blessings, item);
				if (perkDef != null)
				{
					list.Add("Blessing: " + perkDef.name + " (" + perkDef.desc + ")");
				}
			}
			PerkDef perkDef2 = Find(rpg.curses, data.gambleCurse);
			list.Add((perkDef2 != null) ? ("Curse: " + perkDef2.name + " (" + perkDef2.desc + ")") : "No curse this level!");
			Color val = ParseColor(Current?.color ?? "#FFFFFF");
			Notify(PopupKind.Perk, string.Join("  |  ", list), val, "gamble");
			Toast("Fortune's Wheel: " + string.Join(", ", list.ConvertAll((string l) => l.Split('(')[0].Trim())), val, 5f);
		}

		private static int StableHash(string s)
		{
			int num = -2128831035;
			foreach (char c in s)
			{
				num = (num ^ c) * 16777619;
			}
			return num;
		}

		private static PerkDef? Find(PerkDef[] list, string id)
		{
			foreach (PerkDef perkDef in list)
			{
				if (perkDef.id == id)
				{
					return perkDef;
				}
			}
			return null;
		}

		private void ApplyClassExtras()
		{
			string currentId = CurrentId;
			if (currentId == "gambler")
			{
				RunSave data = _store.Data;
				if (data.gambleKey == RunInfo.Key + ":" + RunInfo.LevelIndex)
				{
					float mult = 1f + Mathf.Max(0f, ClassStat("gambler.bless_power")) / 100f;
					float mult2 = Mathf.Max(0f, 1f - Mathf.Max(0f, ClassStat("gambler.curse_soft")) / 100f);
					foreach (string item in data.gambleBless)
					{
						PerkDef perkDef = Find(Plugin.Rpg.blessings, item);
						if (perkDef != null)
						{
							_stats.AddPermEffects(perkDef.effects, mult);
						}
					}
					PerkDef perkDef2 = Find(Plugin.Rpg.curses, data.gambleCurse);
					if (perkDef2 != null)
					{
						_stats.AddPermEffects(perkDef2.effects, mult2);
					}
				}
				_stats.AddPerm(Stat.GearFind, ClassStat("gambler.gear_find"));
			}
			if (currentId == "quartermaster")
			{
				_stats.AddPerm(Stat.ScrapBonus, ClassStat("quartermaster.scrap"));
			}
			ApplyThirdWaveExtras(currentId);
		}

		private void OnLevelStartClasses()
		{
			ClearAbilityLimits();
			_buffs.Clear();
			_selfDyn.Clear();
			_inspire = 0f;
			_pactEnd = 0f;
			_copies[0] = (_copies[1] = "");
			_copyFrom[0] = (_copyFrom[1] = "");
			_copySlot = 0;
			_slotState[0] = (_slotState[1] = (charges: 1, cdEnd: 0f));
			_copyCandidate = -1;
			_copyTimer = 0f;
			_bloodAcc = 0f;
			_drainAcc = 0f;
			_refundAfterUse = false;
			ClassFx.HideAll();
			ThirdWaveReset();
			_gambleCheckAt = Time.time + 3f;
			if (!_cartFollowOn)
			{
				SendCartFollow();
			}
		}

		private void TickBloodbound(PlayerAvatar local)
		{
			PlayerHealth playerHealth = local.playerHealth;
			float num = ClassStat("bloodbound.hit_power");
			if ((Object)(object)playerHealth != (Object)null && (float)Game.Health(playerHealth) < (float)Game.MaxHealth(playerHealth) * 0.4f)
			{
				num += ClassStat("bloodbound.low_power");
			}
			_stats.AddDyn(Stat.WeaponDamage, num);
			_stats.AddDyn(Stat.ThrowStrength, ClassStat("bloodbound.throw_power"));
			float num2 = _stats.Dyn(Stat.WeaponDamage);
			if (Mathf.Abs(num2 - _lastBloodWeapon) > 0.5f)
			{
				_lastBloodWeapon = num2;
				_nextCombatSend = 0f;
			}
			TickPactDrain(local);
		}

		private void TickPactDrain(PlayerAvatar local)
		{
			if (_pactEnd <= 0f)
			{
				return;
			}
			PlayerHealth playerHealth = local.playerHealth;
			if (Time.time < _pactEnd && (Object)(object)playerHealth != (Object)null)
			{
				_drainAcc += _pactDrain * Time.deltaTime;
				if (_drainAcc >= 1f)
				{
					int num = Mathf.FloorToInt(_drainAcc);
					_drainAcc -= num;
					SpendHealth(num);
				}
			}
			else
			{
				_drainAcc = 0f;
				_pactEnd = 0f;
			}
		}

		private void SpendHealth(float amount)
		{
			PlayerAvatar val = Game.LocalPlayer();
			PlayerHealth val2 = (((Object)(object)val != (Object)null) ? val.playerHealth : null);
			if ((Object)(object)val2 == (Object)null || (Object)(object)val == (Object)null || !Game.IsAlive(val))
			{
				return;
			}
			int num = Game.Health(val2);
			_bloodAcc = Mathf.Clamp(_bloodAcc + amount, -50f, 50f);
			if (_bloodAcc <= -1f)
			{
				int num2 = Mathf.FloorToInt(0f - _bloodAcc);
				_bloodAcc += num2;
				val2.Heal(num2, false);
				if (CurrentId == "bloodbound")
				{
					CEv("cls.bloodbound", num2);
				}
			}
			else
			{
				if (_bloodAcc < 1f)
				{
					return;
				}
				int num3 = Mathf.FloorToInt(_bloodAcc);
				_bloodAcc -= num3;
				int num4 = Mathf.Min(num3, num - 1);
				if (num4 <= 0)
				{
					return;
				}
				int num5 = num - num4;
				try
				{
					Game.Set(val2, "health", num5);
					StatsManager instance = StatsManager.instance;
					if (instance != null)
					{
						instance.SetPlayerHealth(Game.SteamId(val), num5, false);
					}
					PhotonView val3 = Game.Get<PhotonView>(val2, "photonView", null);
					if (Game.IsMultiplayer() && (Object)(object)val3 != (Object)null)
					{
						val3.RPC("UpdateHealthRPC", (RpcTarget)1, new object[3]
						{
							num5,
							Game.MaxHealth(val2),
							false
						});
					}
				}
				catch (Exception ex)
				{
					Game.WarnOnce("Blood Price failed: " + ex.GetBaseException().Message);
				}
				_lastSeenHp = num5;
			}
		}

		private void OnKillNear(float dist)
		{
			if (!(CurrentId != "bloodbound") && !(dist > Plugin.Cfg.KillShareRadius.Value + Mathf.Max(0f, ClassStat("bloodbound.feed_range"))))
			{
				PlayerAvatar val = Game.LocalPlayer();
				PlayerHealth val2 = (((Object)(object)val != (Object)null) ? val.playerHealth : null);
				int num = Mathf.RoundToInt(Mathf.Clamp(ClassStat("bloodbound.feed"), 0f, 60f));
				if ((Object)(object)val2 != (Object)null && num > 0)
				{
					Game.HealSelf(val2, num);
					NoteHeal(num, HealKind.Instant, "Feed");
				}
				float num2 = ClassStat("bloodbound.feed_cd");
				if (num2 > 0f && _cooldownEnd > 0f)
				{
					_cooldownEnd -= num2;
				}
				float num3 = ClassStat("bloodbound.feast_speed");
				if (num3 > 0f)
				{
					AddSelfBuff(new AllyBuff
					{
						Speed = num3,
						Duration = 5f,
						Source = "Sanguine Feast"
					});
				}
			}
		}

		public void OnClassNotice(Notice kind, float value, string text)
		{
			//IL_0052: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ef: Unknown result type (might be due to invalid IL or missing references)
			switch (kind)
			{
			case Notice.Text:
				if (text != "")
				{
					Toast(text, ParseColor(Current?.color ?? "#FFFFFF"));
				}
				break;
			case Notice.BloodCost:
				if (CurrentId == "bloodbound")
				{
					SpendHealth(value);
				}
				break;
			case Notice.Slip:
				if (value > 0f)
				{
					AddSelfBuff(new AllyBuff
					{
						Speed = Mathf.Min(value, 40f),
						Duration = 3f,
						Source = ""
					});
				}
				break;
			case Notice.Popup:
				if (text != "")
				{
					Notify(PopupKind.Other, text, ParseColor(Current?.color ?? "#FFFFFF"));
				}
				break;
			case Notice.AbilityState:
				OnAbilityState(text);
				break;
			case Notice.CartState:
				_cartState = text;
				_nextHudBuild = 0f;
				break;
			case Notice.RefundAbility:
				_specialistPending = false;
				if (_inActive)
				{
					_refundAfterUse = true;
				}
				else
				{
					RefundCharge();
				}
				break;
			}
		}

		private void RefundCharge()
		{
			_charges = Mathf.Min(MaxCharges, _charges + 1);
			if (_charges >= MaxCharges)
			{
				_cooldownEnd = 0f;
			}
		}

		public void ShowFx(ClassHost.Fx fx, Vector3 pos, float radius, float seconds)
		{
			//IL_0025: Unknown result type (might be due to invalid IL or missing references)
			//IL_003d: Unknown result type (might be due to invalid IL or missing references)
			//IL_004d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0065: Unknown result type (might be due to invalid IL or missing references)
			//IL_0075: Unknown result type (might be due to invalid IL or missing references)
			//IL_008d: Unknown result type (might be due to invalid IL or missing references)
			//IL_009d: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b8: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c8: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e4: Unknown result type (might be due to invalid IL or missing references)
			//IL_00f4: Unknown result type (might be due to invalid IL or missing references)