Skip to content

Triggers & Casting

Active Triggers

EmakiSkills provides 14 built-in active triggers. Active triggers require the player to press keys in cast mode:

Trigger IDDisplay NameEvent SourceConflict Rule
left_click[Left Click]InteractTriggerSourceConflicts with shift_left_click
right_click[Right Click]InteractTriggerSourceConflicts with shift_right_click
shift_left_click[Shift + Left Click]InteractTriggerSourceConflicts with left_click
shift_right_click[Shift + Right Click]InteractTriggerSourceConflicts with right_click
drop_q[Q Key]DropTriggerSourceNo conflicts
hotbar_1[Number Key 1]HotbarTriggerSourceNo conflicts
hotbar_2[Number Key 2]HotbarTriggerSourceNo conflicts
hotbar_3[Number Key 3]HotbarTriggerSourceNo conflicts
hotbar_4[Number Key 4]HotbarTriggerSourceNo conflicts
hotbar_5[Number Key 5]HotbarTriggerSourceNo conflicts
hotbar_6[Number Key 6]HotbarTriggerSourceNo conflicts
hotbar_7[Number Key 7]HotbarTriggerSourceNo conflicts
hotbar_8[Number Key 8]HotbarTriggerSourceNo conflicts
hotbar_9[Number Key 9]HotbarTriggerSourceNo conflicts

Conflict Rules

Conflict rules are configured via incompatible_with. When two triggers conflict with each other, the same player cannot bind them to different slots simultaneously.

Typical conflict: left_clickshift_left_click, because the Shift+Left-click event in Bukkit also triggers the left-click event simultaneously, causing ambiguity.

Event Sources

Source ClassListened EventDescription
InteractTriggerSourcePlayerInteractEventLeft/right click and Shift combinations
DropTriggerSourcePlayerDropItemEventQ key item drop
HotbarTriggerSourcePlayerItemHeldEventNumber key hotbar switching

Passive Triggers

Passive triggers are automatically fired by game events without requiring cast mode. Passive skills declare which passive triggers they respond to via the passive_triggers list in their definition files.

EmakiSkills provides 22 built-in passive triggers:

Trigger IDDisplay NameTrigger EventTarget Passing
attack[Attack Hit]Player attacks entityAttacked entity
damaged_by_entity[Damaged by Entity]Player damaged by entityAttacker
damaged[Damaged]Any damage receivedNone
death[Death]Player deathNone
kill_entity[Kill Entity]Kill non-player entityKilled entity
kill_player[Kill Player]Kill playerKilled player
shoot_bow[Shoot Bow]Shoot bowNone
arrow_hit[Arrow Hit Entity]Arrow hits entityHit entity
arrow_land[Arrow Land]Arrow hits blockNone (passes landing point)
shoot_trident[Throw Trident]Throw tridentNone
trident_hit[Trident Hit Entity]Trident hits entityHit entity
trident_land[Trident Land]Trident hits blockNone (passes landing point)
break_block[Break Block]Break blockNone (passes block location)
place_block[Place Block]Place blockNone (passes block location)
drop_item[Drop Item]Drop item (not sneaking)Dropped item entity
shift_drop_item[Shift+Drop Item]Drop item (sneaking)Dropped item entity
swap_items[Swap Items]Swap hand items (not sneaking)None
shift_swap_items[Shift+Swap Items]Swap hand items (sneaking)None
login[Login]Player joins serverNone
sneak[Sneak]Start sneakingNone
teleport[Teleport]Player teleportNone (passes target location)
timer[Timer]Periodic checkNone

The timer trigger interval is configured via passive_trigger_settings.timer_interval_ticks, default 20 ticks (1 second).

Passive Casting Flow

The passive skill casting flow is simpler than active skills — it skips cast mode check and slot binding lookup:

Game event → PassiveTriggerDispatcher.dispatch(invocation)

    ├─ 1. Check trigger exists and is enabled

    ├─ 2. Iterate all unlocked skills
    │     Filter: trigger_type == passive && passive_triggers contains current trigger

    ├─ 3. Check forced delay / global cooldown / skill cooldown

    ├─ 4. Check resource costs

    ├─ 5. MythicMobs cast (passes event target info)

    └─ Post-success: consume resources, record cooldowns

Target Passing

When a passive skill triggers, the event's target entity and location are passed to MythicMobs @target. For example, the attack trigger passes the attacked entity as target. Triggers without a target entity use the player as caster without passing additional targets.


Cast Mode Entry

Cast mode uses the F key (PlayerSwapHandItemsEvent) to toggle. The F key's original swap-hand function is intercepted by cast mode.

Active skills require the player to enter cast mode first. Outside cast mode, active trigger events are ignored. Passive skills are not affected by cast mode and are always listening.


Active Skill Casting Flow

When an active trigger event reaches CastAttemptService, the following 10-step check is executed:

Trigger event → CastAttemptService.attemptCast(player, triggerId)

    ├─ 1. Validate input
    │     player non-null, triggerId non-null

    ├─ 2. Check cast mode
    │     CastModeService.isCastModeEnabled(player) == true
    │     ✗ → Failure: NOT_IN_CAST_MODE

    ├─ 3. Find binding
    │     Iterate PlayerSkillProfile.bindings, find SkillSlotBinding matching triggerId
    │     ✗ → Failure: NO_BINDING

    ├─ 4. Find skill definition
    │     SkillRegistryService.getDefinition(binding.skillId)
    │     ✗ → Failure: SKILL_NOT_FOUND

    ├─ 5. Verify skill is still in unlock pool
    │     PlayerSkillStateService.getUnlockedSkills(player) contains binding.skillId
    │     ✗ → Failure: SOURCE_LOST (equipment unequipped)

    ├─ 6. Check forced delay
    │     PlayerCastTimingState.isForcedDelayActive() == false
    │     ✗ → Failure: FORCED_DELAY_ACTIVE

    ├─ 7. Check global cooldown
    │     PlayerCastTimingState.isGlobalCooldownActive() == false
    │     ✗ → Failure: GLOBAL_COOLDOWN_ACTIVE

    ├─ 8. Check skill cooldown
    │     PlayerCastTimingState.isSkillOnCooldown(skillId) == false
    │     ✗ → Failure: SKILL_COOLDOWN_ACTIVE

    ├─ 9. Check resource costs
    │     Iterate SkillDefinition.resourceCosts:
    │     ├─ local-resource → Check PlayerLocalResourceState
    │     ├─ ea-resource → Check EA resource via EaBridge
    │     └─ ea-attribute-check → Check EA attribute via EaBridge
    │     ✗ → Failure: RESOURCE_INSUFFICIENT

    ├─ 10. MythicMobs cast
    │      MythicSkillCastService.cast(player, mythicSkillId)
    │      ✗ → Failure: MYTHIC_CAST_FAILED

    └─ Post-success handling:
         ├─ Consume resources (resources with operation = CONSUME)
         ├─ Record skill cooldown (cooldown_ticks)
         ├─ Record global cooldown (global_cooldown_ticks)
         └─ Record forced delay (forced_global_cast_delay_ticks)

Failure Reason Enum

Failure ReasonDescription
NOT_IN_CAST_MODENot in cast mode
NO_BINDINGTrigger has no skill bound
SKILL_NOT_FOUNDSkill definition does not exist
SOURCE_LOSTSkill source lost (equipment unequipped)
FORCED_DELAY_ACTIVEForced delay active
GLOBAL_COOLDOWN_ACTIVEGlobal cooldown active
SKILL_COOLDOWN_ACTIVESkill cooldown active
RESOURCE_INSUFFICIENTInsufficient resources
MYTHIC_SKILL_NOT_FOUNDMythicMobs skill does not exist
MYTHIC_CAST_FAILEDMythicMobs cast failed

ActionBar Service

ActionBarService periodically refreshes the player's ActionBar during cast mode, displaying the current skill slot status.

Template Variables

VariableDescription
{slot_1} ~ {slot_N}Skill name for each slot (empty if unbound)
{slot_display}Formatted display of all slots
{forced_delay}Current forced delay remaining time

Configuration Example

yaml
actionbar:
  enabled: true
  refresh_interval_ticks: 10
  template_cast_mode: "&aCast Mode &7| {slot_display}"
  template_idle: "&7Idle"

EaBridge & MythicBridge

EaBridge

EaBridge obtains the EmakiAttributeBridge service via Bukkit's ServicesManager:

MethodDescription
isAvailable()Whether the EA bridge is available
readResourceCurrent()Read the current value of an EA resource
consumeResource()Consume an EA resource
readAttributeValue()Read an EA attribute value
providerMode()Current provider mode

MythicBridge

MythicBridge wraps the MythicMobs API:

MethodDescription
isAvailable()Whether MythicMobs is available
skillExists()Check if a MythicMobs skill exists
cast()Execute a MythicMobs skill cast (active skills, no target)
cast(target, location)Execute a MythicMobs skill cast (passive skills, passes target entity and location)

GUI Layout

skills_gui — Skills GUI (6 rows)

Row 1: [Border] [Border] [Border] [Border] [Border] [Border] [Border] [Border] [Border]
Row 2: [Border] [Skill 1] [Skill 2] [Skill 3] [Skill 4] [Skill 5] [Skill 6] [Skill 7] [Border]
Row 3: [Border] [Skill 8] [Skill 9] [Skill 10] [...] [...] [...] [...] [Border]
Row 4: [Border] [Border] [Border] [Border] [Border] [Border] [Border] [Border] [Border]
Row 5: [Border] [Slot 1] [Slot 2] [Slot 3] [Border] [Cast Mode] [Border] [Border] [Border]
Row 6: [Border] [Border] [Border] [Border] [Border] [Border] [Border] [Border] [Border]
  • Skill area (rows 2-3): Displays all unlocked skills, click to select
  • Slot area (row 5): Displays currently bound skill slots
  • Cast mode button: Toggle cast mode on/off

trigger_select_gui — Trigger Selection GUI (4 rows)

Row 1: [Border] [Border] [Border] [Border] [Border] [Border] [Border] [Border] [Border]
Row 2: [Border] [Trigger 1] [Trigger 2] [Trigger 3] [Trigger 4] [Trigger 5] [Border] [Border] [Border]
Row 3: [Border] [Trigger 6] [Trigger 7] [...] [...] [...] [Border] [Border] [Border]
Row 4: [Border] [Border] [Border] [Border] [Back] [Border] [Border] [Border] [Border]
  • Trigger area (rows 2-3): Displays all available triggers; conflicting triggers are shown in gray
  • Back button (row 4): Return to the skills GUI

Released under the GPL-3.0 License