From 39c07eec30d9dc30b379fef241520ff43d9ca6f8 Mon Sep 17 00:00:00 2001 From: Arsenii Fomin Date: Thu, 15 Feb 2024 21:30:07 +0700 Subject: [PATCH 1/3] Changed item gating with dropping item materials instead --- EpicLoot/GatedItemType/GatedItemTypeHelper.cs | 56 +++++------ EpicLoot/LootRoller.cs | 96 +++++++++++-------- 2 files changed, 79 insertions(+), 73 deletions(-) diff --git a/EpicLoot/GatedItemType/GatedItemTypeHelper.cs b/EpicLoot/GatedItemType/GatedItemTypeHelper.cs index 573094d2c..bcc1945a2 100644 --- a/EpicLoot/GatedItemType/GatedItemTypeHelper.cs +++ b/EpicLoot/GatedItemType/GatedItemTypeHelper.cs @@ -111,24 +111,9 @@ public static string GetGatedItemID(string itemID, GatedItemTypeMode mode, List< return null; } - while (CheckIfItemNeedsGate(mode, itemID, itemName)) + if (ItemNotAllowedYet(mode, itemID, itemName)) { - //EpicLoot.Log("Yes..."); - - var index = info.Items.IndexOf(itemID); - if (index < 0) - { - // Items list is empty, no need to gate any items from of this type - return itemID; - } - if (index == 0) - { - return string.IsNullOrEmpty(info.Fallback) ? itemID : GetGatedFallbackItem(info.Fallback, mode, itemID, usedTypes); - } - - itemID = info.Items[index - 1]; - itemName = GetItemName(itemID); - //EpicLoot.Log($"Next lower tier item is ({itemID} - {itemName})"); + return null; } return itemID; @@ -154,24 +139,33 @@ private static string GetItemName(string itemID) return item.m_shared.m_name; } - private static bool CheckIfItemNeedsGate(GatedItemTypeMode mode, string itemID, string itemName) + private static bool ItemNotAllowedYet(GatedItemTypeMode mode, string itemID, string itemName) { - if (!BossPerItem.ContainsKey(itemID)) + if (mode == GatedItemTypeMode.PlayerMustKnowRecipe) { - EpicLoot.LogWarning($"Item ({itemID}) was not registered in iteminfo.json with any particular boss"); - return false; + return Player.m_localPlayer != null && !Player.m_localPlayer.IsRecipeKnown(itemName); } - - var bossKeyForItem = BossPerItem[itemID]; - var prevBossKey = Bosses.GetPrevBossKey(bossKeyForItem); - //EpicLoot.Log($"Checking if item ({itemID}) needs gating (boss: {bossKeyForItem}, prev boss: {prevBossKey}"); - switch (mode) + else if (mode == GatedItemTypeMode.PlayerMustHaveCraftedItem) { - case GatedItemTypeMode.BossKillUnlocksCurrentBiomeItems: return !ZoneSystem.instance.GetGlobalKey(bossKeyForItem); - case GatedItemTypeMode.BossKillUnlocksNextBiomeItems: return !(string.IsNullOrEmpty(prevBossKey) || ZoneSystem.instance.GetGlobalKey(prevBossKey)); - case GatedItemTypeMode.PlayerMustKnowRecipe: return Player.m_localPlayer != null && !Player.m_localPlayer.IsRecipeKnown(itemName); - case GatedItemTypeMode.PlayerMustHaveCraftedItem: return Player.m_localPlayer != null && !Player.m_localPlayer.m_knownMaterial.Contains(itemName); - default: return false; + return Player.m_localPlayer != null && !Player.m_localPlayer.m_knownMaterial.Contains(itemName); + } + else + { + if (!BossPerItem.ContainsKey(itemID)) + { + EpicLoot.LogWarning($"Item ({itemID}) was not registered in iteminfo.json with any particular boss"); + return false; + } + + var bossKeyForItem = BossPerItem[itemID]; + var prevBossKey = Bosses.GetPrevBossKey(bossKeyForItem); + //EpicLoot.Log($"Checking if item ({itemID}) needs gating (boss: {bossKeyForItem}, prev boss: {prevBossKey}"); + switch (mode) + { + case GatedItemTypeMode.BossKillUnlocksCurrentBiomeItems: return !ZoneSystem.instance.GetGlobalKey(bossKeyForItem); + case GatedItemTypeMode.BossKillUnlocksNextBiomeItems: return !(string.IsNullOrEmpty(prevBossKey) || ZoneSystem.instance.GetGlobalKey(prevBossKey)); + default: return false; + } } } diff --git a/EpicLoot/LootRoller.cs b/EpicLoot/LootRoller.cs index a36f64a53..2eabeb2cd 100644 --- a/EpicLoot/LootRoller.cs +++ b/EpicLoot/LootRoller.cs @@ -270,60 +270,72 @@ private static List RollLootTableInternal(LootTable lootTable, int l var itemName = !string.IsNullOrEmpty(lootDrop?.Item) ? lootDrop.Item : "Invalid Item Name"; var rarityLength = lootDrop?.Rarity?.Length != null ? lootDrop.Rarity.Length : -1; EpicLoot.Log($"Item: {itemName} - Rarity Count: {rarityLength} - Weight: {lootDrop.Weight}"); - - if (!cheatsActive && EpicLoot.ItemsToMaterialsDropRatio.Value > 0) + + var itemID = (CheatDisableGating) ? lootDrop.Item : GatedItemTypeHelper.GetGatedItemID(lootDrop.Item); + + bool ReplaceWithMats() { - var clampedConvertRate = Mathf.Clamp(EpicLoot.ItemsToMaterialsDropRatio.Value, 0.0f, 1.0f); - var replaceWithMats = Random.Range(0.0f, 1.0f) < clampedConvertRate; - if (replaceWithMats) + if (itemID == null) { - GameObject prefab = null; + return true; + } - try - { - prefab = ObjectDB.instance.GetItemPrefab(lootDrop.Item); - } - catch (Exception e) - { - EpicLoot.LogWarning($"Unable to get Prefab for [{lootDrop.Item}]. Continuing."); - EpicLoot.LogWarning($"Error: {e.Message}"); - } + if (!cheatsActive && EpicLoot.ItemsToMaterialsDropRatio.Value > 0) + { + var clampedConvertRate = Mathf.Clamp(EpicLoot.ItemsToMaterialsDropRatio.Value, 0.0f, 1.0f); + return Random.Range(0.0f, 1.0f) < clampedConvertRate; + } + + return false; + }; + + if (ReplaceWithMats()) + { + GameObject prefab = null; - if (prefab != null) + try + { + prefab = ObjectDB.instance.GetItemPrefab(lootDrop.Item); + } + catch (Exception e) + { + EpicLoot.LogWarning($"Unable to get Prefab for [{lootDrop.Item}]. Continuing."); + EpicLoot.LogWarning($"Error: {e.Message}"); + } + + if (prefab != null) + { + var rarity = RollItemRarity(lootDrop, luckFactor); + var itemType = prefab.GetComponent().m_itemData.m_shared.m_itemType; + var disenchantProducts = EnchantCostsHelper.GetSacrificeProducts(true, itemType, rarity); + if (disenchantProducts != null) { - var rarity = RollItemRarity(lootDrop, luckFactor); - var itemType = prefab.GetComponent().m_itemData.m_shared.m_itemType; - var disenchantProducts = EnchantCostsHelper.GetSacrificeProducts(true, itemType, rarity); - if (disenchantProducts != null) + foreach (var itemAmountConfig in disenchantProducts) { - foreach (var itemAmountConfig in disenchantProducts) + GameObject materialPrefab = null; + try { - GameObject materialPrefab = null; - try - { - materialPrefab = ObjectDB.instance.GetItemPrefab(itemAmountConfig.Item); - } - catch (Exception e) - { - EpicLoot.LogWarning($"Unable to get Disenchant Product Prefab for [{itemAmountConfig?.Item ?? "Invalid Item"}]. Continuing."); - EpicLoot.LogWarning($"Error: {e.Message}"); - } - - if (materialPrefab == null) continue; - var materialItem = SpawnLootForDrop(materialPrefab, dropPoint, true); - var materialItemDrop = materialItem.GetComponent(); - materialItemDrop.m_itemData.m_stack = itemAmountConfig.Amount; - if (materialItemDrop.m_itemData.IsMagicCraftingMaterial()) - materialItemDrop.m_itemData.m_variant = EpicLoot.GetRarityIconIndex(rarity); - results.Add(materialItem); + materialPrefab = ObjectDB.instance.GetItemPrefab(itemAmountConfig.Item); } + catch (Exception e) + { + EpicLoot.LogWarning($"Unable to get Disenchant Product Prefab for [{itemAmountConfig?.Item ?? "Invalid Item"}]. Continuing."); + EpicLoot.LogWarning($"Error: {e.Message}"); + } + + if (materialPrefab == null) continue; + var materialItem = SpawnLootForDrop(materialPrefab, dropPoint, true); + var materialItemDrop = materialItem.GetComponent(); + materialItemDrop.m_itemData.m_stack = itemAmountConfig.Amount; + if (materialItemDrop.m_itemData.IsMagicCraftingMaterial()) + materialItemDrop.m_itemData.m_variant = EpicLoot.GetRarityIconIndex(rarity); + results.Add(materialItem); } } - - continue; } + + continue; } - var itemID = (CheatDisableGating) ? lootDrop.Item : GatedItemTypeHelper.GetGatedItemID(lootDrop.Item); GameObject itemPrefab = null; From 516531dbf04a8022e83a06cfde7729e0b8efe565 Mon Sep 17 00:00:00 2001 From: Arsenii Fomin Date: Mon, 4 Mar 2024 09:11:27 +0700 Subject: [PATCH 2/3] Implemented item drop limits exceptions --- EpicLoot/EpicLoot.cs | 4 +++- EpicLoot/GatedItemType/GatedItemTypeHelper.cs | 17 ++++++++--------- EpicLoot/LootConfig.cs | 1 + EpicLoot/LootRoller.cs | 2 +- EpicLoot/loottables.json | 16 ++++++++++++++++ 5 files changed, 29 insertions(+), 11 deletions(-) diff --git a/EpicLoot/EpicLoot.cs b/EpicLoot/EpicLoot.cs index 884bdd427..c8ffd9287 100644 --- a/EpicLoot/EpicLoot.cs +++ b/EpicLoot/EpicLoot.cs @@ -117,6 +117,7 @@ public class EpicLoot : BaseUnityPlugin private static ConfigEntry _logLevel; public static ConfigEntry UseGeneratedMagicItemNames; private static ConfigEntry _gatedItemTypeModeConfig; + public static ConfigEntry AllowItemDropLimitsExceptions; public static ConfigEntry BossBountyMode; private static ConfigEntry _bossTrophyDropMode; private static ConfigEntry _bossTrophyDropPlayerRange; @@ -220,7 +221,8 @@ private void Awake() _loggingEnabled = Config.Bind("Logging", "Logging Enabled", false, "Enable logging"); _logLevel = Config.Bind("Logging", "Log Level", LogLevel.Info, "Only log messages of the selected level or higher"); UseGeneratedMagicItemNames = Config.Bind("General", "Use Generated Magic Item Names", true, "If true, magic items uses special, randomly generated names based on their rarity, type, and magic effects."); - _gatedItemTypeModeConfig = SyncedConfig("Balance", "Item Drop Limits", GatedItemTypeMode.BossKillUnlocksCurrentBiomeItems, "Sets how the drop system limits what item types can drop. Unlimited: no limits, exactly what's in the loot table will drop. BossKillUnlocksCurrentBiomeItems: items will drop for the current biome if the that biome's boss has been killed (Leather gear will drop once Eikthyr is killed). BossKillUnlocksNextBiomeItems: items will only drop for the current biome if the previous biome's boss is killed (Bronze gear will drop once Eikthyr is killed). PlayerMustKnowRecipe: (local world only) the item can drop if the player can craft it. PlayerMustHaveCraftedItem: (local world only) the item can drop if the player has already crafted it or otherwise picked it up. If an item type cannot drop, it will downgrade to an item of the same type and skill that the player has unlocked (i.e. swords will stay swords) according to iteminfo.json."); + _gatedItemTypeModeConfig = SyncedConfig("Balance", "Item Drop Limits", GatedItemTypeMode.BossKillUnlocksCurrentBiomeItems, "Sets how the drop system limits what item types can drop. Unlimited: no limits, exactly what's in the loot table will drop. BossKillUnlocksCurrentBiomeItems: items will drop for the current biome if the that biome's boss has been killed (Leather gear will drop once Eikthyr is killed). BossKillUnlocksNextBiomeItems: items will only drop for the current biome if the previous biome's boss is killed (Bronze gear will drop once Eikthyr is killed). PlayerMustKnowRecipe: (local world only) the item can drop if the player can craft it. PlayerMustHaveCraftedItem: (local world only) the item can drop if the player has already crafted it or otherwise picked it up. If an item type cannot drop, it will be converted into materials."); + AllowItemDropLimitsExceptions = SyncedConfig("Balance", "Allow Item Drop Limits Exceptions", false, "Allows specific items (configured in loottables.json) to be dropped even if not permited by current Item Drop Limits mode"); BossBountyMode = SyncedConfig("Balance", "Gated Bounty Mode", GatedBountyMode.Unlimited, "Sets whether available bounties are ungated or gated by boss kills."); _bossTrophyDropMode = SyncedConfig("Balance", "Boss Trophy Drop Mode", BossDropMode.OnePerPlayerNearBoss, "Sets bosses to drop a number of trophies equal to the number of players. Optionally set it to only include players within a certain distance, use 'Boss Trophy Drop Player Range' to set the range."); _bossTrophyDropPlayerRange = SyncedConfig("Balance", "Boss Trophy Drop Player Range", 100.0f, "Sets the range that bosses check when dropping multiple trophies using the OnePerPlayerNearBoss drop mode."); diff --git a/EpicLoot/GatedItemType/GatedItemTypeHelper.cs b/EpicLoot/GatedItemType/GatedItemTypeHelper.cs index bcc1945a2..4ad195f84 100644 --- a/EpicLoot/GatedItemType/GatedItemTypeHelper.cs +++ b/EpicLoot/GatedItemType/GatedItemTypeHelper.cs @@ -52,9 +52,9 @@ public static void Initialize(ItemInfoConfig config) } } - public static string GetGatedItemID(string itemID) + public static string GetGatedItemID(string itemID, List itemDropLimitsExceptions = null) { - return GetGatedItemID(itemID, EpicLoot.GetGatedItemTypeMode()); + return GetGatedItemID(itemID, EpicLoot.GetGatedItemTypeMode(), null, itemDropLimitsExceptions); } public static string GetGatedFallbackItem(string infoType, GatedItemTypeMode mode, string originalItemID, List usedTypes = null) @@ -80,7 +80,7 @@ public static string GetGatedFallbackItem(string infoType, GatedItemTypeMode mod return returnItem; } - public static string GetGatedItemID(string itemID, GatedItemTypeMode mode, List usedTypes = null) + public static string GetGatedItemID(string itemID, GatedItemTypeMode mode, List usedTypes = null, List itemDropLimitsExceptions = null) { if (string.IsNullOrEmpty(itemID)) { @@ -88,6 +88,11 @@ public static string GetGatedItemID(string itemID, GatedItemTypeMode mode, List< return null; } + if(EpicLoot.AllowItemDropLimitsExceptions.Value && itemDropLimitsExceptions != null && itemDropLimitsExceptions.Contains(itemID)) + { + return itemID; + } + if (mode == GatedItemTypeMode.Unlimited) { return itemID; @@ -98,12 +103,6 @@ public static string GetGatedItemID(string itemID, GatedItemTypeMode mode, List< EpicLoot.LogError($"Tried to get gated itemID ({itemID}) but ObjectDB is not initialized!"); return null; } - - //Gets Info Item for specific itemId - if (!ItemInfoByID.TryGetValue(itemID, out var info)) - { - return itemID; - } var itemName = GetItemName(itemID); if (string.IsNullOrEmpty(itemName)) diff --git a/EpicLoot/LootConfig.cs b/EpicLoot/LootConfig.cs index 9dd956e9c..9760e7269 100644 --- a/EpicLoot/LootConfig.cs +++ b/EpicLoot/LootConfig.cs @@ -57,5 +57,6 @@ public class LootConfig public LootItemSet[] ItemSets; public LootTable[] LootTables; public List RestrictedItems = new List(); + public List ItemDropLimitsExceptions = new List(); } } diff --git a/EpicLoot/LootRoller.cs b/EpicLoot/LootRoller.cs index 2eabeb2cd..17de44a9e 100644 --- a/EpicLoot/LootRoller.cs +++ b/EpicLoot/LootRoller.cs @@ -271,7 +271,7 @@ private static List RollLootTableInternal(LootTable lootTable, int l var rarityLength = lootDrop?.Rarity?.Length != null ? lootDrop.Rarity.Length : -1; EpicLoot.Log($"Item: {itemName} - Rarity Count: {rarityLength} - Weight: {lootDrop.Weight}"); - var itemID = (CheatDisableGating) ? lootDrop.Item : GatedItemTypeHelper.GetGatedItemID(lootDrop.Item); + var itemID = (CheatDisableGating) ? lootDrop.Item : GatedItemTypeHelper.GetGatedItemID(lootDrop.Item, Config.ItemDropLimitsExceptions); bool ReplaceWithMats() { diff --git a/EpicLoot/loottables.json b/EpicLoot/loottables.json index 71a60f7ac..5b5ed4fd4 100644 --- a/EpicLoot/loottables.json +++ b/EpicLoot/loottables.json @@ -26,6 +26,22 @@ "$item_pickaxe_stone" ], + /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + // ITEM DROP LIMITS EXCEPTIONS + // - these items can drop even if the player doesn't meet Item Drop Limits criterion + /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + "ItemDropLimitsExceptions": [ + "Club", + "AxeStone", + "Torch", + "Hammer", + "Hoe", + "ArmorRagsLegs", + "ArmorRagsChest", + "ShieldWood", + "ShieldWoodTower" + ], + /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// // ITEM SETS /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// From bb0c42ea2fe6cd44cb9cfae6b5cd238851e21867 Mon Sep 17 00:00:00 2001 From: Arsenii Fomin Date: Mon, 4 Mar 2024 09:20:59 +0700 Subject: [PATCH 3/3] Hotfix --- EpicLoot/EpicLoot.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/EpicLoot/EpicLoot.cs b/EpicLoot/EpicLoot.cs index c8ffd9287..5e13b25f7 100644 --- a/EpicLoot/EpicLoot.cs +++ b/EpicLoot/EpicLoot.cs @@ -222,7 +222,7 @@ private void Awake() _logLevel = Config.Bind("Logging", "Log Level", LogLevel.Info, "Only log messages of the selected level or higher"); UseGeneratedMagicItemNames = Config.Bind("General", "Use Generated Magic Item Names", true, "If true, magic items uses special, randomly generated names based on their rarity, type, and magic effects."); _gatedItemTypeModeConfig = SyncedConfig("Balance", "Item Drop Limits", GatedItemTypeMode.BossKillUnlocksCurrentBiomeItems, "Sets how the drop system limits what item types can drop. Unlimited: no limits, exactly what's in the loot table will drop. BossKillUnlocksCurrentBiomeItems: items will drop for the current biome if the that biome's boss has been killed (Leather gear will drop once Eikthyr is killed). BossKillUnlocksNextBiomeItems: items will only drop for the current biome if the previous biome's boss is killed (Bronze gear will drop once Eikthyr is killed). PlayerMustKnowRecipe: (local world only) the item can drop if the player can craft it. PlayerMustHaveCraftedItem: (local world only) the item can drop if the player has already crafted it or otherwise picked it up. If an item type cannot drop, it will be converted into materials."); - AllowItemDropLimitsExceptions = SyncedConfig("Balance", "Allow Item Drop Limits Exceptions", false, "Allows specific items (configured in loottables.json) to be dropped even if not permited by current Item Drop Limits mode"); + AllowItemDropLimitsExceptions = SyncedConfig("Balance", "Allow Item Drop Limits Exceptions", false, "Allows specific items (configured in loottables.json) to be dropped even if not permitted by current Item Drop Limits mode"); BossBountyMode = SyncedConfig("Balance", "Gated Bounty Mode", GatedBountyMode.Unlimited, "Sets whether available bounties are ungated or gated by boss kills."); _bossTrophyDropMode = SyncedConfig("Balance", "Boss Trophy Drop Mode", BossDropMode.OnePerPlayerNearBoss, "Sets bosses to drop a number of trophies equal to the number of players. Optionally set it to only include players within a certain distance, use 'Boss Trophy Drop Player Range' to set the range."); _bossTrophyDropPlayerRange = SyncedConfig("Balance", "Boss Trophy Drop Player Range", 100.0f, "Sets the range that bosses check when dropping multiple trophies using the OnePerPlayerNearBoss drop mode.");