Scripting Lua: Zonas y Objetivos
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étodo | Notas |
|---|---|
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
| Campo | Tipo | Predeterminado | Notas |
|---|---|---|---|
kind (o type) | string | — | "sphere", "dome", "cylinder", "cuboid", "cone", "static_ray", "rotating_ray", "translating_ray" |
radius | number | 0 | Radio de la zona (sphere, dome, cylinder, cone) |
height | number | 0 | Altura del cilindro |
origin | location | ubicación del boss | Ubicación central |
destination | location | ubicación del boss | Punto final para rayos y conos |
x, y, z | number | 0 | Semi-extensiones del cuboide |
thickness / point_radius / pointRadius | number | 0.5 | Grosor del rayo |
border_radius / borderRadius | number | 1 | Ancho del borde |
x_border, y_border, z_border | number | 1 | Anchos de borde del cuboide |
animation_duration | int | 0 | Duración de la animación en ticks para rayos animados |
pitch_pre_rotation, yaw_pre_rotation | number | 0 | Ángulos de pre-rotación (rayo rotatorio) |
pitch_rotation, yaw_rotation | number | 0 | Ángulos de rotación por tick (rayo rotatorio) |
origin_end, destination_end | location | ubicación del boss | Posiciones finales para rayo en traslación |
ignores_solid_blocks | boolean | true | Si los rayos atraviesan bloques sólidos |
length | number | 0 | Solo 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úsculasA 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.
destinationTanto 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.
destination o lengthSi 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
| Clave | Notas |
|---|---|
filter | "player" / "players", "elite" / "elites", "mob" / "mobs", "living" (por defecto) |
mode | "full" (por defecto) o "border" |
coverage | 0.0 a 1.0 -- fracción de ubicaciones a muestrear (por defecto 1.0) |
Callbacks de observación
| Clave | Notas |
|---|---|
on_enter | function(entity) -- se llama cuando una entidad entra en la zona |
on_leave | function(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 enginecontext.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
TargetyTarget2van en mayúscula inicial mientras quetargetTypeyborderRadiusvan 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étodo | Notas |
|---|---|
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étodo | Notas |
|---|---|
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
| Clave | Predeterminado | Notas |
|---|---|---|
targetType | "SELF" | Cualquier tipo de objetivo de EliteScript |
range | 20 | Alcance para tipos de objetivo cercanos |
coverage | 1.0 | De 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 |
offset | 0,0,0 | Cadena "x,y,z" o tabla { x = n, y = n, z = n } |
relativeOffset | ninguno | Una tabla de especificación de vector relativo, para un desplazamiento relativo a la orientación del boss |
location | ninguno | Ubicación única, para "LOCATION" |
locations | ninguno | Lista de ubicaciones, para "LOCATIONS" |
track | true | Si 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étodo | Notas |
|---|---|
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
| Clave | Predeterminado | Notas |
|---|---|---|
shape | "CYLINDER" | "SPHERE", "DOME", "CYLINDER", "CUBOID", "CONE", "STATIC_RAY", "ROTATING_RAY", "TRANSLATING_RAY" |
radius | 5 | Sphere, dome, cylinder, cone |
height | 1 | Solo cylinder |
x, y, z | 0 | Semi-extensiones del cuboide |
xBorder, yBorder, zBorder | 0 | Anchos de borde del cuboide |
borderRadius | 1 | Ancho del borde para sphere / dome / cylinder / cone |
pointRadius | 0.5 | Grosor del rayo |
animationDuration | 0 | Duració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 |
Target2 | ninguno | Segundo punto. Obligatorio para conos y todas las formas de rayo |
FinalTarget, FinalTarget2 | ninguno | Posiciones 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 |
ignoresSolidBlocks | true | Solo rayos |
pitchPreRotation, yawPreRotation | 0 | Solo rayo rotatorio |
pitchRotation, yawRotation | 0 | Solo 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
| Clave | Notas |
|---|---|
SourceTarget | Especificación del objetivo de origen (tabla) |
DestinationTarget | Especificación del objetivo de destino (tabla) |
normalize | boolean -- si se debe normalizar el vector resultante |
multiplier | Factor de escala aplicado después de la normalización |
offset | Cadena "x,y,z" o tabla { x = n, y = n, z = n } |
Métodos del handle de vector relativo
| Método | Notas |
|---|---|
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:
| Clave | Predeterminado | Notas |
|---|---|---|
particle | "FLAME" | Nombre de partícula (ej. "FLAME", "DUST", "SMOKE") |
amount | 1 | Número de partículas. Con 0, x/y/z pasan a ser un vector de velocidad |
x, y, z | 0.01 | Valores de offset/dispersión, o velocidad cuando amount es 0 |
speed | 0.01 | Velocidad de partículas |
red, green, blue | 255 | Color para DUST, DUST_COLOR_TRANSITION, WITCH y otras partículas con datos de color (0-255) |
toRed, toGreen, toBlue | 255 | Color 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, ...) |
relativeVector | ninguno | Una especificación de vector relativo. Establecerlo fuerza amount a 0 y sobrescribe x/y/z con la dirección resuelta |
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.statepara usarlos en una llamada posterior a un hook. watch()de zona devuelve un ID de tarea que puede cancelar concontext.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ón | Notas |
|---|---|
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ón | Parámetros | Mutadores |
|---|---|---|
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) |
length argument is not usedLos 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
}
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 uso | Enfoque recomendado |
|---|---|
| Verificación simple de "¿hay algo en esta área?" | Zonas nativas (context.zones) |
| Consulta rápida de entidades con una forma | Zonas nativas |
NEARBY_PLAYERS, ZONE_FULL con coverage | Utilidades 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/entities | Utilidades de script |
| Generación de partículas en ubicaciones de zona | Utilidades de script (spawn_particles) |
| Acciones de daño y empuje vinculadas a objetivos | Utilidades de script (damage, push) |
| Vectores relativos para efectos direccionales | Utilidades de script (relative_vector) |
| Combinación de flujo de control Lua con selección de objetivos avanzada | Utilidades 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
- Ejemplos y Patrones -- poderes funcionales completos que puede estudiar y adaptar
- Referencia de Enums -- valores válidos para Particle, Sound, Material y otras constantes de cadena
