Волны и враги EternalTD
Файл волны в plugins/EternalTD/waves/ определяет весь состав врагов для уровня, включая обычные волны, волны внезапной смерти и опциональные сообщения перед волной или во время волны. Каждая конфигурация уровня ссылается на один файл волны через wavesConfigFile:.
Поля верхнего уровня
| Поле | Тип | По умолчанию | Примечания |
|---|---|---|---|
isEnabled | bool | true | Отключение здесь также отключает уровень, зависящий от этого файла |
baseMobAmount | int | 20 | Количество по умолчанию, используемое, когда запись не указывает amount= |
waveEntities | список строк | обязательно | Записи врагов по волнам |
suddenDeathWaveEntities | список строк | опционально | Опциональный циклический пул волн, запускаемый после исчерпания настроенных волн |
prewaveMessages | список карт | опционально | Сообщения, показываемые перед началом определённой волны |
waveMessages | список карт | опционально | Сообщения, показываемые при начале волны |
Если файл волны не определяет ни одной записи внезапной смерти, уровень заканчивается, как только настроенные волны исчерпываются.
Формат записи сущности волны
Каждая строка в waveEntities (или suddenDeathWaveEntities) — это запись, разделённая двоеточиями:
- wave=1:entityType=ZOMBIE:healthMultiplier=1.0:amount=10
- wave=2:entityType=SKELETON:fast:treasure
- wave=5:entityType=WITHER_SKELETON:boss
- wave=8:entityType=PHANTOM:air:horde
| Ключ | Тип | Примечания |
|---|---|---|
wave | int | Обязательно. Номер волны, к которой относится эта запись |
entityType | enum | Обязательно. Значение Bukkit EntityType |
healthMultiplier | double | Опционально. Умножает максимальное здоровье сущности |
amount | int | Опционально. Переопределяет baseMobAmount для этой записи |
name | string | Опционально. Пользовательская строка имени |
resist | флаг | Помечает сущность как невосприимчивую к замедлению |
fast | флаг | Увеличивает скорость передвижения |
treasure | флаг | Удваивает золотую награду за убийство |
boss | флаг | Создаёт одного босса с увеличенным здоровьем и полосой здоровья босса |
horde | флаг | Удваивает amount и уменьшает здоровье вдвое |
air | флаг | Сущность появляется в 4 блоках над путём и игнорирует наземные стены |
Внутренняя математика количества
amountувеличивается наwave / 10перед спавном.- Записи
bossпереопределяютamountвmax(1, floor(wave / 10)). - Записи
hordeудваивают итоговоеamount. - Поверх количества для каждой записи рантайм волны также клонирует дополнительные копии первой, третьей, пятой, ... записей волны (каждый чётный индекс
0, 2, 4, ...) доwaveNumber - 1раз. Записи боссов никогда не клонируются таким образом. Поэтому более высокие волны накапливают больше дубликатов записей с меньшими индексами.
Формат блока сообщений
И prewaveMessages, и waveMessages принимают список карт:
prewaveMessages:
- wave: 1
message:
- "&aWelcome! Build a couple of basic towers along the path."
- wave: 5
message:
- "&6Heads up: a boss is coming next wave."
prewaveMessages запускается в начале фазы строительства для этой волны. waveMessages запускается в момент начала оборонительной фазы.
Жизненный цикл волны
Сессия проходит через эти состояния:
STARTING— до того, как игрок впервые выполнит/etd start.CONSTRUCTION_PHASE— 10-секундное окно строительства между оборонительными фазами.DEFENSIVE_PHASE— враги появляются и идут по пути.ENDING— игрок вышел, проиграл или у уровня закончились волны.
Фаза строительства всегда длится 10 секунд, если её не задерживает обучение (см. Особый случай уровня обучения).
Поведение окончания волны:
- Завершение волны даёт
waveNumber * 10золота. - Если вы не потеряли жизней во время волны, вы получаете «Идеальный» бонус, равный половине бонуса волны (
waveNumber * 10 * 0.5). Объявляемое число и фактически начисляемое золото теперь совпадают. - Каждая волна может выплатить награду только один раз — волна, которая почему-либо сообщит о завершении дважды, во второй раз игнорируется, и выплата не происходит вообще, как только сессия завершается.
- Список модификаторов следующей волны объявляется после окончания каждой волны.
Когда уровень заканчивается
Сессия продвигается дальше, только если номер следующей волны существует как ключ в waveEntities, поэтому номера волн должны идти подряд начиная с 1. Когда следующего номера нет:
- если файл определяет
suddenDeathWaveEntities, забег переходит во внезапную смерть; - иначе уровень заканчивается немедленно, не засчитывая волну, которая так и не началась. Сохраняемый рекорд и заголовок о завершении используют последнюю волну, которую игрок действительно прошёл.
Внезапная смерть
Если определён suddenDeathWaveEntities, уровень продолжает работать после списка настроенных волн.
Пул внезапной смерти циклится по настроенному номеру волны, а не по внутреннему счётчику: каждый раз, когда нужна волна внезапной смерти, EternalTD выбирает наименьший номер wave= в пуле, который больше текущего, и возвращается к наименьшему настроенному номеру, когда большего не остаётся. Поэтому пул не обязан быть пронумерован 1, 2, 3, ... — пропуски и произвольные начальные номера циклятся корректно.
Отображаемый номер волны продолжает расти от обычного списка волн; циклится только та запись пула, которая спавнится.
Стихийная привязка сущностей волны
Каждая волна имеет свою стихийную привязку, которая чередуется по волнам:
- Волна 1 → Огонь
- Волна 2 → Воздух
- Волна 3 → Вода
- Волна 4 → Земля
- (затем повторяется)
Когда сущность волны появляется, есть шанс waveNumber / 100, что сущность унаследует стихийную привязку волны, отображаемую как цветной тег, плавающий над мобом.
Правила стихийного урона обрабатываются классом DamageTower башни:
- Атакующий с той же привязкой против цели с той же привязкой — урон 0.5× (сопротивление).
- Противоположные одиночные стихии (Огонь против Воды, Воздух против Земли) — урон 2× (крит).
- Слитые привязки (Магма, Взрыв, Шторм, Слизь) следуют парным взаимодействиям; полную матрицу см. в исходном коде.
- Башня без привязки наносит урон 1× всем.
Слитые привязки образуются, когда Basic Tower касаются вспомогательные башни с комбинирующимися стихийными привязками:
| Комбинация | Результирующее слияние |
|---|---|
| Огонь + Земля | Магма |
| Огонь + Воздух | Взрыв |
| Вода + Воздух | Шторм |
| Вода + Земля | Слизь |
Конфликтующие пары (Огонь + Вода, Земля + Воздух) и любая смесь из 3+ стихий возвращают башню к состоянию «Без привязки».
Масштабирование здоровья, брони и награды
WaveEntity применяет эти формулы при спавне:
health = (currentHealth + ((wave - 1)^1.2) / 2) × healthMultiplier- Здоровье сущностей-боссов дополнительно умножается на
baseMobAmount × 0.5. - Здоровье сущностей-орд делится пополам.
- Здоровье воздушных сущностей делится пополам ещё раз.
- Броня появляется только с волны 10, установлена в
maxHealth / 80. - Награда —
ceil(health × 1)и удваивается для записейtreasure. Вспомогательные башни Gold Mine добавляют к награде при смерти.
Splitterlings (мини-споуны)
С волны 20 и далее неполётные враги при смерти спавнят дополнительных малых мобов («splitterlings»).
- Количество:
floor(wave / 20)за убийство. - Если родитель был
CAVE_SPIDER, splitterlings будутSILVERFISH. В противном случае этоCAVE_SPIDER. - Splitterlings появляются на
wave / 2от волны родителя, поэтому достаточно глубокий забег всё равно может породить цепочку splitterling в новые splitterlings при их собственной смерти. - Splitterlings не дают золота при смерти, а воздушные враги никогда не спавнят splitterlings.
Особый случай уровня обучения
Встроенная карта обучения проходит по жёстко закодированному скрипту волн обучения:
- Фаза строительства не завершается автоматически, пока вы не разместите точно требуемые башни на выделенных квадратах.
- Жёстко закодированные башни обозначаются цветными участками бетона под целевым квадратом сетки и, если установлен FMM, моделью красной стрелки, направленной вниз, плавающей над ним.
- Обучение начисляет игроку дополнительное золото на ранних волнах, чтобы заскриптованный набор башен всегда был доступен.
Жизни и золото игрока
- Стартовые жизни: 20.
- Стартовое золото: 150.
- Мобы-боссы стоят 5 жизней, если они достигают конца. Все остальные мобы стоят 1 жизнь.
- Читы (
/etd cheat) устанавливают жизни и золото в эффективно неограниченные значения и помечают сессию как читерскую для целей таблицы рекордов.
Отслеживание рекордов
Каждая конфигурация уровня сохраняет highscoreWave и highscorePlayerName. В конце нечитерской сессии плагин сохраняет новый номер волны в файл уровня и транслирует сообщение по всему серверу, если он побил предыдущий рекорд.