Skip to content

技能定义

技能定义文件存放在 skills/ 目录下,每个文件定义一个技能。技能定义描述的是"这个技能叫什么、冷却多久、消耗什么资源、对应哪个 MythicMobs 技能",而不是技能的实际效果——效果由 MythicMobs 那边配置。

完整 YAML 格式

yaml
# skills/example_fireball.yml

# 技能唯一标识
id: "fireball"

# 显示名称(支持 MiniMessage)
display_name: "<red>火球术"

# 技能描述
description:
  - "<gray>向前方发射一颗火球"
  - "<gray>造成范围伤害"

# GUI 中显示的图标材质
icon_material: "FIRE_CHARGE"

# 对应的 MythicMobs 技能 ID
mythic_skill: "Fireball"

# 技能冷却时间(tick,20 tick = 1 秒)
cooldown_ticks: 100

# 全局冷却时间(tick)—— 释放此技能后所有技能共享的冷却
global_cooldown_ticks: 20

# Lore 别名 —— 用于从装备 Lore 中匹配解锁此技能
lore_aliases:
  - "火球术"
  - "Fireball"

# GUI 分类标签
ui_category: "攻击"

# GUI 排序权重
sort_order: 1

# 技能激活类型:active(主动,默认)/ passive(被动)
trigger_type: "active"

# 是否启用
enabled: true

# ============================================================
# 技能参数 (Skill Parameters)
# 定义技能的数值参数,会随等级变化并注入到 MythicMobs
# ============================================================
skill_parameters:
  # 数值型参数:用公式计算,{level} 会被替换为当前技能等级
  damage:
    type: "expression"
    expression: "{base_damage} + {level_bonus}"
    variables:
      base_damage:
        type: "constant"
        value: 18
      level_bonus:
        type: "expression"
        expression: "({level} - 1) * 4"
    decimals: 1        # 保留 1 位小数
    min: 0             # 最小值

  # 另一个数值参数
  radius:
    type: "expression"
    expression: "2 + floor(({level} - 1) / 3) * 0.5"
    decimals: 2
    min: 1

  # 点燃时长参数
  ignite_ticks:
    type: "expression"
    expression: "40 + ({level} - 1) * 6"
    decimals: 0
    min: 20

  # 字符串型参数:直接传递文本
  element:
    type: "string"
    value: "fire"

  # 带变量替换的字符串参数
  element_label:
    type: "string"
    value: "fire_lv_{level}"

  # 布尔型参数:可以用比较表达式
  empowered:
    type: "boolean"
    expression: "{level} >= 5 && {has_target} == 1"
    default: false

  # 随机文本参数:从候选行中随机抽取
  random_bonus_lines:
    type: "random_text"
    rolls: "{bonus_rolls}"
    allow_duplicates: false
    variables:
      bonus_rolls:
        type: "constant"
        value: 2
      物理攻击:
        type: "range"
        min: 2
        max: 6
      物理防御:
        type: "uniform"
        min: 1
        max: 4
    lines:
      - "物理攻击: +{物理攻击}"
      - "物理防御: +{物理防御}"

# ============================================================
# 升级配置 (Upgrade)
# 定义技能的升级规则、费用和成功率
# ============================================================
upgrade:
  enabled: true
  max_level: 10
  failure_penalty: "none"      # none = 失败不降级;downgrade = 失败降一级

  # 升级费用(全局默认)
  economy:
    enabled: true
    currencies:
      - provider: "vault"
        base_cost: 1200
        cost_formula: "{base_cost} * {target_level}"
        display_name: "<gold>金币</gold>"

  # 成功率表(键 = 目标等级)
  success_rates:
    2: 100.0
    3: 95.0
    5: 80.0
    8: 60.0
    10: 40.0

  # 特定等级的额外配置
  levels:
    5:
      materials:
        - item: "minecraft-blaze_rod"
          amount: 1
      success_actions:
        - "sendmessage text=<yellow>火球术达到 V 级!"
    10:
      economy:
        enabled: true
        currencies:
          - provider: "vault"
            base_cost: 50000
            cost_formula: "{base_cost}"
            display_name: "<gold>金币</gold>"
      materials:
        - item: "minecraft-nether_star"
          amount: 1

# ============================================================
# 资源消耗 (Resource Costs)
# 施法前检查并消耗的资源列表
# ============================================================
resource_costs:
  # 本地资源消耗
  - type: "local-resource"
    target_id: "mana"
    amount: 30
    operation: "CONSUME"       # CONSUME = 检查并扣除, CHECK = 仅检查
    failure_message: "<red>法力不足!需要 30 点法力。"

  # EmakiAttribute 资源消耗(需要 EA 软依赖)
  - type: "ea-resource"
    target_id: "mp"
    amount: 20
    operation: "CONSUME"
    failure_message: "<red>MP 不足!"

  # EmakiAttribute 属性检查(仅检查,不消耗)
  - type: "ea-attribute-check"
    target_id: "intelligence"
    amount: 50
    operation: "CHECK"
    failure_message: "<red>智力不足!需要 50 点智力。"

关于 global_cooldown_ticks:这个冷却是"释放此技能后,所有技能都要等的时间"。和 cooldown_ticks(只影响这个技能本身)不同,它影响的是全局。典型用法是防止玩家瞬间连放多个不同技能。

关于 lore_aliases:这是 Lore 解锁机制的关键字段。系统扫描装备 Lore 时,只要发现包含列表中任意一个文本,就认为这件装备解锁了这个技能。支持多个别名是为了兼容不同语言或不同写法。

资源消耗类型

类型说明
local-resource本地资源(由 Skills 自身管理,如法力值)
ea-resourceEmakiAttribute 资源(如 MP、SP),需要 EA 软依赖
ea-attribute-checkEmakiAttribute 属性检查(只读,不消耗),用于设置施法门槛

三种类型可以混用。比如一个技能可以同时消耗本地法力和 EA 的 MP,还要求智力达到 50。

operation 操作类型

操作说明
CONSUME检查资源是否充足,充足则扣除
CHECK仅检查资源是否充足,不扣除。适合用于属性门槛检查

本地资源定义

本地资源是 Skills 自己管理的资源系统,独立于 EmakiAttribute。最典型的用法就是法力值。定义文件存放在 resources/ 目录下。

yaml
# resources/mana.yml

# 资源唯一标识
id: "mana"

# 显示名称
display_name: "<blue>法力"

# 最大值
max: 100

# 默认当前值
default_current: 100

# 自然恢复量
regen_amount: 5

# 恢复间隔(tick)
regen_interval_ticks: 40

# 最小值钳制
clamp_min: 0

# 最大值钳制(-1 = 使用 max)
clamp_max: -1

字段说明

字段类型说明
idstring资源唯一标识
display_namestring显示名称
maxdouble最大值
default_currentdouble玩家首次加入时的初始值
regen_amountdouble每次恢复的量
regen_interval_ticksint恢复间隔(tick),40 tick = 2 秒
clamp_mindouble最小值下限,资源不会低于这个值
clamp_maxdouble最大值上限,-1 表示使用 max 字段的值

为什么有 clamp_maxmax 两个字段?max 是资源的标准上限,clamp_max 是硬上限。如果某些效果临时提升了资源上限超过 maxclamp_max 可以作为最终的天花板。设为 -1 就是不额外限制。


默认技能

技能 ID名称类型MythicMobs 技能冷却消耗
fireball火球术主动Fireball5 秒30 法力
attack_passive命中回响被动ExampleAttackPassive2 秒

被动技能定义

被动技能通过 trigger_type: "passive" 标记,并用 passive_triggers 列表声明触发事件。被动技能不需要施法模式,不占用槽位,由游戏事件自动触发。

yaml
# skills/example_attack_passive.yml

id: attack_passive
display_name: "<gradient:#FFD166:#EF476F>命中回响</gradient>"
description:
  - "<gray>被动技能示例:命中实体时自动触发</gray>"
  - "<gray>玩家不可在 GUI 中修改此技能的触发器</gray>"
icon_material: "ECHO_SHARD"
mythic_skill: "ExampleAttackPassive"

# 标记为被动技能
trigger_type: "passive"

# 被动触发器列表(可以声明多个)
passive_triggers:
  - "attack"

cooldown_ticks: 40
global_cooldown_ticks: 0
lore_aliases:
  - "命中回响"
ui_category: "passive"
sort_order: 100
enabled: true
resource_costs: []

主动 vs 被动对比

维度主动技能被动技能
trigger_typeactive(默认)passive
passive_triggers必须声明触发器 ID 列表
触发方式玩家进入施法模式后按键游戏事件自动触发
施法模式必须在施法模式中不需要
槽位绑定需要装备到槽位 + 绑定触发器不使用槽位
GUI 展示出现在技能池,可装备不出现在技能池
触发器选择玩家可在 GUI 中自由选择固定写在 YAML,不可修改
冷却/资源检查✅(与主动技能相同)

被动触发器 ID 列表

触发器 ID说明MythicMobs target
attack攻击命中实体被攻击实体
damaged_by_entity被实体伤害攻击者
damaged受到任意伤害
death玩家死亡
kill_entity击杀非玩家实体被杀实体
kill_player击杀玩家被杀玩家
shoot_bow射出弓箭
arrow_hit箭矢命中实体命中实体
arrow_land箭矢落地无(传递落点位置)
shoot_trident掷出三叉戟
trident_hit三叉戟命中实体命中实体
trident_land三叉戟落地无(传递落点位置)
break_block破坏方块无(传递方块位置)
place_block放置方块无(传递方块位置)
drop_item丢弃物品掉落物实体
shift_drop_itemShift+丢弃物品掉落物实体
swap_items交换主副手
shift_swap_itemsShift+交换主副手
login玩家登录
sneak开始潜行
teleport传送无(传递目标位置)
timer定时触发

timer 触发器的检查间隔由 passive_trigger_settings.timer_interval_ticks 配置,默认 20 tick(1 秒)。

MythicMobs target 传递

被动技能触发时,系统会把事件中的目标实体和位置传递给 MythicMobs。比如 attack 触发器会把被攻击的实体作为 @targetarrow_hit 会把被命中的实体作为 @target。没有目标实体的触发器(如 timerdeath)会以玩家自身为施法者,不传递额外目标。

技能参数系统

技能参数让你可以在 YAML 里定义技能的数值(比如伤害、范围、持续时间),这些数值会随着技能等级自动变化,并且在释放技能时传递给 MythicMobs。

简单来说:你在技能定义里写好公式,系统会根据玩家的技能等级算出实际数值,然后 MythicMobs 那边就能直接用这些数值。

参数类型

类型YAML 写法说明
数值number(默认)用数学公式计算,支持 min/max 限制和小数位控制
表达式expressionexprformulanumber 等价,显式声明使用表达式求值
字符串stringtext直接传递文本,支持 {变量} 替换
布尔booleanbool真/假值,支持比较表达式(如 {level} >= 3
随机文本random_textrandom_text_linesrandom_lines从候选行列表中随机抽取文本,适合随机词条生成

参数字段说明

字段必填类型默认值说明
typestring"number"参数类型
formulastring数学公式,优先于 value。可用 {level} 等变量
expressionstringformula 等价,type: expression 时推荐使用此字段名
valuestring静态值。formula/expression 为空时使用
decimalsint0小数位数(仅 number/expression 类型有效,0 = 取整)
mindouble最小值限制(仅 number/expression 类型)
maxdouble最大值限制(仅 number/expression 类型)
defaultstring""formulavalue 都为空时的兜底值
variablesmap嵌套变量定义,每个变量支持数值配置类型(constant/range/expression 等)

random_text 专用字段

字段必填类型默认值说明
rolls数值配置1抽取次数,支持常量、range、expression 等
allow_duplicatesbooleanfalse是否允许重复抽取同一行
lineslist候选文本行列表(别名:valuesoptionstexts
variablesmap局部变量定义
separatorstring\n多行合并分隔符

公式中可用的变量

变量说明
{level}玩家当前技能等级(最常用)
{max_level}技能最大等级
{target_level}升级目标等级(升级预览时使用)
{player_level}玩家的 Minecraft 经验等级
{player_health}玩家当前血量
{player_max_health}玩家最大血量
{sneaking}是否潜行(0 或 1)
{has_target}是否有目标实体(0 或 1)
{skill_id}技能 ID

公式支持基本数学运算(+-*/)和 floor() 等函数。

简写形式

如果参数只是一个固定的字符串值,可以直接写成一行:

yaml
skill_parameters:
  element: "fire"    # 等价于 type: string, value: "fire"

参数如何传递给 MythicMobs

释放技能时,所有参数会自动注入到 MythicMobs 的技能变量中。在 MythicMobs 技能配置里用 <skill.var.参数名> 来引用:

yaml
# MythicMobs 技能配置
ExampleFireball:
  Skills:
  - damage{amount=<skill.var.damage>} @target
  - particles{particle=flame;amount=20;radius=<skill.var.radius>} @self

系统还会自动注入以下内置变量(不需要你手动定义):

变量说明
<skill.var.emaki_skill_id>技能 ID
<skill.var.emaki_skill_level>当前技能等级
<skill.var.emaki_trigger_id>触发器 ID
<skill.var.emaki_is_passive>是否被动技能(0 或 1)
<skill.var.emaki_has_target>是否有目标实体(0 或 1)

注意

参数 ID 不能以 emaki_ 开头,这个前缀是系统保留的。如果你定义了 emaki_ 开头的参数,加载时会被跳过。

嵌套变量

expression 类型的参数支持通过 variables 字段定义嵌套变量。每个嵌套变量本身也是一个数值配置对象,支持 constantrangeuniformexpression 等类型:

yaml
damage:
  type: "expression"
  expression: "{base_damage} + {level_bonus}"
  variables:
    base_damage:
      type: "constant"
      value: 18
    level_bonus:
      type: "expression"
      expression: "({level} - 1) * 4"

嵌套变量会在求值前先被解析为数值,然后替换到主表达式中。这样可以把复杂的公式拆分成更易读的部分。

random_text 参数类型

random_text 类型用于从候选行列表中随机抽取文本行,适合生成随机词条、随机描述等。抽取结果会作为字符串传递给 MythicMobs。

yaml
random_bonus_lines:
  type: "random_text"
  rolls: "{bonus_rolls}"           # 抽取次数(支持数值配置)
  allow_duplicates: false           # 不允许重复
  variables:
    bonus_rolls:
      type: "constant"
      value: 2
    物理攻击:
      type: "range"
      min: 2
      max: 6
  lines:
    - "物理攻击: +{物理攻击}"
    - "物理防御: +{物理防御}"

random_text 参数的求值结果是多行文本用分隔符(默认 \n)拼接后的字符串。variables 中定义的局部变量会在每行文本中进行替换。

详细的字段说明参见表达式引擎 — 随机文本


技能升级系统

技能升级让玩家可以花费金币和材料来提升技能等级,等级越高参数越强。

升级配置字段说明

字段必填类型默认值说明
enabledbooleanfalse是否开启升级功能
max_levelint1最大等级。设为 1 表示不可升级
failure_penaltystring"none"升级失败的惩罚:none = 不降级;downgrade = 降一级

经济费用配置

yaml
upgrade:
  economy:
    enabled: true
    currencies:
      - provider: "vault"         # 经济提供者:vault / excellenteconomy / auto
        currency_id: ""           # 货币 ID(Vault 留空)
        base_cost: 1200           # 基础费用
        cost_formula: "{base_cost} * {target_level}"  # 费用公式
        display_name: "<gold>金币</gold>"              # 显示名称

cost_formula 中可用的变量和技能参数公式相同({level}{target_level}{base_cost} 等)。

成功率配置

yaml
upgrade:
  success_rates:
    2: 100.0     # 升到 2 级:100% 成功
    5: 80.0      # 升到 5 级:80% 成功
    10: 40.0     # 升到 10 级:40% 成功

键是目标等级,值是成功率百分比。没有配置的等级默认 100% 成功。

特定等级配置

你可以为某些关键等级设置额外的材料需求、费用覆盖、参数覆盖和动作:

yaml
upgrade:
  levels:
    5:
      # 升到 5 级需要额外材料
      materials:
        - item: "minecraft-blaze_rod"    # 物品来源(和动作系统的 source 格式相同)
          amount: 1                      # 需要数量
          optional: false                # 是否可选(可选材料不放也能升级)
          protection: false              # 是否为保护材料

      # 覆盖这个等级的经济费用(不写就用全局的)
      economy:
        enabled: true
        currencies:
          - provider: "vault"
            base_cost: 20000
            cost_formula: "{base_cost}"
            display_name: "<gold>金币</gold>"

      # 覆盖这个等级的成功率
      success_rate: 40.0

      # 覆盖这个等级的参数定义(比如到了 5 级范围固定为 3.5)
      parameters:
        radius:
          type: "number"
          value: 3.5
          decimals: 2

      # 升级成功/失败时执行的动作
      success_actions:
        - "sendmessage text=<yellow>达到 V 级!"
        - "playsound sound=entity.player.levelup volume=1.0 pitch=1.5"
      failure_actions:
        - "sendmessage text=<red>升级失败了..."

升级流程

玩家执行 /eskills upgrade <技能ID> 后,系统会按以下步骤处理:

1. 检查技能是否已解锁(没解锁不能升级)
2. 检查是否已满级
3. 计算目标等级 = 当前等级 + 1
4. 检查金币是否充足
5. 检查背包材料是否充足
6. 扣除金币和材料
7. 按成功率随机判定
   ├─ 成功 → 等级 +1,执行 success_actions
   └─ 失败 → 根据 failure_penalty 决定是否降级,执行 failure_actions

如果扣费过程中出了问题(比如扣了金币但材料不够),系统会自动退还已扣除的所有费用。

升级命令

命令权限说明
/eskills upgrade <技能ID>emakiskills.use玩家自助升级已解锁的技能
/eskills level get <玩家> <技能>emakiskills.admin查询玩家的技能等级
/eskills level set <玩家> <技能> <等级>emakiskills.admin直接设置玩家的技能等级
/eskills level add <玩家> <技能> <数值>emakiskills.admin增加或减少玩家的技能等级

GUI 中的等级和参数展示

技能 GUI 中,每个技能图标的 Lore 会自动显示当前等级和参数预览:

等级: 3/10
参数预览:
 - damage: 26.0
 - radius: 2.5
 - can_ignite: true

最多显示 3 个参数。以 emaki_ 开头的内置参数不会显示。


默认资源

资源 ID名称最大值恢复
mana法力1005/2秒

技能解锁机制

技能不是直接"学会"的,而是通过装备来解锁。玩家穿上带有技能标记的装备,技能就可用;脱下装备,技能就从可用池中移除。有两种标记方式:

1. PDC 解锁

装备的 PersistentDataContainer 中存储技能 ID 列表:

PDC Key: emaki_skills:item.skills.ids
Value: "fireball;ice_bolt;heal"

值是分号分隔的技能 ID 字符串。当玩家装备含有此 PDC 数据的物品时,对应技能自动解锁。卸下装备后技能从解锁池中移除。

这种方式适合通过插件精确控制装备带哪些技能。EmakiForge、EmakiStrengthen、EmakiGem 三个模块都支持在配方/星级/宝石定义中声明 skill 效果,锻造/强化/镶嵌完成后会自动通过 ReflectiveSkillPdcGateway 把技能 ID 写入产物的 PDC——不需要手动操作。

2. Lore 解锁

装备 Lore 中包含技能定义的 lore_aliases 中的任意文本时,该技能解锁:

yaml
# 技能定义
lore_aliases:
  - "火球术"

# 装备 Lore 中包含 "火球术" → 技能解锁

Lore 解锁更灵活,不需要修改物品的 PDC,只要 Lore 里有对应文本就行。适合和 MMOItems、ItemsAdder 等物品插件配合使用。

提示

两种解锁方式可以同时使用。EquipmentSkillCollector 会同时扫描 PDC 和 Lore,合并所有解锁的技能。如果同一个技能被多件装备同时解锁,也只会出现一次。


PlayerSkillProfile 数据模型

每个玩家的技能档案存储在 data/{uuid}.yml 中,记录了施法模式状态、槽位绑定、本地资源、冷却计时和技能等级:

yaml
# data/xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx.yml
cast_mode_enabled: true
bindings:
  - slot: 0
    skill_id: "fireball"
    trigger_id: "right_click"
  - slot: 1
    skill_id: "ice_bolt"
    trigger_id: "shift_right_click"
  - slot: 2
    skill_id: null
    trigger_id: null
local_resources:
  mana:
    current: 75.0
timing:
  last_cast_time_ms: 1700000000000
  forced_delay_until_ms: 0
  global_cooldown_until_ms: 1700000001000
  skill_cooldowns:
    fireball: 1700000005000
skill_levels:
  fireball: 3
  ice_bolt: 1

Released under the GPL-3.0 License