Skip to main content

Lua Scripting: World & Environment

webapp_banner.jpg

This page covers the EliteMobs boss extensions to context.world, plus context.vectors, context.settings, and context.event. These let Lua powers spawn entities, play effects, query blocks, and change world state. If you are new to Lua powers, start with Getting Started first.

EliteMobs boss context

EliteMobs boss powers reuse the MagmaCore Lua sandbox. Boss context.world starts from the shared MagmaCore world table, so generic coordinate helpers such as get_block_at(...), set_block_at(...), and spawn_particle(...) are still available. This page focuses on the EliteMobs boss-specific context.world, context.vectors, context.settings, and context.event additions and overrides. For the generic world API, see MagmaCore Lua Scripting Engine.

Where a same-named method exists in both, the EliteMobs version wins. The methods documented below keep EliteMobs semantics, including protection bypass on lightning, the richer particle spec, and the temporary-block tracker. Other shared methods remain available, including get_entity(uuid), block_is_passable(x, y, z), location_is_protected(location), spawn_dust(...), and raycast(...). Use the shared API reference for their arguments and unloaded-chunk behavior; those guarantees do not automatically apply to an EliteMobs override.

FreeMinecraftModels loot helpers are not available here

FreeMinecraftModels adds drop_elitemobs_procedural_loot, drop_elitemobs_random_loot, drop_elitemobs_custom_loot and start_elitemobs_transport to context.world in its own prop scripts only. Each plugin carries a separate copy of the shared scripting library, so these helpers do not appear in EliteMobs boss powers or NPC scripts, even with FreeMinecraftModels installed. Boss powers use generate_player_loot and drop_bonus_coins instead.


context.world​

The world table provides methods for spawning entities, playing effects, modifying blocks, and changing world state. These methods accept colon syntax (world:method()) or dot syntax without an explicit self argument.

The boss overrides below convert a location table using x, y, z, optional yaw/pitch, and a loaded world name in world. Missing coordinates become 0; an omitted world uses the boss's current world, but an explicitly unknown world fails conversion. They also accept a nested current_location table. A nil or non-table location defaults to the boss location. Shared methods retain their separate location contract and the world captured when that table was created.

World changes and spawned entities are not automatically undone when the Lua instance closes. Script-owned monitors stop, but independent entity-removal timers, explosion regeneration, empowered lightning and gold-projectile tasks have their own lifetimes. Block and spawn overrides do not automatically apply location_is_protected or the shared unloaded-chunk guards; check the relevant constraints before changing the world.


world:spawn_particle_at_location(location, particleSpec)​

Spawns particles at a location. The second argument can be a particle name string or a particle spec table. An optional third integer argument supplies the count when amount is absent; its default is 1. Names are uppercased before lookup. Invalid names or unsupported particle data produce a warning and no particle.

ParameterTypeNotes
locationlocation tableWhere to spawn particles
particleSpecstring or tableParticle name or a particle spec table (see below)
Example
return {
api_version = 1,
on_enter_combat = function(context)
-- Simple particle by name
context.world:spawn_particle_at_location(context.boss:get_location(), "FLAME")

-- Full particle spec table with red dust
context.world:spawn_particle_at_location(context.boss:get_location(), {
particle = "DUST",
amount = 10,
x = 0.5,
y = 0.5,
z = 0.5,
speed = 0.02,
red = 255,
green = 0,
blue = 0,
})
end
}

Particle Spec Table Format​

KeyTypeDefaultNotes
particlestringrequiredParticle name
amountint1Number of particles
x, y, znumber0Spread/offset in each axis
speednumber0Particle speed
red, green, blueint255RGB color for DUST and DUST_COLOR_TRANSITION
toRed, toGreen, toBlueint255Transition target color for DUST_COLOR_TRANSITION
tip

For DUST_COLOR_TRANSITION, you can also use snake_case keys: to_red, to_green, to_blue. Camel-case values take precedence. Both dust types use a fixed size of 1; RGB components must be in 0..255. Other particles receive no extra data payload, so data-dependent particles are not all supported by this helper.

warning

Unlike EliteScript YAML configs, Lua particle names do not support legacy particle name conversions. You must use the current Spigot API names (e.g., FIREWORK not FIREWORKS_SPARK, SMOKE not SMOKE_NORMAL, DUST not REDSTONE). See the valid particles list for the full list of current names and their legacy equivalents.


world:play_sound_at_location(location, sound, volume, pitch)​

Plays a sound at a location.

ParameterTypeDefaultNotes
locationlocation tableWhere to play the sound
soundstringMinecraft sound key (e.g. "entity.blaze.shoot") or a Spigot Sound enum name. Resource-pack keys work too.
volumenumber1.0Volume
pitchnumber1.0Pitch
Example
return {
api_version = 1,
on_spawn = function(context)
context.world:play_sound_at_location(
context.boss:get_location(),
"entity.wither.spawn",
1.0,
0.5
)
end
}

world:strike_lightning_at_location(location)​

Strikes real, damaging lightning at a location and enables EliteMobs' lightning-spawn bypass. This is not the visual-only shared lightning helper, and the bypass is not a guarantee that every other plugin's damage or protection rules are ignored.

ParameterTypeNotes
locationlocation tableWhere to strike
Example
return {
api_version = 1,
on_boss_damaged_by_player = function(context)
if context.player == nil then return end
if not context.cooldowns:check_local("lightning", 100) then return end
context.world:strike_lightning_at_location(context.player:get_location())
context.player:send_message("&eA bolt of lightning strikes you!")
end
}

world:spawn_entity_at_location(entityType, location, options)​

Spawns a vanilla Minecraft entity directly in the location's world. Unknown entity names return nil; a recognized but non-spawnable type can still fail. This helper does not automatically set a projectile shooter or make the entity an elite reinforcement.

ParameterTypeNotes
entityTypestringEntity type name (e.g. "FIREBALL", "ARROW")
locationlocation tableWhere to spawn
optionstable (optional)Spawn options (see below)

Entity Spawn Options​

KeyTypeDefaultNotes
velocityvector tablenilInitial velocity {x, y, z}
effectstringnilEntityEffect to play on spawn
durationint0Positive values schedule removal after this many ticks; nonpositive values add no removal timer
on_landfunctionnilfunction(land_location, entity_ref) when grounded, invalid, or past max_ticks; not a projectile-impact event and not proof the entity landed
max_ticksint6000Max ticks to monitor before forcing the on_land callback
persistentbooleanMinecraft's defaultfalse keeps the entity out of the chunk save, so a shutdown or chunk unload mid-effect cannot leave it in the world

Returns an entity wrapper table. Non-living entities (FIREBALL, ARROW, TNT, ...) come back as a non-living reference wrapper where is_valid() is a method. Living entity types (ZOMBIE, GIANT, ...) come back as a full living-entity wrapper instead, where is_valid is a boolean field -- calling entity:is_valid() on one of those raises attempt to call a boolean value.

The landing monitor polls every tick while the script is active and stops with its owned tasks. The positive duration timer is independent and can still remove the entity after the script closes. Unknown effect names are ignored.

Example
return {
api_version = 1,
on_boss_damaged_by_player = function(context)
if context.player == nil then return end
if not context.cooldowns:check_local("fireball_spawn", 100) then return end
-- Spawn a fireball aimed at the player
local boss_loc = context.boss:get_location()
local dir = context.vectors.get_vector_between_locations(boss_loc, context.player:get_location())
dir = context.vectors.normalize_vector(dir)

context.world:spawn_entity_at_location("FIREBALL", boss_loc, {
velocity = { x = dir.x * 2, y = dir.y * 2, z = dir.z * 2 },
duration = 100,
})
end
}
Example
return {
api_version = 1,
on_enter_combat = function(context)
-- Spawn a primed TNT with a landing callback
context.world:spawn_entity_at_location("TNT", context.boss:get_location(), {
velocity = { x = 0, y = 1.5, z = 0 },
on_land = function(land_location, entity_ref)
context.world:spawn_particle_at_location(land_location, {
particle = "EXPLOSION_EMITTER",
amount = 1,
})
end,
})
end
}

world:spawn_display_at_location(location, options)​

Spawns an item or block display: a floating visual with no hitbox, gravity or AI. Use it for orbiting stones, thrown props and other effects that only need to be seen, instead of styling an armor stand. The display is centered on location and turned by its yaw.

OptionTypeDefaultNotes
itemstringMaterial shown as an item. A block item such as "AMETHYST_BLOCK" shows as a centered block
blockstringBlock shown as a block display, as a material or block data such as "lantern[hanging=true]"
scalenumber or vector table1A number scales every axis; {x, y, z} scales each. At 1 a block is one block wide
durationint0Positive values remove the display after this many ticks
teleport_durationint0Ticks the client takes to glide to each new location, 0 to 59. Use 1 when you teleport the display every tick
billboardstringFIXEDFIXED, VERTICAL, HORIZONTAL or CENTER
glowingbooleanfalseOutline glow
brightnessintworld light0 to 15, overriding the light at the display
bedrock_fallbackbooleantrueSee below

Give exactly one of item or block. A missing or unknown item or block, both at once, or a scale that is not positive returns nil and logs a warning naming the power. An unknown billboard value keeps FIXED.

Displays are never saved with the chunk. They are removed when duration runs out, when you call remove(), or when the power shuts down, whichever comes first.

Bedrock clients cannot render display entities. Bedrock players who are in the world when the display spawns instead see an invisible armor stand wearing the same item, or the block's item for a block display, and the display is hidden from them. The stand follows the display and is removed with it. Bedrock players who enter the world later get no stand, and a block that has no item form, such as fire, gets no stand at all. Turn this off with bedrock_fallback = false for effects Bedrock players do not need to see.

The returned wrapper has uuid and entity_type and these methods:

MethodNotes
is_valid(), is_alive()Whether the display still exists
get_location()Current location
teleport_to_location(location)Moves the display, and its Bedrock stand
remove()Removes the display and its Bedrock stand
set_scale(scale)Same values as the scale option
set_item(material)Item displays only; returns false otherwise
set_block(block)Block displays only; returns false otherwise
set_glowing(enabled)Outline glow
set_brightness(level)0 to 15, or nil to use the world's light again
set_teleport_duration(ticks)Same as the teleport_duration option
Example
-- Three amethyst stones circle the target for three seconds.
return {
api_version = 1,
on_boss_damaged_by_player = function(context)
if context.player == nil or not context.cooldowns:check_local("orbit", 200) then return end
local target = context.player
local stones = {}
for i = 1, 3 do
stones[i] = context.world:spawn_display_at_location(target:get_location(), {
item = "AMETHYST_BLOCK", scale = 0.3, duration = 60, teleport_duration = 1
})
end
local elapsed = 0
local task
task = context.scheduler:run_every(1, function(context)
elapsed = elapsed + 1
if elapsed >= 60 then
context.scheduler:cancel_task(task)
return
end
local center = target:get_location()
for i = 1, 3 do
local angle = elapsed * 0.2 + i * (2 * math.pi / 3)
if stones[i] ~= nil and stones[i]:is_valid() then
stones[i]:teleport_to_location(em.create_location(
center.x + math.cos(angle) * 1.5, center.y + 1.2, center.z + math.sin(angle) * 1.5, center.world, 0, 0))
end
end
end)
end
}

world:spawn_falling_block_at_location(location, material, options)​

Spawns a falling block entity using a block material. With on_land, EliteMobs intercepts its block-change event, cancels placement, and calls function(land_location, entity_ref) once. Without that callback, normal falling-block placement can occur. This helper has no duration or max_ticks option and no invalid-entity/timeout callback.

ParameterTypeNotes
locationlocation tableWhere to spawn
materialstringMaterial name (e.g. "STONE", "MAGMA_BLOCK")
optionstable (optional)Spawn options (see below)

Falling Block Options​

KeyTypeDefaultNotes
velocityvector tablenilInitial velocity {x, y, z}
drop_itembooleanfalseWhether the block drops as an item
hurt_entitiesbooleanfalseWhether the block damages entities it lands on
on_landfunctionnilCallback function(land_location, entity_ref) when the block lands

Returns a non-living entity reference table, or nil if the location or material cannot be resolved. A recognized non-block material can still fail when creating block data.

Example
return {
api_version = 1,
on_enter_combat = function(context)
-- Rain magma blocks from above
local loc = context.boss:get_location()
for i = 1, 5 do
local offset_loc = {
x = loc.x + math.random(-3, 3),
y = loc.y + 10,
z = loc.z + math.random(-3, 3),
world = loc.world
}
context.world:spawn_falling_block_at_location(offset_loc, "MAGMA_BLOCK", {
velocity = { x = 0, y = -0.5, z = 0 },
hurt_entities = true,
on_land = function(land_location, entity_ref)
context.world:spawn_particle_at_location(land_location, { particle = "LAVA", amount = 8 })
end,
})
end
end
}

world:spawn_custom_boss_at_location(filename, location, options)​

Spawns an EliteMobs custom boss from a config file.

ParameterTypeNotes
filenamestringBoss config filename (e.g. "my_boss.yml")
locationlocation tableWhere to spawn
optionstable (optional)Spawn options (see below)

Custom Boss Spawn Options​

KeyTypeDefaultNotes
levelintspawned boss's config levelOverride the spawned boss level. If omitted, its own config and dynamic-level rules apply; this does not inherit the casting boss's level.
silentbooleanfalseSuppress spawn messages
velocityvector tablenilInitial velocity
add_as_reinforcementbooleanfalseRegister as a reinforcement of the current boss

Returns an entity wrapper table, or nil if the boss could not be created.

Example
return {
api_version = 1,
on_enter_combat = function(context)
local minion = context.world:spawn_custom_boss_at_location(
"skeleton_minion.yml",
context.boss:get_location(),
{ level = 10, add_as_reinforcement = true }
)
if minion ~= nil then
context.boss:send_message("&cMinions, arise!")
end
end
}

world:spawn_boss_at_location(filename, location, level)​

A simpler boss spawn method. Omitted location and level use the casting boss's location and level. It does not register the result as a reinforcement. Omit the third argument to use that default; explicitly passing nil there is not accepted.

ParameterTypeDefaultNotes
filenamestringBoss config filename
locationlocation tableboss locationWhere to spawn (optional, defaults to boss location)
levelintboss levelOverride spawn level (optional)

Returns an entity wrapper table, or nil.

Example
return {
api_version = 1,
on_enter_combat = function(context)
context.world:spawn_boss_at_location("zombie_guard.yml", context.boss:get_location(), 5)
context.boss:send_message("&cGuards, defend me!")
end
}

world:spawn_reinforcement_at_location(filename, location, duration, velocity)​

Spawns silently through the EliteMobs reinforcement system, records the summoner, and inherits normalized combat when the custom-boss summoner uses it. The reinforcement's own configuration and dynamic-level rules determine its level; duration is an escape timer, not a level override.

ParameterTypeDefaultNotes
filenamestringBoss config filename
locationlocation tableWhere to spawn
durationint0Escape timer in ticks; 0 adds no timer. This argument does not override the reinforcement level.
velocityvector tablenilInitial velocity (optional)

Returns an entity wrapper table, or nil.

Example
return {
api_version = 1,
on_enter_combat = function(context)
context.world:spawn_reinforcement_at_location(
"necro_skeleton.yml",
context.boss:get_location(),
0,
{ x = 0, y = 0.5, z = 0 }
)
context.boss:send_message("&5Rise, my servant!")
end
}

world:spawn_fireworks_at_location(location, spec)​

Spawns a real firework entity, with no automatic damage suppression. Provide at least one valid color per effect; an effect without colors can fail during construction.

ParameterTypeNotes
locationlocation tableWhere to spawn
spectableFirework specification (see below)

Firework Spec Table​

KeyTypeDefaultNotes
powerint1Flight power (height)
velocityvector tablenilInitial velocity
shot_at_anglebooleantrueWhether the firework is shot at an angle (used when velocity is set)
effectstable of tablesnilArray of firework effect specs. If omitted, the top-level spec is treated as a single effect.

Firework Effect Spec​

KeyTypeDefaultNotes
typestring"BALL_LARGE""BALL", "BALL_LARGE", "STAR", "BURST", "CREEPER"
flickerbooleantrueTwinkle effect
trailbooleantrueTrail effect
colorstablerequired for each effectNonempty array of color names or {red = 255, green = 0, blue = 0} tables
fade_colorstablenilArray of fade color names or {red, green, blue} tables

Color names: "WHITE", "SILVER", "GRAY", "BLACK", "RED", "MAROON", "YELLOW", "OLIVE", "LIME", "GREEN", "AQUA", "TEAL", "BLUE", "NAVY", "FUCHSIA", "PURPLE", "ORANGE"

Returns a non-living entity reference table, or nil if the location cannot be resolved. Call :detonate() to request detonation. Type and named-color lookup ignore case; an unknown type falls back to BALL_LARGE and an unknown color to white. RGB values must be in 0..255.

Example
return {
api_version = 1,
on_spawn = function(context)
local fw = context.world:spawn_fireworks_at_location(context.boss:get_location(), {
power = 0,
effects = {
{
type = "STAR",
flicker = true,
trail = true,
colors = { "RED", "ORANGE", { red = 255, green = 200, blue = 0 } },
fade_colors = { "YELLOW" },
},
},
})

if fw == nil then return end
-- Detonate on the next tick for a visual burst
context.scheduler:run_after(1, function()
fw:detonate()
end)
end
}

world:spawn_splash_potion_at_location(location, spec)​

Spawns a real thrown splash potion. Unknown Bukkit effect names are warned about and skipped. This helper does not set a shooter or apply the instance-effect filter used by direct boss potion methods; normal potion splash behavior applies.

ParameterTypeNotes
locationlocation tableWhere to spawn
spectablePotion specification (see below)

Splash Potion Spec Table​

KeyTypeNotes
velocityvector tableInitial velocity for the thrown potion
effectstable of tablesArray of potion effect specs

Potion Effect Spec​

KeyTypeDefaultNotes
typestringrequiredPotion effect type name (e.g. "SLOWNESS", "POISON")
durationint0Duration in ticks
amplifierint0Effect amplifier (0 = level I)
overwritebooleantrueReplace an earlier effect of the same type in this potion's metadata; not a rule for effects already on a player

Returns an entity reference table, or nil.

Example
return {
api_version = 1,
on_boss_damaged_by_player = function(context)
if context.player == nil then return end
if not context.cooldowns:check_local("potion_throw", 200) then return end

local dir = context.vectors.get_vector_between_locations(
context.boss:get_location(),
context.player:get_location()
)
dir = context.vectors.normalize_vector(dir)

context.world:spawn_splash_potion_at_location(context.boss:get_location(), {
velocity = { x = dir.x * 1.5, y = 0.5, z = dir.z * 1.5 },
effects = {
{ type = "SLOWNESS", duration = 100, amplifier = 1 },
{ type = "WEAKNESS", duration = 60, amplifier = 0 },
},
})
end
}

world:place_temporary_block_at_location(location, material, duration, requireAir)​

Places a tracked block that restores its previous block data after a positive duration. This saves block data, not container contents. The original block comes back when the timer ends, when the chunk or world unloads, or when the plugin shuts down, but only while the block still holds the temporary block, so a later edit is not overwritten. Placing again on a block that still holds a temporary block restarts its timer and keeps the first saved original. Blocks with block entities, such as chests and signs, unloaded chunks, and blocks held by another temporary-block owner are skipped. Breaking a tracked block drops nothing and ends tracking without restoring. Use a block material. This boss override returns nil, including when requireAir or a skip prevents placement; it does not report success or check region protection automatically.

ParameterTypeDefaultNotes
locationlocation tableWhere to place
materialstringMaterial name
durationint0Ticks before restoration; 0 or a negative value places the block permanently without tracking
requireAirbooleanfalseIf true, only places if the block is currently air
Example
return {
api_version = 1,
on_enter_combat = function(context)
-- Create a temporary ice floor under the boss
local loc = context.boss:get_location()
for dx = -2, 2 do
for dz = -2, 2 do
context.world:place_temporary_block_at_location(
{ x = loc.x + dx, y = loc.y - 1, z = loc.z + dz, world = loc.world },
"PACKED_ICE",
100,
false
)
end
end
end
}

world:set_block_at_location(location, material, requireAir)​

Sets a block permanently through the temporary-block manager, with no restoration timer and no tracking, so the change stays after the plugin shuts down. If the block currently holds a timed temporary block, that block stops being tracked and is not restored. Blocks held by another temporary-block owner are left unchanged. Use a positive duration with place_temporary_block_at_location when the original block should be restored on a timer.

ParameterTypeDefaultNotes
locationlocation tableWhere to place
materialstringMaterial name
requireAirbooleanfalseIf true, only places if the block is currently air
Example
return {
api_version = 1,
on_enter_combat = function(context)
-- Place fire at the boss's location
context.world:set_block_at_location(context.boss:get_location(), "FIRE", true)
end
}

world:get_block_type_at_location(location)​

Returns the uppercase material name at a location, or nil if the location cannot be resolved. Unlike the shared coordinate query, this override accesses the block directly without an unloaded-chunk guard.

ParameterTypeNotes
locationlocation tableLocation to query
Example
return {
api_version = 1,
on_enter_combat = function(context)
local block_type = context.world:get_block_type_at_location(context.boss:get_location())
if block_type == "WATER" then
context.boss:send_message("&bThe boss is empowered by water!")
context.boss:apply_potion_effect("SPEED", 200, 1)
end
end
}

world:get_highest_block_y_at_location(location)​

Returns Bukkit's highest-block Y coordinate at the given X/Z position, or nil if the location cannot be resolved. It does not check whether the chunk is already loaded or whether the destination is safe for teleportation.

ParameterTypeNotes
locationlocation tableLocation to query (X and Z are used)
Example
return {
api_version = 1,
on_boss_damaged_by_player = function(context)
if context.player == nil then return end
if not context.cooldowns:check_local("skyport", 200) then return end
local loc = context.player:get_location()
local ground_y = context.world:get_highest_block_y_at_location(loc)
-- Teleport the player to the surface
context.player:teleport_to_location({
x = loc.x, y = ground_y + 1, z = loc.z, world = loc.world
})
context.player:send_message("&eYou are teleported to the surface!")
end
}

world:get_blast_resistance_at_location(location)​

Returns the material's blast resistance at a location, or 0 when the location cannot be resolved.

ParameterTypeNotes
locationlocation tableLocation to query
Example
return {
api_version = 1,
on_enter_combat = function(context)
local resistance = context.world:get_blast_resistance_at_location(context.boss:get_location())
context.log:info("Blast resistance at boss: " .. resistance)
end
}

world:is_air_at_location(location)​

Returns true if the block at the location is air.

ParameterTypeNotes
locationlocation tableLocation to query
Example
return {
api_version = 1,
on_enter_combat = function(context)
local loc = context.boss:get_location()
local above = { x = loc.x, y = loc.y + 2, z = loc.z, world = loc.world }
if context.world:is_air_at_location(above) then
-- There is space above the boss, launch upward
context.boss:set_velocity_vector({ x = 0, y = 1.5, z = 0 })
end
end
}

world:is_passable_at_location(location)​

Returns Bukkit's Block.isPassable() result, or false for an unresolved location. This is a single-block query, not a check that a whole entity can fit or navigate there.

ParameterTypeNotes
locationlocation tableLocation to query
Example
return {
api_version = 1,
on_enter_combat = function(context)
if context.world:is_passable_at_location(context.boss:get_location()) then
context.log:info("Boss is in a passable block")
end
end
}

world:is_passthrough_at_location(location)​

Returns true if the block at the location is not solid (similar to passable, but based on solid check).

ParameterTypeNotes
locationlocation tableLocation to query
Example
return {
api_version = 1,
on_enter_combat = function(context)
local loc = context.boss:get_location()
local above = { x = loc.x, y = loc.y + 1, z = loc.z, world = loc.world }
if context.world:is_passthrough_at_location(above) then
context.log:info("Boss can move upward")
end
end
}

world:is_on_floor_at_location(location)​

Returns true if the block at the location is non-solid and the block one Y unit below is solid. This does not inspect an entity's grounded state, collision box, or headroom.

ParameterTypeNotes
locationlocation tableLocation to query
Example
return {
api_version = 1,
on_enter_combat = function(context)
if context.world:is_on_floor_at_location(context.boss:get_location()) then
context.boss:send_message("&aThe boss slams the ground!")
context.world:spawn_particle_at_location(context.boss:get_location(), {
particle = "CLOUD",
amount = 30,
})
end
end
}

world:is_standing_on_material(location, material)​

Returns true if the block directly below the location matches the given material.

ParameterTypeNotes
locationlocation tableLocation to query
materialstringMaterial name to check
Example
return {
api_version = 1,
on_boss_damaged_by_player = function(context)
if context.player == nil then return end
if context.world:is_standing_on_material(context.player:get_location(), "SOUL_SAND") then
context.player:send_message("&8The soul sand saps your strength!")
context.player:apply_potion_effect("SLOWNESS", 60, 2)
end
end
}

world:set_world_time(time) / world:set_world_time(location, time)​

Sets the entire world's time. You can optionally pass a location to select the world. The old time is not restored when the script closes.

ParameterTypeNotes
locationlocation table (optional)Which world to affect. Defaults to the boss world.
timeintWorld time in ticks (0 = dawn, 6000 = noon, 13000 = night, 18000 = midnight)
Example
return {
api_version = 1,
on_enter_combat = function(context)
-- Set to midnight when combat starts
context.world:set_world_time(18000)
context.boss:send_message("&8Darkness falls...")
end
}

world:set_world_weather(weather, duration) / world:set_world_weather(location, weather, duration)​

Sets weather in the boss world, or the world of the optional location. Names ignore case; unknown names only warn. RAIN/CLEAR set the weather-duration timer, while THUNDER sets the thunder-duration timer. This affects the entire world and does not restore the previous state when the script closes.

ParameterTypeDefaultNotes
locationlocation table (optional)boss worldWhich world to affect
weatherstring"CLEAR", "RAIN" (or "PRECIPITATION"), "THUNDER"
durationint6000Weather duration in ticks
Example
return {
api_version = 1,
on_enter_combat = function(context)
-- Start a thunderstorm for 200 ticks
context.world:set_world_weather("THUNDER", 200)
context.boss:send_message("&eA storm gathers!")
end
}

world:generate_fake_explosion(blockLocations, sourceLocation)​

Removes actual blocks and creates falling-block debris through EliteMobs' explosion-regeneration system. The debris has entity damage enabled, so this is not a harmless particle effect. doExplosionRegen must be enabled; the WorldGuard explosion-regeneration flag is checked when a source location is supplied. Air, fire, liquids and tracked temporary blocks are skipped, and dependent neighboring blocks can be included. Restoration starts after 1200 ticks and processes one recorded block per tick. Keep all input locations in the boss's world. The operation returns nil and is not undone by closing the script.

ParameterTypeNotes
blockLocationstable of location tablesArray of block locations to "explode"
sourceLocationlocation table (optional)Explosion source for directional calculations
Example
return {
api_version = 1,
on_enter_combat = function(context)
local loc = context.boss:get_location()
local blocks = {}
for dx = -1, 1 do
for dz = -1, 1 do
table.insert(blocks, { x = loc.x + dx, y = loc.y, z = loc.z + dz, world = loc.world })
end
end
context.world:generate_fake_explosion(blocks, loc)
end
}

world:run_console_command(command)​

Dispatches a console command immediately as the server and returns nil, without exposing the command's success result. No player or boss placeholders are substituted automatically.

Vanilla commands report their result, and with the default broadcast-console-to-ops=true the server shows every result to all online operators. Commands run often, such as data merge entity, kill or damage, flood their chat. Use the native methods instead: spawn_display_at_location for visuals, the armor stand methods for stands, entity:remove() to remove what a script spawned, and entity:deal_custom_damage(amount) for exact damage from the boss.

ParameterTypeNotes
commandstringThe command to run (without the leading /)
Example
return {
api_version = 1,
on_enter_combat = function(context)
context.world:run_console_command("say The boss has entered phase 2!")
end
}

world:run_empowered_lightning_task_at_location(location)​

Starts an independent Bukkit task at the captured location. It emits SOUL_FIRE_FLAME for 60 iterations, then strikes real lightning with the spawn bypass and launches a downward fireball with explosion yield 5, tagged as ender_dragon_empowered_lightning.yml. This is a damaging attack, not just a visual. Closing or pausing the Lua script does not cancel this task, and the helper does not consult the warning-effects setting.

ParameterTypeNotes
locationlocation tableWhere to strike
Example
return {
api_version = 1,
on_enter_combat = function(context)
context.world:run_empowered_lightning_task_at_location(context.boss:get_location())
context.boss:send_message("&eFeel the power of the storm!")
end
}

world:spawn_fake_gold_nugget_at_location(location, velocity, hasGravity)​

Creates a packet-based gold nugget visual for nearby players; players and hoppers cannot pick it up. Creation alone does not advance it or deal damage. Pass it to run_fake_gold_nugget_damage once as part of a batch, or remove it explicitly.

ParameterTypeDefaultNotes
locationlocation tableSpawn location
velocityvector tableInitial velocity
hasGravitybooleanfalseWhether the projectile has gravity

Returns a fake projectile table, or nil for an unresolved location/vector, with methods: get_location(), set_gravity(bool), remove(), is_removed().

Example
return {
api_version = 1,
on_boss_damaged_by_player = function(context)
if context.player == nil then return end
if not context.cooldowns:check_local("nugget", 60) then return end

local dir = context.vectors.get_vector_between_locations(
context.boss:get_location(),
context.player:get_location()
)
dir = context.vectors.normalize_vector(dir)

local nugget = context.world:spawn_fake_gold_nugget_at_location(
context.boss:get_location(),
{ x = dir.x, y = dir.y, z = dir.z }
)
if nugget ~= nil then
context.world:run_fake_gold_nugget_damage({ nugget })
end
end
}

world:run_fake_gold_nugget_damage(projectiles)​

Starts an independent Bukkit task that advances and checks a batch every tick. Call this once per batch: each call starts another task. It queries living entities in a box with half-size 0.5 at the new position, skips the originating boss and blocking players, and submits custom damage of 1 through the boss damage policy. A collision can remove the projectile even when that damage is rejected. Ground contact or the 100-tick timeout also removes it. This is a sampled collision check, not a swept ray; closing or pausing the Lua instance does not cancel the task.

ParameterTypeNotes
projectilestableArray of fake projectile tables from spawn_fake_gold_nugget_at_location
Example
return {
api_version = 1,
on_enter_combat = function(context)
-- Keep this batch separate from later combat entries.
local projectiles = {}
local loc = context.boss:get_location()
for i = 1, 5 do
local angle = (i / 5) * math.pi * 2
local nugget = context.world:spawn_fake_gold_nugget_at_location(
loc,
{ x = math.cos(angle) * 0.5, y = 0.3, z = math.sin(angle) * 0.5 }
)
if nugget ~= nil then table.insert(projectiles, nugget) end
end

-- Start the batch once; the helper runs its own per-tick task.
context.world:run_fake_gold_nugget_damage(projectiles)
-- Remove any surviving projectiles after 3 seconds.
context.scheduler:run_after(60, function()
for _, projectile in ipairs(projectiles) do
projectile:remove()
end
end)
end
}

world:generate_player_loot(times)​

Runs the normal player-loot generator times times; nonpositive values do nothing. It requires eliteLoot, no triggered anti-exploit state, loaded player data and recorded damage of at least 10% of maximum health. Instanced lockout players are skipped. Each pass can include coins and, when random loot is enabled, random/special loot and scrolls under their normal settings and party rules. It does not rerun every authored custom drop or guarantee one item per roll. Repeated calls grant additional reward attempts; there is no once-per-boss guard.

ParameterTypeDefaultNotes
timesint1Number of loot rolls
Example
return {
api_version = 1,
on_boss_damaged_by_player = function(context)
local pct = context.boss:get_health() / context.boss:get_maximum_health()
if pct < 0.5 and not context.boss:has_tag("bonus_loot") then
context.boss:add_tag("bonus_loot")
context.world:generate_player_loot(2)
context.boss:send_message("&6Bonus loot drops!")
end
end
}

world:drop_bonus_coins(multiplier)​

Drops bonus coins for tracked players whose recorded damage exceeds 10% of the boss's maximum health. NPCs and players without loaded EliteMobs data are skipped. The amount uses the player's scaled reward level multiplied by multiplier.

ParameterTypeDefaultNotes
multipliernumber2.0Coin amount multiplier
Example
return {
api_version = 1,
on_boss_damaged_by_player = function(context)
local pct = context.boss:get_health() / context.boss:get_maximum_health()
if pct < 0.25 and not context.boss:has_tag("bonus_coins") then
context.boss:add_tag("bonus_coins")
context.world:drop_bonus_coins(3.0)
context.boss:send_message("&6Gold spills everywhere!")
end
end
}

context.vectors​

Vector math helpers accept dot syntax as shown; colon calls also work. Inputs accept named x, y, z fields, numeric indices 1..3, or a nested direction table. Missing components become 0. Results are new tables; inputs are not modified.

MethodReturnsNotes
vectors.get_vector_between_locations(loc1, loc2[, options])vector tableDisplacement loc2 - loc1, not normalized by default
vectors.normalize_vector(vec)vector tableUnit vector for a nonzero input; zero remains zero
vectors.rotate_vector(vec, pitch, yaw)vector tableRotate around world X first, then world Y, in degrees

All vector tables have fields x, y, z.

vectors.get_vector_between_locations(loc1, loc2, options)​

ParameterTypeNotes
loc1location tableStart point
loc2location tableEnd point
optionstable (optional)Post-processing options (see below)

Vector Options​

KeyTypeDefaultNotes
normalizebooleanfalseNormalize the resulting vector
multipliernumber1.0Scale the vector
offsetvector tablenilAdd an offset vector

Options apply in order: normalize a nonzero displacement, multiply, then add the world-axis offset. Unresolved locations or different worlds return zero before applying any options. Coincident valid locations can still receive an offset.

Example
return {
api_version = 1,
on_boss_damaged_by_player = function(context)
if context.player == nil then return end
if not context.cooldowns:check_local("dash", 100) then return end
-- Compute a normalized direction from boss to player, scaled to speed 2
local dir = context.vectors.get_vector_between_locations(
context.boss:get_location(),
context.player:get_location(),
{ normalize = true, multiplier = 2.0 }
)
-- Launch the boss toward the player
context.boss:set_velocity_vector(dir)
end
}

vectors.normalize_vector(vec)​

ParameterTypeNotes
vecvector tableInput vector
Example
return {
api_version = 1,
on_boss_damaged_by_player = function(context)
if context.player == nil then return end
local raw = context.vectors.get_vector_between_locations(
context.boss:get_location(),
context.player:get_location()
)
local unit = context.vectors.normalize_vector(raw)
context.log:info("Direction: " .. unit.x .. ", " .. unit.y .. ", " .. unit.z)
end
}

vectors.rotate_vector(vec, pitch, yaw)​

ParameterTypeNotes
vecvector tableInput vector
pitchnumberRotation around X axis in degrees
yawnumberRotation around Y axis in degrees
Example
return {
api_version = 1,
on_boss_damaged_by_player = function(context)
if context.player == nil then return end
if not context.cooldowns:check_local("spread_shot", 100) then return end
local forward = context.vectors.normalize_vector(
context.vectors.get_vector_between_locations(
context.boss:get_location(),
context.player:get_location()
)
)
-- Fire three fireballs in a spread pattern
for _, yaw_offset in ipairs({ -30, 0, 30 }) do
local dir = context.vectors.rotate_vector(forward, 0, yaw_offset)
context.boss:summon_projectile(
"FIREBALL",
context.boss:get_eye_location(),
{
x = context.boss:get_location().x + dir.x * 10,
y = context.boss:get_location().y + dir.y * 10,
z = context.boss:get_location().z + dir.z * 10,
world = context.boss:get_location().world
},
1.0
)
end
end
}
tip

You can build a spread of directions by rotating a base vector in a loop:

local base = context.vectors.normalize_vector(
context.vectors.get_vector_between_locations(boss_loc, target_loc)
)
for angle = 0, 330, 30 do
local dir = context.vectors.rotate_vector(base, 0, angle)
-- Use dir for spawning projectiles in a ring
end

context.settings​

Read-only access to power-related configuration values. This getter reads the current setting when called; it does not automatically suppress particles or other effects. Your script must use the result to decide whether to emit a warning.

MethodReturnsNotes
settings:warning_visual_effects_enabled()booleanWhether warning visual effects are enabled in the mob combat settings
Example
return {
api_version = 1,
on_enter_combat = function(context)
if context.settings:warning_visual_effects_enabled() then
context.world:spawn_particle_at_location(context.boss:get_location(), {
particle = "DUST",
amount = 20,
red = 255, green = 0, blue = 0,
})
end
end
}

context.event​

Event data for the current hook. The available fields depend on the underlying event, so guard optional fields. Numeric damage setters require dot syntax (event.set_damage_amount(value)); transfer_damage accepts either dot or colon syntax. This boss event table does not expose the shared table's cancel, uncancel or is_cancelled members.

Field or MethodWhen AvailableNotes
event.damage_amountDamage hooksDamage snapshot when the lazy event table is first resolved
event.get_damage_amount()Damage hooksReads the current amount after any changes
event.damage_causeDamage hooksBukkit DamageCause enum name (e.g. "ENTITY_ATTACK")
event.cancel_event()Cancellable eventsCancels the event
event.set_damage_amount(value)EliteDamageEvent-based hooksSets the damage directly
event.multiply_damage_amount(multiplier)EliteDamageEvent-based hooksMultiplies current damage
event.damagerDamage events with a damager entityRaw Bukkit damager wrapper: the projectile itself for projectile hits, not its shooter
event.projectileDamage events where damager is a projectileProjectile entity reference wrapper
event.spawn_reasonon_spawnSpawn reason enum name
event.entityPlayer-to-boss damage, on_death, zone eventsThe damaged boss, dead entity, or entity crossing the zone; for reinforcement damage this is the reinforcement
event.is_damage_transferPlayer-to-boss damage, including reinforcement forwardingWhether this hit was created by a transfer
event:transfer_damage(target, amount)Player-to-boss damage, including reinforcement forwardingSubmits a separate hit to another eligible elite; see the damage transfer contract

Example: Halving incoming damage​

Example
return {
api_version = 1,
on_boss_damaged_by_player = function(context)
if context.event ~= nil then
local dmg = context.event.damage_amount
context.log:info("Boss took " .. dmg .. " damage, halving it")
context.event.multiply_damage_amount(0.5)
end
end
}

Example: Cancelling damage from projectiles​

Example
return {
api_version = 1,
on_boss_damaged_by_player = function(context)
if context.event ~= nil and context.event.damage_cause == "PROJECTILE" then
context.event.cancel_event()
if context.player ~= nil then
context.player:send_message("&cThe boss deflects your projectile!")
end
end
end
}

Example: Reading damage cause​

Example
return {
api_version = 1,
on_player_damaged_by_boss = function(context)
if context.event ~= nil then
context.log:info("Damage cause: " .. (context.event.damage_cause or "unknown"))
end
end
}
note
  • damage_amount is a snapshot. It does not auto-refresh after calling set_damage_amount() or multiply_damage_amount().
  • The fresh context supplied to a scheduled callback has event = nil. Capturing the old hook context does not make its completed event a valid target for later modification; modify events during their hook.
  • Damage setters change the pending event, not health already lost. Later listeners can still modify or cancel the hit. A successful transfer submits an additional hit; it does not reduce or cancel the original automatically.

Next Steps​