Skip to content

Costs, Conditions & Variables

Previous: Cast Modes & Channeling · Next: Scripts


This page covers the cost a skill must pay before it's cast, the prerequisites for whether it can be cast, and finally how to pass data through to MythicMobs and scale by level. Four blocks of content:

BlockFieldPurpose
💧 Resource costresource.<key>Spend a resource pool such as mana
🩸 Health / hunger costcost.health / cost.hungerBlood-sacrifice playstyle, spending vanilla health / hunger
✅ Declarative conditionsconditionsA set of "cast only if satisfied" checks
📦 Variables & levelsvariables / levelsPass to MM, scale by level

🖼️ [Image placeholder] A gate-order diagram for one cast (resource → blood sacrifice → condition → fire) · suggested assets/cost-gate-flow.png


💧 Resource Cost resource.<key>

The most common one is mana mana:

yaml
resource:
  mana: 15        # deducts 15 mana when the cast succeeds; if insufficient, the cast is blocked with a notice

⚠️ Important: resource pools like mana will eventually be managed by QinhClass (QC); for now it's a temporary placeholder. QS currently manages this number temporarily through its own PlayerSkillProfile cost seam (channel costs also reuse the same seam, rather than building a second pool). When QC takes over, only this one spot changes; the resource.mana you write now won't need to change.

A resource's initial value / cap is in the resources.* section of config.yml:

config.yml keyDefaultMeaning
resources.default_mana100.0Player's initial mana
resources.max_mana100.0Mana cap

🩸 Health / Hunger Cost (Blood Sacrifice)

cost.health and cost.hunger deduct vanilla attributes, not the mana pool above. The blood-sacrifice playstyle (using health as a resource) relies on these.

FieldUnit / rule
cost.healthDeducts health, half a heart = 1. Can't cast when health ≤ this value; after deduction it floors at 0.5 (won't kill yourself)
cost.hungerDeducts hunger
yaml
cost:
  health: 4.0      # deducts 2 hearts; can't cast when health ≤ 4, leaves at least 0.5 after deduction
  hunger: 2        # deducts 1 hunger bar

💡 A blood-sacrifice skill can omit the resource section entirely—relying purely on health as the cost. Below is a pure blood-sacrifice example.

Full example: a blood-sacrifice skill (pure health cost, no mana)

yaml
id: blood_nova
display: "&4血祭新星"

meta:
  category: combat
  type: active
  rank: rare
trigger:
  primary: SHIFT_RIGHT_CLICK
state:
  required: IDLE
graph:
  entry: blood_nova
execution:
  mythic_skill: blood_nova

type: active
max_level: 1

cooldown:
  base: 5000

# Pure blood sacrifice: no resource section, only deducts health and hunger
cost:
  health: 6.0          # deducts 3 hearts (can't cast when health ≤ 6)
  hunger: 3            # also deducts 1.5 hunger bars

variables:
  element: blood       # passed to MM, <skill.var.element> = blood

✅ Declarative Conditions conditions

conditions is a list of strings that must all be satisfied to cast. For simple "can I cast it or not" checks this is enough, with no scripting needed.

yaml
conditions:
  - "player_level:>=5"          # level ≥ 5
  - "player_health_pct:>=50"    # health percentage ≥ 50
  - "player_in_world:world"     # in the main world

Syntax rules

  • Written as key:value, where the value can carry a comparator: >= <= == != > < = (no comparator defaults to =).
  • An empty list = no restriction (anyone can cast).
  • An unknown key is always true—a misspelled key name won't lock the skill, that line just has no effect.

Full table of condition keys

KeyValue / description
player_levelPlayer level
player_healthAbsolute health value
player_health_pctHealth percentage (0–100)
player_foodHunger value
player_in_worldWorld name
player_has_permissionPermission node
player_gamemodeSURVIVAL / CREATIVE / ADVENTURE / SPECTATOR
player_sneakingBoolean (true/false/1/yes)
player_sprintingBoolean
player_on_fireBoolean
player_on_groundBoolean
player_yY coordinate
has_targetWhether there is a target (passive target / crosshair target)
target_typeTarget entity type, e.g. ZOMBIE
target_distanceDistance to the target

Full example: a multi-condition skill (castable only under specific circumstances)

yaml
id: execute_strike
display: "&c处决斩"

meta:
  category: combat
  type: active
trigger:
  primary: LEFT_CLICK
state:
  required: IDLE
graph:
  entry: execute_strike
execution:
  mythic_skill: execute_strike

type: active

cooldown:
  base: 4000

target: NEAREST                 # auto-lock the nearest target
conditions:
  - "player_level:>=10"         # this playstyle unlocks at level 10
  - "player_sneaking:true"      # must be sneaking (charging up the execution)
  - "has_target:true"           # must have a target
  - "target_type:ZOMBIE"        # only against zombies
  - "target_distance:<=4"       # within 4 blocks (point-blank)
  - "player_gamemode:SURVIVAL"  # not usable in creative mode

If any one condition isn't satisfied, QS blocks the cast and gives the corresponding notice, deducting no resources.

For more complex checks (combining multiple values, calling external data) use the pre_js script, see Scripts.


📦 Variables variables (pass-through to MM)

variables.<key> passes any value through to the MM skill, which the MM side reads with <skill.var.key>.

yaml
variables:
  element: fire        # in MM, <skill.var.element> reads "fire"
  power: "2.5"

Besides what you write, QS also auto-injects these variables (MM reads them all with <skill.var.key>):

Auto variableMeaning
modeTrigger mode
sourceTrigger source
slotSkill slot (-1 when there's no slot, e.g. the command bridge)
playerNamePlayer name (on the MM side it's playerName, not player)
originFixed as QinhSkills
logicOnlyFixed as true (marks a logic-layer-only call)
toggle_stateToggle skill state on/off (only for toggle skills)

⚠️ Two easy-to-get-wrong spots (verified against the source code):

  1. The variables: / levels.params: keys you write appear in MM as-is, with no prefixvariables.element<skill.var.element>, levels.params.power<skill.var.power>. (Only in the script ctx do they carry the var_ prefix; don't mix the two conventions.)
  2. The MM side can't get player or level: use <skill.var.playerName> for the player name; the skill level is not injected into MM (it's only available in the script via ctx.get("level")). To scale values by level in MM, pass a parameter (such as power) via levels.params: and read it with <skill.var.power>.

For the full explanation of MM receiving variables (including @Target/@Trigger), see Integrating with MythicMobs.


📈 Level Scaling levels.N

levels.<level>.{cooldown_ms, resource, params} lets a skill override values by the player's level in that skill (1 to max_level).

  • cooldown_ms: the cooldown at that level.
  • resource: the resource cost at that level.
  • params: the parameters at that level, also passed through to MM (MM reads with <skill.var.power>).

Merge rule (SkillParamResolver): if the level has it, use the level's value; if not, use the top-level default—so you only need to write the few items in levels that "change with level."

Full example: cooldown decreasing + power increasing

yaml
id: fire_lance
display: "&c烈焰长矛"

meta:
  category: combat
  type: active
trigger:
  primary: RIGHT_CLICK
state:
  required: IDLE
graph:
  entry: fire_lance
execution:
  mythic_skill: fire_lance

type: active
max_level: 3

# Top-level defaults (used for any level / field not overridden in levels)
cooldown:
  base: 5000
resource:
  mana: 20
variables:
  element: fire

levels:
  1:
    cooldown_ms: 5000           # level 1: 5-second cooldown
    resource: { mana: 20 }      # deducts 20 mana
    params: { power: "1.0" }    # power=1.0 → MM uses <skill.var.power> to scale damage
  2:
    cooldown_ms: 4000           # level 2: cooldown drops to 4 seconds
    resource: { mana: 18 }
    params: { power: "1.5" }    # higher damage
  3:
    cooldown_ms: 3000           # level 3: 3-second cooldown (strongest)
    resource: { mana: 15 }      # cost is actually lower
    params: { power: "2.2" }

On the MM side, just multiply <skill.var.power> into the damage formula, and QS will feed in the corresponding power based on the player's level.

Set a player's level: /qs level <skill> <level> [player], see Commands & Permissions.


🔗 How These Values Are Read in Scripts

If you wrote pre_js/post_js scripts, all the variables above can be read with ctx.get(key)—mind the prefixes:

SourceKey in the script
variables.<key> (skill variables)Add the var_ prefix, e.g. ctx.get("var_element")
levels.params.<key> (level parameters)Add the param_ prefix, e.g. ctx.get("param_power")
Auto variables (mode/source/level…)Read directly, e.g. ctx.get("level")

For scripts see Scripts.


📚 Continue Reading