技术:出怪机制

版本差异

到此差别页面的链接

两侧同时换到之前的修订记录 前一修订版
后一修订版
前一修订版
技术:出怪机制 [2023/02/12 19:00] – 那位叫 "我是沙雕www" 的网友还蛮有自知之明 185.220.100.252技术:出怪机制 [2023/12/15 20:46] (当前版本) – [合法行] 39.76.68.180
行 1: 行 1:
 +~~SNIPPET_O1670878323~~snippet:通用排版~~
  
 +
 +/* 以上为所有页面共用的排版格式,请勿删除。 */
 +
 +~~SNIPPET_C~~snippet:通用排版~~
 +
 +
 +~~SNIPPET_O1715740674~~snippet:优秀条目~~
 +{{tag>[优秀条目]}}
 +<WRAP center round tip note>
 +经OP鉴定,本词条内容清晰,排版优美,是值得参考的优秀范例。
 +</WRAP>
 +~~SNIPPET_C~~snippet:优秀条目~~
 +
 +
 +~~SNIPPET_O1715740674~~snippet:引自外部~~
 +{{tag>[引自外部]}}
 +<WRAP center round info note>
 +本条目部分或全部内容搬运自外部资源。
 +
 +遵守[[https://creativecommons.org/licenses/by-sa/4.0/deed.zh|CC BY-SA 4.0协议]],部分内容可能有所改动。
 +</WRAP>
 +~~SNIPPET_C~~snippet:引自外部~~
 +
 +<WRAP center round help note>
 +以下内容涉及较多精确数据,除非确信某处有误,否则请**谨慎修改**。
 +</WRAP>
 +
 +======出怪机制======
 +
 +<callout type="tip" title="引用源" icon="true">
 +/* 使用时请取消勾选【保持同步】,否则无法输入内容! */
 +
 +[[https://pvz.tools/wiki/#%E5%87%BA%E6%80%AA%E8%A7%84%E5%BE%8B|植僵百科知识:出怪规律]]
 +</callout>
 +
 +本条目主要讲解生存无尽模式中僵尸的生成算法与随机原理。
 +
 +=====出生点=====
 +
 +出生点指僵尸生成时的x坐标。(([[https://crescb.com/timespace/ts/index.html|现代遗留问题清算——这个世界的时空。]]))
 +
 +^  僵尸  ^  普通波出生点  ^  旗帜波出生点  ^
 +|  旗帜  |  -  |  800  |
 +|  冰车  |  800~809  ||
 +|  投篮  |  825~834  ||
 +|  白眼、红眼  |  845~854  ||
 +|  撑杆  |  870~879  ||
 +|  雪橇  |  880~1030  ||
 +|  所有其他僵尸  |  780~819  |  820~859  |
 +===== 出怪类型 =====
 +
 +出怪类型指本次选卡**准许**生成的僵尸种类。
 +
 +<callout type="info" title="准许" icon="true">
 +即使准许生成某僵尸,也不代表该僵尸一定会出现。例如,即便出怪类型中含有蹦极僵尸,也可能不生成蹦极,取决于生成时的随机结果。
 +
 +另有一部分僵尸无需准许亦能生成,如固定出现的旗帜僵尸、小概率随机出现的雪人僵尸。
 +</callout>
 +
 +出怪类型位于''%%[[[6a9ec0]+768]+54d4]%%''开始的连续33个''bool''类型的地址,''true''代表准许,''false''代表不准许。
 +
 +出怪类型的决定方式如下(([[https://tieba.baidu.com/p/2316788883|出怪种子到出怪类型的算法和示例代码]])):
 +
 +  - 设定要出普僵
 +  - 产生一个0~4的伪随机整数(后文详解),若等于0则设定要出读报,否则设定要出路障((此处读报和路障中未被选中者,仍有可能在后面的步骤中被选中,因而“读报路障不同出”系谣言))
 +  - 若''**轮数**<8'',则设定剩余出怪类型数为''轮数+1'',否则设定剩余出怪类型数为9
 +  - 产生一个0~33的伪随机整数,若未设定要出此类僵尸且没有禁止出此类僵尸((伴舞/鸭子/雪橇/雪人/小鬼、植物僵尸、黑夜的冰车、非后院的潜水/海豚、屋顶的舞王/矿工、''轮数<2''时的冰车/白眼、''轮数<5''时的红眼)),则设定要出此类僵尸并进入第5步,否则重复第4步
 +  - 若第4步中已设定要出的僵尸类型数等于第3步的剩余出怪类型数,则进入第6步,否则重复第4步
 +  - 忽略摇旗、僵博,即强制设为''false''((若均未选中,为常规“11怪”;若选中其一,为“10怪”;若均选中,为“9怪”))
 +
 +
 +<callout type="info" title="轮数" icon="true">
 +轮数即''选卡时已完成flag数/2-1''
 +</callout>
 +
 +
 +随机数生成器算法为[[https://baike.baidu.com/item/%E6%A2%85%E6%A3%AE%E6%97%8B%E8%BD%AC%E7%AE%97%E6%B3%95|MT19937]],种子由以下几个数值相加:
 +
 +<code>
 +[[[6a9ec0] +82c] +20]              // 用户序号
 +[[[6a9ec0] +768] +561c]            // 出怪种子
 +[[[[6a9ec0] +768] +160] +6c] * 65  // 完成选卡次数 * 101
 +[[6a9ec0] +7f8]                    // 游戏模式
 +</code>
 +
 +===== 出怪概率 =====
 +
 +以下表格列出了不同轮数下,各僵尸出现在出怪类型中的概率,以及出怪类型中僵尸总数((普僵与鸭子计一种,不计旗帜(固定生成)、雪人(极小概率随机生成)))各取值的概率。(([[https://tieba.baidu.com/p/5714350581|无尽生存僵尸出现概率统计]]))
 +
 +''轮数=1''
 +^      ^  路障  ^  读报  ^  其他  ^  2种  ^  3种 ^  4种 ^
 +^  前院     |  82.67% |  30.67% |  13.33% |  0.95% |  24.76% |  74.29% |
 +^  后院     |  82.35% |  29.41% |  11.76% |  0.74% |  22.06% |  77.21% |
 +^  屋顶     |  83.08% |  32.31% |  15.38% |  1.28% |  28.21% |  70.51% |
 +
 +''轮数=2''
 +^      ^  路障  ^  读报  ^  其他  ^  3种  ^  4种 ^  5种 ^
 +^  白昼     |  83.53% |  34.12% |  17.65% |  2.21% |  30.88% |  66.91% |
 +^  黑夜       83.75% |  35.00% |  18.75% |  2.50% |  32.50% |  65.00% |
 +^  后院     |  83.16% |  32.63% |  15.79% |  1.75% |  28.07% |  70.18% |
 +^  屋顶     |  84.00% |  36.00% |  20.00% |  2.86% |  34.29% |  62.86% |
 +
 +''轮数=3''
 +^      ^  路障  ^  读报  ^  其他  ^  4种  ^  5种 ^  6种 |
 +^  白昼     |  84.71% |  38.82% |  23.53% |  4.41% |  38.24% |  57.35% |
 +^  黑夜       85.00% |  40.00% |  25.00% |  5.00% |  40.00% |  55.00% |
 +^  后院     |  84.21% |  36.84% |  21.05% |  3.51% |  35.09% |  61.40% |
 +^  屋顶     |  85.33% |  41.33% |  26.67% |  5.71% |  41.90% |  52.38% |
 +
 +''轮数=4''
 +^      ^  路障  ^  读报  ^  其他  ^  5种  ^  6种 ^  7种 |
 +^  白昼     |  85.88% |  43.53% |  29.41% |  7.35% |  44.12% |  48.53% |
 +^  黑夜       86.25% |  45.00% |  31.25% |  8.33% |  45.83% |  45.83% |
 +^  后院     |  85.26% |  41.05% |  26.32% |  5.85% |  40.94% |  53.22% |
 +^  屋顶     |  86.67% |  46.67% |  33.33% |  9.52% |  47.62% |  42.86% |
 +
 +''轮数=5''
 +^      ^  路障  ^  读报  ^  其他  ^  6种  ^  7种 ^  8种 |
 +^  白昼     |  86.67% |  46.67% |  33.33% |  9.80% |  47.06% |  43.14% |
 +^  黑夜       87.06% |  48.24% |  35.29% |  11.03% |  48.53% |  40.44% |
 +^  后院     |  86.00% |  44.00% |  30.00% |  7.89% |  44.21% |  47.89% |
 +^  屋顶     |  87.50% |  50.00% |  37.50% |  12.50% |  50.00% |  37.50% |
 +
 +''轮数=6''
 +^      ^  路障  ^  读报  ^  其他  ^  7种  ^  8种 ^  9种 |
 +^  白昼     |  87.78% |  51.11% |  38.89% |  13.73% |  50.33% |  35.95% |
 +^  黑夜       88.24% |  52.94% |  41.18% |  15.44% |  51.47% |  33.09% |
 +^  后院     |  87.00% |  48.00% |  35.00% |  11.05% |  47.89% |  41.05% |
 +^  屋顶     |  88.75% |  55.00% |  43.75% |  17.50% |  52.50% |  30.00% |
 +
 +''轮数=7''
 +^      ^  路障  ^  读报  ^  其他  ^  8种  ^  9种 ^  10种 |
 +^  白昼     |  88.89% |  55.56% |  44.44% |  18.30% |  52.29% |  29.41% |
 +^  黑夜       89.41% |  57.65% |  47.06% |  20.59% |  52.94% |  26.47% |
 +^  后院     |  88.00% |  52.00% |  40.00% |  14.74% |  50.53% |  34.74% |
 +^  屋顶     |  90.00% |  60.00% |  50.00% |  23.33% |  53.33% |  23.33% |
 +
 +
 +''轮数≥8''
 +^      ^  路障  ^  读报  ^  其他  ^  9种  ^  10种 ^  11种 |
 +^ 白天     |  90.00% |  60.00% |  50.00% |  23.53% |  52.94% |  23.53% |
 +^ 黑夜       90.59% |  62.35% |  52.94% |  26.47% |  52.94% |  20.59% |
 +^ 后院     |  89.00% |  56.00% |  45.00% |  18.95% |  52.11% |  28.95% |
 +^ 屋顶     |  91.25% |  65.00% |  56.25% |  30.00% |  52.50% |  17.50% |
 +
 +<callout type="info" title="计算公式" icon="true">
 +设可出怪类型数是''a'',剩余出怪类型数是''b'',则:
 +  * 路障出现概率''0.8+0.2*b/a''
 +  * 读报出现概率''0.2+0.8*b/a''
 +  * 其他出现概率''b/a''
 +僵尸种类数的三种情况概率分别为:
 +  * ''b*(b-1)/(a*(a-1))''
 +  * ''b*(a-b)*2/(a*(a-1))''
 +  * ''(a-b)*(a-b-1)/(a*(a-1))''
 +''轮数≥5''时,六大场地的''a''值分别为18/17/20/20/16/16;''轮数≥8''时,''b''为9。
 +</callout>
 +
 +===== 出怪列表 =====
 +
 +出怪列表决定了实际生成的僵尸的具体种类与个数,在选卡页面就已经确定。退出重进选卡页面会刷新出怪列表<wrap lo>(所谓的无痕S/L)</wrap>
 +
 +完整的出怪列表长度2000(([[https://tieba.baidu.com/p/2306159144|这两天研究了一下PVZ的出怪机制]])),位于''%%[[[6a9ec0]+768]+6b4]%%''开始的连续2000个int_32类型的地址,每50个为1波,总共记录40波。因此,每波至多生成50只僵尸。若出怪列表中留空,则对应波次会生成少于50只。
 +
 +生存无尽模式中每轮仅20波,故只使用前1000个值。老虎机、宝石迷阵等无限出怪的模式中,第41波起会重复循环第40波的出怪。
 +
 +每波僵尸刷新时,游戏会严格按照出怪列表预先设定的顺序依次生成对应僵尸。
 +
 +生存无尽中,出怪列表的生成受以下因素影响:**权重、级别、阶数、红眼数量上限**。
 +
 +==== 权重 ====
 +
 +权重位于''%%[0x0069da94 + i * 0x1c]%%'',游戏依此**加权随机**决定下一个要填入出怪列表的僵尸。
 +
 +<callout type="info" title="加权随机" icon="true">
 +即调整不同结果被随机到的概率。
 +
 +例如从箱中抽红球与黄球,若红球权重2,黄球权重1,等同于抽到红球的概率为3分之2,抽到黄球的概率为3分之1。
 +</callout>
 +
 +
 +==== 级别 ====
 +
 +每种僵尸的级别位于''%%[0x0069da88 + i * 0x1c]%%''
 +
 +各僵尸级别与权重一览((以内存值为准,实际有调整的标于备注)):
 +<sortable 3phase 2=nosort 5=nosort>
 +^  序号 ^        简称 ^  级别 ^  权重 ^                           备注                            |
 +|    |     普僵    |    |  4000 |     ''轮数=5''起每轮-180,''轮数=25''起固定为400                                                        |
 +|    |     旗帜    |    |    |       无需出怪类型准许亦可生成,每个旗帜波有且仅有一只                                                      |
 +|    |     路障    |    |  4000 |      ''轮数=5''起每轮-150,''轮数=25''起固定为1000                                                      |
 +|    |     撑杆    |    |  2000 |                                                            |
 +|    |     铁桶    |    |  3000 |                                                            |
 +|    |     读报    |    |  1000 |                                                            |
 +|    |     铁门    |    |  3500 |                                                            |
 +|    |     橄榄    |    |  2000 |                                                            |
 +|    |     舞王    |    |  1000 |                                                            |
 +|    |     伴舞    |    |    |            衍生于舞王                                                |
 +|  10  |     鸭子    |    |    |  实际出现的鸭子僵尸为出现在水路的普僵/路障/铁桶自动转换而来 |
 +|  11  |     潜水    |    |  2000 |                                                            |
 +|  12  |     冰车    |    |  2000 |                                                            |
 +|  13  |     雪橇    |    |  2000 |                                                            |
 +|  14  |     海豚    |    |  1500 |                                                            |
 +|  15  |     小丑    |    |  1000 |                                                            |
 +|  16  |     气球    |    |  2000 |                                                            |
 +|  17  |     矿工    |    |  1000 |                                                            |
 +|  18  |     跳跳    |    |  1000 |                                                            |
 +|  19  |     雪人    |    |    |      无需出怪类型准许亦可生成,需已在[[教程:冒险模式|冒险]]二周目4-10见到雪人                                                      |
 +|  20  |     蹦极    |    |  1000 |     仅在旗帜波生成                                                        |
 +|  21  |     梯子    |    |  1000 |                                                            |
 +|  22  |     投篮    |    |  1500 |                                                            |
 +|  23  |     白眼    |  10  |  1500 |                                                            |
 +|  24  |     小鬼    |  10  |    |         衍生于巨人                                                    |
 +|  25  |     僵博    |  10  |    |                                                            |
 +|  26  |     豌豆    |    |  4000 |                                                            |
 +|  27  |     坚果    |    |  3000 |                                                            |
 +|  28  |     辣椒    |    |  1000 |                                                            |
 +|  29  |     机枪    |    |  2000 |                                                            |
 +|  30  |     窝瓜    |    |  2000 |                                                            |
 +|  31  |    高坚果      |  2000 |                                                            |
 +|  32  |     红眼    |  10  |  6000 |       非旗帜波调整为1000                                                      |
 +</sortable>
 +
 +每波所出僵尸的级别总和不超过该波**级别上限**。
 +
 +<callout type="info" title="级别上限" icon="true">
 +每波级别上限 = ''%%int(int((当前波数 + 已完成选卡数 * 每轮总波数) * 0.8) / 2) + 1%%'',旗帜波再''* 2.5''并向零取整。
 +</callout>
 +
 +==== 阶数 ====
 +
 +阶数决定了这个僵尸从第几波才会出现(([[https://tieba.baidu.com/p/7861483105|【无尽开局出怪规律科普】你知道多少轮以后出怪饱和吗?]]))。
 +
 +|<100% 5em>|
 +^  阶数  ^  包含  ^  限制  |
 +|  一阶僵尸  |  普僵、路障、铁桶、读报、雪人  |  第1波开始就可以出现  |
 +|  二阶僵尸  |  撑杆、铁门、橄榄、舞王  |  至少从第5波开始才可以出现  |
 +|  三阶僵尸  |  潜水、海豚、冰车、小丑、气球、矿工、跳跳、梯子、投篮  |  至少从第10波开始才可以出现  |
 +|  四阶僵尸  |  白眼、红眼  |  至少从第15波开始才可以出现,''轮数=9''起每轮-1,''轮数=23''起固定为1  |
 +
 +==== 红眼数量上限 ====
 +
 +已生成的红眼总数达到红眼数量上限后,非旗帜波不再出红眼,立刻生效。
 +
 +红眼数量上限初始为0,''轮数=5''起每轮+1,''轮数=54''起固定为50。
 +
 +===== 出怪难度饱和 =====
 +出怪难度饱和指到达一定flags数后,游戏不再增加出怪算法难度的情况。该flags数阈值被称作“饱和f数”。
 +
 +从不同角度可以得到不同的饱和f数:
 +  * 第**47f**起,阶数不再起限制作用
 +  * 第**85f**起,级别上限在统计意义上不再起限制作用
 +  * 第**109f**起,红眼数量上限不再起限制作用
 +  * 第**126f**起,级别上限在严格意义上不再起限制作用
 +
 +
 +===== 出怪选行 =====
 +
 +
 +<callout type="tip" title="引用源" icon="true">
 +/* 使用时请取消勾选【保持同步】,否则无法输入内容! */
 +
 +[[https://tieba.baidu.com/p/8048386143|出怪论:出怪的选行]]
 +</callout>
 +
 +
 +<callout type="danger" title="不要强行认字" icon="true">
 +理解以下内容需要一定的数学知识。
 +</callout>
 +
 +==== 出怪行信息 ====
 +
 +对于第i行,有权重、上次选择、上上次选择三个信息。
 +
 +权重用于计算出怪内容,之前出怪用于计算出怪概率。
 +
 +作如下定义:
 +  * 将第i行权重定义为''Weight<fs x-small>i</fs>''
 +  * 将第i行距离上次被选取定义为''LastPicked<fs x-small>i</fs>''
 +  * 将第i行距离上上次被选取定义为''SecondLastPicked<fs x-small>i</fs>''
 +
 +''LastPicked<fs x-small>i</fs>''和''SecondLastPicked<fs x-small>i</fs>''的初始值为0。
 +
 +==== 某一行出怪时 ====
 +又称**第j行插入事件**。
 +
 +为了避免某行僵尸过多,当某一行出怪,游戏会减少改行出怪的概率,提高其他行的出怪概率<wrap lo>(设想一下,如果让一个人将一堆金币平均分给几个人,但是这几个人没有顺序,也只能抽取,那么这个发金币的人肯定更倾向于发给金币更少的人)</wrap>
 +
 +执行第j行插入事件时,会发生如下变化:
 +  - ∀i∈[1,6],如果''Weight<fs x-small>i</fs>>0'',则''LastPicked<fs x-small>i</fs>''和''SecondLastPicked<fs x-small>i</fs>''均增加1
 +  - 将''LastPicked<fs x-small>j</fs>''的值赋给''SecondLastPicked<fs x-small>j</fs>''
 +  - 将''LastPicked<fs x-small>j</fs>''设为0
 +
 +=== 计算示例 ===
 +
 +[{{ :技术:pasted:20221219-172750.png?350|示例结果}}]
 +用文字语言来解释的话,即如果某一行发生出怪,则所有行的上次和上上次被选取增加1,然后本行距离上次被选取(即当次选取)为0,上上次被选取改为上次被选取。
 +
 +如按(3,4,1,2,5,1)的行顺序出怪后,结果如右(不考虑第6行)。
 +<WRAP clear/>
 +
 +==== 选取某次出怪的行 ====
 +又称**抽取行事件**。
 +
 +将受到''LastPicked<fs x-small>i</fs>''和''SecondLastPicked<fs x-small>i</fs>''影响后的''Weight<fs x-small>i</fs>''称之为平滑权重,记为''SmoothWeight<fs x-small>i</fs>''
 +
 +计算第i行的平滑权重的步骤如下:
 +1. 将第i行出怪权重在总权重的占比称之为,则有:
 +
 +{{:技术:pasted:20221220-031546.png}}
 +
 +将''LastPicked<fs x-small>i</fs>''对结果的影响因子称为''PLast<fs x-small>i</fs>'',再将''SecondLastPicked<fs x-small>i</fs>''对结果的影响因子称为''PSecondLast<fs x-small>i</fs>'',通过查阅代码我们知道,它们的计算公式是:
 +
 +{{:技术:pasted:20221220-031722.png}}
 +
 +最后获得平滑权重的计算公式如下:
 +
 +{{:技术:pasted:20221220-031732.png}}
 +
 +{{:技术:pasted:20221220-031740.png}}
 +
 +{{:技术:pasted:20221220-031814.png}}
 +
 +{{:技术:pasted:20221220-031938.png}}
 +
 +不难发现,在总权值为0的时候会在第6行出怪;如果前5行概率均为0的时候也会选择在第6行出怪;当所有行权重相等,且均未出过怪的时候,每行出怪概率相等,符合基本的要求。
 +
 +==== 合法行 ====
 +
 +对于一种僵尸,如果僵尸出现在这行是符合游戏规则的,那么这行对于这种僵尸就是合法行。
 +
 +通常地,如果满足下列任意条件,那么该行不合法:
 +  - 行大于6或者小于1
 +  - 无草皮之地关卡外的裸地行
 +  - 非泳池浓雾关卡(包含无草皮之地)的第6行
 +  - 无草皮之地关卡的第1行与第5行
 +
 +特别地,对于一些僵尸,有额外的不合法判定方法:
 +  - 高地行((正式版废除了高地行,故无需考虑;高低行在游戏中行类型为3))类型对冰车僵尸与雪橇队僵尸不合法
 +  - 水路对普僵、旗帜、路障、铁桶、潜水、海豚、气球、植物僵尸以外的僵尸不合法
 +  - 水路(波数小于5)对海豚、潜水以外的僵尸不合法(谁笑到最后关卡的波数需加上10*轮数)
 +  - 非水路对于海豚僵尸与潜水僵尸不合法
 +  - 冰道消失倒计时为0的行(冰道长度为0,但是倒计时不为0不算,是合法的),雪橇小队僵尸不合法
 +  - 非无尽关卡的第1行对于白眼、红眼不合法
 +  - 非后院场合,上下有任意一行不满足如下条件的对舞王僵尸不合法
 +    - 为草地
 +    - 行不大于6且不小于1
 +
 +注:无草皮之地的裸地对舞王僵尸合法。
 +
 +==== 选取出怪行的流程 ====
 +
 +对于选择僵尸出怪的行,游戏将依次计算钉耙、行类型、保护传送门、隐形食脑者、最后一波、推车、权重,最后得出结果。
 +
 +对于选取好的僵尸,选取出怪行按以下操作:
 +  * 若场上有钉耙,获取编号((即栈位))最小的钉耙并执行以下流程,否则跳过钉耙
 +    * 钉耙所在行对于该僵尸类型是否合法,若不合法,则跳过钉耙
 +    * 若钉耙和僵尸绑定过(即使曾经与之绑定的僵尸消失),则跳过钉耙
 +    * 将钉耙标记为已绑定,插入钉耙行,返回钉耙行行直接结束出怪计算
 +
 +先依次计算每行的权重,对于第i行,流程如下:
 +
 +{{:技术:pasted:20221220-032900.png}}
 +
 +所有行计算完毕后,按抽取行原则选取行,然后插入行并返回结果行。
 +
 +==== 实验数据 ====
 +
 +{{:技术:pasted:20221220-032909.png}}
 +
 +==== 一些推论 ====
 +
 +推论1:僵尸没有可出行时出现在第六行
 +
 +{{:技术:pasted:20221220-032938.png}}
 +
 +推论2:在样本量足够大的情况下,平均概率仅与权重有关
 +
 +{{:技术:pasted:20221220-032945.png}}
 +
 +推论3:在样本量足够大的情况下,''LastPicked<fs x-small>i</fs>''和''SecondLastPicked<fs x-small>i</fs>''仅与行被选中的顺序有关
 +
 +推论2被验证后,推论3是显然的。
  • 最后更改: 15月前
  • 185.220.100.252 修改