From 323676b2ee37d8f50aefcfacae41cee87b804df4 Mon Sep 17 00:00:00 2001 From: wusumac <736139669@qq.com> Date: Wed, 16 Sep 2026 02:26:49 +0800 Subject: [PATCH] fix(m80-i08): reach profession bases and apply guard-kind actions to the guard pool --- docs/EVIDENCE_LEDGER.md | 2 +- docs/plans/M80_BATTLE_SIMULATION.md | 11 +++++++---- runtime/domain/battle_simulation.gd | 13 +++++++++++++ runtime/entry/battle_sim_bridge.gd | 4 +++- runtime/tools/dbg_tmp.gd.uid | 1 - 5 files changed, 24 insertions(+), 7 deletions(-) delete mode 100644 runtime/tools/dbg_tmp.gd.uid diff --git a/docs/EVIDENCE_LEDGER.md b/docs/EVIDENCE_LEDGER.md index a5bd2351..8e81ec06 100644 --- a/docs/EVIDENCE_LEDGER.md +++ b/docs/EVIDENCE_LEDGER.md @@ -17,7 +17,7 @@ | 2026-09-15 | M79-F 区域 6 内容(数据/本地化/立绘/音乐/战场)+ 推进门到第十一份合同 + 注册表测试 R6 计修正 | `feat(m79-f)` `c728a49a`/`a4de1565` | `m79-region6` `20260915T050042Z-16542` | runtime_verified | 240 装备/45 遗物/74 敌人/12 Boss/12 合同/461 本地化;`contracts=11 region=RG-06`;15 marker 各 1 次 | | 2026-09-15 | M79-E 区域 5 内容(数据/本地化/立绘/音乐/战场)+ 推进门到第九份合同 + 注册表验证器修 13 敌人 | `feat(m79-e)` `aff0358b`/`6a9518e3` | `m79-region5` `20260915T023248Z-65213` | runtime_verified | 200 装备/37 遗物/61 敌人/10 Boss/10 合同/395 本地化;`contracts=9 region=RG-05`;15 marker 各 1 次 | | 2026-09-15 | M79-D 区域 4 美术+音乐+接线(含 R2/R3 姿态回填;risk 选项轮询去 flake) | `feat(m79-d)` `5f9723d2` + `test(m79-d)` `c7abcb97` | `m79-region4` `20260915T022134Z-55448` | runtime_verified | 28 张 R4 立绘+卷根战场+`battle_r4`/`boss_r4`;R2/R3 42 条姿态接线回填;15 marker 各 1 次 | -| 2026-09-15 | M80 平衡扫描工具 + 装备数值接线(发现 M80-I08 阻塞) | `wip(m80-sweep)` | runtime_verified(工具与接线落地;平衡跑数因阻塞暂无效) | `ABG_M80_BALANCE_SWEEP_OK`;三配置 tick 相同(305)已登记 | +| 2026-09-15 | M80-I08 修复:职业基础值键名 + guard 类动作语义;平衡扫描重出 | `fix(m80-i08)` | runtime_verified | 探针 `cleared=12`;扫描 1-6 回合 0% 灭团 / 7-12 回合 12-62% | | 2026-09-15 | M80-B3 收尾:装备 320/320 逐行点名(90 行显式表 + 关键词兜底) | `feat(m80-b3c)` | runtime_verified | `ABG_M80_EQUIPMENT_HOOKS_OK rows=320 classified=320 implemented=233 legal_hooks=true pending=0` | | 2026-09-15 | M80-B4 切片 1:合同结构(12 回合 + Boss 集合)+ 区域遭遇语法 + 装备数值作者化接入桥 | `feat(m80-b4a)` | runtime_verified | `ABG_M80_CONTRACT_RUN_OK rounds=12 grammar=reach …`;探针 `ABG_M80_CONTRACT_RUN_PROBE_OK cleared=6 …`(记录见 M80-I07) | | 2026-09-15 | M80-B3 切片 2:区域 1 十二条敌人行动档案(可执行 + 合法钩子) | `feat(m80-b3b)` | runtime_verified | `ABG_M80_ENEMY_ACTIONS_OK enemies=12 legal_hooks=true battle=resolved deterministic=true` | diff --git a/docs/plans/M80_BATTLE_SIMULATION.md b/docs/plans/M80_BATTLE_SIMULATION.md index 23ba4027..c0118024 100644 --- a/docs/plans/M80_BATTLE_SIMULATION.md +++ b/docs/plans/M80_BATTLE_SIMULATION.md @@ -85,10 +85,13 @@ reach/目标选择、Guard/护盾、伤害公式(含暴击与标签化随机 | `M80-I05` | RESOLVED(2026-09-15)| 320/320 行全部声明 §17 合法钩子 + 效果类(230 行关键词分类 + 90 行逐行点名; 233 行落在模拟已实现的效果类,其余按未实现效果类登记,绝不猜);后续把未实现效果类逐类落地即可 | | `M80-I03` | OPEN | 职业优先级行的条件中有一批依赖 B3/B4 的系统(敌方预警/设备/链接/资源阈值);当前按“条件不成立”跳过,落地后逐行启用并补断言 | -| `M80-I08` | OPEN(B5 阻塞)| **装备数值不改变战斗**:桥构建的友军行确实带上了装备数值(实测 `wp=10 guard=8`),但同一 seed/同一敌人下 +| `M80-I08` | RESOLVED(2026-09-15)| **两个真缺陷已修**:(1) 桥的 `_ally_row` 合并短键 `hp/tempo/initiative`,模拟读 `profession_base_*` → 职业基础值从未生效; + (2) `kind: "guard"` 的动作用了伤害路径(自伤且 Guard 池不恢复)→ `self_guard_below_half` 永真,角色整场循环 `refresh_guard` 不再攻击。 + 修复后合同探针 6→**12/12 全清 + Boss 击破**(4 次重试);平衡扫描重出(无断崖) | +| `M80-I08x` | RESOLVED(历史记录)| **装备数值不改变战斗**:桥构建的友军行确实带上了装备数值(实测 `wp=10 guard=8`),但同一 seed/同一敌人下 `item=""` / `EQ-002` / `EQ-001` 三种配置的 tick 完全相同(305)→ 模拟未按 §9/§15 消费 `weapon_power`/`armor_guard`(或消费路径与行字段不一致)。 复现脚本已在本轮记录;修复前所有平衡跑数(M80-I02/I07)无效 | -| `M80-I07` | OPEN | 合同跑量探针(CTR-R1-01)实测:静态 4 人 4 级队清到第 6 回合,**第 7 回合(含精英锚点 + 后排 - reach 的 4 敌)是墙**;Boss 一击可胜(比精英群好打);前段战斗 208 ticks ≈ 21 s,低于文档 90 s 战斗区间目标。 - 结论:墙要靠经济/晋阶路径(真实跑量会长等级换装备),Boss 与精英群强度顺序、战斗时长仍需 B4 后的批量跑数校准 | +| `M80-I07` | OPEN(数值已可用)| 修完 I08 后重扫区域 1(成长阶梯 3→8 级 + 装备档随回合):1-6 回合 0% 灭团、23-53 s; + 7-12 回合 12%-62% 灭团、58-70 s、1-2.5 人生还 —— 曲线合理无断崖。仍需:对齐文档 90 s 战斗区间; + Boss 与精英群强度顺序复核;其余 7 区同法扫描(B4 后批量跑数) | | `M80-I02` | OPEN | 12 回合 × 16 合同的完整跑量平衡需在 B4 后用模拟批量跑数(经济/时长)复核 | diff --git a/runtime/domain/battle_simulation.gd b/runtime/domain/battle_simulation.gd index 517c5317..810f0c6f 100644 --- a/runtime/domain/battle_simulation.gd +++ b/runtime/domain/battle_simulation.gd @@ -228,6 +228,19 @@ func _apply_damage(record: Dictionary) -> void: if bool(victim.fallen): return var amount := int(record.amount) + if str(record.get("kind", "damage")) == "guard": + # A guard-kind action raises the target's Guard pool instead of dealing + # damage. Without this branch the row's amount was applied as self-damage + # while the pool stayed empty, so `self_guard_below_half` never cleared + # and the actor looped on its refresh row for the rest of the battle. + var cap := int(victim.stats.guard) * 2 + victim.guard = mini(cap, int(victim.guard) + amount) + record.guard_after = int(victim.guard) + record.hp_after = int(victim.hp) + record.erase("source") + record.erase("victim") + journal.append(record) + return if str(record.get("kind", "damage")) == "healing": var max_hp := int(victim.stats.max_hp) var heal_bonus := int(_trait_effect(victim, "after_heal").get("heal_bonus", 0)) diff --git a/runtime/entry/battle_sim_bridge.gd b/runtime/entry/battle_sim_bridge.gd index 3cf96ef9..46eec005 100644 --- a/runtime/entry/battle_sim_bridge.gd +++ b/runtime/entry/battle_sim_bridge.gd @@ -138,7 +138,9 @@ static func _recruit_by_id(recruits: Array, recruit_id: String) -> Dictionary: static func _ally_row(recruit_id: String, position: int, recruit: Dictionary) -> Dictionary: var profession_id := String(recruit.get("profession_id", "PF-B01")) - var bases := Authoring.profession_bases(profession_id) + # Section 9 reads `profession_base_hp/tempo/initiative`; the raw + # `profession_bases` table uses short keys and never reached the simulation. + var bases := Authoring.profession_row(profession_id) var row := { "id": "ally-%s" % recruit_id, "position": position, diff --git a/runtime/tools/dbg_tmp.gd.uid b/runtime/tools/dbg_tmp.gd.uid deleted file mode 100644 index f58e18a8..00000000 --- a/runtime/tools/dbg_tmp.gd.uid +++ /dev/null @@ -1 +0,0 @@ -uid://dtkcbwjxonyop