using UnityEngine; using Colosseum.Passives; using Colosseum.Skills; using Colosseum.Weapons; namespace Colosseum.Player { /// /// 플레이어의 방어 유지 자원 소모를 관리합니다. /// 방어 판정과 분리되어 있으며, 애니메이션 이벤트로 시작/종료됩니다. /// [DisallowMultipleComponent] public class PlayerDefenseSustainController : MonoBehaviour { [Header("References")] [Tooltip("플레이어 자원 관리자")] [SerializeField] private PlayerNetworkController networkController; [Tooltip("현재 실행 중인 스킬 정보 참조용")] [SerializeField] private SkillController skillController; [Tooltip("무기 마나 배율 참조용")] [SerializeField] private WeaponEquipment weaponEquipment; [Header("Sustain Settings")] [Tooltip("방어 유지의 초당 기본 마나 소모량입니다.")] [Min(0f)] [SerializeField] private float sustainManaPerSecond = 4f; [Tooltip("방어 유지 시간이 길어질수록 추가되는 초당 마나 소모량입니다.")] [Min(0f)] [SerializeField] private float sustainManaRampPerSecond = 4f; [Tooltip("완벽한 방어 성공 시 환급할 시작 마나 비율입니다.")] [Range(0f, 1f)] [SerializeField] private float perfectGuardStartManaRefundRatio = 1f; [Tooltip("방어 유지 중 이동 속도 배율입니다.")] [Range(0f, 1f)] [SerializeField] private float sustainMoveSpeedMultiplier = 0.45f; [Header("Debug")] [Tooltip("현재 방어 유지 활성 여부")] [SerializeField] private bool isSustainActive; [Tooltip("현재 방어 유지 시간")] [Min(0f)] [SerializeField] private float sustainElapsed; [Tooltip("현재 프레임에 계산된 초당 유지 마나")] [Min(0f)] [SerializeField] private float currentSustainManaPerSecond; [Tooltip("마지막으로 캡처한 시작 마나 소모량")] [Min(0f)] [SerializeField] private float capturedStartManaCost; /// /// 현재 방어 유지 활성 여부입니다. /// public bool IsSustainActive => isSustainActive; /// /// 방어 유지 중 이동 속도 배율입니다. /// public float MoveSpeedMultiplier => isSustainActive ? sustainMoveSpeedMultiplier : 1f; private void Awake() { EnsureReferences(); } private void OnDisable() { ClearSustainState(); } private void Update() { if (!isSustainActive) return; sustainElapsed += Time.deltaTime; currentSustainManaPerSecond = sustainManaPerSecond + (sustainManaRampPerSecond * sustainElapsed); if (networkController == null || !networkController.IsServer) return; float requiredMana = currentSustainManaPerSecond * Time.deltaTime; float actualSpentMana = networkController.SpendMana(requiredMana); if (actualSpentMana + 0.001f < requiredMana) { skillController?.CancelSkillFromServer(SkillCancelReason.ResourceExhausted); ClearSustainState(); } } /// /// 애니메이션 이벤트로 방어 유지 자원 소모를 시작합니다. /// public void BeginSustain() { EnsureReferences(); isSustainActive = true; sustainElapsed = 0f; currentSustainManaPerSecond = sustainManaPerSecond; capturedStartManaCost = ResolveCurrentSkillManaCost(); } /// /// 애니메이션 이벤트로 방어 유지 자원 소모를 종료합니다. /// public void EndSustain() { ClearSustainState(); } /// /// 스킬 종료/취소 시 방어 유지 상태를 정리합니다. /// public void HandleSkillExecutionEnded() { ClearSustainState(); } /// /// 완벽한 방어 성공 시 시작 마나를 환급합니다. /// public void RefundStartManaOnPerfectGuard() { EnsureReferences(); if (!isSustainActive || networkController == null || !networkController.IsServer) return; float refundAmount = capturedStartManaCost * perfectGuardStartManaRefundRatio; if (refundAmount <= 0f) return; networkController.RestoreMana(refundAmount); } private void EnsureReferences() { if (networkController == null) networkController = GetComponent(); if (skillController == null) skillController = GetComponent(); if (weaponEquipment == null) weaponEquipment = GetComponent(); } private float ResolveCurrentSkillManaCost() { SkillLoadoutEntry loadoutEntry = skillController != null ? skillController.CurrentLoadoutEntry : null; SkillData skill = loadoutEntry != null ? loadoutEntry.BaseSkill : skillController != null ? skillController.CurrentSkill : null; if (skill == null) return 0f; float baseManaCost = loadoutEntry != null ? loadoutEntry.GetResolvedManaCost() : skill.ManaCost; float weaponMultiplier = weaponEquipment != null ? weaponEquipment.ManaCostMultiplier : 1f; float passiveMultiplier = PassiveRuntimeModifierUtility.GetManaCostMultiplier(gameObject, skill); return baseManaCost * weaponMultiplier * passiveMultiplier; } private void ClearSustainState() { isSustainActive = false; sustainElapsed = 0f; currentSustainManaPerSecond = 0f; capturedStartManaCost = 0f; } } }