using System.Collections.Generic; using Cielonos.MainGame.Characters; using UnityEngine; namespace Cielonos.MainGame { public static partial class Attack { /// /// 攻击结果:伤害结算后的数据载体,包含攻击事实、最终数值和对原始上下文的引用。 /// public class Result { #region References /// /// 产生本次结算的攻击区域。Buff、持续伤害等非 AttackArea 路径保持为 null。 /// public AttackAreaBase sourceArea; /// /// 原始攻击上下文,包含攻击者、目标、命中点、spamGroupID 和可修改攻击值。 /// public Context context; public CharacterBase attacker => context.attacker; public CharacterBase target => context.target; public Vector3 hitPosition => context.hitPosition; public string spamGroupID => context.spamGroupID; public Value value { get => context.value; set => context.value = value; } #endregion #region Final Values public float shieldBlockedDamage; public float finalDamage; public float finalStanceDepletion; public float hitRecoveryTime; #endregion #region Constructors /// /// 从已有上下文构建结果。用于标准攻击流程:Context 阶段完成后包装为 Result。 /// public Result(Context context) { this.context = context; } /// /// 从攻击区域构建结算结果,并保留本次攻击的来源。 /// public Result(Context context, AttackAreaBase sourceArea) : this(context) { this.sourceArea = sourceArea; } /// /// 直接从参数构建结果,用于 Buff 直接附伤等流程。会自动构建 Context 并关联 Value。 /// public Result(Context context, Value value) { this.context = context; this.value = value; } #endregion #region Outcomes public readonly HashSet outcomes = new HashSet(); public bool HasOutcome(Outcome outcome) { return outcomes.Contains(outcome); } public bool HasAnyOutcome(params Outcome[] queryOutcomes) { if (queryOutcomes == null) return false; foreach (Outcome outcome in queryOutcomes) { if (outcomes.Contains(outcome)) return true; } return false; } public bool HasAllOutcomes(params Outcome[] queryOutcomes) { if (queryOutcomes == null || queryOutcomes.Length == 0) return false; foreach (Outcome outcome in queryOutcomes) { if (!outcomes.Contains(outcome)) return false; } return true; } public void AddOutcome(Outcome outcome) { outcomes.Add(outcome); } public void RemoveOutcome(Outcome outcome) { outcomes.Remove(outcome); } public void SetOutcome(Outcome outcome, bool isActive) { if (isActive) { AddOutcome(outcome); } else { RemoveOutcome(outcome); } } public bool isBlocked { get => HasOutcome(Outcome.Blocked); set => SetOutcome(Outcome.Blocked, value); } public bool isDodged { get => HasOutcome(Outcome.Dodged); set => SetOutcome(Outcome.Dodged, value); } public bool isReflected { get => HasOutcome(Outcome.Reflected); set => SetOutcome(Outcome.Reflected, value); } public bool isMissed { get => HasOutcome(Outcome.Missed); set => SetOutcome(Outcome.Missed, value); } public bool isEvaded { get => HasOutcome(Outcome.Evaded); set => SetOutcome(Outcome.Evaded, value); } public bool causedDeath { get => HasOutcome(Outcome.Killed); set => SetOutcome(Outcome.Killed, value); } public bool isBreakthrough { get => HasOutcome(Outcome.Breakthrough); set => SetOutcome(Outcome.Breakthrough, value); } public bool isDisrupted { get => HasOutcome(Outcome.Disrupted); set => SetOutcome(Outcome.Disrupted, value); } public bool causedStanceBreak { get => HasOutcome(Outcome.StanceBreak); set => SetOutcome(Outcome.StanceBreak, value); } public bool isReactionOnlyCheck { get => HasOutcome(Outcome.ReactionOnlyCheck); set => SetOutcome(Outcome.ReactionOnlyCheck, value); } public bool isInvalidAttack { get => HasOutcome(Outcome.InvalidAttack); set => SetOutcome(Outcome.InvalidAttack, value); } public bool hitEventsInvoked { get => HasOutcome(Outcome.HitEventsInvoked); set => SetOutcome(Outcome.HitEventsInvoked, value); } public bool damageEventsInvoked { get => HasOutcome(Outcome.DamageEventsInvoked); set => SetOutcome(Outcome.DamageEventsInvoked, value); } public bool isDenied { get => context?.isDenied ?? false; set { if (context != null) { context.isDenied = value; } SetOutcome(Outcome.Denied, value); } } public bool isDamageNegated { get => value?.isDamageNegated ?? false; set { if (this.value != null) { this.value.isDamageNegated = value; } SetOutcome(Outcome.DamageNegated, value); } } public bool isEffectiveHit => !isBlocked && !isDodged && !isMissed && !isEvaded && !isDenied && target != null; /// /// 根据当前结算字段同步派生 Outcome。这里只记录攻击事实,不决定具体反馈表现。 /// public void ResolveOutcomes() { SetOutcome(Outcome.InvalidTarget, target == null); SetOutcome(Outcome.Denied, isDenied); SetOutcome(Outcome.Hit, isEffectiveHit && hitEventsInvoked); SetOutcome(Outcome.DamageNegated, isDamageNegated); SetOutcome(Outcome.ShieldAbsorbed, shieldBlockedDamage > 0f); SetOutcome(Outcome.HealthDamaged, finalDamage > 0f); SetOutcome(Outcome.Critical, isEffectiveHit && value is { isCritical: true }); SetOutcome(Outcome.StanceDepleted, finalStanceDepletion > 0f); } #endregion } } }