武器 proc:完整过滤流程、目标参数与伤害角色归属
本批继续在 main,未创建 worktree、未提交、未 attach 原版游戏。使用 godot-master 的状态/表现分离原则;本批新增的是核心过滤与数据读取,没有新增未经结算验证的攻击特效。
已落地
ProcTargetQuery.cs:原版字符与物件两个列表的有序过滤、alignment、技能 canTarget、尸体、具体定义/UNITTYPE、宠物归属、MIMIC、退却保护与延迟 LOS 调用。F2WeaponProcs.Targeting:全部 16 个可达原版武器 proc 的目标参数,逐个确认均为一条来源链、一个 LEVEL1。根属性先加载,再继承到 LEVEL1;不擅自展开未验证的未来 BASEFILE/多等级情况。- 修复派发器漏掉 REQUIRES_TARGET:空查询仍先消耗 synced 旋转骰,之后才跳过本次施放,不停止该装备后续 proc。
- 明确 FROM TARGET 的原始施放角色、空间原点、管理器持有物和实际伤害角色,不能混成一个 actor。
**范围说明:**过滤流程能在完整原版输入下执行,不等于 Godot 已提供全部这些输入。新的 IProcQueryWorld 是只读、延迟取值接口;生产方缺字段必须报缺口,不能默认“可见、可选、无遮挡”。本批没有开放 Stormclaw/Bloodwash 等攻击型 proc,武器构造仍为 1053/1419(14 成长),319 个 host/NG+ 待补、47 个基础等级缺口。
原版证据
只读库:E:/Torchlight 2/Torchlight2.exe.i64;EXE SHA256: 186472c3057b38f4cdff4696959a943c396ae6166995f7418997b5ea853e8a5e。 C/ASM 保存在 build/research_weapon_families/。本批重新核对:
| 入口 | 已确认职责 |
|---|---|
| 5FC670 | 字符列表 +140、物件列表 +152 的查询次序与过滤 |
| 5DB730 | query alignment、targetable +392、PVP/归属例外 |
| 6BE880 | 技能 canTarget:SELF、尸体、UNITTYPE、具体定义、亲属与敌对门 |
| 41F600 / 523890 | 普通候选排除退却保护、非存活、状态41/42 |
| 51CA50 | 可选的 PET_CAN_ATTACK 门;无定义/未写时默认 true |
| 5F3060 / 5F4EA0 | 公共场景线段遮挡与反向布尔封装 |
| 6BFD40 | 优先从技能管理器装备解析角色持有者 |
| 6CC710 / 6C9CC0 | 事件的放置角色 +44 与伤害角色覆盖 +52 |
| 1B8ECE0 | 15 个 TARGET_TYPE 枚举的原始顺序 |
TARGET_TYPE 顺序是 NONE=0、POSITION=1、TARGET=2、SELF=3、EVERYBODY=4、POSITIONRANDOM=5、POSITIONFLEE=6、ITEM=7、UNIDENTIFIEDITEM=8、PETS=9、SELFANDPETS=10、TARGET_POS=11、OWNER=12、POSITION_RANDOM_CIRCLE=13、POSITION_RANDOM_AT_TARGET=14。
字符与物件过滤不能互相套用
字符列表依次检查:
- 存活;仅有效技能 owner 存在且 TARGET_CORPSES=true 时,允许进入尸体分支。
- vtable+52 的 enabled、+105 的 visible、显式 exclude、+406 的 queryable。
- query alignment,包含 +392 targetable;FROM TARGET 临时禁选 origin 的行为以只读掩码表达,不修改共享世界对象。
- 普通非尸体分支排除退却保护、非存活以及 native state 41/42。
- MIMIC(类型167)且 MIMICIDLE 排除;再做可选技能 canTarget。
- 可选 PET_CAN_ATTACK、局部几何、最后才做 LOS。
物件列表只检查 +557、+406、enabled、UNITTYPE29、它自己的几何与 LOS;不借用字符列表的存活、可见、阵营、exclude 或技能门。FROM TARGET 的随机选择只使用字符输出;物件输出仍独立保留。
保留调用方给出的原版列表顺序,不排序、不按距离选最近。原版几何沿用前批已订正的近身规则;完整 inverse Matrix4/Ogre x87 运算仍需由空间生产方提供,不把 Math.atan2 的普通实现冒充已逐位等价。
阵营和技能 canTarget 的边界
- targetable=false 在 ALL/PVP 之前拒绝。
- Query ALL(3) 直接放行;PVP 跨 owning-player 的例外早于普通阵营比较。
- SMASHABLE(7) 请求无需读取候选 alignment;候选 alignment=7 也有单独放行。
- 普通 GOOD/GOODBERSERK 接受1或8,EVIL/EVILBERSERK接受2或8,EVILONLY(9)只接受2。
- 查询 exclude 是有 master 且能找到 owning player 的宠物时,有另一分支:GOOD/EVIL不接受8,其他 requested alignment 直接通过,不能合并成普通敌对比较。
6BE110仅在原始 caster alignment=EVIL(2) 时对技能目标 GOOD/EVIL 做互换,不扩展到5/6等变种。- 技能 SELF 先把验证对象换成 caster;EVERYBODY 在非中立 caster 下跳过敌对比较。
- PETS、SELFANDPETS、OWNER 使用真实 master 指针关系,不能按阵营模拟亲属。
- PLAYER类型在内层 canTarget 有可见/enabled 特例,但它不能绕过外层 query 已经做过的相同门。
- TARGET_CORPSES/强制尸体按 HP 符号过滤;具体定义白名单/黑名单和必需/忽略 UNITTYPE 各自独立。
退却保护 523890 需要 invincible。floor(HP)≤1 会命中;状态10下还检查15%阈值及 min(floorHP,maxHP)/maxHP < 1 - threshold;AI flag3把threshold减半。该门不是简单的“HP>0即可选”。
LOS 新订正
前批只看到两个不同入口。本批展开 5F4EA0 后确认它等于 !5F3060,没有第二套物件遮挡规则。 两边都是起点/终点 Y 加5后,使用同一套场景线段遮挡。5F3060 内部含场景条件、分区/碰撞候选及附加阻挡体,并非一条随意的 Godot raycast 可以直接替换。
因此接口统一为 RayBlocked(from,to),外部完整射线生产方仍待接入。缺真实遮挡数据要抛出缺口,不返回 false 蒙混。
FROM TARGET 的伤害不是被击中怪物的武器
- 582380 将 other 当作临时 caster/发射原点,但技能仍归原装备的技能管理器。
- 6BFD40 首先检查管理器 owner 是否为装备及是否有持有者,有则优先返回持有角色。
- 6CC710:事件 +44 保存放置角色;6CCBFF→6CCC08 将上述解析角色写入 +52。
- 6C9CC0:先读 +44,再由非空 +52 覆盖;随后的读取武器、重算属性、strike_pickWeapon 全部使用该覆盖后的角色。
- 所以装备仍被玩家持有时,从怪物位置放出的闪电不能改成读取怪物武器。
- 装备已经没有持有者时,6BFD40 存在回落到赋值角色的分支;不能硬编码“永远用原玩家”,换装/掉落/owner生命周期必须参与。
REQUIRES_TARGET 与随机顺序
默认 false(6C2690);Stormclaw 显式 true。 53C7E0 与 582380 都在 FROM TARGET 的旋转/查询/选择之后检查它:
原版概率骰
→ synced 随机旋转(2步)
→ 有序字符查询
→ 有多个候选才消耗 volatile 选择骰
→ REQUIRES_TARGET && target为空:仅跳过本次施放丢弃无目标施放时不能回滚已经发生的随机旋转;若只是查询所需数据缺失或提供了应排除的 actor,则是实现缺口,整次暂存派发不提交随机流。
验证与后续
build/proc_target_core.log:1105 条核心断言通过,含真实16技能目标参数、分支顺序、两个列表、LOS抬高、尸体/宠物/PVP、owner覆盖和空目标RNG。build/proc_target_python.log:46 项原版证据/目录/既有回归通过。- Godot C# 零 warning/error,coresimlint通过;原有 struck_proc 主场景再次通过,未声称运行了尚未开放的攻击型 proc。
- 默认存档 SHA256 保持
9840fe858b6e311c73f8c2d4ed49912d59d71365f6278392811730e012d32a7f。 - 本批无新视觉资源和新攻击画面行为;不以旧回血截图证明闪电链已经可用。
剩余核心工作:Godot场景的真实flag/native state生产方、原版列表顺序、完整遮挡/矩阵、CSkill事件生命周期和伤害/命中调用、技能内部RNG与运行实例GUID。随后才能启用攻击型proc并增加生产覆盖。全武器目标保持未完成。