From f6e13af5322dff3cfba5a6ace896dff6a9ec522d Mon Sep 17 00:00:00 2001 From: Arsenii Fomin Date: Thu, 15 Feb 2024 16:26:04 +0700 Subject: [PATCH 01/13] Added new effect value roll distribution and config parameter for its usage --- EpicLoot/EpicLoot.cs | 8 ++++++++ EpicLoot/LootRoller.cs | 28 ++++++++++++++++++++-------- 2 files changed, 28 insertions(+), 8 deletions(-) diff --git a/EpicLoot/EpicLoot.cs b/EpicLoot/EpicLoot.cs index 884bdd427..5900240b8 100644 --- a/EpicLoot/EpicLoot.cs +++ b/EpicLoot/EpicLoot.cs @@ -52,6 +52,12 @@ public enum GatedBountyMode BossKillUnlocksNextBiomeBounties } + public enum EffectValueRollDistributionTypes + { + Linear, + TendsToLowAverage + } + public class Assets { public AssetBundle AssetBundle; @@ -112,6 +118,7 @@ public class EpicLoot : BaseUnityPlugin //private static ConfigEntry _mythicMaterialIconColor; public static ConfigEntry UseScrollingCraftDescription; public static ConfigEntry TransferMagicItemToCrafts; + public static ConfigEntry EffectValueRollDistribution; public static ConfigEntry CraftingTabStyle; private static ConfigEntry _loggingEnabled; private static ConfigEntry _logLevel; @@ -235,6 +242,7 @@ private void Awake() GlobalDropRateModifier = SyncedConfig("Balance", "Global Drop Rate Modifier", 1.0f, "A global percentage that modifies how likely items are to drop. 1 = Exactly what is in the loot tables will drop. 0 = Nothing will drop. 2 = The number of items in the drop table are twice as likely to drop (note, this doesn't double the number of items dropped, just doubles the relative chance for them to drop). Min = 0, Max = 4"); ItemsToMaterialsDropRatio = SyncedConfig("Balance", "Items To Materials Drop Ratio", 0.0f, "Sets the chance that item drops are instead dropped as magic crafting materials. 0 = all items, no materials. 1 = all materials, no items. Values between 0 and 1 change the ratio of items to materials that drop. At 0.5, half of everything that drops would be items and the other half would be materials. Min = 0, Max = 1"); TransferMagicItemToCrafts = SyncedConfig("Balance", "Transfer Enchants to Crafted Items", false, "When enchanted items are used as ingredients in recipes, transfer the highest enchant to the newly crafted item. Default: False."); + EffectValueRollDistribution = SyncedConfig("Balance", "Effect Value Roll Distribution", EffectValueRollDistributionTypes.Linear, "Function to be used for rolling effect values on an item. Linear: any number in the possible effect value range can be rolled with equal chance. TendsToLowAverage: values close to min and especially max of the range are very unlikely to be rolled. Default: Linear."); AlwaysShowWelcomeMessage = Config.Bind("Debug", "AlwaysShowWelcomeMessage", false, "Just a debug flag for testing the welcome message, do not use."); OutputPatchedConfigFiles = Config.Bind("Debug", "OutputPatchedConfigFiles", false, "Just a debug flag for testing the patching system, do not use."); diff --git a/EpicLoot/LootRoller.cs b/EpicLoot/LootRoller.cs index a36f64a53..067fe03c8 100644 --- a/EpicLoot/LootRoller.cs +++ b/EpicLoot/LootRoller.cs @@ -22,6 +22,7 @@ public static class LootRoller public static readonly Dictionary ItemSets = new Dictionary(); public static readonly Dictionary> LootTables = new Dictionary>(); + private static System.Random _random; private static WeightedRandomCollection> _weightedDropCountTable; private static WeightedRandomCollection _weightedLootTable; private static WeightedRandomCollection _weightedEffectTable; @@ -39,13 +40,13 @@ public static void Initialize(LootConfig lootConfig) { Config = lootConfig; - var random = new System.Random(); - _weightedDropCountTable = new WeightedRandomCollection>(random); - _weightedLootTable = new WeightedRandomCollection(random); - _weightedEffectTable = new WeightedRandomCollection(random); - _weightedEffectCountTable = new WeightedRandomCollection>(random); - _weightedRarityTable = new WeightedRandomCollection>(random); - _weightedLegendaryTable = new WeightedRandomCollection(random); + _random = new System.Random(); + _weightedDropCountTable = new WeightedRandomCollection>(_random); + _weightedLootTable = new WeightedRandomCollection(_random); + _weightedEffectTable = new WeightedRandomCollection(_random); + _weightedEffectCountTable = new WeightedRandomCollection>(_random); + _weightedRarityTable = new WeightedRandomCollection>(_random); + _weightedLegendaryTable = new WeightedRandomCollection(_random); ItemSets.Clear(); LootTables.Clear(); @@ -623,7 +624,18 @@ public static MagicItemEffect RollEffect(MagicItemEffectDefinition effectDef, It { EpicLoot.Log($"RollEffect: {effectDef.Type} {itemRarity} value={value} (min={valuesDef.MinValue} max={valuesDef.MaxValue})"); var incrementCount = (int)((valuesDef.MaxValue - valuesDef.MinValue) / valuesDef.Increment); - value = valuesDef.MinValue + (Random.Range(0, incrementCount + 1) * valuesDef.Increment); + + double v; + if (EpicLoot.EffectValueRollDistribution.Value == EffectValueRollDistributionTypes.TendsToLowAverage) + { + v = Math.Pow(_random.NextDouble() * _random.NextDouble(), 0.7); + } + else + { + v = _random.NextDouble(); + } + + value = valuesDef.MinValue + (int)(v * (incrementCount + 1)) * valuesDef.Increment; } } From 5d4611a0dd7604e96ffcdd145c1e75f85e026cd8 Mon Sep 17 00:00:00 2001 From: Arsenii Fomin Date: Thu, 15 Feb 2024 19:32:07 +0700 Subject: [PATCH 02/13] Changed luck formula to work properly with any rarity distributions (that is, always increase chances for the highest rarity available) --- EpicLoot/LootRoller.cs | 42 ++++++++++-------------------------------- 1 file changed, 10 insertions(+), 32 deletions(-) diff --git a/EpicLoot/LootRoller.cs b/EpicLoot/LootRoller.cs index a36f64a53..1cb70f3ee 100644 --- a/EpicLoot/LootRoller.cs +++ b/EpicLoot/LootRoller.cs @@ -673,7 +673,16 @@ public static Dictionary GetRarityWeights(float[] rarity, flo { ItemRarity.Legendary, rarity.Length >= 4 ? rarity[3] : 0 } }; - return ModifyRarityByLuck(rarityWeights, luckFactor); + for (var r = ItemRarity.Legendary; r >= ItemRarity.Magic; r--) + { + if (rarityWeights[r] > 0) + { + rarityWeights[r] = rarityWeights[r] * (1 + luckFactor); + break; + } + } + + return rarityWeights; } public static List GetLootTable(string objectName) @@ -878,37 +887,6 @@ public static void DebugLuckFactor() } } - public static Dictionary ModifyRarityByLuck(IReadOnlyDictionary rarityWeights, float luckFactor = 0) - { - var results = new Dictionary(); - for (var rarity = ItemRarity.Magic; rarity <= ItemRarity.Legendary; rarity++) - { - var skewFactor = GetSkewFactor(rarity); - results.Add(rarity, rarityWeights[rarity] * GetSkewedLuckFactor(luckFactor, skewFactor)); - } - - return results; - } - - public static float GetSkewFactor(ItemRarity rarity) - { - switch (rarity) - { - case ItemRarity.Magic: return -0.2f; - case ItemRarity.Rare: return 0.0f; - case ItemRarity.Epic: return 0.2f; - case ItemRarity.Legendary: return 1; - case ItemRarity.Mythic: return 1.1f; - default: - throw new ArgumentOutOfRangeException(nameof(rarity), rarity, null); - } - } - - public static float GetSkewedLuckFactor(float luckFactor, float skewFactor) - { - return Mathf.Max(0, 1 + luckFactor * skewFactor); - } - public static void PrintLuckTest(string lootTableName, float luckFactor) { var lootTable = GetLootTable(lootTableName)[0]; From 39c07eec30d9dc30b379fef241520ff43d9ca6f8 Mon Sep 17 00:00:00 2001 From: Arsenii Fomin Date: Thu, 15 Feb 2024 21:30:07 +0700 Subject: [PATCH 03/13] 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 692d9a72aa4e34f8113511c8e8f963f10e6517c2 Mon Sep 17 00:00:00 2001 From: Arsenii Fomin Date: Fri, 16 Feb 2024 17:34:43 +0700 Subject: [PATCH 04/13] Added ItemName in MagicItem definition and implemented it's proper setting on item creation --- EpicLoot/Crafting/AugmentChoiceDialog.cs | 2 +- EpicLoot/Crafting/AugmentHelper.cs | 4 ++-- EpicLoot/Crafting/AugmentsAvailableDialog.cs | 2 +- EpicLoot/CraftingV2/EnchantingUIController.cs | 6 ++--- EpicLoot/LootRoller.cs | 23 ++++++++++--------- EpicLoot/MagicItem.cs | 17 +++++++------- EpicLoot/MagicItemEffectDefinition.cs | 4 ++-- EpicLoot/Multiplayer_Player_Patch.cs | 2 +- EpicLoot/Terminal_Patch.cs | 2 +- EpicLoot/TextsDialog_Patch.cs | 2 +- 10 files changed, 33 insertions(+), 31 deletions(-) diff --git a/EpicLoot/Crafting/AugmentChoiceDialog.cs b/EpicLoot/Crafting/AugmentChoiceDialog.cs index 0e04e73c2..2a0c67b5d 100644 --- a/EpicLoot/Crafting/AugmentChoiceDialog.cs +++ b/EpicLoot/Crafting/AugmentChoiceDialog.cs @@ -137,7 +137,7 @@ public void Show(ItemDrop.ItemData fromItem, int effectIndex, Action(); - text.text = Localization.instance.Localize((index == 0 ? "($mod_epicloot_augment_keep) " : "") + MagicItem.GetEffectText(effect, rarity, true)); + text.text = Localization.instance.Localize((index == 0 ? "($mod_epicloot_augment_keep) " : "") + MagicItem.GetEffectText(effect, rarity, fromItem.m_shared.m_name, true)); text.color = rarityColor; if (EpicLoot.HasAuga) diff --git a/EpicLoot/Crafting/AugmentHelper.cs b/EpicLoot/Crafting/AugmentHelper.cs index a044e00d8..35d79e945 100644 --- a/EpicLoot/Crafting/AugmentHelper.cs +++ b/EpicLoot/Crafting/AugmentHelper.cs @@ -169,7 +169,7 @@ public static List GetAvailableAugments(AugmentRecipe if (recipe.EffectIndex >= 0 && recipe.EffectIndex < magicItem.Effects.Count) { var currentEffectDef = MagicItemEffectDefinitions.Get(magicItem.Effects[recipe.EffectIndex].EffectType); - valuelessEffect = currentEffectDef.GetValuesForRarity(rarity) == null; + valuelessEffect = currentEffectDef.GetValuesForRarity(rarity, item.m_shared.m_name) == null; } return MagicItemEffectDefinitions.GetAvailableEffects(item.Extended(), item.GetMagicItem(), valuelessEffect ? -1 : recipe.EffectIndex); @@ -179,7 +179,7 @@ public static string GetAugmentSelectorText(MagicItem magicItem, int i, IReadOnl { var pip = EpicLoot.GetMagicEffectPip(magicItem.IsEffectAugmented(i)); bool free = EnchantCostsHelper.EffectIsDeprecated(augmentableEffects[i].EffectType); - return $"{pip} {Localization.instance.Localize(MagicItem.GetEffectText(augmentableEffects[i], rarity, true))}{(free ? " [*FREE]" : "")}"; + return $"{pip} {Localization.instance.Localize(MagicItem.GetEffectText(augmentableEffects[i], rarity, magicItem.ItemName, true))}{(free ? " [*FREE]" : "")}"; } public static List> GetAugmentCosts(ItemDrop.ItemData item, int recipeEffectIndex) diff --git a/EpicLoot/Crafting/AugmentsAvailableDialog.cs b/EpicLoot/Crafting/AugmentsAvailableDialog.cs index f3c8a6552..b29c1750c 100644 --- a/EpicLoot/Crafting/AugmentsAvailableDialog.cs +++ b/EpicLoot/Crafting/AugmentsAvailableDialog.cs @@ -72,7 +72,7 @@ public void Show(AugmentHelper.AugmentRecipe recipe) foreach (var effectDef in availableEffects) { - var values = effectDef.GetValuesForRarity(item.GetRarity()); + var values = effectDef.GetValuesForRarity(item.GetRarity(), item.m_shared.m_name); var valueDisplay = values != null ? Mathf.Approximately(values.MinValue, values.MaxValue) ? $"{values.MinValue}" : $"({values.MinValue}-{values.MaxValue})" : ""; t.AppendLine($"‣ {string.Format(Localization.instance.Localize(effectDef.DisplayText), valueDisplay)}"); } diff --git a/EpicLoot/CraftingV2/EnchantingUIController.cs b/EpicLoot/CraftingV2/EnchantingUIController.cs index e5e57b18c..2dcfed35d 100644 --- a/EpicLoot/CraftingV2/EnchantingUIController.cs +++ b/EpicLoot/CraftingV2/EnchantingUIController.cs @@ -388,7 +388,7 @@ private static string GetEnchantInfo(ItemDrop.ItemData item, MagicRarityUnity _r foreach (var effectDef in availableEffects) { - var values = effectDef.GetValuesForRarity(rarity); + var values = effectDef.GetValuesForRarity(rarity, item.m_shared.m_name); var valueDisplay = values != null ? Mathf.Approximately(values.MinValue, values.MaxValue) ? $"{values.MinValue}" : $"({values.MinValue}-{values.MaxValue})" : ""; sb.AppendLine($"‣ {string.Format(Localization.instance.Localize(effectDef.DisplayText), valueDisplay)}"); } @@ -520,7 +520,7 @@ private static string GetAvailableAugmentEffects(ItemDrop.ItemData item, int aug if (augmentindex >= 0 && augmentindex < magicItem.Effects.Count) { var currentEffectDef = MagicItemEffectDefinitions.Get(magicItem.Effects[augmentindex].EffectType); - valuelessEffect = currentEffectDef.GetValuesForRarity(rarity) == null; + valuelessEffect = currentEffectDef.GetValuesForRarity(rarity, item.m_shared.m_name) == null; } var availableEffects = MagicItemEffectDefinitions.GetAvailableEffects(item.Extended(), item.GetMagicItem(), valuelessEffect ? -1 : augmentindex); @@ -529,7 +529,7 @@ private static string GetAvailableAugmentEffects(ItemDrop.ItemData item, int aug sb.Append($""); foreach (var effectDef in availableEffects) { - var values = effectDef.GetValuesForRarity(item.GetRarity()); + var values = effectDef.GetValuesForRarity(item.GetRarity(), item.m_shared.m_name); var valueDisplay = values != null ? Mathf.Approximately(values.MinValue, values.MaxValue) ? $"{values.MinValue}" : $"({values.MinValue}-{values.MaxValue})" : ""; sb.AppendLine($"‣ {string.Format(Localization.instance.Localize(effectDef.DisplayText), valueDisplay)}"); } diff --git a/EpicLoot/LootRoller.cs b/EpicLoot/LootRoller.cs index a36f64a53..928c31274 100644 --- a/EpicLoot/LootRoller.cs +++ b/EpicLoot/LootRoller.cs @@ -351,7 +351,7 @@ private static List RollLootTableInternal(LootTable lootTable, int l var magicItem = RollMagicItem(lootDrop, itemData, luckFactor); if (CheatForceMagicEffect) { - AddDebugMagicEffects(magicItem); + AddDebugMagicEffects(magicItem, itemData.m_shared.m_name); } magicItemComponent.SetMagicItem(magicItem); itemDrop.m_itemData = itemData; @@ -464,7 +464,7 @@ public static MagicItem RollMagicItem(ItemRarity rarity, ItemDrop.ItemData baseI rarity = ItemRarity.Legendary; } - var magicItem = new MagicItem { Rarity = rarity }; + var magicItem = new MagicItem { Rarity = rarity, ItemName = baseItem.m_shared.m_name }; var effectCount = CheatEffectCount >= 1 ? CheatEffectCount : RollEffectCountPerRarity(magicItem.Rarity); @@ -512,7 +512,7 @@ public static MagicItem RollMagicItem(ItemRarity rarity, ItemDrop.ItemData baseI continue; } - var effect = RollEffect(effectDef, ItemRarity.Legendary, guaranteedMagicEffect.Values); + var effect = RollEffect(effectDef, ItemRarity.Legendary, baseItem.m_shared.m_name, guaranteedMagicEffect.Values); magicItem.Effects.Add(effect); effectCount--; } @@ -532,7 +532,7 @@ public static MagicItem RollMagicItem(ItemRarity rarity, ItemDrop.ItemData baseI _weightedEffectTable.Setup(availableEffects, x => x.SelectionWeight); var effectDef = _weightedEffectTable.Roll(); - var effect = RollEffect(effectDef, magicItem.Rarity); + var effect = RollEffect(effectDef, magicItem.Rarity, baseItem.m_shared.m_name); magicItem.Effects.Add(effect); } @@ -612,10 +612,10 @@ public static List> GetEffectCountsPerRarity(ItemRarity return result; } - public static MagicItemEffect RollEffect(MagicItemEffectDefinition effectDef, ItemRarity itemRarity, MagicItemEffectDefinition.ValueDef valuesOverride = null) + public static MagicItemEffect RollEffect(MagicItemEffectDefinition effectDef, ItemRarity itemRarity, string itemName, MagicItemEffectDefinition.ValueDef valuesOverride = null) { float value = MagicItemEffect.DefaultValue; - var valuesDef = valuesOverride ?? effectDef.GetValuesForRarity(itemRarity); + var valuesDef = valuesOverride ?? effectDef.GetValuesForRarity(itemRarity, itemName); if (valuesDef != null) { value = valuesDef.MinValue; @@ -630,7 +630,8 @@ public static MagicItemEffect RollEffect(MagicItemEffectDefinition effectDef, It return new MagicItemEffect(effectDef.Type, value); } - public static List RollEffects(List availableEffects, ItemRarity itemRarity, int count, bool removeOnSelect = true) + + public static List RollEffects(List availableEffects, ItemRarity itemRarity, string itemName, int count, bool removeOnSelect = true) { var results = new List(); @@ -644,7 +645,7 @@ public static List RollEffects(List EpicLoot.LogError($"EffectDef was null! RollEffects({itemRarity}, {count})"); continue; } - results.Add(RollEffect(effectDef, itemRarity)); + results.Add(RollEffect(effectDef, itemRarity, itemName)); } return results; @@ -818,7 +819,7 @@ public static List RollAugmentEffects(ItemDrop.ItemData item, M for (var i = 0; i < augmentChoices && i < availableEffects.Count; i++) { - var newEffect = RollEffects(availableEffects, rarity, 1, false).FirstOrDefault(); + var newEffect = RollEffects(availableEffects, rarity, item.m_shared.m_name, 1, false).FirstOrDefault(); if (newEffect == null) { EpicLoot.LogError($"Rolled a null effect: item:{item.m_shared.m_name}, index:{effectIndex}"); @@ -837,12 +838,12 @@ public static List RollAugmentEffects(ItemDrop.ItemData item, M return results; } - public static void AddDebugMagicEffects(MagicItem item) + public static void AddDebugMagicEffects(MagicItem item, string itemName) { if (!string.IsNullOrEmpty(ForcedMagicEffect) && !item.HasEffect(ForcedMagicEffect)) { EpicLoot.Log($"AddDebugMagicEffect {ForcedMagicEffect}"); - item.Effects.Add(RollEffect(MagicItemEffectDefinitions.Get(ForcedMagicEffect), item.Rarity)); + item.Effects.Add(RollEffect(MagicItemEffectDefinitions.Get(ForcedMagicEffect), item.Rarity, itemName)); } } diff --git a/EpicLoot/MagicItem.cs b/EpicLoot/MagicItem.cs index 0a8743a28..ac46241f2 100644 --- a/EpicLoot/MagicItem.cs +++ b/EpicLoot/MagicItem.cs @@ -39,7 +39,7 @@ public MagicItemEffect(string type, float value = DefaultValue) [Serializable] public class MagicItem { - public int Version = 2; + public int Version = 3; public ItemRarity Rarity; public List Effects = new List(); public string TypeNameOverride; @@ -48,6 +48,7 @@ public class MagicItem public string DisplayName; public string LegendaryID; public string SetID; + public string ItemName; public string GetItemTypeName(ItemDrop.ItemData baseItem) { @@ -71,7 +72,7 @@ public string GetTooltip() { var effect = Effects[index]; var pip = EpicLoot.GetMagicEffectPip(IsEffectAugmented(index)); - tooltip.AppendLine($"{pip} {GetEffectText(effect, Rarity, showRange)}"); + tooltip.AppendLine($"{pip} {GetEffectText(effect, Rarity, ItemName, showRange)}"); } tooltip.Append($""); @@ -127,11 +128,11 @@ public static string GetEffectText(MagicItemEffectDefinition effectDef, float va return result; } - public static string GetEffectText(MagicItemEffect effect, ItemRarity rarity, bool showRange, string legendaryID, MagicItemEffectDefinition.ValueDef valuesOverride) + public static string GetEffectText(MagicItemEffect effect, ItemRarity rarity, string itemName, bool showRange, string legendaryID, MagicItemEffectDefinition.ValueDef valuesOverride) { var effectDef = MagicItemEffectDefinitions.Get(effect.EffectType); var result = GetEffectText(effectDef, effect.EffectValue); - var values = valuesOverride ?? (string.IsNullOrEmpty(legendaryID) ? effectDef.GetValuesForRarity(rarity) : UniqueLegendaryHelper.GetLegendaryEffectValues(legendaryID, effect.EffectType)); + var values = valuesOverride ?? (string.IsNullOrEmpty(legendaryID) ? effectDef.GetValuesForRarity(rarity, itemName) : UniqueLegendaryHelper.GetLegendaryEffectValues(legendaryID, effect.EffectType)); if (showRange && values != null) { if (!Mathf.Approximately(values.MinValue, values.MaxValue)) @@ -142,14 +143,14 @@ public static string GetEffectText(MagicItemEffect effect, ItemRarity rarity, bo return result; } - public static string GetEffectText(MagicItemEffect effect, ItemRarity rarity, bool showRange, string legendaryID = null) + public static string GetEffectText(MagicItemEffect effect, ItemRarity rarity, string itemName, bool showRange, string legendaryID = null) { - return GetEffectText(effect, rarity, showRange, legendaryID, null); + return GetEffectText(effect, rarity, itemName, showRange, legendaryID, null); } - public static string GetEffectText(MagicItemEffect effect, MagicItemEffectDefinition.ValueDef valuesOverride) + public static string GetEffectText(MagicItemEffect effect, string itemName, MagicItemEffectDefinition.ValueDef valuesOverride) { - return GetEffectText(effect, ItemRarity.Legendary, false, null, valuesOverride); + return GetEffectText(effect, ItemRarity.Legendary, itemName, false, null, valuesOverride); } public void ReplaceEffect(int index, MagicItemEffect newEffect) diff --git a/EpicLoot/MagicItemEffectDefinition.cs b/EpicLoot/MagicItemEffectDefinition.cs index 7668918ef..b0598f15b 100644 --- a/EpicLoot/MagicItemEffectDefinition.cs +++ b/EpicLoot/MagicItemEffectDefinition.cs @@ -336,7 +336,7 @@ public bool HasRarityValues() return ValuesPerRarity.Magic != null && ValuesPerRarity.Epic != null && ValuesPerRarity.Rare != null && ValuesPerRarity.Legendary != null; } - public ValueDef GetValuesForRarity(ItemRarity itemRarity) + public ValueDef GetValuesForRarity(ItemRarity itemRarity, string itemName) { switch (itemRarity) { @@ -426,7 +426,7 @@ public static bool IsValuelessEffect(string effectType, ItemRarity rarity) return false; } - return effectDef.GetValuesForRarity(rarity) == null; + return effectDef.GetValuesForRarity(rarity, null) == null; } } } diff --git a/EpicLoot/Multiplayer_Player_Patch.cs b/EpicLoot/Multiplayer_Player_Patch.cs index 58e3f3b4c..e9b9cf3d3 100644 --- a/EpicLoot/Multiplayer_Player_Patch.cs +++ b/EpicLoot/Multiplayer_Player_Patch.cs @@ -119,7 +119,7 @@ private static bool DoCheck(Player player, ZDO zdo, string equipKey, string lege itemData = targetItemData.Clone(); itemData.m_durability = float.PositiveInfinity; var magicItemComponent = itemData.Data().GetOrCreate(); - var stubMagicItem = new MagicItem { Rarity = ItemRarity.Legendary, LegendaryID = zdoLegendaryID }; + var stubMagicItem = new MagicItem { Rarity = ItemRarity.Legendary, ItemName = itemData.m_shared.m_name, LegendaryID = zdoLegendaryID }; magicItemComponent.SetMagicItem(stubMagicItem); ForceResetVisEquipment(player, itemData); diff --git a/EpicLoot/Terminal_Patch.cs b/EpicLoot/Terminal_Patch.cs index f2720211e..a4625f8ae 100644 --- a/EpicLoot/Terminal_Patch.cs +++ b/EpicLoot/Terminal_Patch.cs @@ -618,7 +618,7 @@ private static void ReplaceMagicEffect(ItemDrop.ItemData itemData, MagicItem mag return; } - var replacementEffect = LootRoller.RollEffect(replacementEffectDef, magicItem.Rarity); + var replacementEffect = LootRoller.RollEffect(replacementEffectDef, magicItem.Rarity, itemData.m_shared.m_name); magicItem.Effects[index] = replacementEffect; itemData.SaveMagicItem(magicItem); } diff --git a/EpicLoot/TextsDialog_Patch.cs b/EpicLoot/TextsDialog_Patch.cs index 195a7159a..259e5682d 100644 --- a/EpicLoot/TextsDialog_Patch.cs +++ b/EpicLoot/TextsDialog_Patch.cs @@ -64,7 +64,7 @@ public static void AddMagicEffectsPage(TextsDialog textsDialog, Player player) { var effect = entry2.Key; var item = entry2.Value; - t.AppendLine($" - {MagicItem.GetEffectText(effect, item.GetRarity(), false)} ({item.GetDecoratedName()})"); + t.AppendLine($" - {MagicItem.GetEffectText(effect, item.GetRarity(), item.m_shared.m_name, false)} ({item.GetDecoratedName()})"); } t.AppendLine(); From a985a25ffeba6d5accfb9a65cc2e1e32caffec55 Mon Sep 17 00:00:00 2001 From: Arsenii Fomin Date: Wed, 21 Feb 2024 13:27:15 +0700 Subject: [PATCH 05/13] Added ValuesPerItemName filter --- EpicLoot/MagicItemEffectDefinition.cs | 48 +++++++++++++++++++++------ 1 file changed, 37 insertions(+), 11 deletions(-) diff --git a/EpicLoot/MagicItemEffectDefinition.cs b/EpicLoot/MagicItemEffectDefinition.cs index b0598f15b..3cfa078ed 100644 --- a/EpicLoot/MagicItemEffectDefinition.cs +++ b/EpicLoot/MagicItemEffectDefinition.cs @@ -300,12 +300,20 @@ public class ValuesPerRarityDef public ValueDef Mythic; } + [Serializable] + public class ValuesPerItemNameDef + { + public List ItemNames = new List(); + public ValuesPerRarityDef ValuesPerRarity = new ValuesPerRarityDef(); + } + public string Type { get; set; } public string DisplayText = ""; public string Description = ""; public MagicItemEffectRequirements Requirements = new MagicItemEffectRequirements(); public ValuesPerRarityDef ValuesPerRarity = new ValuesPerRarityDef(); + public List ValuesPerItemName = new List(); public float SelectionWeight = 1; public bool CanBeAugmented = true; public bool CanBeDisenchanted = true; @@ -338,18 +346,36 @@ public bool HasRarityValues() public ValueDef GetValuesForRarity(ItemRarity itemRarity, string itemName) { - switch (itemRarity) - { - case ItemRarity.Magic: return ValuesPerRarity.Magic; - case ItemRarity.Rare: return ValuesPerRarity.Rare; - case ItemRarity.Epic: return ValuesPerRarity.Epic; - case ItemRarity.Legendary: return ValuesPerRarity.Legendary; - case ItemRarity.Mythic: - // TODO: Mythic Hookup - return null;//ValuesPerRarity.Mythic; - default: - throw new ArgumentOutOfRangeException(nameof(itemRarity), itemRarity, null); + ValueDef ValueForRarity(ValuesPerRarityDef valuesPerRarity) + { + switch (itemRarity) + { + case ItemRarity.Magic: return valuesPerRarity.Magic; + case ItemRarity.Rare: return valuesPerRarity.Rare; + case ItemRarity.Epic: return valuesPerRarity.Epic; + case ItemRarity.Legendary: return valuesPerRarity.Legendary; + case ItemRarity.Mythic: + // TODO: Mythic Hookup + return null;//ValuesPerRarity.Mythic; + default: + throw new ArgumentOutOfRangeException(nameof(itemRarity), itemRarity, null); + } + } + + if (string.IsNullOrEmpty(itemName) || ValuesPerItemName == null) + { + return ValueForRarity(ValuesPerRarity); + } + + for (var i = 0; i < ValuesPerItemName.Count; i++) + { + if (ValuesPerItemName[i].ItemNames.Contains(itemName)) + { + return ValueForRarity(ValuesPerItemName[i].ValuesPerRarity); + } } + + return ValueForRarity(ValuesPerRarity); } } From 476aa486f51efc5cdd15b679c316f07e6d2b71eb Mon Sep 17 00:00:00 2001 From: Arsenii Fomin Date: Sat, 24 Feb 2024 11:23:13 +0700 Subject: [PATCH 06/13] Implemented DistanceLoot loottables config to be used for chests loot adjustments --- EpicLoot/EpicLoot.cs | 4 +-- EpicLoot/LootConfig.cs | 9 +++++++ EpicLoot/LootRoller.cs | 54 +++++++++++++++++++++++++++++++------- EpicLoot/Terminal_Patch.cs | 3 ++- EpicLoot/loottables.json | 10 +++++++ 5 files changed, 68 insertions(+), 12 deletions(-) diff --git a/EpicLoot/EpicLoot.cs b/EpicLoot/EpicLoot.cs index 884bdd427..5487ea01d 100644 --- a/EpicLoot/EpicLoot.cs +++ b/EpicLoot/EpicLoot.cs @@ -1483,7 +1483,7 @@ private static void WriteLootTableDrops(StringBuilder t, LootTable lootTable) for (var i = 0; i < limit; i++) { var level = i + 1; - var dropTable = LootRoller.GetDropsForLevel(lootTable, level, false); + var dropTable = LootRoller.GetDropsForLevelOrDistance(lootTable, level, 0, false); if (dropTable == null || dropTable.Count == 0) { continue; @@ -1513,7 +1513,7 @@ private static void WriteLootTableItems(StringBuilder t, LootTable lootTable) for (var i = 0; i < limit; i++) { var level = i + 1; - var lootList = LootRoller.GetLootForLevel(lootTable, level, false); + var lootList = LootRoller.GetLootForLevelOrDistance(lootTable, level, 0, false); if (ArrayUtils.IsNullOrEmpty(lootList)) { continue; diff --git a/EpicLoot/LootConfig.cs b/EpicLoot/LootConfig.cs index 9dd956e9c..74ed0fe6c 100644 --- a/EpicLoot/LootConfig.cs +++ b/EpicLoot/LootConfig.cs @@ -19,6 +19,14 @@ public class LeveledLootDef public LootDrop[] Loot; } + [Serializable] + public class DistanceLootDef + { + public int Distance; + public float[][] Drops; + public LootDrop[] Loot; + } + [Serializable] public class LootTable { @@ -31,6 +39,7 @@ public class LootTable public LootDrop[] Loot2; public LootDrop[] Loot3; public List LeveledLoot = new List(); + public List DistanceLoot = new List(); } [Serializable] diff --git a/EpicLoot/LootRoller.cs b/EpicLoot/LootRoller.cs index a36f64a53..9583cc573 100644 --- a/EpicLoot/LootRoller.cs +++ b/EpicLoot/LootRoller.cs @@ -199,7 +199,9 @@ private static List RollLootTableInternal(LootTable lootTable, int l var luckFactor = GetLuckFactor(dropPoint); - var drops = GetDropsForLevel(lootTable, level); + int distanceFromWorldCenter = (int)new Vector3(dropPoint.x, 0, dropPoint.z).magnitude; + + var drops = GetDropsForLevelOrDistance(lootTable, level, distanceFromWorldCenter); if (drops.Count == 0) { return results; @@ -233,7 +235,7 @@ private static List RollLootTableInternal(LootTable lootTable, int l return results; } - var loot = GetLootForLevel(lootTable, level); + var loot = GetLootForLevelOrDistance(lootTable, level, distanceFromWorldCenter); if (loot == null) loot = new LootDrop[] { }; @@ -440,7 +442,7 @@ private static bool IsLootTableRefence(string lootDropItem, out LootDrop[] lootL var lootTable = LootTables[objectName].FirstOrDefault(); if (lootTable != null) { - lootList = GetLootForLevel(lootTable, level); + lootList = GetLootForLevelOrDistance(lootTable, level, 0); return true; } @@ -689,7 +691,7 @@ public static List GetLootTable(string objectName) return results; } - public static List> GetDropsForLevel([NotNull] LootTable lootTable, int level, bool useNextHighestIfNotPresent = true) + public static List> GetDropsForLevelOrDistance([NotNull] LootTable lootTable, int level, int distance, bool useNextHighestIfNotPresent = true) { if (level == 3 && !ArrayUtils.IsNullOrEmpty(lootTable.Drops3)) { @@ -718,6 +720,23 @@ public static List> GetDropsForLevel([NotNull] LootTabl return ToDropList(lootTable.Drops); } + if(lootTable.DistanceLoot.Count > 0) + { + var drops = lootTable.Drops; + + int maxDistanceUsed = -1; + foreach (var distanceLoot in lootTable.DistanceLoot) + { + if(distance >= distanceLoot.Distance && distanceLoot.Distance > maxDistanceUsed) + { + drops = distanceLoot.Drops; + maxDistanceUsed = distanceLoot.Distance; + } + } + + return ToDropList(lootTable.Drops); + } + for (var lvl = level; lvl >= 1; --lvl) { var found = lootTable.LeveledLoot.Find(x => x.Level == lvl); @@ -741,7 +760,7 @@ private static List> ToDropList(float[][] drops) return drops.Select(x => new KeyValuePair((int) x[0], x[1])).ToList(); } - public static LootDrop[] GetLootForLevel([NotNull] LootTable lootTable, int level, bool useNextHighestIfNotPresent = true) + public static LootDrop[] GetLootForLevelOrDistance([NotNull] LootTable lootTable, int level, int distance, bool useNextHighestIfNotPresent = true) { if (level == 3 && !ArrayUtils.IsNullOrEmpty(lootTable.Loot3)) { @@ -770,6 +789,23 @@ public static LootDrop[] GetLootForLevel([NotNull] LootTable lootTable, int leve return lootTable.Loot.ToArray(); } + if (lootTable.DistanceLoot.Count > 0) + { + var loot = lootTable.Loot; + + int maxDistanceUsed = -1; + foreach (var distanceLoot in lootTable.DistanceLoot) + { + if (distance >= distanceLoot.Distance && distanceLoot.Distance > maxDistanceUsed) + { + loot = distanceLoot.Loot; + maxDistanceUsed = distanceLoot.Distance; + } + } + + return loot.ToArray(); + } + for (var lvl = level; lvl >= 1; --lvl) { var found = lootTable.LeveledLoot.Find(x => x.Level == lvl); @@ -912,7 +948,7 @@ public static float GetSkewedLuckFactor(float luckFactor, float skewFactor) public static void PrintLuckTest(string lootTableName, float luckFactor) { var lootTable = GetLootTable(lootTableName)[0]; - var lootDrop = GetLootForLevel(lootTable, 1)[0]; + var lootDrop = GetLootForLevelOrDistance(lootTable, 1, 0)[0]; lootDrop = ResolveLootDrop(lootDrop); var rarityBase = GetRarityWeights(lootDrop.Rarity, 0); var rarityLuck = GetRarityWeights(lootDrop.Rarity, luckFactor); @@ -945,12 +981,12 @@ public static void PrintLuckTest(string lootTableName, float luckFactor) Debug.LogWarning(sb.ToString()); } - public static void PrintLootResolutionTest(string lootTableName, int level, int itemIndex) + public static void PrintLootResolutionTest(string lootTableName, int level, int distance, int itemIndex) { - Debug.LogWarning($"{lootTableName}:{level}:{itemIndex}"); + Debug.LogWarning($"{lootTableName}:{level}:{distance}:{itemIndex}"); var lootTable = GetLootTable(lootTableName)[0]; - var lootDrop = GetLootForLevel(lootTable, level)[itemIndex]; + var lootDrop = GetLootForLevelOrDistance(lootTable, level, distance)[itemIndex]; lootDrop = ResolveLootDrop(lootDrop); var rarity = lootDrop.Rarity; diff --git a/EpicLoot/Terminal_Patch.cs b/EpicLoot/Terminal_Patch.cs index f2720211e..4688c1c61 100644 --- a/EpicLoot/Terminal_Patch.cs +++ b/EpicLoot/Terminal_Patch.cs @@ -186,7 +186,8 @@ public static void Postfix() var lootTable = args.Length > 1 ? args[1] : "Greydwarf"; var level = args.Length > 2 ? int.Parse(args[2]) : 1; var itemIndex = args.Length > 3 ? int.Parse(args[3]) : 0; - LootRoller.PrintLootResolutionTest(lootTable, level, itemIndex); + var distance = args.Length > 4 ? int.Parse(args[4]) : 0; + LootRoller.PrintLootResolutionTest(lootTable, level, distance, itemIndex); })); new Terminal.ConsoleCommand("resetcooldowns", "", (args => { diff --git a/EpicLoot/loottables.json b/EpicLoot/loottables.json index 71a60f7ac..327cfba75 100644 --- a/EpicLoot/loottables.json +++ b/EpicLoot/loottables.json @@ -1456,6 +1456,16 @@ "Loot": [ { "Item": "Tier0Everything", "Weight": 4, "Rarity": [ 97, 2, 1, 0] }, { "Item": "Tier1Everything", "Weight": 1, "Rarity": [ 97, 2, 1, 0] } + ], + "DistanceLoot": [ + { + "Distance": 4000, + "Drops": [ [0, 40], [1, 38], [2, 20], [3, 2] ], + "Loot": [ + { "Item": "Tier0Everything", "Weight": 4, "Rarity": [ 97, 2, 1, 0] }, + { "Item": "Tier1Everything", "Weight": 1, "Rarity": [ 97, 2, 1, 0] } + ] + } ] }, //TreasureChest_blackforest From b73430d78e3fd23fb8ebff0f4c67777554505dee Mon Sep 17 00:00:00 2001 From: Arsenii Fomin Date: Sat, 24 Feb 2024 14:23:45 +0700 Subject: [PATCH 07/13] Hotfix --- EpicLoot/LootRoller.cs | 68 +++++++++++++++++++++--------------------- 1 file changed, 34 insertions(+), 34 deletions(-) diff --git a/EpicLoot/LootRoller.cs b/EpicLoot/LootRoller.cs index 9583cc573..2ae6e6782 100644 --- a/EpicLoot/LootRoller.cs +++ b/EpicLoot/LootRoller.cs @@ -693,6 +693,23 @@ public static List GetLootTable(string objectName) public static List> GetDropsForLevelOrDistance([NotNull] LootTable lootTable, int level, int distance, bool useNextHighestIfNotPresent = true) { + if (lootTable.DistanceLoot.Count > 0) + { + var drops = lootTable.Drops; + + int maxDistanceUsed = -1; + foreach (var distanceLoot in lootTable.DistanceLoot) + { + if (distance >= distanceLoot.Distance && distanceLoot.Distance > maxDistanceUsed) + { + drops = distanceLoot.Drops; + maxDistanceUsed = distanceLoot.Distance; + } + } + + return ToDropList(drops); + } + if (level == 3 && !ArrayUtils.IsNullOrEmpty(lootTable.Drops3)) { if (lootTable.LeveledLoot.Any(x => x.Level == level)) @@ -720,23 +737,6 @@ public static List> GetDropsForLevelOrDistance([NotNull return ToDropList(lootTable.Drops); } - if(lootTable.DistanceLoot.Count > 0) - { - var drops = lootTable.Drops; - - int maxDistanceUsed = -1; - foreach (var distanceLoot in lootTable.DistanceLoot) - { - if(distance >= distanceLoot.Distance && distanceLoot.Distance > maxDistanceUsed) - { - drops = distanceLoot.Drops; - maxDistanceUsed = distanceLoot.Distance; - } - } - - return ToDropList(lootTable.Drops); - } - for (var lvl = level; lvl >= 1; --lvl) { var found = lootTable.LeveledLoot.Find(x => x.Level == lvl); @@ -762,6 +762,23 @@ private static List> ToDropList(float[][] drops) public static LootDrop[] GetLootForLevelOrDistance([NotNull] LootTable lootTable, int level, int distance, bool useNextHighestIfNotPresent = true) { + if (lootTable.DistanceLoot.Count > 0) + { + var loot = lootTable.Loot; + + int maxDistanceUsed = -1; + foreach (var distanceLoot in lootTable.DistanceLoot) + { + if (distance >= distanceLoot.Distance && distanceLoot.Distance > maxDistanceUsed) + { + loot = distanceLoot.Loot; + maxDistanceUsed = distanceLoot.Distance; + } + } + + return loot.ToArray(); + } + if (level == 3 && !ArrayUtils.IsNullOrEmpty(lootTable.Loot3)) { if (lootTable.LeveledLoot.Any(x => x.Level == level)) @@ -789,23 +806,6 @@ public static LootDrop[] GetLootForLevelOrDistance([NotNull] LootTable lootTable return lootTable.Loot.ToArray(); } - if (lootTable.DistanceLoot.Count > 0) - { - var loot = lootTable.Loot; - - int maxDistanceUsed = -1; - foreach (var distanceLoot in lootTable.DistanceLoot) - { - if (distance >= distanceLoot.Distance && distanceLoot.Distance > maxDistanceUsed) - { - loot = distanceLoot.Loot; - maxDistanceUsed = distanceLoot.Distance; - } - } - - return loot.ToArray(); - } - for (var lvl = level; lvl >= 1; --lvl) { var found = lootTable.LeveledLoot.Find(x => x.Level == lvl); From 5e8df4d6991a90c1a4bcef1930eab31f000e1023 Mon Sep 17 00:00:00 2001 From: Arsenii Fomin Date: Mon, 26 Feb 2024 12:36:33 +0700 Subject: [PATCH 08/13] Fixed unique legendaries custom effect ranges not being shown properly in hints --- EpicLoot/Crafting/AugmentChoiceDialog.cs | 2 +- EpicLoot/Crafting/AugmentHelper.cs | 2 +- EpicLoot/MagicItem.cs | 24 +++++++++++++++++------- EpicLoot/TextsDialog_Patch.cs | 3 ++- 4 files changed, 21 insertions(+), 10 deletions(-) diff --git a/EpicLoot/Crafting/AugmentChoiceDialog.cs b/EpicLoot/Crafting/AugmentChoiceDialog.cs index 2a0c67b5d..23983d30a 100644 --- a/EpicLoot/Crafting/AugmentChoiceDialog.cs +++ b/EpicLoot/Crafting/AugmentChoiceDialog.cs @@ -137,7 +137,7 @@ public void Show(ItemDrop.ItemData fromItem, int effectIndex, Action(); - text.text = Localization.instance.Localize((index == 0 ? "($mod_epicloot_augment_keep) " : "") + MagicItem.GetEffectText(effect, rarity, fromItem.m_shared.m_name, true)); + text.text = Localization.instance.Localize((index == 0 ? "($mod_epicloot_augment_keep) " : "") + MagicItem.GetEffectText(effect, rarity, fromItem.m_shared.m_name, true, magicItem.LegendaryID)); text.color = rarityColor; if (EpicLoot.HasAuga) diff --git a/EpicLoot/Crafting/AugmentHelper.cs b/EpicLoot/Crafting/AugmentHelper.cs index 35d79e945..62a5101ef 100644 --- a/EpicLoot/Crafting/AugmentHelper.cs +++ b/EpicLoot/Crafting/AugmentHelper.cs @@ -179,7 +179,7 @@ public static string GetAugmentSelectorText(MagicItem magicItem, int i, IReadOnl { var pip = EpicLoot.GetMagicEffectPip(magicItem.IsEffectAugmented(i)); bool free = EnchantCostsHelper.EffectIsDeprecated(augmentableEffects[i].EffectType); - return $"{pip} {Localization.instance.Localize(MagicItem.GetEffectText(augmentableEffects[i], rarity, magicItem.ItemName, true))}{(free ? " [*FREE]" : "")}"; + return $"{pip} {Localization.instance.Localize(MagicItem.GetEffectText(augmentableEffects[i], rarity, magicItem.ItemName, true, magicItem.LegendaryID))}{(free ? " [*FREE]" : "")}"; } public static List> GetAugmentCosts(ItemDrop.ItemData item, int recipeEffectIndex) diff --git a/EpicLoot/MagicItem.cs b/EpicLoot/MagicItem.cs index ac46241f2..6dc50c2aa 100644 --- a/EpicLoot/MagicItem.cs +++ b/EpicLoot/MagicItem.cs @@ -72,7 +72,7 @@ public string GetTooltip() { var effect = Effects[index]; var pip = EpicLoot.GetMagicEffectPip(IsEffectAugmented(index)); - tooltip.AppendLine($"{pip} {GetEffectText(effect, Rarity, ItemName, showRange)}"); + tooltip.AppendLine($"{pip} {GetEffectText(effect, Rarity, ItemName, showRange, LegendaryID)}"); } tooltip.Append($""); @@ -132,7 +132,22 @@ public static string GetEffectText(MagicItemEffect effect, ItemRarity rarity, st { var effectDef = MagicItemEffectDefinitions.Get(effect.EffectType); var result = GetEffectText(effectDef, effect.EffectValue); - var values = valuesOverride ?? (string.IsNullOrEmpty(legendaryID) ? effectDef.GetValuesForRarity(rarity, itemName) : UniqueLegendaryHelper.GetLegendaryEffectValues(legendaryID, effect.EffectType)); + MagicItemEffectDefinition.ValueDef values = null; + if (valuesOverride != null) + { + values = valuesOverride; + } + else + { + if (!string.IsNullOrEmpty(legendaryID)) + { + values = UniqueLegendaryHelper.GetLegendaryEffectValues(legendaryID, effect.EffectType); + } + if (values == null) + { + values = effectDef.GetValuesForRarity(rarity, itemName); + } + } if (showRange && values != null) { if (!Mathf.Approximately(values.MinValue, values.MaxValue)) @@ -148,11 +163,6 @@ public static string GetEffectText(MagicItemEffect effect, ItemRarity rarity, st return GetEffectText(effect, rarity, itemName, showRange, legendaryID, null); } - public static string GetEffectText(MagicItemEffect effect, string itemName, MagicItemEffectDefinition.ValueDef valuesOverride) - { - return GetEffectText(effect, ItemRarity.Legendary, itemName, false, null, valuesOverride); - } - public void ReplaceEffect(int index, MagicItemEffect newEffect) { if (index < 0 || index >= Effects.Count) diff --git a/EpicLoot/TextsDialog_Patch.cs b/EpicLoot/TextsDialog_Patch.cs index 259e5682d..f4cb06dff 100644 --- a/EpicLoot/TextsDialog_Patch.cs +++ b/EpicLoot/TextsDialog_Patch.cs @@ -64,7 +64,8 @@ public static void AddMagicEffectsPage(TextsDialog textsDialog, Player player) { var effect = entry2.Key; var item = entry2.Value; - t.AppendLine($" - {MagicItem.GetEffectText(effect, item.GetRarity(), item.m_shared.m_name, false)} ({item.GetDecoratedName()})"); + var magicItem = item.GetMagicItem(); + t.AppendLine($" - {MagicItem.GetEffectText(effect, item.GetRarity(), item.m_shared.m_name, false, magicItem?.LegendaryID)} ({item.GetDecoratedName()})"); } t.AppendLine(); From 913c1d74733f7753feffabcf8d92671fde8d72d8 Mon Sep 17 00:00:00 2001 From: Arsenii Fomin Date: Mon, 26 Feb 2024 14:32:11 +0700 Subject: [PATCH 09/13] Implemented item quality config for loottables.json (Normal, Exception, Elite) and the corresponding ValuesPerRarityExceptional, ValuesPerRarityElite config for magiceffects.json --- EpicLoot/Crafting/AugmentChoiceDialog.cs | 2 +- EpicLoot/Crafting/AugmentHelper.cs | 4 +- EpicLoot/Crafting/AugmentsAvailableDialog.cs | 2 +- EpicLoot/CraftingV2/EnchantingUIController.cs | 8 +- .../LegendarySystem/LegendaryItemConfig.cs | 2 + .../LegendarySystem/UniqueLegendaryHelper.cs | 17 ++++- EpicLoot/LootConfig.cs | 1 + EpicLoot/LootRoller.cs | 76 +++++++++++++++---- EpicLoot/MagicItem.cs | 20 +++-- EpicLoot/MagicItemComponent.cs | 24 +++++- EpicLoot/MagicItemEffectDefinition.cs | 37 ++++++--- EpicLoot/Terminal_Patch.cs | 2 +- EpicLoot/TextsDialog_Patch.cs | 2 +- EpicLoot/translations.json | 6 +- 14 files changed, 159 insertions(+), 44 deletions(-) diff --git a/EpicLoot/Crafting/AugmentChoiceDialog.cs b/EpicLoot/Crafting/AugmentChoiceDialog.cs index 23983d30a..8e023d494 100644 --- a/EpicLoot/Crafting/AugmentChoiceDialog.cs +++ b/EpicLoot/Crafting/AugmentChoiceDialog.cs @@ -137,7 +137,7 @@ public void Show(ItemDrop.ItemData fromItem, int effectIndex, Action(); - text.text = Localization.instance.Localize((index == 0 ? "($mod_epicloot_augment_keep) " : "") + MagicItem.GetEffectText(effect, rarity, fromItem.m_shared.m_name, true, magicItem.LegendaryID)); + text.text = Localization.instance.Localize((index == 0 ? "($mod_epicloot_augment_keep) " : "") + MagicItem.GetEffectText(effect, rarity, magicItem.Quality, fromItem.m_shared.m_name, true, magicItem.LegendaryID)); text.color = rarityColor; if (EpicLoot.HasAuga) diff --git a/EpicLoot/Crafting/AugmentHelper.cs b/EpicLoot/Crafting/AugmentHelper.cs index 62a5101ef..a26fb402a 100644 --- a/EpicLoot/Crafting/AugmentHelper.cs +++ b/EpicLoot/Crafting/AugmentHelper.cs @@ -169,7 +169,7 @@ public static List GetAvailableAugments(AugmentRecipe if (recipe.EffectIndex >= 0 && recipe.EffectIndex < magicItem.Effects.Count) { var currentEffectDef = MagicItemEffectDefinitions.Get(magicItem.Effects[recipe.EffectIndex].EffectType); - valuelessEffect = currentEffectDef.GetValuesForRarity(rarity, item.m_shared.m_name) == null; + valuelessEffect = currentEffectDef.GetValuesForRarity(rarity, item.m_shared.m_name, magicItem.Quality) == null; } return MagicItemEffectDefinitions.GetAvailableEffects(item.Extended(), item.GetMagicItem(), valuelessEffect ? -1 : recipe.EffectIndex); @@ -179,7 +179,7 @@ public static string GetAugmentSelectorText(MagicItem magicItem, int i, IReadOnl { var pip = EpicLoot.GetMagicEffectPip(magicItem.IsEffectAugmented(i)); bool free = EnchantCostsHelper.EffectIsDeprecated(augmentableEffects[i].EffectType); - return $"{pip} {Localization.instance.Localize(MagicItem.GetEffectText(augmentableEffects[i], rarity, magicItem.ItemName, true, magicItem.LegendaryID))}{(free ? " [*FREE]" : "")}"; + return $"{pip} {Localization.instance.Localize(MagicItem.GetEffectText(augmentableEffects[i], rarity, magicItem.Quality, magicItem.ItemName, true, magicItem.LegendaryID))}{(free ? " [*FREE]" : "")}"; } public static List> GetAugmentCosts(ItemDrop.ItemData item, int recipeEffectIndex) diff --git a/EpicLoot/Crafting/AugmentsAvailableDialog.cs b/EpicLoot/Crafting/AugmentsAvailableDialog.cs index b29c1750c..050431269 100644 --- a/EpicLoot/Crafting/AugmentsAvailableDialog.cs +++ b/EpicLoot/Crafting/AugmentsAvailableDialog.cs @@ -72,7 +72,7 @@ public void Show(AugmentHelper.AugmentRecipe recipe) foreach (var effectDef in availableEffects) { - var values = effectDef.GetValuesForRarity(item.GetRarity(), item.m_shared.m_name); + var values = effectDef.GetValuesForRarity(item.GetRarity(), item.m_shared.m_name, magicItem.Quality); var valueDisplay = values != null ? Mathf.Approximately(values.MinValue, values.MaxValue) ? $"{values.MinValue}" : $"({values.MinValue}-{values.MaxValue})" : ""; t.AppendLine($"‣ {string.Format(Localization.instance.Localize(effectDef.DisplayText), valueDisplay)}"); } diff --git a/EpicLoot/CraftingV2/EnchantingUIController.cs b/EpicLoot/CraftingV2/EnchantingUIController.cs index 2dcfed35d..7d9d66e36 100644 --- a/EpicLoot/CraftingV2/EnchantingUIController.cs +++ b/EpicLoot/CraftingV2/EnchantingUIController.cs @@ -388,7 +388,7 @@ private static string GetEnchantInfo(ItemDrop.ItemData item, MagicRarityUnity _r foreach (var effectDef in availableEffects) { - var values = effectDef.GetValuesForRarity(rarity, item.m_shared.m_name); + var values = effectDef.GetValuesForRarity(rarity, item.m_shared.m_name, ItemQuality.Normal); var valueDisplay = values != null ? Mathf.Approximately(values.MinValue, values.MaxValue) ? $"{values.MinValue}" : $"({values.MinValue}-{values.MaxValue})" : ""; sb.AppendLine($"‣ {string.Format(Localization.instance.Localize(effectDef.DisplayText), valueDisplay)}"); } @@ -418,7 +418,7 @@ private static GameObject EnchantItemAndReturnSuccessDialog(ItemDrop.ItemData it previousDurabilityPercent = item.m_durability / item.GetMaxDurability(); var luckFactor = player.GetTotalActiveMagicEffectValue(MagicEffectType.Luck, 0.01f); - var magicItem = LootRoller.RollMagicItem((ItemRarity)rarity, item, luckFactor); + var magicItem = LootRoller.RollMagicItem((ItemRarity)rarity, ItemQuality.Normal, item, luckFactor); var magicItemComponent = item.Data().GetOrCreate(); magicItemComponent.SetMagicItem(magicItem); @@ -520,7 +520,7 @@ private static string GetAvailableAugmentEffects(ItemDrop.ItemData item, int aug if (augmentindex >= 0 && augmentindex < magicItem.Effects.Count) { var currentEffectDef = MagicItemEffectDefinitions.Get(magicItem.Effects[augmentindex].EffectType); - valuelessEffect = currentEffectDef.GetValuesForRarity(rarity, item.m_shared.m_name) == null; + valuelessEffect = currentEffectDef.GetValuesForRarity(rarity, item.m_shared.m_name, magicItem.Quality) == null; } var availableEffects = MagicItemEffectDefinitions.GetAvailableEffects(item.Extended(), item.GetMagicItem(), valuelessEffect ? -1 : augmentindex); @@ -529,7 +529,7 @@ private static string GetAvailableAugmentEffects(ItemDrop.ItemData item, int aug sb.Append($""); foreach (var effectDef in availableEffects) { - var values = effectDef.GetValuesForRarity(item.GetRarity(), item.m_shared.m_name); + var values = effectDef.GetValuesForRarity(item.GetRarity(), item.m_shared.m_name, magicItem.Quality); var valueDisplay = values != null ? Mathf.Approximately(values.MinValue, values.MaxValue) ? $"{values.MinValue}" : $"({values.MinValue}-{values.MaxValue})" : ""; sb.AppendLine($"‣ {string.Format(Localization.instance.Localize(effectDef.DisplayText), valueDisplay)}"); } diff --git a/EpicLoot/LegendarySystem/LegendaryItemConfig.cs b/EpicLoot/LegendarySystem/LegendaryItemConfig.cs index c0ab8bb49..91ae6f04f 100644 --- a/EpicLoot/LegendarySystem/LegendaryItemConfig.cs +++ b/EpicLoot/LegendarySystem/LegendaryItemConfig.cs @@ -28,6 +28,8 @@ public class LegendaryInfo public string Description; public MagicItemEffectRequirements Requirements; public List GuaranteedMagicEffects = new List(); + public List GuaranteedMagicEffectsExceptional = new List(); + public List GuaranteedMagicEffectsElite = new List(); public int GuaranteedEffectCount = -1; public float SelectionWeight = 1; public string EquipFx; diff --git a/EpicLoot/LegendarySystem/UniqueLegendaryHelper.cs b/EpicLoot/LegendarySystem/UniqueLegendaryHelper.cs index 134a65441..9931cbdb8 100644 --- a/EpicLoot/LegendarySystem/UniqueLegendaryHelper.cs +++ b/EpicLoot/LegendarySystem/UniqueLegendaryHelper.cs @@ -69,10 +69,25 @@ public static IList GetAvailableLegendaries(ItemDrop.ItemData bas return availableLegendaries; } - public static MagicItemEffectDefinition.ValueDef GetLegendaryEffectValues(string legendaryID, string effectType) + public static MagicItemEffectDefinition.ValueDef GetLegendaryEffectValues(string legendaryID, string effectType, ItemQuality quality) { if (LegendaryInfo.TryGetValue(legendaryID, out var legendaryInfo)) { + if (quality == ItemQuality.Elite) + { + if (legendaryInfo.GuaranteedMagicEffectsElite.TryFind(x => x.Type == effectType, out var guaranteedMagicEffectElite)) + { + return guaranteedMagicEffectElite.Values; + } + } + else if (quality == ItemQuality.Exceptional) + { + if (legendaryInfo.GuaranteedMagicEffectsExceptional.TryFind(x => x.Type == effectType, out var guaranteedMagicEffectExceptional)) + { + return guaranteedMagicEffectExceptional.Values; + } + } + if (legendaryInfo.GuaranteedMagicEffects.TryFind(x => x.Type == effectType, out var guaranteedMagicEffect)) { return guaranteedMagicEffect.Values; diff --git a/EpicLoot/LootConfig.cs b/EpicLoot/LootConfig.cs index 9dd956e9c..7f50361fe 100644 --- a/EpicLoot/LootConfig.cs +++ b/EpicLoot/LootConfig.cs @@ -9,6 +9,7 @@ public class LootDrop public string Item; public float Weight = 1; public float[] Rarity; + public float[] Quality; } [Serializable] diff --git a/EpicLoot/LootRoller.cs b/EpicLoot/LootRoller.cs index 4755d4d4c..1e8ad641b 100644 --- a/EpicLoot/LootRoller.cs +++ b/EpicLoot/LootRoller.cs @@ -28,6 +28,7 @@ public static class LootRoller private static WeightedRandomCollection _weightedEffectTable; private static WeightedRandomCollection> _weightedEffectCountTable; private static WeightedRandomCollection> _weightedRarityTable; + private static WeightedRandomCollection> _weightedQualityTable; private static WeightedRandomCollection _weightedLegendaryTable; public static bool CheatRollingItem = false; public static int CheatEffectCount; @@ -46,6 +47,7 @@ public static void Initialize(LootConfig lootConfig) _weightedEffectTable = new WeightedRandomCollection(_random); _weightedEffectCountTable = new WeightedRandomCollection>(_random); _weightedRarityTable = new WeightedRandomCollection>(_random); + _weightedQualityTable = new WeightedRandomCollection>(_random); _weightedLegendaryTable = new WeightedRandomCollection(_random); ItemSets.Clear(); @@ -376,7 +378,7 @@ public static GameObject SpawnLootForDrop(GameObject itemPrefab, Vector3 dropPoi private static LootDrop ResolveLootDrop(LootDrop lootDrop) { - var result = new LootDrop { Item = lootDrop.Item, Rarity = ArrayUtils.Copy(lootDrop.Rarity), Weight = lootDrop.Weight }; + var result = new LootDrop { Item = lootDrop.Item, Rarity = ArrayUtils.Copy(lootDrop.Rarity), Quality = ArrayUtils.Copy(lootDrop.Quality), Weight = lootDrop.Weight }; var needsResolve = true; while (needsResolve) { @@ -394,6 +396,10 @@ private static LootDrop ResolveLootDrop(LootDrop lootDrop) { result.Rarity = ArrayUtils.Copy(itemSetResult.Rarity); } + if (ArrayUtils.IsNullOrEmpty(result.Quality)) + { + result.Quality = ArrayUtils.Copy(itemSetResult.Quality); + } } else if (IsLootTableRefence(result.Item, out var lootList)) { @@ -409,6 +415,10 @@ private static LootDrop ResolveLootDrop(LootDrop lootDrop) { result.Rarity = ArrayUtils.Copy(referenceResult.Rarity); } + if (ArrayUtils.IsNullOrEmpty(result.Quality)) + { + result.Quality = ArrayUtils.Copy(referenceResult.Quality); + } } else { @@ -454,10 +464,11 @@ private static bool IsLootTableRefence(string lootDropItem, out LootDrop[] lootL public static MagicItem RollMagicItem(LootDrop lootDrop, ItemDrop.ItemData baseItem, float luckFactor) { var rarity = RollItemRarity(lootDrop, luckFactor); - return RollMagicItem(rarity, baseItem, luckFactor); + var quality = RollItemQuality(lootDrop); + return RollMagicItem(rarity, quality, baseItem, luckFactor); } - public static MagicItem RollMagicItem(ItemRarity rarity, ItemDrop.ItemData baseItem, float luckFactor) + public static MagicItem RollMagicItem(ItemRarity rarity, ItemQuality quality, ItemDrop.ItemData baseItem, float luckFactor) { var cheatLegendary = !string.IsNullOrEmpty(CheatForceLegendary); if (cheatLegendary) @@ -465,7 +476,7 @@ public static MagicItem RollMagicItem(ItemRarity rarity, ItemDrop.ItemData baseI rarity = ItemRarity.Legendary; } - var magicItem = new MagicItem { Rarity = rarity, ItemName = baseItem.m_shared.m_name }; + var magicItem = new MagicItem { Rarity = rarity, Quality = quality, ItemName = baseItem.m_shared.m_name }; var effectCount = CheatEffectCount >= 1 ? CheatEffectCount : RollEffectCountPerRarity(magicItem.Rarity); @@ -504,7 +515,21 @@ public static MagicItem RollMagicItem(ItemRarity rarity, ItemDrop.ItemData baseI effectCount = legendary.GuaranteedEffectCount; } - foreach (var guaranteedMagicEffect in legendary.GuaranteedMagicEffects) + List guaranteedMagicEffects; + if (quality == ItemQuality.Elite && legendary.GuaranteedMagicEffectsElite != null) + { + guaranteedMagicEffects = legendary.GuaranteedMagicEffectsElite; + } + else if (quality == ItemQuality.Exceptional && legendary.GuaranteedMagicEffectsExceptional != null) + { + guaranteedMagicEffects = legendary.GuaranteedMagicEffectsExceptional; + } + else + { + guaranteedMagicEffects = legendary.GuaranteedMagicEffects; + } + + foreach (var guaranteedMagicEffect in guaranteedMagicEffects) { var effectDef = MagicItemEffectDefinitions.Get(guaranteedMagicEffect.Type); if (effectDef == null) @@ -513,7 +538,7 @@ public static MagicItem RollMagicItem(ItemRarity rarity, ItemDrop.ItemData baseI continue; } - var effect = RollEffect(effectDef, ItemRarity.Legendary, baseItem.m_shared.m_name, guaranteedMagicEffect.Values); + var effect = RollEffect(effectDef, ItemRarity.Legendary, magicItem.Quality, baseItem.m_shared.m_name, guaranteedMagicEffect.Values); magicItem.Effects.Add(effect); effectCount--; } @@ -533,7 +558,7 @@ public static MagicItem RollMagicItem(ItemRarity rarity, ItemDrop.ItemData baseI _weightedEffectTable.Setup(availableEffects, x => x.SelectionWeight); var effectDef = _weightedEffectTable.Roll(); - var effect = RollEffect(effectDef, magicItem.Rarity, baseItem.m_shared.m_name); + var effect = RollEffect(effectDef, magicItem.Rarity, magicItem.Quality, baseItem.m_shared.m_name); magicItem.Effects.Add(effect); } @@ -613,10 +638,10 @@ public static List> GetEffectCountsPerRarity(ItemRarity return result; } - public static MagicItemEffect RollEffect(MagicItemEffectDefinition effectDef, ItemRarity itemRarity, string itemName, MagicItemEffectDefinition.ValueDef valuesOverride = null) + public static MagicItemEffect RollEffect(MagicItemEffectDefinition effectDef, ItemRarity itemRarity, ItemQuality quality, string itemName, MagicItemEffectDefinition.ValueDef valuesOverride = null) { float value = MagicItemEffect.DefaultValue; - var valuesDef = valuesOverride ?? effectDef.GetValuesForRarity(itemRarity, itemName); + var valuesDef = valuesOverride ?? effectDef.GetValuesForRarity(itemRarity, itemName, quality); if (valuesDef != null) { value = valuesDef.MinValue; @@ -643,7 +668,7 @@ public static MagicItemEffect RollEffect(MagicItemEffectDefinition effectDef, It } - public static List RollEffects(List availableEffects, ItemRarity itemRarity, string itemName, int count, bool removeOnSelect = true) + public static List RollEffects(List availableEffects, ItemRarity itemRarity, ItemQuality quality, string itemName, int count, bool removeOnSelect = true) { var results = new List(); @@ -657,7 +682,7 @@ public static List RollEffects(List EpicLoot.LogError($"EffectDef was null! RollEffects({itemRarity}, {count})"); continue; } - results.Add(RollEffect(effectDef, itemRarity, itemName)); + results.Add(RollEffect(effectDef, itemRarity, quality, itemName)); } return results; @@ -675,6 +700,19 @@ public static ItemRarity RollItemRarity(LootDrop lootDrop, float luckFactor) _weightedRarityTable.Setup(rarityWeights, x => x.Value); return _weightedRarityTable.Roll().Key; } + public static ItemQuality RollItemQuality(LootDrop lootDrop) + { + if (lootDrop.Quality == null || lootDrop.Quality.Length == 0) + { + return ItemQuality.Normal; + } + + var qualityWeights = GetQualityWeights(lootDrop.Quality); + + _weightedQualityTable.Setup(qualityWeights, x => x.Value); + var quality = _weightedQualityTable.Roll().Key; + return quality; + } public static Dictionary GetRarityWeights(float[] rarity, float luckFactor) { @@ -698,6 +736,18 @@ public static Dictionary GetRarityWeights(float[] rarity, flo return rarityWeights; } + public static Dictionary GetQualityWeights(float[] quality) + { + var qualityWeights = new Dictionary() + { + { ItemQuality.Normal, quality.Length >= 1 ? quality[0] : 0 }, + { ItemQuality.Exceptional, quality.Length >= 2 ? quality[1] : 0 }, + { ItemQuality.Elite, quality.Length >= 3 ? quality[2] : 0 } + }; + + return qualityWeights; + } + public static List GetLootTable(string objectName) { var results = new List(); @@ -840,7 +890,7 @@ public static List RollAugmentEffects(ItemDrop.ItemData item, M for (var i = 0; i < augmentChoices && i < availableEffects.Count; i++) { - var newEffect = RollEffects(availableEffects, rarity, item.m_shared.m_name, 1, false).FirstOrDefault(); + var newEffect = RollEffects(availableEffects, rarity, magicItem.Quality, item.m_shared.m_name, 1, false).FirstOrDefault(); if (newEffect == null) { EpicLoot.LogError($"Rolled a null effect: item:{item.m_shared.m_name}, index:{effectIndex}"); @@ -864,7 +914,7 @@ public static void AddDebugMagicEffects(MagicItem item, string itemName) if (!string.IsNullOrEmpty(ForcedMagicEffect) && !item.HasEffect(ForcedMagicEffect)) { EpicLoot.Log($"AddDebugMagicEffect {ForcedMagicEffect}"); - item.Effects.Add(RollEffect(MagicItemEffectDefinitions.Get(ForcedMagicEffect), item.Rarity, itemName)); + item.Effects.Add(RollEffect(MagicItemEffectDefinitions.Get(ForcedMagicEffect), item.Rarity, item.Quality, itemName)); } } diff --git a/EpicLoot/MagicItem.cs b/EpicLoot/MagicItem.cs index 6dc50c2aa..61befd400 100644 --- a/EpicLoot/MagicItem.cs +++ b/EpicLoot/MagicItem.cs @@ -16,6 +16,13 @@ public enum ItemRarity Mythic } + public enum ItemQuality + { + Normal, + Exceptional, + Elite + } + [Serializable] public class MagicItemEffect { @@ -49,6 +56,7 @@ public class MagicItem public string LegendaryID; public string SetID; public string ItemName; + public ItemQuality Quality; public string GetItemTypeName(ItemDrop.ItemData baseItem) { @@ -72,7 +80,7 @@ public string GetTooltip() { var effect = Effects[index]; var pip = EpicLoot.GetMagicEffectPip(IsEffectAugmented(index)); - tooltip.AppendLine($"{pip} {GetEffectText(effect, Rarity, ItemName, showRange, LegendaryID)}"); + tooltip.AppendLine($"{pip} {GetEffectText(effect, Rarity, Quality, ItemName, showRange, LegendaryID)}"); } tooltip.Append($""); @@ -128,7 +136,7 @@ public static string GetEffectText(MagicItemEffectDefinition effectDef, float va return result; } - public static string GetEffectText(MagicItemEffect effect, ItemRarity rarity, string itemName, bool showRange, string legendaryID, MagicItemEffectDefinition.ValueDef valuesOverride) + public static string GetEffectText(MagicItemEffect effect, ItemRarity rarity, ItemQuality quality, string itemName, bool showRange, string legendaryID, MagicItemEffectDefinition.ValueDef valuesOverride) { var effectDef = MagicItemEffectDefinitions.Get(effect.EffectType); var result = GetEffectText(effectDef, effect.EffectValue); @@ -141,11 +149,11 @@ public static string GetEffectText(MagicItemEffect effect, ItemRarity rarity, st { if (!string.IsNullOrEmpty(legendaryID)) { - values = UniqueLegendaryHelper.GetLegendaryEffectValues(legendaryID, effect.EffectType); + values = UniqueLegendaryHelper.GetLegendaryEffectValues(legendaryID, effect.EffectType, quality); } if (values == null) { - values = effectDef.GetValuesForRarity(rarity, itemName); + values = effectDef.GetValuesForRarity(rarity, itemName, quality); } } if (showRange && values != null) @@ -158,9 +166,9 @@ public static string GetEffectText(MagicItemEffect effect, ItemRarity rarity, st return result; } - public static string GetEffectText(MagicItemEffect effect, ItemRarity rarity, string itemName, bool showRange, string legendaryID = null) + public static string GetEffectText(MagicItemEffect effect, ItemRarity rarity, ItemQuality quality, string itemName, bool showRange, string legendaryID = null) { - return GetEffectText(effect, rarity, itemName, showRange, legendaryID, null); + return GetEffectText(effect, rarity, quality, itemName, showRange, legendaryID, null); } public void ReplaceEffect(int index, MagicItemEffect newEffect) diff --git a/EpicLoot/MagicItemComponent.cs b/EpicLoot/MagicItemComponent.cs index e1c5a1af6..552a7f647 100644 --- a/EpicLoot/MagicItemComponent.cs +++ b/EpicLoot/MagicItemComponent.cs @@ -264,13 +264,33 @@ public static string GetDisplayName(this ItemDrop.ItemData itemData) public static string GetDecoratedName(this ItemDrop.ItemData itemData, string colorOverride = null) { var color = "white"; + + var magicItem = itemData.GetMagicItem(); + var qualityStr = ""; + if (magicItem != null) + { + var quality = magicItem.Quality; + if (quality == ItemQuality.Elite) + { + qualityStr = Localization.instance.Localize("$mod_epicloot_elite"); + } + else if (quality == ItemQuality.Exceptional) + { + qualityStr = Localization.instance.Localize("$mod_epicloot_exceptional"); + } + if (qualityStr != "") + { + qualityStr = qualityStr + " "; + } + } + var name = GetDisplayName(itemData); if (!string.IsNullOrEmpty(colorOverride)) { color = colorOverride; } - else if (itemData.IsMagic(out var magicItem)) + else if (magicItem != null) { color = magicItem.GetColorString(); } @@ -279,7 +299,7 @@ public static string GetDecoratedName(this ItemDrop.ItemData itemData, string co color = itemData.GetCraftingMaterialRarityColor(); } - return $"{name}"; + return $"{qualityStr}{name}"; } public static string GetDescription(this ItemDrop.ItemData itemData) diff --git a/EpicLoot/MagicItemEffectDefinition.cs b/EpicLoot/MagicItemEffectDefinition.cs index 3cfa078ed..6d8cd43a1 100644 --- a/EpicLoot/MagicItemEffectDefinition.cs +++ b/EpicLoot/MagicItemEffectDefinition.cs @@ -305,6 +305,8 @@ public class ValuesPerItemNameDef { public List ItemNames = new List(); public ValuesPerRarityDef ValuesPerRarity = new ValuesPerRarityDef(); + public ValuesPerRarityDef ValuesPerRarityExceptional = new ValuesPerRarityDef(); + public ValuesPerRarityDef ValuesPerRarityElite = new ValuesPerRarityDef(); } public string Type { get; set; } @@ -313,6 +315,8 @@ public class ValuesPerItemNameDef public string Description = ""; public MagicItemEffectRequirements Requirements = new MagicItemEffectRequirements(); public ValuesPerRarityDef ValuesPerRarity = new ValuesPerRarityDef(); + public ValuesPerRarityDef ValuesPerRarityExceptional = new ValuesPerRarityDef(); + public ValuesPerRarityDef ValuesPerRarityElite = new ValuesPerRarityDef(); public List ValuesPerItemName = new List(); public float SelectionWeight = 1; public bool CanBeAugmented = true; @@ -344,16 +348,29 @@ public bool HasRarityValues() return ValuesPerRarity.Magic != null && ValuesPerRarity.Epic != null && ValuesPerRarity.Rare != null && ValuesPerRarity.Legendary != null; } - public ValueDef GetValuesForRarity(ItemRarity itemRarity, string itemName) + public ValueDef GetValuesForRarity(ItemRarity itemRarity, string itemName, ItemQuality quality) { - ValueDef ValueForRarity(ValuesPerRarityDef valuesPerRarity) + ValueDef ValueForQuality(ValueDef normal, ValueDef exceptional, ValueDef elite) + { + if (quality == ItemQuality.Elite && elite != null) + { + return elite; + } + if (quality == ItemQuality.Exceptional && exceptional != null) + { + return exceptional; + } + return normal; + } + + ValueDef ValueForRarity(ValuesPerRarityDef normal, ValuesPerRarityDef exceptional, ValuesPerRarityDef elite) { switch (itemRarity) { - case ItemRarity.Magic: return valuesPerRarity.Magic; - case ItemRarity.Rare: return valuesPerRarity.Rare; - case ItemRarity.Epic: return valuesPerRarity.Epic; - case ItemRarity.Legendary: return valuesPerRarity.Legendary; + case ItemRarity.Magic: return ValueForQuality(normal?.Magic, exceptional?.Magic, elite?.Magic); + case ItemRarity.Rare: return ValueForQuality(normal?.Rare, exceptional?.Rare, elite?.Rare); + case ItemRarity.Epic: return ValueForQuality(normal?.Epic, exceptional?.Epic, elite?.Epic); + case ItemRarity.Legendary: return ValueForQuality(normal?.Legendary, exceptional?.Legendary, elite?.Legendary); case ItemRarity.Mythic: // TODO: Mythic Hookup return null;//ValuesPerRarity.Mythic; @@ -364,18 +381,18 @@ ValueDef ValueForRarity(ValuesPerRarityDef valuesPerRarity) if (string.IsNullOrEmpty(itemName) || ValuesPerItemName == null) { - return ValueForRarity(ValuesPerRarity); + return ValueForRarity(ValuesPerRarity, ValuesPerRarityExceptional, ValuesPerRarityElite); } for (var i = 0; i < ValuesPerItemName.Count; i++) { if (ValuesPerItemName[i].ItemNames.Contains(itemName)) { - return ValueForRarity(ValuesPerItemName[i].ValuesPerRarity); + return ValueForRarity(ValuesPerItemName[i].ValuesPerRarity, ValuesPerItemName[i].ValuesPerRarityExceptional, ValuesPerItemName[i].ValuesPerRarityElite); } } - return ValueForRarity(ValuesPerRarity); + return ValueForRarity(ValuesPerRarity, ValuesPerRarityExceptional, ValuesPerRarityElite); } } @@ -452,7 +469,7 @@ public static bool IsValuelessEffect(string effectType, ItemRarity rarity) return false; } - return effectDef.GetValuesForRarity(rarity, null) == null; + return effectDef.GetValuesForRarity(rarity, null, ItemQuality.Normal) == null; } } } diff --git a/EpicLoot/Terminal_Patch.cs b/EpicLoot/Terminal_Patch.cs index a4625f8ae..8a4f823c3 100644 --- a/EpicLoot/Terminal_Patch.cs +++ b/EpicLoot/Terminal_Patch.cs @@ -618,7 +618,7 @@ private static void ReplaceMagicEffect(ItemDrop.ItemData itemData, MagicItem mag return; } - var replacementEffect = LootRoller.RollEffect(replacementEffectDef, magicItem.Rarity, itemData.m_shared.m_name); + var replacementEffect = LootRoller.RollEffect(replacementEffectDef, magicItem.Rarity, magicItem.Quality, itemData.m_shared.m_name); magicItem.Effects[index] = replacementEffect; itemData.SaveMagicItem(magicItem); } diff --git a/EpicLoot/TextsDialog_Patch.cs b/EpicLoot/TextsDialog_Patch.cs index f4cb06dff..799b0f8cd 100644 --- a/EpicLoot/TextsDialog_Patch.cs +++ b/EpicLoot/TextsDialog_Patch.cs @@ -65,7 +65,7 @@ public static void AddMagicEffectsPage(TextsDialog textsDialog, Player player) var effect = entry2.Key; var item = entry2.Value; var magicItem = item.GetMagicItem(); - t.AppendLine($" - {MagicItem.GetEffectText(effect, item.GetRarity(), item.m_shared.m_name, false, magicItem?.LegendaryID)} ({item.GetDecoratedName()})"); + t.AppendLine($" - {MagicItem.GetEffectText(effect, item.GetRarity(), magicItem != null ? magicItem.Quality : ItemQuality.Normal, item.m_shared.m_name, false, magicItem?.LegendaryID)} ({item.GetDecoratedName()})"); } t.AppendLine(); diff --git a/EpicLoot/translations.json b/EpicLoot/translations.json index 21d0c0611..6825c0608 100644 --- a/EpicLoot/translations.json +++ b/EpicLoot/translations.json @@ -99,7 +99,7 @@ "mod_epicloot_effectsperlevel": "Upgrades:", "mod_epicloot_upgrademessage": "$1 upgraded to level $2", "mod_epicloot_unlockmessage": "$1 upgraded to level $2", - "mod_epicloot_bonus": "Bonus!", + "mod_epicloot_bonus": "Bonus!", "mod_epicloot_featureinfo_none": "Select a feature from the list to the left to view upgrade options.", "mod_epicloot_featureinfo_sacrifice": "Sacrifice magic items and trophies, destroying them to produce enchanting materials.\n\nWhen upgraded, gain a chance to recieve double the items normally gained from the sacrifice.", @@ -1254,5 +1254,7 @@ "mod_epicloot_rare": "Rare", "mod_epicloot_epic": "Epic", "mod_epicloot_legendary": "Legendary", - "mod_epicloot_legendarysetlabel": "Legendary Set Item" + "mod_epicloot_legendarysetlabel": "Legendary Set Item", + "mod_epicloot_exceptional": "Exceptional", + "mod_epicloot_elite": "Elite" } From 7bcc66327c33551d078ab690cc061b50895954a7 Mon Sep 17 00:00:00 2001 From: Arsenii Fomin Date: Thu, 29 Feb 2024 15:18:21 +0700 Subject: [PATCH 10/13] Implemented loot filters --- EpicLoot/EpicLoot.cs | 3 + EpicLoot/EpicLoot.csproj | 3 + EpicLoot/LootFilter.cs | 75 +++++++++++++++++++++++++ EpicLoot/LootRoller.cs | 40 +++++++++++--- EpicLoot/lootfilters.json | 112 ++++++++++++++++++++++++++++++++++++++ 5 files changed, 224 insertions(+), 9 deletions(-) create mode 100644 EpicLoot/LootFilter.cs create mode 100644 EpicLoot/lootfilters.json diff --git a/EpicLoot/EpicLoot.cs b/EpicLoot/EpicLoot.cs index 9fca20393..2b530c34e 100644 --- a/EpicLoot/EpicLoot.cs +++ b/EpicLoot/EpicLoot.cs @@ -119,6 +119,7 @@ public class EpicLoot : BaseUnityPlugin public static ConfigEntry UseScrollingCraftDescription; public static ConfigEntry TransferMagicItemToCrafts; public static ConfigEntry EffectValueRollDistribution; + public static ConfigEntry UseLootFilters; public static ConfigEntry CraftingTabStyle; private static ConfigEntry _loggingEnabled; private static ConfigEntry _logLevel; @@ -243,6 +244,7 @@ private void Awake() ItemsToMaterialsDropRatio = SyncedConfig("Balance", "Items To Materials Drop Ratio", 0.0f, "Sets the chance that item drops are instead dropped as magic crafting materials. 0 = all items, no materials. 1 = all materials, no items. Values between 0 and 1 change the ratio of items to materials that drop. At 0.5, half of everything that drops would be items and the other half would be materials. Min = 0, Max = 1"); TransferMagicItemToCrafts = SyncedConfig("Balance", "Transfer Enchants to Crafted Items", false, "When enchanted items are used as ingredients in recipes, transfer the highest enchant to the newly crafted item. Default: False."); EffectValueRollDistribution = SyncedConfig("Balance", "Effect Value Roll Distribution", EffectValueRollDistributionTypes.Linear, "Function to be used for rolling effect values on an item. Linear: any number in the possible effect value range can be rolled with equal chance. TendsToLowAverage: values close to min and especially max of the range are very unlikely to be rolled. Default: Linear."); + UseLootFilters = SyncedConfig("Balance", "Use Loot Filters", false, "If set to true, all item drop will be affected by loot filters (defined in lootfilters.json). Loot filters allow to prevent dropping of the items you don't need anymore or auto sacrifice the unneeded items into materials on drop."); AlwaysShowWelcomeMessage = Config.Bind("Debug", "AlwaysShowWelcomeMessage", false, "Just a debug flag for testing the welcome message, do not use."); OutputPatchedConfigFiles = Config.Bind("Debug", "OutputPatchedConfigFiles", false, "Just a debug flag for testing the patching system, do not use."); @@ -496,6 +498,7 @@ public static void InitializeConfig() LoadJsonFile("abilities.json", AbilityDefinitions.Initialize, ConfigType.Synced); LoadJsonFile("materialconversions.json", MaterialConversions.Initialize, ConfigType.Synced); LoadJsonFile("enchantingupgrades.json", EnchantingTableUpgrades.InitializeConfig, ConfigType.Synced); + LoadJsonFile("lootfilters.json", LootFilterDefinitions.Initialize, ConfigType.Synced); WatchNewPatchConfig(); } diff --git a/EpicLoot/EpicLoot.csproj b/EpicLoot/EpicLoot.csproj index 08a668af7..c30f3574a 100644 --- a/EpicLoot/EpicLoot.csproj +++ b/EpicLoot/EpicLoot.csproj @@ -131,6 +131,7 @@ + @@ -287,6 +288,7 @@ + @@ -338,6 +340,7 @@ xcopy "$(ProjectDir)legendaries.json" "G:\Steam\steamapps\common\Valheim-Dev\BepInEx\plugins\$(ProjectName)\" /q /y /i xcopy "$(ProjectDir)abilities.json" "G:\Steam\steamapps\common\Valheim-Dev\BepInEx\plugins\$(ProjectName)\" /q /y /i xcopy "$(ProjectDir)materialconversions.json" "G:\Steam\steamapps\common\Valheim-Dev\BepInEx\plugins\$(ProjectName)\" /q /y /i + xcopy "$(ProjectDir)lootfilter.json" "G:\Steam\steamapps\common\Valheim-Dev\BepInEx\plugins\$(ProjectName)\" /q /y /i diff --git a/EpicLoot/LootFilter.cs b/EpicLoot/LootFilter.cs new file mode 100644 index 000000000..8cdd6a734 --- /dev/null +++ b/EpicLoot/LootFilter.cs @@ -0,0 +1,75 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace EpicLoot +{ + [Serializable] + public class LootFilter + { + public string Name; + public bool Whitelist; + public bool DropMaterials; + public List Items = new List(); + public List Rarities = new List(); + public List Quality = new List(); + public int Distance; + // public int Day; to be implemented for full accordance with CreatureLevelControl world level settings, that is, distance or day based + } + + [Serializable] + public class LootFiltersConfig + { + public List LootFilters = new List(); + } + + public class LootFilterDefinitions { + public static readonly List BlackLists = new List(); + public static readonly List WhiteLists = new List(); + + public static void Initialize(LootFiltersConfig _config) + { + foreach(var item in _config?.LootFilters) + { + if(item.Whitelist) + { + WhiteLists.Add(item); + } + else + { + BlackLists.Add(item); + } + } + } + + public static bool FilteredOut(string itemName, ItemRarity rarity, ItemQuality quality, int distance, out bool dropMaterials) + { + bool ItemMatches(LootFilter item, out bool dropMats) + { + dropMats = item.DropMaterials; + return item.Items.Contains(itemName) && item.Rarities.Contains(rarity) && item.Quality.Contains(quality) && distance > item.Distance; + } + + foreach (var item in WhiteLists) + { + if(ItemMatches(item, out dropMaterials)) + { + return false; + } + } + + foreach (var item in BlackLists) + { + if (ItemMatches(item, out dropMaterials)) + { + return true; + } + } + + dropMaterials = false; + return false; + } + } +} diff --git a/EpicLoot/LootRoller.cs b/EpicLoot/LootRoller.cs index af1728a7c..34bf3e664 100644 --- a/EpicLoot/LootRoller.cs +++ b/EpicLoot/LootRoller.cs @@ -278,10 +278,35 @@ private static List RollLootTableInternal(LootTable lootTable, int l var itemID = (CheatDisableGating) ? lootDrop.Item : GatedItemTypeHelper.GetGatedItemID(lootDrop.Item); + var rarity = RollItemRarity(lootDrop, luckFactor); + var cheatLegendary = !string.IsNullOrEmpty(CheatForceLegendary); + if (cheatLegendary) + { + rarity = ItemRarity.Legendary; + } + var quality = RollItemQuality(lootDrop); + + var lootFilterForcedSacrifice = false; + if(LootFilterDefinitions.FilteredOut(itemName, rarity, quality, distanceFromWorldCenter, out lootFilterForcedSacrifice)) + { + if (!lootFilterForcedSacrifice) + { + EpicLoot.Log($"Item filtered out due to loot filters"); + continue; + } + } + bool ReplaceWithMats() { if (itemID == null) { + EpicLoot.Log($"Item replaced with materials due to its id being null"); + return true; + } + + if (lootFilterForcedSacrifice) + { + EpicLoot.Log($"Item replaced with materials due to loot filters"); return true; } @@ -310,7 +335,6 @@ bool ReplaceWithMats() 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) @@ -365,7 +389,7 @@ bool ReplaceWithMats() { var itemData = itemDrop.m_itemData; var magicItemComponent = itemData.Data().GetOrCreate(); - var magicItem = RollMagicItem(lootDrop, itemData, luckFactor); + var magicItem = RollMagicItem(rarity, quality, itemData, luckFactor); if (CheatForceMagicEffect) { AddDebugMagicEffects(magicItem, itemData.m_shared.m_name); @@ -375,6 +399,11 @@ bool ReplaceWithMats() itemDrop.Save(); InitializeMagicItem(itemData); } + else + { + EpicLoot.LogWarning($"Warning: can't make item magic due to a) item {itemName} can't be magic: {!EpicLoot.CanBeMagicItem(itemDrop.m_itemData)} b) loot drop rarity is null or empty: {ArrayUtils.IsNullOrEmpty(lootDrop.Rarity)}"); + } + results.Add(item); } @@ -475,13 +504,6 @@ private static bool IsLootTableRefence(string lootDropItem, out LootDrop[] lootL return false; } - public static MagicItem RollMagicItem(LootDrop lootDrop, ItemDrop.ItemData baseItem, float luckFactor) - { - var rarity = RollItemRarity(lootDrop, luckFactor); - var quality = RollItemQuality(lootDrop); - return RollMagicItem(rarity, quality, baseItem, luckFactor); - } - public static MagicItem RollMagicItem(ItemRarity rarity, ItemQuality quality, ItemDrop.ItemData baseItem, float luckFactor) { var cheatLegendary = !string.IsNullOrEmpty(CheatForceLegendary); diff --git a/EpicLoot/lootfilters.json b/EpicLoot/lootfilters.json new file mode 100644 index 000000000..6cecf507f --- /dev/null +++ b/EpicLoot/lootfilters.json @@ -0,0 +1,112 @@ +{ + "LootFilters": [ + // example + // { + // "Name": "Magic loot filter", - name of the filter for the reference + // "Whitelist": false, - if set to true, the filter works in the opposite way, that is, the matching item will be dropped even if should be filtered out by other loot filters + // "DropMaterials": true, - if set to true, the item materials will be dropped instead of the item itself, if set to false, there will be no drop at all + // "Items": [], - list of any "Name" fields from loottables.json + // "Rarities" : [ + // "Magic", + // "Rare", + // "Epic", + // "Legendary" + // ], + // "Quality": [ + // "Normal", + // "Exceptional", + // "Elite" + // ], + // "Distance": 0, - minimal distance from the center of the world for the filter to be applied + // "Day": 0, - minimal day in the world for the filter to be applied + // "ApplyToChests": true - if set to true, chests items also affected + // } + { + "Name": "Tier0Everything - Normal", + "DropMaterials": true, + "Items": [ + "Club", + "AxeStone", + "Torch", + "Hammer", + "Hoe", + "ArmorRagsLegs", + "ArmorRagsChest", + "ShieldWood", + "ShieldWoodTower" + ], + "Rarities" : [ + "Magic", + "Rare", + "Epic" + ], + "Quality": [ + "Normal" + ], + "Distance": 3500, + "ApplyToChests": true + }, + { + "Name": "Tier1Everything - Normal", + "DropMaterials": true, + "Items": [ + "AxeFlint", + "SpearFlint", + "KnifeFlint", + "Bow", + "ArmorLeatherLegs", + "ArmorLeatherChest", + "HelmetLeather", + "CapeDeerHide", + "PickaxeAntler", + "ShieldBoneTower" + ], + "Rarities" : [ + "Magic", + "Rare", + "Epic" + ], + "Quality": [ + "Normal" + ], + "Distance": 3500, + "ApplyToChests": true + }, + { + "Name": "Tier2Everything - Normal", + "DropMaterials": true, + "Items": [ + "ArmorTrollLeatherLegs", + "ArmorTrollLeatherChest", + "HelmetTrollLeather", + "CapeTrollHide", + "KnifeCopper", + "SledgeStagbreaker", + "SwordBronze", + "AxeBronze", + "MaceBronze", + "AtgeirBronze", + "SpearBronze", + "BowFineWood", + "KnifeChitin", + "SpearChitin", + "ArmorBronzeLegs", + "ArmorBronzeChest", + "HelmetBronze", + "ShieldBronzeBuckler", + "PickaxeBronze", + "Cultivator" + ], + "Rarities" : [ + "Magic", + "Rare", + "Epic" + ], + "Quality": [ + "Normal" + ], + "Distance": 5000, + "ApplyToChests": true + } + ] +} \ No newline at end of file From 6a532a32f56d6dcd6e9cd3ffaa40186a16a805b4 Mon Sep 17 00:00:00 2001 From: Arsenii Fomin Date: Sun, 3 Mar 2024 10:41:19 +0700 Subject: [PATCH 11/13] Fixed issue with incorrectly set guaranteed magic effects for elite/exceptional unique item if the related config doesn't possess the required quality effects --- EpicLoot/LegendarySystem/UniqueLegendaryHelper.cs | 4 ++-- EpicLoot/LootRoller.cs | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/EpicLoot/LegendarySystem/UniqueLegendaryHelper.cs b/EpicLoot/LegendarySystem/UniqueLegendaryHelper.cs index 9931cbdb8..de81ec652 100644 --- a/EpicLoot/LegendarySystem/UniqueLegendaryHelper.cs +++ b/EpicLoot/LegendarySystem/UniqueLegendaryHelper.cs @@ -75,14 +75,14 @@ public static MagicItemEffectDefinition.ValueDef GetLegendaryEffectValues(string { if (quality == ItemQuality.Elite) { - if (legendaryInfo.GuaranteedMagicEffectsElite.TryFind(x => x.Type == effectType, out var guaranteedMagicEffectElite)) + if (legendaryInfo.GuaranteedMagicEffectsElite.Count() > 0 && legendaryInfo.GuaranteedMagicEffectsElite.TryFind(x => x.Type == effectType, out var guaranteedMagicEffectElite)) { return guaranteedMagicEffectElite.Values; } } else if (quality == ItemQuality.Exceptional) { - if (legendaryInfo.GuaranteedMagicEffectsExceptional.TryFind(x => x.Type == effectType, out var guaranteedMagicEffectExceptional)) + if (legendaryInfo.GuaranteedMagicEffectsExceptional.Count() > 0 && legendaryInfo.GuaranteedMagicEffectsExceptional.TryFind(x => x.Type == effectType, out var guaranteedMagicEffectExceptional)) { return guaranteedMagicEffectExceptional.Values; } diff --git a/EpicLoot/LootRoller.cs b/EpicLoot/LootRoller.cs index 1e8ad641b..c3568ceb6 100644 --- a/EpicLoot/LootRoller.cs +++ b/EpicLoot/LootRoller.cs @@ -516,11 +516,11 @@ public static MagicItem RollMagicItem(ItemRarity rarity, ItemQuality quality, It } List guaranteedMagicEffects; - if (quality == ItemQuality.Elite && legendary.GuaranteedMagicEffectsElite != null) + if (quality == ItemQuality.Elite && legendary.GuaranteedMagicEffectsElite.Count() > 0) { guaranteedMagicEffects = legendary.GuaranteedMagicEffectsElite; } - else if (quality == ItemQuality.Exceptional && legendary.GuaranteedMagicEffectsExceptional != null) + else if (quality == ItemQuality.Exceptional && legendary.GuaranteedMagicEffectsExceptional.Count() > 0) { guaranteedMagicEffects = legendary.GuaranteedMagicEffectsExceptional; } From c852655136577904624c94999983f4d8b1d96d89 Mon Sep 17 00:00:00 2001 From: Arsenii Fomin Date: Sun, 3 Mar 2024 11:28:16 +0700 Subject: [PATCH 12/13] Updated lootfilters.json file --- EpicLoot/lootfilters.json | 20 ++++++++------------ 1 file changed, 8 insertions(+), 12 deletions(-) diff --git a/EpicLoot/lootfilters.json b/EpicLoot/lootfilters.json index 6cecf507f..e28949c93 100644 --- a/EpicLoot/lootfilters.json +++ b/EpicLoot/lootfilters.json @@ -5,7 +5,7 @@ // "Name": "Magic loot filter", - name of the filter for the reference // "Whitelist": false, - if set to true, the filter works in the opposite way, that is, the matching item will be dropped even if should be filtered out by other loot filters // "DropMaterials": true, - if set to true, the item materials will be dropped instead of the item itself, if set to false, there will be no drop at all - // "Items": [], - list of any "Name" fields from loottables.json + // "Items": [], - list of item names (check "Item" fields used in loottables.json) // "Rarities" : [ // "Magic", // "Rare", @@ -18,8 +18,7 @@ // "Elite" // ], // "Distance": 0, - minimal distance from the center of the world for the filter to be applied - // "Day": 0, - minimal day in the world for the filter to be applied - // "ApplyToChests": true - if set to true, chests items also affected + // "Day": 0, - minimal day in the world for the filter to be applied, NOT IMPLEMENTED YET // } { "Name": "Tier0Everything - Normal", @@ -35,7 +34,7 @@ "ShieldWood", "ShieldWoodTower" ], - "Rarities" : [ + "Rarities": [ "Magic", "Rare", "Epic" @@ -43,8 +42,7 @@ "Quality": [ "Normal" ], - "Distance": 3500, - "ApplyToChests": true + "Distance": 3500 }, { "Name": "Tier1Everything - Normal", @@ -61,7 +59,7 @@ "PickaxeAntler", "ShieldBoneTower" ], - "Rarities" : [ + "Rarities": [ "Magic", "Rare", "Epic" @@ -69,8 +67,7 @@ "Quality": [ "Normal" ], - "Distance": 3500, - "ApplyToChests": true + "Distance": 3500 }, { "Name": "Tier2Everything - Normal", @@ -97,7 +94,7 @@ "PickaxeBronze", "Cultivator" ], - "Rarities" : [ + "Rarities": [ "Magic", "Rare", "Epic" @@ -105,8 +102,7 @@ "Quality": [ "Normal" ], - "Distance": 5000, - "ApplyToChests": true + "Distance": 5000 } ] } \ No newline at end of file From 620d2f43d0e58d3e0aba5ee47845811d676db525 Mon Sep 17 00:00:00 2001 From: Arsenii Fomin Date: Sun, 3 Mar 2024 11:30:54 +0700 Subject: [PATCH 13/13] Small fix --- EpicLoot/LootFilter.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/EpicLoot/LootFilter.cs b/EpicLoot/LootFilter.cs index 8cdd6a734..574036470 100644 --- a/EpicLoot/LootFilter.cs +++ b/EpicLoot/LootFilter.cs @@ -49,7 +49,7 @@ public static bool FilteredOut(string itemName, ItemRarity rarity, ItemQuality q bool ItemMatches(LootFilter item, out bool dropMats) { dropMats = item.DropMaterials; - return item.Items.Contains(itemName) && item.Rarities.Contains(rarity) && item.Quality.Contains(quality) && distance > item.Distance; + return item.Items.Contains(itemName) && item.Rarities.Contains(rarity) && item.Quality.Contains(quality) && distance >= item.Distance; } foreach (var item in WhiteLists)