Decompiled source of Megalomania v0.1.1

plugins/MegalomaniaPlugin.dll

Decompiled 7 hours ago
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.Versioning;
using System.Security;
using System.Security.Permissions;
using BepInEx;
using BepInEx.Configuration;
using BepInEx.Logging;
using Microsoft.CodeAnalysis;
using On.RoR2;
using R2API;
using R2API.Utils;
using RoR2;
using RoR2.Projectile;
using UnityEngine;
using UnityEngine.Networking;

[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("MegalomaniaPlugin")]
[assembly: AssemblyConfiguration("Debug")]
[assembly: AssemblyFileVersion("1.0.0.0")]
[assembly: AssemblyInformationalVersion("1.0.0+daf3ecaab7438110571a7b6e64587794ec71735a")]
[assembly: AssemblyProduct("MegalomaniaPlugin")]
[assembly: AssemblyTitle("MegalomaniaPlugin")]
[assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)]
[assembly: AssemblyVersion("1.0.0.0")]
[module: UnverifiableCode]
[module: RefSafetyRules(11)]
namespace Microsoft.CodeAnalysis
{
	[CompilerGenerated]
	[Microsoft.CodeAnalysis.Embedded]
	internal sealed class EmbeddedAttribute : Attribute
	{
	}
}
namespace System.Runtime.CompilerServices
{
	[CompilerGenerated]
	[Microsoft.CodeAnalysis.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]
	[Microsoft.CodeAnalysis.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]
	[Microsoft.CodeAnalysis.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 MegalomaniaPlugin
{
	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 Error(object data)
		{
			_logSource.LogError(data);
		}

		internal static void Fatal(object data)
		{
			_logSource.LogFatal(data);
		}

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

		internal static void Message(object data)
		{
			_logSource.LogMessage(data);
		}

		internal static void Warning(object data)
		{
			_logSource.LogWarning(data);
		}
	}
	[BepInDependency(/*Could not decode attribute arguments.*/)]
	[BepInDependency(/*Could not decode attribute arguments.*/)]
	[BepInPlugin("A5TR0spud.Megalomania", "Megalomania", "0.1.1")]
	public class MegalomaniaPlugin : BaseUnityPlugin
	{
		public const string PluginGUID = "A5TR0spud.Megalomania";

		public const string PluginAuthor = "A5TR0spud";

		public const string PluginName = "Megalomania";

		public const string PluginVersion = "0.1.1";

		private static ItemDef transformToken;

		private Dictionary<ItemTier, int> parsedRarityPriorityList;

		private Dictionary<ItemIndex, int> parsedItemPriorityList;

		private static ConfigEntry<bool> ConfigCompatibilityMode { get; set; }

		private static ConfigEntry<double> ConfigMaxHealthPerStack { get; set; }

		private static ConfigEntry<double> ConfigRegenPerStack { get; set; }

		private static ConfigEntry<double> ConfigArmorPerStack { get; set; }

		private static ConfigEntry<double> ConfigArmorMax { get; set; }

		private static ConfigEntry<double> ConfigDamagePerStack { get; set; }

		private static ConfigEntry<double> ConfigCritChancePerStack { get; set; }

		private static ConfigEntry<bool> ConfigAttackSpeedType { get; set; }

		private static ConfigEntry<double> ConfigAttackSpeedPerStack { get; set; }

		private static ConfigEntry<double> ConfigAttackSpeedBonusCap { get; set; }

		private static ConfigEntry<bool> ConfigMovementSpeedType { get; set; }

		private static ConfigEntry<double> ConfigMovementSpeedPerStack { get; set; }

		private static ConfigEntry<double> ConfigMovementSpeedBonusCap { get; set; }

		private static ConfigEntry<bool> ConfigEnableBombs { get; set; }

		private static ConfigEntry<bool> ConfigBombStacking { get; set; }

		private static ConfigEntry<bool> ConfigPassiveBombAttack { get; set; }

		private static ConfigEntry<double> ConfigBombCreationRate { get; set; }

		private static ConfigEntry<double> ConfigBombCreationStackingMultiplier { get; set; }

		private static ConfigEntry<double> ConfigBombCreationStackingAdder { get; set; }

		private static ConfigEntry<double> ConfigBombDamage { get; set; }

		private static ConfigEntry<double> ConfigBombStackingDamage { get; set; }

		private static ConfigEntry<int> ConfigBombCap { get; set; }

		private static ConfigEntry<double> ConfigBombStackingCap { get; set; }

		private static ConfigEntry<double> ConfigBombRange { get; set; }

		private static ConfigEntry<double> ConfigBombStackingRange { get; set; }

		private static ConfigEntry<double> ConfigTransformTime { get; set; }

		private static ConfigEntry<double> ConfigTransformTimePerStack { get; set; }

		private static ConfigEntry<double> ConfigTransformTimeDiminishing { get; set; }

		private static ConfigEntry<double> ConfigTransformTimeMax { get; set; }

		private static ConfigEntry<int> ConfigTransformMaxPerStage { get; set; }

		private static ConfigEntry<int> ConfigTransformMaxPerStageStacking { get; set; }

		private static ConfigEntry<string> ConfigRarityPriorityList { get; set; }

		private static ConfigEntry<string> ConfigItemPriorityList { get; set; }

		public void Awake()
		{
			//IL_0022: Unknown result type (might be due to invalid IL or missing references)
			//IL_002c: Expected O, but got Unknown
			//IL_0052: Unknown result type (might be due to invalid IL or missing references)
			//IL_005c: Expected O, but got Unknown
			//IL_0064: Unknown result type (might be due to invalid IL or missing references)
			//IL_006e: Expected O, but got Unknown
			//IL_0076: Unknown result type (might be due to invalid IL or missing references)
			//IL_0080: Expected O, but got Unknown
			Log.Init(((BaseUnityPlugin)this).Logger);
			CreateConfig();
			ParseRarityPriorityList();
			ItemCatalog.SetItemDefs += new hook_SetItemDefs(ItemCatalog_SetItemDefs);
			HookLunarSunStats();
			if (!ConfigCompatibilityMode.Value)
			{
				InitItems();
				LunarSunBehavior.FixedUpdate += new hook_FixedUpdate(LunarSunBehavior_FixedUpdate);
				LunarSunBehavior.GetMaxProjectiles += new hook_GetMaxProjectiles(LunarSunBehavior_GetMaxProjectiles);
				CharacterMaster.OnServerStageBegin += new hook_OnServerStageBegin(CharacterMaster_OnServerStageBegin);
			}
		}

		private void ItemCatalog_SetItemDefs(orig_SetItemDefs orig, ItemDef[] newItemDefs)
		{
			orig.Invoke(newItemDefs);
			ParseItemPriorityList();
		}

		private void ParseRarityPriorityList()
		{
			//IL_0141: Unknown result type (might be due to invalid IL or missing references)
			//IL_0149: Unknown result type (might be due to invalid IL or missing references)
			//IL_0175: Unknown result type (might be due to invalid IL or missing references)
			parsedRarityPriorityList = new Dictionary<ItemTier, int>();
			string[] array = ConfigRarityPriorityList.Value.Split(',');
			string[] array2 = array;
			foreach (string text in array2)
			{
				string[] array3 = text.Split(":");
				if (array3.Length != 2)
				{
					Log.Warning("Invalid amount of colons: `" + text + "`");
					continue;
				}
				string text2 = array3[0].Trim().ToLower();
				string text3 = array3[1].Trim();
				if (Utility.IsNullOrWhiteSpace(text2) || Utility.IsNullOrWhiteSpace(text3))
				{
					Log.Warning("Invalid empty tier or priority: `" + text + "`");
					continue;
				}
				if (!int.TryParse(text3, out var result) || result < 0)
				{
					Log.Warning("Invalid priority: `" + text + "`");
					continue;
				}
				if (result == 0)
				{
					Log.Info("Blacklisting Rarity:Priority '" + text + "'");
					continue;
				}
				if (!Enum.TryParse<Utils.ItemTierLookup>(text2, out var result2))
				{
					Log.Warning("Invalid rarity: `" + text + "`");
					continue;
				}
				ItemTier key = (ItemTier)result2;
				if (parsedRarityPriorityList.ContainsKey(key))
				{
					Log.Warning("Rarity already in list: `" + text + "`");
					continue;
				}
				parsedRarityPriorityList.Add(key, result);
				Log.Info("Rarity:Priority added! `" + text + "`");
			}
		}

		private void ParseItemPriorityList()
		{
			//IL_00e3: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e8: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ea: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ed: Invalid comparison between Unknown and I4
			//IL_0114: 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)
			parsedItemPriorityList = new Dictionary<ItemIndex, int>();
			string[] array = ConfigItemPriorityList.Value.Split(',');
			string[] array2 = array;
			foreach (string text in array2)
			{
				string[] array3 = text.Split(":");
				if (array3.Length != 2)
				{
					Log.Warning("Invalid amount of colons: `" + text + "`");
					continue;
				}
				string text2 = array3[0].Trim();
				string text3 = array3[1].Trim();
				if (Utility.IsNullOrWhiteSpace(text2) || Utility.IsNullOrWhiteSpace(text3))
				{
					Log.Warning("Invalid empty item or priority: `" + text + "`");
					continue;
				}
				if (!int.TryParse(text3, out var result))
				{
					Log.Warning("Invalid priority: `" + text + "`");
					continue;
				}
				ItemIndex val = ItemCatalog.FindItemIndex(text2);
				if ((int)val == -1)
				{
					Log.Warning("Invalid item: `" + text + "`");
					continue;
				}
				if (parsedItemPriorityList.ContainsKey(val))
				{
					Log.Warning("Item already in list: `" + text + "`");
					continue;
				}
				parsedItemPriorityList.Add(val, result);
				Log.Info("Item:Priority added! `" + text + "`");
			}
		}

		private void InitItems()
		{
			//IL_005d: 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_007f: Expected O, but got Unknown
			//IL_0085: Unknown result type (might be due to invalid IL or missing references)
			//IL_008f: Expected O, but got Unknown
			transformToken = ScriptableObject.CreateInstance<ItemDef>();
			((Object)transformToken).name = "MEGALOMANIA_TOKEN_NAME";
			transformToken.nameToken = "MEGALOMANIA_TOKEN_NAME";
			transformToken.pickupToken = "MEGALOMANIA_TOKEN_PICKUP";
			transformToken.descriptionToken = "MEGALOMANIA_TOKEN_DESC";
			transformToken.loreToken = "MEGALOMANIA_TOKEN_LORE";
			transformToken.deprecatedTier = (ItemTier)5;
			transformToken.canRemove = false;
			transformToken.hidden = true;
			ItemDisplayRuleDict val = new ItemDisplayRuleDict((ItemDisplayRule[])null);
			ItemAPI.Add(new CustomItem(transformToken, val));
		}

		private void CreateConfig()
		{
			ConfigCompatibilityMode = ((BaseUnityPlugin)this).Config.Bind<bool>("0. Main", "Compatibility Mode", false, "If true, skips the hook to override Egocentrism's behavior:\nDisables all bomb stat and transformation changes.\nOther features, including stats (eg. max health), will still work.\nChanging requires a restart.");
			ConfigMaxHealthPerStack = ((BaseUnityPlugin)this).Config.Bind<double>("1. Stats - Defensive", "Stacking Max Health", 5.0, "A flat amount added to max health per stack.");
			ConfigRegenPerStack = ((BaseUnityPlugin)this).Config.Bind<double>("1. Stats - Defensive", "Stacking Regeneration", 0.3, "A flat amount added to base regeneration per stack. Measured in health per second.");
			ConfigArmorPerStack = ((BaseUnityPlugin)this).Config.Bind<double>("1. Stats - Defensive", "Stacking Armor", 2.0, "A flat amount added to armor per stack.");
			ConfigArmorMax = ((BaseUnityPlugin)this).Config.Bind<double>("1. Stats - Defensive", "Stacking Armor Cap", 200.0, "Used to determine maximum armor benefit from stacking.\nSet cap to a negative value to disable the cap.");
			ConfigDamagePerStack = ((BaseUnityPlugin)this).Config.Bind<double>("2. Stats - Offensive", "Stacking Damage", 0.02, "A percentage increase to damage per stack.");
			ConfigCritChancePerStack = ((BaseUnityPlugin)this).Config.Bind<double>("2. Stats - Offensive", "Stacking Crit Chance", 0.01, "A percentage increase to critical hit chance per stack.");
			ConfigAttackSpeedType = ((BaseUnityPlugin)this).Config.Bind<bool>("2. Stats - Offensive", "Attack Speed Diminishing Returns", false, "If true, attack speed will have dimishing returns, with the limit towards infinity approaching the bonus cap.\nIf false, attack speed will stack linearly and cap at the bonus cap.");
			ConfigAttackSpeedPerStack = ((BaseUnityPlugin)this).Config.Bind<double>("2. Stats - Offensive", "Stacking Attack Speed", 0.028, "A percentage used to determine how much attack speed is given per item stack.");
			ConfigAttackSpeedBonusCap = ((BaseUnityPlugin)this).Config.Bind<double>("2. Stats - Offensive", "Bonus Attack Speed Cap", -1.0, "A percentage used to determine the maximum attack speed boost from Egocentrism stacking.\nIn linear mode, set cap to a negative value to disable the cap.\nIn any mode, set cap to 0 to disable attack speed bonus entirely.");
			ConfigMovementSpeedType = ((BaseUnityPlugin)this).Config.Bind<bool>("3. Stats - Movement Speed", "Movement Speed Diminishing Returns", true, "If true, movement speed will have dimishing returns, with the limit towards infinity approaching the bonus cap.\nIf false, movement speed will stack linearly and cap at the bonus cap.");
			ConfigMovementSpeedPerStack = ((BaseUnityPlugin)this).Config.Bind<double>("3. Stats - Movement Speed", "Stacking Movement Speed", 0.028, "A percentage used to determine how much speed is given per item stack.");
			ConfigMovementSpeedBonusCap = ((BaseUnityPlugin)this).Config.Bind<double>("3. Stats - Movement Speed", "Bonus Movement Speed Cap", 9.0, "A percentage used to determine the maximum speed boost from Egocentrism stacking.\nIn linear mode, set cap to a negative value to disable the cap.\nIn any mode, set cap to 0 to disable speed bonus entirely.");
			ConfigEnableBombs = ((BaseUnityPlugin)this).Config.Bind<bool>("4. Bombs - Toggles", "Enable Bomb Generation", true, "Should bombs be generated over time at all?");
			ConfigBombStacking = ((BaseUnityPlugin)this).Config.Bind<bool>("4. Bombs - Toggles", "Bomb Stacking", false, "If true, the amount of bombs currently orbiting the player is used instead of the amount of Egocentrism, for stacking calculations of player stats.");
			ConfigPassiveBombAttack = ((BaseUnityPlugin)this).Config.Bind<bool>("4. Bombs - Toggles", "Passive Bomb Attack", true, "Whether the vanilla seeking behavior should apply.");
			ConfigBombCreationRate = ((BaseUnityPlugin)this).Config.Bind<double>("5. Bombs - Stats", "Initial Bomb Creation Rate", 3.0, "How many seconds it takes to generate a bomb at stack size 1.");
			ConfigBombCreationStackingMultiplier = ((BaseUnityPlugin)this).Config.Bind<double>("5. Bombs - Stats", "Bomb Creation Stacking Multiplier", 1.0, "Scales the rate at which additional stacks decrease cooldown.\nLower values require more Egocentrism to reduce the cooldown by the same amount.\nFor example, 0.5 would require 2x as many stacks to reduce the time by the same amount.");
			ConfigBombCreationStackingAdder = ((BaseUnityPlugin)this).Config.Bind<double>("5. Bombs - Stats", "Bomb Creation Stacking Adder", 0.0, "Time to add to bomb creation rate per stack. Can be negative.");
			ConfigBombDamage = ((BaseUnityPlugin)this).Config.Bind<double>("5. Bombs - Stats", "Initial Bomb Damage", 2.0, "A percentage of damage the bombs should do at stack size 1. Vanilla is 3.6 (360%).");
			ConfigBombStackingDamage = ((BaseUnityPlugin)this).Config.Bind<double>("5. Bombs - Stats", "Stacking Bomb Damage", 0.1, "How much damage to add to each bomb per stack.");
			ConfigBombCap = ((BaseUnityPlugin)this).Config.Bind<int>("5. Bombs - Stats", "Initial Bomb Cap", 3, "How many bombs can be generated at stack size 1.");
			ConfigBombStackingCap = ((BaseUnityPlugin)this).Config.Bind<double>("5. Bombs - Stats", "Stacking Bomb Cap", 1.0, "How many bombs to add to the bomb cap per stack.");
			ConfigBombRange = ((BaseUnityPlugin)this).Config.Bind<double>("5. Bombs - Stats", "Bomb Range", 15.0, "The distance at which bombs can target enemies.");
			ConfigBombStackingRange = ((BaseUnityPlugin)this).Config.Bind<double>("5. Bombs - Stats", "Stacking Bomb Range", 1.0, "The distance to add to bomb range per stack.");
			ConfigTransformTime = ((BaseUnityPlugin)this).Config.Bind<double>("5. Transform - When to Transform", "Default Transform Timer", 0.0, "The time it takes for Egocentrism to transform another item.\nIf this is set to 0, behavior is overriden to happen on entering a new stage instead of over time, like Benthic Bloom.\nMinimum allowed value is 1/60th of a second.");
			ConfigTransformTimePerStack = ((BaseUnityPlugin)this).Config.Bind<double>("5. Transform - When to Transform", "Flat Time Per Stack", 0.0, "Time to add to transform timer per stack. Can be negative.\nIgnored if Default Transform Timer is 0");
			ConfigTransformTimeDiminishing = ((BaseUnityPlugin)this).Config.Bind<double>("5. Transform - When to Transform", "Multiplier Per Stack", 0.9, "Every stack multiplies the transform timer by this value.");
			ConfigTransformTimeMax = ((BaseUnityPlugin)this).Config.Bind<double>("5. Transform - When to Transform", "Max Time", 120.0, "The maximum time Egocentrism can take before transforming an item.\nAnything less than 1/60th of a second is forced back up to 1/60th of a second.");
			ConfigTransformMaxPerStage = ((BaseUnityPlugin)this).Config.Bind<int>("5. Transform - When to Transform", "Max Transforms Per Stage", 5, "Caps how many transformations can happen per stage.\nSet negative to disable cap, unless Default Transform Timer is 0.");
			ConfigTransformMaxPerStageStacking = ((BaseUnityPlugin)this).Config.Bind<int>("5. Transform - When to Transform", "Max Transforms Per Stage Per Stack", 0, "How many transformations to add to the cap per stack.\nThe system is intelligent and won't count stacks added by conversion from the current stage.");
			ConfigRarityPriorityList = ((BaseUnityPlugin)this).Config.Bind<string>("6. Transform - Rules", "Rarity:Priority List", "voidyellow:50, voidred:40, red:40, yellow:30, voidgreen:20, green:20, voidwhite:10, white:10, blue:0", "A priority of 0 or a negative priority blacklists that tier from Egocentrism.\nIf a rarity is not listed here, it cannot be converted by Egocentrism.\nHigher numbers means Egocentrism is more conditioned to select that tier of item.\nFormat: tier1:integer, tier2:int, tier3:i, etc\nCase insensitive, mostly whitespace insensitive.\nValid Tiers:\nwhite,green,red,blue,yellow,voidwhite,voidgreen,voidred,voidyellow,\ncommon,uncommon,legendary,lunar,boss,voidcommon,voiduncommon,voidlegendary,voidboss");
			ConfigItemPriorityList = ((BaseUnityPlugin)this).Config.Bind<string>("6. Transform - Rules", "Item:Priority List", "BeetleGland:5, GhostOnKill:5, MinorConstructOnKill:5, RoboBallBuddy:10, ScrapGreen:15, ScrapWhite:10, ScrapYellow:5, ScrapRed:1, RegeneratingScrap:-10, ExtraStatsOnLevelUp:20, FreeChest:-19, ExtraShrineItem:10, CloverVoid:-15, LowerPricedChests:-19, ResetChests:-5", "A priority of 0 blacklists that item from Egocentrism.\nCan be negative. If negative is of a greater magnitude than the rarity, the item is blacklisted.\nIf a rarity that an item is part of is blacklisted but the item shows up in this list with a positive value, that item won't be blacklisted.\nIf a rarity is not listed here, its priority is determined exclusively by its tier.\nHigher numbers means Egocentrism is more conditioned to select that item.\nFormat: item1:integer, item2:int, item3:i, etc\nCase sensitive, somewhat whitespace sensitive.\nThe diplay name might not always equal the codename of the item.\nFor example: Wax Quail = JumpBoost. To find the name out for yourself, download the DebugToolkit mod, open the console (ctrl + alt + backtick (`)) and type in \"list_item\"");
			ConfigCleanup();
		}

		private void ConfigCleanup()
		{
			Dictionary<ConfigDefinition, string> propertyValue = Reflection.GetPropertyValue<Dictionary<ConfigDefinition, string>>((object)((BaseUnityPlugin)this).Config, "OrphanedEntries");
			propertyValue.Clear();
			((BaseUnityPlugin)this).Config.Save();
		}

		private void HookLunarSunStats()
		{
			//IL_0008: Unknown result type (might be due to invalid IL or missing references)
			//IL_0012: Expected O, but got Unknown
			RecalculateStatsAPI.GetStatCoefficients += (StatHookEventHandler)delegate(CharacterBody sender, StatHookEventArgs args)
			{
				if (Object.op_Implicit((Object)(object)sender) && Object.op_Implicit((Object)(object)sender.inventory))
				{
					int num = ((!ConfigBombStacking.Value) ? sender.inventory.GetItemCount(Items.LunarSun) : sender.master.GetDeployableCount((DeployableSlot)16));
					if (num > 0)
					{
						args.baseHealthAdd += (float)num * (float)ConfigMaxHealthPerStack.Value;
						args.baseRegenAdd += (float)num * (float)ConfigRegenPerStack.Value;
						args.baseMoveSpeedAdd += determineStatBoost(ConfigMovementSpeedType.Value, (float)ConfigMovementSpeedPerStack.Value, (float)ConfigMovementSpeedBonusCap.Value, num);
						args.baseDamageAdd += (float)num * (float)ConfigDamagePerStack.Value;
						args.attackSpeedMultAdd += determineStatBoost(ConfigAttackSpeedType.Value, (float)ConfigAttackSpeedPerStack.Value, (float)ConfigAttackSpeedBonusCap.Value, num);
						args.critAdd += (float)num * (float)ConfigCritChancePerStack.Value;
						float num2 = (float)num * (float)ConfigArmorPerStack.Value;
						if (ConfigArmorMax.Value > 0.0)
						{
							num2 = Math.Min(num2, (float)ConfigArmorMax.Value);
						}
						args.armorAdd += num2;
					}
				}
			};
		}

		private float determineStatBoost(bool diminishing, float perStack, float max, float stacksize)
		{
			if (max == 0f)
			{
				return 0f;
			}
			if (diminishing)
			{
				return max - max * (float)Math.Pow(1f - perStack / max, stacksize);
			}
			if (max > 0f)
			{
				return Math.Min(perStack * stacksize, max);
			}
			return perStack * stacksize;
		}

		private void LunarSunBehavior_FixedUpdate(orig_FixedUpdate orig, LunarSunBehavior self)
		{
			CharacterBody fieldValue = Reflection.GetFieldValue<CharacterBody>((object)self, "body");
			GameObject fieldValue2 = Reflection.GetFieldValue<GameObject>((object)self, "projectilePrefab");
			int fieldValue3 = Reflection.GetFieldValue<int>((object)self, "stack");
			float fieldValue4 = Reflection.GetFieldValue<float>((object)self, "projectileTimer");
			float transformTimer = Reflection.GetFieldValue<float>((object)self, "transformTimer");
			Xoroshiro128Plus fieldValue5 = Reflection.GetFieldValue<Xoroshiro128Plus>((object)self, "transformRng");
			fieldValue4 += Time.fixedDeltaTime;
			handleBombs(fieldValue, ref fieldValue4, fieldValue3, fieldValue2);
			if (ConfigTransformTime.Value > 0.0)
			{
				handleTransUpdate(fieldValue, ref transformTimer, fieldValue3, fieldValue5);
			}
			Reflection.SetFieldValue<float>((object)self, "projectileTimer", fieldValue4);
			Reflection.SetFieldValue<float>((object)self, "transformTimer", transformTimer);
		}

		private int LunarSunBehavior_GetMaxProjectiles(orig_GetMaxProjectiles orig, Inventory inventory)
		{
			return (int)((double)ConfigBombCap.Value + (double)(inventory.GetItemCount(Items.LunarSun) - 1) * ConfigBombStackingCap.Value);
		}

		private void handleBombs(CharacterBody body, ref float projectileTimer, int stack, GameObject projectilePrefab)
		{
			//IL_00c8: Unknown result type (might be due to invalid IL or missing references)
			//IL_010e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0134: Unknown result type (might be due to invalid IL or missing references)
			//IL_0139: 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_0145: Unknown result type (might be due to invalid IL or missing references)
			//IL_014f: Unknown result type (might be due to invalid IL or missing references)
			float num = (float)(stack - 1) * (float)ConfigBombCreationStackingMultiplier.Value + 1f;
			if (!ConfigEnableBombs.Value || body.master.IsDeployableLimited((DeployableSlot)16) || !((double)projectileTimer > ConfigBombCreationRate.Value / (double)num + ConfigBombCreationStackingAdder.Value * (double)stack))
			{
				return;
			}
			projectileTimer = 0f;
			ProjectileSphereTargetFinder component = projectilePrefab.GetComponent<ProjectileSphereTargetFinder>();
			if (Object.op_Implicit((Object)(object)component))
			{
				if (ConfigPassiveBombAttack.Value)
				{
					component.lookRange = (float)(ConfigBombRange.Value + ConfigBombStackingRange.Value * (double)(stack - 1));
				}
				else
				{
					component.lookRange = 0f;
				}
			}
			else
			{
				Log.Error("LunarSunBehavior: Unable to modify projectile Range (ProjectileSphereTargetFinder component not found)");
			}
			FireProjectileInfo val = default(FireProjectileInfo);
			val.projectilePrefab = projectilePrefab;
			val.crit = body.RollCrit();
			val.damage = body.damage * (float)(ConfigBombDamage.Value + ConfigBombStackingDamage.Value * (double)stack);
			val.damageColorIndex = (DamageColorIndex)3;
			val.force = 0f;
			val.owner = ((Component)body).gameObject;
			val.position = body.transform.position;
			val.rotation = Quaternion.identity;
			ProjectileManager.instance.FireProjectile(val);
			if (ConfigBombStacking.Value)
			{
				body.statsDirty = true;
			}
		}

		private void handleTransUpdate(CharacterBody body, ref float transformTimer, int stack, Xoroshiro128Plus transformRng)
		{
			//IL_009c: Unknown result type (might be due to invalid IL or missing references)
			transformTimer += Time.fixedDeltaTime;
			double num = Math.Min(ConfigTransformTime.Value * Math.Pow(ConfigTransformTimeDiminishing.Value, stack) + (double)stack * ConfigTransformTimePerStack.Value, ConfigTransformTimeMax.Value);
			if ((double)transformTimer > num)
			{
				transformTimer = 0f;
				if (Object.op_Implicit((Object)(object)body.master) && Object.op_Implicit((Object)(object)body.inventory) && (ConfigTransformMaxPerStage.Value <= 0 || body.inventory.GetItemCount(transformToken.itemIndex) < ConfigTransformMaxPerStage.Value + (stack - 1) * ConfigTransformMaxPerStageStacking.Value))
				{
					TransformItems(body.inventory, 1, transformRng, body.master);
				}
			}
		}

		private void TransformItems(Inventory inventory, int amount, Xoroshiro128Plus transformRng, CharacterMaster master)
		{
			//IL_0065: Unknown result type (might be due to invalid IL or missing references)
			//IL_006c: Expected O, but got Unknown
			//IL_00a4: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a9: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ab: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b2: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c5: 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: Invalid comparison between Unknown and I4
			//IL_0188: Unknown result type (might be due to invalid IL or missing references)
			//IL_018d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0190: Unknown result type (might be due to invalid IL or missing references)
			//IL_0102: Unknown result type (might be due to invalid IL or missing references)
			//IL_01d3: Unknown result type (might be due to invalid IL or missing references)
			//IL_01da: Unknown result type (might be due to invalid IL or missing references)
			//IL_01e7: Unknown result type (might be due to invalid IL or missing references)
			//IL_0125: Unknown result type (might be due to invalid IL or missing references)
			//IL_01fc: Unknown result type (might be due to invalid IL or missing references)
			//IL_015a: Unknown result type (might be due to invalid IL or missing references)
			if (!NetworkServer.active)
			{
				Log.Warning("[Server] function 'TransformItems' called on client");
			}
			else
			{
				if (!Object.op_Implicit((Object)(object)inventory) || !Object.op_Implicit((Object)(object)master) || amount <= 0)
				{
					return;
				}
				if (transformRng == null)
				{
					transformRng = new Xoroshiro128Plus(Run.instance.seed);
				}
				List<ItemIndex> list = new List<ItemIndex>(inventory.itemAcquisitionOrder);
				int count = list.Count;
				if (count <= 0)
				{
					return;
				}
				Dictionary<ItemIndex, int> dictionary = new Dictionary<ItemIndex, int>();
				int num;
				for (num = 0; num < count; num++)
				{
					ItemIndex val = list[num];
					if (val != Items.LunarSun.itemIndex)
					{
						ItemDef itemDef = ItemCatalog.GetItemDef(val);
						if (Object.op_Implicit((Object)(object)itemDef) && (int)itemDef.tier != 5)
						{
							int value = 0;
							if (!parsedRarityPriorityList.TryGetValue(itemDef.tier, out value))
							{
								value = 0;
							}
							int value2 = 1;
							if (!parsedItemPriorityList.TryGetValue(val, out value2) || value2 != 0)
							{
								value += value2;
								if (value > 0)
								{
									dictionary.Add(val, value);
								}
							}
						}
					}
					num++;
				}
				while (amount > 0)
				{
					ItemIndex randomWeightedDictKey = getRandomWeightedDictKey(dictionary, transformRng);
					inventory.RemoveItem(randomWeightedDictKey, 1);
					inventory.GiveItem(Items.LunarSun, 1);
					if (ConfigTransformMaxPerStage.Value > 0)
					{
						inventory.GiveItem(transformToken, 1 + ConfigTransformMaxPerStageStacking.Value);
					}
					CharacterMasterNotificationQueue.SendTransformNotification(master, randomWeightedDictKey, Items.LunarSun.itemIndex, (TransformationType)4);
					if (inventory.GetItemCount(randomWeightedDictKey) <= 0)
					{
						dictionary.Remove(randomWeightedDictKey);
					}
					amount--;
				}
			}
		}

		private static T getRandomWeightedDictKey<T>(Dictionary<T, int> dict, Xoroshiro128Plus rng)
		{
			int num = 0;
			foreach (int value in dict.Values)
			{
				num += value;
			}
			int num2 = rng.RangeInt(0, num);
			foreach (KeyValuePair<T, int> item in dict)
			{
				num2 -= item.Value;
				if (num2 < 0)
				{
					return item.Key;
				}
			}
			Log.Error("Couldn't return a random weighted dictionary key! This shouldn't happen if all weights are positive. Returned FirstOrDefault() instead.");
			return dict.FirstOrDefault().Key;
		}

		[Server]
		private void CharacterMaster_OnServerStageBegin(orig_OnServerStageBegin orig, CharacterMaster self, Stage stage)
		{
			orig.Invoke(self, stage);
			Inventory inventory = self.inventory;
			if (Object.op_Implicit((Object)(object)inventory))
			{
				int itemCount = inventory.GetItemCount(Items.LunarSun);
				if (ConfigTransformTime.Value == 0.0 && itemCount > 0)
				{
					int amount = ConfigTransformMaxPerStage.Value + (itemCount - 1) * ConfigTransformMaxPerStageStacking.Value;
					TransformItems(inventory, amount, null, self);
				}
				int itemCount2 = inventory.GetItemCount(transformToken);
				if (itemCount2 > 0)
				{
					inventory.RemoveItem(transformToken, itemCount2);
				}
			}
		}
	}
	public static class Utils
	{
		public enum ItemTierLookup
		{
			white = 0,
			common = 0,
			green = 1,
			uncommon = 1,
			red = 2,
			legendary = 2,
			blue = 3,
			lunar = 3,
			yellow = 4,
			boss = 4,
			voidwhite = 6,
			voidcommon = 6,
			voidgreen = 7,
			voiduncommon = 7,
			voidred = 8,
			voidlegendary = 8,
			voidyellow = 9,
			voidboss = 9
		}
	}
}