using System; using System.Collections.Generic; using System.Linq; using Cielonos.MainGame.Inventory; using Sirenix.OdinInspector; using SLSUtilities.General; using UnityEngine; namespace Cielonos.MainGame.Characters { public class DodgeSubmodule : SubmoduleBase { public List dodgeSources; public bool canDodge; [ShowInInspector] public bool isDodging => dodgeSources.Count > 0; [ShowInInspector] public bool isPerfectDodging => dodgeSources.Any(source => source.hasPerfectDodge && source.isDuringPerfectDodge); public float afterPerfectDodgeTimer; public float afterNormalDodgeTimer; public DodgeSubmodule(ReactionSubcontroller owner) : base(owner) { dodgeSources = new List(); canDodge = true; } public void ApplyDodge(DodgeSource source, bool refreshPerfect = false) { if (canDodge) { DodgeSource existingSource = dodgeSources.Find(x => x.dodgeName == source.dodgeName); if (existingSource != null) { if (source.dodgeTime > existingSource.dodgeTime) { existingSource.dodgeTime = source.dodgeTime; } if (refreshPerfect && existingSource.hasPerfectDodge) { existingSource.isDuringPerfectDodge = true; existingSource.perfectTime = source.perfectTime; } return; } dodgeSources.AddByPriority(source); } } public void ApplyDodge(CharacterBase sourceCharacter, ItemBase sourceItem, string dodgeName, int priority = 0, float dodgeTime = Mathf.Infinity, float perfectTime = 0.2f, bool refreshPerfect = false, string normalEffectName = "NormalDodge", string perfectEffectName = "PerfectDodge") { DodgeSource newSource = new DodgeSource(sourceCharacter, sourceItem, dodgeName, priority, normalEffectName, perfectEffectName, dodgeTime, perfectTime); ApplyDodge(newSource, refreshPerfect); } public void RemoveDodge(string dodgeName) { dodgeSources.RemoveAll(source => source.dodgeName == dodgeName); } public DodgeSource GetCurrentDodgeSource() { return dodgeSources.Count == 0 ? null : dodgeSources[0]; } public void Update() { if (isDodging) { dodgeSources.ForEach(source => { source.dodgeTime -= owner.owner.selfTimeSm.DeltaTime; if (source.hasPerfectDodge) { source.perfectTime -= owner.owner.selfTimeSm.DeltaTime; if (source.perfectTime <= 0) { source.isDuringPerfectDodge = false; } } }); dodgeSources.RemoveAll(source => source.dodgeTime <= 0); } afterPerfectDodgeTimer -= owner.owner.selfTimeSm.DeltaTime; afterNormalDodgeTimer -= owner.owner.selfTimeSm.DeltaTime; } } public class DodgeSource : IPrioritized { public int Priority { get; private set; } public CharacterBase sourceCharacter; public ItemBase sourceItem; public string dodgeName; public float dodgeBufferTime = 0.5f; public bool hasPerfectDodge; public bool isDuringPerfectDodge; public float perfectTime; public float dodgeTime; public string perfectEffectName; public Action onPerfectDodge; public string normalEffectName; public Action onNormalDodge; private bool _isTriggered; public DodgeSource(CharacterBase sourceCharacter, ItemBase sourceItem, string dodgeName, int priority, string dodgeEffectName, float dodgeTime) { this.sourceCharacter = sourceCharacter; this.sourceItem = sourceItem; this.dodgeName = dodgeName; this.normalEffectName = dodgeEffectName; this.Priority = priority; this.dodgeTime = dodgeTime; this.hasPerfectDodge = false; this.isDuringPerfectDodge = false; this._isTriggered = false; } public DodgeSource(CharacterBase sourceCharacter, ItemBase sourceItem, string dodgeName, int priority, string normalEffectName, string perfectEffectName, float dodgeTime, float perfectTime) { this.sourceCharacter = sourceCharacter; this.sourceItem = sourceItem; this.dodgeName = dodgeName; this.normalEffectName = normalEffectName; this.perfectEffectName = perfectEffectName; this.Priority = priority; this.dodgeTime = dodgeTime; this.perfectTime = perfectTime; this.hasPerfectDodge = true; this.isDuringPerfectDodge = true; this._isTriggered = false; } public static DodgeSource Default(CharacterBase sourceCharacter, float duration = Mathf.Infinity) { DodgeSource defaultDodge = new DodgeSource(sourceCharacter, null, "DefaultDodge", 0, "NormalDodge", "PerfectDodge", duration, 0.2f); if (sourceCharacter is Player player) { defaultDodge.onPerfectDodge = () => { // Perfect Dodge 反馈将在 PlayerFeedbackSubcontroller 中统一处理 // 这里可以添加任何 Perfect Dodge 特有的回调逻辑 // 例如:记录完美闪避次数、触发成就等 }; } return defaultDodge; } public void PerfectDodge() { if(_isTriggered) return; _isTriggered = true; onPerfectDodge?.Invoke(); if (sourceItem == null) { sourceCharacter.feedbackSc.PlayFeedback("PerfectDodge"); } sourceCharacter.reactionSc.dodgeSm.afterPerfectDodgeTimer = dodgeBufferTime + 0.25f; } public void NormalDodge() { if(_isTriggered) return; _isTriggered = true; onNormalDodge?.Invoke(); if (sourceItem == null) { sourceCharacter.feedbackSc.PlayFeedback("NormalDodge"); } sourceCharacter.reactionSc.dodgeSm.afterNormalDodgeTimer = dodgeBufferTime + 0.25f; } } }