Pular para o conteúdo principal

Lua Scripting: Zones & Targeting

webapp_banner.jpg

EliteMobs Lua powers offer two complementary approaches for defining spatial areas and resolving targets:

  • Native zones (context.zones) -- simple and direct. You build a zone definition as a plain Lua table and query it for entities or locations. Best for straightforward "is anything in this area?" checks.
  • Script utilities (context.script) -- richer targeting, zone handles with watch/contains/entities methods, particle spawning, damage, and push actions. Uses the same field names as EliteScript Zones and EliteScript Targets for familiarity.

Both approaches are native Lua APIs. Pick whichever fits the complexity of your power.


Native Zones: context.zones

Native zones let you define zones as plain Lua tables and query them directly. No handles, no extra abstraction -- just a table describing a shape and a method call to query it.

Methods

MethodNotes
zones:get_entities_in_zone(zoneDef, options)Returns an array of entity wrappers inside the zone
zones:get_locations_in_zone(zoneDef, options)Returns an array of location tables inside the zone
zones:zone_contains(zoneDef, location[, "full"|"border"])Returns true if the location is inside the zone
zones:watch_zone(zoneDef, callbacks, options)Registers a persistent zone watcher that fires per tick

Zone definition fields

FieldTypeNotes
kindstring"sphere", "dome", "cylinder", "cuboid", "cone", "static_ray", "rotating_ray", "translating_ray"
radiusnumberZone radius (sphere, dome, cylinder, cone)
heightnumberCylinder height
originlocationCenter location (defaults to boss location if omitted)
destinationlocationEnd point for rays and cones
x, y, znumberCuboid half-extents
lengthnumberLength for cones and rays
thickness / point_radiusnumberRay thickness
border_radiusnumberBorder width (default 1)
x_border, y_border, z_bordernumberCuboid border widths (default 1)
animation_durationintAnimation length in ticks for animated rays
pitch_pre_rotation, yaw_pre_rotationnumberPre-rotation angles (rotating ray)
pitch_rotation, yaw_rotationnumberPer-tick rotation angles (rotating ray)
origin_end, destination_endlocationEnd positions for translating ray
ignores_solid_blocksbooleanWhether rays pass through solid blocks (default true)

Query options

KeyNotes
filter"player" / "players", "elite" / "elites", "mob" / "mobs", "living" (default)
mode"full" (default) or "border"
coverage0.0 to 1.0 -- fraction of locations to sample (default 1.0)

Watch callbacks

KeyNotes
on_enterfunction(entity) -- called when an entity enters the zone
on_leavefunction(entity) -- called when an entity leaves the zone

Example: basic sphere query

Example
return {
api_version = 1,
on_spawn = function(context)
-- Store a zone definition for reuse
context.state.danger_zone = {
kind = "sphere",
origin = context.boss:get_location(),
radius = 10
}
end,

on_boss_damaged_by_player = function(context)
-- Update the origin to the boss's current position
context.state.danger_zone.origin = context.boss:get_location()

local players = context.zones:get_entities_in_zone(
context.state.danger_zone,
{ filter = "players" }
)

for _, player in ipairs(players) do
player:send_message("&cYou are in the danger zone!")
end
end
}

Example: zone watching with enter/leave

Example
return {
api_version = 1,
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)
entity:send_message("&7You feel sluggish near the boss...")
end,
on_leave = function(entity)
entity:send_message("&aYou escape the slowing aura.")
end
},
{ filter = "players", mode = "full" }
)
end
}

Watcher notes:

  • 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

Script Utilities: context.script

The script utilities provide target resolution, zone handles, relative vectors, particle spawning, and combat actions. They use the same field names as EliteScript Zones and EliteScript Targets for familiarity -- the enum names (like "NEARBY_PLAYERS", "SPHERE", "ZONE_FULL") are identical so that authors already comfortable with EliteScript can transfer that knowledge directly.

info

context.script is a native Lua API. It is not a bridge to YAML or to the EliteScript runtime. It simply reuses the same naming conventions so you do not have to learn a second set of enum names.

Methods

MethodNotes
script:target(spec)Creates a target handle from a target spec table
script:zone(spec)Creates a zone handle from a zone spec table
script:relative_vector(spec[, actionLocation][, zoneHandle])Creates a relative-vector handle
script:damage(targetHandle, amount[, multiplier])Deals damage to resolved targets
script:push(targetHandle, vectorOrHandle[, additive])Pushes resolved targets
script:set_facing(targetHandle, vectorOrHandle)Sets facing direction for targets
script:spawn_particles(targetHandle, particleSpec)Spawns particles at resolved target locations

Target handle methods

MethodNotes
handle:entities()Returns array of entity wrappers
handle:locations()Returns array of location tables
handle:first_entity()Returns first entity or nil
handle:first_location()Returns first location or nil

Target spec keys

KeyNotes
targetType"SELF", "DIRECT_TARGET", "NEARBY_PLAYERS", "NEARBY_MOBS", "NEARBY_ELITES", "ZONE_FULL", "ZONE_BORDER", "ALL_PLAYERS", "WORLD_PLAYERS", "SELF_SPAWN", "LOCATION"
rangeRange for nearby-type targets
coverage0.0 to 1.0 for zone targets
offset"x,y,z" string or { x = n, y = n, z = n } table
trackWhether to re-resolve moving targets

Example: creating and using a target

Example
return {
api_version = 1,
on_boss_damaged_by_player = function(context)
if not context.cooldowns:check_local("roar", 200) then return end
-- Find all players within 20 blocks
local nearby = context.script:target({
targetType = "NEARBY_PLAYERS",
range = 20
})

for _, player in ipairs(nearby:entities()) do
player:send_message("&eThe boss roars in fury!")
end

-- Single-entity access
local closest = nearby:first_entity()
if closest then
closest:show_title("&cRUN!", "&7The boss is targeting you")
end
end
}

Zone handle methods

MethodNotes
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[, "full"|"border"])Returns true if the location is inside the zone
handle:watch(callbacks[, mode])Watches zone for enter/leave events, returns task ID

Zone spec keys

KeyNotes
shape"SPHERE", "DOME", "CYLINDER", "CUBOID", "CONE", "STATIC_RAY", "ROTATING_RAY", "TRANSLATING_RAY"
radiusZone radius
heightCylinder height
x, y, zCuboid half-extents
borderRadiusBorder width
pointRadiusRay thickness
animationDurationAnimation length in ticks for animated rays
TargetCenter target spec (table) -- uses the same target spec format
Target2Second point for rays and cones
filterEntity filter
ignoresSolidBlocksboolean
pitchPreRotation, yawPreRotationPre-rotation angles
pitchRotation, yawRotationPer-tick rotation angles

Example: zone with damage and particles

Example
return {
api_version = 1,
on_enter_combat = function(context)
-- Create a sphere zone centered on the boss
local zone = context.script:zone({
shape = "SPHERE",
radius = 6,
Target = { targetType = "SELF" }
})

-- Spawn warning particles on the zone border
context.script:spawn_particles(
zone:border_target(0.3),
{ particle = "FLAME", amount = 1, speed = 0.02 }
)

-- Damage all players inside the zone
local targets = zone:full_target()
context.script:damage(targets, 5.0)

-- Repeat every 20 ticks
context.scheduler:run_every(20, function(ctx)
local z = ctx.script:zone({
shape = "SPHERE",
radius = 6,
Target = { targetType = "SELF" }
})

ctx.script:spawn_particles(
z:border_target(0.3),
{ particle = "FLAME", amount = 1, speed = 0.02 }
)

ctx.script:damage(z:full_target(), 5.0)
end)
end
}

Relative-vector spec keys

KeyNotes
SourceTargetSource target spec (table)
DestinationTargetDestination target spec (table)
normalizeboolean -- whether to normalize the resulting vector
multiplierScale factor applied after normalization
offset"x,y,z" string or { x = n, y = n, z = n } table

Relative-vector handle methods

MethodNotes
handle:resolve()Returns the computed vector table

Example: pushing targets with a relative vector

Example
return {
api_version = 1,
on_boss_damaged_by_player = function(context)
if not context.cooldowns:check_local("knockback", 100) then return end

-- Build a vector from the boss toward the attacker
local vec = context.script:relative_vector({
SourceTarget = { targetType = "SELF" },
DestinationTarget = { targetType = "DIRECT_TARGET" },
normalize = true,
multiplier = 2.5
})

-- Push the attacker away
local target = context.script:target({
targetType = "DIRECT_TARGET"
})

context.script:push(target, vec)
end
}

Particle spec format

Particle specs can be a string, a single table, or an array of tables:

KeyNotes
particleParticle name (e.g. "FLAME", "DUST", "SMOKE")
amountNumber of particles
x, y, zOffset/spread values
speedParticle speed
red, green, blueColor for DUST / DUST_COLOR_TRANSITION (0-255)
toRed, toGreen, toBlueTransition target color for DUST_COLOR_TRANSITION

For the full list of particle names, see the Enum Reference.

Important caveats

  • Script utility handles are tied to the event context in which they were created. Do not store them in context.state for use in a later hook call.
  • Zone watch() returns a task ID that you can cancel with context.scheduler:cancel_task().
  • Coverage values apply only to location-based resolution, not entity queries.
  • All string values use the same UPPER_SNAKE_CASE enum names as EliteScript YAML (e.g. "SELF", "NEARBY_PLAYERS", "SPHERE").

em Helper Namespace

The em namespace is available globally in all Lua power files. It provides convenience constructors for locations, vectors, and zone definitions.

Location and vector constructors

FunctionNotes
em.create_location(x, y, z[, world][, yaw][, pitch])Returns a location table with an add(dx, dy, dz) method
em.create_vector(x, y, z)Returns a vector table

Zone builder helpers

The em.zone sub-table provides builder functions that return zone definition tables compatible with context.zones. Each builder returns a table with chainable mutator methods.

FunctionParametersMutators
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)

Example

Example
return {
api_version = 1,
on_spawn = function(context)
-- Create a location offset from the boss
local boss_loc = context.boss:get_location()
local above = em.create_location(boss_loc.x, boss_loc.y + 5, boss_loc.z)

-- Create a sphere zone using the builder
local zone = em.zone.create_sphere_zone(10):set_center(boss_loc)

-- Use with native zone queries
local players = context.zones:get_entities_in_zone(zone, { filter = "players" })
for _, p in ipairs(players) do
p:send_message("&cYou are within the boss's aura!")
end

-- Create a directional vector
local push_vec = em.create_vector(0, 1.5, 0)
context.boss:set_velocity_vector(push_vec)
end
}
info

The em namespace is not per-instance -- all Lua power instances share the same em helper functions. The functions are pure constructors and do not carry any state.


Native Zones vs Script Utilities

Both systems work with the same underlying zone geometry. Here is when to use each:

Use caseRecommended approach
Simple "is anything in this area?" checkNative zones (context.zones)
Quick entity query with a shapeNative zones
NEARBY_PLAYERS, ZONE_FULL with coverageScript utilities (context.script)
Animated zones (rotating/translating rays)Either -- native zones support these shapes too
Zone handles with watch/contains/entities methodsScript utilities
Particle spawning at zone locationsScript utilities (spawn_particles)
Damage and push actions tied to targetingScript utilities (damage, push)
Relative vectors for directional effectsScript utilities (relative_vector)
Combining Lua control flow with rich targetingScript utilities

In practice, many powers use both. Native zones are great for the initial "are players nearby?" check in a cooldown guard, while script utilities handle the complex attack logic that follows.


Next Steps