Decompiled source of Loot Manager v0.0.4
OutwardLootManager.dll
Decompiled 3 days ago
The result has been truncated due to the large size, download it to view full contents!
using System; using System.Collections.Generic; using System.ComponentModel; 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.Xml; using System.Xml.Serialization; using BepInEx; using BepInEx.Logging; using HarmonyLib; using OutwardLootManager.Drop; using OutwardLootManager.Drop.Serialization; using OutwardLootManager.Events; using OutwardLootManager.Managers; using OutwardLootManager.Utility.Data; using OutwardLootManager.Utility.Enums; using OutwardLootManager.Utility.Extensions; using OutwardLootManager.Utility.Helpers.Static; using OutwardModsCommunicator.EventBus; using OutwardModsCommunicator.Managers; using SideLoader; using UnityEngine; using UnityEngine.SceneManagement; [assembly: CompilationRelaxations(8)] [assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)] [assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)] [assembly: AssemblyTitle("OutwardModPackTemplate")] [assembly: AssemblyDescription("")] [assembly: AssemblyConfiguration("")] [assembly: AssemblyCompany("")] [assembly: AssemblyProduct("OutwardModPackTemplate")] [assembly: AssemblyCopyright("Copyright © 2025")] [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 OutwardLootManager { [BepInPlugin("gymmed.loot_manager", "Loot Manager", "0.0.4")] [BepInDependency(/*Could not decode attribute arguments.*/)] public class OutwardLootManager : BaseUnityPlugin { [HarmonyPatch(typeof(LootableOnDeath), "OnDeath")] public class LootableOnDeath_OnDeath { private static void Prefix(LootableOnDeath __instance, bool _loadedDead) { AddNewItemDrops(__instance, _loadedDead); } } [HarmonyPatch(typeof(ResourcesPrefabManager), "Load")] public class ResourcesPrefabManager_Load { private static void Postfix(ResourcesPrefabManager __instance) { LootRulesSerializer.Instance.LoadPlayerCustomLoots(); } } public const string GUID = "gymmed.loot_manager"; public const string NAME = "Loot Manager"; public const string VERSION = "0.0.4"; public const string EVENT_BUS_ALL_GUID = "gymmed.loot_manager_*"; public static string prefix = "[Loot-Manager]"; 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 Loot Manager 0.0.4!"); new Harmony("gymmed.loot_manager").PatchAll(); EventBusRegister.RegisterEvents(); EventBusSubscriber.AddSubscribers(); } public static void AddNewItemDrops(LootableOnDeath lootableOnDeath, bool _loadedDead) { try { List<LootRule> matchingRules = LootRuleRegistryManager.Instance.GetMatchingRules(lootableOnDeath.Character); if (matchingRules.Count < 1) { return; } if (_loadedDead && lootableOnDeath.m_lootDroppers != null && BossRegistryManager.Instance.IsBoss(lootableOnDeath.Character) && !LootManager.Instance.HasDrops(lootableOnDeath)) { Character character = lootableOnDeath.Character; object obj; if (character == null) { obj = null; } else { CharacterInventory inventory = character.Inventory; obj = ((inventory != null) ? inventory.Pouch : null); } if ((Object)obj == (Object)null) { return; } ItemContainer pouch = lootableOnDeath.Character.Inventory.Pouch; if (!pouch.IsEmpty) { pouch.ClearPouch(); } Dropable[] lootDroppers = lootableOnDeath.m_lootDroppers; for (int i = 0; i < lootDroppers.Length; i++) { lootDroppers[i].GenerateContents(lootableOnDeath.Character.Inventory.Pouch); } } foreach (LootRule item in matchingRules) { LootManager.Instance.AddLootToLootableOnDeath(lootableOnDeath, item.itemDropRate); } } catch (Exception ex) { LogMessage("LootManager@AddNewItemDrops We encountered a problem: \"" + 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 OutwardLootManager.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 OutwardLootManager.Utility.Helpers.Static { public static class AiSquadHelpers { public static List<Character> GetCharactersFromAiSquads() { List<Character> list = new List<Character>(); foreach (AISquad value in AISquadManager.Instance.m_allSquads.Values) { foreach (AISquadMember member in value.Members) { list.Add(member.Character); } } return list; } } 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 CharacterHelpers { public static bool IsCharacterIdInList(Character character, List<string> ids = null) { //IL_0017: Unknown result type (might be due to invalid IL or missing references) //IL_001c: Unknown result type (might be due to invalid IL or missing references) if (ids == null) { return false; } foreach (string id in ids) { UID uID = character.UID; if (((UID)(ref uID)).Value == id) { return true; } } return false; } } public static class LocalizationHelpers { public static void LogConstructedAreasForEnum<T>(Dictionary<T, string> locations) where T : Enum { string text = ""; bool flag = false; foreach (KeyValuePair<T, string> location in locations) { Area[] areas = AreaManager.Instance.Areas; for (int i = 0; i < areas.Length; i++) { text = areas[i].GetName(); if (location.Value.Equals(text, StringComparison.OrdinalIgnoreCase)) { OutwardLootManager.LogMessage("{ " + typeof(T).Name + "." + location.Key.ToString() + ", \"" + text + "\" },"); flag = true; break; } } if (flag) { flag = false; continue; } OutwardLootManager.LogMessage("{ " + typeof(T).Name + "." + location.Key.ToString() + ", \"---" + locations[location.Key] + "---\" },"); } } public static string GetAllLocalizationsForEnum<T>(Dictionary<T, string> names) where T : Enum { string text = ""; foreach (KeyValuePair<string, string> item in LocalizationManager.Instance.m_generalLocalization) { string uniqueEnumNameInLocalization = GetUniqueEnumNameInLocalization(item.Value, names); if (!string.IsNullOrEmpty(uniqueEnumNameInLocalization)) { text = text + "{ " + typeof(T).Name + "." + uniqueEnumNameInLocalization + ", \"" + item.Key + "\" },\n"; } } return text; } public static string GetAllLocalizationsForUniques() { return string.Concat(string.Concat(string.Concat("" + GetSeparationForTypeAndLocalization(UniqueEnemiesHelper.Enemies.GetFirstDisplayNameFromGroup()), GetSeparationForTypeAndLocalization(UniqueArenaBossesHelper.Enemies.GetFirstDisplayNameFromGroup())), GetSeparationForTypeAndLocalization(BossPawnsHelper.Enemies.GetFirstDisplayNameFromGroup())), GetSeparationForTypeAndLocalization(StoryBossesHelper.Enemies.GetFirstDisplayNameFromGroup())); } public static string GetSeparationForTypeAndLocalization<T>(Dictionary<T, string> names) where T : Enum { return string.Concat(string.Concat("" + typeof(T).Name + " Start \n", GetAllLocalizationsForEnum(names)), typeof(T).Name, " End \n"); } public static string GetUniqueEnumNameInLocalization<T>(string localizedName, Dictionary<T, string> names) where T : Enum { foreach (T value2 in Enum.GetValues(typeof(T))) { if (names.TryGetValue(value2, out var value) && string.Equals(value, localizedName, StringComparison.OrdinalIgnoreCase)) { return value2.ToString(); } } return null; } } public static class LootRuleHelpers { public static bool TryToFillRuleWithEnemyId(LootRule lootRule, EventPayload payload, bool required = false) { (string, Type, string) tuple = EventRegistryParamsHelper.Get(EventRegistryParams.EnemyId); string text = payload.Get<string>(tuple.Item1, (string)null); if (!string.IsNullOrEmpty(text)) { lootRule.enemyID = text; return true; } if (required) { OutwardLootManager.LogSL("LootRuleHelpers@TryToFillRuleWithEnemyId didn't receive " + tuple.Item1 + " variable! Cannot add loot!"); } return false; } public static bool TryToFillRuleWithEnemyName(LootRule lootRule, EventPayload payload, bool required = false) { (string, Type, string) tuple = EventRegistryParamsHelper.Get(EventRegistryParams.EnemyName); string text = payload.Get<string>(tuple.Item1, (string)null); if (!string.IsNullOrEmpty(text)) { lootRule.enemyName = text; return true; } if (required) { OutwardLootManager.LogSL("LootRuleHelpers@TryToFillRuleWithEnemyName didn't receive " + tuple.Item1 + " variable! Cannot add loot!"); } return false; } public static bool TryToFillRuleWithId(LootRule lootRule, EventPayload payload) { string text = payload.Get<string>(EventRegistryParamsHelper.Get(EventRegistryParams.LootId).key, (string)null); if (!string.IsNullOrEmpty(text)) { lootRule.id = text; return true; } return false; } public static bool FillRuleWithEnvironmentConditions(LootRule lootRule, EventPayload payload) { lootRule.areaFamily = payload.Get<AreaFamily>("areaFamily", (AreaFamily)null); lootRule.area = payload.Get<AreaEnum?>("area", (AreaEnum?)null); lootRule.faction = payload.Get<Factions?>("faction", (Factions?)null); if (lootRule.areaFamily == null && !lootRule.area.HasValue) { return lootRule.faction.HasValue; } return true; } public static bool FillRuleWithExceptions(LootRule lootRule, EventPayload payload) { bool num = FillRuleWithIdExceptions(lootRule, payload); bool flag = FillRuleWithNameExceptions(lootRule, payload); return num || flag; } public static bool FillRuleWithIdExceptions(LootRule lootRule, EventPayload payload) { List<string> list = payload.Get<List<string>>(EventRegistryParamsHelper.Get(EventRegistryParams.ExceptIds).key, (List<string>)null); if (list == null) { return false; } lootRule.exceptIds = list; return true; } public static bool FillRuleWithNameExceptions(LootRule lootRule, EventPayload payload) { List<string> list = payload.Get<List<string>>(EventRegistryParamsHelper.Get(EventRegistryParams.ExceptNames).key, (List<string>)null); if (list == null) { return false; } lootRule.exceptNames = list; return true; } public static bool FillRuleForStrongEnemyTypes(LootRule lootRule, EventPayload payload) { lootRule.isBoss = payload.Get<bool>("isForBosses", false); lootRule.isBossPawn = payload.Get<bool>("isForBossesPawns", false); lootRule.isStoryBoss = payload.Get<bool>("isForStoryBosses", false); lootRule.isUniqueArenaBoss = payload.Get<bool>("isForUniqueArenaBosses", false); lootRule.isUniqueEnemy = payload.Get<bool>("isForUniqueEnemies", false); if (lootRule.isBoss || lootRule.isBossPawn || lootRule.isStoryBoss || lootRule.isUniqueArenaBoss || lootRule.isUniqueEnemy) { return true; } return false; } public static bool GetItemDropRateAndFillInRule(LootRule lootRule, EventPayload payload) { int num = payload.Get<int>("itemId", -1); if (num > -1) { FillRuleWithDropRate(lootRule, payload, num); return true; } List<ItemDropChance> list = payload.Get<List<ItemDropChance>>("listOfItemDropChances", (List<ItemDropChance>)null); if (list != null) { FillRuleWithDropRate(lootRule, payload, list); return true; } ItemDropChance val = payload.Get<ItemDropChance>("itemDropChance", (ItemDropChance)null); if (val != null) { FillRuleWithDropRate(lootRule, payload, val); return true; } return false; } public static void FillRuleWithDropRate(LootRule lootRule, EventPayload payload, ItemDropChance itemDropChance) { List<ItemDropChance> list = new List<ItemDropChance>(); list.Add(itemDropChance); FillRuleWithDropRate(lootRule, payload, list); } public static void FillRuleWithDropRate(LootRule lootRule, EventPayload payload, int itemId = -1) { if (itemId < 0) { OutwardLootManager.LogSL("LootRuleHelpers@FillRuleWithDropRate didn't receive itemId! Failed to add loot!"); return; } ItemDropChance itemDropChanceFromPayLoad = GetItemDropChanceFromPayLoad(payload, itemId); List<ItemDropChance> list = new List<ItemDropChance>(); list.Add(itemDropChanceFromPayLoad); FillRuleWithDropRate(lootRule, payload, list); } public static void FillRuleWithDropRate(LootRule lootRule, EventPayload payload, List<ItemDropChance> itemDrops) { ItemDropRate itemDropRate = new ItemDropRate(itemDrops); FillDropRate(itemDropRate, payload); lootRule.itemDropRate = itemDropRate; itemDropRate.ListItemDropChance = itemDrops; } public static void FillDropRate(ItemDropRate itemDropRate, EventPayload payload) { int num = payload.Get<int>("emptyDropChance", -1); int num3 = (itemDropRate.MaxDiceValue = payload.Get<int>("maxDiceValue", 0)); if (num3 < 1) { itemDropRate.CalculateChangeRequired = true; if (num < 0) { num = GetNormalizedEmptyDropChanceFromItems(payload); } } if (num < 0) { num = 0; } itemDropRate.EmptyDropChance = num; int minNumberOfDrops = payload.Get<int>("minNumberOfDrops", 1); itemDropRate.MinNumberOfDrops = minNumberOfDrops; int maxNumberOfDrops = payload.Get<int>("maxNumberOfDrops", 1); itemDropRate.MaxNumberOfDrops = maxNumberOfDrops; } public static int GetNormalizedEmptyDropChanceFromItems(EventPayload payload) { if (TryGetNormalizedEmptyDropChanceFromItemDropChances(payload, out var value)) { return value; } if (TryGetNormalizedEmptyDropChanceFromItemDropChance(payload, out var value2)) { return value2; } if (TryGetNormalizedEmptyDropChanceFromPayload(payload, out var value3)) { return value3; } return 0; } public static bool TryGetNormalizedEmptyDropChanceFromPayload(EventPayload payload, out int value) { int num = payload.Get<int>("dropChance", -1); if (num < 0 || num > 100) { value = 0; return false; } value = 100 - Mathf.Clamp(num, 0, num); return true; } public static bool TryGetNormalizedEmptyDropChanceFromItemDropChance(EventPayload payload, out int value) { ItemDropChance val = payload.Get<ItemDropChance>("itemDropChance", (ItemDropChance)null); if (val == null) { value = 0; return false; } if (val.DropChance > 100) { value = 0; return true; } value = 100 - Mathf.Clamp(val.DropChance, 0, val.DropChance); return true; } public static bool TryGetNormalizedEmptyDropChanceFromItemDropChances(EventPayload payload, out int value) { List<ItemDropChance> list = payload.Get<List<ItemDropChance>>("listOfItemDropChances", (List<ItemDropChance>)null); if (list == null) { value = -1; return false; } int num = 0; foreach (ItemDropChance item in list) { num += Mathf.Clamp(item.DropChance, 0, item.DropChance); } if (num > 100) { value = 0; } else { value = 100 - num; } return true; } public static ItemDropChance GetItemDropChanceFromPayLoad(EventPayload payload, int itemId = -1) { //IL_0010: Unknown result type (might be due to invalid IL or missing references) //IL_0015: Unknown result type (might be due to invalid IL or missing references) //IL_002a: Unknown result type (might be due to invalid IL or missing references) //IL_003e: Unknown result type (might be due to invalid IL or missing references) //IL_0052: Unknown result type (might be due to invalid IL or missing references) //IL_0066: Unknown result type (might be due to invalid IL or missing references) //IL_007b: Unknown result type (might be due to invalid IL or missing references) //IL_0091: Unknown result type (might be due to invalid IL or missing references) //IL_009a: Expected O, but got Unknown if (itemId < 0) { OutwardLootManager.LogSL("LootRuleHelpers@GetItemDropChanceFromPayLoad didn't receive itemId! Failed to add loot!"); return null; } ItemDropChance val = new ItemDropChance { ItemID = itemId }; int dropChance = payload.Get<int>("dropChance", 100); val.DropChance = dropChance; int minDropCount = payload.Get<int>("minDropCount", 1); ((BasicItemDrop)val).MinDropCount = minDropCount; int maxDropCount = payload.Get<int>("maxDropCount", 1); ((BasicItemDrop)val).MaxDropCount = maxDropCount; int minDiceRollValue = payload.Get<int>("minDiceRollValue", 0); val.MinDiceRollValue = minDiceRollValue; int maxDiceRollValue = payload.Get<int>("maxDiceRollValue", 0); val.MaxDiceRollValue = maxDiceRollValue; int chanceReduction = payload.Get<int>("chanceReduction", 0); val.ChanceReduction = chanceReduction; return val; } } public static class OnSceneLoadLootHelpers { public static void AddLootsToFaction(Factions faction, List<ItemDropChance> itemDropChances, List<string> exceptIds = 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) foreach (Character charactersFromAiSquad in AiSquadHelpers.GetCharactersFromAiSquads()) { if (charactersFromAiSquad.Faction != faction || CharacterHelpers.IsCharacterIdInList(charactersFromAiSquad, exceptIds)) { continue; } foreach (ItemDropChance itemDropChance in itemDropChances) { AddLootToCharacter(charactersFromAiSquad, itemDropChance); } } } public static void AddLootToFaction(Factions faction, ItemDropChance itemDropChance, List<string> exceptIds = 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) foreach (Character charactersFromAiSquad in AiSquadHelpers.GetCharactersFromAiSquads()) { if (charactersFromAiSquad.Faction == faction && !CharacterHelpers.IsCharacterIdInList(charactersFromAiSquad, exceptIds)) { AddLootToCharacter(charactersFromAiSquad, itemDropChance); } } } public static void AddLootToCharacter(Character character, ItemDropChance itemDropChance) { LootableOnDeath component = ((Component)character).GetComponent<LootableOnDeath>(); if ((Object)(object)component == (Object)null) { OutwardLootManager.LogSL("LootManager@AddLootToCharacter received lootOnDeath null! Can't add loot to gameobject without LootableOnDeath component."); UnityEngineExtensions.GetOrAddComponent<LootableOnDeath>(((Component)character).transform); } List<ItemDropChance> list = new List<ItemDropChance>(); list.Add(itemDropChance); LootManager.Instance.AddLootToLootableOnDeath(component, list); } } public static class SceneLoopActionHelpers { public static List<Character> allScenesCharacters = new List<Character>(); public static void FinishedAction() { OutwardLootManager.LogMessage($"Total characters found in scenes: {allScenesCharacters.Count}"); TryLoggingCharacterForEnum(UniqueEnemiesHelper.Enemies.GetFirstNameLocFromGroup(), UniqueEnemiesHelper.Enemies.GetFirstWikiLocationsFromGroup(), UniqueEnemiesHelper.Enemies.GetFirstGameLocationsFromGroup()); TryLoggingCharacterForEnum(UniqueArenaBossesHelper.Enemies.GetFirstNameLocFromGroup(), UniqueArenaBossesHelper.Enemies.GetFirstWikiLocationsFromGroup(), UniqueArenaBossesHelper.Enemies.GetFirstGameLocationsFromGroup()); TryLoggingCharacterForEnum(StoryBossesHelper.Enemies.GetFirstNameLocFromGroup(), StoryBossesHelper.Enemies.GetFirstWikiLocationsFromGroup(), StoryBossesHelper.Enemies.GetFirstGameLocationsFromGroup()); TryLoggingCharacterForEnum(BossPawnsHelper.Enemies.GetFirstNameLocFromGroup(), BossPawnsHelper.Enemies.GetFirstWikiLocationsFromGroup(), BossPawnsHelper.Enemies.GetFirstGameLocationsFromGroup()); } public static void TryLoggingCharacterForEnum<T>(Dictionary<T, string> names, Dictionary<T, string> wikiLocations, Dictionary<T, string> gameLocations) where T : Enum { //IL_0199: Unknown result type (might be due to invalid IL or missing references) //IL_019e: Unknown result type (might be due to invalid IL or missing references) string text = ""; string text2 = ""; foreach (KeyValuePair<T, string> name in names) { foreach (Character allScenesCharacter in allScenesCharacters) { text = name.Key.ToString().Replace("_", ""); text2 = name.Key.ToString().Replace("_", " "); if (allScenesCharacter.m_nameLocKey.Equals(name.Value) || allScenesCharacter.Name.Equals(text) || allScenesCharacter.m_name.Equals(text) || allScenesCharacter.Name.Equals(text2) || allScenesCharacter.m_name.Equals(text2)) { string value; string text3 = (wikiLocations.TryGetValue(name.Key, out value) ? value : "N/A"); string value2; string text4 = (gameLocations.TryGetValue(name.Key, out value2) ? value2 : "N/A"); string[] obj = new string[17] { "{ ", typeof(T).Name, ".", name.Key.ToString(), ", new(\"", allScenesCharacter.Name, "\", \"", allScenesCharacter.m_name, "\", \"", allScenesCharacter.m_nameLocKey, "\", \"", null, null, null, null, null, null }; UID uID = allScenesCharacter.UID; obj[11] = ((UID)(ref uID)).Value; obj[12] = "\", \""; obj[13] = text3; obj[14] = "\", \""; obj[15] = text4; obj[16] = "\");"; OutwardLootManager.LogMessage(string.Concat(obj)); break; } } } } public static void StartSceneTesting() { EventBusSubscriber.AddSceneTesterSubscribers(); HashSet<AreaEnum> uniqueAreasFromEnumDictionary = AreaHelpers.GetUniqueAreasFromEnumDictionary(UniqueEnemiesHelper.Enemies.GetFirstGameLocationsFromGroup()); HashSet<AreaEnum> uniqueAreasFromEnumDictionary2 = AreaHelpers.GetUniqueAreasFromEnumDictionary(UniqueArenaBossesHelper.Enemies.GetFirstGameLocationsFromGroup()); HashSet<AreaEnum> uniqueAreasFromEnumDictionary3 = AreaHelpers.GetUniqueAreasFromEnumDictionary(StoryBossesHelper.Enemies.GetFirstGameLocationsFromGroup()); HashSet<AreaEnum> uniqueAreasFromEnumDictionary4 = AreaHelpers.GetUniqueAreasFromEnumDictionary(BossPawnsHelper.Enemies.GetFirstGameLocationsFromGroup()); HashSet<AreaEnum> other = UnknownArenasHelper.GetAllAreaEnums().ToHashSet(); HashSet<AreaEnum> hashSet = new HashSet<AreaEnum>(); hashSet.UnionWith(uniqueAreasFromEnumDictionary); hashSet.UnionWith(uniqueAreasFromEnumDictionary2); hashSet.UnionWith(uniqueAreasFromEnumDictionary3); hashSet.UnionWith(uniqueAreasFromEnumDictionary4); hashSet.UnionWith(other); AddEnemyIdentifierLogger(hashSet); } public static void AddEnemyIdentifierLogger(HashSet<AreaEnum> areas) { allScenesCharacters = new List<Character>(); Action function = delegate { //IL_0099: Unknown result type (might be due to invalid IL or missing references) //IL_009e: Unknown result type (might be due to invalid IL or missing references) string name = AreaManager.Instance.CurrentArea.GetName(); OutwardLootManager.LogMessage("Current Area GetName:" + name); Transform transform = ((Component)AISquadManager.Instance).transform; if (!((Object)(object)transform == (Object)null)) { Character[] componentsInChildren = ((Component)transform).GetComponentsInChildren<Character>(); foreach (Character val in componentsInChildren) { allScenesCharacters.Add(val); string[] obj = new string[8] { "Name: ", val.Name, " m_name: ", val.m_name, " m_nameLoc: ", val.m_nameLocKey, " id: ", null }; UID uID = val.UID; obj[7] = ((UID)(ref uID)).Value; OutwardLootManager.LogMessage(string.Concat(obj)); } OutwardLootManager.LogMessage("End of Area:" + name); } }; EventBusPublisher.SendSceneLoopAction(EventBusSubscriber.SceneUniquesActionId, function, areas); } } } namespace OutwardLootManager.Utility.Extensions { public static class DictionaryExtensions { public static void AddToListValue<TKey, TValue>(this Dictionary<TKey, List<TValue>> dict, TKey key, TValue value) { if (!dict.ContainsKey(key)) { dict[key] = new List<TValue>(); } dict[key].Add(value); } } 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 boss) 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)))) { boss = item.Key; return true; } } boss = 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 OutwardLootManager.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 EventRegistryParams { LootId, ItemId, DropChance, MinDropCount, MaxDropCount, MinDiceRollValue, MaxDiceRollValue, EnemyId, EnemyName, AreaEnum, AreaFamily, Faction, ExceptIds, ExceptNames, IsForBosses, IsForBossesPawns, IsForStoryBosses, IsForUniqueArenaBosses, IsForUniqueEnemies, ListOfItemDropChances, ItemDropChance, MinNumberOfDrops, MaxNumberOfDrops, EmptyDropChance, MaxDiceValue, LoadLootsXmlFilePath, StoreLootsXmlFilePath, LootRuleId } public static class EventRegistryParamsHelper { private static readonly Dictionary<EventRegistryParams, (string key, Type type, string description)> _registry = new Dictionary<EventRegistryParams, (string, Type, string)> { [EventRegistryParams.LootId] = ("lootId", typeof(string), "Optional. You will need loot id if you planning to remove loot later."), [EventRegistryParams.ItemId] = ("itemId", typeof(int), "Required if itemDropChance/listOfItemDropChances is not provided. Loot item ID."), [EventRegistryParams.DropChance] = ("dropChance", typeof(int), "Optional. Default is 10. Determines chance of dropping item. You can provide ItemDropChance instead if you like."), [EventRegistryParams.MinDropCount] = ("minDropCount", typeof(int), "Optional. Default is 1. Provides minimum amount of items could be dropped. You can provide ItemDropChance instead if you like."), [EventRegistryParams.MaxDropCount] = ("dropChance", typeof(int), "Optional. Default is 1. Provides maximum amount of items could be dropped. You can provide ItemDropChance instead if you like."), [EventRegistryParams.MinDiceRollValue] = ("minDiceRollValue", typeof(int), "Optional. Default is 0. Sets the lowest dice roll value at which item drop chances begin to count. Use together with 'maxDiceRollValue' and 'maxDiceValue'. You can provide ItemDropChance instead if you like."), [EventRegistryParams.MaxDiceRollValue] = ("maxDiceRollValue", typeof(int), "Optional. Default is 0. Sets the highest dice roll value considered when calculating item drop chances. Use together with 'minDiceRollValue' and 'maxDiceValue'. You can provide ItemDropChance instead if you like."), [EventRegistryParams.EnemyId] = ("enemyId", typeof(string), "Default null. Determines if drop should be appliead for enemy. You can get this from UnityExplorer mod or logs."), [EventRegistryParams.EnemyName] = ("enemyName", typeof(string), "Default null. Determines if drop should be appliead for enemy. You can get this from UnityExplorer mod or logs."), [EventRegistryParams.AreaEnum] = ("area", typeof(AreaEnum?), "Optional. Default nullable. Determines if drop should be appliead for specific area. You can get this from AreaManager.AreaEnum enum."), [EventRegistryParams.AreaFamily] = ("areaFamily", typeof(AreaFamily), "Optional. Default null. Determines if drop should be appliead for specific area family(region). You can get this from AreaManager.AreaFamilies variable."), [EventRegistryParams.Faction] = ("faction", typeof(Factions?), "Optional. Default nullable. Determines if drop should be appliead for specific faction. You can get this from Character.Factions enum."), [EventRegistryParams.ExceptIds] = ("listExceptIds", typeof(List<string>), "Optional. Default null. List of enemy ids that will not receive loot. You can get this from Character.UID.Value ."), [EventRegistryParams.ExceptNames] = ("listExceptNames", typeof(List<string>), "Optional. Default null. List of enemy names that will not receive loot. You can get this from Character.Name ."), [EventRegistryParams.IsForBosses] = ("isForBosses", typeof(bool), "Optional. Default false. Determines if drop should be appliead for all game bosses and pawns."), [EventRegistryParams.IsForBossesPawns] = ("isForBossPawns", typeof(bool), "Optional. Default false. Should drop be applied for bosses pawns?"), [EventRegistryParams.IsForStoryBosses] = ("isForStoryBosses", typeof(bool), "Optional. Default false. Should drop be applied for story bosses?"), [EventRegistryParams.IsForUniqueArenaBosses] = ("isForUniqueArenaBosses", typeof(bool), "Optional. Default false. Should drop be applied for unique arena bosses?"), [EventRegistryParams.IsForUniqueEnemies] = ("isForUniqueEnemies", typeof(bool), "Optional. Default false. Should drop be applied for unique enemies?"), [EventRegistryParams.ListOfItemDropChances] = ("listOfItemDropChances", typeof(List<string>), "Optional. Default null. Provide your created list of your ItemDropChance instances to be dropped."), [EventRegistryParams.ItemDropChance] = ("itemDropChance", typeof(ItemDropChance), "Optional. Default null. Provide your created ItemDropChance instance to be dropped."), [EventRegistryParams.MinNumberOfDrops] = ("minNumberOfDrops", typeof(int), "Optional. Default is 1. Determines minimum amout of drops for same provided items(ItemDropChance)."), [EventRegistryParams.MaxNumberOfDrops] = ("maxNumberOfDrops", typeof(int), "Optional. Default is 1. Determines maximum amout of drops for same provided items(ItemDropChance)."), [EventRegistryParams.EmptyDropChance] = ("emptyDropChance", typeof(int), "Optional. Default is 0. Defines the percentage chance for a drop to be empty. Used together with 'maxDiceValue'."), [EventRegistryParams.MaxDiceValue] = ("maxDiceValue", typeof(int), "Optional. Default 1. Is the limit of dice rolls on ItemDropChance. It determines which item should be added in drop."), [EventRegistryParams.LoadLootsXmlFilePath] = ("filePath", typeof(string), "Required. Used for loading custom loots from xml file."), [EventRegistryParams.StoreLootsXmlFilePath] = ("filePath", typeof(string), "Optional. Default \"BepInEx/config/gymmed.Mods_Communicator/Loot_Manager\".Used for storing custom loots from xml file."), [EventRegistryParams.LootRuleId] = ("lootRuleId", typeof(string), "Provides loot rule id.") }; public static (string key, Type type, string description) Get(EventRegistryParams 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") } }; } public enum UnknownArenas { Chersonese, Hallowed, Abrassar, AntiqueField, Emercar, Caldera } public static class UnknownArenasHelper { public static readonly Dictionary<UnknownArenas, UnknownArenaData> Arenas = new Dictionary<UnknownArenas, UnknownArenaData> { { UnknownArenas.Chersonese, new UnknownArenaData("ChersoneseDungeonsBosses", "Scene_Chersonese_DungeonsBosses", "Chersonese Arena", "Unknown Arena") }, { UnknownArenas.Hallowed, new UnknownArenaData("HallowedDungeonsBosses", "Scene_Hallowed_DungeonsBosses", "Hallowed Marsh Arena", "Unknown Arena") }, { UnknownArenas.Abrassar, new UnknownArenaData("AbrassarDungeonsBosses", "Scene_Abrassar_DungeonsBosses", "Abrassar Arena", "Unknown Arena") }, { UnknownArenas.AntiqueField, new UnknownArenaData("AntiqueFieldDungeonsBosses", "Scene_Harmattan_DungeonsBosses", "Antique Field Arena", "Unknown Arena") }, { UnknownArenas.Emercar, new UnknownArenaData("EmercarDungeonsBosses", "Scene_Emercar_DungeonsBosses", "Enmercar Arena", "Unknown Arena") }, { UnknownArenas.Caldera, new UnknownArenaData("CalderaDungeonsBosses", "Scene_Caldera_DungeonsBosses", "Caldera Arena", "Unknown Arena") } }; public static Area GetArea(UnknownArenas arena) { if (!Arenas.TryGetValue(arena, out var data)) { return null; } return ((IEnumerable<Area>)AreaManager.Instance.Areas).FirstOrDefault((Func<Area, bool>)((Area area) => area.DefaultName.Equals(data.defaultName, StringComparison.OrdinalIgnoreCase))); } public static List<AreaEnum> GetAllAreaEnums() { List<Area> allAreas = GetAllAreas(); List<AreaEnum> list = new List<AreaEnum>(); foreach (Area item in allAreas) { list.Add((AreaEnum)item.ID); } return list; } public static List<Area> GetAllAreas() { List<Area> list = new List<Area>(); foreach (KeyValuePair<UnknownArenas, UnknownArenaData> kvp in Arenas) { Area val = ((IEnumerable<Area>)AreaManager.Instance.Areas).FirstOrDefault((Func<Area, bool>)((Area area) => area.DefaultName.Equals(kvp.Value.defaultName, StringComparison.OrdinalIgnoreCase))); if (val != null) { list.Add(val); } } return list; } } } namespace OutwardLootManager.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)); } } public class UnknownArenaData { public string scene; public string nameLoc; public string defaultName; public string getName; public UnknownArenaData(string scene, string nameLoc, string defaultName, string getName) { this.scene = scene; this.nameLoc = nameLoc; this.defaultName = defaultName; this.getName = getName; } } } namespace OutwardLootManager.Managers { 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 LootManager { private static LootManager _instance; public static LootManager Instance { get { if (_instance == null) { _instance = new LootManager(); } return _instance; } } private LootManager() { } public void AddLootForIds(LootableOnDeath lootableOnDeath, List<string> ids, List<ItemDropChance> itemsChances) { //IL_002e: Unknown result type (might be due to invalid IL or missing references) //IL_0033: Unknown result type (might be due to invalid IL or missing references) Character character = lootableOnDeath.m_character; if ((Object)(object)character == (Object)null) { OutwardLootManager.LogSL("LootManager@AddLootForFaction could not retrieve character!"); return; } bool flag = false; foreach (string id in ids) { UID uID = character.UID; if (id == ((UID)(ref uID)).Value) { flag = true; } } if (flag) { AddLootToLootableOnDeath(lootableOnDeath, itemsChances); } } public void AddLootForFaction(LootableOnDeath lootableOnDeath, Factions faction, List<ItemDropChance> itemsChances, List<string> exceptIds) { //IL_001c: Unknown result type (might be due to invalid IL or missing references) //IL_0021: Unknown result type (might be due to invalid IL or missing references) //IL_0037: Unknown result type (might be due to invalid IL or missing references) //IL_003c: Unknown result type (might be due to invalid IL or missing references) Character character = lootableOnDeath.m_character; if ((Object)(object)character == (Object)null) { OutwardLootManager.LogSL("LootManager@AddLootForFaction could not retrieve character!"); } else { if (character.Faction != faction) { return; } foreach (string exceptId in exceptIds) { UID uID = character.UID; if (exceptId == ((UID)(ref uID)).Value) { return; } } AddLootToLootableOnDeath(lootableOnDeath, itemsChances); } } public void AddLootForArea(LootableOnDeath lootableOnDeath, AreaEnum area, List<ItemDropChance> itemsChances, List<string> exceptIds) { //IL_001b: 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_003c: Unknown result type (might be due to invalid IL or missing references) //IL_005c: Unknown result type (might be due to invalid IL or missing references) //IL_0061: Unknown result type (might be due to invalid IL or missing references) Character character = lootableOnDeath.m_character; if ((Object)(object)character == (Object)null) { OutwardLootManager.LogSL("LootManager@AddLootForArea could not retrieve character!"); return; } Scene activeScene = SceneManager.GetActiveScene(); if (AreaManager.Instance.GetAreaFromSceneName(((Scene)(ref activeScene)).name).ID != AreaManager.Instance.GetArea(area).ID) { return; } foreach (string exceptId in exceptIds) { UID uID = character.UID; if (exceptId == ((UID)(ref uID)).Value) { return; } } AddLootToLootableOnDeath(lootableOnDeath, itemsChances); } public void AddLootToLootableOnDeath(LootableOnDeath lootOnDeath, List<ItemDropChance> itemDropChances) { //IL_0015: Unknown result type (might be due to invalid IL or missing references) //IL_001a: Unknown result type (might be due to invalid IL or missing references) //IL_004f: Unknown result type (might be due to invalid IL or missing references) //IL_0054: Unknown result type (might be due to invalid IL or missing references) //IL_0061: Unknown result type (might be due to invalid IL or missing references) //IL_0085: Unknown result type (might be due to invalid IL or missing references) //IL_00f3: Unknown result type (might be due to invalid IL or missing references) //IL_00fd: Expected O, but got Unknown Transform orCreatDropTableObject = GetOrCreatDropTableObject(lootOnDeath); Character character = lootOnDeath.Character; object value; if (character == null) { value = null; } else { UID uID = character.UID; value = ((UID)(ref uID)).Value; } if (string.IsNullOrEmpty((string?)value)) { OutwardLootManager.LogSL("LootManager@AddLootToLootableOnDeath Missing Item Container UID!"); return; } lootOnDeath.m_lootable = true; string lootId = GetLootId(lootOnDeath); GameObject val = new GameObject("LootManager_" + lootId); val.transform.SetParent(orCreatDropTableObject, false); Dropable val2 = val.AddComponent<Dropable>(); val2.m_targetContainer = lootOnDeath.Character.Inventory.Pouch; val2.m_uid = UID.op_Implicit(lootOnDeath.Character.UID) + "_" + lootOnDeath.m_lootDroppers.Length; lootOnDeath.m_lootDroppers = new List<Dropable>((IEnumerable<Dropable>)(((object)lootOnDeath.m_lootDroppers) ?? ((object)new Dropable[0]))) { val2 }.ToArray(); DropTable obj = val.AddComponent<DropTable>(); obj.UID = lootId; obj.m_itemDrops = itemDropChances; obj.m_emptyDropChance = 0; obj.m_dropAmount = new SimpleRandomChance(); obj.m_calculateChangeRequired = false; obj.m_maxDiceValue = itemDropChances.First().DropChance; val2.Start(); obj.Start(); } public void AddLootToLootableOnDeath(LootableOnDeath lootOnDeath, ItemDropRate itemDropRate) { //IL_003b: Unknown result type (might be due to invalid IL or missing references) //IL_0041: Unknown result type (might be due to invalid IL or missing references) //IL_007e: Unknown result type (might be due to invalid IL or missing references) //IL_0084: Expected O, but got Unknown //IL_00ba: Unknown result type (might be due to invalid IL or missing references) //IL_0173: Unknown result type (might be due to invalid IL or missing references) //IL_017d: Expected O, but got Unknown try { if ((Object)(object)lootOnDeath == (Object)null) { OutwardLootManager.LogMessage("AddLootToLootableOnDeath: lootOnDeath is null!"); return; } if ((Object)(object)lootOnDeath.Character == (Object)null) { OutwardLootManager.LogMessage("AddLootToLootableOnDeath: lootOnDeath.Character is null!"); return; } if (lootOnDeath.Character.UID == UID.op_Implicit((string)null)) { OutwardLootManager.LogMessage("AddLootToLootableOnDeath: lootOnDeath.Character.UID is null!"); return; } Transform orCreatDropTableObject = GetOrCreatDropTableObject(lootOnDeath); lootOnDeath.m_lootable = true; string lootId = GetLootId(lootOnDeath); GameObject val = new GameObject("LootManager_" + lootId); val.transform.SetParent(orCreatDropTableObject, false); Dropable val2 = val.AddComponent<Dropable>(); val2.m_targetContainer = lootOnDeath.Character.Inventory.Pouch; object arg = lootOnDeath.Character.UID; Dropable[] lootDroppers = lootOnDeath.m_lootDroppers; val2.m_uid = $"{arg}_{((lootDroppers != null) ? lootDroppers.Length : 0)}"; if (string.IsNullOrEmpty(val2.m_uid)) { OutwardLootManager.LogMessage("AddLootToLootableOnDeath: Invalid UID for " + ((Object)val).name); return; } List<Dropable> list = new List<Dropable>((IEnumerable<Dropable>)(((object)lootOnDeath.m_lootDroppers) ?? ((object)new Dropable[0]))); list.Add(val2); lootOnDeath.m_lootDroppers = list.ToArray(); DropTable obj = val.AddComponent<DropTable>(); obj.UID = lootId; obj.MinNumberOfDrops = itemDropRate.MinNumberOfDrops; obj.MaxNumberOfDrops = itemDropRate.MaxNumberOfDrops; obj.m_itemDrops = itemDropRate.ListItemDropChance; obj.m_emptyDropChance = itemDropRate.EmptyDropChance; obj.m_dropAmount = new SimpleRandomChance(); obj.m_calculateChangeRequired = itemDropRate.CalculateChangeRequired; obj.m_maxDiceValue = itemDropRate.MaxDiceValue; val2.Start(); obj.Start(); TryMakeLootable(lootOnDeath.Character); } catch (Exception ex) { OutwardLootManager.LogMessage("LootManager@AddLootToLootableOnDeath We encountered a problem: \"" + ex.Message + "\"!"); } } public bool TryMakeLootable(Character character, bool _dropWeapons = false, bool _enablePouch = true, bool _forceIteractable = true, bool _loadedDead = false) { if ((Object)(object)((character == null) ? null : character.Inventory?.m_inventoryPouch) == (Object)null) { OutwardLootManager.LogMessage("LootManager@TryMakeLootable can't make lootable! missing character?.Inventory?.m_invetoryPouch."); return false; } if (!Object.op_Implicit((Object)(object)((Component)((Component)character.Inventory.m_inventoryPouch).transform).GetComponent<InteractionLoot>())) { character.Inventory.MakeLootable(_dropWeapons, _enablePouch, _forceIteractable, _loadedDead); } return true; } public string GetLootId(LootableOnDeath lootOnDeath) { //IL_0047: Unknown result type (might be due to invalid IL or missing references) //IL_004d: Unknown result type (might be due to invalid IL or missing references) //IL_012b: Unknown result type (might be due to invalid IL or missing references) //IL_0145: Unknown result type (might be due to invalid IL or missing references) //IL_00c4: Unknown result type (might be due to invalid IL or missing references) try { if ((Object)(object)lootOnDeath == (Object)null) { OutwardLootManager.LogMessage("LootManager@GetLootId: lootOnDeath is null!"); return "invalid_lootOnDeath"; } if ((Object)(object)lootOnDeath.Character == (Object)null) { OutwardLootManager.LogMessage("LootManager@GetLootId: lootOnDeath.Character is null!"); return "invalid_character"; } if (lootOnDeath.Character.UID == UID.op_Implicit((string)null)) { OutwardLootManager.LogMessage("LootManager@GetLootId: lootOnDeath.Character.UID is null!"); return "invalid_UID"; } Dropable[] lootDroppers = lootOnDeath.m_lootDroppers; int num = ((lootDroppers != null) ? lootDroppers.Length : 0); int num2 = ((num >= 1) ? (num - 1) : 0); int num3 = 0; if (lootOnDeath.m_lootDroppers != null && num > 0) { List<DropTable> list = lootOnDeath.m_lootDroppers[num2]?.m_mainDropTables; if (list != null) { num3 = list.Count; } } return $"{lootOnDeath.Character.UID}_{num2.ToString()}_{num3.ToString()}"; } catch (Exception ex) { OutwardLootManager.LogMessage("LootManager@GetLootId We encountered a problem: \"" + ex.Message + "\"!"); UID? obj; if (lootOnDeath == null) { obj = null; } else { Character character = lootOnDeath.Character; obj = ((character != null) ? new UID?(character.UID) : null); } UID? val = obj; return "Error_" + (val.HasValue ? UID.op_Implicit(val.GetValueOrDefault()) : null); } } public bool HasDrops(LootableOnDeath lootOnDeath) { if ((Object)(object)lootOnDeath == (Object)null) { return false; } Transform val = ((Component)lootOnDeath).transform.Find("DropTables"); if ((Object)(object)val == (Object)null) { return false; } if ((Object)(object)((Component)val).GetComponentInChildren<Dropable>() == (Object)null) { return false; } return true; } public Transform GetOrCreatDropTableObject(LootableOnDeath lootOnDeath) { //IL_001f: Unknown result type (might be due to invalid IL or missing references) //IL_0024: Unknown result type (might be due to invalid IL or missing references) Transform val = ((Component)lootOnDeath).transform.Find("DropTables"); if ((Object)(object)val == (Object)null) { GameObject val2 = new GameObject("DropTables"); val2.transform.SetParent(((Component)lootOnDeath).transform); val = val2.transform; } return val; } } public class LootRuleRegistryManager { private static LootRuleRegistryManager _instance; public List<LootRule> lootRules = new List<LootRule>(); public static LootRuleRegistryManager Instance { get { if (_instance == null) { _instance = new LootRuleRegistryManager(); } return _instance; } } private LootRuleRegistryManager() { } public void AppendLootRules(List<LootRule> lootRules) { foreach (LootRule lootRule in lootRules) { AppendLootRule(lootRule); } } public void AppendLootRule(LootRule rule) { lootRules.Add(rule); EventBusPublisher.SendAppendLootRule(rule.id); } public void RemoveLootRuleById(string id) { foreach (LootRule item in lootRules.Where((LootRule rule) => rule.id == id).ToList()) { RemoveLootRule(item); } } public void RemoveLootRule(LootRule rule) { lootRules.Remove(rule); EventBusPublisher.SendRemoveLootRule(rule.id); } public List<LootRule> GetMatchingRules(Character character) { List<LootRule> list = new List<LootRule>(); foreach (LootRule lootRule in lootRules) { if (lootRule.Matches(character)) { list.Add(lootRule); } } return list; } } public class LootRulesSerializer { private static LootRulesSerializer _instance; public string configPath = ""; public string xmlFilePath = ""; public static LootRulesSerializer Instance { get { if (_instance == null) { _instance = new LootRulesSerializer(); } return _instance; } } private LootRulesSerializer() { configPath = Path.Combine(PathsManager.ConfigPath, "Loot_Manager"); xmlFilePath = Path.Combine(configPath, "PlayerCustomLoots.xml"); } public LootRulesFile Load(string path) { try { if (!File.Exists(path)) { OutwardLootManager.LogSL("LootRules file not found at: " + path); return null; } XmlSerializer xmlSerializer = new XmlSerializer(typeof(LootRulesFile)); using FileStream stream = new FileStream(path, FileMode.Open, FileAccess.Read); return xmlSerializer.Deserialize(stream) as LootRulesFile; } catch (Exception ex) { OutwardLootManager.LogSL("Failed to load LootRules file at '" + path + "': " + ex.Message); return null; } } public void LoadPlayerCustomLoots() { if (File.Exists(xmlFilePath)) { LoadCustomLoots(xmlFilePath); } } public void LoadCustomLoots(string path) { try { if (!File.Exists(path)) { OutwardLootManager.LogSL("LootRulesSerializer@LoadCustomLoots file not found at: " + path); return; } LootRulesFile lootRulesFile = Load(path); if (lootRulesFile != null) { List<LootRule> lootRules = GetLootRules(lootRulesFile); LootRuleRegistryManager.Instance.AppendLootRules(lootRules); } } catch (Exception ex) { OutwardLootManager.LogSL("LootRulesSerializer@LoadCustomLoots failed loading '" + path + "': " + ex.Message); } } public void SaveLootRulesToXml(string filePath, List<LootRule> lootRules) { try { string directoryName = Path.GetDirectoryName(filePath); if (!string.IsNullOrEmpty(directoryName) && !Directory.Exists(directoryName)) { Directory.CreateDirectory(directoryName); } LootRulesFile o = BuildLootRulesFile(lootRules); XmlSerializer xmlSerializer = new XmlSerializer(typeof(LootRulesFile)); XmlWriterSettings settings = new XmlWriterSettings { Indent = true, NewLineOnAttributes = false }; using XmlWriter xmlWriter = XmlWriter.Create(filePath, settings); xmlSerializer.Serialize(xmlWriter, o); } catch (Exception ex) { OutwardLootManager.LogSL("LootRulesSerializer@SaveLootRulesToXml failed saving '" + filePath + "': " + ex.Message); } } public List<LootRule> GetLootRules(LootRulesFile file) { //IL_0042: Unknown result type (might be due to invalid IL or missing references) //IL_0049: Expected O, but got Unknown List<LootRule> list = new List<LootRule>(); foreach (LootRuleSerializable rule in file.Rules) { List<ItemDropChance> list2 = new List<ItemDropChance>(); foreach (ItemDropChanceSerializable drop in rule.ItemDropRate.Drops) { ItemDropChance val = new ItemDropChance(); val.DropChance = drop.DropChance; val.ChanceReduction = drop.ChanceReduction; ((BasicItemDrop)val).ItemID = drop.ItemID; ((BasicItemDrop)val).MinDropCount = drop.MinDropCount; ((BasicItemDrop)val).MaxDropCount = drop.MaxDropCount; val.MinDiceRollValue = drop.MinDiceRollValue; val.MaxDiceRollValue = drop.MaxDiceRollValue; list2.Add(val); } ItemDropRate itemDropRate = new ItemDropRate(list2); itemDropRate.EmptyDropChance = rule.ItemDropRate.EmptyDropChance; itemDropRate.MaxDiceValue = rule.ItemDropRate.MaxDiceValue; itemDropRate.MinNumberOfDrops = rule.ItemDropRate.MinDrops; itemDropRate.MaxNumberOfDrops = rule.ItemDropRate.MaxDrops; itemDropRate.CalculateChangeRequired = rule.ItemDropRate.CalculateChangeRequired; LootRule lootRule = new LootRule(rule.Id, rule.EnemyID, rule.EnemyName, AreaFamiliesHelpers.GetAreaFamilyByName(rule.AreaFamilyName), itemDropRate); lootRule.area = AreaHelpers.GetAreaEnumFromAreaName(rule.AreaName); lootRule.faction = rule.Faction; lootRule.exceptIds = rule.ExceptIds; lootRule.exceptNames = rule.ExceptNames; lootRule.isBoss = rule.IsBoss; lootRule.isBossPawn = rule.IsBossPawn; lootRule.isStoryBoss = rule.IsStoryBoss; lootRule.isUniqueArenaBoss = rule.IsUniqueArenaBoss; lootRule.isUniqueEnemy = rule.IsUniqueEnemy; list.Add(lootRule); } return list; } public LootRulesFile BuildLootRulesFile(List<LootRule> lootRules) { //IL_01a3: Unknown result type (might be due to invalid IL or missing references) //IL_01a8: Unknown result type (might be due to invalid IL or missing references) //IL_01d8: Unknown result type (might be due to invalid IL or missing references) //IL_01dd: Unknown result type (might be due to invalid IL or missing references) LootRulesFile lootRulesFile = new LootRulesFile { Rules = new List<LootRuleSerializable>() }; foreach (LootRule lootRule in lootRules) { ItemDropRateSerializable itemDropRateSerializable = new ItemDropRateSerializable { Drops = new List<ItemDropChanceSerializable>(), EmptyDropChance = lootRule.itemDropRate.EmptyDropChance, MaxDiceValue = lootRule.itemDropRate.MaxDiceValue, MinDrops = lootRule.itemDropRate.MinNumberOfDrops, MaxDrops = lootRule.itemDropRate.MaxNumberOfDrops, CalculateChangeRequired = lootRule.itemDropRate.CalculateChangeRequired }; foreach (ItemDropChance item3 in lootRule.itemDropRate.ListItemDropChance) { ItemDropChanceSerializable item = new ItemDropChanceSerializable { ItemID = ((BasicItemDrop)item3).ItemID, DropChance = item3.DropChance, ChanceReduction = item3.ChanceReduction, MinDropCount = ((BasicItemDrop)item3).MinDropCount, MaxDropCount = ((BasicItemDrop)item3).MaxDropCount, MinDiceRollValue = item3.MinDiceRollValue, MaxDiceRollValue = item3.MaxDiceRollValue }; itemDropRateSerializable.Drops.Add(item); } LootRuleSerializable obj = new LootRuleSerializable { Id = (lootRule.id ?? null), EnemyID = (lootRule.enemyID ?? null), EnemyName = (lootRule.enemyName ?? ""), AreaFamilyName = (lootRule.areaFamily?.FamilyName ?? "") }; ref Factions? faction = ref lootRule.faction; object obj2; if (!faction.HasValue) { obj2 = null; } else { Factions valueOrDefault = faction.GetValueOrDefault(); obj2 = ((object)(Factions)(ref valueOrDefault)).ToString(); } if (obj2 == null) { obj2 = ""; } obj.FactionName = (string)obj2; ref AreaEnum? area = ref lootRule.area; object obj3; if (!area.HasValue) { obj3 = null; } else { AreaEnum valueOrDefault2 = area.GetValueOrDefault(); obj3 = ((object)(AreaEnum)(ref valueOrDefault2)).ToString(); } if (obj3 == null) { obj3 = ""; } obj.AreaName = (string)obj3; obj.ItemDropRate = itemDropRateSerializable; obj.ExceptIds = lootRule.exceptIds ?? null; obj.ExceptNames = lootRule.exceptNames ?? null; obj.IsBoss = lootRule.isBoss; obj.IsBossPawn = lootRule.isBossPawn; obj.IsStoryBoss = lootRule.isStoryBoss; obj.IsUniqueArenaBoss = lootRule.isUniqueArenaBoss; obj.IsUniqueEnemy = lootRule.isUniqueEnemy; LootRuleSerializable item2 = obj; lootRulesFile.Rules.Add(item2); } return lootRulesFile; } } } namespace OutwardLootManager.Events { public static class EventBusPublisher { public const string Event_AppendLootRule = "LootRuleRegistryManager@AppendLootRule"; public const string Event_RemoveLootRule = "LootRuleRegistryManager@RemoveLootRule"; public const string Event_AddSceneLoopAction = "AddSceneLoopAction"; public const string Scene_Tester_Listener = "gymmed.scene_tester_*"; public static void SendAppendLootRule(string id) { //IL_0000: Unknown result type (might be due to invalid IL or missing references) //IL_0012: Unknown result type (might be due to invalid IL or missing references) //IL_001a: Expected O, but got Unknown //IL_001b: Expected O, but got Unknown EventPayload val = new EventPayload { }; string item; ((Dictionary<string, object>)val)[item] = id; EventPayload val2 = val; EventBus.Publish("gymmed.loot_manager", "LootRuleRegistryManager@AppendLootRule", val2); } public static void SendRemoveLootRule(string id) { //IL_0000: Unknown result type (might be due to invalid IL or missing references) //IL_0012: Unknown result type (might be due to invalid IL or missing references) //IL_001a: Expected O, but got Unknown //IL_001b: Expected O, but got Unknown EventPayload val = new EventPayload { }; string item; ((Dictionary<string, object>)val)[item] = id; EventPayload val2 = val; EventBus.Publish("gymmed.loot_manager", "LootRuleRegistryManager@RemoveLootRule", val2); } public static void SendSceneLoopAction(Action function, HashSet<AreaEnum> areas) { //IL_0000: Unknown result type (might be due to invalid IL or missing references) //IL_0005: Unknown result type (might be due to invalid IL or missing references) //IL_0011: Expected O, but got Unknown //IL_0011: Unknown result type (might be due to invalid IL or missing references) //IL_001d: Expected O, but got Unknown //IL_001e: Expected O, but got Unknown EventPayload val = new EventPayload(); ((Dictionary<string, object>)val)["action"] = function; ((Dictionary<string, object>)val)["hashSetOfAreas"] = areas; EventPayload val2 = val; EventBus.Publish("gymmed.scene_tester_*", "AddSceneLoopAction", val2); } public static void SendSceneLoopAction(string actionId, Action function, HashSet<AreaEnum> areas) { //IL_0000: Unknown result type (might be due to invalid IL or missing references) //IL_0005: Unknown result type (might be due to invalid IL or missing references) //IL_0011: Expected O, but got Unknown //IL_0011: Unknown result type (might be due to invalid IL or missing references) //IL_001d: Expected O, but got Unknown //IL_001d: Unknown result type (might be due to invalid IL or missing references) //IL_0029: Expected O, but got Unknown //IL_002a: Expected O, but got Unknown EventPayload val = new EventPayload(); ((Dictionary<string, object>)val)["actionId"] = actionId; ((Dictionary<string, object>)val)["action"] = function; ((Dictionary<string, object>)val)["hashSetOfAreas"] = areas; EventPayload val2 = val; EventBus.Publish("gymmed.scene_tester_*", "AddSceneLoopAction", val2); } public static void SendEnchantmentDescriptions() { //IL_0000: Unknown result type (might be due to invalid IL or missing references) //IL_0005: Unknown result type (might be due to invalid IL or missing references) //IL_0024: Expected O, but got Unknown //IL_0025: Expected O, but got Unknown EventPayload val = new EventPayload(); ((Dictionary<string, object>)val)["filePath"] = Path.Combine(LootRulesSerializer.Instance.configPath, "ModsCustomEnchantmentsDescriptions.xml"); EventPayload val2 = val; EventBus.Publish("gymmed.outward_enchantments_viewer_*", "LoadCustomEnchantmentsDescriptionsXml", val2); } } public static class EventBusRegister { private static readonly (string key, Type type, string description)[] EnvironmentConditionsParams = new(string, Type, string)[3] { EventRegistryParamsHelper.Get(EventRegistryParams.AreaFamily), EventRegistryParamsHelper.Get(EventRegistryParams.Faction), EventRegistryParamsHelper.Get(EventRegistryParams.AreaEnum) }; private static readonly (string key, Type type, string description)[] UniqueEnemiesParams = new(string, Type, string)[5] { EventRegistryParamsHelper.Get(EventRegistryParams.IsForBosses), EventRegistryParamsHelper.Get(EventRegistryParams.IsForBossesPawns), EventRegistryParamsHelper.Get(EventRegistryParams.IsForStoryBosses), EventRegistryParamsHelper.Get(EventRegistryParams.IsForUniqueArenaBosses), EventRegistryParamsHelper.Get(EventRegistryParams.IsForUniqueEnemies) }; private static readonly (string key, Type type, string description)[] DropRateParams = new(string, Type, string)[4] { EventRegistryParamsHelper.Get(EventRegistryParams.EmptyDropChance), EventRegistryParamsHelper.Get(EventRegistryParams.MaxDiceValue), EventRegistryParamsHelper.Get(EventRegistryParams.MinNumberOfDrops), EventRegistryParamsHelper.Get(EventRegistryParams.MaxNumberOfDrops) }; private static readonly (string key, Type type, string description)[] DropChanceProvideWaysParams = new(string, Type, string)[2] { EventRegistryParamsHelper.Get(EventRegistryParams.ItemDropChance), EventRegistryParamsHelper.Get(EventRegistryParams.ListOfItemDropChances) }; private static readonly (string key, Type type, string description)[] DropChanceParams = new(string, Type, string)[6] { EventRegistryParamsHelper.Get(EventRegistryParams.ItemId), EventRegistryParamsHelper.Get(EventRegistryParams.DropChance), EventRegistryParamsHelper.Get(EventRegistryParams.MinDropCount), EventRegistryParamsHelper.Get(EventRegistryParams.MaxDropCount), EventRegistryParamsHelper.Get(EventRegistryParams.MinDiceRollValue), EventRegistryParamsHelper.Get(EventRegistryParams.MaxDiceValue) }; private static readonly (string key, Type type, string description)[] ExceptionsParams = new(string, Type, string)[2] { EventRegistryParamsHelper.Get(EventRegistryParams.ExceptIds), EventRegistryParamsHelper.Get(EventRegistryParams.ExceptNames) }; public static void RegisterEvents() { EventBus.RegisterEvent("gymmed.loot_manager", "LootRuleRegistryManager@AppendLootRule", "Publishes event on appending loot rule to loot manager.", new(string, Type, string)[1] { EventRegistryParamsHelper.Get(EventRegistryParams.LootRuleId) }); EventBus.RegisterEvent("gymmed.loot_manager", "LootRuleRegistryManager@RemoveLootRule", "Publishes event on removing loot rule from loot manager.", new(string, Type, string)[1] { EventRegistryParamsHelper.Get(EventRegistryParams.LootRuleId) }); EventBus.RegisterEvent("gymmed.loot_manager_*", "LootRulesSerializer@LoadCustomLoots", "Listens for event, when to load custom loot rules from xml.", new(string, Type, string)[1] { EventRegistryParamsHelper.Get(EventRegistryParams.LoadLootsXmlFilePath) }); EventBus.RegisterEvent("gymmed.loot_manager_*", "LootRulesSerializer@SaveLootRulesToXml", "Listens for event, when to store loot manager loot rules to xml.", new(string, Type, string)[1] { EventRegistryParamsHelper.Get(EventRegistryParams.StoreLootsXmlFilePath) }); EventBus.RegisterEvent("gymmed.loot_manager_*", "AddLoot", "Very abstract way to add loot rules. It allows you pass all the possible variables to determine if loot should be applied to a character.", EventRegistryParamsHelper.Combine(EventRegistryParamsHelper.Get(EventRegistryParams.LootId), EnvironmentConditionsParams, UniqueEnemiesParams, DropRateParams, DropChanceProvideWaysParams, DropChanceParams, ExceptionsParams)); EventBus.RegisterEvent("gymmed.loot_manager_*", "AddLootByEnemyId", "Add loot rule for specific enemy id. If enemy id validates it will not check other requirements!", EventRegistryParamsHelper.Combine(EventRegistryParamsHelper.Get(EventRegistryParams.LootId), EventRegistryParamsHelper.Get(EventRegistryParams.EnemyId), DropRateParams, DropChanceProvideWaysParams, DropChanceParams)); EventBus.RegisterEvent("gymmed.loot_manager_*", "AddLootByEnemyName", "Add loot rule for specific enemy name. Simple way to add loot rule for specific characters. If using for bosses or unique enemies make sure to attach atleast one of the variables: " + EventRegistryParamsHelper.Get(EventRegistryParams.IsForUniqueEnemies).key + "/" + EventRegistryParamsHelper.Get(EventRegistryParams.IsForBosses).key + "/" + EventRegistryParamsHelper.Get(EventRegistryParams.IsForStoryBosses).key + "/" + EventRegistryParamsHelper.Get(EventRegistryParams.IsForUniqueArenaBosses).key + "/" + EventRegistryParamsHelper.Get(EventRegistryParams.IsForBossesPawns).key + " otherwise it will not be applied.", EventRegistryParamsHelper.Combine(EventRegistryParamsHelper.Get(EventRegistryParams.LootId), EventRegistryParamsHelper.Get(EventRegistryParams.EnemyName), DropRateParams, DropChanceProvideWaysParams, DropChanceParams, EventRegistryParamsHelper.Get(EventRegistryParams.ExceptIds))); EventBus.RegisterEvent("gymmed.loot_manager_*", "AddLootForUniques", "Add loot rule for unique enemy groups." + EventRegistryParamsHelper.Combine(EventRegistryParamsHelper.Get(EventRegistryParams.LootId), UniqueEnemiesParams, DropRateParams, DropChanceProvideWaysParams, DropChanceParams, ExceptionsParams), (EventSchema)null); } } public static class EventBusSubscriber { public const string Event_AddLoot = "AddLoot"; public const string Event_AddLootByEnemyName = "AddLootByEnemyName"; public const string Event_AddLootByEnemyId = "AddLootByEnemyId"; public const string Event_AddLootForUniques = "AddLootForUniques"; public const string Event_StoreLootToXml = "LootRulesSerializer@SaveLootRulesToXml"; public const string Event_LoadCustomLoots = "LootRulesSerializer@LoadCustomLoots"; public static string SceneUniquesActionId = UID.op_Implicit(UID.Generate()); public const string Event_FinishedSceneLoopAction = "FinishedSceneLoopAction"; public static void AddSubscribers() { EventBus.Subscribe("gymmed.loot_manager_*", "AddLoot", (Action<EventPayload>)AddLoot); EventBus.Subscribe("gymmed.loot_manager_*", "AddLootByEnemyName", (Action<EventPayload>)AddLootByEnemyName); EventBus.Subscribe("gymmed.loot_manager_*", "AddLootByEnemyId", (Action<EventPayload>)AddLootByEnemyId); EventBus.Subscribe("gymmed.loot_manager_*", "AddLootForUniques", (Action<EventPayload>)AddLootForUniques); EventBus.Subscribe("gymmed.loot_manager_*", "LootRulesSerializer@SaveLootRulesToXml", (Action<EventPayload>)StoreLootsToXml); EventBus.Subscribe("gymmed.loot_manager_*", "LootRulesSerializer@LoadCustomLoots", (Action<EventPayload>)LoadLootsXml); } public static void AddSceneTesterSubscribers() { EventBus.Subscribe("gymmed.scene_tester", "FinishedSceneLoopAction", (Action<EventPayload>)FinishedSceneLoopAction); } public static void AddLoot(EventPayload payload) { if (payload == null) { return; } LootRule lootRule = new LootRule(); LootRuleHelpers.TryToFillRuleWithId(lootRule, payload); if (!LootRuleHelpers.GetItemDropRateAndFillInRule(lootRule, payload)) { OutwardLootManager.LogSL("EventBusSubscriber@AddLoot didn't receive " + EventRegistryParamsHelper.Get(EventRegistryParams.ItemId).key + "/" + EventRegistryParamsHelper.Get(EventRegistryParams.ItemDropChance).key + "/" + EventRegistryParamsHelper.Get(EventRegistryParams.ListOfItemDropChances).key + "! Cannot add loot!"); return; } bool flag = LootRuleHelpers.FillRuleWithEnvironmentConditions(lootRule, payload); bool num = LootRuleHelpers.FillRuleForStrongEnemyTypes(lootRule, payload); bool flag2 = LootRuleHelpers.TryToFillRuleWithEnemyName(lootRule, payload); bool flag3 = LootRuleHelpers.TryToFillRuleWithEnemyId(lootRule, payload); if (!num && !flag3 && !flag2 && !flag) { OutwardLootManager.LogSL("EventBusSubscriber@AddLoot didn't receive " + EventRegistryParamsHelper.Get(EventRegistryParams.EnemyName).key + "/" + EventRegistryParamsHelper.Get(EventRegistryParams.EnemyId).key + "/" + EventRegistryParamsHelper.Get(EventRegistryParams.Faction).key + "/" + EventRegistryParamsHelper.Get(EventRegistryParams.AreaFamily).key + "/" + EventRegistryParamsHelper.Get(EventRegistryParams.AreaEnum).key + "/" + EventRegistryParamsHelper.Get(EventRegistryParams.IsForBosses).key + "/" + EventRegistryParamsHelper.Get(EventRegistryParams.IsForBossesPawns).key + "/" + EventRegistryParamsHelper.Get(EventRegistryParams.IsForStoryBosses).key + EventRegistryParamsHelper.Get(EventRegistryParams.IsForUniqueArenaBosses).key + EventRegistryParamsHelper.Get(EventRegistryParams.IsForUniqueEnemies).key + ". Cannot add loot!"); } else { LootRuleHelpers.FillRuleWithExceptions(lootRule, payload); LootRuleRegistryManager.Instance.AppendLootRule(lootRule); } } public static void AddLootByEnemyName(EventPayload payload) { if (payload == null) { return; } LootRule lootRule = new LootRule(); LootRuleHelpers.TryToFillRuleWithId(lootRule, payload); if (LootRuleHelpers.TryToFillRuleWithEnemyName(lootRule, payload, required: true)) { if (!LootR