核心定位:
EFFECTSLIST.DAT是效果系统的类型注册表。 技能与词缀 dat 里每个[EFFECT]块的TYPE键,写的就是这张表某一行的NAME; 那一行的行号会成为CEffect+0x1C,进而决定这个效果做什么、五个数值槽分别叫什么、 缺省时套哪条曲线、tooltip 里怎么排版。本文档把这 239 行完整摊开,并把加载器逐指令拆到底。分析依据:基于 IDA 对 32 位可执行文件
Torchlight2.exe(基址0x400000)的逐指令反汇编分析。文中所有0x……均为绝对内存地址。 用量数据来自实机样本统计:原版E:/Torchlight 2/MEDIA的 16084 个.DAT文件共 9984 个可解析[EFFECT]块, MOD 库D:/WizardProject/TL2的 157950 个.DAT文件共 200352 个。 MOD 库是会变的——本系列三篇的用量数字已统一到同一次全量扫描; 原版侧(16084 个文件 / 9984 个块)在整个分析期间保持不变。EFFECTSLIST.DAT自身的 239 行属类型注册、不计入效果块,已排除。关联文档:效果对象本身参见 CEffect 参考手册,词缀容器参见 CAffix 参考手册, 挂载调度参见 CEffectManager 参考手册,状态栏显示参见 CEffectDisplayMgr 参考手册。 本文档不重复那四篇的内容,只负责「239 行本身」这一层。 每个类型实际做什么(走哪条执行路径、
DURATION该怎么填、写错会不会静默失效)见 239 个 TYPE 的行为解释; 每个类型的真实数据样例见 239 个 TYPE 的实例速查。
1. 这张表怎么进内存
加载器是 EffectsList_dat_load_239,起始 0x401000,读取路径硬编码为字符串 "media/EffectsList.dat"(0x401068)。 它把文件解析成一串 [EFFECT] 子节点,然后按行号顺序把 19 个键分别灌进 13 张平行的全局数组。
| DAT 键 | 标签 | 运行期全局 | 地址 | 元素 | 写入点 | 读取点 |
|---|---|---|---|---|---|---|
NAME | <STRING> | g_EffectTypeNames_239 | 0x28A28D8 | wstring×239 | 0x40113A | 0x7AABBD、0x531D74、0x7A4C09、0x7C8FAA |
VALUE1–VALUE5 | <STRING> | g_EffectParamNames_239x5 | 0x28AABA0 | wstring[239][5] | 0x4012F1 起 | 0x7A5F46(CEffect__readValueSlot) |
GRAPH1、GRAPH2 | <STRING> | g_EffectGraphNames_239x5 | 0x28B2E58 | wstring[239][5] | 0x4014AA、0x401503 | 0x7A606E(CEffect__bindGraphs) |
TYPE | <STRING> | g_EffectDisplayKind_239 | 0x28A1D80 | int×239 | 0x401792、0x4017B7 | 0x7A71D4 |
MINVAL | <INTEGER> | g_EffectMinVal_239 | 0x28A2500 | int×239 | 0x4017FD | 无 |
MAXVAL | <INTEGER> | g_EffectMaxVal_239 | 0x28A2140 | int×239 | 0x401857 | 0x7A71FD |
DISPLAYPRECISION | <INTEGER> | dword_28A19C0 | 0x28A19C0 | int×239 | 0x401667 | 0x7A7237、0x7A727B、0x7A7318 |
DISPLAYPRECISIONMAXVAL | <FLOAT> | flt_28A1600 | 0x28A1600 | float×239 | 0x4016B7 | 0x7A7229、0x7A7274、0x7A730E |
AFFIX_MODIFIES | <BOOL> | g_EffectAffixModifies_239 | 0x28A1510 | bool×239 | 0x40170B | 0x7A4247 |
GOODDES | <TRANSLATE> | g_EffectGoodDes_239 | 0x28A4300 | wstring×239 | 0x401193 | 0x7A73BF |
GOODDESOT | <TRANSLATE> | byte_28A5D28 | 0x28A5D28 | wstring×239 | 0x4011EC | 0x7A7394 |
BADDES | <TRANSLATE> | g_EffectBadDes_239 | 0x28A7750 | wstring×239 | 0x401245 | 0x7A73D1 |
BADDESOT | <TRANSLATE> | byte_28A9178 | 0x28A9178 | wstring×239 | 0x40129E | 0x7A73A6 |
EFFECT 键(值形如 KEFFECT_TYPE_MELEEDAMAGEBONUS)在整个加载器里没有对应的写入指令—— 它是给人看的枚举名注记,引擎从不解析。真正决定行为的是行号。
1.1 239 这个数字是怎么把自己锁死的
加载完成后有一道校验(0x40109E):
0040109E cmp [esp+0D4h+var_74], 0EFh ; 0xEF = 239,子节点数量
004010A6 jz short loc_4010E6 ; 正好 239 → 静默通过
004010A8 push offset aTheEffectFileM ; 否则打一条日志日志原文是 The effect file( media/effectslist.dat ) appears to no longer match up with the internal effect list. Please revert this file.
CAUTION
这道校验只写日志,不截断,也不中止加载。 紧接着的填表循环(0x401100–0x40188D)用的上界是 var_74,也就是文件里实际的块数, 而不是常量 239:
0040187D add [esp+0D8h+var_AC], 1Ch ; 描述串行指针 += 28
00401882 inc esi ; 行号
00401883 add ebp, 8Ch ; 槽数组行偏移 += 140
00401889 cmp esi, [esp+0D8h+var_74] ; ← 文件实际块数
0040188D jb loc_401100后果分两种,都不是「多出来的行被忽略」:
- 少于 239 行:
esi到不了的那些行保持空wstring,NAME为空串。 由于[EFFECT]块的TYPE是拿大写化后的值去和NAME逐个比较(见 9.1 节), 空NAME永远匹配不上,这些类型号就此全部失效。 - 多于 239 行:
esi与ebp继续往后走,越界写进紧邻的全局数组。g_EffectParamNames_239x5的基址是0x28AABA0,239 行 × 140 字节 = 33460 字节, 末尾落在0x28B2E54;而g_EffectGraphNames_239x5的基址是0x28B2E58, 两者只隔 4 个字节。第 240 行的VALUE1会直接盖在第 0 行的GRAPH1上。 再往后g_EffectGraphNames_239x5的末尾同样紧邻别的全局对象。
换句话说,这个 239 不是「建议值」,而是一个既不能减也不能加的硬编号空间。 至于为什么连行序都不能动(存档里存的是索引而非名字),见 CEffect §8。
2. 五个数值槽是怎么对上名字的
槽名表的行偏移由 ebp 携带,每行递增 0x8C = 140 = 5 × 28(wstring 在这个二进制里是 28 字节)。 加载器先算出该行的槽 1 地址,再用相对位移填其余四个:
004012F1 lea edi, g_EffectParamNames_slot2[ebp] ; edi = 基址 + 0x1C + 行偏移
004012FD lea ecx, [edi-1Ch] ; VALUE1 → 槽 0
(VALUE2 直接用 edi) ; VALUE2 → 槽 1
004013A8 lea ecx, [edi+1Ch] ; VALUE3 → 槽 2
004013FE lea ecx, [edi+38h] ; VALUE4 → 槽 3
00401454 lea ecx, [edi+54h] ; VALUE5 → 槽 4映射是直白的 VALUEn → 槽 n-1,没有重排。数组总跨度 239 × 140 = 33460 字节,与实测的符号间距一致。 读取侧只有一个函数:CEffect__readValueSlot(0x7A5F46), 它按 CEffect+0x1C(类型号)与槽号取出别名字符串,再拿这个别名去 [EFFECT] 块里查键。
IMPORTANT
[EFFECT] 块里能写哪些数值键,完全由这张表该行的 VALUE1–VALUE5 决定。 比如第 55 行 CRITICAL CHANCE 的槽名是 MIN/MAX/NA/NA/NA, 那么 <FLOAT>MIN: 与 <FLOAT>MAX: 有效,写 <FLOAT>CHANCE: 则不会被任何代码读到。 而第 156 行 DAMAGE CHANCE 的槽 4 恰好叫 CHANCE,同一个键名在那里就是有效的。 键名不是全局约定,是逐类型的。
2.1 NA 的含义
NA 是「这个槽没有别名」的占位写法,在 239 × 5 = 1195 个槽位里占了 676 个。 剩下 519 个槽位上共出现 62 个不同的别名。 下表按使用频次列出全部别名,以及它们各自出现在哪个槽位、哪些行:
| 别名 | 出现槽位 | 行数 | 用在哪些行 |
|---|---|---|---|
MAX | 槽 1 | 202 | 0、1、2、3、4、5、6、7、8、9、10、11、13、14… |
MIN | 槽 0 | 202 | 0、1、2、3、4、5、6、7、8、9、10、11、13、14… |
CHANCE | 槽 0/槽 2/槽 4 | 17 | 157、158、213、214、235、236、144、146、147、148、149、150、151、160… |
MAXFORCE | 槽 3 | 6 | 0、1、7、52、156、237 |
MAXRANGE | 槽 3/槽 4 | 6 | 157、158、235、236、160、161 |
MINFORCE | 槽 2 | 6 | 0、1、7、52、156、237 |
MINRANGE | 槽 2/槽 3 | 6 | 157、158、235、236、160、161 |
COOLDOWN | 槽 4 | 4 | 157、158、235、236 |
RANGE | 槽 1/槽 2 | 3 | 213、231、234 |
COUNT | 槽 0 | 2 | 160、161 |
FORCE | 槽 0 | 2 | 12、43 |
MAXTIME | 槽 1 | 2 | 227、228 |
MAX_COUNT | 槽 3 | 2 | 231、234 |
MAX_PER | 槽 1 | 2 | 231、234 |
MAX_TARGETS | 槽 4 | 2 | 229、230 |
MINTIME | 槽 0 | 2 | 227、228 |
MIN_PER | 槽 0 | 2 | 231、234 |
NO_LOOT | 槽 2/槽 3 | 2 | 67、110 |
PULSE_RATE | 槽 2 | 2 | 229、230 |
RADIUS | 槽 3 | 2 | 229、230 |
RESISTANCE | 槽 0 | 2 | 53、121 |
TIME | 槽 0 | 2 | 223、225 |
VALUE | 槽 2 | 2 | 181、182 |
ANGLE | 槽 2 | 1 | 163 |
CHANCE% | 槽 1 | 1 | 164 |
CHANCE_TO_100 | 槽 0 | 1 | 187 |
DESTROY_BODY | 槽 4 | 1 | 67 |
DESTROY_WEAPONS | 槽 4 | 1 | 163 |
DMGPCT | 槽 2 | 1 | 61 |
DMGPCTMAX | 槽 3 | 1 | 60 |
DMGPCTMIN | 槽 2 | 1 | 60 |
EFFECT_DURATION | 槽 1 | 1 | 223 |
ENDSCALE | 槽 1 | 1 | 59 |
EXPLODE | 槽 2 | 1 | 110 |
GOLD% | 槽 0 | 1 | 164 |
HP% | 槽 0 | 1 | 163 |
HPOVERRIDE | 槽 1 | 1 | 163 |
HPPCT | 槽 1 | 1 | 161 |
IGNORE_RESISTANCE | 槽 2 | 1 | 64 |
INVISIBLE | 槽 0 | 1 | 155 |
MAXSCALE | 槽 0 | 1 | 184 |
MAX_DEPTH | 槽 1 | 1 | 113 |
MAX_PER_HEALTH | 槽 1 | 1 | 229 |
MAX_PER_MANA | 槽 1 | 1 | 230 |
MAX_STOP_AT | 槽 4 | 1 | 185 |
MINSCALE | 槽 1 | 1 | 184 |
MIN_DEPTH | 槽 0 | 1 | 113 |
MIN_PER_HEALTH | 槽 0 | 1 | 229 |
MIN_PER_MANA | 槽 0 | 1 | 230 |
MIN_STOP_AT | 槽 3 | 1 | 185 |
NO_DIE_ANIM | 槽 3 | 1 | 67 |
OFFSET | 槽 3 | 1 | 163 |
PERCENT_TO_100 | 槽 0 | 1 | 186 |
PERCENT_TO_HEAL | 槽 0 | 1 | 185 |
PETINDEX | 槽 0 | 1 | 142 |
POI | 槽 0 | 1 | 162 |
STARTSCALE | 槽 0 | 1 | 59 |
TARGET_SKILL_TARGET | 槽 2 | 1 | 213 |
TIMETOSCALE | 槽 2 | 1 | 59 |
TIMETOSCALEBACK | 槽 3 | 1 | 59 |
TIME_TO_HEAL | 槽 1 | 1 | 185 |
TIME_TO_HEAL_MAX | 槽 2 | 1 | 185 |
MIN/MAX 这一对占了绝对多数(各 202 行的槽 0/槽 1), 这也是「效果数值写成一个区间」成为默认写法的原因——但区间的含义因场景而异: 装备词缀里它是品质插值的两端(见 CAffix), 技能效果里它是随机滚动的两端,而只有在该行注册了默认曲线时才需要 NOGRAPH:true 才能拿到真随机(见下节与 CEffect §6.1)。
3. 曲线槽:表里有五个位置,只有两个填得上
g_EffectGraphNames_239x5(0x28B2E58)与槽名表同构——同样 239 行、同样 0x8C 行距、同样 5 个 28 字节的 wstring。 但加载器只写前两个:
004014AA lea ecx, g_EffectGraphNames_239x5[ebp] ; GRAPH1 → 曲线槽 0
00401503 lea ecx, unk_28B2E74[ebp] ; GRAPH2 → 曲线槽 1(+0x1C)而 EFFECTSLIST.DAT 里根本不存在 GRAPH3/GRAPH4/GRAPH5 这三个键(全表 19 个键,已在第 1 节列全)。
NOTE
这张表的形状说明设计意图曾是「五个数值槽各配一条曲线」, 但落地的数据格式只提供了两个入口,于是每一行的曲线槽 2/3/4 永久为空。 这正是为什么曲线插值只作用于槽 0 与槽 1(也就是绝大多数行的 MIN/MAX), 槽 2–4 上的数值(MINFORCE、CHANCE、RANGE 之类)从不参与曲线求值。
全表 239 行里只有 36 行注册了默认曲线。 另一个实测结论:这 36 行的 GRAPH1 与 GRAPH2 完全相同,无一例外, 所以两列的区分在原版数据里从未体现过。
| # | TYPE 名 | 曲线名 | 原版 | MOD |
|---|---|---|---|---|
| 0 | MELEEDAMAGEBONUS | BASE_WEAPON_DAMAGE | 1 | 51 |
| 1 | RANGEDDAMAGEBONUS | BASE_WEAPON_DAMAGE | 1 | 1 |
| 2 | DEFENSE | ATTRIBUTE_BONUS | 24 | 624 |
| 3 | MAGIC | ATTRIBUTE_BONUS | 24 | 881 |
| 4 | MAX MANA | MANA_PLAYER_GENERIC | 18 | 1139 |
| 5 | MAX HP | HEALTH_PLAYER_GENERIC | 23 | 1657 |
| 7 | HP RECHARGE | HEALTH_MONSTER_BYLEVEL | 34 | 884 |
| 8 | ARMOR BONUS | ARMOR_PLAYER_BYLEVEL_FORSET | 85 | 1730 |
| 10 | DAMAGE BONUS | BASE_WEAPON_DAMAGE | 124 | 3865 |
| 35 | PHYSICAL DEFENSE | ARMOR_PLAYER_BYLEVEL_FORSET | · | 44 |
| 36 | MAGICAL DEFENSE | ARMOR_PLAYER_BYLEVEL_FORSET | · | 50 |
| 37 | FIRE DEFENSE | ARMOR_PLAYER_BYLEVEL_FORSET | 43 | 409 |
| 38 | ICE DEFENSE | ARMOR_PLAYER_BYLEVEL_FORSET | 42 | 417 |
| 39 | ELECTRICAL DEFENSE | ARMOR_PLAYER_BYLEVEL_FORSET | 43 | 435 |
| 40 | POISON DEFENSE | ARMOR_PLAYER_BYLEVEL_FORSET | 38 | 468 |
| 47 | SUMMON DURATION | SUMMONDURATION | 88 | 909 |
| 48 | DAMAGE REFLECTION | BASE_WEAPON_DAMAGE | 40 | 581 |
| 49 | LIFE STEAL | STEAL_HEALTH_AND_MANA | 29 | 721 |
| 50 | MANA STEAL | STEAL_MANA | 23 | 514 |
| 52 | DAMAGE | DAMAGE_MONSTER | 1067 | 18351 |
| 54 | DEGRADE ARMOR | ARMOR_MONSTER_BYLEVEL | 45 | 841 |
| 69 | STRENGTH BONUS | ATTRIBUTE_BONUS | 24 | 657 |
| 70 | DEXTERITY BONUS | ATTRIBUTE_BONUS | 24 | 535 |
| 93 | REDUCED ITEM REQUIREMENTS | ITEM_DEFENSE_REQUIREMENTS | 5 | 41 |
| 122 | SHIELD BUFFER | HEALTH_MONSTER_BYLEVEL | 62 | 1556 |
| 123 | MANA RECHARGE PLAYER | MANA_PLAYER_GENERIC | 87 | 1562 |
| 124 | HP RECHARGE PLAYER | HEALTH_PLAYER_GENERIC | 164 | 2856 |
| 125 | LIFE STEAL MASTER | STEAL_HEALTH_AND_MANA | 7 | 118 |
| 156 | DAMAGE CHANCE | DAMAGE_MONSTER | 16 | 703 |
| 218 | INNATE ICE DEFENSE | ARMOR_PLAYER_BYLEVEL_FORSET | · | 1 |
| 219 | INNATE FIRE DEFENSE | ARMOR_PLAYER_BYLEVEL_FORSET | · | 1 |
| 220 | INNATE ELECTRIC DEFENSE | ARMOR_PLAYER_BYLEVEL_FORSET | · | 1 |
| 221 | INNATE POISON DEFENSE | ARMOR_PLAYER_BYLEVEL_FORSET | · | 1 |
| 229 | DRAW HEALTH | HEALTH_PLAYER_GENERIC | 10 | 208 |
| 230 | DRAW MANA | MANA_PLAYER_GENERIC | 10 | 205 |
| 237 | MINIONDAMAGE | DAMAGE_MONSTER | 9 | 801 |
WARNING
只有上表这 36 行需要靠 <BOOL>NOGRAPH:true 才能让 MIN~MAX 退化成真随机。 其余 203 行没有默认曲线,NOGRAPH 写与不写没有区别。 把这条规律说成「MIN~MAX 随机需要 NOGRAPH」是过度推广。
4. MINVAL 与 MAXVAL:一列是死数据,一列只贡献符号
这两列长期被理解成「数值的合法范围」或「UI 钳位」。逐指令核对的结果是两者都不成立。
按立即数字节扫描 0x401000–0x2200000(不依赖 IDA 的交叉引用,避免漏掉 SIB 寻址形式):
g_EffectMinVal_239(0x28A2500)全程出现 1 次,就是加载器0x4017FD的那次写入。 没有任何读取点。MINVAL是一列纯粹的死数据。g_EffectMaxVal_239(0x28A2140)出现 2 次:写入0x401857,读取0x7A71FD。 而那唯一的读取长这样:
007A71FD fild g_EffectMaxVal_239[ebx*4] ; 整数载入
007A7204 fstp dword ptr [esp+164h+X+4]
007A7207 call ds:?Sign@Math@Ogre@@SAMM@Z ; Ogre::Math::Sign —— 只留符号量级被 Ogre::Math::Sign 丢弃了。 这一列实际编码的是「这个属性往哪个方向变算好事」。
4.1 好/坏描述串的完整选择链
读取点位于 CEffect__build_tooltip_desc(函数起始 0x7A70B0)。两个栈变量控制最终取哪个串:
007A71A9 mov [esp+160h+var_10C], 1 ; var_10C = 1 → 默认「好」
007A71AE mov byte ptr [...var_14A], 0 ; var_14A = 0 → 默认非「持续」措辞
; ── var_14A:是否用 OT(over time)措辞 ──
007A719C fld dword ptr [esi+24h] ; CEffect+0x24 = DURATION
007A719F fld ds:flt_219A6E0 ; = -900.0
007A71B8 jnp loc_7A71D1 ; 相等 → 保持 0
007A71BA fld dword ptr [esi+24h]
007A71BD fld ds:flt_219A6E4 ; = -1000.0
007A71CA jnp loc_7A71D1 ; 相等 → 保持 0
007A71CC mov byte ptr [...var_14A], 1 ; 两个哨兵都不是 → 用 OT 措辞
; ── var_10C:好还是坏 ──
007A71D1 mov ebx, [esi+1Ch] ; 类型号
007A71D4 cmp g_EffectDisplayKind_239[ebx*4], 2
007A71DC jz short loc_7A7226 ; TYPE:None → 整段跳过,保持「好」
007A71E4 fucom st(1) ; 数值 vs 0.0
007A71ED jnp short loc_7A7224 ; 数值为 0 → 跳过,保持「好」
s1 = Sign(数值)
s2 = Sign((float)MAXVAL[类型号])
007A7214 fucompp
007A721B jnp short loc_7A7226 ; 符号相同 → 保持「好」
007A721D mov [esp+160h+var_10C], 0 ; 符号不同 → 改判「坏」(test ah, 44h + jnp 是 MSVC 的浮点相等判定惯用式:fucom 相等时置 C3,ah & 0x44 == 0x40, 奇校验使 PF = 0,于是 jnp 在相等时跳转。)
四路选择在 0x7A7371–0x7A73D8:
var_14A(DURATION 非哨兵) | var_10C | 取用的串 | 取址指令 |
|---|---|---|---|
| 1 | ≠0(好) | GOODDESOT | 0x7A7394 |
| 1 | 0(坏) | BADDESOT | 0x7A73A6 |
| 0 | ≠0(好) | GOODDES | 0x7A73BF |
| 0 | 0(坏) | BADDES | 0x7A73D1 |
索引算法是 ecx = 类型号 * 8 - 类型号(即 ×7)后取 [基址 + ecx*4],等价于 基址 + 类型号 * 28,与 wstring 步长吻合。
NOTE
由此可读出两条非直觉的行为:
- 数值恰好为 0 的效果一律用「好」措辞(
0x7A71ED跳过判定)。 TYPE:None的 14 行一律用「好」措辞(0x7A71DC跳过判定), 与「不显示数值」是同一个分支的副作用。
4.2 MAXVAL 符号为负的行
全表 220 行是标准的 MINVAL:-100 / MAXVAL:100。剩下 19 行如下, 其中 4 行的 MAXVAL 为负——这正是「数值越低越好」的属性,符号翻转后 Sign 判定才正确:
| # | TYPE 名 | MINVAL | MAXVAL | MAXVAL 符号 → 好的方向 |
|---|---|---|---|---|
| 11 | DAMAGE TAKEN | 20 | -20 | 负向为好 |
| 26 | PERCENT DAMAGE TAKEN | 50 | -50 | 负向为好 |
| 45 | OPEN WAYPOINT PORTAL | -1 | 100000 | 正向为好 |
| 48 | DAMAGE REFLECTION | 0 | 100 | 正向为好 |
| 49 | LIFE STEAL | -9999 | 9999 | 正向为好 |
| 52 | DAMAGE | -10000 | 10000 | 正向为好 |
| 53 | PERCENT KNOCK BACK RESISTANCE | 0 | 100 | 正向为好 |
| 59 | SCALE | 0 | 10 | 正向为好 |
| 66 | DEGRADE ARMOR EFFECT | 100 | -100 | 负向为好 |
| 113 | WARP | -1000 | 1000 | 正向为好 |
| 125 | LIFE STEAL MASTER | -9999 | 9999 | 正向为好 |
| 155 | SET MESH INVISIBLE | 0 | 1 | 正向为好 |
| 156 | DAMAGE CHANCE | -10000 | 10000 | 正向为好 |
| 184 | SCALE BY HP | 0 | 10 | 正向为好 |
| 185 | HP MOD OVER TIME | -1000 | 1000 | 正向为好 |
| 186 | TRANSFORMATION TIME | -1000 | 1000 | 正向为好 |
| 187 | TRAP DISARM CHANCE | 0 | 100 | 正向为好 |
| 231 | PERCENT DAMAGE TAKEN BY MONSTER COUNT | 100 | -100 | 负向为好 |
| 237 | MINIONDAMAGE | -10000 | 10000 | 正向为好 |
MINVAL 一列在这 19 行里也出现了与 MAXVAL 倒挂的写法(如第 11 行 MINVAL:20 / MAXVAL:-20), 但既然它没有读取点,这种倒挂纯属数据侧的书写惯例,不产生任何行为。
5. 显示形态与精度
5.1 TYPE 列:只有 None 有意义
加载器把这一列归一化成一个整数(0x401748 起,缺省实参是字面量 "VALUE",随后 toUpperW):
00401792 mov g_EffectDisplayKind_239[esi*4], 1 ; == "PERCENT"
; 否则:
004017AB movzx edx, al ; al = (值 == "NONE")
004017AE neg edx
004017B3 sbb edx, edx ; edx = 相等 ? -1 : 0
004017B5 and edx, ebx ; ebx = 2(0x40104F 处 mov ebx, 2)
004017B7 mov g_EffectDisplayKind_239[esi*4], edx ; NONE → 2,其余 → 0| DAT 写法 | 表值 | 原版行数 |
|---|---|---|
Percent | 1 | 59 |
None | 2 | 14 |
Value、缺省、或任何拼错的值 | 0 | 166 |
WARNING
Percent 与 Value 对引擎完全等价,百分号不是这一列画出来的。 立即数扫描显示 g_EffectDisplayKind_239 全程只有 3 处:两处写入加一处读取, 而那唯一的读取是 cmp …, 2(0x7A71D4)——只判断「是不是 None」,从不区分 0 与 1。
百分号来自 GOODDES 等描述串里写死的字面 %。实测反证两条: 原版有 56 行标着 TYPE:Value、描述里却带 % (第 33、55、56、60、64、68、80、88 行……), 而第 44 行 PERCENT ACTIVE DISTANCE BONUS 标着 Percent,四个描述串却全是 NA。 这一列在原版数据里更接近一份给人看的分类注记。
5.2 精度两列
DISPLAYPRECISION(0x28A19C0,int)与 DISPLAYPRECISIONMAXVAL(0x28A1600,float) 成对传给同一个格式化函数 sub_7A6760,在 build_tooltip_desc 里被调用四次 (0x7A7269、0x7A72C3、0x7A7303,以及 0x7A733F 之后一处), 分别对应「数值」「上限数值」「时长」「区间上界」四个待排版的数字。
DISPLAYPRECISION 全表 222 行为 0,14 行为 1,3 行为 2:
| # | TYPE 名 | DISPLAYPRECISION |
|---|---|---|
| 6 | MANA RECHARGE | 1 |
| 7 | HP RECHARGE | 1 |
| 21 | PERCENT SPEED | 1 |
| 22 | PERCENT ATTACK SPEED | 1 |
| 43 | KNOCK BACK EFFECT | 1 |
| 47 | SUMMON DURATION | 1 |
| 57 | TRANSFORM | 2 |
| 78 | MISSILE RANGE BONUS | 2 |
| 123 | MANA RECHARGE PLAYER | 1 |
| 124 | HP RECHARGE PLAYER | 1 |
| 152 | CAST SKILL ON STRIKE | 1 |
| 168 | ADD CHARGE PERCENT | 2 |
| 196 | IMMOBILIZE | 1 |
| 229 | DRAW HEALTH | 1 |
| 230 | DRAW MANA | 1 |
| 231 | PERCENT DAMAGE TAKEN BY MONSTER COUNT | 1 |
| 234 | PERCENT DAMAGE BONUS BY MONSTER COUNT | 1 |
DISPLAYPRECISIONMAXVAL 的取值只有三种:0(226 行)、19(10 行)、9(3 行)。
6. 完整对照表
列的读法
- # —— 行号,也就是
CEffect+0x1C里存的类型号,以及存档里落盘的那个整数。 TYPE名 ——[EFFECT]块的TYPE键要写的字面值,比较前会被大写化。- 槽 0–4 —— 该行
VALUE1–VALUE5注册的键名;·表示该槽写的是占位值NA,无可用键名。 - 形 ——
g_EffectDisplayKind_239的值:值= 0,%= 1(与 0 等价),无= 2。 - 默认曲线 ——
GRAPH1(该行GRAPH2与之相同)。留空表示无默认曲线,NOGRAPH对该行无意义。 - 特判 —— 引擎里针对该类型号硬编码的分支,代号见第 7 节。
- 原版/MOD ——
[EFFECT]块里TYPE命中该行的次数;·为 0。
| # | TYPE 名 | 槽 0 | 槽 1 | 槽 2 | 槽 3 | 槽 4 | 形 | 默认曲线 | 特判 | 原版 | MOD |
|---|---|---|---|---|---|---|---|---|---|---|---|
| 0 | MELEEDAMAGEBONUS | MIN | MAX | MINFORCE | MAXFORCE | · | 值 | BASE_WEAPON_DAMAGE | 1 | 51 | |
| 1 | RANGEDDAMAGEBONUS | MIN | MAX | MINFORCE | MAXFORCE | · | 值 | BASE_WEAPON_DAMAGE | 1 | 1 | |
| 2 | DEFENSE | MIN | MAX | · | · | · | 值 | ATTRIBUTE_BONUS | M | 24 | 623 |
| 3 | MAGIC | MIN | MAX | · | · | · | 值 | ATTRIBUTE_BONUS | 24 | 880 | |
| 4 | MAX MANA | MIN | MAX | · | · | · | 值 | MANA_PLAYER_GENERIC | 18 | 1139 | |
| 5 | MAX HP | MIN | MAX | · | · | · | 值 | HEALTH_PLAYER_GENERIC | 23 | 1657 | |
| 6 | MANA RECHARGE | MIN | MAX | · | · | · | 值 | F | 24 | 369 | |
| 7 | HP RECHARGE | MIN | MAX | MINFORCE | MAXFORCE | · | 值 | HEALTH_MONSTER_BYLEVEL | F | 34 | 883 |
| 8 | ARMOR BONUS | MIN | MAX | · | · | · | 值 | ARMOR_PLAYER_BYLEVEL_FORSET | 85 | 1730 | |
| 9 | TO HIT BONUS | MIN | MAX | · | · | · | 值 | · | · | ||
| 10 | DAMAGE BONUS | MIN | MAX | · | · | · | 值 | BASE_WEAPON_DAMAGE | 124 | 3865 | |
| 11 | DAMAGE TAKEN | MIN | MAX | · | · | · | 值 | · | 70 | ||
| 12 | KNOCK BACK | FORCE | · | · | · | · | 值 | 106 | 760 | ||
| 13 | SIGHT BONUS | MIN | MAX | · | · | · | 值 | · | 8 | ||
| 14 | VIEW ANGLE BONUS | MIN | MAX | · | · | · | 值 | 1 | · | ||
| 15 | PERCENT MELEEDAMAGE | MIN | MAX | · | · | · | % | 17 | 265 | ||
| 16 | PERCENT RANGEDDAMAGE | MIN | MAX | · | · | · | % | 23 | 246 | ||
| 17 | PERCENT DEFENSE | MIN | MAX | · | · | · | % | M | · | 306 | |
| 18 | PERCENT MAGIC | MIN | MAX | · | · | · | % | · | 136 | ||
| 19 | PERCENT MANA | MIN | MAX | · | · | · | % | 11 | 545 | ||
| 20 | PERCENT HP | MIN | MAX | · | · | · | % | 32 | 1639 | ||
| 21 | PERCENT SPEED | MIN | MAX | · | · | · | % | 260 | 4654 | ||
| 22 | PERCENT ATTACK SPEED | MIN | MAX | · | · | · | % | 303 | 4818 | ||
| 23 | PERCENT ARMOR BONUS | MIN | MAX | · | · | · | % | 89 | 2940 | ||
| 24 | PERCENT TO HIT BONUS | MIN | MAX | · | · | · | % | · | 15 | ||
| 25 | PERCENT DAMAGE BONUS | MIN | MAX | · | · | · | % | 391 | 7179 | ||
| 26 | PERCENT DAMAGE TAKEN | MIN | MAX | · | · | · | % | 389 | 6021 | ||
| 27 | PERCENT MAGICAL DROP | MIN | MAX | · | · | · | % | 43 | 439 | ||
| 28 | PERCENT GOLD DROP | MIN | MAX | · | · | · | % | 37 | 423 | ||
| 29 | PERCENT CAST SPEED | MIN | MAX | · | · | · | % | 156 | 3690 | ||
| 30 | PERCENT LIFE STOLEN | MIN | MAX | · | · | · | % | 7 | 325 | ||
| 31 | PERCENT MANA STOLEN | MIN | MAX | · | · | · | % | 4 | 119 | ||
| 32 | PERCENT DAMAGE REFLECTED | MIN | MAX | · | · | · | % | 31 | 785 | ||
| 33 | PERCENT BLOCK CHANCE | MIN | MAX | · | · | · | 值 | 23 | 299 | ||
| 34 | PERCENT ITEM REQUIREMENTS | MIN | MAX | · | · | · | % | · | · | ||
| 35 | PHYSICAL DEFENSE | MIN | MAX | · | · | · | 值 | ARMOR_PLAYER_BYLEVEL_FORSET | M | · | 44 |
| 36 | MAGICAL DEFENSE | MIN | MAX | · | · | · | 值 | ARMOR_PLAYER_BYLEVEL_FORSET | · | 50 | |
| 37 | FIRE DEFENSE | MIN | MAX | · | · | · | 值 | ARMOR_PLAYER_BYLEVEL_FORSET | M | 43 | 408 |
| 38 | ICE DEFENSE | MIN | MAX | · | · | · | 值 | ARMOR_PLAYER_BYLEVEL_FORSET | M | 42 | 416 |
| 39 | ELECTRICAL DEFENSE | MIN | MAX | · | · | · | 值 | ARMOR_PLAYER_BYLEVEL_FORSET | M | 43 | 434 |
| 40 | POISON DEFENSE | MIN | MAX | · | · | · | 值 | ARMOR_PLAYER_BYLEVEL_FORSET | M | 38 | 467 |
| 41 | PERCENT SIGHT BONUS | MIN | MAX | · | · | · | % | 1 | 26 | ||
| 42 | PERCENT VIEW ANGLE BONUS | MIN | MAX | · | · | · | % | · | · | ||
| 43 | KNOCK BACK EFFECT | FORCE | · | · | · | · | 无 | G | 601 | 5771 | |
| 44 | PERCENT ACTIVE DISTANCE BONUS | MIN | MAX | · | · | · | % | 13 | 61 | ||
| 45 | OPEN WAYPOINT PORTAL | MIN | MAX | · | · | · | 无 | 2 | 2 | ||
| 46 | IDENTIFY | MIN | MAX | · | · | · | 无 | 2 | 2 | ||
| 47 | SUMMON DURATION | MIN | MAX | · | · | · | 值 | SUMMONDURATION | 88 | 907 | |
| 48 | DAMAGE REFLECTION | MIN | MAX | · | · | · | 值 | BASE_WEAPON_DAMAGE | 40 | 580 | |
| 49 | LIFE STEAL | MIN | MAX | · | · | · | 值 | STEAL_HEALTH_AND_MANA | 29 | 716 | |
| 50 | MANA STEAL | MIN | MAX | · | · | · | 值 | STEAL_MANA | 23 | 510 | |
| 51 | GOLD DROP | MIN | MAX | · | · | · | 值 | · | 39 | ||
| 52 | DAMAGE | MIN | MAX | MINFORCE | MAXFORCE | · | 值 | DAMAGE_MONSTER | XA | 1067 | 18348 |
| 53 | PERCENT KNOCK BACK RESISTANCE | RESISTANCE | · | · | · | · | % | 302 | 3058 | ||
| 54 | DEGRADE ARMOR | MIN | MAX | · | · | · | 值 | ARMOR_MONSTER_BYLEVEL | 45 | 840 | |
| 55 | CRITICAL CHANCE | MIN | MAX | · | · | · | 值 | 311 | 3979 | ||
| 56 | INTERRUPT CHANCE | MIN | MAX | · | · | · | 值 | 120 | 1066 | ||
| 57 | TRANSFORM | MIN | MAX | · | · | · | 无 | 37 | 72 | ||
| 58 | UNIT THEME | · | · | · | · | · | 无 | 216 | 3178 | ||
| 59 | SCALE | STARTSCALE | ENDSCALE | TIMETOSCALE | TIMETOSCALEBACK | · | 无 | Q | 21 | 351 | |
| 60 | MISSILE REFLECT | MIN | MAX | DMGPCTMIN | DMGPCTMAX | · | 值 | R | 69 | 1040 | |
| 61 | MISSILE REFLECT VISUAL | MIN | MAX | DMGPCT | · | · | 值 | · | 8 | ||
| 62 | PERCENT BLOCK CHANCE BASE | MIN | MAX | · | · | · | % | S | 45 | 437 | |
| 63 | VELOCITY MULT | MIN | MAX | · | · | · | 值 | · | · | ||
| 64 | STUN | MIN | MAX | IGNORE_RESISTANCE | · | · | 值 | 225 | 3319 | ||
| 65 | LEARN SKILL | MIN | MAX | · | · | · | 无 | 197 | 893 | ||
| 66 | DEGRADE ARMOR EFFECT | MIN | MAX | · | · | · | 值 | 12 | 74 | ||
| 67 | DESUMMON MONSTER | MIN | MAX | NO_LOOT | NO_DIE_ANIM | DESTROY_BODY | 无 | 271 | 2426 | ||
| 68 | XP GAIN BONUS | MIN | MAX | · | · | · | 值 | 19 | 254 | ||
| 69 | STRENGTH BONUS | MIN | MAX | · | · | · | 值 | ATTRIBUTE_BONUS | 24 | 656 | |
| 70 | DEXTERITY BONUS | MIN | MAX | · | · | · | 值 | ATTRIBUTE_BONUS | 24 | 534 | |
| 71 | PERCENT STRENGTH BONUS | MIN | MAX | · | · | · | % | · | 221 | ||
| 72 | PERCENT DEXTERITY BONUS | MIN | MAX | · | · | · | % | · | 149 | ||
| 73 | TRANSFORM PERMANENT | MIN | MAX | · | · | · | 值 | 16 | 63 | ||
| 74 | CAST SKILL | MIN | MAX | · | · | · | % | 25 | 810 | ||
| 75 | CAST SKILL ON TARGET | MIN | MAX | · | · | · | % | · | 49 | ||
| 76 | CAST SKILL AT TARGET | MIN | MAX | · | · | · | % | · | 11 | ||
| 77 | FAME GAIN BONUS | MIN | MAX | · | · | · | % | 1 | 69 | ||
| 78 | MISSILE RANGE BONUS | MIN | MAX | · | · | · | 值 | 17 | 174 | ||
| 79 | FLEE EFFECT | MIN | MAX | · | · | · | % | 88 | 1017 | ||
| 80 | TURN ALIGNMENT | MIN | MAX | · | · | · | 值 | 27 | 542 | ||
| 81 | CAST SKILL ON STRUCK | MIN | MAX | · | · | · | % | 52 | 1242 | ||
| 82 | SKILL BONUS | MIN | MAX | · | · | · | 值 | 7 | 215 | ||
| 83 | PRICE REDUCTION | MIN | MAX | · | · | · | % | 6 | 58 | ||
| 84 | FISHING LUCK | MIN | MAX | · | · | · | % | 5 | 45 | ||
| 85 | ATTACK SPELL BONUS | MIN | MAX | · | · | · | 值 | 1 | 6 | ||
| 86 | DEFENSE SPELL BONUS | MIN | MAX | · | · | · | 值 | M | 1 | 4 | |
| 87 | CHARM SPELL BONUS | MIN | MAX | · | · | · | 值 | 1 | 4 | ||
| 88 | DUAL WIELDING BONUS | MIN | MAX | · | · | · | 值 | 23 | 294 | ||
| 89 | PERCENT CRITICAL DAMAGE | MIN | MAX | · | · | · | 值 | 20 | 1444 | ||
| 90 | POTION EFFICIENCY | MIN | MAX | · | · | · | 值 | 15 | 212 | ||
| 91 | PERCENT PET DAMAGE | MIN | MAX | · | · | · | 值 | 19 | 422 | ||
| 92 | PERCENT PET VELOCITY | MIN | MAX | · | · | · | 值 | 5 | 87 | ||
| 93 | REDUCED ITEM REQUIREMENTS | MIN | MAX | · | · | · | 值 | ITEM_DEFENSE_REQUIREMENTS | 5 | 41 | |
| 94 | ARMOR ITEM REQUIREMENTS | MIN | MAX | · | · | · | 值 | 1 | 28 | ||
| 95 | SPELL REQUIREMENTS | MIN | MAX | · | · | · | 值 | · | 2 | ||
| 96 | PET DEPARTURE TIME | MIN | MAX | · | · | · | 值 | 3 | 38 | ||
| 97 | PERCENT PET ARMOR | MIN | MAX | · | · | · | 值 | 14 | 221 | ||
| 98 | MARTIAL ITEM REQUIREMENTS | MIN | MAX | · | · | · | 值 | 1 | 59 | ||
| 99 | PERCENT MARTIAL ITEM DAMAGE BONUS | MIN | MAX | · | · | · | 值 | 1 | 78 | ||
| 100 | RANGED ITEM REQUIREMENTS | MIN | MAX | · | · | · | 值 | 1 | 20 | ||
| 101 | MAGIC ITEM REQUIREMENTS | MIN | MAX | · | · | · | 值 | 1 | 8 | ||
| 102 | PERCENT RANGED ITEM DAMAGE BONUS | MIN | MAX | · | · | · | 值 | 1 | 102 | ||
| 103 | PERCENT MAGIC ITEM DAMAGE BONUS | MIN | MAX | · | · | · | 值 | 7 | 90 | ||
| 104 | PERCENT PET HEALTH | MIN | MAX | · | · | · | 值 | 10 | 224 | ||
| 105 | CAST SKILL ON DEATH | MIN | MAX | · | · | · | 值 | 112 | 529 | ||
| 106 | FREEZE | MIN | MAX | · | · | · | 值 | 142 | 1151 | ||
| 107 | BURN | MIN | MAX | · | · | · | 值 | 82 | 1144 | ||
| 108 | POISON | MIN | MAX | · | · | · | 值 | 63 | 914 | ||
| 109 | SHOCK | MIN | MAX | · | · | · | 值 | 62 | 901 | ||
| 110 | KILL | MIN | MAX | EXPLODE | NO_LOOT | · | 值 | 91 | 1279 | ||
| 111 | FADE OUT | MIN | MAX | · | · | · | 值 | 10 | 444 | ||
| 112 | SET VISIBLE | MIN | MAX | · | · | · | 值 | 18 | 60 | ||
| 113 | WARP | MIN_DEPTH | MAX_DEPTH | · | · | · | 无 | 21 | 18 | ||
| 114 | PERMANENT STRENGTH | MIN | MAX | · | · | · | 值 | 2 | 6 | ||
| 115 | PERMANENT DEXTERITY | MIN | MAX | · | · | · | 值 | 2 | 6 | ||
| 116 | PERMANENT MAGIC | MIN | MAX | · | · | · | 值 | 2 | 6 | ||
| 117 | PERMANENT HEALTH | MIN | MAX | · | · | · | 值 | 1 | 7 | ||
| 118 | PERMANENT DEFENSE | MIN | MAX | · | · | · | 值 | M | 3 | 7 | |
| 119 | PERMANENT MANA | MIN | MAX | · | · | · | 值 | · | 2 | ||
| 120 | AWARD STATPOINT | MIN | MAX | · | · | · | 值 | · | 8 | ||
| 121 | FLEE RESIST | RESISTANCE | · | · | · | · | 值 | 60 | 295 | ||
| 122 | SHIELD BUFFER | MIN | MAX | · | · | · | 值 | HEALTH_MONSTER_BYLEVEL | 62 | 1543 | |
| 123 | MANA RECHARGE PLAYER | MIN | MAX | · | · | · | 值 | MANA_PLAYER_GENERIC | F | 87 | 1560 |
| 124 | HP RECHARGE PLAYER | MIN | MAX | · | · | · | 值 | HEALTH_PLAYER_GENERIC | F | 164 | 2837 |
| 125 | LIFE STEAL MASTER | MIN | MAX | · | · | · | 值 | STEAL_HEALTH_AND_MANA | 7 | 118 | |
| 126 | PERCENT LIFE STOLEN MASTER | MIN | MAX | · | · | · | % | 4 | 48 | ||
| 127 | STOP SKILL | MIN | MAX | · | · | · | 值 | 67 | 1867 | ||
| 128 | SILENCE | MIN | MAX | · | · | · | 值 | 35 | 653 | ||
| 129 | DESUMMON ON DEATH | MIN | MAX | · | · | · | 值 | 29 | 602 | ||
| 130 | EMOTIONAL DAMAGE | MIN | MAX | · | · | · | 值 | · | · | ||
| 131 | FUTURISTICNESS | MIN | MAX | · | · | · | 值 | · | 21 | ||
| 132 | JAUNTINESS | MIN | MAX | · | · | · | 值 | · | · | ||
| 133 | SOCKS | MIN | MAX | · | · | · | 值 | · | · | ||
| 134 | LOGIC RESISTANCE | MIN | MAX | · | · | · | 值 | · | · | ||
| 135 | NOODLE ARMS | MIN | MAX | · | · | · | 值 | 1 | · | ||
| 136 | INTERRUPT RESISTANCE | MIN | MAX | · | · | · | 值 | 130 | 1105 | ||
| 137 | CHARM RESISTANCE | MIN | MAX | · | · | · | 值 | 41 | 459 | ||
| 138 | SILENCE_RESISTANCE | MIN | MAX | · | · | · | 值 | 3 | 88 | ||
| 139 | STUN RESISTANCE | MIN | MAX | · | · | · | 值 | 10 | 497 | ||
| 140 | SLOW RESISTANCE | MIN | MAX | · | · | · | 值 | 32 | 831 | ||
| 141 | OPEN PORTAL | MIN | MAX | · | · | · | 无 | 7 | 21876 | ||
| 142 | SWAP POS WITH PET | PETINDEX | · | · | · | · | 无 | 1 | 1 | ||
| 143 | RESPEC | MIN | MAX | · | · | · | 值 | 1 | 2 | ||
| 144 | PERCENT BLIND | MIN | MAX | CHANCE | · | · | 值 | 40 | 267 | ||
| 145 | EXPLODE DEAD | MIN | MAX | · | · | · | 值 | 47 | 596 | ||
| 146 | ADD STAT | MIN | MAX | CHANCE | · | · | 值 | 278 | 5307 | ||
| 147 | ADD STAT TO LEVEL | MIN | MAX | CHANCE | · | · | 值 | · | · | ||
| 148 | SET STAT | MIN | MAX | CHANCE | · | · | 值 | 8 | 3088 | ||
| 149 | SET STAT ON LEVEL | MIN | MAX | CHANCE | · | · | 值 | · | · | ||
| 150 | CLEAR STAT | MIN | MAX | CHANCE | · | · | 值 | 28 | 1418 | ||
| 151 | CLEAR STAT ON LEVEL | MIN | MAX | CHANCE | · | · | 值 | · | · | ||
| 152 | CAST SKILL ON STRIKE | MIN | MAX | · | · | · | % | 26 | 1913 | ||
| 153 | PERCENT DUAL WIELDING ATTACK | MIN | MAX | · | · | · | % | 22 | 273 | ||
| 154 | DAMAGE BONUS SECONDARY | MIN | MAX | · | · | · | 值 | 23 | 275 | ||
| 155 | SET MESH INVISIBLE | INVISIBLE | · | · | · | · | 值 | 5 | 83 | ||
| 156 | DAMAGE CHANCE | MIN | MAX | MINFORCE | MAXFORCE | CHANCE | 值 | DAMAGE_MONSTER | X | 16 | 703 |
| 157 | TELEPORT RANDOM | CHANCE | · | MINRANGE | MAXRANGE | COOLDOWN | 值 | 11 | 198 | ||
| 158 | TELEPORT | CHANCE | · | MINRANGE | MAXRANGE | COOLDOWN | 值 | 6 | 8 | ||
| 159 | TELEPORT RESISTANCE | MIN | MAX | · | · | · | 值 | 4 | 39 | ||
| 160 | SPAWN UNIT | COUNT | · | CHANCE | MINRANGE | MAXRANGE | 值 | · | · | ||
| 161 | SPAWN UNIT ON DEATH | COUNT | HPPCT | CHANCE | MINRANGE | MAXRANGE | 值 | A | 1 | 110 | |
| 162 | WARP TO POI | POI | · | · | · | · | 无 | 2 | 2 | ||
| 163 | DESTRUCTABLE SHIELD | HP% | HPOVERRIDE | ANGLE | OFFSET | DESTROY_WEAPONS | 值 | Q | 32 | 175 | |
| 164 | DISENCHANT | GOLD% | CHANCE% | · | · | · | 无 | 1 | 5 | ||
| 165 | ADD TRIGGERABLE | · | · | CHANCE | · | · | 值 | 271 | 3273 | ||
| 166 | REMOVE TRIGGERABLE | MIN | MAX | · | · | · | 值 | E | 84 | 2345 | |
| 167 | INTERRUPT | MIN | MAX | · | · | · | 值 | 17 | 164 | ||
| 168 | ADD CHARGE PERCENT | MIN | MAX | · | · | · | 值 | 81 | 1390 | ||
| 169 | SET CHARGE PERCENT | MIN | MAX | · | · | · | 值 | 17 | 80 | ||
| 170 | MAX CHARGES | MIN | MAX | · | · | · | 值 | · | 1 | ||
| 171 | ADD CHARGES | MIN | MAX | · | · | · | 值 | 110 | 2525 | ||
| 172 | PERCENT CHARGE BAR DECAY RATE | MIN | MAX | · | · | · | 值 | 13 | 161 | ||
| 173 | CHARGE BAR DECAY DELAY | MIN | MAX | · | · | · | 值 | 1 | 7 | ||
| 174 | PERCENT CHARGING BONUS | MIN | MAX | · | · | · | 值 | 40 | 614 | ||
| 175 | PERCENT MANA COST BONUS | MIN | MAX | · | · | · | 值 | 3 | 399 | ||
| 176 | CHARGE BAR DECAY RATE | MIN | MAX | · | · | · | 值 | · | 7 | ||
| 177 | EXPLODE ON DEATH | MIN | MAX | · | · | · | 值 | 77 | 551 | ||
| 178 | DODGE CHANCE BONUS | MIN | MAX | · | · | · | 值 | 40 | 783 | ||
| 179 | FUMBLE CHANCE REDUCTION | MIN | MAX | · | · | · | 值 | 18 | 311 | ||
| 180 | FUMBLE PENALTY REDUCTION | MIN | MAX | · | · | · | 值 | 1 | 30 | ||
| 181 | CONVERT CHARGE TO STAT | · | · | VALUE | · | · | 值 | 30 | 314 | ||
| 182 | CONVERT CHARGE PERCENT TO STAT | · | · | VALUE | · | · | 值 | · | 6 | ||
| 183 | CAST SKILL ON DEATH FROM EFFECT OWNER | MIN | MAX | · | · | · | % | 41 | 836 | ||
| 184 | SCALE BY HP | MAXSCALE | MINSCALE | · | · | · | 值 | 6 | 20 | ||
| 185 | HP MOD OVER TIME | PERCENT_TO_HEAL | TIME_TO_HEAL | TIME_TO_HEAL_MAX | MIN_STOP_AT | MAX_STOP_AT | 值 | A | 34 | 11434 | |
| 186 | TRANSFORMATION TIME | PERCENT_TO_100 | · | · | · | · | 值 | · | · | ||
| 187 | TRAP DISARM CHANCE | CHANCE_TO_100 | · | · | · | · | 值 | · | · | ||
| 188 | ELEMENTAL EFFECT DURATION BONUS | MIN | MAX | · | · | · | 值 | 4 | 71 | ||
| 189 | BURN DURATION BONUS | MIN | MAX | · | · | · | 值 | · | 57 | ||
| 190 | FREEZE DURATION BONUS | MIN | MAX | · | · | · | 值 | · | 40 | ||
| 191 | SHOCK DURATION BONUS | MIN | MAX | · | · | · | 值 | · | 18 | ||
| 192 | POISON DURATION BONUS | MIN | MAX | · | · | · | 值 | · | 42 | ||
| 193 | NONE | · | · | · | · | · | 无 | 19 | 275 | ||
| 194 | CAST SKILL ON RANGED STRIKE | MIN | MAX | · | · | · | % | 15 | 55 | ||
| 195 | CAST SKILL ON MELEE STRIKE | MIN | MAX | · | · | · | % | · | 85 | ||
| 196 | IMMOBILIZE | MIN | MAX | · | · | · | 值 | 117 | 1473 | ||
| 197 | IMMOBILIZE RESISTANCE | MIN | MAX | · | · | · | 值 | 20 | 605 | ||
| 198 | CAST SKILL FROM TARGET | MIN | MAX | · | · | · | % | · | 75 | ||
| 199 | CAST SKILL ON MELEE STRIKE FROM TARGET | MIN | MAX | · | · | · | % | 2 | 90 | ||
| 200 | CAST SKILL ON RANGED STRIKE FROM TARGET | MIN | MAX | · | · | · | % | · | 18 | ||
| 201 | CAST SKILL ON STRIKE FROM TARGET | MIN | MAX | · | · | · | % | 52 | 1167 | ||
| 202 | BLIND | MIN | MAX | · | · | · | % | 8 | 614 | ||
| 203 | CAST SKILL ON KILL | MIN | MAX | · | · | · | % | 11 | 177 | ||
| 204 | CAST SKILL ON KILL AT TARGET | MIN | MAX | · | · | · | % | 20 | 275 | ||
| 205 | SHIELD BREAK | MIN | MAX | · | · | · | % | 15 | 456 | ||
| 206 | CAST SKILL ON MELEE SKILL STRIKE | MIN | MAX | · | · | · | % | · | 2 | ||
| 207 | CAST SKILL ON MELEE SKILL STRIKE FROM TARGET | MIN | MAX | · | · | · | % | 1 | 18 | ||
| 208 | CAST SKILL ON RANGED SKILL STRIKE | MIN | MAX | · | · | · | % | · | · | ||
| 209 | CAST SKILL ON RANGED SKILL STRIKE FROM TARGET | MIN | MAX | · | · | · | % | · | 3 | ||
| 210 | CAST SKILL ON SKILL STRIKE | MIN | MAX | · | · | · | % | · | 451 | ||
| 211 | CAST SKILL ON SKILL STRIKE FROM TARGET | MIN | MAX | · | · | · | % | · | 62 | ||
| 212 | TARGET LOCKED | · | · | · | · | · | 值 | 1 | 17 | ||
| 213 | RETARGET | CHANCE | RANGE | TARGET_SKILL_TARGET | · | · | 值 | 1 | 6 | ||
| 214 | AGRO | CHANCE | · | · | · | · | 值 | 1 | 50 | ||
| 215 | SHIELD BREAK EFFECT | MIN | MAX | · | · | · | % | 50 | 821 | ||
| 216 | MODIFY SKILL COOLDOWN REMAINING | MIN | MAX | · | · | · | 值 | · | 103 | ||
| 217 | SET SKILL COOLDOWN REMAINING | MIN | MAX | · | · | · | 值 | 5 | 318 | ||
| 218 | INNATE ICE DEFENSE | MIN | MAX | · | · | · | 值 | ARMOR_PLAYER_BYLEVEL_FORSET | · | 1 | |
| 219 | INNATE FIRE DEFENSE | MIN | MAX | · | · | · | 值 | ARMOR_PLAYER_BYLEVEL_FORSET | · | 1 | |
| 220 | INNATE ELECTRIC DEFENSE | MIN | MAX | · | · | · | 值 | ARMOR_PLAYER_BYLEVEL_FORSET | · | 1 | |
| 221 | INNATE POISON DEFENSE | MIN | MAX | · | · | · | 值 | ARMOR_PLAYER_BYLEVEL_FORSET | · | 1 | |
| 222 | SET SKILL LEVEL | MIN | MAX | · | · | · | 值 | 69 | 2306 | ||
| 223 | PULL | TIME | EFFECT_DURATION | · | · | · | 值 | 11 | 304 | ||
| 224 | PULL RESISTANCE | MIN | MAX | · | · | · | % | 45 | 819 | ||
| 225 | PULL EFFECT | TIME | · | · | · | · | 值 | · | 10 | ||
| 226 | MISS CHANCE | MIN | MAX | · | · | · | % | 2 | 177 | ||
| 227 | SKILL ENABLE | MINTIME | MAXTIME | · | · | · | 值 | 10 | 11 | ||
| 228 | SKILL DISABLE | MINTIME | MAXTIME | · | · | · | 值 | 7 | 3 | ||
| 229 | DRAW HEALTH | MIN_PER_HEALTH | MAX_PER_HEALTH | PULSE_RATE | RADIUS | MAX_TARGETS | 值 | HEALTH_PLAYER_GENERIC | 10 | 208 | |
| 230 | DRAW MANA | MIN_PER_MANA | MAX_PER_MANA | PULSE_RATE | RADIUS | MAX_TARGETS | 值 | MANA_PLAYER_GENERIC | 10 | 205 | |
| 231 | PERCENT DAMAGE TAKEN BY MONSTER COUNT | MIN_PER | MAX_PER | RANGE | MAX_COUNT | · | % | N | 31 | 379 | |
| 232 | REMOVE EFFECT | MIN | MAX | · | · | · | 值 | 8 | 306 | ||
| 233 | BLIND RESISTANCE | MIN | MAX | · | · | · | 值 | 3 | 452 | ||
| 234 | PERCENT DAMAGE BONUS BY MONSTER COUNT | MIN_PER | MAX_PER | RANGE | MAX_COUNT | · | % | N | 15 | 338 | |
| 235 | TELEPORT NOPARTICLE | CHANCE | · | MINRANGE | MAXRANGE | COOLDOWN | 值 | 1 | 49 | ||
| 236 | TELEPORT RANDOM NOPARTICLE | CHANCE | · | MINRANGE | MAXRANGE | COOLDOWN | 值 | · | 45 | ||
| 237 | MINIONDAMAGE | MIN | MAX | MINFORCE | MAXFORCE | · | 值 | DAMAGE_MONSTER | A | 9 | 801 |
| 238 | CHEATED | MIN | MAX | · | · | · | 值 | · | · |
7. 引擎里按类型号硬编码的分支
上表「特判」列的代号在此展开。这些判定不看数据,只看类型号,改 EFFECTSLIST.DAT 无法迁移它们。
| 代号 | 类型号 | 位置 | 行为 |
|---|---|---|---|
X | 52、156 | CEffect__ctorFromDat | 构造时自动预置 EXCLUSIVE,无需在 dat 里写 |
M | 2、17、35、37–40、86、118 | 0x7AABEF 的跳转表(落点 0x7AAC0A) | 强制 DAMAGE_TYPE 为魔法系 |
F | 6、7、123、124 | 数值换算路径 | 每帧量按 值 × DURATION × 0.016 折算 |
A | 52、161、185、237 | 0x7A4247 | 该行 AFFIX_MODIFIES:false,词缀品质插值跳过 |
Q | 59、163 | 0x7A4250、0x7A4255 | 词缀品质插值的硬编码排除(与 A 是两套机制) |
N | 231、234 | 去重路径 | 合并同类项时清空 NAME |
G | 43 | UI 分组扫描 | 跳过分组,见 CEffectDisplayMgr |
R | 60 | accumMissileReflect | 单独累加通道 |
S | 62 | removeEffectsBySourceGuid | 按来源批量移除时被跳过 |
E | 166 | expireEffects | 过期处理特判 |
7.1 品质插值的完整门禁
CAffix__applyQualityPercentToEffects 里,一个效果要想被品质插值改写数值,得连过五道:
007A4217 fld dword ptr [ecx+0DCh] ; MIN
007A421D fcomp dword ptr [ecx+0E0h] ; vs MAX
007A4228 jnp loc_7A42AE ; ① MIN == MAX → 无区间,跳过
007A422E xor eax, eax
007A4230 lea edx, [ecx+0F0h]
007A4236 cmp dword ptr [edx], 0
007A4239 jnz short loc_7A42AE ; ② 五个槽任一被显式写过 → 跳过
007A423F cmp eax, 5
007A4242 jb short loc_7A4236
007A4244 mov eax, [ecx+1Ch] ; 类型号
007A4247 cmp g_EffectAffixModifies_239[eax], 0
007A424E jz short loc_7A42AE ; ③ AFFIX_MODIFIES:false → 跳过
007A4250 cmp eax, 3Bh
007A4253 jz short loc_7A42AE ; ④ 59 SCALE → 跳过
007A4255 cmp eax, 0A3h
007A425A jz short loc_7A42AE ; ⑤ 163 DESTRUCTABLE SHIELD → 跳过
; 通过:值 = MIN + (MAX - MIN) × 品质百分比
007A4290 call CEffect__setSlotAndReroll第③道走数据(AFFIX_MODIFIES 列,共 4 行为 false),第④⑤道是写死的两个类型号。 所以一共 6 个类型的词缀数值不做品质插值,但成因分属两套机制,改数据只能影响其中 4 个。
8. 从未被使用的 16 行
原版用到 185/239 个类型,MOD 库用到 222/239,并集 223/239。 两边用量都为 0 的有 16 行:
| # | TYPE 名 | 形 | 默认曲线 | 描述串 |
|---|---|---|---|---|
| 9 | TO HIT BONUS | 值 | — | 四条全空 |
| 34 | PERCENT ITEM REQUIREMENTS | % | — | 四条齐全 |
| 42 | PERCENT VIEW ANGLE BONUS | % | — | 四条齐全 |
| 63 | VELOCITY MULT | 值 | — | 四条全空 |
| 130 | EMOTIONAL DAMAGE | 值 | — | 四条齐全 |
| 132 | JAUNTINESS | 值 | — | 四条齐全 |
| 133 | SOCKS | 值 | — | 四条齐全 |
| 134 | LOGIC RESISTANCE | 值 | — | 四条齐全 |
| 147 | ADD STAT TO LEVEL | 值 | — | 四条全空 |
| 149 | SET STAT ON LEVEL | 值 | — | 四条全空 |
| 151 | CLEAR STAT ON LEVEL | 值 | — | 四条全空 |
| 160 | SPAWN UNIT | 值 | — | 缺 BADDES、BADDESOT |
| 186 | TRANSFORMATION TIME | 值 | — | 四条齐全 |
| 187 | TRAP DISARM CHANCE | 值 | — | 四条齐全 |
| 208 | CAST SKILL ON RANGED SKILL STRIKE | % | — | 四条齐全 |
| 238 | CHEATED | 值 | — | 四条齐全 |
其中 JAUNTINESS(轻快)、SOCKS(袜子)、LOGIC RESISTANCE(逻辑抗性)、EMOTIONAL DAMAGE(情感伤害)、CHEATED 明显是开发期的占位或玩笑行;TO HIT BONUS、PERCENT ITEM REQUIREMENTS、SPAWN UNIT 一类 则是有名有实、只是最终没进正式数据的功能。
NOTE
「从未使用」不等于「不可用」。这 16 行同样占着有效的类型号, NAME 也已进表,MOD 直接写它们的名字是能匹配上的。 但没有原版数据可参照,各槽的实际语义只能从引擎侧反推,风险自担。
9. 排错
9.1 TYPE 拼错会怎样:静默降级为第 193 行
匹配循环在 CEffect__ctorFromDat(函数起始 0x7AAA30):
007AAB9E call toUpperW ; dat 里的值先大写化
007AABBB xor ebx, ebx ; 候选行号 = 0
007AABBD mov ebp, offset g_EffectTypeNames_239
007AABC2 ...
007AABCB call std::operator==<wchar_t> ; 逐行比较
007AABD6 jnz short loc_7AABE9 ; 命中
007AABD8 add edi, 1Ch ; 下一行(wstring 步长 28)
007AABDB inc ebx
007AABDC add ebp, 1Ch
007AABDF cmp edi, 1A24h ; 0x1A24 = 239 × 28
007AABE5 jb short loc_7AABC2
007AABE7 jmp short loc_7AABEC ; ← 全表未命中:直接跳过赋值
007AABE9 mov [esi+1Ch], ebx ; 命中才写类型号
007AABEC mov eax, [esi+1Ch] ; 无论如何都要读它未命中时 [esi+0x1C] 保持构造初值,而初值在同一函数开头就已定下:
007AAA7E mov dword ptr [esi+1Ch], 0C1h ; 0xC1 = 193第 193 行是 NONE——TYPE:None、四个描述串全空、槽名全为 NA 的空操作行。
IMPORTANT
TYPE 写错不会报错、不会崩溃、也不会退化成第 0 行 MELEEDAMAGEBONUS, 而是静默变成第 193 行 NONE,即一个什么都不做、什么都不显示的空效果。
这是个体面的设计(比落到第 0 行白送近战伤害好得多),但对调试极不友好: 效果块语法完全合法、加载无声无息、游戏里就是不生效。
另需注意:NAME 列进表时没有做大写归一(0x40113A 直接赋值,无 toUpperW), 而 dat 侧的 TYPE 值是大写化之后才比较的。 所以如果有人把 EFFECTSLIST.DAT 某行的 NAME 改成含小写字母的写法,那一行会就此永久失配。 原版 239 行的 NAME 全为大写、无空值、无重名,实测确认。
9.2 MOD 库里实测到的失效 TYPE
在 MOD 库的 200352 个效果块中,有 206 个块的 TYPE 对不上任何一行, 涉及 20 个不同的错误值。它们全部静默降级为 NONE:
| 出现次数 | 写成了 | 大概想写的 |
|---|---|---|
| 66 | CAST SKILL ON KILL AT TARGE | CAST SKILL ON KILL AT TARGET(尾字母被截) |
| 49 | PERCENT DAMAGE | PERCENT DAMAGE BONUS 或 PERCENT DAMAGE TAKEN |
| 30 | PERCENT DEGRADE ARMOR | 无此行;应为 DEGRADE ARMOR 或 DEGRADE ARMOR EFFECT |
| 28 | PHYSICAL | PHYSICAL DEFENSE |
| 8 | POISONED | POISON DEFENSE 一类 |
| 3 | DEXTERITY | DEXTERITY BONUS |
| 2 | MAGIC BONUS | MAGIC |
| 2 | CAST SKILL ON STRIKE ON STRIKE | CAST SKILL ON STRIKE(复制粘贴重复) |
| 2 | SUMMONIU DURATION | SUMMON DURATION |
| 2 | DESUMMONIU MONSTER | DESUMMON MONSTER |
| 2 | BLIND RESISTANC | BLIND RESISTANCE |
| 2 | AST SKILL ON RANGED STRIKE | CAST SKILL ON RANGED STRIKE(首字母被吞) |
| 2 | VITALITY BONUS | 无此行 |
| 2 | (空串) | —— |
| 1 | POSION DEFENSE | POISON DEFENSE |
| 1 | ELECTRIC DEFENSE | ELECTRICAL DEFENSE |
| 1 | CAST SKILL AFTER TIME | 无此行 |
| 1 | CUSTOM TEXT | 无此行 |
| 1 | STRENGTH | STRENGTH BONUS |
| 1 | ATTACK SPEED | PERCENT ATTACK SPEED |
SUMMONIU 与 DESUMMONIU 这两个错法值得单说:它们是把 MON 误替换成 IU 的批量查找替换事故, 两处成对出现,说明出自同一次操作。
NOTE
原版数据里也有一处同类问题:CAST SKILL AFTER TIME 在原版出现 1 次,同样对不上任何行。 这份 20 项清单可以直接当拼写检查表用——写完效果块,把 TYPE 的值拿去和第 6 节的对照表核一遍, 比在游戏里找一个「加载成功但毫无反应」的效果快得多。
9.3 其他常见误判
「我在 [EFFECT] 里写了 CHANCE,但没生效。」 查第 6 节该行的槽 0–4。CHANCE 只在 17 行上注册过,其余行写它等于写注释。
「NOGRAPH:true 加了,MIN~MAX 还是不随机。」 只有第 3 节那 36 行有默认曲线,NOGRAPH 对它们之外的 203 行无作用; 数值不随机是别的原因(词缀场景下是品质插值,见 7.1 节)。
「改了 MINVAL/MAXVAL,游戏里数值没被限制住。」MINVAL 没有读取点,MAXVAL 只贡献符号。这两列限制不了任何东西(第 4 节)。 真想限制数值范围,得在写数据时自己控制。
「把某行的 TYPE 列从 Value 改成 Percent,显示没变。」 这两个值对引擎等价(5.1 节)。百分号在 GOODDES 等描述串里。
「往 EFFECTSLIST.DAT 末尾加了一行新类型。」 文件块数不再等于 239,加载器会打一条日志然后继续越界写(1.1 节)。 这不是「新类型不可用」,是内存损坏。
10. 速查
| 想知道 | 看哪 |
|---|---|
| 某类型能写哪些数值键 | 第 6 节该行的槽 0–4 |
某类型需不需要 NOGRAPH | 第 3 节的 36 行清单 |
| 某类型的 tooltip 为什么显示「坏」措辞 | 4.1 节的四路选择表 |
| 某类型是否被硬编码特判 | 第 6 节「特判」列 + 第 7 节 |
| 效果加载成功但毫无反应 | 9.1 节(静默降级为 NONE)+ 9.2 节的错误值清单 |
| 为什么行序和行数都不能动 | 1.1 节 + CEffect §8 |