本帖最后由 Kuriyama_Mirai 于 2026-7-29 21:50 编辑
最近开始打文花帖了(才不是文花帖 DS 打不动了),于是想起 KirbyComment 曾经提出
过一些与文花帖的分数相关的、希望 thprac 能加入的辅助功能。这几天实现了一下这些功
能,也顺便研究了一下文花帖的得分机制,于是就想着写篇文章来解释一下。
文花帖整体的得分机制和文花帖 DS 类似,首先有一个基础分数(就是 DS 里的 Base
Point),在其上还会加一系列奖分,加完后会乘一系列奖励倍率,最后再乘一个与当前关
卡、波次有关的修正系数,然后舍去个位以及小数点后的部分,就得到了最终的分数。接下
来我们来逐一说明每个部分。
一些约定
所有的长度单位,如无特殊说明都是像素;所有的速度单位,如无特殊说明都是像素每帧。
几乎所有的涉及小数的计算都是用 float32 进行的,可以简单理解为在十进制下有 7 位左右
的有效数字。
在内存地址的表示上,本文用中括号表示对其中的内容取地址。譬如,当提到「内存地址
[0x401234]+0xABC」时,指的是这样的地址:先从地址 0x401234 处取出一个 32 位整
数,将其加上 0xABC 后得到的数作为一个地址。
当提到 自机/一颗子弹/boss/敌人 的位置时,是在指判定框的中心位置。这些东西的判定
框,以及相机的取景框,都是边与游戏区域的边框平行的矩形。激光可以认为是一根有方
向、宽度的线段,包含起始端点、结尾端点以及宽度。
基础分数
基础分数与拍到的子弹、激光,以及非 boss 的敌人有关。大体上,子弹越快分数越高,
(拍到的)激光长度越长分数越高。然而,这些都有例外。在原版游戏里,基础分数不会以
任何形式显示。
子弹
如果一颗子弹的判定框与取景框有公共点,游戏就会判定这颗子弹被拍到了。
我们将子弹按照大小分为四类,微型子弹、小型子弹、中型子弹和大型子弹,见下图所示:
这四种子弹在静止时的得分分别为 10, 20, 40 和 150。如果子弹不是静止的,其得分还会
乘上一个与速度 v 相关的系数 k,二者关系大致如下:
上述公式在 v 为 [2,6) 这段是近似的。这是因为游戏会舍去每颗子弹的分数的个位及小数点
后的部分。下面是四种不同的子弹在不同速度下的得分:
微型子弹得分与速度的关系
小型子弹得分与速度的关系
中型子弹得分与速度的关系
大型子弹得分与速度的关系
我们从上图可以看出,除了微型子弹以外,如果子弹的速度恰好在 5 到 6 之间,其得分可
能会比速度大于 6 时还要高。下面是一个小测试。让露米娅向下分别发射速度为 5.75 和
6.5 的两枚米弹,并通过 thprac 来观察拍摄这枚米弹所得的基础得分为多少(分数界面里
最上面的数字为基础得分)。可以看到,速度为 5.75 时基础分数为 90,高于速度为 6.5
时的 80。
拍摄一颗速度为 5.75 的小型子弹的情况
拍摄一颗速度为 6.5 的小型子弹的情况
激光
我们之前有提到,我们将激光视为一个带方向、宽度的线段,比如下图就是一根从 (20,20)
到 (60,40) 的、宽度为 20 的激光:
一根激光上有若干个「关键点」。将一个点从起始端点开始,沿中轴线方向移动 6 像素,
所得到的点为第一个关键点。第二个关键点为将其从第一个关键点继续移动 12 像素后得到
的点(即距离起始端点 18 像素),第三个关键点为将其从第二个关键点继续移动 12 像素
后得到的点,以此类推。每个关键点必须要在激光的中轴线上,如果超出了结束端点就不算
关键点了。在上图中,关键点已用绿色的实心菱形标出。每个位于取景框内的关键点会为基
础得分贡献 10 分。
一个有趣的事实是,对于同一根激光,并不是总是拍得越长,拍到的关键点就越多(从而分
数越高)。考虑下图的例子。红色和紫色的矩形表示对这根激光的两种可能的拍摄方式,其
中激光在红色取景框内的长度约为 43.68,在紫色取景框内的长度约为 39.84,但前者只包
含了 3 个关键点,而后者包含了 4 个。
非 boss 的敌人
每个拍到的非 boss 的敌人,都会提供 170 分的基础得分。它们包括蕾蒂的冷气、梅蒂欣的毒雾、爱丽丝的人偶、蓝的闪烁佛像(?)。
颜色奖分
游戏中的大多数子弹会被赋予一个用于计算奖分的颜色,大多数情况如下图所示:
没在上图中出现的子弹(譬如钱币弹、白色和灰色的子弹)在颜色奖分部分就被忽略。激
光、敌人也被忽略。如果某种颜色的子弹枚数达到了 100 颗,则会得到一个对应的 300 分
奖分(Red Bonus 等)。如果有三种颜色的子弹枚数分别达到了 20 颗,则会得到一个 900
分的 Colorful Shot 奖分。如果七种颜色的子弹都有至少 1 颗,则会得到一个 2100 分的
Rainbow Shot。这些奖分互相独立,可以全部获得,而不是说譬如拿了 Rainbow Shot 就
拿不了 Colorful Shot。参见下图:
拍摄七种颜色的子弹各 100 颗的情况
另外,6-1 是一个特殊情况:这关里橙发出的子弹被视为是「橙」色的,只要拍到 100 颗
就能拿到 Orange Shot。注意这和是否有拍到橙自己无关,参见下图:
在 6-1 里拍摄到 100 颗子弹,但没拍到橙的情况
Risk Shot
在拍下照片的一瞬间,如果自机周围有子弹或激光,就有可能会获得 Risk Shot。每颗擦到
的微型与小型子弹贡献 100 分,中型子弹贡献 400 分,大型子弹贡献 1000 分;每根擦到
的激光贡献 200 分。Risk Shot 最高有 2000 分,最低有 300 分(不足 300 分就不会有
Risk Shot 这一行)。不过事实上,这个 Risk Shot 并不会以任何形式影响得分计算(或许
是个 bug)。
子弹和激光的擦弹判定是不同的。对于一颗子弹而言,只要其判定框的四个角中有一个在以
玩家自机中心为圆心的、半径为 22 的圆内,就判定为擦弹;对于一根激光而言,将其判定
框向四个方向延伸 22 像素,如果包含了自机中心就判定为擦弹,如下图所示(图中所有虚
线长度均为 22 像素),左边为子弹的擦弹范围,右边为激光的擦弹范围。
Empty Shot
如果一张照片没有拍到自机和 boss,而且一颗子弹都没拍到(可以拍到激光和 boss 外的
敌人),那么会获得 Empty Shot,奖 0 分。
未使用 Bonus
游戏内部有四种无法获得的 Bonus,分别是 Geometric!、Lonely Shot、Miss Shot 和
Counter Flash。其中,Geometric! 似乎只是一个评价,而没有奖分;Lonely Shot 和
Miss Shot 都会奖 0 分,而 Counter Flash 显示上会奖 100 分,实际上不会奖分。下图是
手动获得这四种 bonus 时的分数显示(其中 Counter Flash 由于贴图过长被截断了):
Boss Shot
只要拍到了 boss,就会获得 Boss Shot 的奖励倍率。这个倍率与取景框中心和 boss 的中
心的距离 d 有关,其取值 k 如下:
注意有些时候 boss 可能表现为上下浮动的样子(譬如 1-4 里的露米娅),但其实际的判定
位置并不会跟着一起上下浮动。下图是一个演示,若取景框中心在绿圈内,则会得到 x2.0
的奖励倍率;若在红圈外,则会得到 1.2x 的倍率;若在二者之间,将会得到 x1.2 与 x2.0
之间的倍率。
「拍到 boss」的判定是:以 boss 为中心的、边长为 8 的正方形与取景框有公共点。另外,
尽管游戏在显示 Boss Shot 的时候只显示其小数点后的第一位,但计算时还是会用更高的
精度(float32)进行。
Self Shot 和 Two Shot
只要照片里拍到了自机,就会获得固定 x1.2 的 Self Shot 倍率;如果自机和 boss 都拍到
了,就会获得固定 x1.5 的 Two Shot 倍率。
「拍到自机」的判定是:以自机为中心的、边长为 16 的正方形与取景框有公共点。
Nice Shot
有时候,boss 会发出「咔」的一声,然后会有一个红色的魔法阵迅速出现、缩小并消失。
如果照片中拍到了这个魔法阵,就会获得 Nice Shot 的奖励倍率,其值 k 与魔法阵的大小
s(准确来说,是魔法阵半径与最大可能的半径的比值)的关系如下:
下图是魔法阵半径为其最大值的 80% 的展示。只要拍摄时魔法阵大小有这么大,就能获得
x1.5 的倍率:
与 Boss Shot 相同,尽管这个系数只显示其小数点后的第一位,计算时会以更高精度进行。
修正系数
在上述的得分机制以外,游戏还有一个隐藏的修正系数。这主要是为了平衡不同关之间的分
数,或是平衡同一关内不同波次之间的分数。这个系数会在上述的计算完成后最后乘上,每
关的修正系数如下:
| 关卡 | 乘数 | 关卡 | 乘数 | 关卡 | 乘数 | 关卡 | 乘数 | 关卡 | 乘数 | 关卡 | 乘数 | | 1-1 | 1.0 | 2-1 | 1.0 | 3-1 | 2.0 | 4-1 | 2.5 | 5-1 | 0.7 | 6-1 | 1.0 | | 1-2 | 1.0 | 2-2 | 1.0 | 3-2 | 1.4 | 4-2 | 1.6 | 5-2 | 1.0 | 6-2 | 3.5 | | 1-3 | 1.0 | 2-3 | 3.0 | 3-3 | 1.0 | 4-3 | 0.7 | 5-3 | 1.0 | 6-3 | 2.0 | | 1-4 | 3.0 | 2-4 | 1.0 | 3-4 | 1.5 | 4-4 | 0.4 | 5-4 | 1.0 | 6-4 | 14.0 | | 1-5 | 1.0 | 2-5 | 2.0 | 3-5 | 1.7 | 4-5 | 1.0 | 5-5 | 1.6 | 6-5 | 7.0 | | 1-6 | 1.0 | 2-6 | 1.3 | 3-6 | 1.0 | 4-6 | 0.4 | 5-6 | 0.9 | 6-6 | 1.5 | | | | | 3-7 | 2.0 | 4-7 | 0.7 | 5-7 | 1.0 | 6-7 | 15.0 | | | | | 3-8 | 3.5 | 4-8 | 1.0 | 5-8 | 2.0 | 6-8 | 5.0 | | | | | | | 4-9 | 0.5 | | | | |
| 关卡 | 乘数 | 关卡 | 乘数 | 关卡 | 乘数 | 关卡 | 乘数 | 关卡 | 乘数 | | 7-1 | 0.7 (前三张)
4.0 (中间三张)
0.6 (后三张) | 8-1 | 2.6 | 9-1 | 4.5 | 10-1 | 4.5 | EX-1 | 5.2 | | 7-2 | 0.7 | 8-2 | 1.6 | 9-2 | 4.5 | 10-2 | 1.2 | EX-2 | 12.0 | | 7-3 | 2.0 | 8-3 | 3.7 | 9-3 | 1.5 | 10-3 | 4.0 | EX-3 | 2.0 (激光)
8.0 (散弹) | | 7-4 | 2.7 | 8-4 | 5.0 | 9-4 | 4.0 | 10-4 | 8.0 | EX-4 | 6.2 | | 7-5 | 2.1 | 8-5 | 2.0 | 9-5 | 6.0 | 10-5 | 3.0 | EX-5 | 0.8 | | 7-6 | 4.0 | 8-6 | 1.9 | 9-6 | 4.0 | 10-6 | 6.0 | EX-6 | 5.2 | | 7-7 | 3.0 | 8-7 | 5.1 | 9-7 | 6.0 | 10-7 | 6.0 | EX-7 | 8.2 | | 7-8 | 3.1 | 8-8 | 3.6 | 9-8 | 3.0 | 10-8 | 1.0 (前三张)
10.0 (后六张) | EX-8 | 3.2 |
其中 10-8 由于第四到六张照片的弹幕比较稀疏,就设置了 10.0 的修正系数。然而,第七
张照片开始弹幕变回了和前三张类似的密度,但ZUN 忘了把乘数调回来了,这也使得其最
后三张照片的分数会相当高,甚至能达到一百万分以上。当一张照片的分数达到一百万时,
其分数显示会出问题,参见后文。
如何自己检查没有显示的参数
由于游戏没有显示上述所有的参数(基础分数,修正参数,乘数的小数点后面的位数等),
可以考虑自己检查这些值。若在 0x4339E3 处下断点(它会在每次拍到照片时被触发),
断点被触发后,在 [EBP+0xC] 处有一个结构体,其下 0x4 偏移处为基础得分(类型为
int32),0x14 偏移处为 Boss Shot 的乘数(类型为 float32),0x18 偏移处为 Nice
Shot 的乘数(类型为 float32)。此外,当前的修正系数是位于 [0x4C4E6C]+0x25718 的
一个 float32。
照片分数显示的 bug
游戏界面两侧的照片显示当分数过大或过小时会出 bug。游戏总是假定分数的位数在 2 到
6 之间,所以当总分为 0 时,其会显示 00(在 4-4 比较常见)。当总分达到一百万时,游
戏会以特殊的形式显示分数的十万位,如下图所示:
下图是一个实战中的展示(机师:Ia),其后三张照片的分数的百万位都为 2,十万位都为
1,故在十万位处显示的图像为 Geometric!。
参考资料
|