Decompiled source of Enemies Balancer v0.0.1

OutwardEnemiesBalancer.dll

Decompiled 3 weeks ago
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
using System.Runtime.Versioning;
using System.Security;
using System.Security.Permissions;
using System.Text;
using System.Xml;
using System.Xml.Serialization;
using BepInEx;
using BepInEx.Logging;
using HarmonyLib;
using OutwardEnemiesBalancer.Balancing;
using OutwardEnemiesBalancer.Balancing.Internal;
using OutwardEnemiesBalancer.Balancing.Serializable;
using OutwardEnemiesBalancer.Events;
using OutwardEnemiesBalancer.Managers;
using OutwardEnemiesBalancer.Utility.Data;
using OutwardEnemiesBalancer.Utility.Enums;
using OutwardEnemiesBalancer.Utility.Extensions;
using OutwardEnemiesBalancer.Utility.Helpers.Static;
using OutwardModsCommunicator.EventBus;
using OutwardModsCommunicator.Managers;
using SideLoader;
using UnityEngine;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)]
[assembly: AssemblyTitle("OutwardEnemiesBalancer")]
[assembly: AssemblyDescription("")]
[assembly: AssemblyConfiguration("")]
[assembly: AssemblyCompany("")]
[assembly: AssemblyProduct("OutwardEnemiesBalancer")]
[assembly: AssemblyCopyright("Copyright © 2026")]
[assembly: AssemblyTrademark("")]
[assembly: ComVisible(false)]
[assembly: Guid("c5450fe0-edcf-483f-b9ea-4b1ef9d36da7")]
[assembly: AssemblyFileVersion("1.0.0.0")]
[assembly: TargetFramework(".NETFramework,Version=v4.7.2", FrameworkDisplayName = ".NET Framework 4.7.2")]
[assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)]
[assembly: AssemblyVersion("1.0.0.0")]
[module: UnverifiableCode]
namespace OutwardEnemiesBalancer
{
	public class BalancingRule
	{
		public string id;

		public string enemyID;

		public string enemyName;

		public AreaFamily areaFamily;

		public AreaEnum? area;

		public Factions? faction;

		public bool isBoss;

		public bool isBossPawn;

		public bool isStoryBoss;

		public bool isUniqueArenaBoss;

		public bool isUniqueEnemy;

		public List<string> exceptNames;

		public List<string> exceptIds;

		public Dictionary<string, float?> statModifications;

		public ValueModifierType modifierType = ValueModifierType.Scale;

		public BalancingRule(string id = null)
		{
			//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)
			if (string.IsNullOrEmpty(id))
			{
				UID val = UID.Generate();
				this.id = ((UID)(ref val)).Value;
			}
			else
			{
				this.id = id;
			}
			statModifications = new Dictionary<string, float?>();
		}

		public bool Matches(Character character)
		{
			//IL_0019: Unknown result type (might be due to invalid IL or missing references)
			//IL_001e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0064: Unknown result type (might be due to invalid IL or missing references)
			//IL_0069: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a5: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b0: Unknown result type (might be due to invalid IL or missing references)
			//IL_00dc: Unknown result type (might be due to invalid IL or missing references)
			if ((Object)(object)character == (Object)null)
			{
				return false;
			}
			UID uID;
			if (!string.IsNullOrEmpty(enemyID))
			{
				uID = character.UID;
				return ((UID)(ref uID)).Value == enemyID;
			}
			if (!string.IsNullOrEmpty(enemyName) && !character.Name.Equals(enemyName, StringComparison.OrdinalIgnoreCase))
			{
				return false;
			}
			if (exceptIds != null)
			{
				List<string> list = exceptIds;
				uID = character.UID;
				if (list.Contains(((UID)(ref uID)).Value))
				{
					return false;
				}
			}
			if (exceptNames != null && exceptNames.Contains(character.Name))
			{
				return false;
			}
			if (faction.HasValue && character.Faction != faction.Value)
			{
				return false;
			}
			if (area.HasValue)
			{
				Area currentArea = AreaManager.Instance.CurrentArea;
				Area val = AreaManager.Instance.GetArea(area.Value);
				if (currentArea == null || val == null || currentArea.ID != val.ID)
				{
					return false;
				}
			}
			if (areaFamily != null && !AreaFamiliesHelpers.DoesAreaFamilyMatch(areaFamily))
			{
				return false;
			}
			if (isBoss)
			{
				if (!BossRegistryManager.Instance.IsBoss(character))
				{
					return false;
				}
				return true;
			}
			if (BossRegistryManager.Instance.IsBoss(character))
			{
				return false;
			}
			if (isUniqueArenaBoss)
			{
				if (!UniqueArenaBossesHelper.Enemies.TryGetEnum(character, out var _))
				{
					return false;
				}
			}
			else if (BossRegistryManager.Instance.IsBossOfCategory(character, BossCategories.Arena))
			{
				return false;
			}
			if (isStoryBoss)
			{
				if (!StoryBossesHelper.Enemies.TryGetEnum(character, out var _))
				{
					return false;
				}
			}
			else if (BossRegistryManager.Instance.IsBossOfCategory(character, BossCategories.Story))
			{
				return false;
			}
			if (isBossPawn)
			{
				if (!BossPawnsHelper.Enemies.TryGetEnum(character, out var _))
				{
					return false;
				}
			}
			else if (BossRegistryManager.Instance.IsBossOfCategory(character, BossCategories.Pawn))
			{
				return false;
			}
			UniqueEnemies result5;
			if (isUniqueEnemy)
			{
				if (!UniqueEnemiesHelper.Enemies.TryGetEnum(character, out var _))
				{
					return false;
				}
			}
			else if (UniqueEnemiesHelper.Enemies.TryGetEnum(character, out result5))
			{
				return false;
			}
			return true;
		}
	}
	public class FactionRule
	{
		public string id;

		public string enemyID;

		public string enemyName;

		public AreaFamily areaFamily;

		public AreaEnum? area;

		public Factions? targetFaction;

		public Factions newFaction;

		public bool isBoss;

		public bool isBossPawn;

		public bool isStoryBoss;

		public bool isUniqueArenaBoss;

		public bool isUniqueEnemy;

		public List<string> exceptNames;

		public List<string> exceptIds;

		public FactionRule(string id = null)
		{
			//IL_000f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0014: Unknown result type (might be due to invalid IL or missing references)
			if (string.IsNullOrEmpty(id))
			{
				UID val = UID.Generate();
				this.id = ((UID)(ref val)).Value;
			}
			else
			{
				this.id = id;
			}
			exceptNames = new List<string>();
			exceptIds = new List<string>();
		}

		public bool Matches(Character character)
		{
			//IL_0019: Unknown result type (might be due to invalid IL or missing references)
			//IL_001e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0064: Unknown result type (might be due to invalid IL or missing references)
			//IL_0069: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a5: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b0: Unknown result type (might be due to invalid IL or missing references)
			//IL_00dc: Unknown result type (might be due to invalid IL or missing references)
			if ((Object)(object)character == (Object)null)
			{
				return false;
			}
			UID uID;
			if (!string.IsNullOrEmpty(enemyID))
			{
				uID = character.UID;
				return ((UID)(ref uID)).Value == enemyID;
			}
			if (!string.IsNullOrEmpty(enemyName) && !character.Name.Equals(enemyName, StringComparison.OrdinalIgnoreCase))
			{
				return false;
			}
			if (exceptIds != null)
			{
				List<string> list = exceptIds;
				uID = character.UID;
				if (list.Contains(((UID)(ref uID)).Value))
				{
					return false;
				}
			}
			if (exceptNames != null && exceptNames.Contains(character.Name))
			{
				return false;
			}
			if (targetFaction.HasValue && character.Faction != targetFaction.Value)
			{
				return false;
			}
			if (area.HasValue)
			{
				Area currentArea = AreaManager.Instance.CurrentArea;
				Area val = AreaManager.Instance.GetArea(area.Value);
				if (currentArea == null || val == null || currentArea.ID != val.ID)
				{
					return false;
				}
			}
			if (areaFamily != null && !AreaFamiliesHelpers.DoesAreaFamilyMatch(areaFamily))
			{
				return false;
			}
			if (isBoss)
			{
				if (!BossRegistryManager.Instance.IsBoss(character))
				{
					return false;
				}
				return true;
			}
			if (BossRegistryManager.Instance.IsBoss(character))
			{
				return false;
			}
			if (isUniqueArenaBoss)
			{
				if (!UniqueArenaBossesHelper.Enemies.TryGetEnum(character, out var _))
				{
					return false;
				}
			}
			else if (BossRegistryManager.Instance.IsBossOfCategory(character, BossCategories.Arena))
			{
				return false;
			}
			if (isStoryBoss)
			{
				if (!StoryBossesHelper.Enemies.TryGetEnum(character, out var _))
				{
					return false;
				}
			}
			else if (BossRegistryManager.Instance.IsBossOfCategory(character, BossCategories.Story))
			{
				return false;
			}
			if (isBossPawn)
			{
				if (!BossPawnsHelper.Enemies.TryGetEnum(character, out var _))
				{
					return false;
				}
			}
			else if (BossRegistryManager.Instance.IsBossOfCategory(character, BossCategories.Pawn))
			{
				return false;
			}
			UniqueEnemies result5;
			if (isUniqueEnemy)
			{
				if (!UniqueEnemiesHelper.Enemies.TryGetEnum(character, out var _))
				{
					return false;
				}
			}
			else if (UniqueEnemiesHelper.Enemies.TryGetEnum(character, out result5))
			{
				return false;
			}
			return true;
		}
	}
	[BepInPlugin("gymmed.enemies_balancer", "Enemies Balancer", "0.0.1")]
	[BepInDependency(/*Could not decode attribute arguments.*/)]
	[BepInDependency(/*Could not decode attribute arguments.*/)]
	public class OutwardEnemiesBalancer : BaseUnityPlugin
	{
		[HarmonyPatch(typeof(ResourcesPrefabManager), "Load")]
		public class ResourcesPrefabManager_Load
		{
			private static void Postfix(ResourcesPrefabManager __instance)
			{
				BalancingRulesSerializer.Instance.LoadPlayerBalanceRules();
				BalancingRulesSerializer.Instance.LoadFactionRules(PathsManager.DefaultBalanceRulesPath);
			}
		}

		public const string GUID = "gymmed.enemies_balancer";

		public const string NAME = "Enemies Balancer";

		public const string VERSION = "0.0.1";

		public const string EVENTS_LISTENER_GUID = "gymmed.enemies_balancer_*";

		public static string prefix = "[Enemies-Balancer]";

		internal static ManualLogSource Log;

		internal void Awake()
		{
			//IL_001a: Unknown result type (might be due to invalid IL or missing references)
			Log = ((BaseUnityPlugin)this).Logger;
			LogMessage("Hello world from Enemies Balancer 0.0.1!");
			new Harmony("gymmed.enemies_balancer").PatchAll();
			PathsManager.Initialize();
			EventBusRegister.RegisterEvents();
			EventBusSubscriber.AddSubscribers();
			SL.OnSceneLoaded += OnSceneLoaded;
		}

		private void OnSceneLoaded()
		{
			try
			{
				CharacterBalancerManager.Instance.ApplyBalancingRules();
				FactionBalancerManager.Instance.ApplyFactionRules();
			}
			catch (Exception ex)
			{
				LogMessage("Error applying rules: " + ex.Message);
			}
		}

		internal void Update()
		{
		}

		public static void LogMessage(string message)
		{
			Log.LogMessage((object)(prefix + " " + message));
		}

		public static void LogSL(string message)
		{
			SL.Log(prefix + " " + message);
		}

		public static string GetProjectLocation()
		{
			return Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location);
		}
	}
}
namespace OutwardEnemiesBalancer.Utility.Helpers
{
	public abstract class EnemyEnumHelperBase<T> where T : Enum
	{
		protected abstract Dictionary<T, string> EnemyNames { get; }

		public T GetEnumFromCharacter(Character character)
		{
			if ((Object)(object)character == (Object)null)
			{
				return default(T);
			}
			foreach (KeyValuePair<T, string> enemyName in EnemyNames)
			{
				if (character.Name.Equals(enemyName.Value, StringComparison.OrdinalIgnoreCase))
				{
					return enemyName.Key;
				}
			}
			return default(T);
		}

		public string GetEnemyName(T enemy)
		{
			if (!EnemyNames.TryGetValue(enemy, out var value))
			{
				return enemy.ToString();
			}
			return value;
		}
	}
}
namespace OutwardEnemiesBalancer.Utility.Helpers.Static
{
	public static class AreaFamiliesHelpers
	{
		public static AreaFamily GetAreaFamilyByKeyWord(string keyword)
		{
			AreaFamily[] areaFamilies = AreaManager.AreaFamilies;
			foreach (AreaFamily val in areaFamilies)
			{
				string[] familyKeywords = val.FamilyKeywords;
				for (int j = 0; j < familyKeywords.Length; j++)
				{
					if (familyKeywords[j].Equals(keyword, StringComparison.OrdinalIgnoreCase))
					{
						return val;
					}
				}
			}
			return null;
		}

		public static AreaFamily GetAreaFamilyByName(string name)
		{
			AreaFamily[] areaFamilies = AreaManager.AreaFamilies;
			foreach (AreaFamily val in areaFamilies)
			{
				if (val.FamilyName.Equals(name, StringComparison.OrdinalIgnoreCase))
				{
					return val;
				}
			}
			return null;
		}

		public static bool DoesAreaFamilyMatch(AreaFamily family)
		{
			AreaFamily activeAreaFamily = GetActiveAreaFamily();
			if (activeAreaFamily == null || family == null)
			{
				return false;
			}
			if (activeAreaFamily.FamilyName == family.FamilyName)
			{
				return true;
			}
			return false;
		}

		public static AreaFamily GetActiveAreaFamily()
		{
			AreaFamily[] areaFamilies = AreaManager.AreaFamilies;
			foreach (AreaFamily val in areaFamilies)
			{
				string[] familyKeywords = val.FamilyKeywords;
				foreach (string value in familyKeywords)
				{
					if (SceneManagerHelper.ActiveSceneName.Contains(value))
					{
						return val;
					}
				}
			}
			return null;
		}
	}
	public static class AreaHelpers
	{
		public static bool IsAreaInAreaFamily(AreaEnum area)
		{
			//IL_0021: Unknown result type (might be due to invalid IL or missing references)
			AreaFamily[] areaFamilies = AreaManager.AreaFamilies;
			for (int i = 0; i < areaFamilies.Length; i++)
			{
				string[] familyKeywords = areaFamilies[i].FamilyKeywords;
				foreach (string value in familyKeywords)
				{
					if (AreaManager.Instance.GetArea(area).SceneName.Contains(value))
					{
						return true;
					}
				}
			}
			return false;
		}

		public static AreaEnum? GetAreaEnumFromAreaDefaultName(string areaName)
		{
			Area[] areas = AreaManager.Instance.Areas;
			foreach (Area val in areas)
			{
				if (val.DefaultName == areaName)
				{
					return (AreaEnum)val.ID;
				}
			}
			return null;
		}

		public static AreaEnum? GetAreaEnumFromAreaName(string areaName)
		{
			Area[] areas = AreaManager.Instance.Areas;
			foreach (Area val in areas)
			{
				if (val.GetName() == areaName)
				{
					return (AreaEnum)val.ID;
				}
			}
			return null;
		}

		public static AreaEnum GetAreaEnumFromArea(Area area)
		{
			return (AreaEnum)area.ID;
		}

		public static List<AreaEnum> GetAreasFromEnumDictionary<T>(Dictionary<T, string> locations) where T : Enum
		{
			//IL_0045: Unknown result type (might be due to invalid IL or missing references)
			List<AreaEnum> list = new List<AreaEnum>();
			foreach (KeyValuePair<T, string> location in locations)
			{
				Area[] areas = AreaManager.Instance.Areas;
				foreach (Area val in areas)
				{
					if (val.GetName() == location.Value)
					{
						list.Add(GetAreaEnumFromArea(val));
					}
				}
			}
			return list;
		}

		public static HashSet<AreaEnum> GetUniqueAreasFromEnumDictionary<T>(Dictionary<T, string> locations) where T : Enum
		{
			//IL_0045: Unknown result type (might be due to invalid IL or missing references)
			HashSet<AreaEnum> hashSet = new HashSet<AreaEnum>();
			foreach (KeyValuePair<T, string> location in locations)
			{
				Area[] areas = AreaManager.Instance.Areas;
				foreach (Area val in areas)
				{
					if (val.GetName() == location.Value)
					{
						hashSet.Add(GetAreaEnumFromArea(val));
					}
				}
			}
			return hashSet;
		}
	}
	public static class BalancingRuleHelpers
	{
		public static bool TryToFillRuleWithId(BalancingRule rule, EventPayload payload)
		{
			string text = payload.Get<string>(EnemyBalanceParamsHelper.Get(EnemyBalanceParams.BalanceRuleId).key, (string)null);
			if (!string.IsNullOrEmpty(text))
			{
				rule.id = text;
				return true;
			}
			return false;
		}

		public static bool TryToFillRuleWithEnemyId(BalancingRule rule, EventPayload payload, bool enforceNonEmpty = false)
		{
			(string, Type, string) tuple = EnemyBalanceParamsHelper.Get(EnemyBalanceParams.EnemyId);
			string text = payload.Get<string>(tuple.Item1, (string)null);
			if (string.IsNullOrEmpty(text))
			{
				if (enforceNonEmpty)
				{
					OutwardEnemiesBalancer.LogSL("BalancingRuleHelpers@TryToFillRuleWithEnemyId didn't receive " + tuple.Item1 + "!");
				}
				return false;
			}
			rule.enemyID = text;
			return true;
		}

		public static bool TryToFillRuleWithEnemyName(BalancingRule rule, EventPayload payload, bool enforceNonEmpty = false)
		{
			(string, Type, string) tuple = EnemyBalanceParamsHelper.Get(EnemyBalanceParams.EnemyName);
			string text = payload.Get<string>(tuple.Item1, (string)null);
			if (string.IsNullOrEmpty(text))
			{
				if (enforceNonEmpty)
				{
					OutwardEnemiesBalancer.LogSL("BalancingRuleHelpers@TryToFillRuleWithEnemyName didn't receive " + tuple.Item1 + "!");
				}
				return false;
			}
			rule.enemyName = text;
			return true;
		}

		public static bool FillRuleWithEnvironmentConditions(BalancingRule rule, EventPayload payload)
		{
			(string, Type, string) tuple = EnemyBalanceParamsHelper.Get(EnemyBalanceParams.AreaFamily);
			(string, Type, string) tuple2 = EnemyBalanceParamsHelper.Get(EnemyBalanceParams.Faction);
			(string, Type, string) tuple3 = EnemyBalanceParamsHelper.Get(EnemyBalanceParams.AreaEnum);
			rule.areaFamily = payload.Get<AreaFamily>(tuple.Item1, (AreaFamily)null);
			rule.faction = EventPayloadEnumHelper.GetEnum<Factions>(payload, tuple2.Item1, (Factions?)null);
			rule.area = EventPayloadEnumHelper.GetEnum<AreaEnum>(payload, tuple3.Item1, (AreaEnum?)null);
			if (rule.areaFamily == null && !rule.faction.HasValue)
			{
				return rule.area.HasValue;
			}
			return true;
		}

		public static bool FillRuleForStrongEnemyTypes(BalancingRule rule, EventPayload payload)
		{
			(string, Type, string) tuple = EnemyBalanceParamsHelper.Get(EnemyBalanceParams.IsForBosses);
			(string, Type, string) tuple2 = EnemyBalanceParamsHelper.Get(EnemyBalanceParams.IsForBossesPawns);
			(string, Type, string) tuple3 = EnemyBalanceParamsHelper.Get(EnemyBalanceParams.IsForStoryBosses);
			(string, Type, string) tuple4 = EnemyBalanceParamsHelper.Get(EnemyBalanceParams.IsForUniqueArenaBosses);
			(string, Type, string) tuple5 = EnemyBalanceParamsHelper.Get(EnemyBalanceParams.IsForUniqueEnemies);
			rule.isBoss = payload.Get<bool>(tuple.Item1, false);
			rule.isBossPawn = payload.Get<bool>(tuple2.Item1, false);
			rule.isStoryBoss = payload.Get<bool>(tuple3.Item1, false);
			rule.isUniqueArenaBoss = payload.Get<bool>(tuple4.Item1, false);
			rule.isUniqueEnemy = payload.Get<bool>(tuple5.Item1, false);
			if (!rule.isBoss && !rule.isBossPawn && !rule.isStoryBoss && !rule.isUniqueArenaBoss)
			{
				return rule.isUniqueEnemy;
			}
			return true;
		}

		public static bool FillRuleWithExceptions(BalancingRule rule, EventPayload payload)
		{
			(string, Type, string) tuple = EnemyBalanceParamsHelper.Get(EnemyBalanceParams.ExceptIds);
			(string, Type, string) tuple2 = EnemyBalanceParamsHelper.Get(EnemyBalanceParams.ExceptNames);
			rule.exceptIds = payload.Get<List<string>>(tuple.Item1, (List<string>)null);
			rule.exceptNames = payload.Get<List<string>>(tuple2.Item1, (List<string>)null);
			if (rule.exceptIds == null)
			{
				return rule.exceptNames != null;
			}
			return true;
		}

		public static bool FillRuleWithIdExceptions(BalancingRule rule, EventPayload payload)
		{
			rule.exceptIds = payload.Get<List<string>>(EnemyBalanceParamsHelper.Get(EnemyBalanceParams.ExceptIds).key, (List<string>)null);
			return rule.exceptIds != null;
		}

		public static void FillRuleWithStatModifications(BalancingRule rule, EventPayload payload)
		{
			ValueModifierType? @enum = payload.GetEnum<ValueModifierType>(EnemyBalanceParamsHelper.Get(EnemyBalanceParams.ModifierType).key);
			if (@enum.HasValue)
			{
				rule.modifierType = @enum.Value;
			}
			(string, Type, string) tuple = EnemyBalanceParamsHelper.Get(EnemyBalanceParams.StatModifications);
			(string, Type, string) tuple2 = EnemyBalanceParamsHelper.Get(EnemyBalanceParams.StatType);
			(string, Type, string) tuple3 = EnemyBalanceParamsHelper.Get(EnemyBalanceParams.Value);
			Dictionary<string, float?> dictionary = payload.Get<Dictionary<string, float?>>(tuple.Item1, (Dictionary<string, float?>)null);
			if (dictionary != null)
			{
				foreach (KeyValuePair<string, float?> item in dictionary)
				{
					rule.statModifications[item.Key] = item.Value;
				}
			}
			string text = payload.Get<string>(tuple2.Item1, (string)null);
			float? num = payload.Get<float?>(tuple3.Item1, (float?)null);
			if (!string.IsNullOrEmpty(text) && num.HasValue)
			{
				rule.statModifications[text] = num.Value;
			}
		}

		public static void FillRuleWithStatModificationsFromVitalStats(BalancingRule rule, EventPayload payload)
		{
			(string, Type, string) tuple = EnemyBalanceParamsHelper.Get(EnemyBalanceParams.MaxHealth);
			(string, Type, string) tuple2 = EnemyBalanceParamsHelper.Get(EnemyBalanceParams.MaxStamina);
			(string, Type, string) tuple3 = EnemyBalanceParamsHelper.Get(EnemyBalanceParams.MaxMana);
			(string, Type, string) tuple4 = EnemyBalanceParamsHelper.Get(EnemyBalanceParams.HealthRegen);
			(string, Type, string) tuple5 = EnemyBalanceParamsHelper.Get(EnemyBalanceParams.StaminaRegen);
			(string, Type, string) tuple6 = EnemyBalanceParamsHelper.Get(EnemyBalanceParams.ManaRegen);
			AddStatMod(rule, payload, EnemyBalanceStatType.MaxHealth.ToString(), tuple.Item1);
			AddStatMod(rule, payload, EnemyBalanceStatType.MaxStamina.ToString(), tuple2.Item1);
			AddStatMod(rule, payload, EnemyBalanceStatType.MaxMana.ToString(), tuple3.Item1);
			AddStatMod(rule, payload, EnemyBalanceStatType.HealthRegen.ToString(), tuple4.Item1);
			AddStatMod(rule, payload, EnemyBalanceStatType.StaminaRegen.ToString(), tuple5.Item1);
			AddStatMod(rule, payload, EnemyBalanceStatType.ManaRegen.ToString(), tuple6.Item1);
		}

		private static void AddStatMod(BalancingRule rule, EventPayload payload, string statName, string paramKey)
		{
			float? num = payload.Get<float?>(paramKey, (float?)null);
			if (num.HasValue)
			{
				rule.statModifications[statName] = num.Value;
			}
		}

		public static void FillRuleWithStatModificationsFromEnvironmentalStats(BalancingRule rule, EventPayload payload)
		{
			(string, Type, string) tuple = EnemyBalanceParamsHelper.Get(EnemyBalanceParams.ColdProtection);
			(string, Type, string) tuple2 = EnemyBalanceParamsHelper.Get(EnemyBalanceParams.HeatProtection);
			(string, Type, string) tuple3 = EnemyBalanceParamsHelper.Get(EnemyBalanceParams.CorruptionResistance);
			(string, Type, string) tuple4 = EnemyBalanceParamsHelper.Get(EnemyBalanceParams.Waterproof);
			AddStatMod(rule, payload, EnemyBalanceStatType.ColdProtection.ToString(), tuple.Item1);
			AddStatMod(rule, payload, EnemyBalanceStatType.HeatProtection.ToString(), tuple2.Item1);
			AddStatMod(rule, payload, EnemyBalanceStatType.CorruptionProtection.ToString(), tuple3.Item1);
			AddStatMod(rule, payload, EnemyBalanceStatType.Waterproof.ToString(), tuple4.Item1);
		}

		public static void FillRuleWithStatModificationsFromCombatStats(BalancingRule rule, EventPayload payload)
		{
			(string, Type, string) tuple = EnemyBalanceParamsHelper.Get(EnemyBalanceParams.Impact);
			(string, Type, string) tuple2 = EnemyBalanceParamsHelper.Get(EnemyBalanceParams.ImpactResistance);
			(string, Type, string) tuple3 = EnemyBalanceParamsHelper.Get(EnemyBalanceParams.MovementSpeed);
			(string, Type, string) tuple4 = EnemyBalanceParamsHelper.Get(EnemyBalanceParams.AttackSpeed);
			AddStatMod(rule, payload, EnemyBalanceStatType.Impact.ToString(), tuple.Item1);
			AddStatMod(rule, payload, EnemyBalanceStatType.ImpactResistance.ToString(), tuple2.Item1);
			AddStatMod(rule, payload, EnemyBalanceStatType.MovementSpeed.ToString(), tuple3.Item1);
			AddStatMod(rule, payload, EnemyBalanceStatType.AttackSpeed.ToString(), tuple4.Item1);
		}

		public static bool ValidateAndAppendRule(BalancingRule rule)
		{
			if (string.IsNullOrEmpty(rule.enemyID) && string.IsNullOrEmpty(rule.enemyName) && rule.areaFamily == null && !rule.faction.HasValue && !rule.area.HasValue && !rule.isBoss && !rule.isBossPawn && !rule.isStoryBoss && !rule.isUniqueArenaBoss && !rule.isUniqueEnemy)
			{
				OutwardEnemiesBalancer.LogSL("BalancingRuleHelpers@ValidateAndAppendRule: Rule has no targeting criteria!");
				return false;
			}
			if (rule.statModifications.Count == 0)
			{
				OutwardEnemiesBalancer.LogSL("BalancingRuleHelpers@ValidateAndAppendRule: Rule has no stat modifications!");
				return false;
			}
			BalancingRuleRegistryManager.Instance.AppendBalancingRule(rule);
			return true;
		}
	}
	public static class EventPayloadEnumHelper
	{
		public static T? GetEnum<T>(this EventPayload payload, string key, T? defaultValue = null) where T : struct, Enum
		{
			if (!((Dictionary<string, object>)(object)payload).TryGetValue(key, out object value))
			{
				return defaultValue;
			}
			if (!TryConvertToEnum<T>(value, out var result))
			{
				return defaultValue;
			}
			return result;
		}

		public static T GetEnum<T>(this EventPayload payload, string key, T defaultValue) where T : struct, Enum
		{
			if (!((Dictionary<string, object>)(object)payload).TryGetValue(key, out object value))
			{
				return defaultValue;
			}
			if (!TryConvertToEnum<T>(value, out var result))
			{
				return defaultValue;
			}
			return result;
		}

		public static bool TryGetEnum<T>(this EventPayload payload, string key, out T result) where T : struct, Enum
		{
			result = default(T);
			if (!((Dictionary<string, object>)(object)payload).TryGetValue(key, out object value))
			{
				return false;
			}
			return TryConvertToEnum<T>(value, out result);
		}

		private static bool TryConvertToEnum<T>(object value, out T result) where T : struct, Enum
		{
			result = default(T);
			if (value is T val)
			{
				if (!Enum.IsDefined(typeof(T), val))
				{
					OutwardEnemiesBalancer.LogSL($"EventPayloadEnumHelper: Value '{val}' is not a valid {typeof(T).Name} enum value.");
					return false;
				}
				result = val;
				return true;
			}
			if (value is string text)
			{
				if (Enum.TryParse<T>(text, ignoreCase: true, out var result2))
				{
					if (!Enum.IsDefined(typeof(T), result2))
					{
						OutwardEnemiesBalancer.LogSL("EventPayloadEnumHelper: Value '" + text + "' is not a valid " + typeof(T).Name + " enum value.");
						return false;
					}
					result = result2;
					return true;
				}
				OutwardEnemiesBalancer.LogSL("EventPayloadEnumHelper: Could not parse '" + text + "' to " + typeof(T).Name + " enum.");
				return false;
			}
			OutwardEnemiesBalancer.LogSL("EventPayloadEnumHelper: Cannot convert " + (value?.GetType().Name ?? "null") + " to " + typeof(T).Name + " enum.");
			return false;
		}
	}
}
namespace OutwardEnemiesBalancer.Utility.Extensions
{
	public static class EnemyHelperExtensions
	{
		public static Dictionary<TEnum, TResult> ToDictionaryBySelector<TEnum, TResult>(this Dictionary<TEnum, EnemyIdentificationGroupData> dict, Func<EnemyIdentificationGroupData, TResult> selector) where TEnum : Enum
		{
			return dict.ToDictionary((KeyValuePair<TEnum, EnemyIdentificationGroupData> kvp) => kvp.Key, (KeyValuePair<TEnum, EnemyIdentificationGroupData> kvp) => selector(kvp.Value));
		}

		public static List<TResult> GetAll<TResult, TEnum>(this Dictionary<TEnum, EnemyIdentificationGroupData> dict, Func<EnemyIdentificationData, TResult> selector) where TEnum : Enum
		{
			return dict.SelectMany((KeyValuePair<TEnum, EnemyIdentificationGroupData> kvp) => kvp.Value.Enemies).Select(selector).Distinct()
				.ToList();
		}

		public static List<string> GetAll<TEnum>(this Dictionary<TEnum, EnemyIdentificationGroupData> dict) where TEnum : Enum
		{
			return dict.GetAll((EnemyIdentificationData e) => e.ID);
		}

		public static bool TryGetEnum<TEnum>(this Dictionary<TEnum, EnemyIdentificationGroupData> dict, Character character, out TEnum result) where TEnum : Enum
		{
			string enumIdentificator = BossRegistryManager.GetEnemyBossIdentificator(character);
			foreach (KeyValuePair<TEnum, EnemyIdentificationGroupData> item in dict)
			{
				if (item.Value.Matches(character, (EnemyIdentificationData idData, Character character) => enumIdentificator.Equals(BossRegistryManager.GetIdentificatorFromEnemyIdentification(idData))))
				{
					result = item.Key;
					return true;
				}
			}
			result = default(TEnum);
			return false;
		}

		public static Dictionary<TEnum, string> GetFirstDisplayNameFromGroup<TEnum>(this Dictionary<TEnum, EnemyIdentificationGroupData> dict) where TEnum : Enum
		{
			return dict.ToDictionary((KeyValuePair<TEnum, EnemyIdentificationGroupData> kvp) => kvp.Key, (KeyValuePair<TEnum, EnemyIdentificationGroupData> kvp) => kvp.Value.Enemies.First().DisplayName);
		}

		public static Dictionary<TEnum, string> GetFirstNameLocFromGroup<TEnum>(this Dictionary<TEnum, EnemyIdentificationGroupData> dict) where TEnum : Enum
		{
			return dict.ToDictionary((KeyValuePair<TEnum, EnemyIdentificationGroupData> kvp) => kvp.Key, (KeyValuePair<TEnum, EnemyIdentificationGroupData> kvp) => kvp.Value.Enemies.First().LocKey);
		}

		public static Dictionary<TEnum, string> GetFirstWikiLocationsFromGroup<TEnum>(this Dictionary<TEnum, EnemyIdentificationGroupData> dict) where TEnum : Enum
		{
			return dict.ToDictionary((KeyValuePair<TEnum, EnemyIdentificationGroupData> kvp) => kvp.Key, (KeyValuePair<TEnum, EnemyIdentificationGroupData> kvp) => kvp.Value.Enemies.First().WikiLocation);
		}

		public static Dictionary<TEnum, string> GetFirstGameLocationsFromGroup<TEnum>(this Dictionary<TEnum, EnemyIdentificationGroupData> dict) where TEnum : Enum
		{
			return dict.ToDictionary((KeyValuePair<TEnum, EnemyIdentificationGroupData> kvp) => kvp.Key, (KeyValuePair<TEnum, EnemyIdentificationGroupData> kvp) => kvp.Value.Enemies.First().GameLocation);
		}

		public static List<string> GetAllDisplayNames<TEnum>(this Dictionary<TEnum, EnemyIdentificationGroupData> dict) where TEnum : Enum
		{
			return dict.GetAll((EnemyIdentificationData e) => e.DisplayName);
		}

		public static List<string> GetAllIds<TEnum>(this Dictionary<TEnum, EnemyIdentificationGroupData> dict) where TEnum : Enum
		{
			return dict.GetAll((EnemyIdentificationData e) => e.ID);
		}

		public static List<string> GetAllGameLocations<TEnum>(this Dictionary<TEnum, EnemyIdentificationGroupData> dict) where TEnum : Enum
		{
			return dict.GetAll((EnemyIdentificationData e) => e.GameLocation);
		}

		public static List<string> GetAllWikiLocations<TEnum>(this Dictionary<TEnum, EnemyIdentificationGroupData> dict) where TEnum : Enum
		{
			return dict.GetAll((EnemyIdentificationData e) => e.WikiLocation);
		}
	}
}
namespace OutwardEnemiesBalancer.Utility.Enums
{
	public enum BossCategories
	{
		Story,
		Arena,
		Pawn
	}
	public struct BossID
	{
		public BossCategories Category;

		public EnemyIdentificationGroupData EnemyData;

		public Enum EnumValue;

		public BossID(BossCategories category, EnemyIdentificationGroupData data, Enum enumValue = null)
		{
			Category = category;
			EnemyData = data;
			EnumValue = enumValue;
		}

		public override string ToString()
		{
			string text = "";
			foreach (EnemyIdentificationData enemy in EnemyData.Enemies)
			{
				text = text + "Name " + enemy.DisplayName + " Id " + enemy.ID + " enum " + EnumValue.ToString();
			}
			return $"{Category}:{text}";
		}
	}
	public enum BossPawns
	{
		Elite_Krypteia_warrior,
		Elite_Krypteia_Witch,
		Elite_Obsidian_Elemental
	}
	public static class BossPawnsHelper
	{
		public static readonly Dictionary<BossPawns, EnemyIdentificationGroupData> Enemies = new Dictionary<BossPawns, EnemyIdentificationGroupData>
		{
			{
				BossPawns.Elite_Krypteia_warrior,
				new EnemyIdentificationGroupData("Balira", "KrypteiaGuard", "name_unpc_balira_01", "AbvgKMnPLUiffB6LzjaguQ", "Tower of Regrets Arena", "Unknown Arena", "CalderaDungeonsBosses")
			},
			{
				BossPawns.Elite_Krypteia_Witch,
				new EnemyIdentificationGroupData("Balira", "KrypteiaMage", "name_unpc_balira_01", "MfBjNPYsvkODdyLjYrlXXw", "Tower of Regrets Arena", "Unknown Arena", "CalderaDungeonsBosses")
			},
			{
				BossPawns.Elite_Obsidian_Elemental,
				new EnemyIdentificationGroupData(new EnemyIdentificationData("Obsidian Elemental", "ObsidianElemental", "Wildlife_ObsidianElemental", "RM13rq4JTEqbuANnncMCKA", "Burning Tree Arena", "Unknown Arena", "EmercarDungeonsBosses"), new EnemyIdentificationData("Obsidian Elemental (1)", "ObsidianElemental", "Wildlife_ObsidianElemental", "Qrq3e4nUpkS8CH3yd8J-ow", "Burning Tree Arena", "Unknown Arena", "EmercarDungeonsBosses"))
			}
		};
	}
	public enum EnemyBalanceParams
	{
		BalanceRuleId,
		EnemyId,
		EnemyName,
		AreaEnum,
		AreaFamily,
		Faction,
		IsForBosses,
		IsForBossesPawns,
		IsForStoryBosses,
		IsForUniqueArenaBosses,
		IsForUniqueEnemies,
		ExceptIds,
		ExceptNames,
		StatModifications,
		ModifierType,
		StatType,
		Value,
		MinClamp,
		MaxClamp,
		MaxHealth,
		MaxStamina,
		MaxMana,
		HealthRegen,
		StaminaRegen,
		ManaRegen,
		DamageType,
		DamageValue,
		ResistanceValue,
		ProtectionValue,
		ColdProtection,
		HeatProtection,
		CorruptionResistance,
		Waterproof,
		Impact,
		ImpactResistance,
		MovementSpeed,
		AttackSpeed,
		LoadBalanceRulesXmlPath,
		StoreBalanceRulesXmlPath,
		NewFaction
	}
	public static class EnemyBalanceParamsHelper
	{
		private static readonly Dictionary<EnemyBalanceParams, (string key, Type type, string description)> _registry = new Dictionary<EnemyBalanceParams, (string, Type, string)>
		{
			[EnemyBalanceParams.BalanceRuleId] = ("balanceRuleId", typeof(string), "Optional. Unique identifier for the balancing rule."),
			[EnemyBalanceParams.EnemyId] = ("enemyId", typeof(string), "Optional. Specific enemy UID to target."),
			[EnemyBalanceParams.EnemyName] = ("enemyName", typeof(string), "Optional. Enemy display name to target."),
			[EnemyBalanceParams.AreaEnum] = ("area", typeof(AreaEnum?), "Optional. Specific area filter."),
			[EnemyBalanceParams.AreaFamily] = ("areaFamily", typeof(AreaFamily), "Optional. Area family (region) filter."),
			[EnemyBalanceParams.Faction] = ("faction", typeof(Factions?), "Optional. Faction filter."),
			[EnemyBalanceParams.IsForBosses] = ("isForBosses", typeof(bool), "Optional. Apply to all bosses."),
			[EnemyBalanceParams.IsForBossesPawns] = ("isForBossPawns", typeof(bool), "Optional. Apply to boss pawns."),
			[EnemyBalanceParams.IsForStoryBosses] = ("isForStoryBosses", typeof(bool), "Optional. Apply to story bosses."),
			[EnemyBalanceParams.IsForUniqueArenaBosses] = ("isForUniqueArenaBosses", typeof(bool), "Optional. Apply to unique arena bosses."),
			[EnemyBalanceParams.IsForUniqueEnemies] = ("isForUniqueEnemies", typeof(bool), "Optional. Apply to unique enemies."),
			[EnemyBalanceParams.ExceptIds] = ("listExceptIds", typeof(List<string>), "Optional. List of enemy UIDs to exclude."),
			[EnemyBalanceParams.ExceptNames] = ("listExceptNames", typeof(List<string>), "Optional. List of enemy names to exclude."),
			[EnemyBalanceParams.StatModifications] = ("statModifications", typeof(Dictionary<string, float?>), "Optional. Dictionary of stat name to value. Use with modifierType for scaling."),
			[EnemyBalanceParams.ModifierType] = ("modifierType", typeof(ValueModifierType), "Optional. Default Scale. How to modify: Direct, Scale, Add."),
			[EnemyBalanceParams.StatType] = ("statType", typeof(string), "Optional. Stat name (string) to modify. Use with value parameter."),
			[EnemyBalanceParams.Value] = ("value", typeof(float?), "Optional. Modification value for single stat."),
			[EnemyBalanceParams.MinClamp] = ("minClamp", typeof(float?), "Optional. Minimum clamp for the result."),
			[EnemyBalanceParams.MaxClamp] = ("maxClamp", typeof(float?), "Optional. Maximum clamp for the result."),
			[EnemyBalanceParams.MaxHealth] = ("maxHealth", typeof(float?), "Optional. Max health modification."),
			[EnemyBalanceParams.MaxStamina] = ("maxStamina", typeof(float?), "Optional. Max stamina modification."),
			[EnemyBalanceParams.MaxMana] = ("maxMana", typeof(float?), "Optional. Max mana modification."),
			[EnemyBalanceParams.HealthRegen] = ("healthRegen", typeof(float?), "Optional. Health regen modification."),
			[EnemyBalanceParams.StaminaRegen] = ("staminaRegen", typeof(float?), "Optional. Stamina regen modification."),
			[EnemyBalanceParams.ManaRegen] = ("manaRegen", typeof(float?), "Optional. Mana regen modification."),
			[EnemyBalanceParams.DamageType] = ("damageType", typeof(Types), "Optional. Damage type for grouped damage event."),
			[EnemyBalanceParams.DamageValue] = ("damageValue", typeof(float?), "Optional. Damage value for grouped damage event."),
			[EnemyBalanceParams.ResistanceValue] = ("resistanceValue", typeof(float?), "Optional. Resistance value for grouped damage event."),
			[EnemyBalanceParams.ProtectionValue] = ("protectionValue", typeof(float?), "Optional. Protection value for grouped damage event."),
			[EnemyBalanceParams.ColdProtection] = ("coldProtection", typeof(float?), "Optional. Cold protection modification."),
			[EnemyBalanceParams.HeatProtection] = ("heatProtection", typeof(float?), "Optional. Heat protection modification."),
			[EnemyBalanceParams.CorruptionResistance] = ("corruptionResistance", typeof(float?), "Optional. Corruption resistance modification."),
			[EnemyBalanceParams.Waterproof] = ("waterproof", typeof(float?), "Optional. Waterproof modification."),
			[EnemyBalanceParams.Impact] = ("impact", typeof(float?), "Optional. Impact damage modification."),
			[EnemyBalanceParams.ImpactResistance] = ("impactResistance", typeof(float?), "Optional. Impact resistance modification."),
			[EnemyBalanceParams.MovementSpeed] = ("movementSpeed", typeof(float?), "Optional. Movement speed modification."),
			[EnemyBalanceParams.AttackSpeed] = ("attackSpeed", typeof(float?), "Optional. Attack speed modification."),
			[EnemyBalanceParams.LoadBalanceRulesXmlPath] = ("filePath", typeof(string), "Required. Path to load balance rules XML."),
			[EnemyBalanceParams.StoreBalanceRulesXmlPath] = ("filePath", typeof(string), "Optional. Path to save balance rules XML."),
			[EnemyBalanceParams.NewFaction] = ("newFaction", typeof(Factions), "Required. The faction to change enemies to.")
		};

		public static (string key, Type type, string description) Get(EnemyBalanceParams param)
		{
			return _registry[param];
		}

		public static (string key, Type type, string description)[] Combine(params object[] items)
		{
			List<(string, Type, string)> list = new List<(string, Type, string)>();
			foreach (object obj in items)
			{
				if (obj is (string, Type, string) item)
				{
					list.Add(item);
					continue;
				}
				if (obj is (string, Type, string)[] collection)
				{
					list.AddRange(collection);
					continue;
				}
				throw new ArgumentException("Unsupported item type: " + obj?.GetType().FullName);
			}
			return list.ToArray();
		}
	}
	public enum StoryBosseses
	{
		Crimson_Avatar,
		Djinn,
		Forge_Master,
		Light_Mender,
		Plague_Doctor
	}
	public static class StoryBossesHelper
	{
		public static readonly Dictionary<StoryBosseses, EnemyIdentificationGroupData> Enemies = new Dictionary<StoryBosseses, EnemyIdentificationGroupData>
		{
			{
				StoryBosseses.Crimson_Avatar,
				new EnemyIdentificationGroupData("Burning Man", "CrimsonAvatar (1)", "Undead_BurningMan", "4eeggsSn2Eyah4IjjqvpYQ", "Scarlet Sanctuary", "Scarlet Sanctuary")
			},
			{
				StoryBosseses.Djinn,
				new EnemyIdentificationGroupData("Gold Lich", "LichGold", "Undead_LichGold", "EwoPQ0iVwkK-XtNuaVPf3g", "Oil Refinery", "Oil Refinery")
			},
			{
				StoryBosseses.Forge_Master,
				new EnemyIdentificationGroupData("Jade Lich", "LichRust", "Undead_LichJade", "shyc5M7b-UGVHBZsJMdP4Q", "Forgotten Research Laboratory", "Forgotten Research Laboratory")
			},
			{
				StoryBosseses.Light_Mender,
				new EnemyIdentificationGroupData("Gold Lich", "LichGold", "Undead_LichGold", "EwoPQ0iVwkK-XtNuaVPf3g", "Spire of Light", "Spire of Light")
			},
			{
				StoryBosseses.Plague_Doctor,
				new EnemyIdentificationGroupData("Jade Lich", "LichJade", "Undead_LichJade", "8sjFFBPMvkuJcrcyIYs-KA", "Dark Ziggurat", "Dark Ziggurat Interior")
			}
		};
	}
	public enum UniqueArenaBosses
	{
		Ash_Giant_Highmonk,
		Brand_Squire,
		Breath_of_Darkness,
		Calixa_Boss,
		Concealed_Knight,
		Elite_Alpha_Tuanosaur,
		Elite_Ash_Giant,
		Elite_Beast_Golem,
		Elite_Boozu,
		Elite_Burning_Man,
		Elite_Crescent_Shark,
		Elite_Crimson_Avatar,
		Elite_Gargoyle_Alchemist,
		Elite_Gargoyle_Mage,
		Elite_Gargoyle_Warrior,
		Elite_Mantis_Shrimp,
		Elite_Sublime_Shell,
		Elite_Torcrab,
		Grandmother,
		Immaculate_Dreamer,
		Immaculates_Bird,
		Light_Mender,
		Plague_Doctor,
		Troglodyte_Queen
	}
	public static class UniqueArenaBossesHelper
	{
		public static readonly Dictionary<UniqueArenaBosses, EnemyIdentificationGroupData> Enemies = new Dictionary<UniqueArenaBosses, EnemyIdentificationGroupData>
		{
			{
				UniqueArenaBosses.Ash_Giant_Highmonk,
				new EnemyIdentificationGroupData("Ash Giant Priest", "EliteAshGiantPriest", "Giant_Priest", "UnIXpnDMzUSfBu4S-ZDgsA", "Giant's Village Arena (south)", "Unknown Arena", "HallowedDungeonsBosses")
			},
			{
				UniqueArenaBosses.Brand_Squire,
				new EnemyIdentificationGroupData("Desert Bandit", "EliteBrandSquire", "Bandit_Desert_Basic", "sb0TOkOPS06jhp56AOYJCw", "Conflux Mountain Arena", "Unknown Arena", "ChersoneseDungeonsBosses")
			},
			{
				UniqueArenaBosses.Breath_of_Darkness,
				new EnemyIdentificationGroupData("Breath of Darkness", "AncientDwellerDark", "Elite_Dweller", "JmeufMpL_E6eYnqCYP2r3w", "The Vault of Stone", "The Vault of Stone")
			},
			{
				UniqueArenaBosses.Calixa_Boss,
				new EnemyIdentificationGroupData("Cyrene", "EliteCalixa", "Cyrene", "eCz766tEIEOWfK81om19wg", "Levant Arena", "Unknown Arena", "AbrassarDungeonsBosses")
			},
			{
				UniqueArenaBosses.Concealed_Knight,
				new EnemyIdentificationGroupData("???", "NewBandit", "name_unpc_unknown_01", "XVuyIaCAVkatv89kId9Uqw", "Shipwreck (Castaway)", "CierzoTutorial", "CierzoTutorial")
			},
			{
				UniqueArenaBosses.Elite_Alpha_Tuanosaur,
				new EnemyIdentificationGroupData("Alpha Tuanosaur", "EliteTuanosaurAlpha", "Wildlife_TuanosaurAlpha", "El8bA54i4E6vZraXsVZMow", "Ziggurat Passage Arena", "Unknown Arena", "HallowedDungeonsBosses")
			},
			{
				UniqueArenaBosses.Elite_Ash_Giant,
				new EnemyIdentificationGroupData(new EnemyIdentificationData("Ash Giant", "EliteAshGiantPaf", "Giant_Guard", "3vXChaIK90qgq03PmsHFCg", "Unknown Arena", "Unknown Arena", "HallowedDungeonsBosses"), new EnemyIdentificationData("Ash Giant", "EliteAshGiantPif", "Giant_Guard", "851czvFVDUaB42CgVzfKdg", "Unknown Arena", "Unknown Arena", "HallowedDungeonsBosses"), new EnemyIdentificationData("Ash Giant", "EliteAshGiantPouf", "Giant_Guard", "kNmmOHZzKU-82F3OoX9NXw", "Unknown Arena", "Unknown Arena", "HallowedDungeonsBosses"))
			},
			{
				UniqueArenaBosses.Elite_Beast_Golem,
				new EnemyIdentificationGroupData("Beast Golem", "EliteBeastGolem", "Golem_Beast", "n83g2QJhwUyUrN469WC4jA", "Parched Shipwrecks Arena", "Unknown Arena", "AbrassarDungeonsBosses")
			},
			{
				UniqueArenaBosses.Elite_Boozu,
				new EnemyIdentificationGroupData("Blade Dancer", "BoozuProudBeast", "Wildlife_BladeDancer", "2Ef5z9OfYkev7M7Oi9GN-A", "Mana Lake Arena", "Unknown Arena", "AntiqueFieldDungeonsBosses")
			},
			{
				UniqueArenaBosses.Elite_Burning_Man,
				new EnemyIdentificationGroupData("Burning Man", "EliteBurningMan", "Undead_BurningMan", "JmeufMpL_E6eYnqCYP2r3w", "Burning Tree Arena", "Unknown Arena", "EmercarDungeonsBosses")
			},
			{
				UniqueArenaBosses.Elite_Crescent_Shark,
				new EnemyIdentificationGroupData(new EnemyIdentificationData("Crescent Shark", "EliteCrescentShark", "Wildlife_CrescentShark", "RM13rq4JTEqbuANnncMCKA", "Electric Lab Arena", "Unknown Arena", "AbrassarDungeonsBosses"), new EnemyIdentificationData("Crescent Shark", "EliteCrescentShark (1)", "Wildlife_CrescentShark", "ElDi5-rvqEqJKcXhEdgwBQ", "Electric Lab Arena", "Unknown Arena", "AbrassarDungeonsBosses"), new EnemyIdentificationData("Crescent Shark", "EliteCrescentShark (2)", "Wildlife_CrescentShark", "z3sfjJtqQEmUZ_S6g2RPIg", "Electric Lab Arena", "Unknown Arena", "AbrassarDungeonsBosses"))
			},
			{
				UniqueArenaBosses.Elite_Crimson_Avatar,
				new EnemyIdentificationGroupData("Burning Man", "CrimsonAvatarElite (1)", "Undead_BurningMan", "JmeufMpL_E6eYnqCYP2r3w", "Vault of Stone Arena", "Unknown Arena", "CalderaDungeonsBosses")
			},
			{
				UniqueArenaBosses.Elite_Gargoyle_Alchemist,
				new EnemyIdentificationGroupData("Shell Horror", "GargoyleBossMelee (1)", "Horror_Shell", "k75QmVu5t0e_zIjHnUFbIQ", "New Sirocco Arena", "Unknown Arena", "CalderaDungeonsBosses")
			},
			{
				UniqueArenaBosses.Elite_Gargoyle_Mage,
				new EnemyIdentificationGroupData("Shell Horror", "GargoyleBossMelee (1)", "Horror_Shell", "AKBYHSSMJUaH9ddLiz_SZA", "New Sirocco Arena", "Unknown Arena", "CalderaDungeonsBosses")
			},
			{
				UniqueArenaBosses.Elite_Gargoyle_Warrior,
				new EnemyIdentificationGroupData("Shell Horror", "GargoyleBossMelee (1)", "Horror_Shell", "Z6yTTWK4u0GjDPfZ9X332A", "New Sirocco Arena", "Unknown Arena", "CalderaDungeonsBosses")
			},
			{
				UniqueArenaBosses.Elite_Mantis_Shrimp,
				new EnemyIdentificationGroupData("Mantis Shrimp", "EliteMantisShrimp", "Wildlife_Shrimp", "RM13rq4JTEqbuANnncMCKA", "Voltaic Hatchery Arena", "Unknown Arena", "ChersoneseDungeonsBosses")
			},
			{
				UniqueArenaBosses.Elite_Sublime_Shell,
				new EnemyIdentificationGroupData("Nicolas", "CageArmorBoss (1)", "Nicolas", "X-dfltOoGUm7YlCE_Li1zQ", "Isolated Windmill Arena", "Unknown Arena", "AntiqueFieldDungeonsBosses")
			},
			{
				UniqueArenaBosses.Elite_Torcrab,
				new EnemyIdentificationGroupData("Wildlife_Torcrab", "TorcrabGiant (1)", "Wildlife_Torcrab", "gQDvpLQh3kimgwMmvXJc4g", "River of Red Arena", "Unknown Arena", "CalderaDungeonsBosses")
			},
			{
				UniqueArenaBosses.Grandmother,
				new EnemyIdentificationGroupData("Ghost", "Grandmother", "Undead_Ghost", "7G5APgUksEGdQrBxKXr04g", "Tower of Regrets Arena", "Unknown Arena", "CalderaDungeonsBosses")
			},
			{
				UniqueArenaBosses.Immaculate_Dreamer,
				new EnemyIdentificationGroupData("Immaculate", "EliteImmaculate", "Horror_Immaculate", "9jsiejBtHkOzeo4tOyyweg", "Cabal of Wind Temple Arena", "Unknown Arena", "EmercarDungeonsBosses")
			},
			{
				UniqueArenaBosses.Immaculates_Bird,
				new EnemyIdentificationGroupData("Immaculate", "EliteSupremeShell (1)", "Horror_Immaculate", "JsyOv_Cwu0K0HlXyZInRQQ", "Immaculate's Camp Arena", "Unknown Arena", "AntiqueFieldDungeonsBosses")
			},
			{
				UniqueArenaBosses.Light_Mender,
				new EnemyIdentificationGroupData("Gold Lich", "LichGold (1)", "Undead_LichGold", "v9mN1u1uMkaxsncBXhIM9A", "Spire of Light", "Unknown Arena", "EmercarDungeonsBosses")
			},
			{
				UniqueArenaBosses.Plague_Doctor,
				new EnemyIdentificationGroupData("Jade Lich", "LichJade (1)", "Undead_LichJade", "GfWl16_MZ0uS7UYIKpS5Lg", "Dark Ziggurat", "Unknown Arena", "EmercarDungeonsBosses")
			},
			{
				UniqueArenaBosses.Troglodyte_Queen,
				new EnemyIdentificationGroupData("Mana Troglodyte", "TroglodyteMana (1)", "Troglodyte_Mana", "pcQlY_whLUCC-FZel18VMg", "Blister Burrow Arena", "Unknown Arena", "ChersoneseDungeonsBosses")
			}
		};
	}
	public enum UniqueEnemies
	{
		Accursed_Wendigo,
		Altered_Gargoyle,
		Ancestral_General,
		Ancestral_Soldier,
		Bloody_Alexis,
		Calygrey_Hero,
		Chromatic_Arcane_Elemental,
		Cracked_Gargoyle,
		Elemental_Parasite,
		Executioner_Bug,
		Ghost_of_Vanasse,
		Giant_Horror,
		Glacial_Tuanosaur,
		Golden_Matriarch,
		Grandmother_Medyse,
		Greater_Grotesque,
		Guardian_of_the_Compass,
		Kazite_Admiral,
		Lightning_Dancer,
		Liquid_Cooled_Golem,
		Luke_the_Pearlescent,
		Mad_Captains_Bones,
		Matriarch_Myrmitaur,
		Quartz_Elemental,
		Razorhorn_Stekosaur,
		Royal_Manticore,
		Rusted_Enforcer,
		Sandrose_Horror,
		She_Who_Speaks,
		That_Annoying_Troglodyte,
		The_Crusher,
		The_First_Cannibal,
		The_Last_Acolyte,
		Thunderbolt_Golem,
		Titanic_Guardian_Mk_7,
		Troglodyte_Archmage,
		Tyrant_of_the_Hive,
		Vile_Illuminator,
		Virulent_Hiveman,
		Volcanic_Gastrocin
	}
	public static class UniqueEnemiesHelper
	{
		public static readonly Dictionary<UniqueEnemies, EnemyIdentificationGroupData> Enemies = new Dictionary<UniqueEnemies, EnemyIdentificationGroupData>
		{
			{
				UniqueEnemies.Accursed_Wendigo,
				new EnemyIdentificationGroupData("Accursed Wendigo", "WendigoAccursed", "Unique_DefEd_Wendigo", "ElxncPIfuEuWkexSKkqFXg", "Corrupted Tombs", "Corrupted Tombs")
			},
			{
				UniqueEnemies.Altered_Gargoyle,
				new EnemyIdentificationGroupData("Altered Gargoyle", "GargoyleAltered", "Unique_DefEd_AlteredGargoyle", "dhQVMNRU5kCIWsWRFYpDdw", "Ziggurat Passage", "Ziggurat Passage")
			},
			{
				UniqueEnemies.Ancestral_General,
				new EnemyIdentificationGroupData("Ancestral General", "SkeletonBig (1)", "Unique_DefEd_AncestorBig", "XVuyIaCAVkatv89kId9Uqw", "Necropolis", "Necropolis")
			},
			{
				UniqueEnemies.Ancestral_Soldier,
				new EnemyIdentificationGroupData("Ancestral Soldier", "SkeletonSmall (1)", "Unique_DefEd_AncestorSmall", "IwZYxBIQZkaXXMWT9HC5nA", "Necropolis", "Necropolis")
			},
			{
				UniqueEnemies.Bloody_Alexis,
				new EnemyIdentificationGroupData("Bloody Alexis", "HumanArmoredThug", "Unique_DefEd_ArmoredThug", "VfYPPb4wcESdDVSiEq4UhA", "Undercity Passage", "Undercity Passage")
			},
			{
				UniqueEnemies.Calygrey_Hero,
				new EnemyIdentificationGroupData("Calygrey Hero", "LionmanElite (1)", "Elite_Calygrey", "pMfhK69Stky7MvE9Ro0XMQ", "Steam Bath Tunnels", "Steam Bath Tunnels")
			},
			{
				UniqueEnemies.Chromatic_Arcane_Elemental,
				new EnemyIdentificationGroupData("Chromatic Arcane Elemental", "ElementalChromatic", "Unique_DefEd_ChromaElemental", "RM13rq4JTEqbuANnncMCKA", "Compromised Mana Transfer Station", "Compromised Mana Transfer Station")
			},
			{
				UniqueEnemies.Cracked_Gargoyle,
				new EnemyIdentificationGroupData("Cracked Gargoyle", "GargoyleCracked", "Unique_DefEd_CrackedGargoyle", "-McLNdZsNEa3itw-ny7YBw", "Ark of the Exiled", "Ark of the Exiled")
			},
			{
				UniqueEnemies.Elemental_Parasite,
				new EnemyIdentificationGroupData("Crescent Shark", "ElementalParasite", "Wildlife_CrescentShark", "YDPy9S-An0-qGuvrJAM8yA", "Crumbling Loading Docks", "Crumbling Loading Docks")
			},
			{
				UniqueEnemies.Executioner_Bug,
				new EnemyIdentificationGroupData("Executioner Bug", "ExecutionerBug", "Unique_DefEd_ExecutionerBug", "MWplmyrxokSXELL63oWcAg", "The Slide", "The Slide")
			},
			{
				UniqueEnemies.Ghost_of_Vanasse,
				new EnemyIdentificationGroupData("Ghost of Vanasse", "GhostOfVanasse", "Undead_GhostVanasse", "R5UngwGS5EGWCH13toZO8Q", "Chersonese", "Chersonese")
			},
			{
				UniqueEnemies.Giant_Horror,
				new EnemyIdentificationGroupData("Giant_Horror", "GiantHorror", "Giant_Horror", "SntMM-EzuE-ptgmqp4qkYQ", "Crumbling Loading Docks", "Crumbling Loading Docks")
			},
			{
				UniqueEnemies.Glacial_Tuanosaur,
				new EnemyIdentificationGroupData("Glacial Tuanosaur", "TuanosaurIce", "Unique_DefEd_GlacialTuano", "1IKBT9DYc0yIkESwKtU40g", "Conflux Chambers", "Conflux Chambers")
			},
			{
				UniqueEnemies.Golden_Matriarch,
				new EnemyIdentificationGroupData("Golden Matriarch", "SpecterMeleeMatriarch", "Unique_DefEd_GoldenMatriarch", "GI-aE4Ry7UOIyAYYk7emFg", "Voltaic Hatchery", "Voltaic Hatchery")
			},
			{
				UniqueEnemies.Grandmother_Medyse,
				new EnemyIdentificationGroupData("Grandmother Medyse", "JellyFishMother", "Unique_DefEd_GrandmotherMedyse", "kp9R4kaoG02YfLdS9ROM4w", "Sulphuric Caverns", "Sulphuric Caverns")
			},
			{
				UniqueEnemies.Greater_Grotesque,
				new EnemyIdentificationGroupData("Greater Grotesque", "ImmaculateHorrorGreater", "Unique_DefEd_GreaterGrotestue", "JmeufMpL_E6eYnqCYP2r3w", "Lost Golem Manufacturing Facility", "Lost Golem Manufacturing Facility")
			},
			{
				UniqueEnemies.Guardian_of_the_Compass,
				new EnemyIdentificationGroupData("Guardian of the Compass", "GolemBoss", "Golem_Basic2", "BINT--E9xUaCgp4onBM54g", "The Walled Garden", "Abrassar")
			},
			{
				UniqueEnemies.Kazite_Admiral,
				new EnemyIdentificationGroupData("Kazite Admiral", "HumanKaziteCaptain", "Unique_DefEd_KaziteCaptain", "XVuyIaCAVkatv89kId9Uqw", "Abandoned Living Quarters", "Abandoned Living Quarters")
			},
			{
				UniqueEnemies.Lightning_Dancer,
				new EnemyIdentificationGroupData("Lightning Dancer", "BladeDancerLight", "Unique_DefEd_LightningDancer", "QRzc3AYY10CWyXOMgrIQTg", "Ancient Foundry", "Ancient Foundry")
			},
			{
				UniqueEnemies.Liquid_Cooled_Golem,
				new EnemyIdentificationGroupData("Liquid-Cooled Golem", "GolemShieldedIce", "Unique_DefEd_LiquidGolem", "8ztut4_yiEmK0-NFLa-XNQ", "Destroyed Test Chambers", "Destroyed Test Chambers")
			},
			{
				UniqueEnemies.Luke_the_Pearlescent,
				new EnemyIdentificationGroupData("Luke the Pearlescent", "NewBanditEquip_WhiteScavengerCaptainBoss_A (1)", "Bandit_Standard_Captain2", "XVuyIaCAVkatv89kId9Uqw", "Ruins of Old Levant", "Abrassar")
			},
			{
				UniqueEnemies.Mad_Captains_Bones,
				new EnemyIdentificationGroupData("Mad Captain's Bones", "SkeletFighter", "Undead_Skeleton2", "JM_HjGXMlkq7a1Yb6gijgQ", "Pirates' Hideout", "Chersonese Misc. Dungeons")
			},
			{
				UniqueEnemies.Matriarch_Myrmitaur,
				new EnemyIdentificationGroupData("Matriarch Myrmitaur", "MyrmElite (1)", "Elite_Myrm", "6sB4_5lOJU2bWuMHnOL4Ww", "Myrmitaur's Haven", "Myrmitaur's Haven")
			},
			{
				UniqueEnemies.Quartz_Elemental,
				new EnemyIdentificationGroupData("Quartz Elemental", "ObsidianElementalQuartz", "Unique_DefEd_QuartzElemental", "LhhpSt8BO0aRN5mbeSuDrw", "The Grotto of Chalcedony", "The Grotto of Chalcedony")
			},
			{
				UniqueEnemies.Razorhorn_Stekosaur,
				new EnemyIdentificationGroupData("Razorhorn Stekosaur", "SteakosaurBlack (1)", "Unique_DefEd_BlackSteko", "03dSXwJMRUuzGu8s3faATQ", "Reptilian Lair", "Reptilian Lair")
			},
			{
				UniqueEnemies.Royal_Manticore,
				new EnemyIdentificationGroupData("The Royal Manticore", "RoyalManticore", "Wildlife_Manticore2", "RM13rq4JTEqbuANnncMCKA", "Enmerkar Forest", "Enmerkar Forest")
			},
			{
				UniqueEnemies.Rusted_Enforcer,
				new EnemyIdentificationGroupData("Rusted Enforcer", "GolemRusted (1)", "Unique_DefEd_RustyGolem", "Ed2bzrgz5k-cRx3bUYTfmg", "Ghost Pass", "Ghost Pass")
			},
			{
				UniqueEnemies.Sandrose_Horror,
				new EnemyIdentificationGroupData("Sandrose Horror", "ShelledHorrorBurning", "Unique_DefEd_SandroseHorror", "H7HoCKhBl0mC1j9UOECDrQ", "Sand Rose Cave", "Sand Rose Cave")
			},
			{
				UniqueEnemies.She_Who_Speaks,
				new EnemyIdentificationGroupData("She Who Speaks", "AncientDwellerSpeak", "Unique_DefEd_BossDweller", "MBooN38mU0GPjQJGRuJ95g", "The Vault of Stone", "The Vault of Stone")
			},
			{
				UniqueEnemies.That_Annoying_Troglodyte,
				new EnemyIdentificationGroupData("That Annoying Troglodyte", "TroglodyteAnnoying", "Unique_DefEd_AnnoyingTrog", "no-Z4ibpcEWbNntm_wRwZA", "Jade Quarry", "Jade Quarry")
			},
			{
				UniqueEnemies.The_Crusher,
				new EnemyIdentificationGroupData("The Crusher", "HumanCrusher (1)", "Unique_DefEd_DesertCrusher", "AZL-EjXmhkOYB1obj0VkTw", "Ancestor's Resting Place", "Ancestor's Resting Place")
			},
			{
				UniqueEnemies.The_First_Cannibal,
				new EnemyIdentificationGroupData("The First Cannibal", "WendigoCanibal", "Wildlife_Wendigo2", "wrYHXXh8J0KMhwoV8AC59w", "Face of the Ancients", "Face of the Ancients")
			},
			{
				UniqueEnemies.The_Last_Acolyte,
				new EnemyIdentificationGroupData("The Last Acolyte", "HumanAcolyte (1)", "Unique_DefEd_LastAcolyte", "YeYzQP-gYUmSivlk5JCJew", "Stone Titan Caves", "Stone Titan Caves")
			},
			{
				UniqueEnemies.Thunderbolt_Golem,
				new EnemyIdentificationGroupData("Thunderbolt Golem", "ForgeGolemLight (1)", "Unique_DefEd_ProtypeForgeGolem", "4qCAJzcAfEKNcl_c2k0r9g", "Electric Lab", "Electric Lab")
			},
			{
				UniqueEnemies.Titanic_Guardian_Mk_7,
				new EnemyIdentificationGroupData(new EnemyIdentificationData("Jade Lich", "TitanGolemHalberd", "Undead_LichJade", "65aI6XT89kmHa1bwJz5PGQ", "Ruined Warehouse", "Ruined Warehouse"), new EnemyIdentificationData("Jade Lich", "TitanGolemHammer", "Undead_LichJade", "G_Q0oH1ttkWAZXCMuaAHjA", "Ruined Warehouse", "Ruined Warehouse"), new EnemyIdentificationData("Jade Lich", "TitanGolemSword", "Undead_LichJade", "wj3frikyIkqwVv7myrc5gw", "Ruined Warehouse", "Ruined Warehouse"))
			},
			{
				UniqueEnemies.Troglodyte_Archmage,
				new EnemyIdentificationGroupData("Troglodyte Archmage", "TroglodyteArcMageDefEd (1)", "Unique_DefEd_TrogMage", "syKWNGT3QUO3nXxPt1WEcQ", "Blister Burrow", "Blister Burrow")
			},
			{
				UniqueEnemies.Tyrant_of_the_Hive,
				new EnemyIdentificationGroupData("Tyrant of the Hive", "HiveLord1AID+", "Undead_Hivelord2", "yOo-iKN3-0mAtZ2pG16pyw", "Forest Hives", "Forest Hives")
			},
			{
				UniqueEnemies.Vile_Illuminator,
				new EnemyIdentificationGroupData("Vile Illuminator", "IlluminatorHorrorVile", "Unique_DefEd_VileIlluminator", "l5ignQfsE0Cv4imB9DZJ5w", "Cabal of Wind Temple", "Cabal of Wind Temple")
			},
			{
				UniqueEnemies.Virulent_Hiveman,
				new EnemyIdentificationGroupData("Virulent Hiveman", "HiveManVirulent", "Unique_DefEd_VirulentHiveman", "v1PnLFpcxEmm_IrZaP-eyg", "Ancient Hive", "Ancient Hive")
			},
			{
				UniqueEnemies.Volcanic_Gastrocin,
				new EnemyIdentificationGroupData("Volcanic Gastrocin", "SlughellVolcanic", "Unique_DefEd_VolcanicSlug", "fEFTRdXp1kOWX-Z9OMAkBg", "The Eldest Brother", "The Eldest Brother")
			}
		};
	}
}
namespace OutwardEnemiesBalancer.Utility.Data
{
	public class EnemyIdentificationData
	{
		public string DisplayName;

		public string InternalName;

		public string LocKey;

		public string ID;

		public string WikiLocation;

		public string GameLocation;

		public string SceneName;

		public EnemyIdentificationData(string Name, string m_name, string m_nameLoc, string id, string wikiLocation, string gameLocation, string sceneName = "")
		{
			DisplayName = Name;
			InternalName = m_name;
			LocKey = m_nameLoc;
			ID = id;
			WikiLocation = wikiLocation;
			GameLocation = gameLocation;
			SceneName = sceneName;
		}

		public bool Matches(Character character, params Func<EnemyIdentificationData, Character, bool>[] comparers)
		{
			//IL_0027: Unknown result type (might be due to invalid IL or missing references)
			//IL_002c: Unknown result type (might be due to invalid IL or missing references)
			if (comparers == null || comparers.Length == 0)
			{
				string iD = ID;
				UID uID = character.UID;
				return string.Equals(iD, ((UID)(ref uID)).Value, StringComparison.Ordinal);
			}
			return comparers.Any((Func<EnemyIdentificationData, Character, bool> c) => c(this, character));
		}
	}
	public class EnemyIdentificationGroupData
	{
		public List<EnemyIdentificationData> Enemies { get; }

		public EnemyIdentificationGroupData(string displayName, string internalName, string locKey, string uid, string wikiLocation, string gameLocation, string sceneName = "")
		{
			Enemies = new List<EnemyIdentificationData>
			{
				new EnemyIdentificationData(displayName, internalName, locKey, uid, wikiLocation, gameLocation, sceneName)
			};
		}

		public EnemyIdentificationGroupData(params EnemyIdentificationData[] entries)
		{
			Enemies = new List<EnemyIdentificationData>();
			Enemies.AddRange(entries);
		}

		public bool Matches(Character character, params Func<EnemyIdentificationData, Character, bool>[] comparers)
		{
			return Enemies.Any((EnemyIdentificationData e) => e.Matches(character, comparers));
		}

		public EnemyIdentificationData GetMatching(Character character)
		{
			return Enemies.FirstOrDefault((EnemyIdentificationData e) => e.Matches(character));
		}
	}
}
namespace OutwardEnemiesBalancer.Managers
{
	public class BalancingRuleRegistryManager
	{
		private static BalancingRuleRegistryManager _instance;

		public List<BalancingRule> balancingRules = new List<BalancingRule>();

		public static BalancingRuleRegistryManager Instance
		{
			get
			{
				if (_instance == null)
				{
					_instance = new BalancingRuleRegistryManager();
				}
				return _instance;
			}
		}

		private BalancingRuleRegistryManager()
		{
		}

		public void AppendBalancingRules(List<BalancingRule> rules)
		{
			foreach (BalancingRule rule in rules)
			{
				AppendBalancingRule(rule);
			}
		}

		public void AppendBalancingRule(BalancingRule rule)
		{
			BalancingRule balancingRule = balancingRules.FirstOrDefault((BalancingRule r) => r.id == rule.id);
			if (balancingRule != null)
			{
				StringBuilder stringBuilder = new StringBuilder();
				stringBuilder.AppendLine("Rule '" + rule.id + "' already exists. Merging stat modifications:");
				stringBuilder.AppendLine("  Old mods: " + CountStats(balancingRule.statModifications));
				stringBuilder.AppendLine("  New mods: " + CountStats(rule.statModifications));
				foreach (KeyValuePair<string, float?> statModification in rule.statModifications)
				{
					float? value;
					string arg = ((!balancingRule.statModifications.TryGetValue(statModification.Key, out value)) ? "added" : "updated");
					balancingRule.statModifications[statModification.Key] = statModification.Value;
					stringBuilder.AppendLine($"    {arg}: {statModification.Key} = {statModification.Value}");
				}
				OutwardEnemiesBalancer.LogSL(stringBuilder.ToString());
			}
			else
			{
				balancingRules.Add(rule);
				EventBusPublisher.SendAppendBalancingRule(rule.id);
			}
		}

		private string CountStats(Dictionary<string, float?> stats)
		{
			if (stats == null)
			{
				return "0";
			}
			return stats.Count.ToString();
		}

		public void RemoveBalancingRuleById(string id)
		{
			foreach (BalancingRule item in balancingRules.Where((BalancingRule rule) => rule.id == id).ToList())
			{
				RemoveBalancingRule(item);
			}
		}

		public void RemoveBalancingRule(BalancingRule rule)
		{
			balancingRules.Remove(rule);
			EventBusPublisher.SendRemoveBalancingRule(rule.id);
		}

		public List<BalancingRule> GetMatchingRules(Character character)
		{
			List<BalancingRule> list = new List<BalancingRule>();
			foreach (BalancingRule balancingRule in balancingRules)
			{
				if (balancingRule.Matches(character))
				{
					list.Add(balancingRule);
				}
			}
			return list;
		}
	}
	public class BalancingRulesSerializer
	{
		private static BalancingRulesSerializer _instance;

		public static BalancingRulesSerializer Instance
		{
			get
			{
				if (_instance == null)
				{
					_instance = new BalancingRulesSerializer();
				}
				return _instance;
			}
		}

		private BalancingRulesSerializer()
		{
		}

		public BalancingRulesFile Load(string path)
		{
			try
			{
				if (!File.Exists(path))
				{
					OutwardEnemiesBalancer.LogSL("BalancingRules file not found at: " + path);
					return null;
				}
				XmlSerializer xmlSerializer = new XmlSerializer(typeof(BalancingRulesFile));
				using FileStream stream = new FileStream(path, FileMode.Open, FileAccess.Read);
				return xmlSerializer.Deserialize(stream) as BalancingRulesFile;
			}
			catch (Exception ex)
			{
				OutwardEnemiesBalancer.LogSL("Failed to load BalancingRules file at '" + path + "': " + ex.Message);
				return null;
			}
		}

		public void LoadPlayerBalanceRules()
		{
			if (File.Exists(PathsManager.DefaultBalanceRulesPath))
			{
				LoadBalanceRules(PathsManager.DefaultBalanceRulesPath);
			}
		}

		public void LoadBalanceRules(string path)
		{
			try
			{
				if (!File.Exists(path))
				{
					OutwardEnemiesBalancer.LogSL("BalancingRulesSerializer@LoadBalanceRules file not found at: " + path);
					return;
				}
				BalancingRulesFile balancingRulesFile = Load(path);
				if (balancingRulesFile != null)
				{
					List<BalancingRule> balancingRules = GetBalancingRules(balancingRulesFile);
					BalancingRuleRegistryManager.Instance.AppendBalancingRules(balancingRules);
				}
			}
			catch (Exception ex)
			{
				OutwardEnemiesBalancer.LogSL("BalancingRulesSerializer@LoadBalanceRules failed loading '" + path + "': " + ex.Message);
			}
		}

		public void SaveBalanceRulesToXml(string filePath, List<BalancingRule> rules)
		{
			try
			{
				string directoryName = Path.GetDirectoryName(filePath);
				if (!string.IsNullOrEmpty(directoryName) && !Directory.Exists(directoryName))
				{
					Directory.CreateDirectory(directoryName);
				}
				BalancingRulesFile o = BuildBalancingRulesFile(rules);
				XmlSerializer xmlSerializer = new XmlSerializer(typeof(BalancingRulesFile));
				XmlWriterSettings settings = new XmlWriterSettings
				{
					Indent = true,
					NewLineOnAttributes = false
				};
				using XmlWriter xmlWriter = XmlWriter.Create(filePath, settings);
				xmlSerializer.Serialize(xmlWriter, o);
			}
			catch (Exception ex)
			{
				OutwardEnemiesBalancer.LogSL("BalancingRulesSerializer@SaveBalanceRulesToXml failed saving '" + filePath + "': " + ex.Message);
			}
		}

		public List<BalancingRule> LoadBalanceRulesFromXmlSync(string path)
		{
			try
			{
				if (!File.Exists(path))
				{
					OutwardEnemiesBalancer.LogSL("LoadBalanceRulesFromXmlSync file not found at: " + path);
					return null;
				}
				BalancingRulesFile balancingRulesFile = Load(path);
				if (balancingRulesFile == null)
				{
					return null;
				}
				return GetBalancingRules(balancingRulesFile);
			}
			catch (Exception ex)
			{
				OutwardEnemiesBalancer.LogSL("LoadBalanceRulesFromXmlSync failed loading '" + path + "': " + ex.Message);
				return null;
			}
		}

		public List<BalancingRule> GetBalancingRules(BalancingRulesFile file)
		{
			//IL_009b: Unknown result type (might be due to invalid IL or missing references)
			List<BalancingRule> list = new List<BalancingRule>();
			foreach (BalancingRuleSerializable rule in file.Rules)
			{
				BalancingRule balancingRule = new BalancingRule(rule.Id);
				balancingRule.enemyID = (string.IsNullOrEmpty(rule.EnemyID) ? null : rule.EnemyID);
				balancingRule.enemyName = rule.EnemyName ?? "";
				balancingRule.areaFamily = AreaFamiliesHelpers.GetAreaFamilyByName(rule.AreaFamilyName);
				balancingRule.area = AreaHelpers.GetAreaEnumFromAreaName(rule.AreaName);
				if (!string.IsNullOrEmpty(rule.FactionName) && Enum.TryParse<Factions>(rule.FactionName, out Factions result))
				{
					balancingRule.faction = result;
				}
				balancingRule.exceptIds = rule.ExceptIds;
				balancingRule.exceptNames = rule.ExceptNames;
				balancingRule.isBoss = rule.IsBoss;
				balancingRule.isBossPawn = rule.IsBossPawn;
				balancingRule.isStoryBoss = rule.IsStoryBoss;
				balancingRule.isUniqueArenaBoss = rule.IsUniqueArenaBoss;
				balancingRule.isUniqueEnemy = rule.IsUniqueEnemy;
				if (rule.StatModifications != null)
				{
					foreach (StatModificationSerializable statModification in rule.StatModifications)
					{
						balancingRule.statModifications[statModification.StatName] = statModification.Value;
					}
				}
				list.Add(balancingRule);
			}
			return list;
		}

		public BalancingRulesFile BuildBalancingRulesFile(List<BalancingRule> rules)
		{
			//IL_0095: 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_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)
			BalancingRulesFile balancingRulesFile = new BalancingRulesFile
			{
				Rules = new List<BalancingRuleSerializable>()
			};
			foreach (BalancingRule rule in rules)
			{
				BalancingRuleSerializable obj = new BalancingRuleSerializable
				{
					Id = (rule.id ?? null),
					EnemyID = (rule.enemyID ?? null),
					EnemyName = (rule.enemyName ?? ""),
					AreaFamilyName = (rule.areaFamily?.FamilyName ?? "")
				};
				ref AreaEnum? area = ref rule.area;
				object obj2;
				if (!area.HasValue)
				{
					obj2 = null;
				}
				else
				{
					AreaEnum valueOrDefault = area.GetValueOrDefault();
					obj2 = ((object)(AreaEnum)(ref valueOrDefault)).ToString();
				}
				if (obj2 == null)
				{
					obj2 = "";
				}
				obj.AreaName = (string)obj2;
				ref Factions? faction = ref rule.faction;
				object obj3;
				if (!faction.HasValue)
				{
					obj3 = null;
				}
				else
				{
					Factions valueOrDefault2 = faction.GetValueOrDefault();
					obj3 = ((object)(Factions)(ref valueOrDefault2)).ToString();
				}
				if (obj3 == null)
				{
					obj3 = "";
				}
				obj.FactionName = (string)obj3;
				obj.ExceptIds = rule.exceptIds ?? null;
				obj.ExceptNames = rule.exceptNames ?? null;
				obj.IsBoss = rule.isBoss;
				obj.IsBossPawn = rule.isBossPawn;
				obj.IsStoryBoss = rule.isStoryBoss;
				obj.IsUniqueArenaBoss = rule.isUniqueArenaBoss;
				obj.IsUniqueEnemy = rule.isUniqueEnemy;
				obj.StatModifications = new List<StatModificationSerializable>();
				BalancingRuleSerializable balancingRuleSerializable = obj;
				foreach (KeyValuePair<string, float?> statModification in rule.statModifications)
				{
					if (statModification.Value.HasValue)
					{
						balancingRuleSerializable.StatModifications.Add(new StatModificationSerializable
						{
							StatName = statModification.Key,
							Value = statModification.Value.Value
						});
					}
				}
				balancingRulesFile.Rules.Add(balancingRuleSerializable);
			}
			return balancingRulesFile;
		}

		public void LoadFactionRules(string path)
		{
			try
			{
				if (!File.Exists(path))
				{
					OutwardEnemiesBalancer.LogSL("FactionRules file not found at: " + path);
					return;
				}
				BalancingRulesFile balancingRulesFile = Load(path);
				if (balancingRulesFile != null && balancingRulesFile.FactionRules != null)
				{
					List<FactionRule> factionRules = GetFactionRules(balancingRulesFile);
					FactionRuleRegistryManager.Instance.AppendFactionRules(factionRules);
				}
			}
			catch (Exception ex)
			{
				OutwardEnemiesBalancer.LogSL("LoadFactionRules failed loading '" + path + "': " + ex.Message);
			}
		}

		public List<FactionRule> GetFactionRules(BalancingRulesFile file)
		{
			//IL_00a5: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ce: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d0: Unknown result type (might be due to invalid IL or missing references)
			List<FactionRule> list = new List<FactionRule>();
			if (file.FactionRules == null)
			{
				return list;
			}
			foreach (FactionRuleSerializable factionRule2 in file.FactionRules)
			{
				FactionRule factionRule = new FactionRule(factionRule2.Id);
				factionRule.enemyID = (string.IsNullOrEmpty(factionRule2.EnemyID) ? null : factionRule2.EnemyID);
				factionRule.enemyName = factionRule2.EnemyName ?? "";
				factionRule.areaFamily = AreaFamiliesHelpers.GetAreaFamilyByName(factionRule2.AreaFamilyName);
				factionRule.area = AreaHelpers.GetAreaEnumFromAreaName(factionRule2.AreaName);
				if (!string.IsNullOrEmpty(factionRule2.TargetFactionName) && Enum.TryParse<Factions>(factionRule2.TargetFactionName, out Factions result))
				{
					factionRule.targetFaction = result;
				}
				if (!string.IsNullOrEmpty(factionRule2.NewFactionName) && Enum.TryParse<Factions>(factionRule2.NewFactionName, out Factions result2))
				{
					factionRule.newFaction = result2;
				}
				factionRule.exceptIds = factionRule2.ExceptIds;
				factionRule.exceptNames = factionRule2.ExceptNames;
				factionRule.isBoss = factionRule2.IsBoss;
				factionRule.isBossPawn = factionRule2.IsBossPawn;
				factionRule.isStoryBoss = factionRule2.IsStoryBoss;
				factionRule.isUniqueArenaBoss = factionRule2.IsUniqueArenaBoss;
				factionRule.isUniqueEnemy = factionRule2.IsUniqueEnemy;
				list.Add(factionRule);
			}
			return list;
		}

		public void SaveFactionRulesToXml(string filePath, List<FactionRule> rules)
		{
			try
			{
				BalancingRulesFile o = BuildFactionRulesFile(rules);
				XmlSerializer xmlSerializer = new XmlSerializer(typeof(BalancingRulesFile));
				XmlWriterSettings settings = new XmlWriterSettings
				{
					Indent = true,
					NewLineOnAttributes = false
				};
				using XmlWriter xmlWriter = XmlWriter.Create(filePath, settings);
				xmlSerializer.Serialize(xmlWriter, o);
			}
			catch (Exception ex)
			{
				OutwardEnemiesBalancer.LogSL("SaveFactionRulesToXml failed saving '" + filePath + "': " + ex.Message);
			}
		}

		public BalancingRulesFile BuildFactionRulesFile(List<FactionRule> rules)
		{
			//IL_0095: 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_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)
			BalancingRulesFile balancingRulesFile = new BalancingRulesFile
			{
				FactionRules = new List<FactionRuleSerializable>()
			};
			foreach (FactionRule rule in rules)
			{
				FactionRuleSerializable obj = new FactionRuleSerializable
				{
					Id = (rule.id ?? null),
					EnemyID = (rule.enemyID ?? null),
					EnemyName = (rule.enemyName ?? ""),
					AreaFamilyName = (rule.areaFamily?.FamilyName ?? "")
				};
				ref AreaEnum? area = ref rule.area;
				object obj2;
				if (!area.HasValue)
				{
					obj2 = null;
				}
				else
				{
					AreaEnum valueOrDefault = area.GetValueOrDefault();
					obj2 = ((object)(AreaEnum)(ref valueOrDefault)).ToString();
				}
				if (obj2 == null)
				{
					obj2 = "";
				}
				obj.AreaName = (string)obj2;
				ref Factions? targetFaction = ref rule.targetFaction;
				object obj3;
				if (!targetFaction.HasValue)
				{
					obj3 = null;
				}
				else
				{
					Factions valueOrDefault2 = targetFaction.GetValueOrDefault();
					obj3 = ((object)(Factions)(ref valueOrDefault2)).ToString();
				}
				if (obj3 == null)
				{
					obj3 = "";
				}
				obj.TargetFactionName = (string)obj3;
				obj.NewFactionName = ((object)(Factions)(ref rule.newFaction)).ToString();
				obj.ExceptIds = rule.exceptIds ?? null;
				obj.ExceptNames = rule.exceptNames ?? null;
				obj.IsBoss = rule.isBoss;
				obj.IsBossPawn = rule.isBossPawn;
				obj.IsStoryBoss = rule.isStoryBoss;
				obj.IsUniqueArenaBoss = rule.isUniqueArenaBoss;
				obj.IsUniqueEnemy = rule.isUniqueEnemy;
				FactionRuleSerializable item = obj;
				balancingRulesFile.FactionRules.Add(item);
			}
			return balancingRulesFile;
		}
	}
	public class BossRegistryManager
	{
		private static BossRegistryManager _instance;

		private readonly Dictionary<string, BossID> bossLookup = new Dictionary<string, BossID>(StringComparer.Ordinal);

		public static BossRegistryManager Instance
		{
			get
			{
				if (_instance == null)
				{
					_instance = new BossRegistryManager();
				}
				return _instance;
			}
		}

		private BossRegistryManager()
		{
			RegisterEnum(StoryBossesHelper.Enemies, BossCategories.Story);
			RegisterEnum(UniqueArenaBossesHelper.Enemies, BossCategories.Arena);
			RegisterEnum(BossPawnsHelper.Enemies, BossCategories.Pawn);
		}

		private void RegisterEnum<T>(Dictionary<T, EnemyIdentificationGroupData> mapping, BossCategories category) where T : Enum
		{
			foreach (KeyValuePair<T, EnemyIdentificationGroupData> item in mapping)
			{
				T key = item.Key;
				EnemyIdentificationGroupData value = item.Value;
				BossID value2 = new BossID(category, value, key);
				foreach (EnemyIdentificationData enemy in value.Enemies)
				{
					if (!string.IsNullOrWhiteSpace(enemy.ID))
					{
						bossLookup[GetIdentificatorFromEnemyIdentification(enemy)] = value2;
					}
				}
			}
		}

		public bool TryGetBoss(string key, out BossID boss)
		{
			return bossLookup.TryGetValue(key, out boss);
		}

		public bool IsBoss(Character character)
		{
			return bossLookup.ContainsKey(GetEnemyBossIdentificator(character));
		}

		public bool IsBossOfCategory(string key, BossCategories category)
		{
			if (TryGetBoss(key, out var boss))
			{
				return boss.Category == category;
			}
			return false;
		}

		public bool IsBossOfCategory(Character character, BossCategories category)
		{
			if (TryGetBoss(GetEnemyBossIdentificator(character), out var boss))
			{
				return boss.Category == category;
			}
			return false;
		}

		public IEnumerable<BossID> GetBossesOfCategory(BossCategories category)
		{
			return bossLookup.Values.Where((BossID b) => b.Category == category);
		}

		public static string GetEnemyBossIdentificator(Character character)
		{
			//IL_002f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0034: Unknown result type (might be due to invalid IL or missing references)
			//IL_0020: Unknown result type (might be due to invalid IL or missing references)
			//IL_0025: Unknown result type (might be due to invalid IL or missing references)
			Area currentArea = AreaManager.Instance.CurrentArea;
			string text = ((currentArea != null) ? currentArea.GetName() : null);
			UID uID;
			if (string.IsNullOrEmpty(text))
			{
				uID = character.UID;
				return ((UID)(ref uID)).Value;
			}
			uID = character.UID;
			return ((UID)(ref uID)).Value + "_" + FixAreaNameForCode(text);
		}

		public static string GetIdentificatorFromEnemyIdentification(EnemyIdentificationData enemy)
		{
			return enemy.ID + "_" + FixAreaNameForCode(enemy.GameLocation);
		}

		public static string FixAreaNameForCode(string name)
		{
			return name.Trim().Replace(' ', '_');
		}
	}
	public class CharacterBalancerManager
	{
		private static CharacterBalancerManager _instance;

		private static MethodInfo _getStatMethod;

		public static CharacterBalancerManager Instance
		{
			get
			{
				if (_instance == null)
				{
					_instance = new CharacterBalancerManager();
				}
				return _instance;
			}
		}

		private CharacterBalancerManager()
		{
		}

		public void ApplyBalancingRules()
		{
			CharacterAI[] array = Object.FindObjectsOfType<CharacterAI>();
			for (int i = 0; i < array.Length; i++)
			{
				Character character = ((CharacterControl)array[i]).Character;
				if ((Object)(object)character == (Object)null || !character.Alive)
				{
					continue;
				}
				List<BalancingRule> matchingRules = BalancingRuleRegistryManager.Instance.GetMatchingRules(character);
				if (matchingRules.Count <= 0)
				{
					continue;
				}
				foreach (BalancingRule item in matchingRules)
				{
					ApplyRuleToCharacter(character, item);
				}
			}
		}

		public void ApplyBalancingRule(BalancingRule rule)
		{
			CharacterAI[] array = Object.FindObjectsOfType<CharacterAI>();
			for (int i = 0; i < array.Length; i++)
			{
				Character character = ((CharacterControl)array[i]).Character;
				if (!((Object)(object)character == (Object)null) && character.Alive && rule.Matches(character))
				{
					ApplyRuleToCharacter(character, rule);
				}
			}
		}

		private int ApplyRuleToCharacter(Character character, BalancingRule rule)
		{
			if ((Object)(object)character.Stats == (Object)null || rule.statModifications == null || rule.statModifications.Count == 0)
			{
				return 0;
			}
			List<StatModification> list = StatModificationBuilder.BuildFromDictionary(rule.statModifications, rule.modifierType);
			int num = 0;
			foreach (StatModification item in list)
			{
				ApplyStatModification(character, item);
				num++;
			}
			return num;
		}

		private void ApplyStatModification(Character character, StatModification mod)
		{
			float statValue = GetStatValue(character.Stats, mod.StatType);
			float num = ApplyModification(statValue, mod);
			if (mod.MinClamp.HasValue)
			{
				num = Mathf.Max(num, mod.MinClamp.Value);
			}
			if (mod.MaxClamp.HasValue)
			{
				num = Mathf.Min(num, mod.MaxClamp.Value);
			}
			SetStatValue(character, mod.StatType, num);
		}

		private float ApplyModification(float currentValue, StatModification mod)
		{
			return mod.ModifierType switch
			{
				ValueModifierType.Direct => mod.Value, 
				ValueModifierType.Scale => currentValue * mod.Value, 
				ValueModifierType.Add => currentValue + mod.Value, 
				_ => currentValue, 
			};
		}

		private StatType? MapToGameStatType(EnemyBalanceStatType statType)
		{
			return statType switch
			{
				EnemyBalanceStatType.MaxHealth => (StatType)0, 
				EnemyBalanceStatType.MaxStamina => (StatType)3, 
				EnemyBalanceStatType.MaxMana => (StatType)8, 
				EnemyBalanceStatType.HealthRegen => (StatType)1, 
				EnemyBalanceStatType.StaminaRegen => (StatType)4, 
				EnemyBalanceStatType.ManaRegen => (StatType)9, 
				EnemyBalanceStatType.Impact => (StatType)12, 
				EnemyBalanceStatType.ImpactResistance => (StatType)43, 
				EnemyBalanceStatType.MovementSpeed => (StatType)54, 
				EnemyBalanceStatType.AttackSpeed => (StatType)56, 
				EnemyBalanceStatType.SkillCooldownModifier => (StatType)68, 
				EnemyBalanceStatType.DodgeInvulnerabilityModifier => (StatType)57, 
				EnemyBalanceStatType.GlobalStatusResistance => (StatType)45, 
				EnemyBalanceStatType.ColdProtection => (StatType)47, 
				EnemyBalanceStatType.HeatProtection => (StatType)48, 
				EnemyBalanceStatType.ColdRegenRate => (StatType)49, 
				EnemyBalanceStatType.HeatRegenRate => (StatType)50, 
				EnemyBalanceStatType.CorruptionProtection => (StatType)52, 
				EnemyBalanceStatType.Waterproof => (StatType)51, 
				_ => null, 
			};
		}

		private Stat GetGameStat(CharacterStats stats, EnemyBalanceStatType statType)
		{
			//IL_0077: Unknown result type (might be due to invalid IL or missing references)
			//IL_0087: Unknown result type (might be due to invalid IL or missing references)
			//IL_008d: Expected O, but got Unknown
			StatType? val = MapToGameStatType(statType);
			if (!val.HasValue)
			{
				return null;
			}
			if (_getStatMethod == null)
			{
				_getStatMethod = typeof(CharacterStats).GetMethods(BindingFlags.Instance | BindingFlags.NonPublic).FirstOrDefault((MethodInfo m) => m.Name == "GetStat" && m.GetParameters().Length == 1 && m.GetParameters()[0].ParameterType == typeof(StatType));
			}
			if (_getStatMethod != null)
			{
				return (Stat)_getStatMethod.Invoke(stats, new object[1] { val.Value });
			}
			return null;
		}

		private float GetStatValue(CharacterStats stats, EnemyBalanceStatType statType)
		{
			switch (statType)
			{
			case EnemyBalanceStatType.MaxHealth:
				return stats.BaseMaxHealth;
			case EnemyBalanceStatType.MaxStamina:
				return stats.MaxStamina;
			case EnemyBalanceStatType.MaxMana:
				return stats.BaseMaxMana;
			case EnemyBalanceStatType.HealthRegen:
				return stats.HealthRegen;
			case EnemyBalanceStatType.StaminaRegen:
				return stats.StaminaRegen;
			case EnemyBalanceStatType.ManaRegen:
				return stats.ManaRegen;
			case EnemyBalanceStatType.Impact:
				return stats.m_impactModifier.CurrentValue;
			case EnemyBalanceStatType.ImpactResistance:
				return stats.GetImpactResistance();
			case EnemyBalanceStatType.MovementSpeed:
				return stats.MovementSpeed;
			case EnemyBalanceStatType.PhysicalDamage:
				return stats.m_damageTypesModifier[0].CurrentValue;
			case EnemyBalanceStatType.EtherealDamage:
				return stats.m_damageTypesModifier[1].CurrentValue;
			case EnemyBalanceStatType.DecayDamage:
				return stats.m_damageTypesModifier[2].CurrentValue;
			case EnemyBalanceStatType.ElectricDamage:
				return stats.m_damageTypesModifier[3].CurrentValue;
			case EnemyBalanceStatType.FrostDamage:
				return stats.m_damageTypesModifier[4].CurrentValue;
			case EnemyBalanceStatType.FireDamage:
				return stats.m_damageTypesModifier[5].CurrentValue;
			case EnemyBalanceStatType.PhysicalResistance:
				return stats.m_damageResistance[0].CurrentValue;
			case EnemyBalanceStatType.EtherealResistance:
				return stats.m_damageResistance[1].CurrentValue;
			case EnemyBalanceStatType.DecayResistance:
				return stats.m_damageResistance[2].CurrentValue;
			case EnemyBalanceStatType.ElectricResistance:
				return stats.m_damageResistance[3].CurrentValue;
			case EnemyBalanceStatType.FrostResistance:
				return stats.m_damageResistance[4].CurrentValue;
			case EnemyBalanceStatType.FireResistance:
				return stats.m_damageResistance[5].CurrentValue;
			case EnemyBalanceStatType.PhysicalProtection:
				return stats.m_damageProtection[0].CurrentValue;
			case EnemyBalanceStatType.EtherealProtection:
				return stats.m_damageProtection[1].CurrentValue;
			case EnemyBalanceStatType.DecayProtection:
				return stats.m_damageProtection[2].CurrentValue;
			case EnemyBalanceStatType.ElectricProtection:
				return stats.m_damageProtection[3].CurrentValue;
			case EnemyBalanceStatType.FrostProtection:
				return stats.m_damageProtection[4].CurrentValue;
			case EnemyBalanceStatType.FireProtection:
				return stats.m_damageProtection[5].CurrentValue;
			default:
			{
				Stat gameStat = GetGameStat(stats, statType);
				return (gameStat != null) ? gameStat.CurrentValue : 0f;
			}
			}
		}

		private void SetStatValue(Character character, EnemyBalanceStatType statType, float value)
		{
			CharacterStats stats = character.Stats;
			switch (statType)
			{
			case EnemyBalanceStatType.MaxHealth:
			{
				float num = Mathf.Max(value, 1f);
				float health = character.Health;
				float num2 = ((stats.BaseMaxHealth > 0f) ? (health / stats.BaseMaxHealth) : 1f);
				num2 = Mathf.Clamp(num2, 0f, 1f);
				stats.RefreshVitalMaxStat(false);
				stats.m_maxHealthStat.BaseValue = num;
				stats.RefreshVitalMaxStat(false);
				stats.SetHealth(num2 * num);
				break;
			}
			case EnemyBalanceStatType.MaxStamina:
			{
				float num5 = Mathf.Max(value, 1f);
				float stamina = character.Stamina;
				float num6 = Mathf.Clamp((stats.MaxStamina > 0f) ? (stamina / stats.MaxStamina) : 1f, 0f, 1f);
				stats.RefreshVitalMaxStat(false);
				stats.m_maxStamina.BaseValue = num5;
				stats.RefreshVitalMaxStat(false);
				float num7 = num6 * num5 - stamina;
				if (Mathf.Abs(num7) > 0.01f)
				{
					stats.AffectStamina(num7);
				}
				break;
			}
			case EnemyBalanceStatType.MaxMana:
			{
				float num3 = Mathf.Max(value, 1f);
				float currentMana = stats.CurrentMana;
				float num4 = ((stats.BaseMaxMana > 0f) ? (currentMana / stats.BaseMaxMana) : 1f);
				num4 = Mathf.Clamp(num4, 0f, 1f);
				stats.RefreshVitalMaxStat(false);
				stats.m_maxManaStat.BaseValue = num3;
				stats.RefreshVitalMaxStat(false);
				stats.SetMana(num4 * num3);
				break;
			}
			case EnemyBalanceStatType.HealthRegen:
			case EnemyBalanceStatType.StaminaRegen:
			case EnemyBalanceStatType.ManaRegen:
			case EnemyBalanceStatType.ColdProtection:
			case EnemyBalanceStatType.HeatProtection:
			case EnemyBalanceStatType.ColdRegenRate:
			case EnemyBalanceStatType.HeatRegenRate:
			case EnemyBalanceStatType.CorruptionProtection:
			case EnemyBalanceStatType.Waterproof:
			case EnemyBalanceStatType.Impact:
			case EnemyBalanceStatType.ImpactResistance:
			case EnemyBalanceStatType.MovementSpeed:
			case EnemyBalanceStatType.AttackSpeed:
			case EnemyBalanceStatType.SkillCooldownModifier:
			case EnemyBalanceStatType.DodgeInvulnerabilityModifier:
			case EnemyBalanceStatType.GlobalStatusResistance:
			{
				Stat gameStat = GetGameStat(stats, statType);
				if (gameStat != null)
				{
					gameStat.BaseValue = value;
					gameStat.Update();
				}
				break;
			}
			case EnemyBalanceStatType.PhysicalDamage:
				stats.m_damageTypesModifier[0].BaseValue = value;
				stats.m_damageTypesModifier[0].Update();
				break;
			case EnemyBalanceStatType.EtherealDamage:
				stats.m_damageTypesModifier[1].BaseValue = value;
				stats.m_damageTypesModifier[1].Update();
				break;
			case EnemyBalanceStatType.DecayDamage:
				stats.m_damageTypesModifier[2].BaseValue = value;
				stats.m_damageTypesModifier[2].Update();
				break;
			case EnemyBalanceStatType.ElectricDamage:
				stats.m_damageTypesModifier[3].BaseValue = value;
				stats.m_damageTypesModifier[3].Update();
				break;
			case EnemyBalanceStatType.FrostDamage:
				stats.m_damageTypesModifier[4].BaseValue = value;
				stats.m_damageTypesModifier[4].Update();
				break;
			case EnemyBalanceStatType.FireDamage:
				stats.m_damageTypesModifier[5].BaseValue = value;
				stats.m_damageTypesModifier[5].Update();
				break;
			case EnemyBalanceStatType.PhysicalResistance:
				stats.m_damageResistance[0].BaseValue = value;
				stats.m_damageResistance[0].Update();
				break;
			case EnemyBalanceStatType.EtherealResistance:
				stats.m_damageResistance[1].BaseValue = value;
				stats.m_damageResistance[1].Update();
				break;
			case EnemyBalanceStatType.DecayResistance:
				stats.m_damageResistance[2].BaseValue = value;
				stats.m_damageResistance[2].Update();
				break;
			case EnemyBalanceStatType.ElectricResistance:
				stats.m_damageResistance[3].BaseValue = value;
				stats.m_damageResistance[3].Update();
				break;
			case EnemyBalanceStatType.FrostResistance:
				stats.m_damageResistance[4].BaseValue = value;
				stats.m_damageResistance[4].Update();
				break;
			case EnemyBalanceStatType.FireResistance:
				stats.m_damageResistance[5].BaseValue = value;
				stats.m_damageResistance[5].Update();
				break;
			case EnemyBalanceStatType.PhysicalProtection:
				stats.m_damageProtection[0].BaseValue = value;
				stats.m_damageProtection[0].Update();
				break;
			case EnemyBalanceStatType.EtherealProtection:
				stats.m_damageProtection[1].BaseValue = value;
				stats.m_damageProtection[1].Update();
				break;
			case EnemyBalanceStatType.DecayProtection:
				stats.m_damageProtection[2].BaseValue = value;
				stats.m_damageProtection[2].Update();
				break;
			case EnemyBalanceStatType.ElectricProtection:
				stats.m_damageProtection[3].BaseValue = value;
				stats.m_damageProtection[3].Update();
				break;
			case EnemyBalanceStatType.FrostProtection:
				stats.m_damageProtection[4].BaseValue = value;
				stats.m_damageProtection[4].Update();
				break;
			case EnemyBalanceStatType.FireProtection:
				stats.m_damageProtection[5].BaseValue = value;
				stats.m_damageProtection[5].Update();
				break;
			}
			if (statType == EnemyBalanceStatType.HealthRegen || statType == EnemyBalanceStatType.StaminaRegen || statType == EnemyBalanceStatType.ManaRegen || statType == EnemyBalanceStatType.ColdProtection || statType == EnemyBalanceStatType.HeatProtection || statType == EnemyBalanceStatType.ColdRegenRate || statType == EnemyBalanceStatType.HeatRegenRate || statType == EnemyBalanceStatType.CorruptionProtection || statType == EnemyBalanceStatType.Waterproof || statType == EnemyBalanceStatType.ImpactResistance)
			{
				stats.UpdateStats();
			}
			if (statType == EnemyBalanceStatType.PhysicalResistance || statType == EnemyBalanceStatType.EtherealResistance || statType == EnemyBalanceStatType.DecayResistance || statType == EnemyBalanceStatType.ElectricResistance || statType == EnemyBalanceStatType.FrostResistance || statType == EnemyBalanceStatType.FireResistance || statType == EnemyBalanceStatType.PhysicalProtection || statType == EnemyBalanceStatType.EtherealProtection || statType == EnemyBalanceStatType.DecayProtection || statType == EnemyBalanceStatType.ElectricProtection || statType == EnemyBalanceStatType.FrostProtection || statType == EnemyBalanceStatType.FireProtection)
			{
				stats.UpdateStats();
			}
		}
	}
	public class FactionBalancerManager
	{
		private static FactionBalancerManager _instance;

		public static FactionBalancerManager Instance
		{
			get
			{
				if (_instance == null)
				{
					_instance = new FactionBalancerManager();
				}
				return _instance;
			}
		}

		private FactionBalancerManager()
		{
		}

		public void ApplyFactionRules()
		{
			CharacterAI[] array = Object.FindObjectsOfType<CharacterAI>();
			for (int i = 0; i < array.Length; i++)
			{
				Character character = ((CharacterControl)array[i]).Character;
				if ((Object)(object)character == (Object)null || !character.Alive)
				{
					continue;
				}
				List<FactionRule> matchingRules = FactionRuleRegistryManager.Instance.GetMatchingRules(character);
				if (matchingRules.Count <= 0)
				{
					continue;
				}
				foreach (FactionRule item in matchingRules)
				{
					ApplyRuleToCharacter(character, item);
				}
			}
		}

		public void ApplyFactionRule(FactionRule rule)
		{
			CharacterAI[] array = Object.FindObjectsOfType<CharacterAI>();
			for (int i = 0; i < array.Length; i++)
			{
				Character character = ((CharacterControl)array[i]).Character;
				if (!((Object)(object)character == (Object)null) && character.Alive && rule.Matches(character))
				{
					ApplyRuleToCharacter(character, rule);
				}
			}
		}

		private void ApplyRuleToCharacter(Character character, FactionRule rule)
		{
			//IL_000a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0013: Unknown result type (might be due to invalid IL or missing references)
			//IL_001b: Unknown result type (might be due to invalid IL or missing references)
			if (!((Object)(object)character == (Object)null) && (int)rule.newFaction != 0)
			{
				_ = character.Faction;
				character.ChangeFaction(rule.newFaction, true);
			}
		}
	}
	public class FactionRuleRegistryManager
	{
		private static FactionRuleRegistryManager _instance;

		public List<FactionRule> factionRules = new List<FactionRule>();

		public static FactionRuleRegistryManager Instance
		{
			get
			{
				if (_instance == null)
				{
					_instance = new FactionRuleRegistryManager();
				}
				return _instance;
			}
		}

		private FactionRuleRegistryManager()
		{
		}

		public void AppendFactionRules(List<FactionRule> rules)
		{
			foreach (FactionRule rule in rules)
			{
				AppendFactionRule(rule);
			}
		}

		public void AppendFactionRule(FactionRule rule)
		{
			FactionRule factionRule = factionRules.FirstOrDefault((FactionRule r) => r.id == rule.id);
			if (factionRule != null)
			{
				OutwardEnemiesBalancer.LogSL("FactionRule '" + rule.id + "' already exists. Replacing.");
				factionRules.Remove(factionRule);
			}
			factionRules.Add(rule);
			EventBusPublisher.SendAppendFactionRule(rule.id);
		}

		public void RemoveFactionRuleById(string id)
		{
			foreach (FactionRule item in factionRules.Where((FactionRule rule) => rule.id == id).ToList())
			{
				RemoveFactionRule(item);
			}
		}

		public void RemoveFactionRule(FactionRule rule)
		{
			factionRules.Remove(rule);
			EventBusPublisher.SendRemoveFactionRule(rule.id);
		}

		public List<FactionRule> GetMatchingRules(Character character)
		{
			List<FactionRule> list = new List<FactionRule>();
			foreach (FactionRule factionRule in factionRules)
			{
				if (factionRule.Matches(character))
				{
					list.Add(factionRule);
				}
			}
			return list;
		}

		public void Clear()
		{
			factionRules.Clear();
		}
	}
	public static class PathsManager
	{
		public const string ConfigDirectoryName = "Enemies_Balancer";

		public static readonly string ConfigPath;

		public static readonly string DefaultBalanceRulesPath;

		public static void Initialize()
		{
			if (!Directory.Exists(ConfigPath))
			{
				Directory.CreateDirectory(ConfigPath);
			}
		}

		static PathsManager()
		{
			ConfigPath = Path.Combine(PathsManager.ConfigPath, "Enemies_Balancer");
			DefaultBalanceRulesPath = Path.Combine(ConfigPath, "BalanceRules.xml");
			Initialize();
		}
	}
}
namespace OutwardEnemiesBalancer.Events
{
	public static class EventBusPublisher
	{
		public const string Event_BalanceRuleAppended = "BalanceRuleAppended";

		public const string Event_BalanceRuleRemoved = "BalanceRuleRemoved";

		public const string Event_FactionRuleAppended = "FactionRuleAppended";

		public const string Event_FactionRuleRemoved = "FactionRuleRemoved";

		public static void SendAppendBalancingRule(string ruleId)
		{
			//IL_0000: Unknown result type (might be due to invalid IL or missing references)
			//IL_0006: Expected O, but got Unknown
			EventPayload val = new EventPayload();
			val.Set("balanceRuleId", (object)ruleId);
			EventBus.Publish("gymmed.enemies_balancer", "BalanceRuleAppended", val);
		}

		public static void SendRemoveBalancingRule(string ruleId)
		{
			//IL_0000: Unknown result type (might be due to invalid IL or missing references)
			//IL_0006: Expected O, but got Unknown
			EventPayload val = new EventPayload();
			val.Set("balanceRuleId", (object)ruleId);
			EventBus.Publish("gymmed.enemies_balancer", "BalanceRuleRemoved", val);
		}

		public static void SendAppendFactionRule(string ruleId)
		{
			//IL_0000: Unknown result type (might be due to invalid IL or missing references)
			//IL_0006: Expected O, but got Unknown
			EventPayload val = new EventPayload();
			val.Set("factionRuleId", (object)ruleId);
			EventBus.Publish("gymmed.enemies_balancer", "FactionRuleAppended", val);
		}

		public static void SendRemoveFactionRule(string ruleId)
		{
			//IL_0000: Unknown result type (might be due to invalid IL or missing references)
			//IL_0006: Expected O, but got Unknown
			EventPayload val = new EventPayload();
			val.Set("factionRuleId", (object)ruleId);
			EventBus.Publish("gymmed.enemies_balancer", "FactionRuleRemoved", val);
		}
	}
	public static class EventBusRegister
	{
		private static readonly (string key, Type type, string description)[] TargetingParams = new(string, Type, string)[5]
		{
			EnemyBalanceParamsHelper.Get(EnemyBalanceParams.EnemyId),
			EnemyBalanceParamsHelper.Get(EnemyBalanceParams.EnemyName),
			EnemyBalanceParamsHelper.Get(EnemyBalanceParams.AreaFamily),
			EnemyBalanceParamsHelper.Get(EnemyBalanceParams.Faction),
			EnemyBalanceParamsHelper.Get(EnemyBalanceParams.AreaEnum)
		};

		private static readonly (string key, Type type, string description)[] UniqueEnemyParams = new(string, Type, string)[5]
		{
			EnemyBalanceParamsHelper.Get(EnemyBalanceParams.IsForBosses),
			EnemyBalanceParamsHelper.Get(EnemyBalanceParams.IsForBossesPawns),
			EnemyBalanceParamsHelper.Get(EnemyBalanceParams.IsForStoryBosses),
			EnemyBalanceParamsHelper.Get(EnemyBalanceParams.IsForUniqueArenaBosses),
			EnemyBalanceParamsHelper.Get(EnemyBalanceParams.IsForUniqueEnemies)
		};

		private static readonly (string key, Type type, string description)[] StatModParams = new(string, Type, string)[4]
		{
			EnemyBalanceParamsHelper.Get(EnemyBalanceParams.StatModifications),
			EnemyBalanceParamsHelper.Get(EnemyBalanceParams.ModifierType),
			EnemyBalanceParamsHelper.Get(EnemyBalanceParams.StatType),
			EnemyBalanceParamsHelper.Get(EnemyBalanceParams.Value)
		};

		private static readonly (string key, Type type, string description)[] ExceptionsParams = new(string, Type, string)[2]
		{
			EnemyBalanceParamsHelper.Get(EnemyBalanceParams.ExceptIds),
			EnemyBalanceParamsHelper.Get(EnemyBalanceParams.ExceptNames)
		};

		private static readonly (string key, Type type, string description)[] VitalStatsParams = new(string, Type, string)[7]
		{
			EnemyBalanceParamsHelper.Get(EnemyBalanceParams.MaxHealth),
			EnemyBalanceParamsHelper.Get(EnemyBalanceParams.MaxStamina),
			EnemyBalanceParamsHelper.Get(EnemyBalanceParams.MaxMana),
			EnemyBalanceParamsHelper.Get(EnemyBalanceParams.HealthRegen),
			EnemyBalanceParamsHelper.Get(EnemyBalanceParams.StaminaRegen),
			EnemyBalanceParamsHelper.Get(EnemyBalanceParams.ManaRegen),
			EnemyBalanceParamsHelper.Get(EnemyBalanceParams.ModifierType)
		};

		private static readonly (string key, Type type, string description)[] EnvironmentalStatsParams = new(string, Type, string)[5]
		{
			EnemyBalanceParamsHelper.Get(EnemyBalanceParams.ColdProtection),
			EnemyBalanceParamsHelper.Get(EnemyBalanceParams.HeatProtection),
			EnemyBalanceParamsHelper.Get(EnemyBalanceParams.CorruptionResistance),
			EnemyBalanceParamsHelper.Get(EnemyBalanceParams.Waterproof),
			EnemyBalanceParamsHelper.Get(EnemyBalanceParams.ModifierType)
		};

		private static readonly (string key, Type type, string description)[] CombatStatsParams = new(string, Type, string)[5]
		{
			EnemyBalanceParamsHelper.Get(EnemyBalanceParams.Impact),
			EnemyBalanceParamsHelper.Get(EnemyBalanceParams.ImpactResistance),
			EnemyBalanceParamsHelper.Get(EnemyBalanceParams.MovementSpeed),
			EnemyBalanceParamsHelper.Get(EnemyBalanceParams.AttackSpeed),
			EnemyBalanceParamsHelper.Get(EnemyBalanceParams.ModifierType)
		};

		private static readonly (string key, Type type, string description)[] FactionRuleParams = new(string, Type, string)[3]
		{
			EnemyBalanceParamsHelper.Get(EnemyBalanceParams.NewFaction),
			EnemyBalanceParamsHelper.Get(EnemyBalanceParams.ExceptIds),
			EnemyBalanceParamsHelper.Get(EnemyBalanceParams.ExceptNames)
		};

		public static void RegisterEvents()
		{
			EventBus.RegisterEvent("gymmed.enemies_balancer", "BalanceRuleAppended", "Published when a balancing rule is appended.", new(string, Type, string)[1] { EnemyBalanceParamsHelper.Get(EnemyBalanceParams.BalanceRuleId) });
			EventBus.RegisterEvent("gymmed.enemies_balancer", "BalanceRuleRemoved", "Published when a balancing rule is removed.", new(string, Type, string)[1] { EnemyBalanceParamsHelper.Get(EnemyBalanceParams.BalanceRuleId) });
			EventBus.RegisterEvent("gymmed.enemies_balancer_*", "AddBalanceRule", "Add a full balancing rule with all targeting options and stat modifications.", EnemyBalanceParamsHelper.Combine(EnemyBalanceParamsHelper.Get(EnemyBalanceParams.BalanceRuleId), TargetingParams, UniqueEnemyParams, StatModParams, ExceptionsParams));
			EventBus.RegisterEvent("gymmed.enemies_balancer_*", "AddBalanceRuleByEnemyName", "Add balancing rule targeting by enemy name.", EnemyBalanceParamsHelper.Combine(EnemyBalanceParamsHelper.Get(EnemyBalanceParams.BalanceRuleId), EnemyBalanceParamsHelper.Get(EnemyBalanceParams.EnemyName), StatModParams, EnemyBalanceParamsHelper.Get(EnemyBalanceParams.ExceptIds)));
			EventBus.RegisterEvent("gymmed.enemies_balancer_*", "AddBalanceRuleByEnemyId", "Add balancing rule targeting by enem