diff --git a/Assets/Character Stats/Equipment/EquippableItemTypeDefinition.cs b/Assets/Character Stats/Equipment/EquippableItemTypeDefinition.cs index 11c16b66..abba7363 100644 --- a/Assets/Character Stats/Equipment/EquippableItemTypeDefinition.cs +++ b/Assets/Character Stats/Equipment/EquippableItemTypeDefinition.cs @@ -25,16 +25,11 @@ public class EquippableItemTypeDefinition : ScriptableObject [SerializeField] private string resourcesPath = ""; // e.g., "Armor/Helmets" [Header("Stat Rules")] - [SerializeField] private StatDefinition[] allowedStats = new StatDefinition[0]; - [SerializeField] private StatDefinition[] forbiddenStats = new StatDefinition[0]; - [SerializeField] private StatDefinition[] mandatoryStats = new StatDefinition[0]; - [SerializeField] private StatWeightModifier[] statWeightModifiers = new StatWeightModifier[0]; + [SerializeField] private StatAvailabilityWeightAndRolls[] statRules = new StatAvailabilityWeightAndRolls[0]; [Header("Generation Settings")] [SerializeField] private bool canBeGenerated = true; [SerializeField] private float baseGenerationWeight = 1f; - [SerializeField] private int minStatRolls = 1; - [SerializeField] private int maxStatRolls = 3; // Public read-only properties public string EquipmentKey => equipmentKey; @@ -48,14 +43,9 @@ public class EquippableItemTypeDefinition : ScriptableObject public Sprite[] AvailableIcons => availableIcons; public bool UseResourcesFolder => useResourcesFolder; public string ResourcesPath => resourcesPath; - public StatDefinition[] AllowedStats => allowedStats; - public StatDefinition[] ForbiddenStats => forbiddenStats; - public StatDefinition[] MandatoryStats => mandatoryStats; - public StatWeightModifier[] StatWeightModifiers => statWeightModifiers; + public StatAvailabilityWeightAndRolls[] StatRules => statRules; public bool CanBeGenerated => canBeGenerated; public float BaseGenerationWeight => baseGenerationWeight; - public int MinStatRolls => minStatRolls; - public int MaxStatRolls => maxStatRolls; // Cached icons from resources private Sprite[] resourceIcons; @@ -86,17 +76,6 @@ public class EquippableItemTypeDefinition : ScriptableObject shortName = displayName.Length > 8 ? displayName.Substring(0, 8) : displayName; } - // Ensure min/max stat rolls make sense - if (minStatRolls > maxStatRolls) - { - maxStatRolls = minStatRolls; - } - - if (minStatRolls < 0) - { - minStatRolls = 0; - } - // Ensure base generation weight is positive if (baseGenerationWeight < 0f) { @@ -108,6 +87,73 @@ public class EquippableItemTypeDefinition : ScriptableObject { Debug.LogWarning($"EquipmentTypeDefinition '{name}': Using resources folder, manual icon array will be ignored."); } + + // Auto-populate stat rules if array is empty or incomplete + ValidateStatRules(); + } + + private void ValidateStatRules() + { +#if UNITY_EDITOR + // Only populate in editor, not at runtime + if (Application.isPlaying) return; + + // Load all stat definitions from Resources + StatDefinition[] allStats = Resources.LoadAll("StatDefinitions"); + if (allStats.Length == 0) return; + + // Check if we need to update the stat rules array + bool needsUpdate = false; + HashSet existingStats = new HashSet(statRules.Select(r => r.stat).Where(s => s != null)); + + foreach (var stat in allStats) + { + if (!existingStats.Contains(stat)) + { + needsUpdate = true; + break; + } + } + + if (needsUpdate) + { + // Create new array with all stats + List newStatRules = new List(); + + // Keep existing rules that are still valid + foreach (var existingRule in statRules) + { + if (existingRule.stat != null && allStats.Contains(existingRule.stat)) + { + newStatRules.Add(existingRule); + } + } + + // Add missing stats with default values + foreach (var stat in allStats) + { + if (!existingStats.Contains(stat)) + { + newStatRules.Add(new StatAvailabilityWeightAndRolls + { + stat = stat, + isAllowed = true, // Default to allowed + isMandatory = false, + weightMultiplier = stat.DefaultWeight, + minStatRoll = 0f, + maxStatRoll = 100f + }); + } + } + + // Sort alphabetically by stat key for consistency + newStatRules.Sort((a, b) => string.Compare(a.stat.StatKey, b.stat.StatKey, System.StringComparison.OrdinalIgnoreCase)); + + statRules = newStatRules.ToArray(); + + Debug.Log($"EquipmentTypeDefinition '{name}': Updated stat rules with {newStatRules.Count} stats"); + } +#endif } // Utility methods @@ -152,32 +198,41 @@ public class EquippableItemTypeDefinition : ScriptableObject public bool IsStatAllowed(StatDefinition stat) { - // Check if explicitly forbidden - if (forbiddenStats.Contains(stat)) - return false; - - // If allowedStats is specified, stat must be in it - if (allowedStats.Length > 0) - return allowedStats.Contains(stat); - - // If no explicit allowed list, allow by default (unless forbidden) - return true; + var rule = statRules.FirstOrDefault(r => r.stat == stat); + return rule?.isAllowed ?? false; // Default to not allowed if no rule found } public bool IsStatMandatory(StatDefinition stat) { - return mandatoryStats.Contains(stat); + var rule = statRules.FirstOrDefault(r => r.stat == stat); + return rule?.isMandatory ?? false; } public float GetStatWeightMultiplier(StatDefinition stat) { - var modifier = statWeightModifiers.FirstOrDefault(m => m.stat == stat); - return modifier != null ? modifier.weightMultiplier : 1f; + var rule = statRules.FirstOrDefault(r => r.stat == stat); + return rule?.weightMultiplier ?? 1f; + } + + public (float min, float max) GetStatRollRange(StatDefinition stat) + { + var rule = statRules.FirstOrDefault(r => r.stat == stat); + if (rule != null) + return (rule.minStatRoll, rule.maxStatRoll); + return (0f, 100f); // Default range } public int GetRandomStatRollCount() { - return Random.Range(minStatRolls, maxStatRolls + 1); + // Count how many stats are allowed and could potentially roll + int allowedStatsCount = statRules.Count(r => r.isAllowed); + int mandatoryStatsCount = statRules.Count(r => r.isMandatory); + + // Ensure we at least roll mandatory stats, but allow for more + int minRolls = Mathf.Max(1, mandatoryStatsCount); + int maxRolls = Mathf.Max(minRolls, Mathf.Min(allowedStatsCount, GameConstants.EquipmentStatRules.ItemTotalStats)); + + return Random.Range(minRolls, maxRolls + 1); } private void LoadIconsFromResources() @@ -201,6 +256,17 @@ public class EquippableItemTypeDefinition : ScriptableObject var icon = GetRandomIcon(); Debug.Log($"{name}: Random icon = {(icon != null ? icon.name : "None")}"); } + + [ContextMenu("Update Stat Rules")] + private void ForceUpdateStatRules() + { +#if UNITY_EDITOR + // Force update by clearing and repopulating + statRules = new StatAvailabilityWeightAndRolls[0]; + ValidateStatRules(); + UnityEditor.EditorUtility.SetDirty(this); +#endif + } } [System.Serializable] @@ -209,6 +275,7 @@ public class StatWeightModifier public StatDefinition stat; public float weightMultiplier = 1f; } + [System.Serializable] public class StatAvailabilityWeightAndRolls { diff --git a/Assets/Scriptables/Data/Resources/Items/Equippables/EquippableItemTypeDefinitions/Resources/EquipmentDefinitions/Helmet.asset b/Assets/Scriptables/Data/Resources/Items/Equippables/EquippableItemTypeDefinitions/Resources/EquipmentDefinitions/Helmet.asset index 4c952e58..ec3c030e 100644 --- a/Assets/Scriptables/Data/Resources/Items/Equippables/EquippableItemTypeDefinitions/Resources/EquipmentDefinitions/Helmet.asset +++ b/Assets/Scriptables/Data/Resources/Items/Equippables/EquippableItemTypeDefinitions/Resources/EquipmentDefinitions/Helmet.asset @@ -23,36 +23,144 @@ MonoBehaviour: availableIcons: [] useResourcesFolder: 1 resourcesPath: Armor/Helmets - allowedStats: - - {fileID: 11400000, guid: 8a59fbc0a19857b48a0789d4b4115ea4, type: 2} - - {fileID: 11400000, guid: 6093187f425cccc43b5fa829db293893, type: 2} - - {fileID: 11400000, guid: e6da017ba613adf4d82d9b6a214c6c7c, type: 2} - - {fileID: 11400000, guid: 79006f60ae538ad4ca179ee739f39232, type: 2} - - {fileID: 11400000, guid: f1c964d3ea9c1d349bb5111b11accade, type: 2} - - {fileID: 11400000, guid: a50126674c634ef49b4986605ee42baa, type: 2} - - {fileID: 11400000, guid: ec3548202e941294da429cd3083937c0, type: 2} - forbiddenStats: - - {fileID: 11400000, guid: de18f1cd5c7345243a127dbf50a1c714, type: 2} - - {fileID: 11400000, guid: 88595dcd80f9c614b8bd7d8218fb5951, type: 2} - - {fileID: 11400000, guid: 0886a83f3dd15114487850e54518829d, type: 2} - - {fileID: 11400000, guid: d318a3662a3ccf04f9f193a818cc3361, type: 2} - - {fileID: 11400000, guid: a19f2ac40579e5d4aa0713f43fcfa276, type: 2} - - {fileID: 11400000, guid: 332d0dbee9590e24e9ad5166dd75ef69, type: 2} - - {fileID: 11400000, guid: aa214c2ad3c962447b486ecf16c9c950, type: 2} - - {fileID: 11400000, guid: 8dcb92f2ee1026241a3bc051a42f91f5, type: 2} - - {fileID: 11400000, guid: 4e90e0c058763a143b3ec657351fcace, type: 2} - - {fileID: 11400000, guid: d9561a8f85fc81f43961fa58de0cd088, type: 2} - - {fileID: 11400000, guid: 1407df369cf076445a1619597e085e1c, type: 2} - mandatoryStats: - - {fileID: 11400000, guid: 8a59fbc0a19857b48a0789d4b4115ea4, type: 2} - statWeightModifiers: + statRules: + - stat: {fileID: 11400000, guid: d9561a8f85fc81f43961fa58de0cd088, type: 2} + isAllowed: 0 + isMandatory: 0 + weightMultiplier: 0 + minStatRoll: 0 + maxStatRoll: 100 - stat: {fileID: 11400000, guid: 8a59fbc0a19857b48a0789d4b4115ea4, type: 2} + isAllowed: 1 + isMandatory: 1 weightMultiplier: 2 - - stat: {fileID: 11400000, guid: 6093187f425cccc43b5fa829db293893, type: 2} - weightMultiplier: 1.5 + minStatRoll: 1 + maxStatRoll: 3 + - stat: {fileID: 11400000, guid: de18f1cd5c7345243a127dbf50a1c714, type: 2} + isAllowed: 0 + isMandatory: 0 + weightMultiplier: 0 + minStatRoll: 0 + maxStatRoll: 100 + - stat: {fileID: 11400000, guid: 0886a83f3dd15114487850e54518829d, type: 2} + isAllowed: 0 + isMandatory: 0 + weightMultiplier: 0 + minStatRoll: 0 + maxStatRoll: 100 + - stat: {fileID: 11400000, guid: 332d0dbee9590e24e9ad5166dd75ef69, type: 2} + isAllowed: 0 + isMandatory: 0 + weightMultiplier: 0 + minStatRoll: 0 + maxStatRoll: 100 + - stat: {fileID: 11400000, guid: 8dcb92f2ee1026241a3bc051a42f91f5, type: 2} + isAllowed: 0 + isMandatory: 0 + weightMultiplier: 0 + minStatRoll: 0 + maxStatRoll: 100 + - stat: {fileID: 11400000, guid: 4e90e0c058763a143b3ec657351fcace, type: 2} + isAllowed: 0 + isMandatory: 0 + weightMultiplier: 0 + minStatRoll: 0 + maxStatRoll: 100 - stat: {fileID: 11400000, guid: ec3548202e941294da429cd3083937c0, type: 2} + isAllowed: 1 + isMandatory: 0 weightMultiplier: 0.25 + minStatRoll: 0.01 + maxStatRoll: 0.05 + - stat: {fileID: 11400000, guid: d318a3662a3ccf04f9f193a818cc3361, type: 2} + isAllowed: 0 + isMandatory: 0 + weightMultiplier: 0 + minStatRoll: 0 + maxStatRoll: 100 + - stat: {fileID: 11400000, guid: a19f2ac40579e5d4aa0713f43fcfa276, type: 2} + isAllowed: 0 + isMandatory: 0 + weightMultiplier: 0 + minStatRoll: 0 + maxStatRoll: 100 + - stat: {fileID: 11400000, guid: d52b20e3f02ba8946bf37a7470beafd0, type: 2} + isAllowed: 0 + isMandatory: 0 + weightMultiplier: 0 + minStatRoll: 0 + maxStatRoll: 100 + - stat: {fileID: 11400000, guid: aa214c2ad3c962447b486ecf16c9c950, type: 2} + isAllowed: 0 + isMandatory: 0 + weightMultiplier: 0 + minStatRoll: 0 + maxStatRoll: 100 + - stat: {fileID: 11400000, guid: 63eee8f1286035f4a80356bcfad289b6, type: 2} + isAllowed: 0 + isMandatory: 0 + weightMultiplier: 0 + minStatRoll: 0 + maxStatRoll: 100 + - stat: {fileID: 11400000, guid: 1e63fcf4ac1c02c4e9b9bd62f0243f05, type: 2} + isAllowed: 0 + isMandatory: 0 + weightMultiplier: 0 + minStatRoll: 0 + maxStatRoll: 100 + - stat: {fileID: 11400000, guid: 79006f60ae538ad4ca179ee739f39232, type: 2} + isAllowed: 1 + isMandatory: 0 + weightMultiplier: 1 + minStatRoll: 1 + maxStatRoll: 2 + - stat: {fileID: 11400000, guid: 6093187f425cccc43b5fa829db293893, type: 2} + isAllowed: 1 + isMandatory: 0 + weightMultiplier: 1.25 + minStatRoll: 1 + maxStatRoll: 3 + - stat: {fileID: 11400000, guid: a50126674c634ef49b4986605ee42baa, type: 2} + isAllowed: 1 + isMandatory: 0 + weightMultiplier: 1 + minStatRoll: 1 + maxStatRoll: 2 + - stat: {fileID: 11400000, guid: e6da017ba613adf4d82d9b6a214c6c7c, type: 2} + isAllowed: 1 + isMandatory: 0 + weightMultiplier: 1 + minStatRoll: 1 + maxStatRoll: 3 + - stat: {fileID: 11400000, guid: f1c964d3ea9c1d349bb5111b11accade, type: 2} + isAllowed: 1 + isMandatory: 0 + weightMultiplier: 1 + minStatRoll: 1 + maxStatRoll: 3 + - stat: {fileID: 11400000, guid: 1407df369cf076445a1619597e085e1c, type: 2} + isAllowed: 0 + isMandatory: 0 + weightMultiplier: 0 + minStatRoll: 0 + maxStatRoll: 100 + - stat: {fileID: 11400000, guid: 599541ff1aaa6c848a732f9a97e5f1c4, type: 2} + isAllowed: 0 + isMandatory: 0 + weightMultiplier: 0 + minStatRoll: 0 + maxStatRoll: 100 + - stat: {fileID: 11400000, guid: 7895ba1f0b9a732488642046ee62c8a6, type: 2} + isAllowed: 0 + isMandatory: 0 + weightMultiplier: 0 + minStatRoll: 0 + maxStatRoll: 100 + - stat: {fileID: 11400000, guid: 88595dcd80f9c614b8bd7d8218fb5951, type: 2} + isAllowed: 0 + isMandatory: 0 + weightMultiplier: 0 + minStatRoll: 0 + maxStatRoll: 100 canBeGenerated: 1 baseGenerationWeight: 1 - minStatRolls: 1 - maxStatRolls: 3 diff --git a/Assets/Scriptables/Data/Resources/Items/Equippables/EquippableItemTypeDefinitions/Resources/EquipmentDefinitions/Shoulder.asset b/Assets/Scriptables/Data/Resources/Items/Equippables/EquippableItemTypeDefinitions/Resources/EquipmentDefinitions/Shoulder.asset index 5df35f19..8b8b51f1 100644 --- a/Assets/Scriptables/Data/Resources/Items/Equippables/EquippableItemTypeDefinitions/Resources/EquipmentDefinitions/Shoulder.asset +++ b/Assets/Scriptables/Data/Resources/Items/Equippables/EquippableItemTypeDefinitions/Resources/EquipmentDefinitions/Shoulder.asset @@ -23,11 +23,144 @@ MonoBehaviour: availableIcons: [] useResourcesFolder: 1 resourcesPath: Armor/Shoulders - allowedStats: [] - forbiddenStats: [] - mandatoryStats: [] - statWeightModifiers: [] + statRules: + - stat: {fileID: 11400000, guid: d9561a8f85fc81f43961fa58de0cd088, type: 2} + isAllowed: 0 + isMandatory: 0 + weightMultiplier: 0 + minStatRoll: 0 + maxStatRoll: 100 + - stat: {fileID: 11400000, guid: 8a59fbc0a19857b48a0789d4b4115ea4, type: 2} + isAllowed: 1 + isMandatory: 1 + weightMultiplier: 2 + minStatRoll: 1 + maxStatRoll: 3 + - stat: {fileID: 11400000, guid: de18f1cd5c7345243a127dbf50a1c714, type: 2} + isAllowed: 0 + isMandatory: 0 + weightMultiplier: 0 + minStatRoll: 0 + maxStatRoll: 100 + - stat: {fileID: 11400000, guid: 0886a83f3dd15114487850e54518829d, type: 2} + isAllowed: 0 + isMandatory: 0 + weightMultiplier: 0 + minStatRoll: 0 + maxStatRoll: 100 + - stat: {fileID: 11400000, guid: 332d0dbee9590e24e9ad5166dd75ef69, type: 2} + isAllowed: 0 + isMandatory: 0 + weightMultiplier: 0 + minStatRoll: 0 + maxStatRoll: 100 + - stat: {fileID: 11400000, guid: 8dcb92f2ee1026241a3bc051a42f91f5, type: 2} + isAllowed: 0 + isMandatory: 0 + weightMultiplier: 0 + minStatRoll: 0 + maxStatRoll: 100 + - stat: {fileID: 11400000, guid: 4e90e0c058763a143b3ec657351fcace, type: 2} + isAllowed: 0 + isMandatory: 0 + weightMultiplier: 0 + minStatRoll: 0 + maxStatRoll: 100 + - stat: {fileID: 11400000, guid: ec3548202e941294da429cd3083937c0, type: 2} + isAllowed: 0 + isMandatory: 0 + weightMultiplier: 0 + minStatRoll: 0.01 + maxStatRoll: 0.05 + - stat: {fileID: 11400000, guid: d318a3662a3ccf04f9f193a818cc3361, type: 2} + isAllowed: 0 + isMandatory: 0 + weightMultiplier: 0 + minStatRoll: 0 + maxStatRoll: 100 + - stat: {fileID: 11400000, guid: a19f2ac40579e5d4aa0713f43fcfa276, type: 2} + isAllowed: 0 + isMandatory: 0 + weightMultiplier: 0 + minStatRoll: 0 + maxStatRoll: 100 + - stat: {fileID: 11400000, guid: d52b20e3f02ba8946bf37a7470beafd0, type: 2} + isAllowed: 0 + isMandatory: 0 + weightMultiplier: 0 + minStatRoll: 0 + maxStatRoll: 100 + - stat: {fileID: 11400000, guid: aa214c2ad3c962447b486ecf16c9c950, type: 2} + isAllowed: 0 + isMandatory: 0 + weightMultiplier: 0 + minStatRoll: 0 + maxStatRoll: 100 + - stat: {fileID: 11400000, guid: 63eee8f1286035f4a80356bcfad289b6, type: 2} + isAllowed: 0 + isMandatory: 0 + weightMultiplier: 0 + minStatRoll: 0 + maxStatRoll: 100 + - stat: {fileID: 11400000, guid: 1e63fcf4ac1c02c4e9b9bd62f0243f05, type: 2} + isAllowed: 0 + isMandatory: 0 + weightMultiplier: 0 + minStatRoll: 0 + maxStatRoll: 100 + - stat: {fileID: 11400000, guid: 79006f60ae538ad4ca179ee739f39232, type: 2} + isAllowed: 1 + isMandatory: 0 + weightMultiplier: 1 + minStatRoll: 1 + maxStatRoll: 2 + - stat: {fileID: 11400000, guid: 6093187f425cccc43b5fa829db293893, type: 2} + isAllowed: 1 + isMandatory: 0 + weightMultiplier: 1.25 + minStatRoll: 1 + maxStatRoll: 3 + - stat: {fileID: 11400000, guid: a50126674c634ef49b4986605ee42baa, type: 2} + isAllowed: 1 + isMandatory: 0 + weightMultiplier: 1 + minStatRoll: 1 + maxStatRoll: 2 + - stat: {fileID: 11400000, guid: e6da017ba613adf4d82d9b6a214c6c7c, type: 2} + isAllowed: 1 + isMandatory: 0 + weightMultiplier: 1 + minStatRoll: 1 + maxStatRoll: 3 + - stat: {fileID: 11400000, guid: f1c964d3ea9c1d349bb5111b11accade, type: 2} + isAllowed: 1 + isMandatory: 0 + weightMultiplier: 1 + minStatRoll: 1 + maxStatRoll: 3 + - stat: {fileID: 11400000, guid: 1407df369cf076445a1619597e085e1c, type: 2} + isAllowed: 0 + isMandatory: 0 + weightMultiplier: 0 + minStatRoll: 0 + maxStatRoll: 100 + - stat: {fileID: 11400000, guid: 599541ff1aaa6c848a732f9a97e5f1c4, type: 2} + isAllowed: 0 + isMandatory: 0 + weightMultiplier: 0 + minStatRoll: 0 + maxStatRoll: 100 + - stat: {fileID: 11400000, guid: 7895ba1f0b9a732488642046ee62c8a6, type: 2} + isAllowed: 0 + isMandatory: 0 + weightMultiplier: 0 + minStatRoll: 0 + maxStatRoll: 100 + - stat: {fileID: 11400000, guid: 88595dcd80f9c614b8bd7d8218fb5951, type: 2} + isAllowed: 0 + isMandatory: 0 + weightMultiplier: 0 + minStatRoll: 0 + maxStatRoll: 100 canBeGenerated: 1 baseGenerationWeight: 1 - minStatRolls: 1 - maxStatRolls: 3 diff --git a/Assets/Scriptables/Data/Resources/Items/Equippables/EquippableItemTypeDefinitions/Resources/EquipmentDefinitions/Shoulder.asset.meta b/Assets/Scriptables/Data/Resources/Items/Equippables/EquippableItemTypeDefinitions/Resources/EquipmentDefinitions/Shoulder.asset.meta index ad183509..d562ccfa 100644 --- a/Assets/Scriptables/Data/Resources/Items/Equippables/EquippableItemTypeDefinitions/Resources/EquipmentDefinitions/Shoulder.asset.meta +++ b/Assets/Scriptables/Data/Resources/Items/Equippables/EquippableItemTypeDefinitions/Resources/EquipmentDefinitions/Shoulder.asset.meta @@ -1,5 +1,5 @@ fileFormatVersion: 2 -guid: b7d57fbc93b54ee4cb5a2dc567254d6a +guid: 9044a1de874c1294bbd261141af44093 NativeFormatImporter: externalObjects: {} mainObjectFileID: 11400000