按 Torchlight2.exe 1.25.9.5 的逐指令实现复算 —— float32 舍入、截断方向、ceil 与 trunc 的每一处差别都照抄。
改一个键,立刻看到面板会写什么、DPS 数字是多少、以及每一刀真正掉在什么区间。
左边填 UNIT BLOCK 的键,右边是引擎会算出来的东西。所有数字实时联动。
MAXDAMAGE 决定量纲总闸,
两者的比值决定下限系数 +0x3B8。MAXDAMAGE:0 会让整条链不跑。base 的整数百分比。不勾「写入」= 键不存在(默认 −1),
此时 MaxDmg = base;勾上并填 0 是生效的,物理基础伤害会真的归零。
元素键填 0 等于没写。右下角「1% 值」= 当前调参粒度。SPEED 只进 DPS 分母、对伤害零影响;SPEED_DMG_MOD 只进伤害、
对攻速零影响。两者同步改是完全对冲的(只改节奏不改强度)。[EFFECT] TYPE:DAMAGE、[AFFIXES] roll 出的词缀、附魔师加的,
在物品创建 / 存盘时被 bakeDamageEffectsIntoTable 一次性搬进伤害表、effect 本体随后被删除 ——
所以扫 effect 列表永远看不到它们。入桶取值是 (int)ceil(效果值),
按 flags & 0x400 分流:附魔师进桶B(祛魔会整桶清零),其余进桶A。
WEAPON,它的 52 / 10 effect 不会被烤:
sumDamageMax/MinOfType 每次求和都现扫每个插槽里宝石的 0 号 effect 链表,
读原始 +0xD4(float,不 ceil),而且每加一条截断一次。
每颗宝石各自不同,所以按插槽分别填。
| 伤害包 | 下限 | 上限 | 均值 | 占比 |
|---|
rand_int_between(min,max) 掷一次、
各自过 applyArmorSoakAndAbsorb —— 物理吃护甲,元素吃对应抗性。
暴击不掷点,全部取上限再叠暴伤。按引擎实际分支给出的判定,不是经验法则。
左边填身份字段,右边直接拿走 UNIT BLOCK;也可以把现成的 .DAT 丢进来反填。
BASEFILE 继承来的键(多数武器的
DEVIATION_FROM_30FPS、RARITY_DMG_MOD)请用上面的基础档 / 品质档补。基址 0x400000,Torchlight2.exe 1.25.9.5。烘焙只在物品创建 / 读档 / 祛魔时发生一次,
之后所有消费端只读烤好的三个东西:+0x3A4 基础物理、+0x3B8 下限比值、
+0x3EC 桶C(DAT 基础元素伤害)。
ratio = f32(MINDAMAGE / MAXDAMAGE) @0x58F17C fild/fidiv/fstp
pctArg = trunc(MAXDAMAGE × f32(SPEED_DMG_MOD×0.01f)
× f32(RARITY_DMG_MOD×0.01f))
base = ceil(BASE_WEAPON_DAMAGE(LEVEL) × pctArg × 0.01f) @0x57C840 仅 MAXDAMAGE≠0 才调用
v150 = f32(base × 0.01f)
元素k = trunc(DAMAGE_k × v150) k: FIRE=2 ICE=3 ELEC=4 POIS=5 → 桶C @0x58E460
MaxDmg = DAMAGE_PHYSICAL > -1 ? trunc(DAMAGE_PHYSICAL × v150) : base → +0x3A4
MinDmg = trunc(MaxDmg × ratio) → +0x3A0
面板 DPS = ceil((D + ratio×D) × 0.5 / T) @0x5803E0
T = DEVIATION_FROM_30FPS × SPEED/100
D = +0x3A4 + Σ(k=0..6) sumDamageMaxOfType(k)
+ Σ(每颗宝石){ 宝石+0x3A4 + sumDamageMaxOfType(this,6) + Σ(k) sumDamageMaxOfType(宝石,k) }
sumDamageMaxOfType(k) @0x580120 = Σ(桶A + 桶B + 桶C) 原值
sumDamageMinOfType(k) @0x580260 = Σ(桶A + 桶B + 桶C×ratio)
一刀 = 逐类型 rand_int_between(min, max),各自 applyArmorSoakAndAbsorb @0x548850
暴击 = max + trunc(暴伤% × 0.01 × max) ← 不掷点
| 地址 | 函数 | 作用 |
|---|---|---|
0x58F0C0 | CEquipment::loadCombatStatsFromDat | 读全部 UNIT 级战斗 descriptor |
0x57C840 | CEquipment::setBaseWeaponDamage | 等级曲线缩放 → +0x3A0/+0x3A4/+0x3B0 |
0x58E460 | CEquipment::addDatBaseDamageOfType | 写桶C(4 个调用点 = 四种元素) |
0x5803E0 | CEquipment::computeDPS | 面板 DPS,只被 tooltip 与编辑器调用 |
0x580120 / 0x580260 | sumDamageMax/MinOfType | 逐类型求和;只有桶C 乘 ratio |
0x548850 | CCharacter::resolveStrikeHit | 实战:7 类型循环 + 掷点 + 暴击 |
0x5182E0 | CAttackDescription::ctor | +0x30[0]=MaxDmg,+0x4C[0]=MinDmg |
0x577E70 | getAttackSpeedLabel | 档位阈值 {130,110,90,80,0} @0x2173A78 |
两处已知的原版口径问题本工具都照实复现:① 插槽循环里 sumDamageMaxOfType(this,6) 传的是武器本体且类型写死 6,
每颗宝石重复计一次;② ratio 被乘在整个 D 上,平坦加成因此被低估。