上一页:config.yml 详解 · 下一页:命令与权限
🗡️ 属性系统(原生属性 + 手把手自定义教程)
QCL 自带一套原生属性后端(native):不装任何属性插件(AttributePlus / MythicLib 等)也能用上攻击力、暴击、防御、闪避、元素伤害等全套属性与伤害结算。全生态(QI 物品 / QS 技能 / QC 职业 / QSt 强化 / QF 锻造)统一从 QCL 这一处读属性,分源叠加:物品、职业、宝石、套装各算一「源」,同名属性自动相加。
本页讲清三件事:属性是怎么组织的、有哪些内置属性、怎么从零写一个自己的属性(.yml + JS 脚本)。
一、先记住:三个文件各管一摊(最容易搞混的点)
| 文件 | 管什么 | 改完 |
|---|---|---|
attributes.yml(插件根目录) | 功能:新增属性、大类、伤害类型、JS 钩子、上下限、战力权重 | /qcl reload |
lang/zh_cn/attributes.yml | 显示:每个属性的显示名 display_name / 图标 prefix / 单位 suffix | /qcl reload 再 /qi refresh |
lang/attributes.yml(根目录) | 基准层:图标 prefix / 单位 suffix 在这里写一次,对所有属性通用 | 同上 |
elements.yml | 元素系统:每个元素自动生成「X伤害 / X增伤 / X抗性」三个属性 | /qcl reload |
⚠️ 想改属性在物品上显示的名字 / 加资源包图标 → 去
lang/那一层,不是attributes.yml!attributes.yml只管「这个属性存在、它怎么参与战斗」;长什么样在lang/。
显示配置放哪
- 显示名
display_name:在lang/zh_cn/attributes.yml。 - 图标
prefix/ 单位suffix:在根lang/attributes.yml设一次即可,对所有属性通用。
加载时根 lang/attributes.yml 为基准,lang/zh_cn/attributes.yml 逐字段覆盖它(显示名以后者为准,图标/单位沿用基准)。
二、内置属性总表
内置属性已写死在代码里,无需在 attributes.yml 声明就能直接用(物品 / 职业 / 怪物上写它的英文 key 即可)。/qcl attr list 可在游戏内查看全部。
📌 概率类属性一律是
0~1小数(0.2= 20%),不是整数百分比!显示层suffix含%时,数值会自动 ×100(存0.2→ 显示20%),你存的时候别自己换算。
| 大类 | 属性 key | 显示名 | 说明 |
|---|---|---|---|
| 基础 | attack_damage | 攻击力 | 映射原版近战攻击 |
| 基础 | attack_speed | 攻击速度 | 映射原版攻速 |
| 物理 | physical_damage | 物理增伤(%) | 放大物理伤害 |
| 物理 | physical_crit_rate | 物理暴击率(%) | max 1.0 |
| 物理 | physical_crit_damage | 物理爆伤(%) | 暴击倍率 |
| 物理 | armor_penetration | 护甲穿透 | |
| 物理 | projectile_damage | 投掷物增伤(%) | 弓弩/投掷 |
| 法术 | magic_attack / magic_damage | 法术伤害 / 法术增伤(%) | |
| 法术 | magic_crit_rate / magic_crit_damage | 法术暴击率(%) / 法术爆伤(%) | |
| 法术 | magic_penetration | 法术穿透 | |
| 技能 | skill_attack / skill_damage | 技能伤害 / 技能增伤(%) | |
| 技能 | skill_crit_rate / skill_crit_damage | 技能暴击率(%) / 技能爆伤(%) | |
| 真实 | true_attack / true_damage | 真实伤害 / 真伤增伤(%) | 穿透防御 |
| 环境 | pvp_damage / pve_damage | PVP/PVE 伤害(%) | 对玩家/对怪 |
| 环境 | pvp_defense / pve_defense | PVP/PVE 防御(%) | |
| 减伤 | defense | 防御 | 自带 defense.js:100 防御≈减伤 50% |
| 减伤 | damage_reduction | 伤害减免(%) | max 0.9,自带脚本 |
| 减伤 | dodge | 闪避率(%) | max 1.0,自带 dodge.js 几率免伤 |
| 减伤 | block_rate | 格挡率(%) | 自带 block.js |
| 减伤 | parry | 招架率(%) | 自带 parry.js |
| 减伤 | crit_resist | 暴击抗性(%) | max 1.0 |
| 减伤 | armor / armor_toughness | 护甲值 / 护甲韧性 | 映射原版 |
| 减伤 | knockback_resistance | 击退抗性(%) | 映射原版 |
| 资源 | health | 生命 | 映射原版 max_health |
| 资源 | health_regen | 生命恢复 | |
| 资源 | max_mana / mana_regen | 最大法力 / 法力恢复 | 供 QS/QC 法力池 |
| 资源 | max_stamina / stamina_regen | 最大耐力 / 耐力恢复 | |
| 通用 | movement_speed / max_absorption / luck | 移动速度 / 最大吸收 / 幸运 | 映射原版 |
| 杂项 | lifesteal | 生命偷取(%) | 自带 lifesteal.js |
| 杂项 | spell_vampirism / reflection | 法术吸血(%) / 伤害反弹(%) | |
| 杂项 | cooldown_reduction / exp_bonus / loot_bonus / money_bonus | 冷却缩减/经验/掉落/金币加成(%) | |
| 杂项 | attack_knockback | 攻击击退 | 映射原版 |
元素属性(火/水/雷/风/土/金/木/光…)由 elements.yml 驱动,每个元素自动生成 <元素>伤害 / <元素>增伤 / <元素>抗性,详见第六节。
查询命令
| 命令 | 作用 |
|---|---|
/qcl attr list | 列出全部已注册属性(按大类分组) |
/qcl attr show [玩家] | 查看玩家当前属性合计(分源后的总值) |
/qcl attr debug | 开关「命中伤害溯源」,每次打/被打都打印属性结算过程 |
/qcl attr book | 打开属性面板书本 |
/qcl mobattr <key> <值> | 给你看向的怪物设置属性(测试自定义属性的最快方式) |

三、手把手教程:写一个自己的属性
下面三个场景由易到难。全程不用改源码、不用重启,写完 /qcl reload 即生效。
场景 A:纯映射原版属性(最简单,零脚本)
想要一个「迅捷」属性,本质就是原版移动速度。只需在 attributes.yml 加:
attributes:
swiftness:
display: 迅捷
vanilla: movement_speed # 映射到原版移速,QCL 自动走原版 AttributeModifier/qcl reload → 完事。现在任何物品/职业写 swiftness 就能加移速。能映射的原版键:max_health movement_speed armor armor_toughness attack_speed attack_damage knockback_resistance luck max_absorption 等。
场景 B:带 JS 效果的属性(完整范例 · 荆棘反伤)
目标:「荆棘」——受到伤害时把一部分反弹给攻击者。需要 3 个文件 配合。
步骤 1️⃣ 写 JS 脚本
新建 plugins/QinhCoreLib/scripts/attributes/thorns.js:
// 触发钩子:on_damage_taken —— 玩家受到伤害时
// 可用变量:
// ctx.get("damage") 当前伤害值
// ctx.get("value") 玩家荆棘总值(0~1,0.2 = 反弹 20%)
// ctx.get("attacker") 攻击者实体(可能为 null,如摔落/火焰)
// qcl.damage(entity, amount) 对实体造成伤害
function onDamageTaken() {
var damage = ctx.get("damage");
var thorns = ctx.get("value");
var attacker = ctx.get("attacker");
if (thorns > 0 && damage > 0 && attacker) {
qcl.damage(attacker, damage * thorns); // 把伤害的 thorns 比例反弹回去
}
return damage; // 不改自己受到的伤害,原样返回
}💡 脚本必须
return一个数值(处理后的伤害)。on_damage_dealt/on_damage_taken的返回值会成为新的伤害;不想改伤害就return ctx.get("damage")。
步骤 2️⃣ 在 attributes.yml 注册它
attributes:
thorns:
display: 荆棘 # 显示名(也可只在 lang/ 配,见步骤 3)
category: 减伤 # /qcl attr list 的分组
order: 100 # 钩子执行顺序,越小越先;反伤/吸血建议靠后
hooks:
on_damage_taken: qinhcorelib:attributes/thorns.js:onDamageTaken引用格式固定为 qinhcorelib:attributes/<文件名>.js:<函数名>。
步骤 3️⃣ 配显示(可选,但建议)
在 lang/zh_cn/attributes.yml 加:
thorns:
display_name: "荆棘"
prefix: "" # 资源包 16px 贴图字符,想要图标就填这里
suffix: "%" # 带 % → 数值自动 ×100:存 0.2 显示 20%步骤 4️⃣ 重载
/qcl reload步骤 5️⃣ 把属性给到玩家测试
属性本身只是「定义」,要生效得有来源带上它。三种常见来源:
- QI 物品:物品
providers.ap.value的 JSON 里写英文 key,例如{"thorns":0.2}(20% 反弹)。 - QC 职业:
classes.yml的stats:块写thorns: { base: 0.1, per-level: 0.005 }。 - 快速测试(怪物):看向一只怪 →
/qcl mobattr thorns 0.5→ 让它打你,看是否反伤。
验证:/qcl attr show 看自己身上的 thorns 合计;/qcl attr debug 打开后每次受击会打印结算过程。

场景 C:覆盖内置属性(改名 / 加图标,英文 key 不变)
想把「物理暴击率」在物品上显示成「暴击」并挂个资源包图标——不用动 key,只在 attributes.yml 写你要改的字段,其余(大类/伤害类型/战力)自动继承内置:
attributes:
physical_crit_rate:
display: 暴击
prefix: "" # 你资源包里的 16px 贴图字符英文 key 永远是 physical_crit_rate(物品/职业照常用它),只是显示变了。这点和 MMOItems 一致。
四、attributes.yml 字段全表
| 字段 | 作用 | 默认 |
|---|---|---|
display | 显示名(也可在 lang/ 配,更推荐) | = key |
prefix | 显示名前缀(一般放资源包 16px 贴图字符 \uXXXX) | 无 |
category | 所属大类(用于 /qcl attr list 与属性 GUI 分组,可自定义新大类) | 杂项 |
vanilla | 映射的原版属性键(配了就走原版 AttributeModifier) | 无 |
type | 伤害类型 physical / magic / skill / true(大类增伤属性用) | 无 |
mitigation | 是否「减伤类」(true 时会被真实伤害穿透,如防御/伤害减免) | false |
combat-power | 战斗力权重(玩家战力 = Σ 属性值 × 权重) | 1.0 |
min / max | 数值上下限钳制(平衡工具,如概率类 max: 1.0) | 无限制 |
message | 触发时给玩家的战斗提示(支持 {damage} {value} 占位) | 无 |
order | 钩子执行顺序,越小越先(暴击=10,反伤/吸血建议 100) | |
hooks | JS 钩子:事件名 → 脚本引用 | 无 |
钩子事件表
| 事件名 | 触发时机 | 脚本返回值 |
|---|---|---|
on_damage_dealt | 玩家造成伤害时 | 新的伤害值 |
on_damage_taken | 玩家受到伤害时 | 新的伤害值 |
on_kill | 击杀实体时 | — |
on_tick | 每 20 tick(需 QI 在装备扫描末尾调 refreshEquipHooks) | — |
on_equip | 装备带该属性的物品时 | — |
on_unequip | 卸下时 | — |
脚本里可用的接口
ctx = 当前上下文,qcl = 工具 API:
| 调用 | 作用 |
|---|---|
ctx.get("damage") | 当前伤害值(已含暴击等前序钩子结果) |
ctx.get("value") | 当前属性的玩家总值(已分源聚合) |
ctx.get("attacker") / ctx.get("victim") | 攻击者 / 受害者实体(可能为 null) |
ctx.get("<任意属性key>") | 读玩家任意其它属性的值 |
ctx.set(key, value) | 写上下文值 |
qcl.heal(amount) | 治疗自己(自动钳到最大生命) |
qcl.damage(entity, amount) | 对实体造成伤害 |
qcl.addPotion(entity, "SLOWNESS", ticks, amplifier) | 施加药水效果 |
qcl.placeholder(text) / qcl.logInfo(msg) / qcl.itemGive(ref, amount) | 解析 PAPI / 打日志 / 发物品 |
内置范例脚本就在
scripts/attributes/:thorns.js(反伤)、lifesteal.js(吸血)、defense.js(减伤曲线)、dodge.js(闪避)、block.js、parry.js、damage_reduction.js、critical_rate.js。直接照抄改即可。
五、属性后端可切换
config.yml 的 attribute.backend:
| 值 | 含义 |
|---|---|
native(默认) | QCL 自带原生属性后端,无需任何属性插件 |
attributeplus | 改用 AttributePlus 接管属性(需装 AP,由 QinhItems 注册) |
auto | 有可用第三方属性后端则优先用它,否则回退 native |
全生态统一从这里读后端,无需各插件各配。改完 /qcl reload。
六、元素系统
elements.yml:每个元素自动生成 3 个属性(/qcl attr list 可见、物品/职业可声明):
<元素>伤害:flat,加在你攻击上的该元素伤害<元素>增伤:%,放大该元素伤害<元素>抗性:%,减免受到的该元素伤害(0~1)
结算公式:元素伤害 = Σ( <元素>伤害 × (1+<元素>增伤) × (1-目标<元素>抗性) × 相克倍率 )。元素伤害穿透物理防御/减伤,但被对应元素抗性减免,且吃闪避/格挡/招架。
相生相克(五行):restrains 列出「我克谁」。克之 ×restraint-bonus(默认 1.5),被克 ×(2-bonus),无关 ×1。目标的「本命元素」= 它抗性最高的那个元素。
restraint-bonus: 1.5
elements:
fire:
name: 火
color: "&c"
restrains: [metal] # 火克金
# ……可自由增删元素 / 改相克七、常见坑
- 概率写成了整数:暴击率/闪避要写
0~1小数(0.3= 30%),写30会被max: 1.0钳成 100%。 - 改显示名改错文件:显示名/图标在
lang/<语言>/attributes.yml,不是根attributes.yml。 - suffix 双重换算:
suffix含%已自动 ×100,别再自己乘。 - 脚本不返回值:
on_damage_*脚本必须return一个数;漏了会让伤害变undefined。 - 改了没生效:
attributes.yml/脚本改完要/qcl reload;物品显示要再/qi refresh重渲。 - 元素抗性方向:抗性是「减免受到的」,本命元素由抗性最高项决定——给怪堆高某元素抗性会让它「本命」变成那个元素。