EternalTD 波次与敌人
plugins/EternalTD/waves/ 下的波次文件定义了某关卡的完整敌人阵容,包括普通波次、突袭波次以及可选的波前消息或波次消息。每个关卡配置都通过 wavesConfigFile: 引用一个波次文件。
顶级字段
| 字段 | 类型 | 默认值 | 备注 |
|---|---|---|---|
isEnabled | bool | true | 已禁用的波次文件不会加载;依赖该缺失配置的关卡无法启动 |
baseMobAmount | int | 20 | 当条目未指定 amount= 时使用的默认数量 |
waveEntities | string list | 必填 | 按波次列出的敌人条目 |
suddenDeathWaveEntities | string list | 可选 | 可选的循环波次池,在已配置的波次用尽后运行 |
prewaveMessages | list of maps | 可选 | 以当前计数器为键的消息:入场时为 0,第 N 波结束后为 N |
waveMessages | list of maps | 可选 | 波次开始时显示的消息 |
没有突袭条目时,会话在转入下一波但找不到对应配置时结束。通常会先经过最后的建造窗口,除非玩家提前推进。
波次实体条目格式
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 | 可选,默认 1.0。乘以实体的最大生命值 |
amount | int | 可选。覆盖此条目的 baseMobAmount |
name | string | 可选。自定义名称字符串。会被解析并保存,但插件目前不会把它应用到生成的生物上(名牌显示的是生命值/护甲条) |
resist | flag | 将实体标记为免疫减速 |
fast | flag | 提高移动速度 |
treasure | flag | 击杀时的金币赏金翻倍 |
boss | flag | 使用下述 Boss 数量规则和生命值缩放,每个 Boss 都有血条 |
horde | flag | amount 翻倍,生命值减半 |
air | flag | 实体在路径上方 4 格处生成,无视地面墙体 |
键和标记前后不要加空格,实体类型使用大写,波次编号、数量和生命值倍率使用正数。解析器不会去除空格,也不会拒绝所有无效范围;未知键会被忽略。普通条目格式错误会禁用波次配置;突袭条目格式错误会记录警告,且池中可能保留此前已解析的条目。文件解析成功并不能证明其中的实体可以生成。
内部数量计算
amount会加上wave / 10后再截断为整数,因此一个amount=20的条目在第 15 波产出 21 只生物,在第 20 波产出 22 只。boss条目会将amount覆盖为max(1, floor(wave / 10))。horde条目会使最终amount翻倍。- 在每条目数量之上,波次运行时在构建该波次时还会追加副本。请注意,它索引的那个列表是完全展开后的生物列表——配置解析器已经为每只生物各生成了一个对象,因此单独一行
amount=20会贡献 20 个连续索引,而不是一个。对每一个既是该展开列表中的有效索引又小于波次编号的偶数索引i(0, 2, 4, ...),都会额外追加一个索引i处生物的克隆。Boss 条目永远不会以此方式被克隆。因此额外生物的数量大致为ceil(min(waveNumber, listSize) / 2):第 1 波多 1 只,第 3-4 波多 2 只,第 9-10 波多 5 只,第 15-16 波多 8 只,以此类推,直到波次编号超过列表长度。
生成间隔为 min(floor(200 / totalEntities), 20) 刻。普通生成要求计数器大于该间隔的两倍;horde 节奏要求大于整数减半后间隔的两倍。由于比较是严格大于,还会多一个计数器刻,并非恰好两倍。是否使用 horde 节奏取决于波次列表中第一个剩余生物,因此混合普通和 horde 条目会随列表变化而改变节奏。每只生物生成时都会随机选择关卡的一个起点格。
消息块格式
prewaveMessages 和 waveMessages 都接受一个 map 列表:
prewaveMessages:
- wave: 0
message:
- "&aWelcome! Build a couple of basic towers along the path."
- wave: 4
message:
- "&6Heads up: a boss is coming next wave."
prewaveMessages[0] 在入场时运行。第 N 波结束后,prewaveMessages[N] 在为下一波建造时运行:要预告第 5 波,请使用键 4。waveMessages[N] 在第 N 波开始时运行。这些键使用会话显示的计数器,突袭模式也一样。同一个键的重复消息条目会覆盖之前的条目。
波次生命周期
一次会话会经历以下状态:
STARTING— 玩家第一次运行/etd start之前。CONSTRUCTION_PHASE— 防御阶段之间的 10 秒建造窗口。DEFENSIVE_PHASE— 敌人正在生成并沿路径行走。ENDING— 玩家退出、失败,或关卡用尽了所有波次。
普通建造计时器为 10 秒。/etd start 或 Next Wave 工具可以提前推进,但仍须满足教程要求(请参阅教程关卡)。最初的开始阶段会等待开始操作;教程在最后一个要求被接受时可以推进。
波次结束行为:
- 完成一波将奖励
waveNumber * 10金币。 - 如果你在波次中未损失生命,将获得“完美”奖励,其价值为波次奖励的一半(
waveNumber * 10 * 0.5)。现在公布的数字与实际授予的金币一致。 - 每一波只能结算一次 —— 如果某一波因故重复上报完成,第二次会被忽略;而一旦会话进入结束流程,就不会再有任何结算。
- 波次结束后,若下一波的修饰符字符串非空,就会公布它。它来自第一个配置的敌人,而不是混合波次的所有条目。
关卡何时结束
只有当下一个波次编号作为键存在于 waveEntities 中时,会话才会继续推进,因此波次编号必须从 1 开始连续排列。当下一个编号缺失时:
- 如果文件定义了
suddenDeathWaveEntities,本局会进入突袭模式; - 否则关卡会立即结束,且不会把那个从未运行的波次计算在内。持久化的最高分和通关标题使用的是玩家实际打过的最后一波。
突袭模式
如果定义了 suddenDeathWaveEntities,关卡会继续运行至已配置波次列表之外。
突袭池按配置的波次编号轮换。每次需要时,EternalTD 会选择大于当前池键的最小非负键;若没有更大的键,就回到最小键。池计数器初始为 0,因此存在正数键时,配置的键 0 会在第一轮被跳过。请使用正数键;允许编号间隔,且键 0 也不适用于下文的生命值公式。
显示的波次计数器会继续增加。敌人的生命值、护甲、速度、基础赏金及分裂小怪阈值使用所选条目配置的 wave=,不会自动随显示计数器缩放。运行时的额外克隆和元素抽取则使用显示计数器。例如,池条目 10 和 20 即使在显示第 100 波时,也保留各自的敌人数值缩放。下一波查找仍会先检查每个显示编号是否有普通条目,因此先前出现缺号后,仍可能使用后续的普通键。
波次实体的元素属性
每一波都有其各自的元素属性,按波次轮换:
- 第 1 波 → 火
- 第 2 波 → 风
- 第 3 波 → 水
- 第 4 波 → 土
- (然后重复)
普通波次实体生成时,继承波次元素的概率为显示的 waveNumber / 100;从显示第 100 波起,抽取必定成功。彩色标签显示元素。分裂小怪单独创建,不参与此抽取。
元素伤害规则由塔的 DamageTower 类处理:
- 相同属性的攻击者对相同属性的目标 —— 0.5× 伤害(抗性)。
- 相对的单一元素(火对水、风对土)—— 2× 伤害(暴击)。
- 融合属性遵循下表。其他不匹配的组合造成 1× 伤害。
- 无属性的塔对任何目标造成 1× 伤害。
| 塔的属性 | 对以下属性造成 2× 伤害 | 对以下属性造成 0.5× 伤害 |
|---|---|---|
| 熔岩 | 风、水 | 土、火、熔岩 |
| 爆裂 | 土、水 | 风、火、爆裂 |
| 风暴 | 火、土 | 风、水、风暴 |
| 淤泥 | 火、风 | 土、水、淤泥 |
当基础塔被具有相互组合的元素属性的辅助塔接触时,会形成融合属性:
| 组合 | 产生的融合 |
|---|---|
| 火 + 土 | 熔岩 |
| 火 + 风 | 爆裂 |
| 水 + 风 | 风暴 |
| 水 + 土 | 淤泥 |
冲突规则比看上去更窄:
- 同一座塔上的土 + 风总是会让它恢复为无属性,无论还附加了什么。
- 火 + 水只有在同时存在三种或更多不同属性时才会恢复为无属性。一座恰好被一个火辅助塔和一个水辅助塔接触的塔,会任意保留两者之一,因为代码会落到“取集合中的第一个属性”,而那个集合是无序的。
- 无属性的辅助塔(Spyglass、Gold Mine)绝不会影响结果;只要附加了任何有属性的塔,它们就会从集合中被剔除。
每次重新计算都从基础塔自身的“无属性”元素开始,因此移除最后一座元素辅助塔后,塔会恢复为无属性。
生命值、护甲与赏金缩放
WaveEntity 生成时使用自身配置的波次编号(分裂小怪则使用父实体波次的一半),依次应用以下步骤:
- 基础生命值从
0.5起步并随波次增长:health = 0.5 + ((wave - 1)^1.2) / 2。 - Boss 实体在此基础上再乘以
baseMobAmount × 0.5。 - Horde 实体的生命值减半。
- 赏金在这里计算,为
ceil(health)——在healthMultiplier之前,也在 air 减半之前。treasure条目随后使其翻倍。 maxHealth = health × healthMultiplier。- Air 实体的
maxHealth再次减半。 - 护甲仅从第 10 波开始出现,设为
maxHealth / 80。
第 4 步的顺序很重要:healthMultiplier 为 3.0 会使生命值变为三倍,却不改变基础赏金。air 敌人虽然只有一半生命值,基础赏金仍与同等地面敌人相同。Gold Mine 在致命一击时加上奖励,并将结果截断为整数;小额赏金可能没有额外金币。
移动速度为:
speed = 0.3 × (1 - slow)
× 1.5 × (1 - slow) if fast
× 0.5 if air
+ wave / 1000
末尾的 wave / 1000 使用敌人配置的波次,在 air 和减速倍率之后加上。该值控制生物的移动速度属性。非 Mob 实体的备用逻辑则在每个移动刻朝下一个目的地传送 0.1 格,因此此公式并不是通用的“格/刻”速度。
分裂小怪(Splitterlings)
从第 20 波开始,非 air 敌人在死亡时会额外生成小型生物(“splitterlings”)。
- 数量:每次击杀生成
floor(wave / 20)个。 - 如果父实体是
CAVE_SPIDER,分裂小怪为SILVERFISH。否则为CAVE_SPIDER。 - 分裂小怪使用
floor(parentWave / 2)并继承当前路径位置。它们使用构造函数的 0.5 生命值倍率,不继承父实体的标记或元素属性。配置波次足够高时,它们死亡后还可能产生更多分裂小怪。 - 分裂小怪死亡时不给予金币,且 air 敌人永远不会生成分裂小怪。
教程关卡特殊情况
tutorial.yml 关卡使用与地图坐标绑定的硬编码脚本:
- 必须在高亮格放置要求的塔类型;若已有同类塔,则在该格升级。允许出售要求格上的错误塔。在对应脚本阶段,无关的放置、出售和升级会被拒绝。最后一个要求被接受时,会立即请求下一波。
- 彩色混凝土标示要求格。若 FMM 和
reddownarrow模型可用,每格上方的红箭头会指示所需的塔或升级。 - 第 1、2、3 波结束并进入建造阶段时,教程增加
+100金币;第 4 波后增加+200。这是额外收入,并非保证买得起。其他波次编号没有这笔补充。 - 每个所需塔的方格都会按它要求的塔类型着色:基础塔为绿色混凝土,Barricade 为棕色,Sugar 为白色,Spyglass 为青色,Beam Generator 为黄色,Explosion Factory 为红色,Ice Box 为蓝色,Armor Crusher 为灰色,Gold Mine 为橙色,Obsidian Quarry 为紫色,其他一律为黑色。
- 在每个脚本阶段,一条绿色 Boss 血条会以
Build towers! done/total!的形式统计已放置的所需塔数量。教程每两分钟会提醒你可以用/etd quit离开;只要还有未完成的要求,它也会重复当前的波前消息。
玩家生命与金币
- 起始生命:20。
- 起始金币:150。
- Boss 生物到达终点会消耗 5 条生命。其他所有生物消耗 1 条生命。
- 每次切换
/etd cheat(包括关闭)都会把金币重设为10,000,000、生命重设为1,000,000。该会话此后始终没有刷新最高分的资格。 /etd setwave <n>会更改会话计数器和奖励防重复状态,并将本局标记为已作弊。它不会替换当前敌人,也不会立即启动指定波次。下一次转换使用n + 1。
最高分追踪
每个关卡配置都会持久化 highscoreWave 和 highscorePlayerName。在非作弊会话结束时,插件会将新的波次编号保存到关卡文件中,如果超过先前的分数则会广播全服消息。