Triggers (TriggerType and active_triggers)
Previous: Full Skill Definition Reference · Next: Passive Skills
This page makes clear "what kind of trigger this player input actually counts as":
- TriggerType — the "kind" of trigger (right-click / left-click / sneak right-click / hold / passive…), 15 in total (server admins mainly use the first 10 click types; the rest are for internal use).
- active_triggers — the "source" of the trigger (item key press / skill slot hotkey / command / API), 4 in total, defaulting to
QI_ACTION. - trigger.primary — the skill's primary trigger; it must appear in the graph entry node's
triggers, otherwise the skill won't cast. - atom mapping — how QinhItems item key presses (atoms) map onto TriggerTypes.
💡 Remember this in one sentence: the "source" decides where this input enters QS (active_triggers); the "kind" decides which skill it routes to (TriggerType). Each handles one end and neither replaces the other.
🖼️ [Image placeholder] A flow diagram of "item key press → QI emits atom → QS normalizes to TriggerType → hits a graph node" · suggested
assets/trigger-pipeline.png
1. Full TriggerType set (15 types)
TriggerType is QS's unified enum for "what action this input is." It appears in three places:
- The skill definition's
trigger.primary(primary trigger); - A graph node's
triggers:(which actions this node accepts); - Inside passive skills (passives are uniformly recorded as
PASSIVE).
| TriggerType | Meaning | Typical use |
|---|---|---|
RIGHT_CLICK | right-click | the most common active skill trigger |
LEFT_CLICK | left-click | melee / basic-attack skills |
SHIFT_RIGHT_CLICK | sneak + right-click | a "second set" of skills on the same item |
SHIFT_LEFT_CLICK | sneak + left-click | same, another set |
SHIFT_TOGGLE | sneak toggle (press/release sneak) | toggle-type skills |
DOUBLE_SHIFT_TOGGLE | double sneak toggle (reserved) | not yet implemented, reserved enum |
DOUBLE_RIGHT_CLICK | double right-click | dash, dodge, and other "two quick presses" |
DOUBLE_LEFT_CLICK | double left-click | same, left-click version |
HOLD_RIGHT_CLICK | hold right-click | charge-up / channel opener |
HOLD_LEFT_CLICK | hold left-click | sustained opener |
CI_TEST | internal testing | 🔧 for internal regression testing, admins don't need it |
COMMAND | command | 🔧 internal/non-item key: triggered by /qs cast |
API | interface | 🔧 internal/non-item key: triggered by plugin code calls |
PASSIVE | passive | 🔧 internal/non-item key: passives use it internally (don't write it in primary) |
UNKNOWN | unknown / internal fallback value | 🔧 internal: do not use in config, only the fallback when recognition fails |
🔧 The 5 marked "internal/non-item key" (
CI_TEST/COMMAND/API/PASSIVE/UNKNOWN) aren't meant for item key presses; admins mainly use the first 10 click-type triggers.UNKNOWNis the internal fallback when recognition fails—never write it in config.
⚠️ Case-sensitive, must be all uppercase, copied verbatim. Writing
right_clickwill be treated as an unknown trigger (normalized toUNKNOWN).
How to pick a TriggerType?
- Single-skill item:
RIGHT_CLICKis enough. - Want to pack two skills on one weapon: right-click casts A, sneak right-click casts B →
RIGHT_CLICK+SHIFT_RIGHT_CLICK. - Want an aura/buff that's "press once on, press again off": use
SHIFT_TOGGLEwith the skill'scast_mode: toggle. - Charge-up channeled skill: open with
HOLD_RIGHT_CLICKand the skill'scast_mode: channel.
2. active_triggers — active trigger sources (4 types)
TriggerType answers "what action is this"; active_triggers answers "where does this come from." It's a list in the skill yml, defaulting to [QI_ACTION] (i.e. "only accept QinhItems item key presses").
| Source type | Meaning | How it triggers | Notes |
|---|---|---|---|
QI_ACTION | QinhItems item key press | player presses a key holding a QI item with a skill | default, most common, this is the default |
KEY_SLOT | skill slot hotkey | player uses a skill slot hotkey to cast the slotted skill | requires slots.active_count (config.yml, default 5) |
COMMAND | command cast | /qs cast <skill> | testing / command bridges (NI, MI, etc.) go through here |
API | interface call | plugin code calls QinhSkillsAPI | developer integration |
# default form: equivalent to active_triggers: [QI_ACTION], can be omitted entirely
active_triggers:
- type: QI_ACTION # item key press trigger (default)
# example: allow both "item key press" and "skill slot hotkey" sources
active_triggers:
- type: QI_ACTION
- type: KEY_SLOT💡 Most item skills can omit
active_triggersentirely—the defaultQI_ACTIONis exactly what you want. Only list it explicitly when connecting to skill slots / command bridges / API.
3. atom mapping — how item key presses become TriggerTypes
QinhItems items are configured with atoms (key atoms). When the item is pressed, QI sends the atom to QS, and QS normalizes it into a TriggerType to match against skills and graphs.
| QI item atom | normalized TriggerType |
|---|---|
left_click | LEFT_CLICK |
right_click | RIGHT_CLICK |
shift_left_click | SHIFT_LEFT_CLICK |
shift_right_click | SHIFT_RIGHT_CLICK |
shift_toggle | SHIFT_TOGGLE |
Rule of thumb: the item's atom should ideally match the skill's trigger.primary.
- Atom matches primary: it hits the entry node directly, everything works.
- Atom doesn't match primary: QS still falls back to the entry node and casts the skill (no misfire), but you lose the fine-grained branching of "right-click and left-click cast different skills."
🔌 For how to configure atoms on the item side, see Connecting QinhItems. Here you just need to remember the mapping.
4. The relationship between trigger.primary and the graph entry node (key section)
This is the pitfall newcomers hit most often. Two iron rules:
trigger.primarymust appear in the graph entry node'striggers:list.- If they don't match, the skill won't cast (or the fallback behavior won't be what you expect).
Here are a positive and a negative example.
✅ Correct: primary is inside the entry node's triggers
skills/combat/blade_slash.yml (excerpt from the bundled example):
trigger:
primary: LEFT_CLICK # primary trigger: left-click
graph:
entry: blade_slash # corresponds to the graph's entry node nameThe matching graphs/combat/blade_slash.graph.yml:
graph_id: blade_slash
entry: blade_slash
nodes:
blade_slash: # ← entry node
skill_id: blade_slash
mythic_skill: blade_slash
require_state: IDLE
triggers:
- LEFT_CLICK # ✅ primary(LEFT_CLICK) is here, it matches → can cast❌ Wrong: primary doesn't appear in the entry node
# in the skill:
trigger:
primary: RIGHT_CLICK # primary trigger is right-click
# but the graph entry node:
fire_wave:
triggers:
- LEFT_CLICK # ❌ only accepts left-click, right-click isn't listed → primary falls through⚠️ After changing triggers, remember to
/qs reloadand double-check with/qs info <skill>.
5. A complete small example: one weapon, two skills
Goal: right-click casts fire wave, sneak right-click casts blade slash.
# skill fire_wave: right-click
trigger:
primary: RIGHT_CLICK
graph:
entry: fire_waveThe matching graph entry node lists both triggers and routes them via skills (see the skills: section in config.yml):
# config.yml — branch to different skills by TriggerType
skills:
fire_wave:
RIGHT_CLICK: fire_wave # right-click → fire wave
LEFT_CLICK: blade_slash # left-click → blade slash
default: fire_wave # fallbackOn the item side, give the same weapon two atoms, right_click and shift_right_click, each matching the primary of one of the two skills.
✅ Self-check list
- [ ]
trigger.primaryuses a valid all-uppercase TriggerType. - [ ] That primary appears in the graph entry node's
triggers:. - [ ] The item atom matches the primary (
right_click↔RIGHT_CLICK). - [ ] If connecting to skill slots / command bridges,
active_triggersis written explicitly. - [ ] After changes, you ran
/qs reloadand double-checked with/qs info.
Further reading
- Next: Passive Skills — no key press, auto-triggered by events (how to use the
PASSIVEtrigger). - Targeting and Target Selection — who a skill locks onto once cast.
- Graphs and Combos — the full mechanics of nodes,
require_state, and combo sequences. - Full Skill Definition Reference — a quick reference of every field in a yml.