using UnityEngine;
using BaseGames.Core.Events;
namespace BaseGames.Combat
{
///
/// 单次伤害信息。流水线:RawDamage → Amount(护盾修改)→ FinalDamage(防御减免后)。
/// ⚠️ 保留为可变 struct:HurtBox 流水线需要在方法内修改本地副本的 Amount / FinalDamage。
/// Builder 通过独立字段构造,不直接修改 DamageInfo 实例。
///
[System.Serializable]
public struct DamageInfo
{
public int RawDamage; // HitBox 设定的原始值(工厂/Builder 写入一次)
public int Amount; // 流水线中被护盾/防御修改
public int FinalDamage; // HurtBox 写入,最终 HP 扣除量
public Vector2 KnockbackDirection;
public float KnockbackForce;
public float HitStunDuration;
public DamageType Type;
public DamageCategory Category;
public DamageFlags Flags;
public DamageTags Tags;
public Vector2 SourcePosition;
public int SourceLayer;
public HitFxType FxType;
public BreakLevel Break;
public string SourceId;
public string SkillId;
///
/// HitBox 激活实例 ID(由 HitBox.Activate() 自动生成并写入,0 = 无追踪路径)。
/// HurtBoxOwnerGuard 用此字段做同激活去重,防止多 HurtBox 节点被同一次攻击重复扣血。
/// [NonSerialized]:每次激活动态生成,不需要序列化。
///
[System.NonSerialized] public uint HitActivationId;
///
/// 攻击来源投射物(仅当攻击方是 Projectile 时非 null)。
/// 用于弹反成功时调用 ReflectAsPlayerProjectile() 翻转阵营。
/// [NonSerialized]:MonoBehaviour 引用不参与 Unity 资产序列化。
///
[System.NonSerialized] public Projectile SourceProjectile;
// ── Builder ──────────────────────────────────────────────────────────
///
/// 通过独立字段构造 DamageInfo,避免直接持有可变 DamageInfo 实例。
///
public class Builder
{
private int _raw;
private DamageType _type;
private DamageCategory _category;
private DamageFlags _flags;
private DamageTags _tags;
private string _skillId;
private string _sourceId;
private Vector2 _knockbackDirection;
private float _knockbackForce;
private float _hitStunDuration;
private HitFxType _fxType;
private BreakLevel _break;
private Vector2 _sourcePosition;
private int _sourceLayer;
private Projectile _sourceProjectile;
public Builder() { }
// SetRaw 同步初始化 Amount(Amount 始终以 RawDamage 为起点)
public Builder SetRaw(int v) { _raw = v; return this; }
public Builder SetType(DamageType v) { _type = v; return this; }
public Builder SetCategory(DamageCategory v) { _category = v; return this; }
public Builder SetFlags(DamageFlags v) { _flags = v; return this; }
public Builder SetTags(DamageTags v) { _tags = v; return this; }
public Builder SetSkillId(string v) { _skillId = v; return this; }
public Builder SetSourceId(string v) { _sourceId = v; return this; }
public Builder SetKnockback(Vector2 dir, float force) { _knockbackDirection = dir; _knockbackForce = force; return this; }
public Builder SetStun(float dur) { _hitStunDuration = dur; return this; }
public Builder SetFx(HitFxType v) { _fxType = v; return this; }
public Builder SetBreak(BreakLevel v) { _break = v; return this; }
public Builder SetSourcePos(Vector2 v) { _sourcePosition = v; return this; }
public Builder SetLayer(int v) { _sourceLayer = v; return this; }
public Builder SetProjectile(Projectile v) { _sourceProjectile = v; return this; }
public DamageInfo Build() => new DamageInfo
{
RawDamage = _raw,
Amount = _raw,
Type = _type,
Category = _category,
Flags = _flags,
Tags = _tags,
SkillId = _skillId,
SourceId = _sourceId,
KnockbackDirection = _knockbackDirection,
KnockbackForce = _knockbackForce,
HitStunDuration = _hitStunDuration,
FxType = _fxType,
Break = _break,
SourcePosition = _sourcePosition,
SourceLayer = _sourceLayer,
SourceProjectile = _sourceProjectile,
};
}
///
/// ⚡ 零堆分配工厂(热路径首选)。从 DamageSourceSO 填入所有静态字段;
/// 可选传入运行时字段(knockbackDir、sourcePos、sourceLayer),
/// 无需调用方事后就地赋值。
///
public static DamageInfo From(
DamageSourceSO so,
Vector2 knockbackDir = default,
Vector2 sourcePos = default,
int sourceLayer = 0,
Projectile sourceProjectile = null)
{
int baseAmt = Mathf.RoundToInt(so.BaseDamage * so.DamageMultiplier);
return new DamageInfo
{
RawDamage = baseAmt,
Amount = baseAmt,
Type = so.Type,
Category = so.Category,
Flags = so.Flags,
Tags = so.Tags,
HitStunDuration = so.HitStunDuration,
FxType = so.FxType,
Break = so.BreakLevel,
SourceId = so.sourceId,
SkillId = so.skillId,
KnockbackDirection = knockbackDir,
KnockbackForce = so.KnockbackForce,
SourcePosition = sourcePos,
SourceLayer = sourceLayer,
SourceProjectile = sourceProjectile,
};
}
}
/// 伤害事件频道(EVT_DamageDealt)。
[UnityEngine.CreateAssetMenu(menuName = "Events/DamageDealt")]
public class DamageInfoEventChannelSO : BaseEventChannelSO { }
}