using System.Collections.Generic; using UnityEngine; namespace Colosseum.Skills { /// /// 단일 슬롯에서 사용할 스킬과 장착된 젬 조합입니다. /// [System.Serializable] public class SkillLoadoutEntry { private const int DefaultGemSlotCount = 2; [Tooltip("이 슬롯의 기반 스킬")] [SerializeField] private SkillData baseSkill; [Tooltip("기반 스킬에 장착된 젬")] [SerializeField] private SkillGemData[] socketedGems = new SkillGemData[DefaultGemSlotCount]; public SkillData BaseSkill => baseSkill; public IReadOnlyList SocketedGems => socketedGems; public static SkillLoadoutEntry CreateTemporary(SkillData skill) { SkillLoadoutEntry entry = new SkillLoadoutEntry(); entry.SetBaseSkill(skill); entry.EnsureGemSlotCapacity(); return entry; } public SkillLoadoutEntry CreateCopy() { SkillLoadoutEntry copy = new SkillLoadoutEntry(); copy.baseSkill = baseSkill; copy.socketedGems = new SkillGemData[socketedGems != null ? socketedGems.Length : DefaultGemSlotCount]; if (socketedGems != null) { for (int i = 0; i < socketedGems.Length; i++) { copy.socketedGems[i] = socketedGems[i]; } } return copy; } public void EnsureGemSlotCapacity(int slotCount = -1) { if (slotCount < 0) { slotCount = baseSkill != null ? baseSkill.MaxGemSlotCount : DefaultGemSlotCount; } slotCount = Mathf.Max(0, slotCount); if (socketedGems != null && socketedGems.Length == slotCount) return; SkillGemData[] resized = new SkillGemData[slotCount]; if (socketedGems != null) { int copyCount = Mathf.Min(socketedGems.Length, resized.Length); for (int i = 0; i < copyCount; i++) { resized[i] = socketedGems[i]; } } socketedGems = resized; } public void SetBaseSkill(SkillData skill) { baseSkill = skill; EnsureGemSlotCapacity(); } public void SetGem(int slotIndex, SkillGemData gem) { EnsureGemSlotCapacity(); if (slotIndex < 0 || slotIndex >= socketedGems.Length) return; socketedGems[slotIndex] = gem; } public SkillGemData GetGem(int slotIndex) { EnsureGemSlotCapacity(); if (slotIndex < 0 || slotIndex >= socketedGems.Length) return null; return socketedGems[slotIndex]; } public float GetResolvedManaCost() { if (baseSkill == null) return 0f; float resolved = baseSkill.ManaCost; if (socketedGems == null) return resolved; for (int i = 0; i < socketedGems.Length; i++) { SkillGemData gem = socketedGems[i]; if (gem == null) continue; resolved *= gem.ManaCostMultiplier; } return resolved; } public float GetResolvedCooldown() { if (baseSkill == null) return 0f; float resolved = baseSkill.Cooldown; if (socketedGems == null) return resolved; for (int i = 0; i < socketedGems.Length; i++) { SkillGemData gem = socketedGems[i]; if (gem == null) continue; resolved *= gem.CooldownMultiplier; } return resolved; } public float GetResolvedAnimationSpeed() { if (baseSkill == null) return 0f; float resolved = baseSkill.AnimationSpeed; if (socketedGems == null) return resolved; for (int i = 0; i < socketedGems.Length; i++) { SkillGemData gem = socketedGems[i]; if (gem == null) continue; resolved *= gem.CastSpeedMultiplier; } return Mathf.Max(0.05f, resolved); } public int GetResolvedRepeatCount() { if (baseSkill == null) return 0; int resolved = 1; if (socketedGems == null) return resolved; for (int i = 0; i < socketedGems.Length; i++) { SkillGemData gem = socketedGems[i]; if (gem == null) continue; resolved += gem.AdditionalRepeatCount; } return Mathf.Max(1, resolved); } public void CollectCastStartEffects(List destination) { if (destination == null) return; if (baseSkill != null && baseSkill.CastStartEffects != null) { for (int i = 0; i < baseSkill.CastStartEffects.Count; i++) { SkillEffect effect = baseSkill.CastStartEffects[i]; if (effect != null) destination.Add(effect); } } if (socketedGems == null) return; for (int i = 0; i < socketedGems.Length; i++) { SkillGemData gem = socketedGems[i]; if (gem == null || gem.CastStartEffects == null) continue; for (int j = 0; j < gem.CastStartEffects.Count; j++) { SkillEffect effect = gem.CastStartEffects[j]; if (effect != null) destination.Add(effect); } } } public void CollectTriggeredEffects(Dictionary> destination) { if (destination == null) return; if (baseSkill != null && baseSkill.Effects != null) { for (int i = 0; i < baseSkill.Effects.Count; i++) { SkillEffect effect = baseSkill.Effects[i]; if (effect == null) continue; AddTriggeredEffect(destination, i, effect); } } if (socketedGems == null) return; for (int i = 0; i < socketedGems.Length; i++) { SkillGemData gem = socketedGems[i]; if (gem == null || gem.TriggeredEffects == null) continue; for (int j = 0; j < gem.TriggeredEffects.Count; j++) { SkillGemTriggeredEffectEntry entry = gem.TriggeredEffects[j]; if (entry == null || entry.Effects == null) continue; for (int k = 0; k < entry.Effects.Count; k++) { SkillEffect effect = entry.Effects[k]; if (effect == null) continue; AddTriggeredEffect(destination, entry.TriggerIndex, effect); } } } } private static void AddTriggeredEffect(Dictionary> destination, int triggerIndex, SkillEffect effect) { if (!destination.TryGetValue(triggerIndex, out List effectList)) { effectList = new List(); destination.Add(triggerIndex, effectList); } effectList.Add(effect); } } }