第 05 篇

僵尸出现在哪里

可选范围、选行历史与放置顺序。

僵尸最初抽中的行,可以与它最终可见的行不同。普通动作先创建整批实体,再应用间距、发出基础位置事件,随后继续子类位置处理。行历史记录较早的抽取;之后的移动不会重写它。

一批实体变为空间队列

普通随机间距动作按指令顺序创建实体,再对已创建实体执行间距处理。对于五行 Board 上共同的右侧入场路径,

X=820+xstage+HitRect.mWidth+80k+J,Y=222+76r,J{0,,29}.\begin{aligned} X&=820+x_{\mathrm{stage}}+\operatorname{HitRect.mWidth}\\ &\quad+80k+J,\\ Y&=222+76r,\qquad J\in\{0,\ldots,29\}. \end{aligned}

其中 rr 是从零开始的行索引,xstagex_{\mathrm{stage}} 是场景入口偏移,kk 统计同一动作中此前分配到该行的实体数量。每个动作从全新的计数器开始,因此独立旗帜动作不会继续普通阵容的间距计数。

这创建的是水平距离,而非按固定计时逐条释放指令。宽度甚至可以反转预期的空间顺序。在场景偏移为零时,某行中第一个宽度为 270 的 air_missile_launcher 起始 X 为 1090–1119;随后宽度为 42 的 skycity 加上 80 单位增量后,起始 X 为 942–971。尚未发生移动,后面的指令就已经更接近草坪。

黑暗时代可以改用符合条件的墓碑捷径 X 减去 50 作为场景入口,再加上宽度与随机间距。普通声明初始没有墓碑,并且没有启用已声明的墓碑设计器;只有实际存在符合条件的捷径,该分支才适用。这里均为游戏坐标。

资格条件提供基础候选行

指令 Row = 5 请求随机选择器;Row = 6 复用前一行。固定行值 0–4 使用另一分支。下列条件属于随机选择,并不适用于所有可能的后续放置:

  1. 行位于 Board.rowCount 范围内,并已启用。
  2. 锚点满足 GridExtents.mY - 1 <= row
  3. 场景条件接受该行与精确僵尸类型。

属性构造器将 GridExtents 默认为 (1, 1)。较大的 Y 范围限制锚点行,并不直接定义碰撞框或伤害覆盖。

场景/类型资格权重为正的玩家视角行号
海盗港湾基础步行僵尸2, 4
海盗港湾 seagullswashbuckler1, 3, 5
海盗港湾 cannon1–5
未来世界 disco_mech2–4
天空之城 invisible_plane,范围 Y = 33–5
天空之城 skycity_twinsplane,范围 Y = 22–5

海盗港湾普通木板声明位于从零开始的行 [1, 3]。场景条件检查名称,因此不能把规则推广到所有看起来会飞的类型。未来世界将 disco_mech 排除在最外侧行之外。其他标准场景条件在这个阶段接受所有行,但共同的 Board 与范围条件仍然适用。

先有基础权重,再看选择历史

对于某行保存的时间戳 trt_r,令 d=ttrd=t-t_r。其基础权重为

ur={0,ineligible,0.01,0<d<5,d/45,5d<45,1,d0    d45.u_r=\begin{cases} 0,&\text{ineligible},\\ 0.01,&0<d<5,\\ d/45,&5\le d<45,\\ 1,&d\le0\;\lor\;d\ge45. \end{cases}

时间戳初始为 FLT_MAX,因此全新 Board 上的合格行使用权重为 1 的分支。追踪到的小推车写入要求 WaveGeneratorModule,而普通无尽列出的是 WaveManagerModuleProperties。这个时间戳不会随每次普通生成而重置。

归一化为 pr=ur/jujp_r=u_r/\sum_j u_j。令 ar,bra_r,b_r 为距最近一次和再前一次选择的计数器。对于 pr106p_r\ge10^{-6},历史调整在代数上为

fr=pr(1.5ar+0.25br+1.75)1,p~r=prclamp(fr,  0.01,  100).\begin{aligned} f_r&=p_r(1.5a_r+0.25b_r+1.75)-1,\\ \widetilde p_r&=p_r\operatorname{clamp}(f_r,\;0.01,\;100). \end{aligned}

更小的 prp_r 得到零调整权重。下一次抽取的名义份额为 p~r/jp~j\widetilde p_r/\sum_j\widetilde p_j。两个计数器初始都为零。选定一行之后,更新顺序为:

  • 对每个基础权重为正的行,同时递增两个计数器。
  • 对选中行,将递增后的 ara_r 复制到 brb_r,再令 ar=0a_r=0

因此,合格但未选中的行从 (a,b)(a,b) 变为 (a+1,b+1)(a+1,b+1),选中行则变为 (0,a+1)(0,a+1)。计数器按选择次数推进,不按秒。

当五行同等符合条件时,前两次抽取的各行权重相等。第三次抽取前,若此前选过两个不同行,它们各占 5.88%,未选行各占 29.41%;若连续选择同一行,该行占 4.76%,其他行各占 23.81%。视图可以重建这些状态,并比较地形限制。

零权重不会移除记录。采样器使用 draw <= cumulative weight,因此恰为零的抽取值可以接受第一条记录,即使它不符合资格。受控原生端点检查及其范围保留在行条件注释中。

基础事件先执行,子类随后完成

应用随机间距时,整批实体已经存在于 Board 僵尸列表中。设置实体位置之后,执行其位置钩子。基础钩子同步发出 OnZombieAddedToBoard,子类代码可以在之后继续运行。

活动的球果训练家幽林马法阵,可以把符合条件的新实体移动到 (744,374,0)(744,374,0),即玩家视角第 9 列、第 3 行。它响应新加入事件,而不是按半径反复拉取所有已有僵尸。目标位置固定,不取自马的位置。

回调允许运行时小型/中型体型,并有状态、标记、Zomboss、精英及精英免疫排除条件。检查的是运行时体型,而非精灵图看起来的大小。普通首领状态与精英状态不同,回调也不直接检查普通首领状态。

国王和渔夫随后进行各自的同类占用扫描。它们能看到同一新批次中其他实体的当前坐标,包括尚未最终确定的位置。

新实体从候选中移除的同类所在行自身处理的影响
dark_kingBoard 列表中的所有匹配对象,包括自身自身有效的当前行会被移除
beach_fisherman其他匹配对象,明确排除自身没有其他匹配对象占用时,保留当前行

当前行不可用时,辅助函数打乱剩余候选并选择一个。成功放置使用最后一列,X 为 744。扫描没有“仅存活对象”筛选:死亡或等待移除的对象,在从 Board 列表中删除前仍可能占用行。

没有剩余行时,新实体被拒绝。普通国王路径进入 ZS_Die,渔夫则立即发起移除。两者都不会选择较早对象作为替代牺牲者、创建重试或退还生成指令。两者仍能到达普通掉落检查,且拒绝发生在初始波次生命值快照之前。

法阵只有一个共享生命周期

Board 保留共享法阵,而非每匹马各有一个。首次创建确定目标位置与是否存在装扮附加效果。具备该效果时,被接受的新实体还会收到眩晕请求,其引用会被保留;这不会绕过正常的状态免疫机制。

随包序列为开始动画、15 秒循环、结束动画。重复激活会以新的 15 秒重新开始循环,不会把时间加到旧剩余时长上。复用保留捕获引用,也不改变首次创建时的装扮效果。

清理会清除追踪的眩晕状态,但没有保存原始坐标,也不会恢复位置。它同样不会持续把已捕获僵尸移回法阵。特别是,之后成功的国王/渔夫放置可以覆盖法阵位置,而最初抽中的行仍保留在历史记录中。

证据注释 /