Lua Scripting: API Reference
This page is the complete reference for every context.* key, method, and field available in EliteMobs Lua powers. If you're new to Lua powers, start with Getting Started first.
The context Object
Hook functions receive one argument: context. It resolves keys lazily -- EliteMobs only looks up values when your code asks for them.
| Key | What it gives you |
|---|---|
context.state | Persistent Lua table for this runtime instance |
context.boss | Boss wrapper |
context.player | Relevant player wrapper when a player is involved, otherwise nil |
context.players | Player query helpers |
context.entities | General entity query helpers |
context.event | Event wrapper for the current event |
context.cooldowns | Local and global cooldown helpers |
context.scheduler | Runtime-owned task scheduling |
context.vectors | Vector math helpers |
context.world | World and spawning helpers |
context.zones | Native Lua zone queries and watchers |
context.script | Bridge into existing EliteScript targeting, zones, particles, and relative vectors |
context.settings | Power-specific configuration values |
context.log | Logging helpers |
Only context.state persists across hook calls. All other tables are created fresh for each call.
context.state
A plain Lua table that persists for the entire lifetime of the runtime instance (i.e. as long as the boss is alive).
Common uses: cache zone handles, store task IDs, remember attack picks, track booleans for one-time triggers.
on_spawn = function(context)
context.state.triggered = false
end
on_boss_damaged_by_player = function(context)
if context.state.triggered then
return
end
context.state.triggered = true
context.boss:add_tag("angry")
end
context.log
Simple logging helpers that print to the server console.
| Method | Notes |
|---|---|
context.log:info(message) | Info log |
context.log:warn(message) | Warning log |
context.log:debug(message) | Debug-style info log |
context.log:info("Boss entered phase 2")
context.cooldowns
Helpers for managing per-power local cooldowns and per-boss global power cooldowns.
| Method | Notes |
|---|---|
context.cooldowns:local_ready([key]) | Returns true if the local cooldown key is ready |
context.cooldowns:local_remaining([key]) | Remaining ticks for the local cooldown key |
context.cooldowns:check_local(key, ticks) | If the key is ready, sets it immediately and returns true; otherwise returns false |
context.cooldowns:set_local(ticks[, key]) | Sets a local cooldown |
context.cooldowns:global_ready() | Returns true if the boss is not in global power cooldown |
context.cooldowns:set_global(ticks) | Starts global cooldown on the boss |
Local cooldown key behavior:
- If you do not pass a key, Lua uses a default key unique to the current Lua filename (
__lua:<filename>) - For multiple independent cooldowns in one file, give them separate names
if context.cooldowns:check_local("slam", 200) and context.cooldowns:global_ready() then
context.cooldowns:set_global(20)
end
context.scheduler
Runtime-owned task scheduling. All tasks are automatically cleaned up when the boss is removed.
| Method | Returns | Notes |
|---|---|---|
context.scheduler:run_after(ticks, fn) | Task ID | Runs once after a delay |
context.scheduler:run_every(ticks, fn) | Task ID | Repeats every ticks |
context.scheduler:cancel_task(taskId) | nil | Cancels a task created by the current runtime |
Scheduler notes:
- Tasks are owned by the runtime and cleaned up on shutdown
- Scheduled callbacks receive a fresh
context - Inside scheduled callbacks,
context.eventisnil,context.playerusually alsonil run_after(0, fn)means "next tick", not "right now"- Repeating tasks should cancel themselves when done
- Do not rely on old captured snapshot fields; use the fresh callback context
context.scheduler:run_after(20, function(delayed_context)
delayed_context.boss:play_sound_at_self("entity.blaze.shoot", 1.0, 1.0)
end)
context.event
The event wrapper depends on which hook is active.
| Field or method | When available | Notes |
|---|---|---|
damage_amount | Damage events | Current damage amount (snapshot) |
damage_cause | Damage events with a cause | Bukkit DamageCause enum name |
cancel_event() | Cancellable events | Cancels the event |
set_damage_amount(value) | EliteDamageEvent-based hooks | Sets damage directly |
multiply_damage_amount(multiplier) | EliteDamageEvent-based hooks | Multiplies current damage |
spawn_reason | Spawn event | Spawn reason enum name |
entity | on_zone_enter / on_zone_leave from script-zone events, on_death | The entity that entered/left, or the dead entity |
damager | Damage events with EntityDamageByEntityEvent | Entity reference wrapper for the damager |
projectile | Damage events where damager is a projectile | Projectile entity reference wrapper |
on_boss_damaged_by_player = function(context)
if context.event ~= nil then
context.event:multiply_damage_amount(0.5)
end
end
Notes:
damage_amountis a snapshot; it does not auto-refresh afterset_damage_amount()ormultiply_damage_amount()- Top-level hooks
on_zone_enter/on_zone_leaveexposecontext.event.entity - Watcher callbacks receive entity wrappers directly, not via
context.event - Event-authoring rule: use
context.eventfor modifying incoming/outgoing damage; usecontext.script:damage()or entity damage helpers for fresh scripted damage
context.players
Player query helpers centered around the boss.
| Method | Notes |
|---|---|
context.players:current_target() | Returns the event player or boss mob target if it is a player |
context.players:nearby_players(radius) | Returns array-like table of player wrappers |
context.players:all_players_in_world() | Returns all players in the boss world |
local nearby = context.players:nearby_players(20)
for _, player in ipairs(nearby) do
player:send_message("&cThe boss is enraged!")
end
context.entities
General entity query helpers centered around the boss.
| Method | Notes |
|---|---|
context.entities:get_nearby_entities(radius[, filter]) | Nearby entities around the boss |
context.entities:get_entities_in_box(center, halfX, halfY, halfZ[, filter]) | Entities within an axis-aligned box |
context.entities:get_all_entities([filter]) | All matching entities in the boss world |
context.entities:get_direct_target_entity() | Direct target for the current event, if any |
context.entities:get_boss_spawn_location() | Boss spawn location as a location table |
Valid filters: living (default if omitted), player / players, elite / elites, mob / mobs, all / entities
local elites = context.entities:get_nearby_entities(10, "elites")
for _, elite in ipairs(elites) do
elite:deal_damage(5)
end
Entity Wrappers
Most entity-returning helpers give you wrapper tables, not raw Bukkit objects.
Two rules:
- Scalar fields (
health,maximum_health,current_location,is_valid) are snapshots taken at creation time - Live re-checks happen through methods like
get_location()andis_alive()
Common entity fields
| Field | Notes |
|---|---|
name | Entity display name |
uuid | UUID as text |
entity_type | Bukkit entity type name |
is_player | true for players |
is_elite | true if EliteMobs tracks it as an elite |
is_monster | true for monster-type entities |
is_valid | Snapshot validity flag on living wrappers |
health | Current health (snapshot) |
maximum_health | Max health (snapshot) |
current_location | Snapshot location table |
Common entity methods
| Method | Notes |
|---|---|
is_alive() | Live validity + not dead |
is_ai_enabled() | Whether AI is currently enabled |
is_frozen() | Whether the boss is frozen (custom boss only) |
is_on_ground() | Whether the entity is on the ground |
get_location() | Current live location |
get_eye_location() | Eye-level location |
get_height() | Entity height |
get_health() | Live current health |
get_maximum_health() | Live max health |
get_velocity() | Current velocity vector |
deal_damage(amount) | Damages the entity (generic source) |
deal_custom_damage(amount) | Damages via BossCustomAttackDamage from the boss |
deal_damage_from_boss(amount) | Damages with the boss entity as the damager |
restore_health(amount) | Heals up to max health |
play_sound_at_entity(sound[, volume][, pitch]) | Plays a sound at that entity |
teleport_to_location(location) | Teleports the entity |
set_velocity_vector(vector) | Sets velocity immediately |
set_gravity(enabled) | Toggles gravity |
apply_push_vector(vector[, additive][, delay]) | Applies velocity after a short delay (default 1 tick) |
set_custom_name(name) | Sets custom display name (supports color codes) |
reset_custom_name() | Resets to original name |
set_custom_name_visible(visible) | Toggles name visibility |
set_ai_enabled(enabled[, duration]) | Toggles AI, optionally reverting after duration |
set_awareness_enabled(enabled[, duration]) | Mob awareness toggle |
face_direction_or_location(vectorOrLocation) | Makes the entity face a direction or location |
play_model_animation(name) | Plays custom model animation if available |
set_scale(scale[, duration]) | Sets generic_scale, optionally reverting to 1.0 |
set_invulnerable(enabled[, duration]) | Toggles invulnerability |
remove_elite() | Removes the entity if it is an elite |
is_healing() | Whether the elite is currently healing |
set_healing(enabled) | Toggles the healing flag on an elite |
navigate_to_location(location[, speed][, follow][, timeout]) | Navigation helper for compatible elite/custom bosses |
add_tag(tag[, duration]) | Adds elite/player tag, optionally removing after duration |
remove_tag(tag) | Removes elite/player tag |
has_tag(tag) | Checks elite/player tag |
push_relative_to(source[, strength][, xOffset][, yOffset][, zOffset]) | Pushes away from a source location or wrapper |
overlaps_box_at_location(center[, halfX][, halfY][, halfZ]) | Tests bounding box overlap |
apply_potion_effect(effect, duration[, amplifier]) | Applies potion effect |
set_equipment(slot, material[, options]) | Sets equipment in a slot |
set_fire_ticks(ticks) | Sets fire ticks |
add_visual_freeze_ticks([ticks]) | Adds freeze ticks |
place_temporary_block(material[, duration][, requireAir]) | Places a block at the entity's current location |
local target = context.players:current_target()
if target ~= nil and target:is_alive() then
target:apply_potion_effect("SLOWNESS", 60, 1)
target:send_message("&7You feel sluggish...")
end
Non-living entity reference wrappers
When an entity is not a LivingEntity (e.g. a projectile, falling block), you receive a lighter reference wrapper.
Fields: name, uuid, entity_type, is_player, is_elite, current_location
Methods:
| Method | Notes |
|---|---|
is_valid() | Live validity check |
get_location() | Current live location |
get_velocity() | Current velocity vector |
is_on_ground() | Whether on the ground |
teleport_to_location(location) | Teleports the entity |
set_velocity_vector(vector) | Sets velocity |
set_direction_vector(vector) | Sets direction (Fireball only) |
set_yield(value) | Sets explosion yield (Fireball only) |
set_gravity(enabled) | Toggles gravity |
detonate() | Detonates firework entities |
remove() | Removes the entity |
unregister([reason]) | Unregisters from entity tracker |
context.player
Only set when the current hook has an obvious player involved (on_boss_damaged_by_player, on_player_damaged_by_boss, etc.).
Player wrappers include every common entity field and method, plus:
| Method | Notes |
|---|---|
send_message(message) | Supports color formatting handled by EliteMobs |
show_action_bar(message) | Sends action bar text |
show_title(title[, subtitle][, fadeIn][, stay][, fadeOut]) | Sends title and subtitle |
show_boss_bar(title[, color][, style][, duration]) | Temporary boss bar |
run_command(command) | Makes the player run a command |
Player-only fields:
| Field | Notes |
|---|---|
game_mode | The player's current game mode name |
Use command text without a leading /.
context.player:show_title("&cDANGER", "&7The boss is charging!", 10, 40, 10)
context.boss
Specialized wrapper for the owning boss.
Boss fields
| Field | Notes |
|---|---|
name | Boss name |
uuid | Boss elite UUID |
entity_type | Bukkit entity type name |
is_monster | true if the underlying entity is a Monster |
level | Elite level |
health | Current health (snapshot) |
maximum_health | Max health (snapshot) |
damager_count | Number of damagers (snapshot) |
is_in_combat | Combat state |
exists | Whether the elite still exists |
current_location | Current location (snapshot) |
Boss methods
| Method | Notes |
|---|---|
is_alive() | Live validity + not dead + elite exists |
is_ai_enabled() | Whether AI is currently enabled |
is_on_ground() | Whether the boss entity is on the ground |
get_health() | Live current health |
get_maximum_health() | Live max health |
get_damager_count() | Live damager count |
get_location() | Current live location |
get_eye_location() | Eye-level location |
get_height() | Entity height |
get_ender_dragon_phase() | Current ender dragon phase name (ender dragon only) |
set_ender_dragon_phase(phase) | Sets ender dragon phase (ender dragon only) |
add_tag(tag[, duration]) | Adds a tag to the boss, optionally removing it later |
remove_tag(tag) | Removes a tag from the boss |
has_tag(tag) | Checks a boss tag |
restore_health(amount) | Heals the boss |
deal_damage(amount) | Damages the boss entity |
teleport_to_location(location) | Teleports the boss |
despawn() | Removes the boss |
set_ai_enabled(enabled[, duration]) | Toggles AI, optionally reverting later |
set_custom_name(name) | Sets custom display name |
reset_custom_name() | Resets to original name |
set_custom_name_visible(visible) | Toggles name visibility |
play_sound_at_self(sound[, volume][, pitch]) | Sound at boss location |
spawn_particle_at_self(particleOrSpec[, count]) | Particle at boss location |
spawn_particles_at_location(location, particle[, amount][, x][, y][, z][, speed]) | Particle helper |
set_velocity_vector(vector) | Sets velocity |
face_direction_or_location(vectorOrLocation) | Rotates the boss |
play_model_animation(name) | Plays model animation if available |
navigate_to_location(location[, speed][, follow][, timeout]) | Pathfinding helper |
send_message(message[, range]) | Sends chat to nearby players (default range 20) |
get_nearby_players(range) | Returns player wrappers |
get_target_player() | Returns current target if player |
get_nearby_players_in_zone(zoneDef) | Uses a native Lua zone definition |
spawn_particles_in_zone(zoneDef, particle, amount, x, y, z, speed[, coverage]) | Spawns particles across a native zone |
spawn_particles_in_zone_border(zoneDef, particle, amount, x, y, z, speed[, coverage]) | Same, but only on the border |
get_particles_from_self_toward_zone(zoneDef, particleKey[, speed]) | Builds particle list pointing outward |
get_particles_toward_self(zoneDef, particleKey[, speed]) | Builds particle list pointing toward boss |
spawn_particles_with_vector(particlesTable) | Spawns particle specs from previous helpers |
summon_reinforcement(filename, zoneOrLocation[, duration]) | Summons reinforcement boss |
summon_projectile(entityType, origin, destination[, speed][, options]) | Launches projectile-like entity |
start_tracking_fireball_system([speed]) | Starts tracking fireball support (monster only) |
handle_spirit_walk_damage(damageCause) | Spirit walk damage handler |
shield_wall_is_active() | Whether shield wall is currently active |
initialize_shield_wall([charges]) | Initializes shield wall with charge count |
shield_wall_absorb_damage(playerWrapper, amount) | Attempts to absorb damage via shield wall |
deactivate_shield_wall() | Deactivates shield wall |
start_zombie_necronomicon(targetWrapper, filename) | Starts zombie necronomicon behavior |
apply_potion_effect(effect, duration[, amplifier]) | Shared entity effect helper |
set_equipment(slot, material[, options]) | Sets equipment on the boss |
set_fire_ticks(ticks) | Shared entity effect helper |
add_visual_freeze_ticks([ticks]) | Shared entity effect helper |
place_temporary_block(material[, duration][, requireAir]) | Shared entity effect helper at boss location |
Boss helper notes:
- Fields like
healthandcurrent_locationare snapshots. Useget_location()andis_alive()for fresh checks. send_message(message[, range])defaults to a radius of 20summon_reinforcement()accepts a location table or native Lua zone definitionsummon_projectile()options:duration,effect,on_land,max_ticks,speed,custom_damage,detonation_power,yield,incendiary,gravity,glowing,invulnerable,persistent,track,spawn_at_origin,direction_onlyon_landcallbacks receive(landing_location, spawned_entity)
context.boss:play_sound_at_self("entity.wither.spawn", 1.0, 0.8)
context.boss:spawn_particle_at_self("SMOKE", 20)
context.boss:send_message("&4You dare challenge me?!")
context.vectors
Vector math helpers.
| Method | Notes |
|---|---|
context.vectors:get_vector_between_locations(source, destination[, options]) | Returns a vector from source to destination |
context.vectors:rotate_vector(vector[, pitchDegrees][, yawDegrees]) | Rotates a vector |
context.vectors:normalize_vector(vector) | Returns a normalized copy |
Options for get_vector_between_locations: normalize (boolean), multiplier (number), offset (vector table)
Vector rules:
- Can be written as
{ x = 0, y = 1, z = 0 }or{ 0, 1, 0 } - Tables with a
directionsub-table can be used where a vector is expected (e.g. a location table) - Cross-world vectors return zero vector
local vec = context.vectors:get_vector_between_locations(
context.boss.current_location,
context.player.current_location,
{ normalize = true, multiplier = 2.0 }
)
context.boss:set_velocity_vector(vec)
context.world
World interaction and spawning helpers.
| Method | Notes |
|---|---|
context.world:play_sound_at_location(location, sound[, volume][, pitch]) | Plays a sound |
context.world:spawn_particle_at_location(location, particleOrSpec[, count]) | Spawns particle by name or table spec |
context.world:set_block_at_location(location, material[, requireAir]) | Permanently sets block type |
context.world:place_temporary_block_at_location(location, material[, duration][, requireAir]) | Places temporary block |
context.world:get_block_type_at_location(location) | Returns material name |
context.world:get_highest_block_y_at_location(location) | Returns the Y of the highest block |
context.world:get_blast_resistance_at_location(location) | Returns blast resistance value |
context.world:is_air_at_location(location) | Returns true if air |
context.world:is_passable_at_location(location) | Returns true if the block is passable |
context.world:is_passthrough_at_location(location) | Returns true if the block is not solid |
context.world:is_on_floor_at_location(location) | Non-solid block above solid block |
context.world:is_standing_on_material(location, material) | Checks material under location |
context.world:strike_lightning_at_location(location) | Strikes lightning |
context.world:run_empowered_lightning_task_at_location(location) | Runs empowered lightning effect |
context.world:set_world_time(time) / set_world_time(location, time) | Sets time |
context.world:set_world_weather(weather[, duration]) / set_world_weather(location, weather[, duration]) | Sets weather |
context.world:run_console_command(command) | Runs console command |
context.world:spawn_boss_at_location(filename[, location][, level]) | Spawns custom boss |
context.world:spawn_custom_boss_at_location(filename, location[, options]) | Spawns custom boss with options |
context.world:spawn_entity_at_location(entityType, location[, options]) | Spawns entity |
context.world:spawn_falling_block_at_location(location, material[, options]) | Spawns falling block |
context.world:spawn_reinforcement_at_location(filename, location[, duration][, velocity]) | Spawns reinforcement |
context.world:spawn_fireworks_at_location(location, spec) | Spawns fireworks |
context.world:spawn_splash_potion_at_location(location, spec) | Spawns splash potion |
context.world:generate_fake_explosion(locations[, sourceLocation]) | Generates fake explosion regen |
context.world:spawn_fake_gold_nugget_at_location(location, velocity[, gravity]) | Spawns fake gold nugget projectile |
context.world:run_fake_gold_nugget_damage(projectilesTable) | Runs gold nugget damage on projectile list |
context.world:generate_player_loot([times]) | Generates player loot |
context.world:drop_bonus_coins([multiplier]) | Drops bonus coins for damagers |
Notes:
- Weather accepts
CLEAR,PRECIPITATION,RAIN, orTHUNDER run_console_commandandrun_commandaccept command text without a leading/spawn_boss_at_locationonly works for custom boss runtimes
spawn_entity_at_location options
context.world:spawn_entity_at_location("ZOMBIE", location, {
velocity = { x = 0, y = 1, z = 0 },
duration = 100, -- auto-remove after ticks
effect = "WOLF_SHAKE", -- EntityEffect to play
on_land = function(landing_location, entity)
-- called when the entity lands
end,
max_ticks = 6000 -- max ticks to monitor for landing
})
spawn_falling_block_at_location options
context.world:spawn_falling_block_at_location(location, "STONE", {
velocity = { x = 0, y = 1, z = 0 },
drop_item = false, -- whether to drop item on land
hurt_entities = false, -- whether to hurt entities
on_land = function(landing_location, entity)
-- called when the block lands
end
})
spawn_custom_boss_at_location options
context.world:spawn_custom_boss_at_location("my_boss.yml", location, {
level = 10, -- override boss level
silent = true, -- suppress spawn messages
add_as_reinforcement = true, -- register as reinforcement of current boss
velocity = { x = 0, y = 1, z = 0 }
})
spawn_fireworks_at_location spec
context.world:spawn_fireworks_at_location(location, {
power = 1,
velocity = { x = 0, y = 0.5, z = 0 },
shot_at_angle = true,
-- single effect:
type = "BALL_LARGE",
flicker = true,
trail = true,
colors = { "RED", "ORANGE" },
fade_colors = { "YELLOW" },
-- OR multiple effects:
effects = {
{ type = "STAR", colors = { "BLUE" }, fade_colors = { "WHITE" }, flicker = true, trail = false },
{ type = "BALL", colors = { "GREEN" } }
}
})
spawn_splash_potion_at_location spec
context.world:spawn_splash_potion_at_location(location, {
velocity = { x = 0, y = 0.5, z = 0 },
effects = {
{ type = "POISON", duration = 100, amplifier = 1, overwrite = true },
{ type = "SLOWNESS", duration = 60, amplifier = 0 }
}
})
Particle table format
Particles can be specified either as a plain string name or as a table spec:
-- plain name
context.world:spawn_particle_at_location(location, "FLAME", 10)
-- table spec
context.world:spawn_particle_at_location(location, {
particle = "DUST",
amount = 5,
x = 0.1,
y = 0.1,
z = 0.1,
speed = 0,
red = 255,
green = 0,
blue = 0
}, 5)
-- dust color transition
context.world:spawn_particle_at_location(location, {
particle = "DUST_COLOR_TRANSITION",
amount = 5,
red = 255, green = 0, blue = 0,
toRed = 0, toGreen = 255, toBlue = 0
-- also accepted: to_red, to_green, to_blue
}, 5)
context.settings
Provides access to power-specific configuration values set by the boss file.
| Method | Notes |
|---|---|
context.settings:warning_visual_effects_enabled() | Whether the server has warning visual effects enabled |
This table may be expanded in future versions.
Native Lua Zones: context.zones
Native Lua zone queries let you define zones as plain Lua tables and query them for entities or locations.
Zone methods
| Method | Notes |
|---|---|
context.zones:get_entities_in_zone(zoneDef[, options]) | Returns entities inside a native zone |
context.zones:get_locations_in_zone(zoneDef[, options]) | Returns location tables inside a native zone |
context.zones:zone_contains(zoneDef, location[, mode]) | Returns true if the location is inside the zone |
context.zones:watch_zone(zoneDef, callbacks[, options]) | Registers a zone watcher that fires per tick |
Zone query options
| Key | Values | Notes |
|---|---|---|
filter | "living", "player", "players", "elite", "elites", "mob", "mobs" | Entity type filter (default "living") |
mode | "full", "border" | Whether to check full volume or border only (default "full") |
coverage | 0.0 to 1.0 | Fraction of locations to sample (default 1.0) |
Native zone definition fields
| Field | Shapes | Notes |
|---|---|---|
kind | All | "sphere", "dome", "cylinder", "cuboid", "cone", "static_ray", "rotating_ray", "translating_ray" |
origin | All | Center or origin location table |
destination | cone, rays | End point location table |
radius | sphere, dome, cylinder, cone | Zone radius |
height | cylinder | Cylinder height |
x, y, z | cuboid | Half-extents |
length | cone, rays | Length of cone or ray |
thickness / point_radius | rays | Ray thickness |
border_radius | sphere, dome, cylinder, cone | Border width (default 1) |
x_border, y_border, z_border | cuboid | Cuboid border widths (default 1) |
animation_duration | rotating_ray, translating_ray | Animation length in ticks |
pitch_pre_rotation, yaw_pre_rotation | rotating_ray | Pre-rotation angles |
pitch_rotation, yaw_rotation | rotating_ray | Per-tick rotation angles |
origin_end, destination_end | translating_ray | End positions for translation |
ignores_solid_blocks | rays | Whether to pass through solid blocks (default true) |
Zone definition example
on_spawn = function(context)
context.state.zone = {
kind = "sphere",
origin = context.boss:get_location(),
radius = 10
}
end
on_boss_damaged_by_player = function(context)
local entities = context.zones:get_entities_in_zone(context.state.zone, { filter = "players" })
for _, entity in ipairs(entities) do
entity:send_message("&cYou are in the danger zone!")
end
end
Zone watcher
Watchers tick every game tick and call on_enter / on_leave callbacks when entities enter or leave the zone.
on_spawn = function(context)
context.zones:watch_zone(
{
kind = "sphere",
origin = context.boss:get_location(),
radius = 8
},
{
on_enter = function(entity)
entity:apply_potion_effect("SLOWNESS", 40, 1)
end,
on_leave = function(entity)
-- entity left the zone
end
},
{ filter = "players", mode = "full" }
)
end
Watcher caveats:
- Watcher callbacks receive a single entity wrapper directly, not via
context.event - Watchers are cleaned up automatically when the boss is removed
- Each watcher runs every tick, so keep callback logic lightweight
- The boss entity itself is excluded from zone queries
EliteScript Bridge: context.script
The bridge lets you use Lua control flow combined with the same target, zone, particle, and relative-vector specs documented in the EliteScript YAML pages.
Bridge authoring rule
Use native Lua helpers (context.boss, context.world, context.zones, etc.) when possible. Use the bridge when you need the full power of EliteScript's target resolution, zone shapes, or particle system -- for example, ZONE_FULL targeting with coverage, or complex relative vectors.
Bridge methods
| Method | Notes |
|---|---|
context.script:target(spec) | Creates a target handle from an EliteScript target spec |
context.script:zone(spec) | Creates a zone handle from an EliteScript zone spec |
context.script:relative_vector(spec[, actionLocation][, zoneHandle]) | Creates a relative-vector handle |
context.script:damage(targetHandle, amount[, multiplier]) | Deals damage to resolved targets |
context.script:push(targetHandle, vectorOrHandle[, additive]) | Pushes resolved targets |
context.script:set_facing(targetHandle, vectorOrHandle) | Sets facing direction for targets |
context.script:spawn_particles(targetHandle, particleSpec) | Spawns particles at resolved target locations |
Target handle methods
| Method | Notes |
|---|---|
handle:entities() | Returns array-like table of entity wrappers |
handle:locations() | Returns array-like table of location tables |
handle:first_entity() | Returns first entity or nil |
handle:first_location() | Returns first location or nil |
Zone handle methods
| Method | Notes |
|---|---|
handle:full_target([coverage]) | Returns a target handle for the full zone volume |
handle:border_target([coverage]) | Returns a target handle for the zone border |
handle:full_locations([coverage]) | Returns locations in the full zone |
handle:border_locations([coverage]) | Returns locations on the zone border |
handle:full_entities() | Returns entities in the full zone |
handle:border_entities() | Returns entities on the zone border |
handle:contains(location[, mode]) | Tests if a location is inside (mode: "full" or "border") |
handle:watch(callbacks[, mode]) | Watches zone for enter/leave events, returns task ID |
Relative-vector handle methods
| Method | Notes |
|---|---|
handle:resolve() | Returns the computed vector table |
Bridge authoring rules
- Build a target spec as a Lua table using the same keys as the EliteScript YAML
Targetsection - Build a zone spec using the same keys as the EliteScript YAML
Zonesection - Build particle specs using the same keys as the EliteScript YAML particle configuration
- All string values use the same enum names as YAML (e.g.
"NEARBY_PLAYERS","ZONE_FULL","SPHERE")
Minimal bridge templates
Target:
local target = context.script:target({
targetType = "NEARBY_PLAYERS",
range = 20
})
for _, entity in ipairs(target:entities()) do
entity:send_message("&cFound you!")
end
Zone:
local zone = context.script:zone({
shape = "SPHERE",
radius = 5,
Target = {
targetType = "SELF"
}
})
local entities = zone:full_entities()
Relative vector:
local vec = context.script:relative_vector({
SourceTarget = { targetType = "SELF" },
DestinationTarget = { targetType = "DIRECT_TARGET" },
normalize = true,
multiplier = 2.0
})
context.boss:set_velocity_vector(vec:resolve())
Important bridge note about magic values
All string values in bridge specs use the same exact enum names as EliteScript YAML. For example, targetType accepts the same values as the targetType: YAML key (e.g. "SELF", "DIRECT_TARGET", "NEARBY_PLAYERS", "ZONE_FULL", "ZONE_BORDER"). Zone shapes use the same names (e.g. "SPHERE", "DOME", "CYLINDER", "CUBOID").
Bridge parser quick reference
Target specs:
| Key | Notes |
|---|---|
targetType | Required. SELF, DIRECT_TARGET, NEARBY_PLAYERS, ZONE_FULL, ZONE_BORDER, LOCATION, LOCATIONS, etc. |
range | Range for nearby-type targets |
coverage | 0.0 to 1.0 for zone targets |
offset | Offset vector { x, y, z } |
track | Whether to track moving targets |
Zone specs:
| Key | Notes |
|---|---|
shape | SPHERE, DOME, CYLINDER, CUBOID, STATIC_RAY, ROTATING_RAY, TRANSLATING_RAY, CONE |
radius | Zone radius |
height | Cylinder height |
x, y, z | Cuboid half-extents |
borderRadius | Border width |
Target | Zone center target spec |
pointRadius | Ray thickness |
animationDuration | Animation length |
pitchPreRotation, yawPreRotation | Pre-rotation |
pitchRotation, yawRotation | Per-tick rotation |
Relative-vector specs:
| Key | Notes |
|---|---|
SourceTarget | Source target spec |
DestinationTarget | Destination target spec |
normalize | Whether to normalize |
multiplier | Scale factor |
offset | Offset vector |
Particle specs:
Particle specs can be a string, a single table, or an array of tables:
| Key | Notes |
|---|---|
particle | Particle name (e.g. "FLAME", "DUST") |
amount | Number of particles |
x, y, z | Offset/spread |
speed | Particle speed |
red, green, blue | Color for DUST / DUST_COLOR_TRANSITION |
toRed, toGreen, toBlue | Transition target color |
Why the bridge matters
The bridge lets you combine the expressiveness of Lua (conditionals, loops, state, randomness) with the battle-tested targeting, zone geometry, and particle systems of EliteScript. You keep your logic in Lua while still benefiting from all the targeting modes, zone shapes, and particle rendering that EliteScript provides.
Important bridge caveats
- Bridge handles are tied to the event context in which they were created. Do not store them in
context.statefor use in a later hook call. - Zone
watch()returns a task ID that you can cancel withcontext.scheduler:cancel_task() - Coverage values apply only to location-based resolution, not entity queries
Exact Signature Cheat Sheet
context.state
context.state -- plain Lua table, persists for runtime lifetime
context.log
context.log:info(message)
context.log:warn(message)
context.log:debug(message)
context.cooldowns
context.cooldowns:local_ready([key]) -> boolean
context.cooldowns:local_remaining([key]) -> number (ticks)
context.cooldowns:check_local(key, ticks) -> boolean
context.cooldowns:set_local(ticks[, key])
context.cooldowns:global_ready() -> boolean
context.cooldowns:set_global(ticks)
context.scheduler
context.scheduler:run_after(ticks, fn) -> taskId
context.scheduler:run_every(ticks, fn) -> taskId
context.scheduler:cancel_task(taskId)
context.event
context.event.damage_amount -- number (snapshot)
context.event.damage_cause -- string
context.event.spawn_reason -- string
context.event.entity -- entity wrapper
context.event.damager -- entity reference wrapper
context.event.projectile -- entity reference wrapper
context.event:cancel_event()
context.event:set_damage_amount(value)
context.event:multiply_damage_amount(multiplier)
context.players
context.players:current_target() -> player wrapper | nil
context.players:nearby_players(radius) -> { player, ... }
context.players:all_players_in_world() -> { player, ... }
context.entities
context.entities:get_nearby_entities(radius[, filter]) -> { entity, ... }
context.entities:get_entities_in_box(center, halfX, halfY, halfZ[, filter]) -> { entity, ... }
context.entities:get_all_entities([filter]) -> { entity, ... }
context.entities:get_direct_target_entity() -> entity | nil
context.entities:get_boss_spawn_location() -> location
context.player (extends entity)
context.player:send_message(message)
context.player:show_action_bar(message)
context.player:show_title(title[, subtitle][, fadeIn][, stay][, fadeOut])
context.player:show_boss_bar(title[, color][, style][, duration])
context.player:run_command(command)
context.player.game_mode -- string
context.boss
context.boss.name -- string
context.boss.uuid -- string
context.boss.entity_type -- string
context.boss.is_monster -- boolean
context.boss.level -- number
context.boss.health -- number (snapshot)
context.boss.maximum_health -- number (snapshot)
context.boss.damager_count -- number (snapshot)
context.boss.is_in_combat -- boolean
context.boss.exists -- boolean
context.boss.current_location -- location table
context.boss:is_alive() -> boolean
context.boss:is_ai_enabled() -> boolean
context.boss:is_on_ground() -> boolean
context.boss:get_health() -> number
context.boss:get_maximum_health() -> number
context.boss:get_damager_count() -> number
context.boss:get_location() -> location
context.boss:get_eye_location() -> location
context.boss:get_height() -> number
context.boss:get_ender_dragon_phase() -> string | nil
context.boss:set_ender_dragon_phase(phase)
context.boss:add_tag(tag[, duration])
context.boss:remove_tag(tag)
context.boss:has_tag(tag) -> boolean
context.boss:restore_health(amount)
context.boss:deal_damage(amount)
context.boss:teleport_to_location(location)
context.boss:despawn()
context.boss:set_ai_enabled(enabled[, duration])
context.boss:set_custom_name(name)
context.boss:reset_custom_name()
context.boss:set_custom_name_visible(visible)
context.boss:play_sound_at_self(sound[, volume][, pitch])
context.boss:spawn_particle_at_self(particleOrSpec[, count])
context.boss:spawn_particles_at_location(location, particle[, amount][, x][, y][, z][, speed])
context.boss:set_velocity_vector(vector)
context.boss:face_direction_or_location(vectorOrLocation)
context.boss:play_model_animation(name)
context.boss:navigate_to_location(location[, speed][, follow][, timeout])
context.boss:send_message(message[, range])
context.boss:get_nearby_players(range) -> { player, ... }
context.boss:get_target_player() -> player | nil
context.boss:get_nearby_players_in_zone(zoneDef) -> { player, ... }
context.boss:spawn_particles_in_zone(zoneDef, particle, amount, x, y, z, speed[, coverage])
context.boss:spawn_particles_in_zone_border(zoneDef, particle, amount, x, y, z, speed[, coverage])
context.boss:get_particles_from_self_toward_zone(zoneDef, particleKey[, speed]) -> { particleSpec, ... }
context.boss:get_particles_toward_self(zoneDef, particleKey[, speed]) -> { particleSpec, ... }
context.boss:spawn_particles_with_vector(particlesTable)
context.boss:summon_reinforcement(filename, zoneOrLocation[, duration]) -> entity | nil
context.boss:summon_projectile(entityType, origin, destination[, speed][, options]) -> entityRef | nil
context.boss:start_tracking_fireball_system([speed])
context.boss:handle_spirit_walk_damage(damageCause)
context.boss:shield_wall_is_active() -> boolean
context.boss:initialize_shield_wall([charges])
context.boss:shield_wall_absorb_damage(playerWrapper, amount) -> boolean
context.boss:deactivate_shield_wall()
context.boss:start_zombie_necronomicon(targetWrapper, filename)
context.boss:apply_potion_effect(effect, duration[, amplifier])
context.boss:set_equipment(slot, material[, options])
context.boss:set_fire_ticks(ticks)
context.boss:add_visual_freeze_ticks([ticks])
context.boss:place_temporary_block(material[, duration][, requireAir])
context.vectors
context.vectors:get_vector_between_locations(source, dest[, options]) -> vector
context.vectors:rotate_vector(vector[, pitch][, yaw]) -> vector
context.vectors:normalize_vector(vector) -> vector
context.world
context.world:play_sound_at_location(location, sound[, volume][, pitch])
context.world:spawn_particle_at_location(location, particleOrSpec[, count])
context.world:set_block_at_location(location, material[, requireAir])
context.world:place_temporary_block_at_location(location, material[, duration][, requireAir])
context.world:get_block_type_at_location(location) -> string
context.world:get_highest_block_y_at_location(location) -> number
context.world:get_blast_resistance_at_location(location) -> number
context.world:is_air_at_location(location) -> boolean
context.world:is_passable_at_location(location) -> boolean
context.world:is_passthrough_at_location(location) -> boolean
context.world:is_on_floor_at_location(location) -> boolean
context.world:is_standing_on_material(location, material) -> boolean
context.world:strike_lightning_at_location(location)
context.world:run_empowered_lightning_task_at_location(location)
context.world:set_world_time(time)
context.world:set_world_time(location, time)
context.world:set_world_weather(weather[, duration])
context.world:set_world_weather(location, weather[, duration])
context.world:run_console_command(command)
context.world:spawn_boss_at_location(filename[, location][, level]) -> entity | nil
context.world:spawn_custom_boss_at_location(filename, location[, options]) -> entity | nil
context.world:spawn_entity_at_location(entityType, location[, options]) -> entityRef | nil
context.world:spawn_falling_block_at_location(location, material[, options]) -> entityRef | nil
context.world:spawn_reinforcement_at_location(filename, location[, duration][, velocity]) -> entity | nil
context.world:spawn_fireworks_at_location(location, spec) -> entityRef | nil
context.world:spawn_splash_potion_at_location(location, spec) -> entityRef | nil
context.world:generate_fake_explosion(locations[, sourceLocation])
context.world:spawn_fake_gold_nugget_at_location(location, velocity[, gravity]) -> fakeProjectile | nil
context.world:run_fake_gold_nugget_damage(projectilesTable)
context.world:generate_player_loot([times])
context.world:drop_bonus_coins([multiplier])
context.zones
context.zones:get_entities_in_zone(zoneDef[, options]) -> { entity, ... }
context.zones:get_locations_in_zone(zoneDef[, options]) -> { location, ... }
context.zones:zone_contains(zoneDef, location[, mode]) -> boolean
context.zones:watch_zone(zoneDef, callbacks[, options])
context.script
context.script:target(spec) -> targetHandle
context.script:zone(spec) -> zoneHandle
context.script:relative_vector(spec[, actionLocation][, zoneHandle]) -> relVecHandle
context.script:damage(targetHandle, amount[, multiplier])
context.script:push(targetHandle, vectorOrHandle[, additive])
context.script:set_facing(targetHandle, vectorOrHandle)
context.script:spawn_particles(targetHandle, particleSpec)
targetHandle:entities() -> { entity, ... }
targetHandle:locations() -> { location, ... }
targetHandle:first_entity() -> entity | nil
targetHandle:first_location() -> location | nil
zoneHandle:full_target([coverage]) -> targetHandle
zoneHandle:border_target([coverage]) -> targetHandle
zoneHandle:full_locations([coverage]) -> { location, ... }
zoneHandle:border_locations([coverage]) -> { location, ... }
zoneHandle:full_entities() -> { entity, ... }
zoneHandle:border_entities() -> { entity, ... }
zoneHandle:contains(location[, mode]) -> boolean
zoneHandle:watch(callbacks[, mode]) -> taskId
relVecHandle:resolve() -> vector
context.settings
context.settings:warning_visual_effects_enabled() -> boolean
Hook-By-Hook Quick Guide
| Hook | context.player | context.event | Notes |
|---|---|---|---|
on_spawn | nil | Spawn event | Called once when elite spawns |
on_game_tick | nil | nil | Fires every server tick while the boss is alive |
on_boss_damaged | nil | Damage event | Any source damages the boss |
on_boss_damaged_by_player | Damaging player | Damage event | Player damages the boss |
on_boss_damaged_by_elite | nil | Damage event | Another elite damages the boss |
on_player_damaged_by_boss | Damaged player | Damage event | Boss damages a player |
on_enter_combat | nil | nil | Boss enters combat |
on_exit_combat | nil | nil | Boss exits combat |
on_heal | nil | nil | Boss heals |
on_boss_target_changed | New target (if player) | nil | Boss switches target |
on_death | nil | Death event | Boss dies |
on_phase_switch | nil | nil | Boss switches phase |
on_zone_enter | Entering entity (if player) | Zone event with .entity | Entity enters a script zone |
on_zone_leave | Leaving entity (if player) | Zone event with .entity | Entity leaves a script zone |
Exact Names Reference
Case sensitivity and normalization rules
- Hook names are lowercase with underscores:
on_spawn,on_boss_damaged_by_player - Context keys are lowercase with underscores:
boss,player,cooldowns - Bukkit enum values (particles, sounds, materials, entity types, potion effects) are normalized to uppercase internally, so you can write them in any case
- Native zone
kindvalues are lowercase:sphere,dome,cylinder,cuboid,cone,static_ray,rotating_ray,translating_ray - Bridge target/zone spec values use UPPER_SNAKE_CASE to match EliteScript YAML:
SELF,NEARBY_PLAYERS,SPHERE, etc.
Exact allowed top-level keys
The Lua file's return table recognizes these top-level callback keys:
on_spawn
on_game_tick
on_boss_damaged
on_boss_damaged_by_player
on_boss_damaged_by_elite
on_player_damaged_by_boss
on_enter_combat
on_exit_combat
on_heal
on_boss_target_changed
on_death
on_phase_switch
on_zone_enter
on_zone_leave
Exact context keys
state, boss, player, players, entities, event, cooldowns, scheduler,
vectors, world, settings, zones, script, log
Exact callback keys
Zone watcher callbacks:
on_enter, on_leave
Landing callbacks (for on_land option):
function(landing_location, spawned_entity)
Exact filter, mode, weather, and zone-kind values
Filters:
living, player, players, elite, elites, mob, mobs, all, entities
Modes:
full, border
Weather:
CLEAR, PRECIPITATION, RAIN, THUNDER
Zone kinds (native Lua):
sphere, dome, cylinder, cuboid, cone, static_ray, rotating_ray, translating_ray
Exact firework color names
WHITE, SILVER, GRAY, BLACK, RED, MAROON, YELLOW, OLIVE, LIME, GREEN,
AQUA, TEAL, BLUE, NAVY, FUCHSIA, PURPLE, ORANGE
Colors can also be specified as tables: { red = 255, green = 128, blue = 0 }
Exact firework effect types
BALL, BALL_LARGE, STAR, BURST, CREEPER
Exact location and vector table keys
Location tables:
x, y, z, yaw, pitch, world, direction
Location tables also include an add(dx, dy, dz) method that modifies in place and returns the table.
Vector tables:
x, y, z
Vectors can also be written as { 0, 1, 0 } (indexed form).
Exact boss bar values
Colors:
PINK, BLUE, RED, GREEN, YELLOW, PURPLE, WHITE
Styles:
SOLID, SEGMENTED_6, SEGMENTED_10, SEGMENTED_12, SEGMENTED_20
Exact bridge spec keys and literals
Target spec keys:
targetType, range, coverage, offset, track
Target type values:
SELF, DIRECT_TARGET, NEARBY_PLAYERS, ZONE_FULL, ZONE_BORDER, LOCATION, LOCATIONS,
LANDING_LOCATION, INHERIT_SCRIPT_ZONE_FULL, INHERIT_SCRIPT_ZONE_BORDER
(and other EliteScript target types as documented in the EliteScript Targets page)
Zone spec keys:
shape, radius, height, x, y, z, borderRadius, Target, pointRadius,
animationDuration, pitchPreRotation, yawPreRotation, pitchRotation, yawRotation
Shape values:
SPHERE, DOME, CYLINDER, CUBOID, STATIC_RAY, ROTATING_RAY, TRANSLATING_RAY, CONE
Relative-vector spec keys:
SourceTarget, DestinationTarget, normalize, multiplier, offset
Particle spec keys:
particle, amount, x, y, z, speed, red, green, blue, toRed, toGreen, toBlue,
to_red, to_green, to_blue
Built-in em Helper Namespace
The em namespace is available globally in all Lua power files. It provides convenience constructors.
| Function | Notes |
|---|---|
em.create_location(x, y, z[, world][, yaw][, pitch]) | Creates a location table |
em.create_vector(x, y, z) | Creates a vector table |
Location tables created via em.create_location include an add(dx, dy, dz) method.
Zone builder helpers
The em.zone sub-table provides builder functions that return zone definition tables with chainable mutators:
| Function | Parameters | Mutators |
|---|---|---|
em.zone.create_sphere_zone(radius) | radius | :set_center(location) |
em.zone.create_dome_zone(radius) | radius | :set_center(location) |
em.zone.create_cylinder_zone(radius, height) | radius, height | :set_center(location) |
em.zone.create_cuboid_zone(x, y, z) | x, y, z (half-extents) | :set_center(location) |
em.zone.create_cone_zone(length, radius) | length, radius | :set_origin(location), :set_destination(location) |
em.zone.create_static_ray_zone(length, thickness) | length, thickness | :set_origin(location), :set_destination(location) |
em.zone.create_rotating_ray_zone(length, point_radius, animation_duration) | length, point_radius, animation_duration | :set_origin(location), :set_destination(location) |
em.zone.create_translating_ray_zone(length, point_radius, animation_duration) | length, point_radius, animation_duration | :set_origin(location), :set_destination(location) |
Mutators return the table itself, allowing chaining:
local zone = em.zone.create_sphere_zone(10):set_center(context.boss:get_location())
Runtime Model
Each boss gets its own Lua runtime instance
When a boss spawns with a Lua power, EliteMobs creates a new LuaPowerInstance for that boss-power pair. This instance holds:
- The compiled script table (from the shared
LuaPowerDefinition) - A private
context.statetable - A set of owned scheduled tasks
- A set of zone watchers
State isolation
Each runtime instance has its own state table. Two bosses using the same Lua power file do not share state.
Scheduled task ownership and cleanup
All tasks created via context.scheduler:run_after() and context.scheduler:run_every() are tracked by the runtime. When the boss is removed (death, despawn, or shutdown), all owned tasks are automatically cancelled. You do not need to manually clean up tasks on death.
Per-tick clock behavior
The runtime registers a per-tick clock if either:
- The script defines an
on_game_tickhook, or - At least one zone watcher is active
The clock is unregistered when neither condition is true.
Error and performance behavior
- If a hook or callback throws an exception, the runtime is immediately shut down and a warning is logged
- If a single hook or callback execution exceeds 50ms, the runtime is shut down and a warning is logged
- This protects the server from runaway scripts while still allowing complex logic within reasonable bounds
Lua Environment and Sandbox
Unsafe globals removed
The following globals are removed from the Lua environment and will return nil:
debug, dofile, io, load, loadfile, luajava, module, os, package, require
Standard helpers that still work
All standard Lua library functions that are not in the removed list remain available:
string.*(string manipulation)table.*(table manipulation)math.*(math functions)pairs(),ipairs(),next()type(),tostring(),tonumber()pcall(),xpcall(),error()select(),unpack()setmetatable(),getmetatable()rawget(),rawset(),rawequal(),rawlen()coroutine.*
Note about em namespace
The em namespace is set on the global environment and is available to all Lua power files. It is not per-instance -- all instances share the same em helper functions. The em functions are pure constructors and do not carry any state.
