Перейти к основному содержимому

Lua-скриптинг: Мир и окружение

webapp_banner.jpg

Эта страница описывает расширения context.world для боссов EliteMobs, а также context.vectors, context.settings и context.event. Они позволяют Lua-способностям создавать сущности, воспроизводить эффекты, запрашивать блоки и менять состояние мира. Новичкам стоит начать с раздела Начало работы.

Контекст босса EliteMobs

Способности боссов используют Lua-песочницу MagmaCore. Их context.world создаётся на основе общей таблицы мира MagmaCore, поэтому координатные методы get_block_at(...), set_block_at(...) и spawn_particle(...) остаются доступны. Здесь описаны дополнения и переопределения EliteMobs для context.world, context.vectors, context.settings и context.event. Общий API мира описан в разделе Lua-движок MagmaCore.

При совпадении имён используется версия EliteMobs. Методы ниже сохраняют поведение EliteMobs, включая обход защиты создания молнии, расширенные параметры частиц и учёт временных блоков. Другие общие методы остаются доступны: get_entity(uuid), block_is_passable(x, y, z), location_is_protected(location), spawn_dust(...) и raycast(...). Их аргументы и поведение в незагруженных чанках приведены в общем справочнике API. Эти гарантии не распространяются автоматически на переопределения EliteMobs.

Методы добычи FreeMinecraftModels здесь недоступны

FreeMinecraftModels добавляет drop_elitemobs_procedural_loot, drop_elitemobs_random_loot, drop_elitemobs_custom_loot и start_elitemobs_transport в context.world только в собственных скриптах пропов. Каждый плагин содержит отдельную копию общей библиотеки скриптинга, поэтому эти методы не появляются в способностях боссов EliteMobs и скриптах NPC, даже если FreeMinecraftModels установлен. Способности боссов используют вместо них generate_player_loot и drop_bonus_coins.


context.world​

Таблица world предоставляет методы создания сущностей, воспроизведения эффектов, изменения блоков и состояния мира. Они поддерживают двоеточие world:method() и точку без явного аргумента self.

Переопределения босса преобразуют таблицы местоположения с полями x, y, z, необязательными yaw/pitch и именем загруженного мира в world. Отсутствующие координаты равны 0; без мира используется текущий мир босса, но явно неизвестный мир приводит к неудаче преобразования. Допускается вложенная таблица current_location. nil или значение не в виде таблицы заменяется позицией босса. Общие методы сохраняют собственные правила преобразования и мир, зафиксированный при создании таблицы.

Закрытие Lua-экземпляра не отменяет изменения мира и не удаляет автоматически созданные сущности. Наблюдатели, принадлежащие скрипту, останавливаются, но независимые таймеры удаления сущностей, восстановление взрывов, усиленная молния и задачи золотых снарядов имеют собственный срок работы. Переопределения блоков и спавна не проверяют автоматически location_is_protected и загрузку чанков по правилам общего API. Проверяйте нужные ограничения перед изменением мира.


world:spawn_particle_at_location(location, particleSpec)​

Создаёт частицы в указанном месте. Второй аргумент принимает имя частицы или таблицу параметров. Необязательный третий целочисленный аргумент задаёт количество, если amount отсутствует; по умолчанию 1. Перед поиском имена переводятся в верхний регистр. Неизвестное имя или неподдерживаемые данные вызывают предупреждение, частицы не создаются.

ПараметрТипПримечания
locationlocation tableКуда спавнить частицы
particleSpecстрока или таблицаИмя частицы или таблица параметров частиц (см. ниже)
Пример
return {
api_version = 1,
on_enter_combat = function(context)
-- Simple particle by name
context.world:spawn_particle_at_location(context.boss:get_location(), "FLAME")

-- Full particle spec table with red dust
context.world:spawn_particle_at_location(context.boss:get_location(), {
particle = "DUST",
amount = 10,
x = 0.5,
y = 0.5,
z = 0.5,
speed = 0.02,
red = 255,
green = 0,
blue = 0,
})
end
}

Формат таблицы спецификации частиц​

КлючТипПо умолчаниюПримечания
particlestringобязательныйИмя частицы
amountint1Количество частиц
x, y, znumber0Разброс/смещение по каждой оси
speednumber0Скорость частиц
red, green, blueint255Цвет RGB для DUST и DUST_COLOR_TRANSITION
toRed, toGreen, toBlueint255Целевой цвет перехода для DUST_COLOR_TRANSITION
подсказка

Для DUST_COLOR_TRANSITION также допускаются ключи to_red, to_green, to_blue, но значения camelCase имеют приоритет. Размер обеих пылевых частиц фиксирован и равен 1; компоненты RGB должны быть в диапазоне 0..255. Другие частицы не получают дополнительных данных, поэтому метод поддерживает не все частицы, которым такие данные нужны.

внимание

В отличие от YAML EliteScript, имена частиц Lua не преобразуются из устаревших названий. Используйте текущие имена Spigot API: FIREWORK вместо FIREWORKS_SPARK, SMOKE вместо SMOKE_NORMAL, DUST вместо REDSTONE. Текущие и прежние названия приведены в списке допустимых частиц.


world:play_sound_at_location(location, sound, volume, pitch)​

Воспроизводит звук в указанном месте.

ПараметрТипПо умолчаниюПримечания
locationlocation tableГде воспроизвести звук
soundstringКлюч звука Minecraft, например "entity.blaze.shoot", или имя перечисления Spigot Sound. Ключи из ресурс-пака тоже работают.
volumenumber1.0Громкость
pitchnumber1.0Высота тона
Пример
return {
api_version = 1,
on_spawn = function(context)
context.world:play_sound_at_location(
context.boss:get_location(),
"entity.wither.spawn",
1.0,
0.5
)
end
}

world:strike_lightning_at_location(location)​

Создаёт настоящую молнию с уроном и включает обход защиты создания молнии EliteMobs. Это отличается от общего метода чисто визуальной молнии. Обход не гарантирует игнорирование всех правил урона и защиты других плагинов.

ПараметрТипПримечания
locationlocation tableКуда бить
Пример
return {
api_version = 1,
on_boss_damaged_by_player = function(context)
if context.player == nil then return end
if not context.cooldowns:check_local("lightning", 100) then return end
context.world:strike_lightning_at_location(context.player:get_location())
context.player:send_message("&eA bolt of lightning strikes you!")
end
}

world:spawn_entity_at_location(entityType, location, options)​

Создаёт ванильную сущность непосредственно в мире указанной позиции. Неизвестное имя возвращает nil; распознанный, но недоступный для создания тип всё ещё может вызвать ошибку. Метод не назначает автоматически стрелка снаряда и не регистрирует сущность как элитное подкрепление.

ПараметрТипПримечания
entityTypestringИмя типа сущности (например, "FIREBALL", "ARROW")
locationlocation tableГде заспавнить
optionstable (optional)Параметры спавна (см. ниже)

Параметры спавна сущности​

КлючТипПо умолчаниюПримечания
velocityvector tablenilНачальная скорость {x, y, z}
effectstringnilEntityEffect, проигрываемый при спавне
durationint0Положительное значение задаёт удаление через указанное число тиков; неположительное не создаёт таймер удаления
on_landfunctionnilfunction(land_location, entity_ref) при касании земли, недействительности сущности или превышении max_ticks; это не событие попадания снаряда и не доказательство приземления
max_ticksint6000Максимум тиков наблюдения до принудительного вызова on_land
persistentbooleanЗначение Minecraft по умолчаниюfalse исключает сущность из сохранения чанка, поэтому остановка сервера или выгрузка чанка посреди эффекта не оставит её в мире

Возвращает таблицу-обёртку сущности. Неживые сущности, например FIREBALL, ARROW и TNT, используют обёртку ссылки на неживую сущность, где is_valid() является методом. Живые сущности, например ZOMBIE и GIANT, используют полную обёртку живой сущности, где is_valid является булевым полем. Вызов entity:is_valid() у такой обёртки приводит к attempt to call a boolean value.

Наблюдатель приземления проверяет сущность каждый тик, пока скрипт активен, и останавливается вместе с его задачами. Таймер положительного duration независим и может удалить сущность после закрытия скрипта. Неизвестные имена effect игнорируются.

Пример
return {
api_version = 1,
on_boss_damaged_by_player = function(context)
if context.player == nil then return end
if not context.cooldowns:check_local("fireball_spawn", 100) then return end
-- Spawn a fireball aimed at the player
local boss_loc = context.boss:get_location()
local dir = context.vectors.get_vector_between_locations(boss_loc, context.player:get_location())
dir = context.vectors.normalize_vector(dir)

context.world:spawn_entity_at_location("FIREBALL", boss_loc, {
velocity = { x = dir.x * 2, y = dir.y * 2, z = dir.z * 2 },
duration = 100,
})
end
}
Пример
return {
api_version = 1,
on_enter_combat = function(context)
-- Spawn a primed TNT with a landing callback
context.world:spawn_entity_at_location("TNT", context.boss:get_location(), {
velocity = { x = 0, y = 1.5, z = 0 },
on_land = function(land_location, entity_ref)
context.world:spawn_particle_at_location(land_location, {
particle = "EXPLOSION_EMITTER",
amount = 1,
})
end,
})
end
}

world:spawn_display_at_location(location, options)​

Создаёт display предмета или блока: парящий визуальный элемент без хитбокса, гравитации и ИИ. Используйте его для вращающихся камней, брошенных объектов и других эффектов, которые нужно только видеть, вместо оформления стойки для брони. Display центрируется на location и поворачивается по его yaw.

КлючТипПо умолчаниюПримечания
itemstringМатериал, показываемый как предмет. Блочный предмет, например "AMETHYST_BLOCK", отображается как блок по центру
blockstringБлок, показываемый как блочный display, в виде материала или данных блока, например "lantern[hanging=true]"
scalenumber или vector table1Число масштабирует все оси; {x, y, z} масштабирует каждую отдельно. При 1 блок имеет ширину в один блок
durationint0Положительные значения удаляют display через указанное число тиков
teleport_durationint0Сколько тиков клиент плавно перемещает display в каждое новое положение, от 0 до 59. Используйте 1, если вы телепортируете display каждый тик
billboardstringFIXEDFIXED, VERTICAL, HORIZONTAL или CENTER
glowingbooleanfalseКонтурное свечение
brightnessintосвещённость мираОт 0 до 15, переопределяет освещённость в месте display
bedrock_fallbackbooleantrueСм. ниже

Укажите ровно одно из item или block. Отсутствующее или неизвестное значение item или block, оба сразу или неположительный scale возвращают nil и записывают предупреждение с названием способности. Неизвестное значение billboard оставляет FIXED.

Display-сущности никогда не сохраняются вместе с чанком. Они удаляются, когда истекает duration, когда вы вызываете remove() или когда способность завершает работу, смотря что наступит раньше.

Клиенты Bedrock не умеют отображать display-сущности. Игроки Bedrock, находящиеся в мире в момент появления display, вместо этого видят невидимую стойку для брони с тем же предметом (для блочного display — с предметом этого блока), а сам display от них скрыт. Стойка следует за display и удаляется вместе с ним. Игроки Bedrock, которые заходят в мир позже, стойку не получают, а блок без предметной формы, например fire, не получает стойки вообще. Отключите это через bedrock_fallback = false для эффектов, которые игрокам Bedrock видеть не нужно.

Возвращаемая обёртка содержит uuid и entity_type и такие методы:

МетодПримечания
is_valid(), is_alive()Существует ли display ещё
get_location()Текущее местоположение
teleport_to_location(location)Перемещает display и его стойку Bedrock
remove()Удаляет display и его стойку Bedrock
set_scale(scale)Те же значения, что у параметра scale
set_item(material)Только для предметных display; иначе возвращает false
set_block(block)Только для блочных display; иначе возвращает false
set_glowing(enabled)Контурное свечение
set_brightness(level)От 0 до 15 или nil, чтобы снова использовать освещённость мира
set_teleport_duration(ticks)То же, что параметр teleport_duration
Пример
-- Three amethyst stones circle the target for three seconds.
return {
api_version = 1,
on_boss_damaged_by_player = function(context)
if context.player == nil or not context.cooldowns:check_local("orbit", 200) then return end
local target = context.player
local stones = {}
for i = 1, 3 do
stones[i] = context.world:spawn_display_at_location(target:get_location(), {
item = "AMETHYST_BLOCK", scale = 0.3, duration = 60, teleport_duration = 1
})
end
local elapsed = 0
local task
task = context.scheduler:run_every(1, function(context)
elapsed = elapsed + 1
if elapsed >= 60 then
context.scheduler:cancel_task(task)
return
end
local center = target:get_location()
for i = 1, 3 do
local angle = elapsed * 0.2 + i * (2 * math.pi / 3)
if stones[i] ~= nil and stones[i]:is_valid() then
stones[i]:teleport_to_location(em.create_location(
center.x + math.cos(angle) * 1.5, center.y + 1.2, center.z + math.sin(angle) * 1.5, center.world, 0, 0))
end
end
end)
end
}

world:spawn_falling_block_at_location(location, material, options)​

Создаёт падающий блок из блочного материала. При наличии on_land EliteMobs перехватывает событие изменения блока, отменяет установку и один раз вызывает function(land_location, entity_ref). Без обработчика блок может установиться обычным образом. Метод не имеет параметров duration или max_ticks и не вызывает обработчик из-за недействительности сущности или истечения времени.

ПараметрТипПримечания
locationlocation tableГде заспавнить
materialstringИмя материала (например, "STONE", "MAGMA_BLOCK")
optionstable (optional)Параметры спавна (см. ниже)

Параметры падающего блока​

КлючТипПо умолчаниюПримечания
velocityvector tablenilНачальная скорость {x, y, z}
drop_itembooleanfalseВыпадает ли блок в виде предмета
hurt_entitiesbooleanfalseНаносит ли блок урон сущностям, на которые падает
on_landfunctionnilОбратный вызов function(land_location, entity_ref) при приземлении блока

Возвращает обёртку неживой сущности или nil, если позиция либо материал не распознаны. Известный материал, не являющийся блоком, всё ещё может вызвать ошибку при создании данных блока.

Пример
return {
api_version = 1,
on_enter_combat = function(context)
-- Rain magma blocks from above
local loc = context.boss:get_location()
for i = 1, 5 do
local offset_loc = {
x = loc.x + math.random(-3, 3),
y = loc.y + 10,
z = loc.z + math.random(-3, 3),
world = loc.world
}
context.world:spawn_falling_block_at_location(offset_loc, "MAGMA_BLOCK", {
velocity = { x = 0, y = -0.5, z = 0 },
hurt_entities = true,
on_land = function(land_location, entity_ref)
context.world:spawn_particle_at_location(land_location, { particle = "LAVA", amount = 8 })
end,
})
end
end
}

world:spawn_custom_boss_at_location(filename, location, options)​

Порождает кастомного босса EliteMobs из конфигурационного файла.

ПараметрТипПримечания
filenamestringИмя конфигурационного файла босса (например, "my_boss.yml")
locationlocation tableГде заспавнить
optionstable (optional)Параметры спавна (см. ниже)

Параметры спавна кастомного босса​

КлючТипПо умолчаниюПримечания
levelintСобственная конфигурация или динамические правила уровня создаваемого боссаПереопределяет уровень; без параметра уровень заклинателя не наследуется
silentbooleanfalseПодавляет сообщения о спавне
velocityvector tablenilНачальная скорость
add_as_reinforcementbooleanfalseРегистрирует как подкрепление текущего босса

Возвращает таблицу-обёртку сущности либо nil, если босса создать не удалось.

Пример
return {
api_version = 1,
on_enter_combat = function(context)
local minion = context.world:spawn_custom_boss_at_location(
"skeleton_minion.yml",
context.boss:get_location(),
{ level = 10, add_as_reinforcement = true }
)
if minion ~= nil then
context.boss:send_message("&cMinions, arise!")
end
end
}

world:spawn_boss_at_location(filename, location, level)​

Более простой метод создания босса. Пропущенные позиция и уровень берутся у босса, вызвавшего метод. Результат не регистрируется как подкрепление. Для уровня по умолчанию пропустите третий аргумент; явный nil в нём не принимается.

ПараметрТипПо умолчаниюПримечания
filenamestringИмя конфигурационного файла босса
locationlocation tableместоположение боссаГде заспавнить (необязательно, по умолчанию — местоположение босса)
levelintуровень боссаПереопределяет уровень спавна (необязательно)

Возвращает таблицу-обёртку сущности или nil.

Пример
return {
api_version = 1,
on_enter_combat = function(context)
context.world:spawn_boss_at_location("zombie_guard.yml", context.boss:get_location(), 5)
context.boss:send_message("&cGuards, defend me!")
end
}

world:spawn_reinforcement_at_location(filename, location, duration, velocity)​

Создаёт подкрепление без сообщений через систему EliteMobs, записывает призывателя и наследует нормализованный бой, если он включён у кастомного босса-призывателя. Уровень определяют собственная конфигурация подкрепления и динамические правила. duration задаёт таймер ухода, а не уровень.

ПараметрТипПо умолчаниюПримечания
filenamestringИмя конфигурационного файла босса
locationlocation tableГде заспавнить
durationint0Число тиков до ухода; 0 отключает таймер
velocityvector tablenilНачальная скорость (необязательно)

Возвращает таблицу-обёртку сущности или nil.

Пример
return {
api_version = 1,
on_enter_combat = function(context)
context.world:spawn_reinforcement_at_location(
"necro_skeleton.yml",
context.boss:get_location(),
0,
{ x = 0, y = 0.5, z = 0 }
)
context.boss:send_message("&5Rise, my servant!")
end
}

world:spawn_fireworks_at_location(location, spec)​

Создаёт настоящий фейерверк без автоматического отключения урона. Укажите хотя бы один допустимый цвет для каждого эффекта; создание эффекта без цветов может завершиться ошибкой.

ПараметрТипПримечания
locationlocation tableГде заспавнить
spectableСпецификация фейерверка (см. ниже)

Таблица спецификации фейерверка​

КлючТипПо умолчаниюПримечания
powerint1Мощность полёта (высота)
velocityvector tablenilНачальная скорость
shot_at_anglebooleantrueЗапускается ли фейерверк под углом (используется, когда задана скорость)
effectstable of tablesnilМассив спецификаций эффектов фейерверка. Если не указан, спецификация верхнего уровня считается одним эффектом.

Спецификация эффекта фейерверка​

КлючТипПо умолчаниюПримечания
typestring"BALL_LARGE""BALL", "BALL_LARGE", "STAR", "BURST", "CREEPER"
flickerbooleantrueЭффект мерцания
trailbooleantrueЭффект следа
colorstableОбязателен для каждого эффектаНепустой массив имён цветов или таблиц {red = 255, green = 0, blue = 0}
fade_colorstablenilМассив имён цветов затухания или таблиц {red, green, blue}

Имена цветов: "WHITE", "SILVER", "GRAY", "BLACK", "RED", "MAROON", "YELLOW", "OLIVE", "LIME", "GREEN", "AQUA", "TEAL", "BLUE", "NAVY", "FUCHSIA", "PURPLE", "ORANGE"

Возвращает обёртку неживой сущности или nil, если позиция не распознана. :detonate() запрашивает взрыв. Тип и имена цветов не учитывают регистр; неизвестный тип заменяется на BALL_LARGE, неизвестный цвет на белый. Значения RGB должны быть в диапазоне 0..255.

Пример
return {
api_version = 1,
on_spawn = function(context)
local fw = context.world:spawn_fireworks_at_location(context.boss:get_location(), {
power = 0,
effects = {
{
type = "STAR",
flicker = true,
trail = true,
colors = { "RED", "ORANGE", { red = 255, green = 200, blue = 0 } },
fade_colors = { "YELLOW" },
},
},
})

if fw == nil then return end
-- Detonate on the next tick for a visual burst
context.scheduler:run_after(1, function()
fw:detonate()
end)
end
}

world:spawn_splash_potion_at_location(location, spec)​

Создаёт настоящее брошенное взрывное зелье. Неизвестные имена эффектов Bukkit вызывают предупреждение и пропускаются. Метод не назначает стрелка и не применяет фильтр эффектов подземелья, используемый прямыми методами зелий босса. Действуют обычные правила взрывного зелья.

ПараметрТипПримечания
locationlocation tableГде заспавнить
spectableСпецификация зелья (см. ниже)

Таблица спецификации взрывного зелья​

КлючТипПримечания
velocityvector tableНачальная скорость брошенного зелья
effectstable of tablesМассив спецификаций эффектов зелья

Спецификация эффекта зелья​

КлючТипПо умолчаниюПримечания
typestringобязательныйИмя типа эффекта зелья (например, "SLOWNESS", "POISON")
durationint0Длительность в тиках
amplifierint0Усилитель эффекта (0 = уровень I)
overwritebooleantrueЗаменяет ранее добавленный эффект того же типа в метаданных этого зелья; не задаёт правила для эффектов, уже действующих на игрока

Возвращает таблицу-ссылку на сущность или nil.

Пример
return {
api_version = 1,
on_boss_damaged_by_player = function(context)
if context.player == nil then return end
if not context.cooldowns:check_local("potion_throw", 200) then return end

local dir = context.vectors.get_vector_between_locations(
context.boss:get_location(),
context.player:get_location()
)
dir = context.vectors.normalize_vector(dir)

context.world:spawn_splash_potion_at_location(context.boss:get_location(), {
velocity = { x = dir.x * 1.5, y = 0.5, z = dir.z * 1.5 },
effects = {
{ type = "SLOWNESS", duration = 100, amplifier = 1 },
{ type = "WEAKNESS", duration = 60, amplifier = 0 },
},
})
end
}

world:place_temporary_block_at_location(location, material, duration, requireAir)​

Устанавливает отслеживаемый блок и при положительном сроке восстанавливает его прежние данные. Содержимое контейнера не сохраняется. Исходный блок возвращается по окончании таймера, при выгрузке чанка или мира либо при выключении плагина, но только если на месте всё ещё стоит временный блок, поэтому более поздняя правка не перезаписывается. Повторная установка на блок, где всё ещё стоит временный блок, перезапускает его таймер и сохраняет первый сохранённый оригинал. Блоки с сущностями блоков, например сундуки и таблички, незагруженные чанки и блоки, удерживаемые другим владельцем временных блоков, пропускаются. Разрушение отслеживаемого блока ничего не выбрасывает и прекращает отслеживание без восстановления. Используйте блочный материал. Это переопределение босса возвращает nil, в том числе когда установке препятствует requireAir или пропуск; оно не сообщает об успехе и не проверяет защиту региона автоматически.

ПараметрТипПо умолчаниюПримечания
locationlocation tableКуда поставить
materialstringИмя материала
durationint0Тики до восстановления; 0 или отрицательное значение ставит блок навсегда без отслеживания
requireAirbooleanfalseЕсли true, ставит только если блок сейчас воздух
Пример
return {
api_version = 1,
on_enter_combat = function(context)
-- Create a temporary ice floor under the boss
local loc = context.boss:get_location()
for dx = -2, 2 do
for dz = -2, 2 do
context.world:place_temporary_block_at_location(
{ x = loc.x + dx, y = loc.y - 1, z = loc.z + dz, world = loc.world },
"PACKED_ICE",
100,
false
)
end
end
end
}

world:set_block_at_location(location, material, requireAir)​

Устанавливает блок навсегда через менеджер временных блоков, без таймера восстановления и без отслеживания, поэтому изменение сохраняется после выключения плагина. Если на месте стоит временный блок с таймером, он перестаёт отслеживаться и не восстанавливается. Блоки, удерживаемые другим владельцем временных блоков, остаются без изменений. Для восстановления по таймеру используйте place_temporary_block_at_location с положительным сроком.

ПараметрТипПо умолчаниюПримечания
locationlocation tableКуда поставить
materialstringИмя материала
requireAirbooleanfalseЕсли true, ставит только если блок сейчас воздух
Пример
return {
api_version = 1,
on_enter_combat = function(context)
-- Place fire at the boss's location
context.world:set_block_at_location(context.boss:get_location(), "FIRE", true)
end
}

world:get_block_type_at_location(location)​

Возвращает имя материала в верхнем регистре или nil, если позиция не распознана. В отличие от общего координатного запроса, это переопределение обращается к блоку напрямую, без проверки загрузки чанка.

ПараметрТипПримечания
locationlocation tableМестоположение для запроса
Пример
return {
api_version = 1,
on_enter_combat = function(context)
local block_type = context.world:get_block_type_at_location(context.boss:get_location())
if block_type == "WATER" then
context.boss:send_message("&bThe boss is empowered by water!")
context.boss:apply_potion_effect("SPEED", 200, 1)
end
end
}

world:get_highest_block_y_at_location(location)​

Возвращает Y самого высокого блока по данным Bukkit или nil, если позиция не распознана. Не проверяет, загружен ли чанк и безопасна ли точка для телепортации.

ПараметрТипПримечания
locationlocation tableМестоположение для запроса (используются X и Z)
Пример
return {
api_version = 1,
on_boss_damaged_by_player = function(context)
if context.player == nil then return end
if not context.cooldowns:check_local("skyport", 200) then return end
local loc = context.player:get_location()
local ground_y = context.world:get_highest_block_y_at_location(loc)
-- Teleport the player to the surface
context.player:teleport_to_location({
x = loc.x, y = ground_y + 1, z = loc.z, world = loc.world
})
context.player:send_message("&eYou are teleported to the surface!")
end
}

world:get_blast_resistance_at_location(location)​

Возвращает взрывоустойчивость материала в указанном месте или 0, если позиция не распознана.

ПараметрТипПримечания
locationlocation tableМестоположение для запроса
Пример
return {
api_version = 1,
on_enter_combat = function(context)
local resistance = context.world:get_blast_resistance_at_location(context.boss:get_location())
context.log:info("Blast resistance at boss: " .. resistance)
end
}

world:is_air_at_location(location)​

Возвращает true, если блок в указанном месте — воздух.

ПараметрТипПримечания
locationlocation tableМестоположение для запроса
Пример
return {
api_version = 1,
on_enter_combat = function(context)
local loc = context.boss:get_location()
local above = { x = loc.x, y = loc.y + 2, z = loc.z, world = loc.world }
if context.world:is_air_at_location(above) then
-- There is space above the boss, launch upward
context.boss:set_velocity_vector({ x = 0, y = 1.5, z = 0 })
end
end
}

world:is_passable_at_location(location)​

Возвращает результат Bukkit Block.isPassable() или false, если позиция не распознана. Это запрос одного блока, а не проверка того, помещается ли целая сущность и может ли она пройти по маршруту.

ПараметрТипПримечания
locationlocation tableМестоположение для запроса
Пример
return {
api_version = 1,
on_enter_combat = function(context)
if context.world:is_passable_at_location(context.boss:get_location()) then
context.log:info("Boss is in a passable block")
end
end
}

world:is_passthrough_at_location(location)​

Возвращает true, если блок в указанном месте не твёрдый (похоже на проходимость, но на основе проверки твёрдости).

ПараметрТипПримечания
locationlocation tableМестоположение для запроса
Пример
return {
api_version = 1,
on_enter_combat = function(context)
local loc = context.boss:get_location()
local above = { x = loc.x, y = loc.y + 1, z = loc.z, world = loc.world }
if context.world:is_passthrough_at_location(above) then
context.log:info("Boss can move upward")
end
end
}

world:is_on_floor_at_location(location)​

Возвращает true, если блок в указанной позиции нетвёрдый, а блок на единицу Y ниже твёрдый. Не проверяет состояние приземления сущности, её габариты или свободное место над головой.

ПараметрТипПримечания
locationlocation tableМестоположение для запроса
Пример
return {
api_version = 1,
on_enter_combat = function(context)
if context.world:is_on_floor_at_location(context.boss:get_location()) then
context.boss:send_message("&aThe boss slams the ground!")
context.world:spawn_particle_at_location(context.boss:get_location(), {
particle = "CLOUD",
amount = 30,
})
end
end
}

world:is_standing_on_material(location, material)​

Возвращает true, если блок непосредственно под указанным местом соответствует заданному материалу.

ПараметрТипПримечания
locationlocation tableМестоположение для запроса
materialstringИмя материала для проверки
Пример
return {
api_version = 1,
on_boss_damaged_by_player = function(context)
if context.player == nil then return end
if context.world:is_standing_on_material(context.player:get_location(), "SOUL_SAND") then
context.player:send_message("&8The soul sand saps your strength!")
context.player:apply_potion_effect("SLOWNESS", 60, 2)
end
end
}

world:set_world_time(time) / world:set_world_time(location, time)​

Задаёт время во всём мире. Необязательное местоположение позволяет выбрать мир. При закрытии скрипта прежнее время не восстанавливается.

ПараметрТипПримечания
locationlocation table (optional)На какой мир воздействовать. По умолчанию — мир босса.
timeintВремя мира в тиках (0 = рассвет, 6000 = полдень, 13000 = ночь, 18000 = полночь)
Пример
return {
api_version = 1,
on_enter_combat = function(context)
-- Set to midnight when combat starts
context.world:set_world_time(18000)
context.boss:send_message("&8Darkness falls...")
end
}

world:set_world_weather(weather, duration) / world:set_world_weather(location, weather, duration)​

Задаёт погоду в мире босса или необязательного местоположения. Имена не учитывают регистр; неизвестные имена лишь вызывают предупреждение. RAIN/CLEAR задают таймер погоды, а THUNDER таймер грозы. Изменение действует на весь мир и не отменяется при закрытии скрипта.

ПараметрТипПо умолчаниюПримечания
locationlocation table (optional)мир боссаНа какой мир воздействовать
weatherstring"CLEAR", "RAIN" (или "PRECIPITATION"), "THUNDER"
durationint6000Длительность погоды в тиках
Пример
return {
api_version = 1,
on_enter_combat = function(context)
-- Start a thunderstorm for 200 ticks
context.world:set_world_weather("THUNDER", 200)
context.boss:send_message("&eA storm gathers!")
end
}

world:generate_fake_explosion(blockLocations, sourceLocation)​

Удаляет настоящие блоки и создаёт обломки из падающих блоков через систему восстановления взрывов EliteMobs. Обломки могут наносить урон сущностям, поэтому это не безвредные частицы. Требуется включённый doExplosionRegen; при передаче исходной позиции проверяется флаг восстановления взрывов WorldGuard. Воздух, огонь, жидкости и отслеживаемые временные блоки пропускаются; зависимые соседние блоки тоже могут попасть в список. Восстановление начинается через 1200 тиков и обрабатывает один записанный блок за тик. Все входные позиции должны быть в мире босса. Операция возвращает nil и не отменяется при закрытии скрипта.

ПараметрТипПримечания
blockLocationstable of location tablesМассив местоположений блоков для «взрыва»
sourceLocationlocation table (optional)Источник взрыва для расчёта направления
Пример
return {
api_version = 1,
on_enter_combat = function(context)
local loc = context.boss:get_location()
local blocks = {}
for dx = -1, 1 do
for dz = -1, 1 do
table.insert(blocks, { x = loc.x + dx, y = loc.y, z = loc.z + dz, world = loc.world })
end
end
context.world:generate_fake_explosion(blocks, loc)
end
}

world:run_console_command(command)​

Немедленно выполняет консольную команду от имени сервера и возвращает nil, не предоставляя результат её успешности. Плейсхолдеры игрока и босса автоматически не подставляются.

Ванильные команды сообщают свой результат, а при значении по умолчанию broadcast-console-to-ops=true сервер показывает каждый результат всем операторам онлайн. Часто выполняемые команды, например data merge entity, kill или damage, засоряют им чат. Используйте вместо них нативные методы: spawn_display_at_location для визуальных эффектов, методы стоек для брони для стоек, entity:remove() для удаления того, что заспавнил скрипт, и entity:deal_custom_damage(amount) для точного урона от босса.

ПараметрТипПримечания
commandstringКоманда для выполнения (без ведущего /)
Пример
return {
api_version = 1,
on_enter_combat = function(context)
context.world:run_console_command("say The boss has entered phase 2!")
end
}

world:run_empowered_lightning_task_at_location(location)​

Запускает независимую задачу Bukkit в сохранённой позиции. Она выпускает SOUL_FIRE_FLAME в течение 60 итераций, затем создаёт настоящую молнию с обходом защиты спавна и направленный вниз огненный шар с силой взрыва 5 и меткой ender_dragon_empowered_lightning.yml. Это атака с уроном. Закрытие или приостановка Lua-скрипта не отменяет задачу; метод также не проверяет настройку предупреждающих эффектов.

ПараметрТипПримечания
locationlocation tableКуда бить
Пример
return {
api_version = 1,
on_enter_combat = function(context)
context.world:run_empowered_lightning_task_at_location(context.boss:get_location())
context.boss:send_message("&eFeel the power of the storm!")
end
}

world:spawn_fake_gold_nugget_at_location(location, velocity, hasGravity)​

Показывает ближайшим игрокам золотой самородок через пакеты; игроки и воронки не могут его подобрать. Само создание не запускает движение и урон. Передайте его в run_fake_gold_nugget_damage один раз в составе группы либо удалите явно.

ПараметрТипПо умолчаниюПримечания
locationlocation tableМестоположение спавна
velocityvector tableНачальная скорость
hasGravitybooleanfalseДействует ли на снаряд гравитация

Возвращает таблицу фиктивного снаряда или nil, если позиция либо вектор не распознаны. Методы: get_location(), set_gravity(bool), remove(), is_removed().

Пример
return {
api_version = 1,
on_boss_damaged_by_player = function(context)
if context.player == nil then return end
if not context.cooldowns:check_local("nugget", 60) then return end

local dir = context.vectors.get_vector_between_locations(
context.boss:get_location(),
context.player:get_location()
)
dir = context.vectors.normalize_vector(dir)

local nugget = context.world:spawn_fake_gold_nugget_at_location(
context.boss:get_location(),
{ x = dir.x, y = dir.y, z = dir.z }
)
if nugget ~= nil then
context.world:run_fake_gold_nugget_damage({ nugget })
end
end
}

world:run_fake_gold_nugget_damage(projectiles)​

Запускает независимую задачу Bukkit, которая каждый тик перемещает и проверяет группу снарядов. Вызывайте один раз на группу: каждый вызов создаёт новую задачу. В новой позиции ищутся живые сущности в прямоугольной области с полуразмером 0.5. Исходный босс и блокирующие игроки пропускаются, остальным отправляется пользовательский урон 1 по правилам урона босса. Столкновение может удалить снаряд даже при отклонённом уроне. Касание земли или предел в 100 тиков также удаляют его. Это проверка отдельных позиций, а не непрерывного луча; закрытие или приостановка Lua-экземпляра не отменяет задачу.

ПараметрТипПримечания
projectilestableМассив таблиц фиктивных снарядов из spawn_fake_gold_nugget_at_location
Пример
return {
api_version = 1,
on_enter_combat = function(context)
-- Keep this batch separate from later combat entries.
local projectiles = {}
local loc = context.boss:get_location()
for i = 1, 5 do
local angle = (i / 5) * math.pi * 2
local nugget = context.world:spawn_fake_gold_nugget_at_location(
loc,
{ x = math.cos(angle) * 0.5, y = 0.3, z = math.sin(angle) * 0.5 }
)
if nugget ~= nil then table.insert(projectiles, nugget) end
end

-- Start the batch once; the helper runs its own per-tick task.
context.world:run_fake_gold_nugget_damage(projectiles)
-- Remove any surviving projectiles after 3 seconds.
context.scheduler:run_after(60, function()
for _, projectile in ipairs(projectiles) do
projectile:remove()
end
end)
end
}

world:generate_player_loot(times)​

Запускает обычный генератор добычи игроков times раз; неположительные значения ничего не делают. Требуются eliteLoot, отсутствие сработавшей защиты от эксплуатации, загруженные данные игрока и записанный урон не менее 10% максимального здоровья босса. Игроки с блокировкой наград подземелья пропускаются. Каждый проход может выдавать монеты, а при включённой случайной добыче также случайные или особые предметы и свитки по обычным настройкам и правилам группы. Метод не повторяет все заданные автором кастомные выпадения и не гарантирует предмет за каждый проход. Повторные вызовы добавляют попытки выдачи наград; ограничения одним вызовом на босса нет.

ПараметрТипПо умолчаниюПримечания
timesint1Количество розыгрышей добычи
Пример
return {
api_version = 1,
on_boss_damaged_by_player = function(context)
local pct = context.boss:get_health() / context.boss:get_maximum_health()
if pct < 0.5 and not context.boss:has_tag("bonus_loot") then
context.boss:add_tag("bonus_loot")
context.world:generate_player_loot(2)
context.boss:send_message("&6Bonus loot drops!")
end
end
}

world:drop_bonus_coins(multiplier)​

Создаёт дополнительные монеты для подходящих игроков с записанным уроном строго больше 10% максимального здоровья босса. NPC и игроки без загруженных данных пропускаются. Награда зависит от уровня наград босса и multiplier.

ПараметрТипПо умолчаниюПримечания
multipliernumber2.0Множитель количества монет
Пример
return {
api_version = 1,
on_boss_damaged_by_player = function(context)
local pct = context.boss:get_health() / context.boss:get_maximum_health()
if pct < 0.25 and not context.boss:has_tag("bonus_coins") then
context.boss:add_tag("bonus_coins")
context.world:drop_bonus_coins(3.0)
context.boss:send_message("&6Gold spills everywhere!")
end
end
}

context.vectors​

Функции векторной математики поддерживают точку, как в примерах, и двоеточие. Входные данные принимают именованные поля x, y, z, числовые индексы 1..3 или вложенную таблицу direction. Отсутствующие компоненты равны 0. Результат возвращается новой таблицей, входные данные не меняются.

МетодВозвращаетПримечания
vectors.get_vector_between_locations(loc1, loc2[, options])таблица вектораСмещение loc2 - loc1, по умолчанию без нормализации
vectors.normalize_vector(vec)таблица вектораЕдиничный вектор для ненулевого входа; нулевой остаётся нулевым
vectors.rotate_vector(vec, pitch, yaw)таблица вектораПоворот в градусах сначала вокруг мировой оси X, затем Y

У всех таблиц векторов есть поля x, y, z.

vectors.get_vector_between_locations(loc1, loc2, options)​

ПараметрТипПримечания
loc1location tableНачальная точка
loc2location tableКонечная точка
optionstable (optional)Параметры постобработки (см. ниже)

Параметры вектора​

КлючТипПо умолчаниюПримечания
normalizebooleanfalseНормализовать полученный вектор
multipliernumber1.0Масштабировать вектор
offsetvector tablenilДобавить вектор смещения

Параметры применяются по порядку: нормализация ненулевого смещения, умножение, затем добавление смещения по мировым осям. Нераспознанные позиции и разные миры дают нулевой вектор до применения параметров. Для совпадающих корректных позиций смещение всё ещё может применяться.

Пример
return {
api_version = 1,
on_boss_damaged_by_player = function(context)
if context.player == nil then return end
if not context.cooldowns:check_local("dash", 100) then return end
-- Compute a normalized direction from boss to player, scaled to speed 2
local dir = context.vectors.get_vector_between_locations(
context.boss:get_location(),
context.player:get_location(),
{ normalize = true, multiplier = 2.0 }
)
-- Launch the boss toward the player
context.boss:set_velocity_vector(dir)
end
}

vectors.normalize_vector(vec)​

ПараметрТипПримечания
vecvector tableВходной вектор
Пример
return {
api_version = 1,
on_boss_damaged_by_player = function(context)
if context.player == nil then return end
local raw = context.vectors.get_vector_between_locations(
context.boss:get_location(),
context.player:get_location()
)
local unit = context.vectors.normalize_vector(raw)
context.log:info("Direction: " .. unit.x .. ", " .. unit.y .. ", " .. unit.z)
end
}

vectors.rotate_vector(vec, pitch, yaw)​

ПараметрТипПримечания
vecvector tableВходной вектор
pitchnumberПоворот вокруг оси X в градусах
yawnumberПоворот вокруг оси Y в градусах
Пример
return {
api_version = 1,
on_boss_damaged_by_player = function(context)
if context.player == nil then return end
if not context.cooldowns:check_local("spread_shot", 100) then return end
local forward = context.vectors.normalize_vector(
context.vectors.get_vector_between_locations(
context.boss:get_location(),
context.player:get_location()
)
)
-- Fire three fireballs in a spread pattern
for _, yaw_offset in ipairs({ -30, 0, 30 }) do
local dir = context.vectors.rotate_vector(forward, 0, yaw_offset)
context.boss:summon_projectile(
"FIREBALL",
context.boss:get_eye_location(),
{
x = context.boss:get_location().x + dir.x * 10,
y = context.boss:get_location().y + dir.y * 10,
z = context.boss:get_location().z + dir.z * 10,
world = context.boss:get_location().world
},
1.0
)
end
end
}
подсказка

Веер направлений можно построить, поворачивая базовый вектор в цикле:

local base = context.vectors.normalize_vector(
context.vectors.get_vector_between_locations(boss_loc, target_loc)
)
for angle = 0, 330, 30 do
local dir = context.vectors.rotate_vector(base, 0, angle)
-- Use dir for spawning projectiles in a ring
end

context.settings​

Доступ только для чтения к настройкам способностей. Метод читает текущее значение при вызове и не отключает частицы или другие эффекты автоматически. Скрипт должен использовать результат, чтобы решить, показывать ли предупреждение.

МетодВозвращаетПримечания
settings:warning_visual_effects_enabled()booleanВключены ли предупреждающие визуальные эффекты в настройках боя мобов
Пример
return {
api_version = 1,
on_enter_combat = function(context)
if context.settings:warning_visual_effects_enabled() then
context.world:spawn_particle_at_location(context.boss:get_location(), {
particle = "DUST",
amount = 20,
red = 255, green = 0, blue = 0,
})
end
end
}

context.event​

Данные текущего события. Доступные поля зависят от исходного события, поэтому проверяйте необязательные поля. Числовые методы изменения урона требуют точки, например event.set_damage_amount(value); transfer_damage поддерживает и точку, и двоеточие. Таблица события босса не предоставляет общие члены cancel, uncancel или is_cancelled.

Поле или методКогда доступноПримечания
event.damage_amountХуки уронаСнимок урона при первом разрешении лениво создаваемой таблицы события
event.get_damage_amount()Хуки уронаЧитает текущую величину после изменений
event.damage_causeХуки уронаИмя перечисления Bukkit DamageCause (например, "ENTITY_ATTACK")
event.cancel_event()Отменяемые событияОтменяет событие
event.set_damage_amount(value)Хуки на основе EliteDamageEventЗадаёт урон напрямую
event.multiply_damage_amount(multiplier)Хуки на основе EliteDamageEventУмножает текущий урон
event.damagerСобытия урона с сущностью, наносящей уронОбёртка исходного источника Bukkit; при попадании снаряда это сам снаряд, а не стрелок
event.projectileСобытия урона, где урон наносит снарядОбёртка-ссылка на сущность-снаряд
event.spawn_reasonon_spawnИмя перечисления причины спавна
event.entityУрон игрока по боссу, on_death, события зонПовреждённый босс, погибшая сущность или сущность, пересекающая зону; при уроне подкреплению это подкрепление
event.is_damage_transferУрон игрока по боссу, включая передачу от подкрепленияСоздан ли этот удар переносом урона
event:transfer_damage(target, amount)Урон игрока по боссу, включая передачу от подкрепленияОтправляет отдельный удар другой подходящей элитной сущности; см. правила переноса урона

Пример: уменьшение входящего урона вдвое​

Пример
return {
api_version = 1,
on_boss_damaged_by_player = function(context)
if context.event ~= nil then
local dmg = context.event.damage_amount
context.log:info("Boss took " .. dmg .. " damage, halving it")
context.event.multiply_damage_amount(0.5)
end
end
}

Пример: отмена урона от снарядов​

Пример
return {
api_version = 1,
on_boss_damaged_by_player = function(context)
if context.event ~= nil and context.event.damage_cause == "PROJECTILE" then
context.event.cancel_event()
if context.player ~= nil then
context.player:send_message("&cThe boss deflects your projectile!")
end
end
end
}

Пример: чтение причины урона​

Пример
return {
api_version = 1,
on_player_damaged_by_boss = function(context)
if context.event ~= nil then
context.log:info("Damage cause: " .. (context.event.damage_cause or "unknown"))
end
end
}
примечание
  • damage_amount — это снимок. Он не обновляется автоматически после вызова set_damage_amount() или multiply_damage_amount().
  • В новом контексте запланированного обработчика event = nil. Сохранение старого контекста хука не позволяет корректно менять уже завершённое событие; изменяйте его во время выполнения хука.
  • Методы урона меняют ожидающее событие, а не уже потерянное здоровье. Последующие слушатели могут изменить или отменить удар. Успешный перенос отправляет дополнительный удар и не уменьшает и не отменяет исходный автоматически.

Дальнейшие шаги​