Scripting Lua: Zonas e Alvos
As funcionalidades Lua do EliteMobs oferecem duas abordagens complementares para definir áreas espaciais e resolver alvos:
- Zonas nativas (
context.zones) -- simples e diretas. Você constrói uma definição de zona como uma tabela Lua simples e a consulta para obter entidades ou localizações. Ideal para verificações diretas de "há algo nesta área?". - Utilitários de script (
context.script) -- segmentação mais rica, handles de zona com métodos watch/contains/entities, geração de partículas, dano e ações de empurrão. Usa os mesmos nomes de campo que as Zonas do EliteScript e os Alvos do EliteScript para maior familiaridade.
Ambas as abordagens são APIs Lua nativas. Escolha a que se adequa à complexidade do seu poder.
Zonas nativas: context.zones
As zonas nativas permitem definir zonas como tabelas Lua simples e consultá-las diretamente. Sem handles, sem abstração adicional -- apenas uma tabela descrevendo uma forma e uma chamada de método para consultá-la.
Métodos
| Método | Notas |
|---|---|
zones:get_entities_in_zone(zoneDef, options) | Retorna um array de wrappers de entidade dentro da zona |
zones:get_locations_in_zone(zoneDef, options) | Retorna um array de tabelas de localização dentro da zona |
zones:zone_contains(zoneDef, location[, "full"|"border"]) | Retorna true se a localização está dentro da zona |
zones:watch_zone(zoneDef, callbacks, options) | Registra um observador de zona persistente que dispara a cada tick |
Campos de definição de zona
| Campo | Tipo | Padrão | Notas |
|---|---|---|---|
kind (ou type) | string | — | "sphere", "dome", "cylinder", "cuboid", "cone", "static_ray", "rotating_ray", "translating_ray" |
radius | number | 0 | Raio da zona (sphere, dome, cylinder, cone) |
height | number | 0 | Altura do cilindro |
origin | location | localização do boss | Localização central |
destination | location | localização do boss | Ponto final para raios e cones |
x, y, z | number | 0 | Semi-extensões do cuboide |
thickness / point_radius / pointRadius | number | 0.5 | Espessura do raio |
border_radius / borderRadius | number | 1 | Largura da borda |
x_border, y_border, z_border | number | 1 | Larguras de borda do cuboide |
animation_duration | int | 0 | Duração da animação em ticks para raios animados |
pitch_pre_rotation, yaw_pre_rotation | number | 0 | Ângulos de pré-rotação (raio rotativo) |
pitch_rotation, yaw_rotation | number | 0 | Ângulos de rotação por tick (raio rotativo) |
origin_end, destination_end | location | localização do boss | Posições finais para raio em translação |
ignores_solid_blocks | boolean | true | Se os raios passam através de blocos sólidos |
length | number | 0 | Só é lido quando destination é omitido; ver abaixo. |
Todos os campos de várias palavras também aceitam camelCase (borderRadius, xBorder, animationDuration, pitchPreRotation, ignoresSolidBlocks, ...), pelo que uma spec copiada de um bloco Zone: de EliteScript funciona quase sempre tal como está.
kind diferencia maiúsculas de minúsculasAo contrário de praticamente todas as outras strings da API Lua, o kind é comparado exatamente e tem de estar em minúsculas. "SPHERE" ou "Sphere" não correspondem a nada, e a zona resolve-se silenciosamente para nada -- as consultas devolvem apenas uma lista vazia, sem qualquer aviso na consola.
destination explícitoTanto o origin como o destination recorrem à própria localização do boss quando são omitidos. Para um cone ou um raio, isso produz uma forma de comprimento zero em vez de um erro. Defina sempre o destination em cone, static_ray, rotating_ray e translating_ray. Não existe um atalho length -- defina uma localização de destino explícita.
destination ou lengthSe origin for omitido, é usada a localização do chefe. Se destination for omitido, origin é projetado length blocos na direção guardada na tabela de localização origin.
Pode definir um cone ou raio destas duas 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 }
A forma abreviada com length só aponta na direção pretendida quando origin contém yaw/pitch. As localizações devolvidas pela API (get_location(), get_eye_location(), current_location) incluem esses valores. Uma tabela escrita à mão { x = .., y = .., z = .. } não os inclui, nem em.create_location(x, y, z) sem os argumentos opcionais yaw e pitch.
Se omitir ambos, length vale 0 por predefinição: a forma tem comprimento zero e todas as consultas devolvem resultados vazios sem aviso.
Opções de consulta
| Chave | Notas |
|---|---|
filter | "player" / "players", "elite" / "elites", "mob" / "mobs", "living" (padrão) |
mode | "full" (padrão) ou "border" |
coverage | 0.0 a 1.0 -- fração de localizações a amostrar (padrão 1.0) |
Callbacks de observação
| Chave | Notas |
|---|---|
on_enter | function(entity) -- chamada quando uma entidade entra na zona |
on_leave | function(entity) -- chamada quando uma entidade sai da zona |
Exemplo: consulta básica de esfera
Exemplo
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
}
Exemplo: observação de zona com entrada/saída
Exemplo
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:
- Os callbacks de observadores recebem diretamente um único wrapper de entidade, não via
context.event - Os observadores são limpos automaticamente quando o boss é removido
- Cada observador é executado a cada tick, portanto mantenha a lógica do callback leve
- A entidade do boss é excluída das consultas de zona
Utilitários de script: context.script
Os utilitários de script fornecem resolução de alvos, handles de zona, vetores relativos, geração de partículas e ações de combate.
context.script executa o motor do EliteScriptO context.script não é apenas "nomenclatura ao estilo do EliteScript" -- a tabela de especificação que você passa é convertida num mapa Java simples e entregue diretamente às mesmas classes de alvo, zona, vetor relativo e partículas que fazem funcionar os EliteScripts em YAML. Não existe uma implementação separada.
O que isso significa na prática:
- Todos os campos documentados em Alvos do EliteScript, Zonas do EliteScript e Vetores Relativos do EliteScript funcionam nestas tabelas de especificação, incluindo qualquer campo que esta página não liste.
- Os valores de enum são exatamente em UPPER_SNAKE_CASE (
"NEARBY_PLAYERS","SPHERE","ZONE_FULL"), tal como no YAML. - Os nomes dos campos são os nomes do YAML, por isso
TargeteTarget2são capitalizados, enquantotargetTypeeborderRadiussão camelCase. - O comportamento do YAML em tempo de carregamento também se aplica: um valor que não possa ser interpretado registra um aviso do EliteScript e limpa o campo, em vez de recorrer ao seu valor padrão.
Isto é o oposto do context.zones, que é uma implementação leve genuinamente separada e que usa nomes de kind em minúsculas.
Métodos
| Método | Notas |
|---|---|
script:target(spec) | Cria um handle de alvo a partir de uma tabela de especificação de alvo |
script:zone(spec) | Cria um handle de zona a partir de uma tabela de especificação de zona |
script:relative_vector(spec[, actionLocation][, zoneHandle]) | Cria um handle de vetor relativo |
script:damage(targetHandle, amount[, multiplier]) | Causa dano aos alvos resolvidos |
script:push(targetHandle, vectorOrHandle[, additive]) | Empurra os alvos resolvidos |
script:set_facing(targetHandle, vectorOrHandle) | Define a direção de orientação dos alvos |
script:spawn_particles(targetHandle, particleSpec) | Gera partículas nas localizações dos alvos resolvidos |
Métodos do handle de alvo
| Método | Notas |
|---|---|
handle:entities() | Retorna array de wrappers de entidade |
handle:locations() | Retorna array de tabelas de localização |
handle:first_entity() | Retorna a primeira entidade ou nil |
handle:first_location() | Retorna a primeira localização ou nil |
Chaves de especificação de alvo
| Chave | Padrão | Notas |
|---|---|---|
targetType | "SELF" | Qualquer tipo de alvo do EliteScript |
range | 20 | Alcance para tipos de alvo próximos |
coverage | 1.0 | 0.0 a 1.0. Só é respeitado nos tipos de alvo de zona; em qualquer outro tipo é reposto a 1.0 com um aviso na consola |
offset | 0,0,0 | String "x,y,z" ou tabela { x = n, y = n, z = n } |
relativeOffset | nenhum | Uma tabela de especificação de vetor relativo, para um offset relativo à orientação do boss |
location | nenhum | Localização única, para "LOCATION" |
locations | nenhum | Lista de localizações, para "LOCATIONS" |
track | true | Se deve resolver novamente alvos em movimento |
Todos os 17 tipos de alvo do EliteScript são aceites, não apenas os mais comuns: 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. Os tipos ACTION_TARGET e INHERIT_* só resolvem para algo quando o contexto de EliteScript envolvente existe, pelo que são de pouca utilidade a partir do Lua.
Exemplo: criar e usar um alvo
Exemplo
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 do handle de zona
| Método | Notas |
|---|---|
handle:full_target([coverage]) | Retorna um handle de alvo para o volume completo da zona |
handle:border_target([coverage]) | Retorna um handle de alvo para a borda da zona |
handle:full_locations([coverage]) | Retorna localizações no volume completo da zona |
handle:border_locations([coverage]) | Retorna localizações na borda da zona |
handle:full_entities() | Retorna entidades no volume completo da zona |
handle:border_entities() | Retorna entidades na borda da zona |
handle:contains(location[, "full"|"border"]) | Retorna true se a localização está dentro da zona |
handle:watch(callbacks[, mode]) | Observa a zona para eventos de entrada/saída, retorna ID de tarefa |
Chaves de especificação de zona
| Chave | Padrão | Notas |
|---|---|---|
shape | "CYLINDER" | "SPHERE", "DOME", "CYLINDER", "CUBOID", "CONE", "STATIC_RAY", "ROTATING_RAY", "TRANSLATING_RAY" |
radius | 5 | Sphere, dome, cylinder, cone |
height | 1 | Apenas cylinder |
x, y, z | 0 | Semi-extensões do cuboide |
xBorder, yBorder, zBorder | 0 | Larguras de borda do cuboide |
borderRadius | 1 | Largura da borda para sphere / dome / cylinder / cone |
pointRadius | 0.5 | Espessura do raio |
animationDuration | 0 | Duração da animação em ticks para raios animados |
Target | {targetType = "SELF"} | Especificação de alvo central (tabela) -- usa o mesmo formato de especificação de alvo |
Target2 | nenhum | Segundo ponto. Obrigatório para cones e para todas as formas de raio |
FinalTarget, FinalTarget2 | nenhum | Posições finais, apenas para raio em translação |
filter | "PLAYER" | "PLAYER", "ELITE", "LIVING" -- note que aqui são MAIÚSCULAS, ao contrário do context.zones |
ignoresSolidBlocks | true | Apenas raios |
pitchPreRotation, yawPreRotation | 0 | Apenas raio rotativo |
pitchRotation, yawRotation | 0 | Apenas raio rotativo |
As chaves que não se aplicam à shape escolhida são lidas sem qualquer reclamação e depois ignoradas -- um height numa esfera não faz nada.
Exemplo: zona com dano e partículas
Exemplo
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
}
Chaves de especificação de vetor relativo
| Chave | Notas |
|---|---|
SourceTarget | Especificação do alvo de origem (tabela) |
DestinationTarget | Especificação do alvo de destino (tabela) |
normalize | boolean -- se deve normalizar o vetor resultante |
multiplier | Fator de escala aplicado após a normalização |
offset | String "x,y,z" ou tabela { x = n, y = n, z = n } |
Métodos do handle de vetor relativo
| Método | Notas |
|---|---|
handle:resolve() | Retorna a tabela do vetor calculado |
Exemplo: empurrar alvos com um vetor relativo
Exemplo
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 especificação de partículas
As especificações de partículas podem ser uma string, uma tabela individual ou um array de tabelas. Como este caminho executa o motor de partículas do EliteScript, as chaves são as do EliteScript documentadas em SPAWN_PARTICLE:
| Chave | Padrão | Notas |
|---|---|---|
particle | "FLAME" | Nome da partícula (ex. "FLAME", "DUST", "SMOKE") |
amount | 1 | Número de partículas. 0 transforma x/y/z num vetor de velocidade |
x, y, z | 0.01 | Valores de offset/dispersão, ou velocidade quando o amount é 0 |
speed | 0.01 | Velocidade das partículas |
red, green, blue | 255 | Cor para DUST, DUST_COLOR_TRANSITION, WITCH e outras partículas com dados de cor (0-255) |
toRed, toGreen, toBlue | 255 | Cor de destino de transição para DUST_COLOR_TRANSITION |
material | "STONE" | Bloco ou item mostrado por partículas que transportam dados de bloco/item (BLOCK, ITEM, FALLING_DUST, ...) |
relativeVector | nenhum | Uma especificação de vetor relativo. Defini-la força o amount a 0 e sobrescreve x/y/z com a direção resolvida |
Estas chaves do EliteScript não são as mesmas que o context.world:spawn_particle_at_location(loc, spec) aceita. A tabela world tem o seu próprio leitor, mais pequeno e com valores padrão diferentes (amount 1, x/y/z/speed 0), sem material e sem relativeVector, e aceita adicionalmente to_red / to_green / to_blue em snake_case. Consulte Mundo e Ambiente.
Para a lista completa de nomes de partículas, consulte a Referência de Enums.
Avisos importantes
- Os handles de utilitários de script estão vinculados ao contexto do evento em que foram criados. Não os armazene em
context.statepara uso em uma chamada de hook posterior. watch()de zona retorna um ID de tarefa que pode ser cancelado comcontext.scheduler:cancel_task().- Os valores de coverage aplicam-se apenas à resolução baseada em localização, não a consultas de entidades.
- Todos os valores de string usam os mesmos nomes de enum em UPPER_SNAKE_CASE que o YAML do EliteScript (ex.
"SELF","NEARBY_PLAYERS","SPHERE").
Namespace auxiliar em
O namespace em está disponível globalmente em todos os arquivos de poder Lua. Fornece construtores convenientes para localizações, vetores e definições de zona.
Construtores de localização e vetor
| Função | Notas |
|---|---|
em.create_location(x, y, z[, world][, yaw][, pitch]) | Retorna uma tabela de localização com um método add(dx, dy, dz) |
em.create_vector(x, y, z) | Retorna uma tabela de vetor |
Helpers de construtor de zonas
A sub-tabela em.zone fornece funções construtoras que retornam tabelas de definição de zona compatíveis com context.zones. Cada construtor retorna uma tabela com métodos mutadores encadeáveis.
| Função | 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-extensões) | :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 não é usadoOs construtores de cone e de raio guardam o length na tabela de especificação, mas o context.zones nunca o lê -- a forma vai do origin até ao destination. Encadeie sempre :set_origin(...) e :set_destination(...) nestes construtores; caso contrário, ambos recorrem à localização do boss e a forma fica com comprimento zero.
Exemplo
Exemplo
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
}
O namespace em não é por instância -- todas as instâncias de poder Lua compartilham as mesmas funções auxiliares em. As funções são construtores puros e não carregam nenhum estado.
Zonas nativas vs. Utilitários de script
Ambos os sistemas trabalham com a mesma geometria de zona subjacente. Aqui está quando usar cada um:
| Caso de uso | Abordagem recomendada |
|---|---|
| Verificação simples de "há algo nesta área?" | Zonas nativas (context.zones) |
| Consulta rápida de entidades com uma forma | Zonas nativas |
NEARBY_PLAYERS, ZONE_FULL com coverage | Utilitários de script (context.script) |
| Zonas animadas (raios rotativos/em translação) | Ambos -- as zonas nativas também suportam estas formas |
Handles de zona com métodos watch/contains/entities | Utilitários de script |
| Geração de partículas em localizações de zona | Utilitários de script (spawn_particles) |
| Ações de dano e empurrão vinculadas a alvos | Utilitários de script (damage, push) |
| Vetores relativos para efeitos direcionais | Utilitários de script (relative_vector) |
| Combinar fluxo de controle Lua com segmentação avançada | Utilitários de script |
Na prática, muitos poderes usam ambos. As zonas nativas são ótimas para a verificação inicial de "há jogadores por perto?" em um guard de cooldown, enquanto os utilitários de script lidam com a lógica de ataque complexa que se segue.
Próximos passos
- Exemplos e padrões -- poderes funcionais completos que você pode estudar e adaptar
- Scripts de NPC -- hooks de proximidade de NPC para comportamentos simples de aproximação/afastamento
- Referência de Enums -- valores válidos para Particle, Sound, Material e outras constantes de string
