本组文档:计算公式 · 110 项字段表 · IDA 交叉核查 · 移植状态与缺口 · 玩家属性与加点

结论

旧资料有实质帮助,足够把主要公式与上游数据来源继续闭合,目前不必为这些公式立即 attach 游戏。 动态验证应放到后续原版/Godot 同状态验收,或专门复核罕见分支,而不是重新从头追整条伤害链。

原始取证批次只读取 D:\WizardProject\TL2\tl2-wiki\docs 和原版 IDA,新增取证报告、 参考算例与测试,当时未修改旧 Wiki、Godot/CoreSim 运行时、原版 DLL/PAK 或存档。 本次同步已将下文确认的参数、伤害入口和库存缓存纠错更新到对应 Wiki 页面; 后续运行时实现另见移植状态与缺口

最有帮助的旧资料

旧文件直接帮助
tools/weapon-bench.md区分武器自身烘焙、装备 Tooltip、实战三种消费口径
public/tools/weapon-designer/index.html可运行的 float32 参考实现,以及每条公式的原生地址
wiki/effect-manager.md §7–8239 缓存、伤害类型筛选、来源权限、反射独立累加
wiki/effect-semantics.md七桶查询与消费方位置,但有两处旧记载需纠正
wiki/combat-log-outer-functions-and-effect-routing.md反射概率与倍率是两列、结算和表现分层
wiki/tl2-skill-design-guide.mdWEAPONDAMAGEPCT / USEDPS / SOAKSCALEPCT 的职责边界
devlog/runtime-hook-readme.md §3.9已有实扣伤害计量入口、过量伤害与 DoT 的取样边界
guides/combat-numbers.md玩家向概览与算例线索,不能代替逐指令算法或混用 MOD 数字

本轮给上述内容及其他两篇效果参考记录了 10 份源文件 SHA256,并重新确认 IDA 13337 对应 E:\Torchlight 2\Torchlight2.exe.i64。21 个相关函数重新抓取,关键分支保留完整汇编。

1. 已闭合:攻击间隔不是未知动画长度

上一轮确认 WeaponPeriod 读取攻击定义的两个浮点字段,但还未完整确认它们从哪来。 旧设计台给出了明确线索,本轮在 IDA 验证:

text
0x58F0C0 CEquipment::loadCombatStatsFromDat
  DEVIATION_FROM_30FPS -> v151 (float)
  SPEED -> getInt(default 100) -> float(SPEED * 0.01f) = v152
        ↓ 构造参数
0x5182E0 CAttackDescription::ctor
  +0x74 = DEVIATION_FROM_30FPS
  +0x78 = float(SPEED * 0.01f)

0x576F30 WeaponPeriod
  优先 item+0x2DC,缺失才用 item+0x2D8
  period = float(def+0x74) * float(def+0x78)

人物页再执行 period / (1 + attackSpeedBonus/100) 的原生包装器,含原版零值分支。 普通武器这段不需要通过测量动画播了多少帧来猜。

2. 三种 DPS/伤害读取口径必须分开

消费方真实入口计算基础
装备浮窗 DPS0x5803E0 CEquipment::computeDPS武器自身三个伤害桶与宝石,整体套下限比值
人物详细页 DPS0x7B7430,enum 94/95人物 Dmin/Dmax + 该手攻击间隔 + 人物攻速修正
实战命中0x548850 CCharacter::resolveStrikeHit基础伤害段及分类型伤害,随机、暴击、护甲、最终合并扣血

本轮重新查到 0x5803E0 只有两个代码引用

  • 0x4E4330,在 EditorGetEquipmentDPSInfo 内;
  • 0x58B0DC,在 CItemTooltip::build 内。

没有发现战斗函数直接读取它。不能拿这个武器浮窗函数填人物详细页,更不能用它替代实战结算。 旧指南中“差 1 是显示间隔舍入”的说法最多是某个算例的解释;普遍差异还可能来自不同消费口径。

3. 已复核:三桶和宝石不是可以合并的 effect 总和

数据位置创建/读取规则
A:物品内联与普通词缀附加伤害+0x3D8WEAPON 的 type 10/52 烘焙,读取 effect+0xD8 的已 ceil 值
B:带 0x400 标志的附魔伤害+0x400同样烘焙,但来源单独保存,祛魔可单独清除
C:DAT 基础元素伤害+0x3ECDAT 配方烘焙后的分类型值,最小值查询才乘 min/max ratio
宝石 live effects各宝石效果列表读原始 +0xD4,按每条效果累加并每次 truncate

已核对 0x590BB0、0x580120、0x580260

text
weapon Max(k) = A[k] + B[k] + C[k] + per-effect-truncated gem contributions
weapon Min(k) = truncate(A[k] + B[k] + C[k]*ratio) + 同样的宝石逐条贡献

武器烘焙后相应 type 10/52 效果被标记消耗,再从效果管理器清理。 因此只扫描存活 effect 列表会丢掉已烘焙的武器附加伤害。

2026-09-13已接入CoreSim真实物品构造:按+0xD8写入A/B,然后从live列表移除,不再同时作为角色stat10加伤。v22单独保存不可变的消耗来源记录与实际A/B数组,读档不再执行烘焙。7AF2A0清理采用末项换入的swap-back顺序,因此相邻吸血等词缀下标也必须重映射。

新原版数据现场例:GREATSWORD_U01C(14级)的固定伤害词缀50.084999…烘焙为51,SWORD_U01(7级)为4,AXE_U01B(9级)为36。三件经过真实生成/装备/HIT/读档重放;这是伤害烘焙链验收,不是随机词缀、TRANSFER、触发器或全部武器已完成。

两条 6.5 是有辨别力的测试:武器 A/B 烘焙得到 14,宝石逐条截断得到 12。 “先把两个 float 求和再取整”会得到错误结果。

装备浮窗的原版缺陷也证实了

0x5803E0 每遍历一颗宝石,在 0x58048Aecx 设成武器自身、固定查询 type 6, 然后 0x5804B3 才把 ecx 设成当前宝石进入其逐类型求和。 所以武器本体的 type-6 最大伤害会随宝石数再次计入。不能把这一句擅自“修正”为只查宝石。

它的下限还使用 D * ratio,会把本应同额加在 min/max 的平坦伤害也缩小。 这就是旧设计台报告“浮窗 DPS 和真实均值 DPS 有偏差”的确切来源之一。

4. 旧资料中确认需要纠正的三点

4.1 0x52DA30 / 0x52E9D0 不是纯近战/纯远程二选一

effect-semantics.md §2.2 与部分 effect-examples 仍这样命名,旧 IDB 注释也有相同说法。 本轮确认:

  • 0x52DA30 使用 sumDamageMinOfType;0x52E9D0 使用 sumDamageMaxOfType
  • 两者都在内部检查 RANGED WEAPON,再决定查 type 0 还是 type 1。
  • 在 Dmax 的 0x52EF05..0x52EF1AhasUnitType(0x23) 决定 push 1/0; 在 Dmin 的 0x52DF65..0x52DF7A 有对应结构。

因此是人物总最小/最大伤害入口,不是只改一边就只影响近战或远程。 旧的 0x52BD90 / 0x52C170 则要按各自实际调用契约分析,不能靠“同样一对”类推。

4.2 CUnit::getStat 的第三个参数不是 ceil 开关

effect-semantics.md §2 曾把第三参写成“是否向上取整”, 但同库的 effect-manager.md §8.1 给出了正确的四参底层签名。

IDA 核实:

text
CUnit::getStat(type, damageType, onlyLocalSource)
  -> EffectMgr::sumStatOfType_filtered(type, damageType, onlyLocalSource, useCeil=0)

0x51886A 读取上层 arg_8,0x518876 先压 useCeil=0,0x518878 再压该 arg_8。 底层 onlyLocalSource 会检查来源单位及本地权威,不是数学取整。 错误传 1 不但不会得到 ceil,还可能把大量来源过滤掉。

4.3 “暴击最终取上限”正确,“暴击不掷点”不正确

旧设计台文字说暴击不掷点,作为“最终数值不取随机值”的概览可以理解,但不能照此省掉代码:

text
0x54978D 调 rand_int_between_volatile
0x549795 检查暴击结果
0x5497A4 取暴击伤害加成
0x5497B3 截断加成
0x5497B8 将加成加到上限
0x5497BA 覆盖此前的随机伤害

另一个分类型伤害段 0x54A5C2 后也采用相同顺序。 即先调用掷点,再在暴击时用上限覆盖。非退化区间仍会消耗随机流;min=max 的 helper 快路另论。 这关系到联机/回放与后续随机结果,不只是这一击数字。

这也标出了当前 CoreSim 窄切片的潜在后续修正:不能直接把其“随机伤害再乘暴伤”的口径 当成完整原版实战 oracle。本轮没有改战斗代码。

5. 人物左右手的一处不对称,静态就能确定

在左手分支决定是否追加元素 type-10 平加时:

  • Dmin 0x52DF90 读取 arg_4,即 component 分量选择;
  • Dmax 0x52EF30 读取 arg_C,即 hand 选择。

后面两者都测试“值为 0 或 2”。但当前左手分支自身已经把 hand 限制为 0/1, 所以显式 left=1 的 Dmax 会跳过这组平加;Dmin 却继续按分量决定。 这是原始栈参读取指令的差异,不是伪代码变量名推断。

下一步转录时必须先保留这项不对称,不能把左右手和 min/max 全压成一个“干净通用公式”。 动态测试可以验证哪些真实装备/效果会触及这个分支,但无需依靠 attach 才知道分支条件。

6. 已跑静态交叉算例,且明确不是原版运行对拍

读取旧网页中已检查过的纯算术部分,在无 DOM、无游戏进程的 Node VM 中执行; 另写 Python 参考按本轮核实的结构复算。先比对原版 BASE_WEAPON_DAMAGE 的全部 105 个点, 再运行 4 个向量,输出逐字段一致。

原版 LEGENDARY_RIFLE01 的 UNIT 标量配方(不包括其完整词缀及宝石实例):

项目结果
Level / MIN / MAX59 / 50 / 80
SPEED / SPEED_DMG_MOD / RARITY_DMG_MOD70 / 70 / 160
pctArg / 曲线烘焙 base89 / 251
物理最小 / 最大54 / 87
冰最小 / 最大31 / 50
毒最小 / 最大86 / 138
实际参数相乘得到的 period0.699999988079071
装备浮窗 DPS320
未经过人物修正/防御的均值 DPS 参考318.57143399666774

其余三个向量分别覆盖 A/B 两条 6.5、宝石两条 6.5、type6=10 加两颗空效果宝石。 最后一个向量的浮窗 D 从 275 增到 305,即基础加 10 后又随两颗宝石各加 10。

限制:这是旧 JavaScript 与新 Python 参考算术一致性,不是两个独立的原版运行 oracle。 未覆盖全部 float 边界、非标准宝石自身烘焙桶、完整传奇词缀与人物修正。 旧指南的 MOD 装备和数值样例没有直接搬进原版数据。

7. 是否还需要动态验证

现在不必:继续实现所需的主要来源已经能静态给出

  • 武器生成后的 max/ratio、三类伤害桶、宝石实例列表;
  • 攻击定义里的 period 输入;
  • 人物侧按类型/来源筛选的效果值;
  • 装备浮窗、人物详细页与实战分别使用的包装器和取整步骤。

后续只做最小对拍,不重新盲跟整条加载链

验证采集点/用途不能混用的东西
同一件装备的字段与面板0x58F0C0 之后的桶/ratio/period,0x5803E0 与详细页 enum94/95不能拿浮窗 DPS 当人物 DPS
暴击与随机流0x54978D 前后及暴击覆盖点;必要时同看 0x54A5C2不能只对最终整数,不对 RNG 推进
左手元素平加固定同一测试角色/装备,记录 component、hand、S10 桶与 min/max不把原生不对称“修正掉”
实际扣血复用已有 combat_meter 的 modifyHealth 前后差值不用传入 delta 或浮字当真实扣血;排除 overkill

runtime-hook-readme.md 的现有计量器已经能提供最后一类数据,未来可优先复用, 不必另挂一整套临时全局 Hook。它的“统计时间窗 DPS”也不能用于验证静态面板 DPS。 测试应隔离原版测试存档;本轮没有启动上述动态操作。

复现与结果

powershell
python -X utf8 tools/research_wiki_combat_crosscheck.py
python -X utf8 tools/check_wiki_weapon_model.py
python -X utf8 -m unittest tests.test_journal_wiki_crosscheck tests.test_journal_stat_research -v

12 项静态证据/参考测试通过。资料和函数指纹、汇编、引用点及算例位于 build/research_journal_wiki/。上一轮 110 字段对照已追加 period 数据来源,仍明确区分 “静态公式”“保存状态读取”“隐藏占位”“武器原生函数体”,没有扩大成全游戏复原声明。

来源与使用范围

本页同步自 Torchlight2-Remaster-Project 的 docs/devlog/2026-09-11-journal-wiki-ida-crosscheck.md。文中的 tools/core_sim/torchlight-2-poc/build/ 路径及复现命令,均属于重制项目,不是 Wiki 仓库目录。原版静态证据、移植进度与尚待验证项分别标明,不把参考算例当成原版运行对拍。