Lua-скриптинг: Зоны и нацеливание

Lua-возможности EliteMobs предлагают два взаимодополняющих подхода для определения пространственных областей и разрешения целей:
- Нативные зоны (
context.zones) -- простые и прямые. Вы создаёте определение зоны как обычную Lua-таблицу и запрашиваете её на наличие сущностей или позиций. Лучше всего подходит для простых проверок «есть ли что-нибудь в этой области?».
- Скриптовые утилиты (
context.script) -- более богатое нацеливание, дескрипторы зон с методами watch/contains/entities, генерация частиц, нанесение урона и действия толчка. Используют те же имена полей, что и Зоны EliteScript и Цели EliteScript для привычности.
Оба подхода являются нативными Lua API. Выберите тот, который соответствует сложности вашей способности.
Нативные зоны: context.zones
Нативные зоны позволяют определять зоны как обычные Lua-таблицы и запрашивать их напрямую. Без дескрипторов, без дополнительной абстракции -- просто таблица, описывающая форму, и вызов метода для запроса.
Методы
| Метод | Примечания |
|---|
zones:get_entities_in_zone(zoneDef, options) | Возвращает массив обёрток сущностей внутри зоны |
zones:get_locations_in_zone(zoneDef, options) | Возвращает массив таблиц позиций внутри зоны |
zones:zone_contains(zoneDef, location[, "full"|"border"]) | Возвращает true, если позиция находится внутри зоны |
zones:watch_zone(zoneDef, callbacks, options) | Регистрирует постоянный наблюдатель зоны, срабатывающий каждый тик |
Поля определения зоны
| Поле | Тип | Примечания |
|---|
kind | string | "sphere", "dome", "cylinder", "cuboid", "cone", "static_ray", "rotating_ray", "translating_ray" |
radius | number | Радиус зоны (sphere, dome, cylinder, cone) |
height | number | Высота цилиндра |
origin | location | Центральная позиция (по умолчанию позиция босса, если не указано) |
destination | location | Конечная точка для лучей и конусов |
x, y, z | number | Полуразмеры параллелепипеда |
length | number | Длина для конусов и лучей |
thickness / point_radius | number | Толщина луча |
border_radius | number | Ширина границы (по умолчанию 1) |
x_border, y_border, z_border | number | Ширина границ параллелепипеда (по умолчанию 1) |
animation_duration | int | Длительность анимации в тиках для анимированных лучей |
pitch_pre_rotation, yaw_pre_rotation | number | Углы предварительного вращения (вращающийся луч) |
pitch_rotation, yaw_rotation | number | Углы вращения за тик (вращающийся луч) |
origin_end, destination_end | location | Конечные позиции для перемещающегося луча |
ignores_solid_blocks | boolean | Проходят ли лучи через твёрдые блоки (по умолчанию true) |
Параметры запроса
| Ключ | Примечания |
|---|
filter | "player" / "players", "elite" / "elites", "mob" / "mobs", "living" (по умолчанию) |
mode | "full" (по умолчанию) или "border" |
coverage | от 0.0 до 1.0 -- доля позиций для выборки (по умолчанию 1.0) |
Колбэки наблюдения
| Ключ | Примечания |
|---|
on_enter | function(entity) -- вызывается, когда сущность входит в зону |
on_leave | function(entity) -- вызывается, когда сущность покидает зону |
Пример: базовый запрос сферы
Пример
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
}
Пример: наблюдение за зоной с входом/выходом
Пример
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
}
Примечания о наблюдателях:
- Колбэки наблюдателей получают одну обёртку сущности напрямую, а не через
context.event
- Наблюдатели автоматически очищаются при удалении босса
- Каждый наблюдатель работает каждый тик, поэтому логика колбэка должна быть лёгкой
- Сущность босса исключается из запросов зоны
Скриптовые утилиты: context.script
Скриптовые утилиты предоставляют разрешение целей, дескрипторы зон, относительные векторы, генерацию частиц и боевые действия. Они используют те же имена полей, что и Зоны EliteScript и Цели EliteScript для привычности -- имена перечислений (такие как "NEARBY_PLAYERS", "SPHERE", "ZONE_FULL") идентичны, чтобы авторы, уже знакомые с EliteScript, могли напрямую перенести эти знания.
context.script — это нативный Lua API. Это не мост к YAML или к среде выполнения EliteScript. Он просто повторно использует те же соглашения об именовании, чтобы вам не нужно было изучать второй набор имён перечислений.
Методы
| Метод | Примечания |
|---|
script:target(spec) | Создаёт дескриптор цели из таблицы спецификации цели |
script:zone(spec) | Создаёт дескриптор зоны из таблицы спецификации зоны |
script:relative_vector(spec[, actionLocation][, zoneHandle]) | Создаёт дескриптор относительного вектора |
script:damage(targetHandle, amount[, multiplier]) | Наносит урон разрешённым целям |
script:push(targetHandle, vectorOrHandle[, additive]) | Толкает разрешённые цели |
script:set_facing(targetHandle, vectorOrHandle) | Устанавливает направление взгляда для целей |
script:spawn_particles(targetHandle, particleSpec) | Генерирует частицы в позициях разрешённых целей |
Методы дескриптора цели
| Метод | Примечания |
|---|
handle:entities() | Возвращает массив обёрток сущностей |
handle:locations() | Возвращает массив таблиц позиций |
handle:first_entity() | Возвращает первую сущность или nil |
handle:first_location() | Возвращает первую позицию или nil |
Ключи спецификации цели
| Ключ | Примечания |
|---|
targetType | "SELF", "DIRECT_TARGET", "NEARBY_PLAYERS", "NEARBY_MOBS", "NEARBY_ELITES", "ZONE_FULL", "ZONE_BORDER", "ALL_PLAYERS", "WORLD_PLAYERS", "SELF_SPAWN", "LOCATION" |
range | Дальность для ближних типов целей |
coverage | от 0.0 до 1.0 для целей зоны |
offset | Строка "x,y,z" или таблица { x = n, y = n, z = n } |
track | Нужно ли повторно разрешать движущиеся цели |
Пример: создание и использование цели
Пример
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
}
Методы дескриптора зоны
| Метод | Примечания |
|---|
handle:full_target([coverage]) | Возвращает дескриптор цели для полного объёма зоны |
handle:border_target([coverage]) | Возвращает дескриптор цели для границы зоны |
handle:full_locations([coverage]) | Возвращает позиции в полном объёме зоны |
handle:border_locations([coverage]) | Возвращает позиции на границе зоны |
handle:full_entities() | Возвращает сущности в полном объёме зоны |
handle:border_entities() | Возвращает сущности на границе зоны |
handle:contains(location[, "full"|"border"]) | Возвращает true, если позиция находится внутри зоны |
handle:watch(callbacks[, mode]) | Наблюдает за зоной на предмет событий входа/выхода, возвращает ID задачи |
Ключи спецификации зоны
| Ключ | Примечания |
|---|
shape | "SPHERE", "DOME", "CYLINDER", "CUBOID", "CONE", "STATIC_RAY", "ROTATING_RAY", "TRANSLATING_RAY" |
radius | Радиус зоны |
height | Высота цилиндра |
x, y, z | Полуразмеры параллелепипеда |
borderRadius | Ширина границы |
pointRadius | Толщина луча |
animationDuration | Длительность анимации в тиках для анимированных лучей |
Target | Спецификация центральной цели (таблица) -- использует тот же формат спецификации цели |
Target2 | Вторая точка для лучей и конусов |
filter | Фильтр сущностей |
ignoresSolidBlocks | boolean |
pitchPreRotation, yawPreRotation | Углы предварительного вращения |
pitchRotation, yawRotation | Углы вращения за тик |
Пример: зона с уроном и частицами
Пример
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
}
Ключи спецификации относительного вектора
| Ключ | Примечания |
|---|
SourceTarget | Спецификация исходной цели (таблица) |
DestinationTarget | Спецификация целевой цели (таблица) |
normalize | boolean -- нужно ли нормализовать результирующий вектор |
multiplier | Коэффициент масштабирования, применяемый после нормализации |
offset | Строка "x,y,z" или таблица { x = n, y = n, z = n } |
Методы дескриптора относительного вектора
| Метод | Примечания |
|---|
handle:resolve() | Возвращает вычисленную таблицу вектора |
Пример: толкание целей с помощью относительного вектора
Пример
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 | Название частицы (напр. "FLAME", "DUST", "SMOKE") |
amount | Количество частиц |
x, y, z | Значения смещения/разброса |
speed | Скорость частиц |
red, green, blue | Цвет для DUST / DUST_COLOR_TRANSITION (0-255) |
toRed, toGreen, toBlue | Целевой цвет перехода для DUST_COLOR_TRANSITION |
Полный список названий частиц см. в Справочнике перечислений.
Важные предупреждения
- Дескрипторы скриптовых утилит привязаны к контексту события, в котором они были созданы. Не сохраняйте их в
context.state для использования в последующем вызове хука.
watch() зоны возвращает ID задачи, который можно отменить с помощью context.scheduler:cancel_task().
- Значения coverage применяются только к разрешению на основе позиций, а не к запросам сущностей.
- Все строковые значения используют те же имена перечислений в UPPER_SNAKE_CASE, что и EliteScript YAML (напр.
"SELF", "NEARBY_PLAYERS", "SPHERE").
Вспомогательное пространство имён em
Пространство имён em доступно глобально во всех файлах Lua-способностей. Оно предоставляет удобные конструкторы для позиций, векторов и определений зон.
Конструкторы позиций и векторов
| Функция | Примечания |
|---|
em.create_location(x, y, z[, world][, yaw][, pitch]) | Возвращает таблицу позиции с методом add(dx, dy, dz) |
em.create_vector(x, y, z) | Возвращает таблицу вектора |
Вспомогательные функции построения зон
Подтаблица em.zone предоставляет функции-конструкторы, возвращающие таблицы определения зон, совместимые с context.zones. Каждый конструктор возвращает таблицу с цепочечными методами-мутаторами.
| Функция | Параметры | Мутаторы |
|---|
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 (полуразмеры) | :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) |
Пример
Пример
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
}
Пространство имён em не является экземплярным -- все экземпляры Lua-способностей разделяют одни и те же вспомогательные функции em. Функции являются чистыми конструкторами и не хранят состояния.
Нативные зоны vs. Скриптовые утилиты
Обе системы работают с одной и той же базовой геометрией зон. Вот когда использовать каждую:
| Сценарий использования | Рекомендуемый подход |
|---|
| Простая проверка «есть ли что-нибудь в этой области?» | Нативные зоны (context.zones) |
| Быстрый запрос сущностей по форме | Нативные зоны |
NEARBY_PLAYERS, ZONE_FULL с coverage | Скриптовые утилиты (context.script) |
| Анимированные зоны (вращающиеся/перемещающиеся лучи) | Оба -- нативные зоны тоже поддерживают эти формы |
Дескрипторы зон с методами watch/contains/entities | Скриптовые утилиты |
| Генерация частиц в позициях зоны | Скриптовые утилиты (spawn_particles) |
| Действия урона и толчка, привязанные к нацеливанию | Скриптовые утилиты (damage, push) |
| Относительные векторы для направленных эффектов | Скриптовые утилиты (relative_vector) |
| Сочетание потока управления Lua с богатым нацеливанием | Скриптовые утилиты |
На практике многие способности используют оба подхода. Нативные зоны отлично подходят для начальной проверки «есть ли рядом игроки?» в защите от перезарядки, а скриптовые утилиты обрабатывают сложную логику атаки, которая следует за ней.
Следующие шаги