Decompiled source of DefenseBudget v1.1.3

DefenseBudget.dll

Decompiled 2 weeks ago
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Globalization;
using System.IO;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.Versioning;
using BepInEx;
using BepInEx.Configuration;
using BepInEx.Logging;
using DefenseBudget.Artifacts;
using DefenseBudget.Items;
using DefenseBudget.Net;
using IL.RoR2;
using Microsoft.CodeAnalysis;
using Mono.Cecil;
using Mono.Cecil.Cil;
using MonoMod.Cil;
using MonoMod.RuntimeDetour;
using On.RoR2;
using On.RoR2.UI;
using R2API;
using R2API.Networking;
using R2API.Networking.Interfaces;
using RoR2;
using RoR2.ExpansionManagement;
using RoR2.Orbs;
using RoR2.UI;
using UnityEngine;
using UnityEngine.AddressableAssets;
using UnityEngine.Networking;
using UnityEngine.Rendering;
using UnityEngine.UI;

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

		public RefSafetyRulesAttribute(int P_0)
		{
			Version = P_0;
		}
	}
}
namespace DefenseBudget
{
	internal static class Assets
	{
		private static GameObject prefabHolder;

		internal static Transform PrefabHolder
		{
			get
			{
				//IL_0018: Unknown result type (might be due to invalid IL or missing references)
				//IL_0022: Expected O, but got Unknown
				if (!Object.op_Implicit((Object)(object)prefabHolder))
				{
					prefabHolder = new GameObject("DefenseBudgetPrefabHolder");
					Object.DontDestroyOnLoad((Object)(object)prefabHolder);
					prefabHolder.SetActive(false);
				}
				return prefabHolder.transform;
			}
		}

		internal static void SetItemTier(ItemDef def, ItemTier tier)
		{
			//IL_0007: Unknown result type (might be due to invalid IL or missing references)
			//IL_0008: Unknown result type (might be due to invalid IL or missing references)
			//IL_0038: Unknown result type (might be due to invalid IL or missing references)
			typeof(ItemDef).GetField("deprecatedTier", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic)?.SetValue(def, tier);
			RoR2Application.onLoad = (Action)Delegate.Combine(RoR2Application.onLoad, (Action)delegate
			{
				//IL_0002: Unknown result type (might be due to invalid IL or missing references)
				ItemTierDef itemTierDef = ItemTierCatalog.GetItemTierDef(tier);
				if (Object.op_Implicit((Object)(object)itemTierDef))
				{
					typeof(ItemDef).GetField("_itemTierDef", BindingFlags.Instance | BindingFlags.NonPublic)?.SetValue(def, itemTierDef);
				}
			});
		}

		internal static ItemDef CreateItemDef(string name, string tokenBase, ItemTier tier, Sprite icon, GameObject model, ItemTag[] tags, bool canRemove = true)
		{
			//IL_007a: Unknown result type (might be due to invalid IL or missing references)
			ItemDef val = ScriptableObject.CreateInstance<ItemDef>();
			((Object)val).name = name;
			val.nameToken = tokenBase + "_NAME";
			val.pickupToken = tokenBase + "_PICKUP";
			val.descriptionToken = tokenBase + "_DESC";
			val.loreToken = tokenBase + "_LORE";
			val.canRemove = canRemove;
			val.hidden = false;
			val.tags = tags;
			val.pickupIconSprite = icon;
			val.pickupModelPrefab = model;
			SetItemTier(val, tier);
			return val;
		}

		private static byte[] ReadResource(string resourceName)
		{
			using Stream stream = Assembly.GetExecutingAssembly().GetManifestResourceStream(resourceName);
			if (stream == null)
			{
				return null;
			}
			using MemoryStream memoryStream = new MemoryStream();
			stream.CopyTo(memoryStream);
			return memoryStream.ToArray();
		}

		internal static Texture2D LoadRawTexture(string resourceName, int size)
		{
			//IL_0029: Unknown result type (might be due to invalid IL or missing references)
			//IL_002e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0037: Expected O, but got Unknown
			try
			{
				byte[] array = ReadResource(resourceName);
				if (array == null || array.Length != size * size * 4)
				{
					return null;
				}
				Texture2D val = new Texture2D(size, size, (TextureFormat)4, false)
				{
					wrapMode = (TextureWrapMode)1
				};
				val.LoadRawTextureData(array);
				val.Apply();
				return val;
			}
			catch (Exception arg)
			{
				Log.Error($"Failed to load texture '{resourceName}': {arg}");
				return null;
			}
		}

		internal static Sprite LoadSprite(string resourceName, int size)
		{
			//IL_0023: Unknown result type (might be due to invalid IL or missing references)
			//IL_0032: Unknown result type (might be due to invalid IL or missing references)
			Texture2D val = LoadRawTexture(resourceName, size);
			return Object.op_Implicit((Object)(object)val) ? Sprite.Create(val, new Rect(0f, 0f, (float)size, (float)size), new Vector2(0.5f, 0.5f)) : null;
		}

		internal static Material CreatePickupMaterial(Color color, Texture2D mainTexture, Color emission)
		{
			//IL_0006: Unknown result type (might be due to invalid IL or missing references)
			//IL_000b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0046: Unknown result type (might be due to invalid IL or missing references)
			//IL_0059: Expected O, but got Unknown
			//IL_0053: Unknown result type (might be due to invalid IL or missing references)
			//IL_00f3: Unknown result type (might be due to invalid IL or missing references)
			//IL_0113: Unknown result type (might be due to invalid IL or missing references)
			GameObject val = Addressables.LoadAssetAsync<GameObject>((object)"RoR2/Base/LunarCoin/PickupLunarCoin.prefab").WaitForCompletion();
			Renderer val2 = (Object.op_Implicit((Object)(object)val) ? val.GetComponentInChildren<Renderer>(true) : null);
			Material val3 = ((Object.op_Implicit((Object)(object)val2) && Object.op_Implicit((Object)(object)val2.sharedMaterial)) ? new Material(val2.sharedMaterial) : new Material(Shader.Find("Standard")));
			string[] array = new string[5] { "_MainTex", "_NormalTex", "_BumpMap", "_EmTex", "_EmissionMap" };
			foreach (string text in array)
			{
				if (val3.HasProperty(text))
				{
					val3.SetTexture(text, (Texture)(object)((!(text == "_MainTex")) ? null : (Object.op_Implicit((Object)(object)mainTexture) ? mainTexture : Texture2D.whiteTexture)));
				}
			}
			if (val3.HasProperty("_Color"))
			{
				val3.color = color;
			}
			if (val3.HasProperty("_EmColor"))
			{
				val3.SetColor("_EmColor", emission);
			}
			return val3;
		}

		internal static Mesh LoadObjMesh(string resourceName)
		{
			//IL_023a: Unknown result type (might be due to invalid IL or missing references)
			//IL_023f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0248: Expected O, but got Unknown
			//IL_012f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0161: Unknown result type (might be due to invalid IL or missing references)
			//IL_01a2: Unknown result type (might be due to invalid IL or missing references)
			byte[] array = ReadResource(resourceName);
			if (array == null)
			{
				return null;
			}
			List<Vector3> positions = new List<Vector3>();
			List<Vector2> texCoords = new List<Vector2>();
			List<Vector3> objNormals = new List<Vector3>();
			Dictionary<(int, int, int), int> vertexMap = new Dictionary<(int, int, int), int>();
			List<Vector3> vertices = new List<Vector3>();
			List<Vector2> uvs = new List<Vector2>();
			List<Vector3> normals = new List<Vector3>();
			List<int> list = new List<int>();
			using (StreamReader streamReader = new StreamReader(new MemoryStream(array)))
			{
				string text;
				while ((text = streamReader.ReadLine()) != null)
				{
					string[] array2 = text.Split(new char[1] { ' ' }, StringSplitOptions.RemoveEmptyEntries);
					if (array2.Length == 0)
					{
						continue;
					}
					switch (array2[0])
					{
					case "v":
						positions.Add(new Vector3(0f - float.Parse(array2[1], CultureInfo.InvariantCulture), float.Parse(array2[2], CultureInfo.InvariantCulture), float.Parse(array2[3], CultureInfo.InvariantCulture)));
						break;
					case "vt":
						texCoords.Add(new Vector2(float.Parse(array2[1], CultureInfo.InvariantCulture), float.Parse(array2[2], CultureInfo.InvariantCulture)));
						break;
					case "vn":
						objNormals.Add(new Vector3(0f - float.Parse(array2[1], CultureInfo.InvariantCulture), float.Parse(array2[2], CultureInfo.InvariantCulture), float.Parse(array2[3], CultureInfo.InvariantCulture)));
						break;
					case "f":
					{
						int item = ResolveVertex(array2[1]);
						int item2 = ResolveVertex(array2[2]);
						for (int i = 3; i < array2.Length; i++)
						{
							int num = ResolveVertex(array2[i]);
							list.Add(item);
							list.Add(num);
							list.Add(item2);
							item2 = num;
						}
						break;
					}
					}
				}
			}
			Mesh val = new Mesh
			{
				indexFormat = (IndexFormat)1
			};
			val.SetVertices(vertices);
			val.SetUVs(0, uvs);
			val.SetNormals(normals);
			val.SetTriangles(list, 0);
			val.RecalculateBounds();
			return val;
			int ResolveVertex(string token)
			{
				//IL_00f0: 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_0105: Unknown result type (might be due to invalid IL or missing references)
				//IL_013a: Unknown result type (might be due to invalid IL or missing references)
				//IL_012a: Unknown result type (might be due to invalid IL or missing references)
				string[] array3 = token.Split('/');
				int num2 = int.Parse(array3[0], CultureInfo.InvariantCulture);
				int num3 = ((array3.Length > 1 && array3[1].Length > 0) ? int.Parse(array3[1], CultureInfo.InvariantCulture) : 0);
				int num4 = ((array3.Length > 2 && array3[2].Length > 0) ? int.Parse(array3[2], CultureInfo.InvariantCulture) : 0);
				if (num2 < 0)
				{
					num2 += positions.Count + 1;
				}
				if (num3 < 0)
				{
					num3 += texCoords.Count + 1;
				}
				if (num4 < 0)
				{
					num4 += objNormals.Count + 1;
				}
				(int, int, int) key = (num2, num3, num4);
				if (vertexMap.TryGetValue(key, out var value))
				{
					return value;
				}
				value = vertices.Count;
				vertices.Add(positions[num2 - 1]);
				uvs.Add((num3 > 0) ? texCoords[num3 - 1] : Vector2.zero);
				normals.Add((num4 > 0) ? objNormals[num4 - 1] : Vector3.up);
				vertexMap[key] = value;
				return value;
			}
		}

		internal static GameObject CreatePickupModel(string name, string objResource, string textureResource, int textureSize, float targetSize, Func<GameObject> fallback = null)
		{
			//IL_006a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0070: Expected O, but got Unknown
			//IL_0094: Unknown result type (might be due to invalid IL or missing references)
			//IL_009a: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b3: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b8: Unknown result type (might be due to invalid IL or missing references)
			//IL_00bc: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ca: Unknown result type (might be due to invalid IL or missing references)
			//IL_00cf: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d3: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e1: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e6: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ea: 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_0119: Unknown result type (might be due to invalid IL or missing references)
			try
			{
				Mesh val = LoadObjMesh(objResource);
				if ((Object)(object)val == (Object)null)
				{
					Log.Warning("Model resource '" + objResource + "' missing; using fallback model for " + name + ".");
					return (fallback != null) ? fallback() : MysteryModel();
				}
				Texture2D mainTexture = LoadRawTexture(textureResource, textureSize);
				GameObject val2 = new GameObject(name);
				val2.transform.SetParent(PrefabHolder);
				val2.AddComponent<MeshFilter>().mesh = val;
				((Renderer)val2.AddComponent<MeshRenderer>()).material = CreatePickupMaterial(Color.white, mainTexture, Color.black);
				float[] array = new float[3];
				Bounds bounds = val.bounds;
				array[0] = ((Bounds)(ref bounds)).size.x;
				bounds = val.bounds;
				array[1] = ((Bounds)(ref bounds)).size.y;
				bounds = val.bounds;
				array[2] = ((Bounds)(ref bounds)).size.z;
				float num = Mathf.Max(array);
				if (num > 0f)
				{
					val2.transform.localScale = Vector3.one * (targetSize / num);
				}
				return val2;
			}
			catch (Exception arg)
			{
				Log.Error($"Failed to build pickup model {name}: {arg}");
				return (fallback != null) ? fallback() : MysteryModel();
			}
		}

		internal static GameObject MysteryModel()
		{
			//IL_0006: Unknown result type (might be due to invalid IL or missing references)
			//IL_000b: Unknown result type (might be due to invalid IL or missing references)
			return Addressables.LoadAssetAsync<GameObject>((object)"RoR2/Base/Mystery/PickupMystery.prefab").WaitForCompletion();
		}

		internal static GameObject CreateGlyphModel(string name, string[] glyph, Color color, float cellSize, float depth)
		{
			//IL_0003: Unknown result type (might be due to invalid IL or missing references)
			//IL_0009: Expected O, but got Unknown
			//IL_0035: Unknown result type (might be due to invalid IL or missing references)
			//IL_0037: Unknown result type (might be due to invalid IL or missing references)
			//IL_003d: Unknown result type (might be due to invalid IL or missing references)
			try
			{
				GameObject val = new GameObject(name);
				val.transform.SetParent(PrefabHolder);
				val.AddComponent<MeshFilter>().mesh = BuildGlyphMesh(glyph, cellSize, depth);
				((Renderer)val.AddComponent<MeshRenderer>()).material = CreatePickupMaterial(color, null, color * 0.4f);
				return val;
			}
			catch (Exception ex)
			{
				Log.Warning("Falling back to mystery pickup model for " + name + ": " + ex.Message);
				return MysteryModel();
			}
		}

		private static Mesh BuildGlyphMesh(string[] glyph, float cellSize, float depth)
		{
			//IL_00ca: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d1: Expected O, but got Unknown
			//IL_0091: Unknown result type (might be due to invalid IL or missing references)
			//IL_0096: Unknown result type (might be due to invalid IL or missing references)
			List<Vector3> vertices = new List<Vector3>();
			List<Vector3> normals = new List<Vector3>();
			List<Vector2> list = new List<Vector2>();
			List<int> list2 = new List<int>();
			int num = glyph.Length;
			int length = glyph[0].Length;
			Vector3 center = default(Vector3);
			for (int i = 0; i < num; i++)
			{
				for (int j = 0; j < length; j++)
				{
					if (glyph[i][j] == 'X')
					{
						((Vector3)(ref center))..ctor(((float)j + 0.5f - (float)length / 2f) * cellSize, ((float)(num - 1 - i) + 0.5f - (float)num / 2f) * cellSize, 0f);
						AddCube(vertices, normals, list, list2, center, new Vector3(cellSize, cellSize, depth));
					}
				}
			}
			Mesh val = new Mesh();
			val.SetVertices(vertices);
			val.SetNormals(normals);
			val.SetUVs(0, list);
			val.SetTriangles(list2, 0);
			val.RecalculateBounds();
			return val;
		}

		private static void AddCube(List<Vector3> vertices, List<Vector3> normals, List<Vector2> uvs, List<int> triangles, Vector3 center, Vector3 size)
		{
			//IL_0001: Unknown result type (might be due to invalid IL or missing references)
			//IL_0008: Unknown result type (might be due to invalid IL or missing references)
			//IL_000d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0016: Unknown result type (might be due to invalid IL or missing references)
			//IL_001b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0022: Unknown result type (might be due to invalid IL or missing references)
			//IL_0027: Unknown result type (might be due to invalid IL or missing references)
			//IL_002e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0033: Unknown result type (might be due to invalid IL or missing references)
			//IL_003a: Unknown result type (might be due to invalid IL or missing references)
			//IL_003f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0046: Unknown result type (might be due to invalid IL or missing references)
			//IL_004b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0052: Unknown result type (might be due to invalid IL or missing references)
			//IL_0057: Unknown result type (might be due to invalid IL or missing references)
			//IL_0069: 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_0071: 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_009b: Unknown result type (might be due to invalid IL or missing references)
			//IL_007f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0081: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a0: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a2: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a4: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a6: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ab: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ad: Unknown result type (might be due to invalid IL or missing references)
			//IL_00af: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b1: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b2: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b7: Unknown result type (might be due to invalid IL or missing references)
			//IL_00bc: Unknown result type (might be due to invalid IL or missing references)
			//IL_00be: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c0: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c1: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c6: 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_00ca: Unknown result type (might be due to invalid IL or missing references)
			//IL_00cb: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d0: Unknown result type (might be due to invalid IL or missing references)
			//IL_00db: Unknown result type (might be due to invalid IL or missing references)
			//IL_00dd: Unknown result type (might be due to invalid IL or missing references)
			//IL_00df: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e4: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e6: Unknown result type (might be due to invalid IL or missing references)
			//IL_00f2: 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)
			//IL_00f6: Unknown result type (might be due to invalid IL or missing references)
			//IL_00fb: Unknown result type (might be due to invalid IL or missing references)
			//IL_00fd: Unknown result type (might be due to invalid IL or missing references)
			//IL_0109: 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_010d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0112: Unknown result type (might be due to invalid IL or missing references)
			//IL_0114: Unknown result type (might be due to invalid IL or missing references)
			//IL_0120: Unknown result type (might be due to invalid IL or missing references)
			//IL_0122: Unknown result type (might be due to invalid IL or missing references)
			//IL_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_012b: Unknown result type (might be due to invalid IL or missing references)
			//IL_008d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0092: Unknown result type (might be due to invalid IL or missing references)
			//IL_0094: Unknown result type (might be due to invalid IL or missing references)
			//IL_013d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0162: 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_018e: Unknown result type (might be due to invalid IL or missing references)
			//IL_01a4: Unknown result type (might be due to invalid IL or missing references)
			Vector3 val = size * 0.5f;
			Vector3[] array = (Vector3[])(object)new Vector3[6]
			{
				Vector3.right,
				Vector3.left,
				Vector3.up,
				Vector3.down,
				Vector3.forward,
				Vector3.back
			};
			Vector3[] array2 = array;
			foreach (Vector3 val2 in array2)
			{
				Vector3 val3 = ((val2 == Vector3.up || val2 == Vector3.down) ? Vector3.right : Vector3.Cross(Vector3.up, val2));
				Vector3 val4 = Vector3.Cross(val2, val3);
				Vector3 val5 = center + Vector3.Scale(val2, val);
				Vector3 val6 = Vector3.Scale(val3, val);
				Vector3 val7 = Vector3.Scale(val4, val);
				int count = vertices.Count;
				vertices.Add(val5 - val6 - val7);
				vertices.Add(val5 - val6 + val7);
				vertices.Add(val5 + val6 + val7);
				vertices.Add(val5 + val6 - val7);
				for (int j = 0; j < 4; j++)
				{
					normals.Add(val2);
				}
				uvs.Add(new Vector2(0f, 0f));
				uvs.Add(new Vector2(0f, 1f));
				uvs.Add(new Vector2(1f, 1f));
				uvs.Add(new Vector2(1f, 0f));
				triangles.AddRange(new int[6]
				{
					count,
					count + 2,
					count + 1,
					count,
					count + 3,
					count + 2
				});
			}
		}
	}
	[BepInDependency(/*Could not decode attribute arguments.*/)]
	[BepInDependency(/*Could not decode attribute arguments.*/)]
	[BepInDependency(/*Could not decode attribute arguments.*/)]
	[BepInPlugin("Isaac_Cummings.DefenseBudget", "DefenseBudget", "1.1.3")]
	public class DefenseBudgetPlugin : BaseUnityPlugin
	{
		private class CostTracker : MonoBehaviour
		{
			public PurchaseInteraction purchaseInteraction;

			public float appliedMultiplier = 1f;

			public int settleTicks = 2;
		}

		private class DebtTracker : MonoBehaviour
		{
			public double debt;

			public bool wasDefaulted;
		}

		public const string PluginGUID = "Isaac_Cummings.DefenseBudget";

		public const string PluginAuthor = "Isaac_Cummings";

		public const string PluginName = "DefenseBudget";

		public const string PluginVersion = "1.1.3";

		private const float DamageTickInterval = 0.5f;

		private const float MultiplierTickInterval = 0.2f;

		public static ItemDef itemDef;

		public static BuffDef inDebtBuff;

		public static BuffDef defaultedBuff;

		public static ConfigEntry<float> CostIncreasePerStack;

		public static ConfigEntry<float> IncomeReductionPerStack;

		public static ConfigEntry<int> BaseDebtLimit;

		public static ConfigEntry<float> InterestRatePerSecond;

		public static ConfigEntry<float> DefaultDamagePerSecond;

		public static ConfigEntry<float> DeficitSpendingBonusPerStack;

		private static readonly List<CostTracker> costTrackers = new List<CostTracker>();

		private static bool applyingDefaultDamage;

		private float interestTimer;

		private float damageTimer;

		private float multiplierTimer;

		private static readonly string[] DollarGlyph = new string[7] { "..X..", ".XXXX", "X.X..", ".XXX.", "..X.X", "XXXX.", "..X.." };

		private static readonly Color DeficitColor = new Color(1f, 0.35f, 0.3f);

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

		private static Color moneyTextOriginalColor;

		private static bool moneyTextColorCached;

		internal static bool ApplyingDefaultDamage => applyingDefaultDamage;

		public void Awake()
		{
			//IL_0072: Unknown result type (might be due to invalid IL or missing references)
			//IL_007c: Expected O, but got Unknown
			//IL_0084: Unknown result type (might be due to invalid IL or missing references)
			//IL_008e: Expected O, but got Unknown
			//IL_0096: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a0: Expected O, but got Unknown
			//IL_00c9: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d3: Expected O, but got Unknown
			//IL_00db: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e5: Expected O, but got Unknown
			Log.Init(((BaseUnityPlugin)this).Logger);
			BindConfig();
			CreateItem();
			CreateBuffs();
			CreateLanguage();
			SavingsBond.Init(((BaseUnityPlugin)this).Config);
			AccountsReceivable.Init(((BaseUnityPlugin)this).Config);
			GoldenParachute.Init(((BaseUnityPlugin)this).Config);
			OvertimePay.Init(((BaseUnityPlugin)this).Config);
			ArtifactOfCommunism.Init(((BaseUnityPlugin)this).Config);
			DebtSync.Init();
			PurchaseInteraction.Awake += new hook_Awake(PurchaseInteraction_Awake);
			PurchaseInteraction.CanBeAffordedByInteractor += new hook_CanBeAffordedByInteractor(PurchaseInteraction_CanBeAffordedByInteractor);
			PurchaseInteraction.OnInteractionBegin += new hook_OnInteractionBegin(PurchaseInteraction_OnInteractionBegin);
			GiveMoneyCompat.Add(CharacterMaster_GiveMoney);
			HealthComponent.TakeDamage += new hook_TakeDamage(HealthComponent_TakeDamage);
			HUD.Update += new hook_Update(HUD_Update);
			Run.onRunStartGlobal += delegate
			{
				costTrackers.Clear();
			};
			Log.Info("DefenseBudget loaded.");
		}

		private void BindConfig()
		{
			CostIncreasePerStack = ((BaseUnityPlugin)this).Config.Bind<float>("DefenseBudget", "CostIncreasePerStack", 0f, "Additional gold-cost multiplier per stack across all players. 2.0 = +200% per stack (x3 with one stack). WARNING: chest prices are shared, so in multiplayer this inflates costs for everyone, including players without the item. Disabled by default in favor of IncomeReductionPerStack.");
			IncomeReductionPerStack = ((BaseUnityPlugin)this).Config.Bind<float>("DefenseBudget", "IncomeReductionPerStack", 0.25f, "Fraction of gold income lost per stack, multiplicative (0.25 = 75% income with one stack, 56% with two, 42% with three). Only affects the holder.");
			BaseDebtLimit = ((BaseUnityPlugin)this).Config.Bind<int>("DefenseBudget", "BaseDebtLimit", 75, "Debt limit per stack, in base gold. Scales with difficulty over time exactly like chest prices (a small chest is 25 base).");
			InterestRatePerSecond = ((BaseUnityPlugin)this).Config.Bind<float>("DefenseBudget", "InterestRatePerSecond", 0.01f, "While in debt, debt grows by this fraction of itself per second (minimum 1 gold/sec).");
			DefaultDamagePerSecond = ((BaseUnityPlugin)this).Config.Bind<float>("DefenseBudget", "DefaultDamagePerSecond", 0.02f, "Fraction of maximum health lost per second while debt exceeds the debt limit.");
			DeficitSpendingBonusPerStack = ((BaseUnityPlugin)this).Config.Bind<float>("DefenseBudget", "DeficitSpendingBonusPerStack", 0.15f, "Damage bonus per stack while in debt ('deficit spending'). Set to 0 to disable.");
		}

		private void CreateItem()
		{
			//IL_00f3: Unknown result type (might be due to invalid IL or missing references)
			//IL_00fd: Expected O, but got Unknown
			//IL_00f8: Unknown result type (might be due to invalid IL or missing references)
			//IL_0102: Expected O, but got Unknown
			itemDef = ScriptableObject.CreateInstance<ItemDef>();
			((Object)itemDef).name = "DefenseBudget";
			itemDef.nameToken = "DEFENSE_BUDGET_NAME";
			itemDef.pickupToken = "DEFENSE_BUDGET_PICKUP";
			itemDef.descriptionToken = "DEFENSE_BUDGET_DESC";
			itemDef.loreToken = "DEFENSE_BUDGET_LORE";
			Assets.SetItemTier(itemDef, (ItemTier)3);
			itemDef.canRemove = true;
			itemDef.hidden = false;
			itemDef.tags = (ItemTag[])(object)new ItemTag[2]
			{
				(ItemTag)3,
				(ItemTag)4
			};
			itemDef.pickupIconSprite = Assets.LoadSprite("DefenseBudget.icon_item.rgba", 128);
			itemDef.pickupModelPrefab = Assets.CreatePickupModel("PickupDefenseBudget", "DefenseBudget.models.dollar_sign.obj", "DefenseBudget.models.dollar_sign.rgba", 512, 0.8f, CreateGlyphModel);
			ItemAPI.Add(new CustomItem(itemDef, new ItemDisplayRuleDict((ItemDisplayRule[])null)));
		}

		private static GameObject CreateGlyphModel()
		{
			//IL_001a: Unknown result type (might be due to invalid IL or missing references)
			return Assets.CreateGlyphModel("PickupDefenseBudgetGlyph", DollarGlyph, new Color(1f, 0.78f, 0.25f), 0.12f, 0.18f);
		}

		private void CreateBuffs()
		{
			//IL_004c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0051: Unknown result type (might be due to invalid IL or missing references)
			//IL_0056: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b4: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b9: Unknown result type (might be due to invalid IL or missing references)
			//IL_00be: Unknown result type (might be due to invalid IL or missing references)
			Sprite iconSprite = Assets.LoadSprite("DefenseBudget.icon_buff.rgba", 128);
			inDebtBuff = ScriptableObject.CreateInstance<BuffDef>();
			((Object)inDebtBuff).name = "DefenseBudgetInDebt";
			inDebtBuff.iconSprite = iconSprite;
			inDebtBuff.buffColor = Color32.op_Implicit(new Color32(byte.MaxValue, (byte)210, (byte)70, byte.MaxValue));
			inDebtBuff.canStack = false;
			inDebtBuff.isDebuff = false;
			ContentAddition.AddBuffDef(inDebtBuff);
			defaultedBuff = ScriptableObject.CreateInstance<BuffDef>();
			((Object)defaultedBuff).name = "DefenseBudgetDefaulted";
			defaultedBuff.iconSprite = iconSprite;
			defaultedBuff.buffColor = Color32.op_Implicit(new Color32(byte.MaxValue, (byte)60, (byte)60, byte.MaxValue));
			defaultedBuff.canStack = false;
			defaultedBuff.isDebuff = false;
			ContentAddition.AddBuffDef(defaultedBuff);
		}

		private void CreateLanguage()
		{
			int num = Mathf.RoundToInt(CostIncreasePerStack.Value * 100f);
			int num2 = Mathf.RoundToInt(IncomeReductionPerStack.Value * 100f);
			float num3 = InterestRatePerSecond.Value * 100f;
			float num4 = DefaultDamagePerSecond.Value * 100f;
			int num5 = Mathf.RoundToInt(DeficitSpendingBonusPerStack.Value * 100f);
			LanguageAPI.Add("DEFENSE_BUDGET_NAME", "Defense Budget");
			LanguageAPI.Add("DEFENSE_BUDGET_PICKUP", "Spend gold you don't have... <style=cDeath>but earn far less.</style>");
			string text = "";
			if (num2 > 0)
			{
				text += $"<style=cDeath>Reduce gold income by {num2}%</style> <style=cStack>(stacks multiplicatively)</style>. ";
			}
			if (num > 0)
			{
				text += $"All <style=cIsUtility>gold purchases</style> cost <style=cDeath>+{num}% (+{num}% per stack)</style>. ";
			}
			text = text + "Gain a <style=cIsUtility>line of credit</style> that scales with difficulty <style=cStack>(+100% per stack)</style>, letting you purchase while in <style=cIsHealth>deficit</style>. " + $"While in deficit, all gold income <style=cIsUtility>repays the deficit first</style> and the deficit grows by <style=cDeath>{num3:0.#}% per second</style>";
			if (num5 > 0)
			{
				text += $", but you deal <style=cIsDamage>+{num5}% damage (+{num5}% per stack)</style>";
			}
			text += $". Exceeding your credit limit causes you to <style=cDeath>lose {num4:0.#}% of your maximum health per second</style> until the deficit is repaid below the limit.";
			LanguageAPI.Add("DEFENSE_BUDGET_DESC", text);
			LanguageAPI.Add("DEFENSE_BUDGET_LORE", "Order: Line-Item Appropriation \"Defense Budget\"\nTracking Number: 13***********\nEstimated Delivery: Fiscal Year 2056\nShipping Method: Priority\nShipping Address: Committee Chambers, Sub-Basement 4, [REDACTED]\n\nThe committee has reviewed your request for additional funding. The committee reminds you that the budget has tripled for nine consecutive cycles, and that the deficit ceiling is a polite fiction we maintain for the auditors.\n\nSpend it anyway. They always do.\n\nShould expenditures exceed the ceiling, interest will be collected in the only currency of guaranteed supply: you.");
		}

		private static int TotalPlayerStacks()
		{
			int num = 0;
			foreach (PlayerCharacterMasterController instance in PlayerCharacterMasterController.instances)
			{
				Inventory val = (Object.op_Implicit((Object)(object)instance.master) ? instance.master.inventory : null);
				if (Object.op_Implicit((Object)(object)val))
				{
					num += val.GetItemCount(itemDef);
				}
			}
			return num;
		}

		private static float CurrentCostMultiplier()
		{
			return 1f + CostIncreasePerStack.Value * (float)TotalPlayerStacks();
		}

		private void PurchaseInteraction_Awake(orig_Awake orig, PurchaseInteraction self)
		{
			//IL_0011: Unknown result type (might be due to invalid IL or missing references)
			//IL_0017: Invalid comparison between Unknown and I4
			orig.Invoke(self);
			if (NetworkServer.active && (int)self.costType == 1)
			{
				CostTracker costTracker = ((Component)self).gameObject.AddComponent<CostTracker>();
				costTracker.purchaseInteraction = self;
				costTrackers.Add(costTracker);
			}
		}

		private static void ApplyMultiplier(CostTracker tracker, float multiplier)
		{
			if (!Mathf.Approximately(tracker.appliedMultiplier, multiplier))
			{
				PurchaseInteraction purchaseInteraction = tracker.purchaseInteraction;
				if (purchaseInteraction.cost > 0 && purchaseInteraction.Networkcost > 0)
				{
					purchaseInteraction.Networkcost = Mathf.Max(1, Mathf.RoundToInt((float)purchaseInteraction.Networkcost * (multiplier / tracker.appliedMultiplier)));
				}
				tracker.appliedMultiplier = multiplier;
			}
		}

		private static void UpdateCostMultipliers()
		{
			float multiplier = CurrentCostMultiplier();
			for (int num = costTrackers.Count - 1; num >= 0; num--)
			{
				CostTracker costTracker = costTrackers[num];
				if (!Object.op_Implicit((Object)(object)costTracker) || !Object.op_Implicit((Object)(object)costTracker.purchaseInteraction))
				{
					costTrackers.RemoveAt(num);
					continue;
				}
				if (costTracker.settleTicks > 0)
				{
					costTracker.settleTicks--;
					if (costTracker.settleTicks > 0)
					{
						continue;
					}
				}
				ApplyMultiplier(costTracker, multiplier);
			}
		}

		private static DebtTracker GetDebt(CharacterMaster master)
		{
			return Object.op_Implicit((Object)(object)master) ? ((Component)master).GetComponent<DebtTracker>() : null;
		}

		private static DebtTracker GetOrCreateDebt(CharacterMaster master)
		{
			DebtTracker component = ((Component)master).GetComponent<DebtTracker>();
			return Object.op_Implicit((Object)(object)component) ? component : ((Component)master).gameObject.AddComponent<DebtTracker>();
		}

		private static int GetStacks(CharacterMaster master)
		{
			return (Object.op_Implicit((Object)(object)master) && Object.op_Implicit((Object)(object)master.inventory)) ? master.inventory.GetItemCount(itemDef) : 0;
		}

		private static double DebtLimit(CharacterMaster master)
		{
			int stacks = GetStacks(master);
			if (stacks <= 0 || !Object.op_Implicit((Object)(object)Run.instance))
			{
				return 0.0;
			}
			return (double)Run.instance.GetDifficultyScaledCost(BaseDebtLimit.Value) * (double)stacks;
		}

		private static CharacterMaster GetMaster(Interactor activator)
		{
			if (!Object.op_Implicit((Object)(object)activator))
			{
				return null;
			}
			CharacterBody component = ((Component)activator).GetComponent<CharacterBody>();
			return Object.op_Implicit((Object)(object)component) ? component.master : null;
		}

		private bool PurchaseInteraction_CanBeAffordedByInteractor(orig_CanBeAffordedByInteractor orig, PurchaseInteraction self, Interactor activator)
		{
			//IL_0019: Unknown result type (might be due to invalid IL or missing references)
			//IL_001f: Invalid comparison between Unknown and I4
			if (orig.Invoke(self, activator))
			{
				return true;
			}
			if ((int)self.costType != 1 || self.cost <= 0)
			{
				return false;
			}
			CharacterMaster master = GetMaster(activator);
			if (!Object.op_Implicit((Object)(object)master) || GetStacks(master) <= 0)
			{
				return false;
			}
			GetCreditState(master, out var debt, out var limit);
			double num = limit - debt;
			return num > 0.0 && (double)master.money + num >= (double)self.cost;
		}

		private static void GetCreditState(CharacterMaster master, out double debt, out double limit)
		{
			DebtView view;
			if (NetworkServer.active)
			{
				DebtTracker debt2 = GetDebt(master);
				debt = (((Object)(object)debt2 != (Object)null) ? debt2.debt : 0.0);
				limit = DebtLimit(master);
			}
			else if (DebtSync.TryGet(master, out view))
			{
				debt = view.debt;
				limit = view.limit;
			}
			else
			{
				debt = 0.0;
				limit = DebtLimit(master);
			}
		}

		private void PurchaseInteraction_OnInteractionBegin(orig_OnInteractionBegin orig, PurchaseInteraction self, Interactor activator)
		{
			//IL_0009: Unknown result type (might be due to invalid IL or missing references)
			//IL_000f: Invalid comparison between Unknown and I4
			if (NetworkServer.active && (int)self.costType == 1 && self.cost > 0)
			{
				CharacterMaster master = GetMaster(activator);
				if (Object.op_Implicit((Object)(object)master) && master.money < (uint)self.cost && GetStacks(master) > 0)
				{
					uint num = (uint)self.cost - master.money;
					DebtTracker orCreateDebt = GetOrCreateDebt(master);
					if (orCreateDebt.debt + (double)num <= DebtLimit(master) + 0.5)
					{
						orCreateDebt.debt += num;
						master.money = (uint)self.cost;
					}
				}
			}
			orig.Invoke(self, activator);
		}

		private static void CharacterMaster_GiveMoney(GiveMoneyCompat.Orig orig, CharacterMaster self, uint amount, bool bypassStatManager)
		{
			if (NetworkServer.active && amount != 0 && !applyingDefaultDamage && !bypassStatManager)
			{
				int stacks = GetStacks(self);
				if (stacks > 0 && IncomeReductionPerStack.Value > 0f)
				{
					amount = (uint)Math.Round((double)amount * Math.Pow(1.0 - (double)Mathf.Clamp01(IncomeReductionPerStack.Value), stacks));
				}
				DebtTracker debt = GetDebt(self);
				if ((Object)(object)debt != (Object)null && debt.debt > 0.0)
				{
					uint num = (uint)Math.Min(amount, Math.Ceiling(debt.debt));
					debt.debt = Math.Max(0.0, debt.debt - (double)num);
					amount -= num;
				}
			}
			orig(self, amount, bypassStatManager);
		}

		private void HealthComponent_TakeDamage(orig_TakeDamage orig, HealthComponent self, DamageInfo damageInfo)
		{
			if (NetworkServer.active && DeficitSpendingBonusPerStack.Value > 0f && damageInfo != null && Object.op_Implicit((Object)(object)damageInfo.attacker))
			{
				CharacterBody component = damageInfo.attacker.GetComponent<CharacterBody>();
				CharacterMaster val = (Object.op_Implicit((Object)(object)component) ? component.master : null);
				if (Object.op_Implicit((Object)(object)val))
				{
					int stacks = GetStacks(val);
					if (stacks > 0)
					{
						DebtTracker debt = GetDebt(val);
						if ((Object)(object)debt != (Object)null && debt.debt > 0.0)
						{
							damageInfo.damage *= 1f + DeficitSpendingBonusPerStack.Value * (float)stacks;
						}
					}
				}
			}
			orig.Invoke(self, damageInfo);
		}

		private void HUD_Update(orig_Update orig, HUD self)
		{
			//IL_0046: Unknown result type (might be due to invalid IL or missing references)
			//IL_004b: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c6: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b1: Unknown result type (might be due to invalid IL or missing references)
			//IL_00aa: Unknown result type (might be due to invalid IL or missing references)
			orig.Invoke(self);
			MoneyText moneyText = self.moneyText;
			if (!Object.op_Implicit((Object)(object)moneyText) || !Object.op_Implicit((Object)(object)moneyText.targetText))
			{
				return;
			}
			if (!moneyTextColorCached)
			{
				moneyTextOriginalColor = ((Graphic)moneyText.targetText).color;
				moneyTextColorCached = true;
			}
			if (DebtSync.TryGet(self.targetMaster, out var view) && view.debt > 0)
			{
				if (self.targetMaster.money == 0)
				{
					moneyText.targetValue = -view.debt;
				}
				((Graphic)moneyText.targetText).color = (view.defaulted ? DefaultedColor : DeficitColor);
			}
			else
			{
				((Graphic)moneyText.targetText).color = moneyTextOriginalColor;
			}
		}

		private void FixedUpdate()
		{
			if (!NetworkServer.active || !Object.op_Implicit((Object)(object)Run.instance))
			{
				return;
			}
			interestTimer += Time.fixedDeltaTime;
			damageTimer += Time.fixedDeltaTime;
			multiplierTimer += Time.fixedDeltaTime;
			bool flag = false;
			bool flag2 = false;
			if (interestTimer >= 1f)
			{
				interestTimer -= 1f;
				flag = true;
			}
			if (damageTimer >= 0.5f)
			{
				damageTimer -= 0.5f;
				flag2 = true;
			}
			if (multiplierTimer >= 0.2f)
			{
				multiplierTimer = 0f;
				UpdateCostMultipliers();
			}
			SavingsBond.FixedUpdate();
			OvertimePay.FixedUpdate();
			ArtifactOfCommunism.FixedUpdate();
			foreach (PlayerCharacterMasterController instance in PlayerCharacterMasterController.instances)
			{
				CharacterMaster master = instance.master;
				if (!Object.op_Implicit((Object)(object)master))
				{
					continue;
				}
				DebtTracker debt = GetDebt(master);
				CharacterBody body = master.GetBody();
				bool flag3 = (Object)(object)debt != (Object)null && debt.debt > 0.0;
				double num = DebtLimit(master);
				if (flag3 && flag)
				{
					debt.debt += Math.Max(1.0, debt.debt * (double)InterestRatePerSecond.Value);
				}
				bool flag4 = flag3 && debt.debt > num;
				if (Object.op_Implicit((Object)(object)body))
				{
					UpdateBuff(body, inDebtBuff, flag3 && !flag4);
					UpdateBuff(body, defaultedBuff, flag4);
				}
				if ((Object)(object)debt != (Object)null)
				{
					if (flag4 && !debt.wasDefaulted)
					{
						AnnounceDefault(master);
					}
					debt.wasDefaulted = flag4;
				}
				if (flag4 && flag2 && Object.op_Implicit((Object)(object)body) && Object.op_Implicit((Object)(object)body.healthComponent) && body.healthComponent.alive)
				{
					ApplyDefaultDamage(master, body);
				}
			}
			DebtSync.ServerTick(Time.fixedDeltaTime, FillDebtSnapshot);
		}

		private static void FillDebtSnapshot(List<DebtSnapshotMessage.Entry> entries)
		{
			//IL_008a: Unknown result type (might be due to invalid IL or missing references)
			//IL_008f: Unknown result type (might be due to invalid IL or missing references)
			foreach (PlayerCharacterMasterController instance in PlayerCharacterMasterController.instances)
			{
				CharacterMaster master = instance.master;
				if (Object.op_Implicit((Object)(object)master))
				{
					DebtTracker debt = GetDebt(master);
					double num = (((Object)(object)debt != (Object)null) ? debt.debt : 0.0);
					if (!(num <= 0.0) || GetStacks(master) > 0)
					{
						entries.Add(new DebtSnapshotMessage.Entry
						{
							masterId = ((NetworkBehaviour)master).netId,
							debt = ClampToInt(Math.Ceiling(num)),
							limit = ClampToInt(Math.Floor(DebtLimit(master))),
							defaulted = ((Object)(object)debt != (Object)null && debt.wasDefaulted)
						});
					}
				}
			}
		}

		private static int ClampToInt(double value)
		{
			return (!(value <= 0.0)) ? ((value >= 2147483647.0) ? int.MaxValue : ((int)value)) : 0;
		}

		private static void UpdateBuff(CharacterBody body, BuffDef buff, bool active)
		{
			bool flag = body.HasBuff(buff);
			if (active && !flag)
			{
				body.AddBuff(buff);
			}
			else if (!active && flag)
			{
				body.RemoveBuff(buff);
			}
		}

		private static void ApplyDefaultDamage(CharacterMaster master, CharacterBody body)
		{
			//IL_0039: Unknown result type (might be due to invalid IL or missing references)
			//IL_003e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0065: Unknown result type (might be due to invalid IL or missing references)
			//IL_0067: Unknown result type (might be due to invalid IL or missing references)
			//IL_006c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0071: Unknown result type (might be due to invalid IL or missing references)
			//IL_0078: Unknown result type (might be due to invalid IL or missing references)
			//IL_007f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0086: Unknown result type (might be due to invalid IL or missing references)
			//IL_0088: 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_0090: Unknown result type (might be due to invalid IL or missing references)
			//IL_0095: Unknown result type (might be due to invalid IL or missing references)
			//IL_009f: Expected O, but got Unknown
			HealthComponent healthComponent = body.healthComponent;
			DebtTracker debt = GetDebt(master);
			uint money = master.money;
			double debt2 = (((Object)(object)debt != (Object)null) ? debt.debt : 0.0);
			applyingDefaultDamage = true;
			try
			{
				healthComponent.TakeDamage(new DamageInfo
				{
					damage = Mathf.Max(1f, healthComponent.fullCombinedHealth * DefaultDamagePerSecond.Value * 0.5f),
					position = body.corePosition,
					attacker = null,
					inflictor = null,
					crit = false,
					damageColorIndex = (DamageColorIndex)3,
					damageType = DamageTypeCombo.op_Implicit((DamageType)66)
				});
			}
			finally
			{
				applyingDefaultDamage = false;
				master.money = money;
				if ((Object)(object)debt != (Object)null)
				{
					debt.debt = debt2;
				}
			}
		}

		private static void AnnounceDefault(CharacterMaster master)
		{
			//IL_0036: Unknown result type (might be due to invalid IL or missing references)
			//IL_003b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0056: Expected O, but got Unknown
			string text = "A survivor";
			PlayerCharacterMasterController playerCharacterMasterController = master.playerCharacterMasterController;
			if (Object.op_Implicit((Object)(object)playerCharacterMasterController) && Object.op_Implicit((Object)(object)playerCharacterMasterController.networkUser))
			{
				text = playerCharacterMasterController.networkUser.userName;
			}
			Chat.SendBroadcastChat((ChatMessageBase)new SimpleChatMessage
			{
				baseToken = "<color=#ff5544>" + text + " has defaulted on their Defense Budget! Repay the deficit or perish.</color>"
			});
		}

		internal static double GetAvailableCredit(CharacterMaster master)
		{
			if (!Object.op_Implicit((Object)(object)master))
			{
				return 0.0;
			}
			DebtTracker debt = GetDebt(master);
			double num = (((Object)(object)debt != (Object)null) ? debt.debt : 0.0);
			return Math.Max(0.0, DebtLimit(master) - num);
		}

		internal static void PayWithCredit(CharacterMaster master, uint cost)
		{
			uint num = Math.Min(master.money, cost);
			master.money -= num;
			uint num2 = cost - num;
			if (num2 != 0)
			{
				GetOrCreateDebt(master).debt += num2;
			}
		}
	}
	internal static class GiveMoneyCompat
	{
		internal delegate void Orig(CharacterMaster self, uint amount, bool bypassStatManager);

		internal delegate void Handler(Orig orig, CharacterMaster self, uint amount, bool bypassStatManager);

		private delegate void OrigLegacy(CharacterMaster self, uint amount);

		private static readonly List<Hook> hooks = new List<Hook>();

		internal static void Add(Handler handler)
		{
			//IL_0061: Unknown result type (might be due to invalid IL or missing references)
			//IL_006b: Expected O, but got Unknown
			//IL_00c9: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d3: Expected O, but got Unknown
			MethodInfo method = typeof(CharacterMaster).GetMethod("GiveMoney", BindingFlags.Instance | BindingFlags.Public, null, new Type[2]
			{
				typeof(uint),
				typeof(bool)
			}, null);
			if (method != null)
			{
				hooks.Add(new Hook((MethodBase)method, (Delegate)handler));
				return;
			}
			MethodInfo method2 = typeof(CharacterMaster).GetMethod("GiveMoney", BindingFlags.Instance | BindingFlags.Public, null, new Type[1] { typeof(uint) }, null);
			if (method2 == null)
			{
				Log.Error("CharacterMaster.GiveMoney not found; gold income hooks are disabled.");
				return;
			}
			Action<OrigLegacy, CharacterMaster, uint> action = delegate(OrigLegacy orig, CharacterMaster self, uint amount)
			{
				handler(delegate(CharacterMaster master, uint value, bool _)
				{
					orig(master, value);
				}, self, amount, bypassStatManager: false);
			};
			hooks.Add(new Hook((MethodBase)method2, (Delegate)action));
		}
	}
	internal static class Log
	{
		private static ManualLogSource _logSource;

		internal static void Init(ManualLogSource logSource)
		{
			_logSource = logSource;
		}

		internal static void Debug(object data)
		{
			_logSource.LogDebug(data);
		}

		internal static void Info(object data)
		{
			_logSource.LogInfo(data);
		}

		internal static void Warning(object data)
		{
			_logSource.LogWarning(data);
		}

		internal static void Error(object data)
		{
			_logSource.LogError(data);
		}

		internal static void Fatal(object data)
		{
			_logSource.LogFatal(data);
		}
	}
}
namespace DefenseBudget.Net
{
	internal struct DebtView
	{
		public int debt;

		public int limit;

		public bool defaulted;
	}
	internal static class DebtSync
	{
		private const float MinSendInterval = 0.25f;

		private const float HeartbeatInterval = 2f;

		private static readonly Dictionary<uint, DebtView> views = new Dictionary<uint, DebtView>();

		private static readonly DebtSnapshotMessage outgoing = new DebtSnapshotMessage();

		private static float sinceLastSend;

		private static int lastHash;

		private static bool lastEmpty = true;

		internal static void Init()
		{
			NetworkingAPI.RegisterMessageType<DebtSnapshotMessage>();
			Run.onRunStartGlobal += delegate
			{
				sinceLastSend = 2f;
				lastHash = 0;
				lastEmpty = true;
			};
			Run.onRunDestroyGlobal += delegate
			{
				views.Clear();
			};
		}

		internal static bool TryGet(CharacterMaster master, out DebtView view)
		{
			//IL_0016: Unknown result type (might be due to invalid IL or missing references)
			//IL_001b: Unknown result type (might be due to invalid IL or missing references)
			view = default(DebtView);
			int result;
			if (Object.op_Implicit((Object)(object)master))
			{
				Dictionary<uint, DebtView> dictionary = views;
				NetworkInstanceId netId = ((NetworkBehaviour)master).netId;
				result = (dictionary.TryGetValue(((NetworkInstanceId)(ref netId)).Value, out view) ? 1 : 0);
			}
			else
			{
				result = 0;
			}
			return (byte)result != 0;
		}

		internal static void ApplySnapshot(List<DebtSnapshotMessage.Entry> entries)
		{
			//IL_0025: Unknown result type (might be due to invalid IL or missing references)
			//IL_002a: Unknown result type (might be due to invalid IL or missing references)
			views.Clear();
			foreach (DebtSnapshotMessage.Entry entry in entries)
			{
				Dictionary<uint, DebtView> dictionary = views;
				NetworkInstanceId masterId = entry.masterId;
				dictionary[((NetworkInstanceId)(ref masterId)).Value] = new DebtView
				{
					debt = entry.debt,
					limit = entry.limit,
					defaulted = entry.defaulted
				};
			}
		}

		internal static void ServerTick(float deltaTime, Action<List<DebtSnapshotMessage.Entry>> fill)
		{
			//IL_0055: Unknown result type (might be due to invalid IL or missing references)
			//IL_005a: Unknown result type (might be due to invalid IL or missing references)
			sinceLastSend += deltaTime;
			outgoing.entries.Clear();
			fill(outgoing.entries);
			int num = 17;
			foreach (DebtSnapshotMessage.Entry entry in outgoing.entries)
			{
				int num2 = num * 31;
				NetworkInstanceId masterId = entry.masterId;
				num = num2 + (int)((NetworkInstanceId)(ref masterId)).Value;
				num = num * 31 + entry.debt;
				num = num * 31 + entry.limit;
				num = num * 31 + (entry.defaulted ? 1 : 0);
			}
			bool flag = outgoing.entries.Count == 0;
			bool flag2 = num != lastHash || flag != lastEmpty;
			if (sinceLastSend >= (flag2 ? 0.25f : 2f))
			{
				NetMessageExtensions.Send((INetMessage)(object)outgoing, (NetworkDestination)1);
				sinceLastSend = 0f;
				lastHash = num;
				lastEmpty = flag;
			}
		}
	}
	internal sealed class DebtSnapshotMessage : INetMessage, ISerializableObject
	{
		internal struct Entry
		{
			public NetworkInstanceId masterId;

			public int debt;

			public int limit;

			public bool defaulted;
		}

		internal readonly List<Entry> entries = new List<Entry>();

		public void Serialize(NetworkWriter writer)
		{
			//IL_002d: Unknown result type (might be due to invalid IL or missing references)
			writer.WritePackedUInt32((uint)entries.Count);
			foreach (Entry entry in entries)
			{
				writer.Write(entry.masterId);
				writer.WritePackedUInt32((uint)entry.debt);
				writer.WritePackedUInt32((uint)entry.limit);
				writer.Write(entry.defaulted);
			}
		}

		public void Deserialize(NetworkReader reader)
		{
			//IL_002a: Unknown result type (might be due to invalid IL or missing references)
			//IL_002f: Unknown result type (might be due to invalid IL or missing references)
			entries.Clear();
			uint num = reader.ReadPackedUInt32();
			for (uint num2 = 0u; num2 < num; num2++)
			{
				entries.Add(new Entry
				{
					masterId = reader.ReadNetworkId(),
					debt = (int)reader.ReadPackedUInt32(),
					limit = (int)reader.ReadPackedUInt32(),
					defaulted = reader.ReadBoolean()
				});
			}
		}

		public void OnReceived()
		{
			DebtSync.ApplySnapshot(entries);
		}
	}
}
namespace DefenseBudget.Items
{
	internal static class AccountsReceivable
	{
		private class Claim : MonoBehaviour
		{
			internal readonly HashSet<CharacterMaster> claimants = new HashSet<CharacterMaster>();
		}

		[CompilerGenerated]
		private static class <>O
		{
			public static hook_TakeDamage <0>__MarkClaim;

			public static hook_OnCharacterDeath <1>__CollectClaims;
		}

		internal static ItemDef Def;

		internal static ConfigEntry<float> BountyBonusPerStack;

		internal static void Init(ConfigFile config)
		{
			//IL_0074: Unknown result type (might be due to invalid IL or missing references)
			//IL_007e: Expected O, but got Unknown
			//IL_0079: Unknown result type (might be due to invalid IL or missing references)
			//IL_0083: Expected O, but got Unknown
			//IL_0105: Unknown result type (might be due to invalid IL or missing references)
			//IL_010a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0110: Expected O, but got Unknown
			//IL_0126: Unknown result type (might be due to invalid IL or missing references)
			//IL_012b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0131: Expected O, but got Unknown
			BountyBonusPerStack = config.Bind<float>("AccountsReceivable", "BountyBonusPerStack", 0.1f, "Bonus fraction of a marked enemy's gold bounty collected on its death, per stack.");
			Def = Assets.CreateItemDef("AccountsReceivable", "ACCOUNTS_RECEIVABLE", (ItemTier)1, Assets.LoadSprite("DefenseBudget.icon_accounts_receivable.rgba", 128), Assets.CreatePickupModel("PickupAccountsReceivable", "DefenseBudget.models.accounts_receivable.obj", "DefenseBudget.models.accounts_receivable.rgba", 512, 0.6f), (ItemTag[])(object)new ItemTag[1] { (ItemTag)3 });
			ItemAPI.Add(new CustomItem(Def, new ItemDisplayRuleDict((ItemDisplayRule[])null)));
			int num = Mathf.RoundToInt(BountyBonusPerStack.Value * 100f);
			LanguageAPI.Add("ACCOUNTS_RECEIVABLE_NAME", "Accounts Receivable");
			LanguageAPI.Add("ACCOUNTS_RECEIVABLE_PICKUP", "Enemies you damage owe you a cut of their bounty.");
			LanguageAPI.Add("ACCOUNTS_RECEIVABLE_DESC", "Damaging an enemy <style=cIsUtility>marks</style> them. Marked enemies grant you an additional " + $"<style=cIsUtility>{num}% <style=cStack>(+{num}% per stack)</style></style> of their gold reward when killed by anyone.");
			LanguageAPI.Add("ACCOUNTS_RECEIVABLE_LORE", "INVOICE #44721\nServices rendered: ballistic consultation (1x)\nPayment due: immediately\nLate fee: continued ballistic consultation");
			object obj = <>O.<0>__MarkClaim;
			if (obj == null)
			{
				hook_TakeDamage val = MarkClaim;
				<>O.<0>__MarkClaim = val;
				obj = (object)val;
			}
			HealthComponent.TakeDamage += (hook_TakeDamage)obj;
			object obj2 = <>O.<1>__CollectClaims;
			if (obj2 == null)
			{
				hook_OnCharacterDeath val2 = CollectClaims;
				<>O.<1>__CollectClaims = val2;
				obj2 = (object)val2;
			}
			GlobalEventManager.OnCharacterDeath += (hook_OnCharacterDeath)obj2;
		}

		private static void MarkClaim(orig_TakeDamage orig, HealthComponent self, DamageInfo damageInfo)
		{
			//IL_009b: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ab: Unknown result type (might be due to invalid IL or missing references)
			if (NetworkServer.active && damageInfo != null && !damageInfo.rejected && damageInfo.damage > 0f && Object.op_Implicit((Object)(object)damageInfo.attacker) && Object.op_Implicit((Object)(object)self.body))
			{
				CharacterBody component = damageInfo.attacker.GetComponent<CharacterBody>();
				CharacterMaster val = (Object.op_Implicit((Object)(object)component) ? component.master : null);
				if (Object.op_Implicit((Object)(object)val) && Object.op_Implicit((Object)(object)val.inventory) && Object.op_Implicit((Object)(object)component.teamComponent) && Object.op_Implicit((Object)(object)self.body.teamComponent) && component.teamComponent.teamIndex != self.body.teamComponent.teamIndex && val.inventory.GetItemCount(Def) > 0)
				{
					Claim claim = ((Component)self.body).GetComponent<Claim>();
					if (!Object.op_Implicit((Object)(object)claim))
					{
						claim = ((Component)self.body).gameObject.AddComponent<Claim>();
					}
					claim.claimants.Add(val);
				}
			}
			orig.Invoke(self, damageInfo);
		}

		private static void CollectClaims(orig_OnCharacterDeath orig, GlobalEventManager self, DamageReport damageReport)
		{
			uint num = 0u;
			Claim claim = null;
			if (NetworkServer.active && Object.op_Implicit((Object)(object)damageReport?.victimBody))
			{
				claim = ((Component)damageReport.victimBody).GetComponent<Claim>();
				if ((Object)(object)claim != (Object)null)
				{
					DeathRewards component = ((Component)damageReport.victimBody).GetComponent<DeathRewards>();
					num = (Object.op_Implicit((Object)(object)component) ? component.goldReward : 0u);
				}
			}
			orig.Invoke(self, damageReport);
			if ((Object)(object)claim == (Object)null || num == 0)
			{
				return;
			}
			foreach (CharacterMaster claimant in claim.claimants)
			{
				if (!Object.op_Implicit((Object)(object)claimant) || !Object.op_Implicit((Object)(object)claimant.inventory))
				{
					continue;
				}
				int itemCount = claimant.inventory.GetItemCount(Def);
				if (itemCount > 0)
				{
					uint num2 = (uint)Math.Round((float)num * BountyBonusPerStack.Value * (float)itemCount);
					if (num2 != 0)
					{
						claimant.GiveMoney(num2);
					}
				}
			}
		}
	}
	internal static class GoldenParachute
	{
		private class ParachuteCooldown : MonoBehaviour
		{
			internal float readyTime;
		}

		[CompilerGenerated]
		private static class <>O
		{
			public static hook_TakeDamage <0>__InterceptLethal;
		}

		internal static ItemDef Def;

		internal static ConfigEntry<int> BaseCost;

		internal static ConfigEntry<float> CooldownSeconds;

		internal static ConfigEntry<float> CooldownReductionPerStack;

		internal static ConfigEntry<float> SurviveHealthFraction;

		internal static ConfigEntry<float> ImmunityDuration;

		internal static void Init(ConfigFile config)
		{
			//IL_00f1: Unknown result type (might be due to invalid IL or missing references)
			//IL_00fb: Expected O, but got Unknown
			//IL_00f6: Unknown result type (might be due to invalid IL or missing references)
			//IL_0100: Expected O, but got Unknown
			//IL_01b7: Unknown result type (might be due to invalid IL or missing references)
			//IL_01bc: Unknown result type (might be due to invalid IL or missing references)
			//IL_01c2: Expected O, but got Unknown
			BaseCost = config.Bind<int>("GoldenParachute", "BaseCost", 40, "Severance fee in base gold, scaled by difficulty over time exactly like chest prices.");
			CooldownSeconds = config.Bind<float>("GoldenParachute", "CooldownSeconds", 45f, "Cooldown between deployments.");
			CooldownReductionPerStack = config.Bind<float>("GoldenParachute", "CooldownReductionPerStack", 0.25f, "Multiplicative cooldown reduction per stack beyond the first.");
			SurviveHealthFraction = config.Bind<float>("GoldenParachute", "SurviveHealthFraction", 0.15f, "Fraction of full health restored on deployment.");
			ImmunityDuration = config.Bind<float>("GoldenParachute", "ImmunityDuration", 1.5f, "Seconds of immunity granted on deployment (covers the rest of the killing burst).");
			Def = Assets.CreateItemDef("GoldenParachute", "GOLDEN_PARACHUTE", (ItemTier)2, Assets.LoadSprite("DefenseBudget.icon_golden_parachute.rgba", 128), Assets.CreatePickupModel("PickupGoldenParachute", "DefenseBudget.models.golden_parachute.obj", "DefenseBudget.models.golden_parachute.rgba", 512, 0.8f), (ItemTag[])(object)new ItemTag[2]
			{
				(ItemTag)3,
				(ItemTag)4
			});
			ItemAPI.Add(new CustomItem(Def, new ItemDisplayRuleDict((ItemDisplayRule[])null)));
			LanguageAPI.Add("GOLDEN_PARACHUTE_NAME", "Golden Parachute");
			LanguageAPI.Add("GOLDEN_PARACHUTE_PICKUP", "Cheat death by cashing out.");
			LanguageAPI.Add("GOLDEN_PARACHUTE_DESC", "Upon taking lethal damage, pay a <style=cIsUtility>severance fee</style> of difficulty-scaled gold (drawing on <style=cIsUtility>credit</style> if you have a Defense Budget) to instead survive at " + $"<style=cIsHealing>{Mathf.RoundToInt(SurviveHealthFraction.Value * 100f)}% health</style>. " + $"If you cannot cover the fee, you die. Recharges every {CooldownSeconds.Value:0} seconds " + $"<style=cStack>(-{Mathf.RoundToInt(CooldownReductionPerStack.Value * 100f)}% per stack)</style>.");
			LanguageAPI.Add("GOLDEN_PARACHUTE_LORE", "Section 12(b): In the event of involuntary separation (termination, restructuring, evisceration), the executive shall receive one (1) severance package, deployment automatic, fee deducted from estate.\n\nThe board notes with approval that the executive has never once read Section 12(c): renewal fees.");
			object obj = <>O.<0>__InterceptLethal;
			if (obj == null)
			{
				hook_TakeDamage val = InterceptLethal;
				<>O.<0>__InterceptLethal = val;
				obj = (object)val;
			}
			HealthComponent.TakeDamage += (hook_TakeDamage)obj;
		}

		private static void InterceptLethal(orig_TakeDamage orig, HealthComponent self, DamageInfo damageInfo)
		{
			//IL_0209: Unknown result type (might be due to invalid IL or missing references)
			//IL_020e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0230: Expected O, but got Unknown
			if (NetworkServer.active && damageInfo != null && !damageInfo.rejected && damageInfo.damage > 0f && self.alive && Object.op_Implicit((Object)(object)self.body) && Object.op_Implicit((Object)(object)Run.instance))
			{
				CharacterMaster master = self.body.master;
				int num = ((Object.op_Implicit((Object)(object)master) && Object.op_Implicit((Object)(object)master.inventory)) ? master.inventory.GetItemCount(Def) : 0);
				if (num > 0)
				{
					ParachuteCooldown parachuteCooldown = ((Component)master).GetComponent<ParachuteCooldown>();
					float time = Run.instance.time;
					if ((Object)(object)parachuteCooldown == (Object)null || time >= parachuteCooldown.readyTime)
					{
						float armor = self.body.armor;
						float num2 = ((armor >= 0f) ? (100f / (100f + armor)) : (2f - 100f / (100f - armor)));
						float num3 = damageInfo.damage * num2;
						if (num3 >= self.combinedHealth)
						{
							uint difficultyScaledCost = (uint)Run.instance.GetDifficultyScaledCost(BaseCost.Value);
							if ((double)master.money + DefenseBudgetPlugin.GetAvailableCredit(master) >= (double)difficultyScaledCost)
							{
								DefenseBudgetPlugin.PayWithCredit(master, difficultyScaledCost);
								self.body.AddTimedBuff(Buffs.Immune, ImmunityDuration.Value);
								self.Networkhealth = Mathf.Max(self.health, self.fullHealth * SurviveHealthFraction.Value);
								Log.Info($"Golden Parachute deployed for {Util.GetBestMasterName(master)} (fee {difficultyScaledCost})");
								if ((Object)(object)parachuteCooldown == (Object)null)
								{
									parachuteCooldown = ((Component)master).gameObject.AddComponent<ParachuteCooldown>();
								}
								parachuteCooldown.readyTime = time + CooldownSeconds.Value * Mathf.Pow(1f - CooldownReductionPerStack.Value, (float)(num - 1));
								Chat.SendBroadcastChat((ChatMessageBase)new SimpleChatMessage
								{
									baseToken = $"<color=#ffd24a>{Util.GetBestMasterName(master)}'s Golden Parachute deployed! Severance fee: {difficultyScaledCost} gold.</color>"
								});
							}
						}
					}
				}
			}
			orig.Invoke(self, damageInfo);
		}
	}
	internal static class OvertimePay
	{
		private class Account : MonoBehaviour
		{
			public float lastEngaged = float.NegativeInfinity;

			public bool bucketFilled;

			public float bucket;

			public float owedChests;

			public float goldCarry;

			public float lastPayoutTime = float.NegativeInfinity;
		}

		[CompilerGenerated]
		private static class <>O
		{
			public static Manipulator <0>__TapOverheal;

			public static Action<DamageReport> <1>__StampCombat;

			public static Action<HealthComponent, float, bool> <2>__OnOverheal;
		}

		internal static ItemDef Def;

		internal static ConfigEntry<float> ContributionHealPerStack;

		internal static ConfigEntry<float> ChestsPerFullOverheal;

		internal static ConfigEntry<float> MaxChestsPerMinutePerStack;

		internal static ConfigEntry<float> BurstSeconds;

		internal static ConfigEntry<bool> RequireCombat;

		internal static ConfigEntry<float> CombatWindow;

		internal static ConfigEntry<bool> CountMinionDamage;

		internal static ConfigEntry<float> RegenWeight;

		private const int SmallChestBaseCost = 25;

		private const float ContributionInterval = 0.5f;

		private const float MinPayoutInterval = 2f;

		private const float MinPayoutGold = 3f;

		private static readonly Dictionary<HealthComponent, Account> holders = new Dictionary<HealthComponent, Account>();

		private static readonly Dictionary<CharacterMaster, Account> accounts = new Dictionary<CharacterMaster, Account>();

		private static float contributionTimer;

		private static readonly string[] HeartGlyph = new string[6] { ".XX.XX.", "XXXXXXX", "XXXXXXX", ".XXXXX.", "..XXX..", "...X..." };

		internal static void Init(ConfigFile config)
		{
			//IL_016e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0173: Unknown result type (might be due to invalid IL or missing references)
			//IL_0186: Unknown result type (might be due to invalid IL or missing references)
			//IL_0190: Expected O, but got Unknown
			//IL_018b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0195: Expected O, but got Unknown
			//IL_019b: Unknown result type (might be due to invalid IL or missing references)
			//IL_01a0: Unknown result type (might be due to invalid IL or missing references)
			//IL_01c1: 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_01df: Unknown result type (might be due to invalid IL or missing references)
			//IL_01f9: Unknown result type (might be due to invalid IL or missing references)
			//IL_01fb: Unknown result type (might be due to invalid IL or missing references)
			//IL_0222: Unknown result type (might be due to invalid IL or missing references)
			//IL_0227: Unknown result type (might be due to invalid IL or missing references)
			//IL_022d: Expected O, but got Unknown
			ContributionHealPerStack = config.Bind<float>("OvertimePay", "ContributionHealPerStack", 0.0075f, "Fraction of maximum health (health + shield) healed per second, per stack. Works like regeneration: no crits, no Aegis barrier, no N'kuhana's charge. Rejuvenation Rack and the Eclipse healing penalty apply.");
			ChestsPerFullOverheal = config.Bind<float>("OvertimePay", "ChestsPerFullOverheal", 1f, "Small chests' worth of gold earned per 100% of maximum health overhealed (0.5 = one chest per 200%). Does not grow with stacks. A small chest's price scales with difficulty over time.");
			MaxChestsPerMinutePerStack = config.Bind<float>("OvertimePay", "MaxChestsPerMinutePerStack", 10f, "Safety cap per stack, in small chests' worth per minute; only extreme healing builds reach it. Overheal beyond the cap is discarded, not banked.");
			BurstSeconds = config.Bind<float>("OvertimePay", "BurstSeconds", 10f, "How many seconds' worth of the payout cap can be paid at once, so a burst heal at full health (Medkit, Monster Tooth) pays in full.");
			RequireCombat = config.Bind<bool>("OvertimePay", "RequireCombat", false, "If true, overheal only pays while in combat (see CombatWindow). If false, it pays whenever the run timer is running, and only in combat while the timer is paused (Bazaar, Void Fields cells) or between Simulacrum waves, so idling where time stands still earns nothing.");
			CombatWindow = config.Bind<float>("OvertimePay", "CombatWindow", 5f, "Seconds after you damage, or are damaged by, an enemy that count as being in combat. Damage over time you applied counts.");
			CountMinionDamage = config.Bind<bool>("OvertimePay", "CountMinionDamage", false, "If true, damage dealt by your drones and turrets also keeps you in combat.");
			RegenWeight = config.Bind<float>("OvertimePay", "RegenWeight", 1f, "Multiplier on overheal from regeneration-type healing (natural regen and this item's own heal). 0 = only healing effects (Leeching Seed, Medkit, ...) pay, like Aegis's barrier.");
			Sprite icon = Assets.LoadSprite("DefenseBudget.icon_overtime_pay.rgba", 128);
			GameObject model = Assets.CreatePickupModel("PickupOvertimePay", "DefenseBudget.models.overtime_pay.obj", "DefenseBudget.models.overtime_pay.rgba", 512, 0.6f, () => Assets.CreateGlyphModel("PickupOvertimePayGlyph", HeartGlyph, new Color(0.95f, 0.35f, 0.75f), 0.1f, 0.16f));
			ItemTag[] array = new ItemTag[4];
			RuntimeHelpers.InitializeArray(array, (RuntimeFieldHandle)/*OpCode not supported: LdMemberToken*/);
			Def = Assets.CreateItemDef("OvertimePay", "OVERTIME_PAY", (ItemTier)6, icon, model, (ItemTag[])(object)array);
			Def.requiredExpansion = Addressables.LoadAssetAsync<ExpansionDef>((object)"RoR2/DLC1/Common/DLC1.asset").WaitForCompletion();
			ItemAPI.Add(new CustomItem(Def, new ItemDisplayRuleDict((ItemDisplayRule[])null)));
			ItemDef itemDef = Addressables.LoadAssetAsync<ItemDef>((object)"RoR2/DLC1/GoldOnHurt/GoldOnHurt.asset").WaitForCompletion();
			ItemRelationshipProvider val = ScriptableObject.CreateInstance<ItemRelationshipProvider>();
			((Object)val).name = "DefenseBudgetContagiousItems";
			val.relationshipType = Addressables.LoadAssetAsync<ItemRelationshipType>((object)"RoR2/DLC1/Common/ContagiousItem.asset").WaitForCompletion();
			val.relationships = (Pair[])(object)new Pair[1]
			{
				new Pair
				{
					itemDef1 = itemDef,
					itemDef2 = Def
				}
			};
			ContentAddition.AddItemRelationshipProvider(val);
			CreateLanguage();
			object obj = <>O.<0>__TapOverheal;
			if (obj == null)
			{
				Manipulator val2 = TapOverheal;
				<>O.<0>__TapOverheal = val2;
				obj = (object)val2;
			}
			HealthComponent.Heal += (Manipulator)obj;
			GlobalEventManager.onServerDamageDealt += StampCombat;
			Run.onRunStartGlobal += delegate
			{
				contributionTimer = 0f;
			};
			Run.onRunDestroyGlobal += delegate
			{
				holders.Clear();
				accounts.Clear();
			};
		}

		private static void CreateLanguage()
		{
			string text = (ContributionHealPerStack.Value * 100f).ToString("0.##");
			string text2 = (100f / Mathf.Max(0.01f, ChestsPerFullOverheal.Value)).ToString("0.#");
			LanguageAPI.Add("OVERTIME_PAY_NAME", "Overtime Pay");
			LanguageAPI.Add("OVERTIME_PAY_PICKUP", "Heal over time. Healing past full health is paid as overtime. <style=cIsVoid>Corrupts all Rolls of Pennies</style>.");
			string text3 = "";
			if (ContributionHealPerStack.Value > 0f)
			{
				text3 = text3 + "<style=cIsHealing>Heal</style> for <style=cIsHealing>" + text + "%</style> <style=cStack>(+" + text + "% per stack)</style> of your <style=cIsHealing>maximum health</style> every second. ";
			}
			text3 = text3 + "<style=cIsHealing>Healing past full health</style>" + (RequireCombat.Value ? " while in combat" : "") + " steadily earns <style=cIsUtility>one small chest's worth of gold</style> for every <style=cIsHealing>" + text2 + "%</style> of your maximum health overhealed. <style=cIsVoid>Corrupts all Rolls of Pennies</style>.";
			LanguageAPI.Add("OVERTIME_PAY_DESC", text3);
			LanguageAPI.Add("OVERTIME_PAY_LORE", "TIMESHEET ADDENDUM, FORM 7-VOID\n\nHours worked beyond full capacity are compensated at the overtime rate: one (1) small container of currency per one (1) complete person.\nOvertime accrues continuously while the employee is in perfect health and the clock is running. Hours spent idling in the break room, where the clock is stopped, are not billable.\n\nPayroll caps overtime per pay period. Vitality in excess of the cap is forfeited to the company. Management thanks you for going above and beyond. Management always does.");
		}

		private static void TapOverheal(ILContext il)
		{
			//IL_0008: Unknown result type (might be due to invalid IL or missing references)
			//IL_000e: Expected O, but got Unknown
			//IL_0113: Unknown result type (might be due to invalid IL or missing references)
			//IL_011a: Invalid comparison between Unknown and I4
			//IL_0196: Unknown result type (might be due to invalid IL or missing references)
			//IL_01a2: Unknown result type (might be due to invalid IL or missing references)
			//IL_01b4: Unknown result type (might be due to invalid IL or missing references)
			ILCursor val = new ILCursor(il);
			int overhealLoc = -1;
			if (!val.TryGotoNext((MoveType)2, new Func<Instruction, bool>[1]
			{
				(Instruction x) => ILPatternMatchingExt.MatchCallOrCallvirt<HealthComponent>(x, "set_Networkhealth")
			}))
			{
				Log.Error("Overtime Pay: set_Networkhealth not found in HealthComponent.Heal; overheal will not pay.");
				return;
			}
			FieldReference val3 = default(FieldReference);
			if (!val.TryGotoNext((MoveType)1, new Func<Instruction, bool>[4]
			{
				(Instruction x) => ILPatternMatchingExt.MatchLdloc(x, ref overhealLoc),
				(Instruction x) => ILPatternMatchingExt.MatchLdcR4(x, 0f),
				(Instruction x) => ILPatternMatchingExt.MatchBleUn(x, ref val3),
				(Instruction x) => ILPatternMatchingExt.MatchLdarg(x, 3)
			}))
			{
				Log.Error("Overtime Pay: Aegis overheal test not found in HealthComponent.Heal; overheal will not pay.");
				return;
			}
			if ((int)((VariableReference)il.Body.Variables[overhealLoc]).VariableType.MetadataType != 12)
			{
				Log.Error("Overtime Pay: overheal local in HealthComponent.Heal is not a float; overheal will not pay.");
				return;
			}
			ILCursor val2 = val.Clone();
			if (!val2.TryGotoNext(new Func<Instruction, bool>[1]
			{
				(Instruction x) => ILPatternMatchingExt.MatchLdfld(x, ref val3) && ((MemberReference)val3).Name == "barrierOnOverHeal"
			}) || val2.Index - val.Index > 12)
			{
				Log.Error("Overtime Pay: HealthComponent.Heal no longer matches the Aegis overheal shape; overheal will not pay.");
				return;
			}
			val.Emit(OpCodes.Ldarg_0);
			val.Emit(OpCodes.Ldloc, overhealLoc);
			val.Emit(OpCodes.Ldarg_3);
			val.EmitDelegate<Action<HealthComponent, float, bool>>((Action<HealthComponent, float, bool>)OnOverheal);
		}

		private static void OnOverheal(HealthComponent healthComponent, float overheal, bool nonRegen)
		{
			if (holders.Count == 0 || !(overheal > 0f) || DefenseBudgetPlugin.ApplyingDefaultDamage)
			{
				return;
			}
			try
			{
				if (holders.TryGetValue(healthComponent, out var value) && Object.op_Implicit((Object)(object)value) && IsOnTheClock(value))
				{
					overheal -= Mathf.Max(0f, healthComponent.fullHealth - healthComponent.health);
					if (overheal > 0f)
					{
						float num = (nonRegen ? 1f : RegenWeight.Value);
						value.owedChests += overheal * num / Mathf.Max(1f, healthComponent.fullCombinedHealth) * ChestsPerFullOverheal.Value;
					}
				}
			}
			catch (Exception arg)
			{
				Log.Error($"Overtime Pay: {arg}");
			}
		}

		private static bool IsOnTheClock(Account account)
		{
			if (SceneExitController.isRunning)
			{
				return false;
			}
			if (Time.fixedTime <= account.lastEngaged + CombatWindow.Value)
			{
				return true;
			}
			if (RequireCombat.Value || !Object.op_Implicit((Object)(object)Run.instance))
			{
				return false;
			}
			Run instance = Run.instance;
			InfiniteTowerRun val = (InfiniteTowerRun)(object)((instance is InfiniteTowerRun) ? instance : null);
			if (val != null)
			{
				return Object.op_Implicit((Object)(object)val.waveController) && !val.waveController.isFinished;
			}
			return !Run.instance.isRunStopwatchPaused;
		}

		private static void StampCombat(DamageReport report)
		{
			//IL_0036: Unknown result type (might be due to invalid IL or missing references)
			//IL_003c: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e6: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ec: Unknown result type (might be due to invalid IL or missing references)
			if (accounts.Count == 0 || report == null)
			{
				return;
			}
			float fixedTime = Time.fixedTime;
			CharacterMaster attackerMaster = report.attackerMaster;
			if (Object.op_Implicit((Object)(object)attackerMaster) && IsHostile(report.attackerTeamIndex, report.victimTeamIndex))
			{
				if (accounts.TryGetValue(attackerMaster, out var value))
				{
					value.lastEngaged = fixedTime;
				}
				else if (CountMinionDamage.Value && Object.op_Implicit((Object)(object)attackerMaster.minionOwnership))
				{
					CharacterMaster ownerMaster = attackerMaster.minionOwnership.ownerMaster;
					if (Object.op_Implicit((Object)(object)ownerMaster) && accounts.TryGetValue(ownerMaster, out var value2))
					{
						value2.lastEngaged = fixedTime;
					}
				}
			}
			CharacterMaster victimMaster = report.victimMaster;
			if (Object.op_Implicit((Object)(object)victimMaster) && Object.op_Implicit((Object)(object)report.attackerBody) && IsHostile(report.victimTeamIndex, report.attackerTeamIndex) && accounts.TryGetValue(victimMaster, out var value3))
			{
				value3.lastEngaged = fixedTime;
			}
		}

		private static bool IsHostile(TeamIndex self, TeamIndex other)
		{
			//IL_0001: Unknown result type (might be due to invalid IL or missing references)
			//IL_0002: Unknown result type (might be due to invalid IL or missing references)
			//IL_0005: Unknown result type (might be due to invalid IL or missing references)
			//IL_0008: Unknown result type (might be due to invalid IL or missing references)
			//IL_000a: Invalid comparison between Unknown and I4
			return self != other && (int)other != 0 && (int)other != -1;
		}

		internal static void FixedUpdate()
		{
			//IL_0229: Unknown result type (might be due to invalid IL or missing references)
			//IL_022f: Unknown result type (might be due to invalid IL or missing references)
			holders.Clear();
			accounts.Clear();
			float fixedDeltaTime = Time.fixedDeltaTime;
			contributionTimer += fixedDeltaTime;
			bool flag = contributionTimer >= 0.5f;
			if (flag)
			{
				contributionTimer -= 0.5f;
			}
			float num = Run.instance.GetDifficultyScaledCost(25);
			float fixedTime = Time.fixedTime;
			foreach (PlayerCharacterMasterController instance in PlayerCharacterMasterController.instances)
			{
				CharacterMaster master = instance.master;
				int num2 = ((Object.op_Implicit((Object)(object)master) && Object.op_Implicit((Object)(object)master.inventory)) ? master.inventory.GetItemCount(Def) : 0);
				if (num2 <= 0)
				{
					continue;
				}
				Account account = ((Component)master).GetComponent<Account>();
				if (!Object.op_Implicit((Object)(object)account))
				{
					account = ((Component)master).gameObject.AddComponent<Account>();
				}
				accounts[master] = account;
				float num3 = MaxChestsPerMinutePerStack.Value * (float)num2 / 60f;
				float num4 = Mathf.Max(num3 * BurstSeconds.Value, num3 * fixedDeltaTime);
				account.bucket = (account.bucketFilled ? Mathf.Min(num4, account.bucket + num3 * fixedDeltaTime) : num4);
				account.bucketFilled = true;
				float num5 = Mathf.Min(account.owedChests, account.bucket);
				account.bucket -= num5;
				account.owedChests = 0f;
				account.goldCarry += num5 * num;
				CharacterBody body = master.GetBody();
				HealthComponent val = (Object.op_Implicit((Object)(object)body) ? body.healthComponent : null);
				if (Object.op_Implicit((Object)(object)val) && val.alive)
				{
					holders[val] = account;
					if (flag && ContributionHealPerStack.Value > 0f)
					{
						val.Heal(ContributionHealPerStack.Value * (float)num2 * val.fullCombinedHealth * 0.5f, default(ProcChainMask), false);
					}
				}
				if (account.goldCarry >= 3f && fixedTime - account.lastPayoutTime >= 2f && !SceneExitController.isRunning)
				{
					uint num6 = (uint)account.goldCarry;
					account.goldCarry -= num6;
					account.lastPayoutTime = fixedTime;
					Deliver(master, body, num6);
				}
			}
		}

		private static void Deliver(CharacterMaster master, CharacterBody body, uint gold)
		{
			//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_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_005d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0062: Unknown result type (might be due to invalid IL or missing references)
			//IL_0067: 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_0071: Unknown result type (might be due to invalid IL or missing references)
			//IL_0076: Unknown result type (might be due to invalid IL or missing references)
			//IL_0082: Unknown result type (might be due to invalid IL or missing references)
			//IL_0089: Unknown result type (might be due to invalid IL or missing references)
			//IL_0095: Expected O, but got Unknown
			if (Object.op_Implicit((Object)(object)body) && Object.op_Implicit((Object)(object)body.healthComponent) && body.healthComponent.alive && Object.op_Implicit((Object)(object)body.mainHurtBox) && Object.op_Implicit((Object)(object)OrbManager.instance))
			{
				OrbManager.instance.AddOrb((Orb)new GoldOrb
				{
					origin = body.corePosition + Random.onUnitSphere * 2f + Vector3.up,
					target = body.mainHurtBox,
					goldAmount = gold,
					scaleOrb = true
				});
			}
			else
			{
				master.GiveMoney(gold);
			}
		}
	}
	internal static class SavingsBond
	{
		internal static ItemDef Def;

		internal static ConfigEntry<float> InterestRatePerStack;

		internal static ConfigEntry<float> InterestInterval;

		private static float timer;

		internal static void Init(ConfigFile config)
		{
			//IL_0093: Unknown result type (might be due to invalid IL or missing references)
			//IL_009d: Expected O, but got Unknown
			//IL_0098: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a2: Expected O, but got Unknown
			InterestRatePerStack = config.Bind<float>("SavingsBond", "InterestRatePerStack", 0.02f, "Interest earned on held gold per stack, each interval.");
			InterestInterval = config.Bind<float>("SavingsBond", "InterestInterval", 10f, "Seconds between interest payments.");
			Def = Assets.CreateItemDef("SavingsBond", "SAVINGS_BOND", (ItemTier)0, Assets.LoadSprite("DefenseBudget.icon_savings_bond.rgba", 128), Assets.CreatePickupModel("PickupSavingsBond", "DefenseBudget.models.savings_bond.obj", "DefenseBudget.models.savings_bond.rgba", 512, 0.6f), (ItemTag[])(object)new ItemTag[1] { (ItemTag)3 });
			ItemAPI.Add(new CustomItem(Def, new ItemDisplayRuleDict((ItemDisplayRule[])null)));
			int num = Mathf.RoundToInt(InterestRatePerStack.Value * 100f);
			LanguageAPI.Add("SAVINGS_BOND_NAME", "Savings Bond");
			LanguageAPI.Add("SAVINGS_BOND_PICKUP", "Earn interest on your held gold.");
			LanguageAPI.Add("SAVINGS_BOND_DESC", $"Every {InterestInterval.Value:0} seconds, earn <style=cIsUtility>{num}% <style=cStack>(+{num}% per stack)</style> interest</style> on your held gold.");
			LanguageAPI.Add("SAVINGS_BOND_LORE", "\"Guaranteed 2% return, backed by the full faith and credit of whatever government still exists when it matures.\"\n\n- Prospectus fragment, recovered from contact light wreckage");
		}

		internal static void FixedUpdate()
		{
			if (SceneExitController.isRunning)
			{
				return;
			}
			timer += Time.fixedDeltaTime;
			if (timer < InterestInterval.Value)
			{
				return;
			}
			timer = 0f;
			foreach (PlayerCharacterMasterController instance in PlayerCharacterMasterController.instances)
			{
				CharacterMaster master = instance.master;
				if (Object.op_Implicit((Object)(object)master) && Object.op_Implicit((Object)(object)master.inventory))
				{
					int itemCount = master.inventory.GetItemCount(Def);
					if (itemCount > 0 && master.money != 0)
					{
						uint num = (uint)Math.Max(1.0, Math.Floor((float)master.money * InterestRatePerStack.Value * (float)itemCount));
						master.GiveMoney(num);
					}
				}
			}
		}
	}
}
namespace DefenseBudget.Artifacts
{
	internal static class ArtifactOfCommunism
	{
		internal static ArtifactDef Def;

		internal static ConfigEntry<float> SharePenaltyPerExtraPlayer;

		private static double pool;

		private static uint lastSyncedMoney;

		private static bool poolInitialized;

		internal static bool Enabled => Object.op_Implicit((Object)(object)Def) && Object.op_Implicit((Object)(object)RunArtifactManager.instance) && RunArtifactManager.instance.IsArtifactEnabled(Def);

		internal static void Init(ConfigFile config)
		{
			SharePenaltyPerExtraPlayer = config.Bind<float>("ArtifactOfCommunism", "SharePenaltyPerExtraPlayer", 0.25f, "Collectivization overhead. Total pool income is multiplied by playerCount - penalty * (playerCount - 1): 0.25 means 2 players earn x1.75, 4 players earn x3.25. Solo is unaffected.");
			Def = ScriptableObject.CreateInstance<ArtifactDef>();
			Def.cachedName = "ArtifactOfCommunism";
			Def.nameToken = "ARTIFACT_COMMUNISM_NAME";
			Def.descriptionToken = "ARTIFACT_COMMUNISM_DESC";
			Def.smallIconSelectedSprite = Assets.LoadSprite("DefenseBudget.icon_artifact_communism_enabled.rgba", 128);
			Def.smallIconDeselectedSprite = Assets.LoadSprite("DefenseBudget.icon_artifact_communism_disabled.rgba", 128);
			ContentAddition.AddArtifactDef(Def);
			LanguageAPI.Add("ARTIFACT_COMMUNISM_NAME", "Artifact of Communism");
			LanguageAPI.Add("ARTIFACT_COMMUNISM_DESC", "All gold belongs to the collective: every player earns into and spends from one shared pool. Total gold income is slightly less than the sum of what individuals would have earned.");
			GiveMoneyCompat.Add(PoolIncome);
			Run.onRunStartGlobal += delegate
			{
				pool = 0.0;
				lastSyncedMoney = 0u;
				poolInitialized = false;
			};
		}

		private static void PoolIncome(GiveMoneyCompat.Orig orig, CharacterMaster self, uint amount, bool bypassStatManager)
		{
			if (!NetworkServer.active || amount == 0 || !Enabled || !Object.op_Implicit((Object)(object)self.playerCharacterMasterController))
			{
				orig(self, amount, bypassStatManager);
				return;
			}
			EnsureInitialized();
			int num = Mathf.Max(1, PlayerCharacterMasterController.instances.Count);
			float num2 = ((float)num - SharePenaltyPerExtraPlayer.Value * (float)(num - 1)) / (float)num;
			pool += (float)amount * num2;
		}

		private static void EnsureInitialized()
		{
			if (poolInitialized)
			{
				return;
			}
			poolInitialized = true;
			pool = 0.0;
			foreach (PlayerCharacterMasterController instance in PlayerCharacterMasterController.instances)
			{
				if (Object.op_Implicit((Object)(object)instance.master))
				{
					pool += instance.master.money;
				}
			}
			lastSyncedMoney = (uint)pool;
			Mirror();
		}

		private static void Mirror()
		{
			foreach (PlayerCharacterMasterController instance in PlayerCharacterMasterController.instances)
			{
				CharacterMaster master = instance.master;
				if (Object.op_Implicit((Object)(object)master) && master.money != lastSyncedMoney)
				{
					master.money = lastSyncedMoney;
				}
			}
		}

		internal static void FixedUpdate()
		{
			if (!Enabled)
			{
				return;
			}
			EnsureInitialized();
			double num = 0.0;
			foreach (PlayerCharacterMasterController instance in PlayerCharacterMasterController.instances)
			{
				CharacterMaster master = instance.master;
				if (Object.op_Implicit((Object)(object)master))
				{
					num += (double)master.money - (double)lastSyncedMoney;
				}
			}
			pool = Math.Max(0.0, pool + num);
			lastSyncedMoney = (uint)pool;
			Mirror();
		}
	}
}