English
Skill Definitions
Skill definition files spell out what each field means, its default, and which values it accepts. Skill files live in plugins/EmakiSkills/skills/*.yml. One skill per file: you only describe what the skill is (name, cooldown, costs, upgrades) and hand the actual effect to the native script system or MythicMobs. Local resource definitions live in plugins/EmakiSkills/resources/*.yml
Loading rules
- One file loads exactly one skill. A blank
idmakes the whole file be skipped and recorded as a loader issue - To park a skill temporarily, set
enabled: false; it never enters the registry, which is the same as the skill not existing - Skill ids are normalized to lower case; ids inside list fields get the same treatment, with
-folded to_ - List fields accept alias keys (see the table); when both are present their entries are merged in order and de-duplicated
Top-level fields
yaml
id: "fireball"
enabled: true
display_name: "<red>Fireball"
description:
- "<gray>Hurls a fireball forwards."
icon_material: "fire_charge"
mythic_skill: "EmakiFireball"
trigger_type: "active"
cooldown_ticks: 100
global_cooldown_ticks: 20| Field | Type | Required | Default | Values | Description |
|---|---|---|---|---|---|
id | string | Yes | — | Non-blank; lower-cased | Unique skill id. A blank value skips the whole file |
enabled | boolean | No | true | true / false | Whether the skill is loaded. false means the skill does not exist |
display_name | string | No | id | Any MiniMessage text | Display name used by the GUI, action bar, and the %skill% placeholder in feedback |
description | list<\string> | No | [] | — | Description lines shown in the GUI |
icon_material | string | No | "" | Bukkit Material name (lower-cased) | GUI icon material. When blank the slot config or a built-in fallback material is used |
mythic_skill | string | No | "" | MythicMobs skill id | The MythicMobs skill run in mythic / hybrid mode, and the effect used for non-player casters |
trigger_type | string | No | "active" | active / passive (anything else counts as active) | Active or passive skill |
passive_triggers | list<\string> | No | [] | Registered passive trigger ids | Event sources of a passive skill. Unregistered ids are dropped at dispatch time without an error |
cron_expression | string | No | "" | Quartz cron expression | When non-blank, a cron_<id> passive trigger is registered and added to passive_triggers; see CoreLib expressions - Cron |
cron_max_executions | integer | No | 0 | ≥ 0, negatives become 0 | Total firing cap for the cron trigger; 0 means unlimited |
variables | map | No | {} | Keys not starting with emaki_ | Runtime variable block; see Variable types |
script | map | No | disabled | — | Native script block; see Native scripting |
upgrade | map | No | disabled | — | Upgrade rules, documented below |
cooldown_ticks | integer | No | 0 | ≥ 0, negatives become 0 | Per-skill cooldown in ticks (20 ticks = 1 second) |
global_cooldown_ticks | integer | No | 0 | ≥ 0, negatives become 0 | Global cooldown in ticks, shared by every skill after a cast |
resource_costs | list<\map> | No | [] | — | Resource costs or checks; entry fields below |
lore_aliases | list<\string> | No | [] | — | Aliases matched when reading skills from equipment lore |
pdc_skill_id | string | No | id | — | ID used when reading the skill from equipment PDC |
tags | list<\string> | No | [] | Limited when matching skill_tags.equip_limits | Skill tags used for equip-count limits and category filtering |
tab_tags | list<\string> | No | [] | Alias tabTags | GUI tab tags |
required_skills | list<\string> | No | [] | Alias dependencies | Skill ids that must already be equipped before this one can be equipped |
conflicting_skills | list<\string> | No | [] | Alias conflicts | Skill ids that cannot be equipped together with this one |
ui_category | string | No | "default" | — | GUI category |
sort_order | integer | No | 0 | Lower sorts first | GUI ordering |
show_in_slots | boolean | No | true | true / false | Whether the skill may appear in the player's active slot selection list. Equipment-forced trigger skills usually set this to false |
condition | map | No | none | — | Cast (and upgrade) condition block, below |
The condition block
Casting and upgrading share the same condition block. The condition text is rendered through PlaceholderAPI before evaluation
yaml
condition:
type: "all_of"
entries:
- "%player_level% >= 5"
- "%emakiskills_level_fireball% >= 2"| Field | Type | Required | Default | Values | Description |
|---|---|---|---|---|---|
condition | map | No | none | — | Must be a mapping node; without entries the block counts as no condition at all |
condition.type | string | No | all_of | all_of, any_of, none_of, at_least, exactly | How multiple conditions combine |
condition.entries | list<\string> | No | [] | Expression strings | Condition expressions; omitting the key leaves the whole block empty |
condition.required_count | integer | No | 0 | ≥ 0 | Match threshold for the at_least / exactly combine modes |
condition.invalid_as_failure | boolean | No | true | true / false | Read by the shared condition parser; EmakiSkills' cast and upgrade paths always treat an unparseable expression as "not passed" |
condition.on_pass.actions / condition.on_fail.actions | list<\string> | No | [] | — | Read by the shared condition parser; EmakiSkills skills do not use them |
condition.on_fail.block_output / condition.on_fail.message | boolean / string | No | false / "" | — | Same as above; not used by EmakiSkills skills |
An unparseable condition counts as "not passed": the skill is not cast and the upgrade is rejected. The cast failure key is cast.condition_not_met and the upgrade failure key is upgrade.condition_not_met
Condition text is handed to PlaceholderAPI before evaluation, so every %...% in it must be resolvable by an installed expansion (for example %emakiskills_level_fireball%). An unresolvable placeholder reaches the expression as-is and, per the rule above, counts as not passed
Variables and scripts
variables: runtime values; syntax and types are in Variable types. Script lines, conditions, and text read them as%var.<name>%script: the native script block; keys and phases are in Native scripting
yaml
variables:
fire_damage:
type: expression
value: "10 + %level% * 5"
battle_cry:
type: random_text
lines:
- "<red>Burn!"
- "<red>Flame power!"
script:
mode: native # native / mythic / hybrid
stop_on_failure: true
actions:
cast:
- 'trigger | damage amount=%var.fire_damage%'
hit:
- 'trigger | ignite duration=3s'resource_costs
yaml
resource_costs:
- type: "ea-resource"
target_id: "mana"
amount: 20
operation: "consume"
failure_message: "<red>Not enough mana."| Field | Type | Required | Default | Values | Description |
|---|---|---|---|---|---|
type | string | Yes | — | ea-resource, attribute-check (alias ea-attribute-check), local-resource, auraskills-mana (aliases aura-skills-mana, aura-mana), mythiclib-mana (aliases mmocore-mana, mythic-mana) | Resource type. An unrecognized value makes the whole entry be dropped |
target_id | string | No | "" | Resource / attribute id | The local resource, Attribute resource, or attribute id involved |
amount | double | No | 0 | ≥ 0, negatives become 0 | Amount to check or deduct |
operation | string | No | consume | consume (deduct), require (check only) | Any other value is treated as consume |
failure_message | string | No | "" | MiniMessage, rendered through PlaceholderAPI | Message shown when the check fails; when blank it falls back to the target_id text |
Watch the fallbacks when a dependency is missing: auraskills-mana requires AuraSkills and mythiclib-mana requires MythicLib or MMOCore; when the plugin is absent the entry counts as unavailable, so the check passes and the deduction is skipped. ea-resource and attribute-check behave the same way when EmakiAttribute is unavailable. attribute-check never deducts
Local resource files
resources/*.yml defines the resources used by local-resource. The resource id comes from the id key you write, not the file name
yaml
id: "mana"
display_name: "<gradient:#4DA6FF:#00BFFF>Mana</gradient>"
max: 100.0
default_current: 100.0
regen_amount: 2.0
regen_interval_ticks: 20
clamp_min: 0.0
clamp_max: 100.0| Field | Type | Required | Default | Values | Description |
|---|---|---|---|---|---|
id | string | Yes | — | Non-blank; lower-cased | Unique resource id; a blank value skips the whole file |
display_name | string | No | id | MiniMessage | Display name |
max | double | No | 100.0 | ≥ 0, negatives become 0 | Resource maximum |
default_current | double | No | 100.0 | ≥ 0, negatives become 0 | Starting value the first time a player is loaded |
regen_amount | double | No | 0.0 | ≥ 0, negatives become 0 | Amount added by each natural regeneration step |
regen_interval_ticks | integer | No | 0 | ≥ 0, negatives become 0 | Regeneration interval in ticks; 0 disables regeneration |
clamp_min | double | No | 0.0 | ≥ 0, negatives become 0 | Lower bound of the current value |
clamp_max | double | No | 0.0 | Falls back to max when <= 0, otherwise ≥ clamp_min | Upper bound of the current value |
Local resources versus other resource systems
Local resources are stored only in skill data and are not synchronized with EmakiAttribute. If you already keep a resource of the same name in EmakiAttribute, switch skill costs to ea-resource so the two never diverge
Upgrade configuration
yaml
upgrade:
enabled: true
max_level: 5
gui_template: "upgrade_gui"
failure_penalty: "none"
economy:
enabled: true
currencies:
- provider: "vault"
currency_id: ""
base_cost: 1200
cost_formula: "%base_cost% * %target_level%"
display_name: "<gold>Coins</gold>"
success_rates:
2: 100.0
3: 90.0
levels:
2:
materials:
- item_sources:
- "minecraft-blaze_powder"
amount: 2
actions:
success:
- 'send_message text="<yellow>The fireball grows stronger.</yellow>"'| Field | Type | Required | Default | Values | Description |
|---|---|---|---|---|---|
upgrade.enabled | boolean | No | false | true / false | Whether upgrades are enabled. When off, the maximum level is 1 |
upgrade.max_level | integer | No | 1 | ≥ 1, values below 1 become 1 | Maximum level, also the clamp used by the level command and the API |
upgrade.gui_template | string | No | upgrade_gui | A template name under gui/ | Upgrade GUI template. Blank, equal to upgrade_gui, or pointing at a missing template all fall back to upgrade_gui (a warning is logged when the template is missing) |
upgrade.failure_penalty | string | No | none | none / downgrade | Failure penalty. Only downgrade lowers the level by one (never below 1). Writing reset only changes the GUI text; it does not reset the level |
upgrade.economy.enabled | boolean | No | false | true / false | Whether currency costs are charged |
upgrade.economy.currencies | list<\map> | No | [] | — | Currency list, fields below |
upgrade.success_rates | map<int,double> | No | 100.0 | Keys are integers > 0; values are clamped to 0-100 | Success rate by target level; unlisted levels use 100. Non-positive or non-integer keys are skipped |
upgrade.levels | map<int,map> | No | {} | Keys are integers > 1 with mapping nodes | Per-target-level overrides for materials, economy, success rate, and upgrade actions |
Each upgrade.economy.currencies entry:
| Field | Type | Required | Default | Values | Description |
|---|---|---|---|---|---|
provider | string | No | auto (lower-cased) | Economy provider name | Economy source; when blank it is auto and CoreLib selects one |
currency_id | string | No | "" | — | Currency id |
base_cost | double | No | 0 | ≥ 0, negatives become 0 | The value of %base_cost% inside cost_formula |
cost_formula | string | No | %base_cost% | Expression | The amount actually charged. May use %base_cost%, %level% (current level), %target_level%, and %max_level%; an entry whose result is ≤ 0 is not charged |
display_name | string | No | "" | MiniMessage | Display name; falls back to currency_id, then to provider |
Each upgrade.levels.<n> entry (<n> is the target level and must be > 1):
| Field | Type | Required | Default | Values | Description |
|---|---|---|---|---|---|
levels.<n>.materials | list<\map> | No | [] | — | Required items for this level; fields below |
levels.<n>.economy.enabled | boolean | No | true | true / false | Whether this level overrides the economy to "enabled" |
levels.<n>.economy.currencies | list<\map> | No | [] | Same as upgrade.economy.currencies | Currency override for this level; with enabled: false this level is free |
levels.<n>.success_rate | double | No | upgrade.success_rates value | Clamped to 0-100 | Success rate override for this level, taking priority over upgrade.success_rates |
levels.<n>.actions.success | list<\string> | No | [] | Action pipeline lines | Actions run after a successful upgrade |
levels.<n>.actions.failure | list<\string> | No | [] | Action pipeline lines | Actions run after a failed upgrade (a failed roll or a downgrade) |
Each levels.<n>.materials entry:
| Field | Type | Required | Default | Values | Description |
|---|---|---|---|---|---|
item_sources | list<\string> | No | "" | Item source syntax, see Item Matcher | Allowed item sources; only the first list entry is used as the item token. Combined with a sibling matcher using AND |
matcher | map | No | none | Component / PDC / lore conditions | Non-item-source conditions. Item sources must not be written inside matcher |
amount | integer | No | 1 | ≥ 1, 0 becomes 1 | Required amount |
optional | boolean | No | false | true / false | Parsed, but the current upgrade check and charging flow never read it |
protection | boolean | No | false | true / false | Parsed, but the current upgrade check and charging flow never read it |
Omitting both item_sources and matcher makes the entry never match, which is equivalent to not needing that item. Entries sharing the same item_sources are merged and accumulated while charging; entries with a matcher are independent of each other
Upgrade flow and GUI
- Compute the target level first (current level + 1), then clamp it by
max_level; the skill must be unlocked andupgrade.enabledmust betrue - Order: condition check →
SkillPreUpgradeEvent(cancellable, success rate may be replaced) → cost check → charge → roll → apply the level or the failure penalty - Costs are charged before the roll, so a failed roll does not refund the currency and materials already charged (compensation is only attempted when the commit stage throws)
- Player-visible feedback comes from the
upgrade.*keys inlang/<language>.yml(for exampleupgrade.success,upgrade.failed,upgrade.insufficient_funds)
The upgrade GUI is rendered from the template named by upgrade.gui_template; the type you write on each slot decides its content:
Slot type | Content |
|---|---|
skill_display | Skill icon and name, with level, success rate, and failure-penalty text as replacements |
cost_currency | Currency cost list; shows gui.upgrade_cost_free when there is no cost. Replacements %currencies%, %currency_count% |
cost_material | Material cost list, one line per item showing "have/required" and colored by whether it is satisfied. Replacements %materials%, %material_count%, %missing_count% |
success_rate | Success-rate title, replacement %success_rate% |
confirm | Confirmation button; its icon and status text switch between upgrades-disabled, max-level, insufficient-materials, and ready. Clicking calls the same upgrade service as the command |
The GUI and the upgrade flow share one quote function (preview), so the numbers you see always match what gets charged: the GUI renders costs from the state at render time, and clicking Upgrade re-quotes and charges from that result. The numbers agree while the player's state is unchanged; if the state moved in between (a material was consumed elsewhere, for example), the re-quote and actual charge win, and a shortfall fails the whole attempt without charging
Skill sources and tag limits in config.yml
You write both blocks below in plugins/EmakiSkills/config.yml; they control how skills are recognized and how many can be equipped
Equipment skill source switches
yaml
skill_sources:
read_lore_skills: true
read_pdc_skills: true
require_lore_pdc_match: false| Field | Type | Required | Default | Values | Description |
|---|---|---|---|---|---|
skill_sources.read_lore_skills | boolean | No | true | true / false | Whether to read skills from equipment lore |
skill_sources.read_pdc_skills | boolean | No | true | true / false | Whether to read skills from equipment PDC |
skill_sources.require_lore_pdc_match | boolean | No | false | true / false | Strict mode. When enabled, only the lore∩PDC intersection for the same item and slot is kept; skills present on just one side do not apply |
Keep this in mind: the config precheck warns when both sides are off, or when strict mode is on with only one side enabled
Tag equip limits
When a skill's tags match an entry here, you can equip at most that many skills carrying the tag:
yaml
skill_tags:
equip_limits:
ultimate: 1
mobility: 2| Field | Type | Required | Default | Values | Description |
|---|---|---|---|---|---|
skill_tags.equip_limits.<tag> | integer | No | none (unlimited) | > 0; <= 0 or non-integer values ignore the key | Maximum number of skills with that tag equipped at once. Tag names are id-normalized with - turned into _ |
tag_limits | map | No | none | Same as above | Legacy key. Read as a fallback when skill_tags.equip_limits is empty |
With the config above, at most one ultimate skill and two mobility skills can be equipped at the same time. Tags not listed here are unlimited
Minimal example
yaml
id: fireball
enabled: true
display_name: '<red>Fireball'
description:
- '<gray>Hurls a fireball forwards.'
icon_material: FIRE_CHARGE
mythic_skill: EmakiFireball
trigger_type: active
cooldown_ticks: 100
global_cooldown_ticks: 20
resource_costs:
- type: ea-resource
target_id: mana
amount: 20
operation: consume
failure_message: '<red>Not enough mana.'