主题
伤害类型与战斗管线
HNAttribute v1.6.0 的战斗层由四个核心概念组成:
- 属性 (Attribute) -- 提供数值,通过
channel+channel-role声明自己属于哪个伤害通道 - Stage -- 独立的计算步骤,定义公式和终止语义
- Pipeline -- 按攻击方式编排 Stage 的执行顺序
- DamageType -- 伤害的显示身份(名称、颜色)+ 可选的通道减伤公式
一次攻击的完整链路:属性提供数值 -> Pipeline 按顺序执行 Stage -> 每个伤害通道按 DamageType 的 resist-formula 结算减伤 -> 输出最终伤害。
配置目录结构
text
plugins/HNAttribute/
├── attributes/ # 属性定义(含 channel / channel-role)
│ ├── base.yml
│ ├── combat.yml
│ └── element.yml
├── stages/ # Stage 定义(独立计算步骤)
│ ├── hit.yml
│ ├── dodge.yml
│ ├── crit.yml
│ ├── block.yml
│ ├── collect.yml
│ ├── damage.yml
│ ├── resist.yml
│ ├── crit_damage.yml
│ ├── lifesteal.yml
│ └── thorns.yml
├── pipelines/ # 管线定义(按攻击方式编排)
│ ├── melee.yml
│ ├── ranged.yml
│ ├── spell.yml
│ └── dot.yml
└── damage_types/ # 伤害类型(显示 + 可选 resist-formula)
├── physical.yml
└── magic.yml属性与伤害通道声明
属性本身只是数值来源。要让一个属性参与伤害通道结算,需要在属性定义中声明 channel 和 channel-role。
yml
# 攻击力属于 physical 通道,角色是 damage(伤害来源)
attack_damage:
display: "&c攻击力"
names: ["攻击力", "物理伤害"]
default: 1.0
channel: physical
channel-role: damage
# 防御力属于 physical 通道,角色是 resist(抗性)
defense:
display: "&9防御力"
names: ["防御力", "防御"]
default: 0.0
channel: physical
channel-role: resistchannel-role 的可选值:
| channel-role | 含义 | 示例 |
|---|---|---|
damage | 伤害来源值 | attack_damage, fire_damage |
resist | 抗性值 | defense, fire_resistance |
penetration_flat | 固定穿透 | physical_penetration_flat |
penetration_rate | 百分比穿透 | physical_penetration_rate |
当 collect_channels Stage 执行时,系统会自动扫描攻击者身上所有 channel-role=damage 且值 > 0 的属性,收集出本次攻击涉及的伤害通道。
一次攻击可以产出多个伤害通道(混合伤害)。例如一把"火焰剑"同时有 attack_damage(physical 通道)和 fire_damage(fire 通道),近战攻击时会同时产出物理伤害和火焰伤害。
Stage 五种类型
Stage 是独立的计算步骤,定义在 stages/*.yml 中。
1. boolean -- 判定型
返回真/假,用于命中、闪避、暴击、格挡等判定。
yml
id: hit
type: boolean
stop_on_false: true
terminate_outcome: miss
description: "命中判定"
formula: |-
def diff = self_accuracy - target_dodge
return diff >= random(0, 1) ? 1 : 0关键字段:
stop_on_false-- 返回 false 时终止管线stop_on_true-- 返回 true 时终止管线terminate_outcome-- 终止时的结果标记(miss / dodge / block / cancel)
2. value -- 数值型
产出一个数值结果,用于基础伤害、吸血值、反伤值等。
yml
id: damage
type: value
description: "基础伤害计算"
formula: |-
if (explicit_damage) {
return input_damage
}
return Math.max(0, self_attack_damage)3. modifier -- 修饰型
基于前面某个 Stage 的结果做修正,通过 depends_on 指定修改目标。
yml
id: crit_damage
type: modifier
depends_on:
- damage
description: "暴击伤害修正"
formula: |-
if (!crit) {
return damage
}
return damage * Math.max(1, self_crit_multiplier / 100)depends_on 对 modifier 有两层含义:
- 声明依赖:这个 Stage 需要
damage先执行 - 回写目标:计算结果会覆盖回
damage
4. collect_channels -- 通道收集
自动扫描攻击者属性,收集所有 channel-role=damage 且值 > 0 的伤害通道。
yml
id: collect
type: collect_channels
description: "收集伤害通道"如果技能/API 已经预设了通道,则直接使用预设值。
5. per_channel -- 按通道执行
对每个伤害通道分别执行公式。系统会自动注入通道相关变量。
yml
id: resist
type: per_channel
description: "按通道减伤"
formula: |-
effective_resist = max(0, channel_resist - channel_penetration_flat) * (1 - channel_penetration_rate / 100)
return max(0, channel_value - effective_resist)per_channel 自动注入的变量:
| 变量 | 含义 |
|---|---|
channel_type | 当前通道类型(如 physical, fire) |
channel_value | 当前通道的伤害值 |
channel_resist | 当前通道的抗性值 |
channel_penetration_flat | 当前通道的固定穿透 |
channel_penetration_rate | 当前通道的百分比穿透 |
如果对应的 DamageType 配置了 resist-formula,则优先使用 DamageType 的公式替代默认公式。
Pipeline -- 按攻击方式编排
Pipeline 定义在 pipelines/*.yml 中,每个 Pipeline 代表一种攻击方式。
yml
# 近战攻击管线
id: melee
description: "近战攻击"
stages:
- hit
- dodge
- crit
- block
- collect
- damage
- resist
- crit_damage
- lifesteal
- thorns默认管线:
| Pipeline | 用途 | 特点 |
|---|---|---|
melee | 近战攻击 | 完整流程,含格挡 |
ranged | 远程射击 | 无格挡、无反伤 |
spell | 法术释放 | 无格挡,含反伤 |
dot | 持续伤害 | 只做通道收集和减伤 |
Stage 的执行顺序由 Pipeline 的 stages 列表决定,不是文件名排序。
DamageType -- 显示 + 可选减伤公式
DamageType 定义在 damage_types/*.yml 中,负责两件事:
- 伤害的显示身份(名称、颜色、格式)
- 可选的通道专属减伤公式(
resist-formula)
yml
id: physical
display-order: 0
display-name: "伤害"
display: "{color}{value}"
color: "&f"
special-color: "&f&l"
description: "物理伤害"
# 可选:自定义减伤公式
# 如果配置了,per_channel Stage 会优先使用这个公式
resist-formula: |-
effective_defense = max(0, channel_resist - channel_penetration_flat) * (1 - channel_penetration_rate / 100)
return max(0, channel_value - effective_defense)DamageType 不负责编排 Stage,不负责绑定属性。它只管"这种伤害长什么样"和"这种伤害怎么减伤"。
完整执行示例:火焰剑近战攻击
假设玩家装备了一把火焰剑,属性如下:
attack_damage: 100(physical 通道)fire_damage: 50(fire 通道)
目标怪物属性:
defense: 30(physical 通道抗性)fire_resistance: 20(fire 通道抗性)
攻击时使用 melee 管线,执行流程:
- hit -- 命中判定,通过
- dodge -- 闪避判定,未闪避
- crit -- 暴击判定,未暴击
- block -- 格挡判定,未格挡
- collect -- 收集伤害通道,发现 physical(100) 和 fire(50)
- damage -- 基础伤害计算,取
attack_damage = 100 - resist -- 按通道减伤:
- physical 通道:使用 physical.yml 的 resist-formula,
100 - 30 = 70 - fire 通道:使用 fire 的 resist-formula(如果有),
50 - 20 = 30
- physical 通道:使用 physical.yml 的 resist-formula,
- crit_damage -- 未暴击,跳过
- lifesteal -- 计算吸血
- thorns -- 计算反伤
最终伤害:物理 70 + 火焰 30 = 100,显示层分别用各自的颜色展示。
新增伤害类型的步骤
只需两步:
第一步:定义属性
在 attributes/*.yml 中注册伤害和抗性属性,声明 channel 和 channel-role:
yml
thunder_damage:
display: "&e雷电伤害"
names: ["雷电伤害", "雷伤"]
default: 0.0
channel: thunder
channel-role: damage
thunder_resistance:
display: "&e雷电抗性"
names: ["雷电抗性", "雷抗"]
default: 0.0
channel: thunder
channel-role: resist第二步:定义显示
在 damage_types/thunder.yml 中定义显示和可选减伤公式:
yml
id: thunder
display-order: 20
display-name: "雷电伤害"
display: "{color}{value}"
color: "&e"
special-color: "&e&l"
description: "雷电伤害"
# 可选:自定义减伤公式
resist-formula: |-
effective_resist = max(0, channel_resist - channel_penetration_flat) * (1 - channel_penetration_rate / 100)
return max(0, channel_value * (1 - min(effective_resist, 100) / 100))不需要写新的 Stage,不需要改 Pipeline。collect_channels 会自动发现 thunder 通道,per_channel 的 resist Stage 会自动使用 thunder 的 resist-formula。
技能调用示例
MythicMobs 技能
yml
# 指定管线和伤害类型
- hna-damage{a=100;pp=true;pipeline=spell;dt=thunder;st=skill} @target
# 不指定管线,使用默认
- hna-damage{a=100;pp=true;dt=thunder} @target参数说明
| 参数 | 含义 |
|---|---|
a / amount | 伤害数值 |
pp / pipeline | 是否进入管线结算(true/false),或指定管线 ID |
dt / damage-type | 伤害类型 ID |
st / source-type | 来源类型(basic / skill) |
重点总结
- 属性通过
channel+channel-role声明伤害通道归属,不再需要在 Stage 或 DamageType 中硬编码属性名 - Pipeline 按攻击方式编排 Stage,不按伤害类型编排
- DamageType 只负责显示和可选的减伤公式,不负责 Stage 编排
collect_channels自动发现伤害通道,per_channel自动按通道执行减伤- 新增伤害类型只需定义属性 + 定义显示,不需要写 Stage 或改 Pipeline
