伤害结算
模组自己发出的伤害只有一条公共路径:DamageCalculationService。它把"谁、用什么、打在谁身上"到"目标实际掉多少血"分成两层,每层只读自己那一侧的数据,因为两半本来就属于两个不同的实体:
| 层 | 在哪结算 | 读什么 |
|---|---|---|
| 第一层:出力 | 发伤害的那一刻,攻击方一侧 | 定义里写的基础值 × 这次施放提供的 damage_multiplier × 攻击者灵根元素对目标灵根元素的 overcomes |
| 第二层:减免 | 目标收到伤害时(LivingIncomingDamageEvent),受击方一侧 | 受击者灵根元素对攻击元素的 adapted_to |
第一层必须发生在发伤害处,因为只有那里同时知道施法者、目标和正在施放的能力;第二层必须发生在受击处,因为只有那里能看到所有打过来的伤害——别的模组的、原版的摔落与怪物攻击都算在内,而"适应什么"本来就是受击者的属性。两层不会互相重复:第二层挂在一个"每次伤害序列只触发一次"的事件上,无论这一击是谁发的。
被收拢进来的发伤害路径:
mxt:damage(实体行为):伤害它所属的实体,没有归属,因此不吃元素关系——反噬、丹毒、环境 tick 这类"代价"用它是对的。damage_multiplier是另一回事:它是"这次施放值多少",只要这次伤害是由一次带水平的施放打出的就照样生效(功法越强,反噬越重),而不是由能力触发的那类伤害其上下文里本来就没有这个值。只有当它作用在别人身上(嵌在mxt:target_action、mxt:passenger_action之类里)时,才把施法者记成加害者、并按双方灵根结算克制。mxt:damage_target(双实体行为):把施加者的伤害打到目标身上,并把施加者记为加害者(击杀与仇恨因此归他),元素关系与damage_multiplier都参与。- 阵法的攻击模块
attack:按attribute_to_owner决定是否把阵主记为加害者;有damage_type就用它,没有就退回原版的玩家/生物攻击来源。 mxt:explode(实体行为):爆炸的每一次单体伤害都过第一层,并把施法者记为这场爆炸的起因。
由原版自己结算的伤害不过第一层:mxt:lightning 与方块版 mxt:explode 根本没有可归的攻击者,而 mxt:spawn_projectile 生成的投掷物虽然把施法者记为 owner,命中的伤害量仍由原版算(箭的威力不读数据包)。这三种都只受目标身上的第二层影响——投掷物那一类的优势是攻击者还在,所以元素适应照样能读出来。
没有声明
damage_type时,带归属的伤害使用原版的playerAttack/mobAttack来源:击杀会计到加害者头上,而原版只在受击者是玩家时按难度缩放这类来源的伤害。想要一个不随难度变化的固定来源,就自己在定义里写damage_type。