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 (или type) | string | — | "sphere", "dome", "cylinder", "cuboid", "cone", "static_ray", "rotating_ray", "translating_ray" |
radius | number | 0 | Радиус зоны (sphere, dome, cylinder, cone) |
height | number | 0 | Высота цилиндра |
origin | location | позиция босса | Начало формы: основание цилиндра, вершина конуса или начало луча |
destination | location | позиция босса | Конечная точка для лучей и конусов |
x, y, z | number | 0 | Размеры параллелепипеда; см. различия геометрии точек и сущностей |
thickness / point_radius / pointRadius | number | 0.5 | Радиус и шаг выборки луча; используйте положительное значение |
border_radius / borderRadius | number | 1 | Внутренний радиус, исключаемый из внешней формы |
x_border, y_border, z_border | number | 1 | Размеры внутреннего параллелепипеда |
animation_duration | int | 0 | Длительность анимации в тиках для анимированных лучей |
pitch_pre_rotation, yaw_pre_rotation | number | 0 | Углы предварительного вращения (вращающийся луч) |
pitch_rotation, yaw_rotation | number | 0 | Общий поворот за анимацию; текущий аниматор применяет только положительные приращения |
origin_end, destination_end | location | позиция босса | Конечные позиции для перемещающегося луча |
ignores_solid_blocks | boolean | true | Проходят ли лучи через твёрдые блоки |
length | number | 0 | Сохраняется конструкторами, но отсутствующий destination становится позицией босса до применения этого резерва; задавайте явную конечную точку |
Числовые и логические поля с подчёркиваниями также принимают camelCase (borderRadius, xBorder, animationDuration, pitchPreRotation, ignoresSolidBlocks). Поля позиций origin_end и destination_end требуют имён с подчёркиваниями. Таблицы EliteScript Target не заменяют нативные поля позиций.
kind чувствителен к региструkind сопоставляется точно и должен быть в нижнем регистре. "SPHERE" и "Sphere" не совпадают ни с одной формой: запросы возвращают пустой список без предупреждения в консоли.
При отсутствии origin или destination используется текущая позиция босса. Текущий обработчик позиций не позволяет заменить отсутствующую конечную точку значением length. Задайте разные точки:
local explicit_ray = { kind = "static_ray", origin = context.boss:get_eye_location(),
destination = context.player:get_eye_location() }
Чтобы анимировать перемещающийся луч, задайте origin_end, destination_end и положительный animation_duration. Опущенная конечная точка остаётся в начальной позиции. Нулевая длительность создаёт неподвижный исходный луч; отрицательная длительность отклоняется. Последний кадр анимации заканчивается точно в запрошенных конечных точках.
Все концы и проверяемые позиции должны находиться в текущем мире босса: нативные запросы сущностей ищут в этом мире. Пропущенные координаты в таблице позиции равны 0; без мира используется мир босса, а явно названный мир должен быть загружен. Размеры должны быть конечными и положительными. Проверки точек, выборка частиц и проверки сущностей не взаимозаменяемы. Общие ограничения форм включают сферическую проверку сущностей для полного купола, проверку всей высоты сущности в цилиндре и разные границы параллелепипеда.
Параметры запроса
| Ключ | Примечания |
|---|---|
filter | "player" / "players", "elite" / "elites", "mob" / "mobs", "living" (по умолчанию) |
mode | "full" (по умолчанию) или "border" |
coverage | от 0.0 до 1.0 -- доля позиций для выборки (по умолчанию 1.0) |
filter не учитывает регистр; неизвестные значения используют living. mobs означает живых сущностей, кроме игроков, включая элитных мобов. Сам босс исключён, но игроки не фильтруются по режиму игры. mode распознаёт border без учёта регистра; остальные значения используют full. Coverage случайно выбирает позиции, а не сущности, и не ограничивает состав наблюдателя. Для лучей используйте full: граничные позиции не поддерживаются и могут вызвать ошибку запроса позиций.
Колбэки наблюдения
| Ключ | Примечания |
|---|---|
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 - Наблюдатели вызывают собственные
on_enter/on_leave, а не верхнеуровневые хуки способностиon_zone_enter/on_zone_leave - Наблюдатели автоматически очищаются при удалении босса
- Нативный наблюдатель создаёт форму один раз. Центр не следует за боссом; изменение исходной таблицы не перемещает существующий наблюдатель. Для движущейся области используйте новые запросы или скриптовую зону с отслеживаемой целью.
- Каждый наблюдатель работает каждый тик, поэтому логика колбэка должна быть лёгкой
- Сущность босса исключается из запросов зоны
Первая проверка происходит через один тик; уже находящиеся внутри сущности вызывают on_enter. Отмена или очистка не вызывает on_leave для оставшихся участников. В этом примере сфера остаётся в точке появления. Замедление длится 40 тиков после входа; пребывание внутри не продлевает его, а выход не снимает досрочно.
Скриптовые утилиты: context.script
Скриптовые утилиты предоставляют разрешение целей, дескрипторы зон, относительные векторы, генерацию частиц и боевые действия.
context.script запускает движок EliteScriptТаблица спецификации преобразуется в Java map и передаётся классам целей, зон, относительных векторов и частиц, используемым YAML-EliteScript.
Что это значит на практике:
- Таблицы используют обработчики из Целей EliteScript, Зон EliteScript и Относительных векторов EliteScript, включая их ограничения. Принятое поле не гарантирует наличия нужного жизненного цикла действия или унаследованного контекста у Lua-дескриптора.
- Значения перечислений — точный UPPER_SNAKE_CASE (
"NEARBY_PLAYERS","SPHERE","ZONE_FULL"), как и в YAML. - Используйте приведённые канонические имена YAML:
Target,Target2,targetType,borderRadius. Внутренние обработчики полей не учитывают регистр. - Неверные значения могут вызвать предупреждения, резервные значения или оставить отсутствующие поля, приводящие к ошибке позже. Принятие таблицы не проверяет всю операцию.
context.zones имеет отдельный обработчик таблиц с именами kind в нижнем регистре, но использует те же классы геометрии. Передавайте непустые таблицы с именованными полями: пустая Lua-таблица {} преобразуется в Java-список, поэтому даже script:target({}) завершится ошибкой. Используйте script:target({targetType = "SELF"}).
Методы
| Метод | Примечания |
|---|---|
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) | Генерирует частицы в позициях разрешённых целей |
damage, push, set_facing и spawn_particles требуют дескриптор цели, а не массив сущностей, и ничего не возвращают. Они не применяют условия, задержки или фильтры YAML-действий. damage передаёт величину урона в Bukkit с боссом в роли атакующего; необязательный множитель действует на путь боя с игроками, а итоговая потеря здоровья зависит от обработки боя. push сразу определяет цели и один вектор, затем применяет этот вектор ко всем целям на следующем тике. Скорость заменяется, кроме случая additive = true: тогда вектор прибавляется к скорости того тика. set_facing сразу задаёт одно направление всем целям. Проверяйте, что направление ненулевое и конечное.
Методы дескриптора цели
| Метод | Примечания |
|---|---|
handle:entities() | Возвращает массив обёрток сущностей |
handle:locations() | Возвращает массив таблиц позиций |
handle:first_entity() | Возвращает первую сущность или nil |
handle:first_location() | Возвращает первую позицию или nil |
Каждый метод заново определяет результат; first_* не читает общий снимок и не гарантирует ближайшую цель. DIRECT_TARGET — цель, захваченная событием, а не текущая боевая цель босса. Если событие не предоставляет цель, ничего не выбирается.
Ключи спецификации цели
| Ключ | По умолчанию | Примечания |
|---|---|---|
targetType | "SELF" | Любой тип цели EliteScript |
range | 20 | Полуширина поискового прямоугольного объёма по каждой оси; результаты не сортируются по расстоянию |
coverage | 1.0 | От 0.0 до 1.0; только для зональных целей. Для других типов значения ниже 1.0 сбрасываются в 1.0 с предупреждением |
offset | 0,0,0 | Строка "x,y,z" с запятыми; это поле EliteScript не принимает Lua-таблицу вектора |
relativeOffset | нет | Спецификация относительного вектора; исходная и конечная цели задают направление |
location | нет | Сериализованная строка "world,x,y,z,yaw,pitch" для "LOCATION" |
locations | нет | Массив сериализованных строк позиций для "LOCATIONS" |
track | true | Нужно ли повторно разрешать движущиеся цели |
Lua-дескрипторы не выполняют этап кеширования целей YAML-действий. Поэтому track = false не фиксирует позицию статической Lua-цели или зоны. Статические зоны заново определяют начало при каждом запросе; анимированные сохраняют формы при создании. Для неподвижной области задайте LOCATION с явными координатами или нативную зону с захваченным origin. offset и relativeOffset смещают все позиции, которые определяет дескриптор, включая LOCATION, LOCATIONS, SELF_SPAWN, цели на основе сущностей и выбранные точки зон; они не перемещают сущности, возвращаемые entities(), а LANDING_LOCATION и INHERIT_SCRIPT_TARGET их игнорируют. full_target() и border_target() дескриптора зоны не принимают смещение, поэтому задавайте смещения в спецификациях Target и Target2 зоны. См. общие атрибуты.
Парсер принимает все 17 имён: 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. Самостоятельные Lua-дескрипторы не предоставляют унаследованных данных действий и позиции приземления. Избегайте INHERIT_* и LANDING_LOCATION: они могут завершиться ошибкой при разрешении. ACTION_TARGET имеет смысл лишь в совместимом контексте относительного вектора или действия. См. ограничения наследуемых зон.
Для ZONE_FULL и ZONE_BORDER получайте цель из дескриптора зоны; у самостоятельного script:target(...) зоны нет. Lua-методы частиц сохраняют стандартную coverage 1.0, не применяя стандарт 0.3 YAML-действия SPAWN_PARTICLE.
Пример: создание и использование цели
Пример
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 along each axis
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
-- First resolved entity; this does not promise the nearest player.
local first = nearby:first_entity()
if first then
first: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 | "CYLINDER" | "SPHERE", "DOME", "CYLINDER", "CUBOID", "CONE", "STATIC_RAY", "ROTATING_RAY", "TRANSLATING_RAY" |
radius | 5 | Сфера, купол, цилиндр, конус |
height | 1 | Только цилиндр; запрос сущностей требует, чтобы сущность помещалась по всей высоте |
x, y, z | 0 | Размеры параллелепипеда; см. различия геометрии точек и сущностей |
xBorder, yBorder, zBorder | 0 | Размеры внутреннего параллелепипеда |
borderRadius | 1 | Внутренний радиус сферы, купола, цилиндра и конуса |
pointRadius | 0.5 | Положительные радиус и шаг выборки луча |
animationDuration | 0 | Длительность анимации в тиках для анимированных лучей |
Target | {targetType = "SELF"} | Спецификация центральной цели (таблица) -- использует тот же формат спецификации цели |
Target2 | нет | Вторая точка. Обязательна для конусов и всех форм лучей |
FinalTarget, FinalTarget2 | нет | Конечные позиции, только для перемещающегося луча |
filter | "PLAYER" | "PLAYER", "ELITE", "LIVING" — учтите, что здесь они в ВЕРХНЕМ регистре, в отличие от context.zones |
ignoresSolidBlocks | true | Только лучи |
pitchPreRotation, yawPreRotation | 0 | Только вращающийся луч |
pitchRotation, yawRotation | 0 | Только вращающийся луч |
Ключи, не относящиеся к выбранной shape, читаются без нареканий и затем игнорируются — height у сферы ничего не делает.
contains проверяет точку, а не ограничивающий объём сущности. watch использует те же колбэки и время первой проверки, что и нативные наблюдатели. Отменяйте возвращённый ID через context.scheduler:cancel_task(id); отмена не вызывает колбэки выхода. Статическая скриптовая зона может следовать за SELF, определяя его каждый тик; анимированный дескриптор сохраняет формы. borderRadius — внутренний радиус, не толщина границы. Для лучей используйте полные цели.
Пример: зона с уроном и частицами
Пример
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)
-- First repeat after 20 ticks, then every 20 ticks.
context.state.zone_task_id = context.scheduler:run_repeating(20, 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
}
В этом примере урон наносится сразу при показе частиц: задержки предупреждения нет. Повторы начинаются через 20 тиков и прекращаются при выходе из боя. Стандартный внутренний радиус 1 создаёт толстую оболочку внутри радиуса 6, а не тонкое кольцо.
Ключи спецификации относительного вектора
| Ключ | Примечания |
|---|---|
SourceTarget | Спецификация исходной цели (таблица) |
DestinationTarget | Спецификация целевой цели (таблица) |
normalize | Логическое значение, стандарт false; нормализовать ли вектор |
multiplier | Множитель после нормализации, стандарт 1 |
offset | Строка "x,y,z" с запятыми, стандарт "0,0,0"; не Lua-таблица вектора |
Методы дескриптора относительного вектора
| Метод | Примечания |
|---|---|
handle:resolve() | Возвращает вычисленную таблицу вектора |
Задайте обе спецификации целей. Используется первая позиция каждой: конечная минус исходная, необязательная нормализация, умножение, затем смещение по осям мира. Пустые результаты или разные миры возвращают ноль до применения смещения; нормализация совпадающих точек может дать неконечный вектор. ACTION_TARGET использует переданную actionLocation, по умолчанию позицию босса при создании дескриптора. Она не заменяется отдельно для каждой толкаемой сущности. Если целям вектора нужна зона, передайте её дескриптор третьим аргументом.
Пример: толкание целей с помощью относительного вектора
Пример
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
}
Формат спецификации частиц
Спецификации частиц могут быть строкой, одной таблицей или массивом таблиц. Поскольку этот путь запускает движок частиц EliteScript, ключи здесь — те же, что описаны в SPAWN_PARTICLE:
| Ключ | По умолчанию | Примечания |
|---|---|---|
particle | "FLAME" | Название частицы (напр. "FLAME", "DUST", "SMOKE") |
amount | 1 | Количество частиц; при 0 направленное поведение зависит от типа частицы |
x, y, z | 0.01 | Значения смещения/разброса или скорость, когда amount равен 0 |
speed | 0.01 | Скорость частиц |
red, green, blue | 255 | Цвет DUST, DUST_COLOR_TRANSITION и частиц, требующих данные Color (0–255); WITCH не использует эти значения |
toRed, toGreen, toBlue | 255 | Конечный цвет перехода для DUST_COLOR_TRANSITION |
material | "STONE" | Блок или предмет, отображаемый частицами, которые несут данные блока/предмета (BLOCK, ITEM, FALLING_DUST, ...) |
relativeVector | нет | Спецификация относительного вектора. Её задание принудительно устанавливает amount в 0 и перезаписывает x/y/z разрешённым направлением |
Размер пыли фиксирован и равен 1. moveToTarget читается, но не перемещает частицы. Неподдерживаемые типы данных пропускаются с предупреждением. Метод смещает позиции частиц зоны и LOCATION / LOCATIONS на +0.5 по X и Z; позиции, возвращаемые дескрипторами, не смещаются.
Эти ключи EliteScript не совпадают с теми, что принимает context.world:spawn_particle_at_location(loc, spec). У таблицы world собственный, более скромный обработчик с другими значениями по умолчанию (amount 1, x/y/z/speed 0), без material и без relativeVector, и он дополнительно принимает to_red / to_green / to_blue в snake_case. См. Мир и окружение.
Полный список названий частиц см. в Справочнике перечислений.
Важные предупреждения
- Дескрипторы скриптовых утилит привязаны к контексту события, в котором они были созданы. Не сохраняйте их в
context.stateдля использования в последующем вызове хука. context.script:zone(...):watch(...)возвращает ID, отменяемый черезcontext.scheduler:cancel_task().context.zones:watch_zone(...)ничего не возвращает и очищается автоматически вместе со способностью.- Значения coverage применяются только к разрешению на основе позиций, а не к запросам сущностей.
- Перечисления целей, форм и фильтров используют имена UPPER_SNAKE_CASE из EliteScript YAML (например,
"SELF","NEARBY_PLAYERS","SPHERE"). Режимы watch/contains остаются"full"или"border".
Вспомогательное пространство имён 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) |
Конструкторы конусов и лучей сохраняют length, но текущий нативный обработчик позиций заменяет отсутствующую конечную точку позицией босса. Вызывайте по цепочке :set_origin(...) и :set_destination(...); не рассчитывайте на length для направления формы. Перемещающимся лучам также нужны origin_end, destination_end и положительный animation_duration в возвращённой таблице.
Пример
Пример
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, boss_loc.world)
-- 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
}
У каждого экземпляра скрипта собственная Lua-среда и пространство em. Конструкторы возвращают новые таблицы; метод позиции add(...) и сеттеры зоны изменяют таблицу, на которой вызваны.
Нативные зоны vs. Скриптовые утилиты
Обе системы работают с одной и той же базовой геометрией зон. Вот когда использовать каждую:
| Сценарий использования | Рекомендуемый подход |
|---|---|
| Простая проверка «есть ли что-нибудь в этой области?» | Нативные зоны (context.zones) |
| Быстрый запрос сущностей по форме | Нативные зоны |
NEARBY_PLAYERS, ZONE_FULL с coverage | Скриптовые утилиты (context.script) |
| Анимированные зоны (вращающиеся/перемещающиеся лучи) | Скриптовые дескрипторы зон для повторного чтения; нативные наблюдатели тоже сохраняют анимированную форму |
Дескрипторы зон с методами watch/contains/entities | Скриптовые утилиты |
| Генерация частиц в позициях зоны | Скриптовые утилиты (spawn_particles) |
| Действия урона и толчка, привязанные к нацеливанию | Скриптовые утилиты (damage, push) |
| Относительные векторы для направленных эффектов | Скриптовые утилиты (relative_vector) |
| Сочетание потока управления Lua с богатым нацеливанием | Скриптовые утилиты |
В одной способности можно применять обе API. Выбирайте по нужным целям и жизненному циклу: нативные запросы по умолчанию выбирают живых сущностей, кроме босса, а скриптовые зоны — игроков.
Следующие шаги
- Примеры и паттерны -- полностью рабочие способности для изучения и адаптации
- Скрипты NPC -- хуки близости NPC для простого приближения и удаления
- Справочник перечислений -- допустимые значения для Particle, Sound, Material и других строковых констант
