Saltar al contenido principal

Scripting Lua: Zonas y Objetivos

webapp_banner.jpg

Las funciones Lua de EliteMobs ofrecen dos enfoques complementarios para definir áreas espaciales y resolver objetivos:

  • Zonas nativas (context.zones) -- simples y directas. Se construye una definición de zona como una tabla Lua simple y se consulta para obtener entidades o ubicaciones. Ideal para verificaciones directas de "¿hay algo en esta área?".
  • Utilidades de script (context.script) -- selección de objetivos más completa, handles de zona con métodos watch/contains/entities, generación de partículas, daño y acciones de empuje. Usa los mismos nombres de campo que las Zonas de EliteScript y los Objetivos de EliteScript para mayor familiaridad.

Ambos enfoques son APIs nativas de Lua. Elija el que se ajuste a la complejidad de su poder.


Zonas nativas: context.zones

Las zonas nativas permiten definir zonas como tablas Lua simples y consultarlas directamente. Sin handles, sin abstracción adicional -- solo una tabla que describe una forma y una llamada a método para consultarla.

Métodos

MétodoNotas
zones:get_entities_in_zone(zoneDef, options)Devuelve un array de wrappers de entidad dentro de la zona
zones:get_locations_in_zone(zoneDef, options)Devuelve un array de tablas de ubicación dentro de la zona
zones:zone_contains(zoneDef, location[, "full"|"border"])Devuelve true si la ubicación está dentro de la zona
zones:watch_zone(zoneDef, callbacks, options)Registra un observador de zona persistente que se ejecuta cada tick

Campos de definición de zona

CampoTipoPredeterminadoNotas
kind (o type)string"sphere", "dome", "cylinder", "cuboid", "cone", "static_ray", "rotating_ray", "translating_ray"
radiusnumber0Radio de la zona (sphere, dome, cylinder, cone)
heightnumber0Altura del cilindro
originlocationubicación del bossUbicación central
destinationlocationubicación del bossPunto final para rayos y conos
x, y, znumber0Semi-extensiones del cuboide
thickness / point_radius / pointRadiusnumber0.5Grosor del rayo
border_radius / borderRadiusnumber1Ancho del borde
x_border, y_border, z_bordernumber1Anchos de borde del cuboide
animation_durationint0Duración de la animación en ticks para rayos animados
pitch_pre_rotation, yaw_pre_rotationnumber0Ángulos de pre-rotación (rayo rotatorio)
pitch_rotation, yaw_rotationnumber0Ángulos de rotación por tick (rayo rotatorio)
origin_end, destination_endlocationubicación del bossPosiciones finales para rayo en traslación
ignores_solid_blocksbooleantrueSi los rayos atraviesan bloques sólidos
lengthnumber0Solo se lee cuando se omite destination; véase abajo.

Todos los campos de varias palabras aceptan también camelCase (borderRadius, xBorder, animationDuration, pitchPreRotation, ignoresSolidBlocks, ...), así que una especificación copiada de un bloque Zone: de EliteScript funciona prácticamente tal cual.

kind distingue mayúsculas y minúsculas

A diferencia de casi cualquier otra cadena de la API de Lua, kind se compara de forma exacta y debe ir en minúsculas. "SPHERE" o "Sphere" no coinciden con nada, y la zona se resuelve silenciosamente en nada: las consultas simplemente devuelven una lista vacía sin ninguna advertencia en consola.

Cones and rays need an explicit destination

Tanto origin como destination recurren a la propia ubicación del boss cuando se omiten. En un cono o un rayo eso produce una forma de longitud cero en lugar de un error. Establece siempre destination en cone, static_ray, rotating_ray y translating_ray. No existe un atajo length: define una ubicación de destino explícita.

Los conos y rayos necesitan destination o length

Si se omite origin, se usa la ubicación del jefe. Si se omite destination, se proyecta origin una distancia de length bloques siguiendo la orientación almacenada en la tabla de ubicación origin.

Puedes definir un cono o rayo de estas dos formas:

-- Explicit endpoint
local explicit_ray = { kind = "static_ray", origin = context.boss:get_eye_location(),
destination = context.player:get_eye_location() }

-- Or a length along the origin's own facing
local forward_ray = { kind = "static_ray", origin = context.boss:get_eye_location(), length = 15 }

La forma abreviada con length solo apunta en la dirección deseada cuando origin contiene yaw/pitch. Las ubicaciones devueltas por la API (get_location(), get_eye_location(), current_location) sí los incluyen. Una tabla escrita a mano { x = .., y = .., z = .. } no los incluye, ni tampoco em.create_location(x, y, z) salvo que pases sus argumentos opcionales yaw y pitch.

Si omites ambos, length vale 0 por defecto: la figura tiene longitud cero y todas las consultas devuelven resultados vacíos sin advertencia.

Opciones de consulta

ClaveNotas
filter"player" / "players", "elite" / "elites", "mob" / "mobs", "living" (por defecto)
mode"full" (por defecto) o "border"
coverage0.0 a 1.0 -- fracción de ubicaciones a muestrear (por defecto 1.0)

Callbacks de observación

ClaveNotas
on_enterfunction(entity) -- se llama cuando una entidad entra en la zona
on_leavefunction(entity) -- se llama cuando una entidad sale de la zona

Ejemplo: consulta básica de esfera

Ejemplo
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
}

Ejemplo: observación de zona con entrada/salida

Ejemplo
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
}

Notas sobre observadores:

  • Los callbacks de observadores reciben directamente un wrapper de entidad individual, no a través de context.event
  • Los observadores se limpian automáticamente cuando el boss es eliminado
  • Cada observador se ejecuta cada tick, así que mantenga la lógica del callback ligera
  • La entidad del boss está excluida de las consultas de zona

Utilidades de script: context.script

Las utilidades de script proporcionan resolución de objetivos, handles de zona, vectores relativos, generación de partículas y acciones de combate.

context.script runs the EliteScript engine

context.script no es simplemente «nomenclatura al estilo de EliteScript»: la tabla de especificación que le pasas se convierte en un mapa Java plano y se entrega directamente a las mismas clases de objetivo, zona, vector relativo y partículas que hacen funcionar los EliteScripts en YAML. No hay una implementación separada.

Lo que eso significa en la práctica:

  • Todos los campos documentados en Objetivos de EliteScript, Zonas de EliteScript y Vectores relativos de EliteScript funcionan en estas tablas de especificación, incluido cualquier campo que esta página no liste.
  • Los valores de enum son exactamente UPPER_SNAKE_CASE ("NEARBY_PLAYERS", "SPHERE", "ZONE_FULL"), igual que en YAML.
  • Los nombres de campo son los nombres de YAML, así que Target y Target2 van en mayúscula inicial mientras que targetType y borderRadius van en camelCase.
  • El comportamiento de carga de YAML también se aplica: un valor que no se pueda procesar registra una advertencia de EliteScript y borra el campo en lugar de recurrir a su valor predeterminado.

Esto es lo contrario de context.zones, que sí es una implementación ligera genuinamente separada que usa nombres kind en minúsculas.

Métodos

MétodoNotas
script:target(spec)Crea un handle de objetivo a partir de una tabla de especificación de objetivo
script:zone(spec)Crea un handle de zona a partir de una tabla de especificación de zona
script:relative_vector(spec[, actionLocation][, zoneHandle])Crea un handle de vector relativo
script:damage(targetHandle, amount[, multiplier])Inflige daño a los objetivos resueltos
script:push(targetHandle, vectorOrHandle[, additive])Empuja los objetivos resueltos
script:set_facing(targetHandle, vectorOrHandle)Establece la dirección de orientación de los objetivos
script:spawn_particles(targetHandle, particleSpec)Genera partículas en las ubicaciones de los objetivos resueltos

Métodos del handle de objetivo

MétodoNotas
handle:entities()Devuelve array de wrappers de entidad
handle:locations()Devuelve array de tablas de ubicación
handle:first_entity()Devuelve la primera entidad o nil
handle:first_location()Devuelve la primera ubicación o nil

Claves de especificación de objetivo

ClavePredeterminadoNotas
targetType"SELF"Cualquier tipo de objetivo de EliteScript
range20Alcance para tipos de objetivo cercanos
coverage1.0De 0.0 a 1.0. Solo se respeta en los tipos de objetivo de zona; en cualquier otro tipo se restablece a 1.0 con una advertencia en consola
offset0,0,0Cadena "x,y,z" o tabla { x = n, y = n, z = n }
relativeOffsetningunoUna tabla de especificación de vector relativo, para un desplazamiento relativo a la orientación del boss
locationningunoUbicación única, para "LOCATION"
locationsningunoLista de ubicaciones, para "LOCATIONS"
tracktrueSi se deben volver a resolver los objetivos en movimiento

Se aceptan los 17 tipos de objetivo de EliteScript, no solo los más comunes: SELF, SELF_SPAWN, DIRECT_TARGET, NEARBY_PLAYERS, NEARBY_MOBS, NEARBY_ELITES, WORLD_PLAYERS, ALL_PLAYERS, LOCATION, LOCATIONS, ZONE_FULL, ZONE_BORDER, LANDING_LOCATION, ACTION_TARGET, INHERIT_SCRIPT_TARGET, INHERIT_SCRIPT_ZONE_FULL, INHERIT_SCRIPT_ZONE_BORDER. Los tipos ACTION_TARGET e INHERIT_* solo se resuelven en algo cuando existe el contexto de EliteScript circundante, así que tienen poca utilidad desde Lua.

Ejemplo: crear y usar un objetivo

Ejemplo
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
}

Métodos del handle de zona

MétodoNotas
handle:full_target([coverage])Devuelve un handle de objetivo para el volumen completo de la zona
handle:border_target([coverage])Devuelve un handle de objetivo para el borde de la zona
handle:full_locations([coverage])Devuelve ubicaciones en el volumen completo de la zona
handle:border_locations([coverage])Devuelve ubicaciones en el borde de la zona
handle:full_entities()Devuelve entidades en el volumen completo de la zona
handle:border_entities()Devuelve entidades en el borde de la zona
handle:contains(location[, "full"|"border"])Devuelve true si la ubicación está dentro de la zona
handle:watch(callbacks[, mode])Observa la zona para eventos de entrada/salida, devuelve ID de tarea

Claves de especificación de zona

ClavePredeterminadoNotas
shape"CYLINDER""SPHERE", "DOME", "CYLINDER", "CUBOID", "CONE", "STATIC_RAY", "ROTATING_RAY", "TRANSLATING_RAY"
radius5Sphere, dome, cylinder, cone
height1Solo cylinder
x, y, z0Semi-extensiones del cuboide
xBorder, yBorder, zBorder0Anchos de borde del cuboide
borderRadius1Ancho del borde para sphere / dome / cylinder / cone
pointRadius0.5Grosor del rayo
animationDuration0Duración de la animación en ticks para rayos animados
Target{targetType = "SELF"}Especificación de objetivo central (tabla) -- usa el mismo formato de especificación de objetivo
Target2ningunoSegundo punto. Obligatorio para conos y todas las formas de rayo
FinalTarget, FinalTarget2ningunoPosiciones finales, solo para el rayo en traslación
filter"PLAYER""PLAYER", "ELITE", "LIVING" -- ten en cuenta que aquí van en MAYÚSCULAS, a diferencia de context.zones
ignoresSolidBlockstrueSolo rayos
pitchPreRotation, yawPreRotation0Solo rayo rotatorio
pitchRotation, yawRotation0Solo rayo rotatorio

Las claves que no se aplican a la shape elegida se leen sin dar error y luego se ignoran: un height en una esfera no hace nada.

Ejemplo: zona con daño y partículas

Ejemplo
return {
api_version = 1,
on_enter_combat = function(context)
-- Create a sphere zone centered on the boss
if context.state.zone_task_id ~= nil then return end
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.state.zone_task_id = 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,
on_exit_combat = function(context)
if context.state.zone_task_id ~= nil then
context.scheduler:cancel_task(context.state.zone_task_id)
context.state.zone_task_id = nil
end
end
}

Claves de especificación de vector relativo

ClaveNotas
SourceTargetEspecificación del objetivo de origen (tabla)
DestinationTargetEspecificación del objetivo de destino (tabla)
normalizeboolean -- si se debe normalizar el vector resultante
multiplierFactor de escala aplicado después de la normalización
offsetCadena "x,y,z" o tabla { x = n, y = n, z = n }

Métodos del handle de vector relativo

MétodoNotas
handle:resolve()Devuelve la tabla del vector calculado

Ejemplo: empujar objetivos con un vector relativo

Ejemplo
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
}

Formato de especificación de partículas

Las especificaciones de partículas pueden ser una cadena, una tabla individual o un array de tablas. Como esta vía ejecuta el motor de partículas de EliteScript, las claves son las de EliteScript documentadas en SPAWN_PARTICLE:

ClavePredeterminadoNotas
particle"FLAME"Nombre de partícula (ej. "FLAME", "DUST", "SMOKE")
amount1Número de partículas. Con 0, x/y/z pasan a ser un vector de velocidad
x, y, z0.01Valores de offset/dispersión, o velocidad cuando amount es 0
speed0.01Velocidad de partículas
red, green, blue255Color para DUST, DUST_COLOR_TRANSITION, WITCH y otras partículas con datos de color (0-255)
toRed, toGreen, toBlue255Color de destino de transición para DUST_COLOR_TRANSITION
material"STONE"Bloque u objeto mostrado por las partículas que llevan datos de bloque/objeto (BLOCK, ITEM, FALLING_DUST, ...)
relativeVectorningunoUna especificación de vector relativo. Establecerlo fuerza amount a 0 y sobrescribe x/y/z con la dirección resuelta
Two different particle key sets

Estas claves de EliteScript no son las mismas que acepta context.world:spawn_particle_at_location(loc, spec). La tabla world tiene su propio lector, más reducido y con valores predeterminados distintos (amount 1, x/y/z/speed 0), sin material ni relativeVector, y además acepta to_red / to_green / to_blue en snake_case. Consulta Mundo y entorno.

Para la lista completa de nombres de partículas, consulte la Referencia de Enums.

Advertencias importantes

  • Los handles de utilidades de script están vinculados al contexto del evento en el que fueron creados. No los almacene en context.state para usarlos en una llamada posterior a un hook.
  • watch() de zona devuelve un ID de tarea que puede cancelar con context.scheduler:cancel_task().
  • Los valores de coverage solo se aplican a la resolución basada en ubicaciones, no a consultas de entidades.
  • Todos los valores de cadena usan los mismos nombres de enum en UPPER_SNAKE_CASE que EliteScript YAML (ej. "SELF", "NEARBY_PLAYERS", "SPHERE").

Espacio de nombres auxiliar em

El espacio de nombres em está disponible globalmente en todos los archivos de poder Lua. Proporciona constructores convenientes para ubicaciones, vectores y definiciones de zona.

Constructores de ubicación y vector

FunciónNotas
em.create_location(x, y, z[, world][, yaw][, pitch])Devuelve una tabla de ubicación con un método add(dx, dy, dz)
em.create_vector(x, y, z)Devuelve una tabla de vector

Helpers de constructor de zonas

La sub-tabla em.zone proporciona funciones constructoras que devuelven tablas de definición de zona compatibles con context.zones. Cada constructor devuelve una tabla con métodos mutadores encadenables.

FunciónParámetrosMutadores
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 (semi-extensiones):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)
The length argument is not used

Los constructores de cono y rayo guardan length en la tabla de especificación, pero context.zones nunca lo lee: la forma va de origin a destination. Encadena siempre :set_origin(...) y :set_destination(...) en estos constructores; de lo contrario ambos recurren a la ubicación del boss y la forma tiene longitud cero.

Ejemplo

Ejemplo
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
}
información

El espacio de nombres em no es por instancia -- todas las instancias de poder Lua comparten las mismas funciones auxiliares de em. Las funciones son constructores puros y no mantienen ningún estado.


Zonas nativas vs. Utilidades de script

Ambos sistemas trabajan con la misma geometría de zona subyacente. Aquí se indica cuándo usar cada uno:

Caso de usoEnfoque recomendado
Verificación simple de "¿hay algo en esta área?"Zonas nativas (context.zones)
Consulta rápida de entidades con una formaZonas nativas
NEARBY_PLAYERS, ZONE_FULL con coverageUtilidades de script (context.script)
Zonas animadas (rayos rotatorios/en traslación)Ambos -- las zonas nativas también soportan estas formas
Handles de zona con métodos watch/contains/entitiesUtilidades de script
Generación de partículas en ubicaciones de zonaUtilidades de script (spawn_particles)
Acciones de daño y empuje vinculadas a objetivosUtilidades de script (damage, push)
Vectores relativos para efectos direccionalesUtilidades de script (relative_vector)
Combinación de flujo de control Lua con selección de objetivos avanzadaUtilidades de script

En la práctica, muchos poderes usan ambos. Las zonas nativas son excelentes para la verificación inicial de "¿hay jugadores cerca?" en un guard de cooldown, mientras que las utilidades de script manejan la lógica de ataque compleja que sigue.


Próximos pasos