using System; using System.Collections.Generic; using UnityEngine; [CreateAssetMenu(fileName = "idol_upgrade_config", menuName = "Idols/Upgrade Config")] public class upgradeConfig : ScriptableObject { [Serializable] public sealed class GrowthMaterialCost { public growthMaterialSO material; [Min(0)] public int amount = 0; } [Serializable] public sealed class BreakthroughBottleCost { public expBottlesSO bottle; [Min(0)] public int amount = 0; } [Serializable] public sealed class TierRule { public HeroGrowthTier currentTier = HeroGrowthTier.C; public HeroGrowthTier nextTier = HeroGrowthTier.B; public bool canTrain = true; public bool canBreakthrough = true; [Min(0)] public int requiredCoins = 0; public List linkedExpBottles = new List(); public List breakthroughCosts = new List(); public List breakthroughBottleCosts = new List(); } public enum SpecialBottleEffect { FillToNextTierCap, ReachTargetTierMaxWithoutSkippedBreakthroughPayment } [Serializable] public sealed class SpecialBottleRule { public expBottlesSO bottle; public SpecialBottleEffect effect = SpecialBottleEffect.FillToNextTierCap; public bool allowAnyCurrentTier = true; public HeroGrowthTier minimumCurrentTier = HeroGrowthTier.C; public HeroGrowthTier maximumCurrentTier = HeroGrowthTier.S; public HeroGrowthTier targetTier = HeroGrowthTier.A; } [Header("Tier Rules")] public List tierRules = new List(); [Header("Special Bottles")] public List specialBottleRules = new List(); public TierRule GetRule(HeroGrowthTier tier) { if (tierRules == null) { return null; } for (int i = 0; i < tierRules.Count; i++) { TierRule rule = tierRules[i]; if (rule != null && rule.currentTier == tier) { return rule; } } return null; } public List GetLinkedBottles(HeroGrowthTier tier) { TierRule rule = GetRule(tier); return rule != null ? rule.linkedExpBottles : null; } public List GetBreakthroughCosts(HeroGrowthTier tier) { TierRule rule = GetRule(tier); return rule != null ? rule.breakthroughCosts : null; } public SpecialBottleRule GetSpecialBottleRule(expBottlesSO bottle) { if (bottle == null || specialBottleRules == null) { return null; } for (int i = 0; i < specialBottleRules.Count; i++) { SpecialBottleRule rule = specialBottleRules[i]; if (rule != null && rule.bottle == bottle) { return rule; } } return null; } private void OnValidate() { EnsureDefaultRules(); NormalizeRules(); } private void EnsureDefaultRules() { EnsureRuleExists(HeroGrowthTier.C, HeroGrowthTier.B, true, true); EnsureRuleExists(HeroGrowthTier.B, HeroGrowthTier.A, true, true); EnsureRuleExists(HeroGrowthTier.A, HeroGrowthTier.S, true, true); } private void EnsureRuleExists(HeroGrowthTier currentTier, HeroGrowthTier nextTier, bool canTrain, bool canBreakthrough) { if (GetRule(currentTier) != null) { return; } if (tierRules == null) { tierRules = new List(); } tierRules.Add(new TierRule { currentTier = currentTier, nextTier = nextTier, canTrain = canTrain, canBreakthrough = canBreakthrough }); } private void NormalizeRules() { if (tierRules == null) { tierRules = new List(); return; } if (specialBottleRules == null) { specialBottleRules = new List(); } HashSet seen = new HashSet(); for (int i = tierRules.Count - 1; i >= 0; i--) { TierRule rule = tierRules[i]; if (rule == null) { tierRules.RemoveAt(i); continue; } if (seen.Contains(rule.currentTier)) { tierRules.RemoveAt(i); continue; } if (rule.currentTier == HeroGrowthTier.S) { tierRules.RemoveAt(i); continue; } seen.Add(rule.currentTier); if (rule.linkedExpBottles == null) { rule.linkedExpBottles = new List(); } if (rule.breakthroughCosts == null) { rule.breakthroughCosts = new List(); } if (rule.breakthroughBottleCosts == null) { rule.breakthroughBottleCosts = new List(); } if ((int)rule.nextTier <= (int)rule.currentTier) { rule.nextTier = (HeroGrowthTier)Mathf.Clamp((int)rule.currentTier + 1, 0, (int)HeroGrowthTier.S); } for (int costIndex = rule.breakthroughCosts.Count - 1; costIndex >= 0; costIndex--) { GrowthMaterialCost cost = rule.breakthroughCosts[costIndex]; if (cost == null) { rule.breakthroughCosts.RemoveAt(costIndex); continue; } cost.amount = Mathf.Max(0, cost.amount); } for (int bottleCostIndex = rule.breakthroughBottleCosts.Count - 1; bottleCostIndex >= 0; bottleCostIndex--) { BreakthroughBottleCost bottleCost = rule.breakthroughBottleCosts[bottleCostIndex]; if (bottleCost == null) { rule.breakthroughBottleCosts.RemoveAt(bottleCostIndex); continue; } bottleCost.amount = Mathf.Max(0, bottleCost.amount); } } for (int i = specialBottleRules.Count - 1; i >= 0; i--) { SpecialBottleRule rule = specialBottleRules[i]; if (rule == null) { specialBottleRules.RemoveAt(i); continue; } if (rule.allowAnyCurrentTier) { rule.minimumCurrentTier = HeroGrowthTier.C; rule.maximumCurrentTier = HeroGrowthTier.S; } else if ((int)rule.minimumCurrentTier > (int)rule.maximumCurrentTier) { HeroGrowthTier temp = rule.minimumCurrentTier; rule.minimumCurrentTier = rule.maximumCurrentTier; rule.maximumCurrentTier = temp; } if (rule.effect == SpecialBottleEffect.FillToNextTierCap) { rule.targetTier = HeroGrowthTier.A; } } tierRules.Sort((left, right) => left.currentTier.CompareTo(right.currentTier)); } }