From f674132c04b9f042d3c579c2e12ca896f7393ec6 Mon Sep 17 00:00:00 2001 From: DKChan <524912269@qq.com> Date: Fri, 23 Oct 2026 03:21:54 +0800 Subject: [PATCH] =?UTF-8?q?test(=E8=BF=81=E7=A7=BB):=20=E6=89=B9=20B=20?= =?UTF-8?q?=E6=B3=A2=201=20G4=20=E5=A5=975=20fresh=20=E6=B1=A0=E6=94=BB?= =?UTF-8?q?=E5=87=BB=E9=93=BE=E4=B8=89=E6=9D=A1=E8=BF=81=E5=85=A5=20roll?= =?UTF-8?q?=5Fmultiplier=5Ftest.gd=E2=80=94=E2=80=94=E5=89=AA=E5=88=87?= =?UTF-8?q?=E6=8C=82=E8=BD=BD=E7=BB=BF=EF=BC=88=E5=AE=BF=E4=B8=BB=2037=20?= =?UTF-8?q?=E6=A3=80=E6=9F=A5=EF=BC=89=EF=BC=8B=E5=8F=98=E5=BC=82=203/3=20?= =?UTF-8?q?=E9=AA=8C=E7=BA=A2=EF=BC=88=E5=8F=97=E7=90=86=E5=AE=88=E5=8D=AB?= =?UTF-8?q?=E6=81=92=E6=8B=92/=E6=95=8C=E6=8A=80=E8=A1=8C=E6=94=B9?= =?UTF-8?q?=E5=90=8D/=E4=B9=98=E5=8C=BA=E6=B1=A0=E6=B3=A8=E5=80=BC?= =?UTF-8?q?=EF=BC=89=EF=BC=9B=E9=A6=96=E8=BD=AE=E5=89=AA=E5=88=87=E8=BE=B9?= =?UTF-8?q?=E7=95=8C=E5=B7=AE=E4=B8=80=E8=A1=8C=E8=87=B4=E6=B8=B8=E7=A6=BB?= =?UTF-8?q?=20check=20=E6=AE=8B=E7=95=99=20Parse=20Error=EF=BC=8C=E9=97=B8?= =?UTF-8?q?01=20=E6=8A=93=E5=88=B0=E8=A1=A5=E5=88=A0=EF=BC=88=E5=8F=91?= =?UTF-8?q?=E7=8E=B0=E2=91=A6=E5=90=8C=E6=BA=90=E6=95=99=E8=AE=AD=E8=AE=B0?= =?UTF-8?q?=E8=B4=A6=EF=BC=89=EF=BC=9Bsmoke=5Fall.gd=20=E5=90=8C=E6=89=B9?= =?UTF-8?q?=E5=88=A0=E5=87=BD=E6=95=B0=E8=8A=82=E5=A4=B4=E4=B8=8E=E8=B0=83?= =?UTF-8?q?=E7=94=A8=E8=A1=8C=EF=BC=9B=E9=97=B801=20=E5=89=A9=E4=BD=99?= =?UTF-8?q?=E9=9D=A2=20981=20=E7=BB=BF?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- game/smoke/smoke_all.gd | 32 ----------------- .../battle_settlement/roll_multiplier_test.gd | 34 +++++++++++++++++++ reports/批B-断言迁移账本-2026-10-22.md | 1 + 3 files changed, 35 insertions(+), 32 deletions(-) diff --git a/game/smoke/smoke_all.gd b/game/smoke/smoke_all.gd index 09a2fa00..ede2345c 100644 --- a/game/smoke/smoke_all.gd +++ b/game/smoke/smoke_all.gd @@ -171,7 +171,6 @@ func _run_core_smoke(db, rng) -> void: _smoke_element_details() _smoke_diag_button_retired() _smoke_encounter_roll() - _smoke_attack_chain_fresh_pool() _smoke_clear_reward_chain() _smoke_refresh_provenance_guard() _smoke_polarity_routing() @@ -2170,37 +2169,6 @@ func _level_battle_nodes(level_index: int) -> Array: return out -# ---- 战斗段 fresh 池攻击链回归(playtest-2026-09-12 报告 Bug#2 沉淀—— -# 「Boss 攻击拍零兑现」= 叠满触底 ×0;本断言钉死: -# 池为空时攻击链必须按掷点档位足额兑现,口径: -# d_tick = max(damage_floor, pool_damage(floor(基线×档位%), 0, 0)),档位读数随行重建可归因)---- - -func _smoke_attack_chain_fresh_pool() -> void: - print("--- 战斗结算·fresh 池攻击链回归(Bug#2·掷点口径)---") - var rng = load("res://core/rng_service.gd").new() - rng.set_master_seed(20260913) - var settlement = load("res://core/battle_orchestrator.gd").new(_db, rng) - var ticks: Array = [] # {baseline, attach, roll, tier, crit, tick}——敌行动伤害行重建 - settlement.step_row.connect(func(row): - if row.type == "damage" and row.source_class == "enemy_action": - ticks.append({"baseline": int(row.baseline), "attach": int(row.get("attach", 0)), "roll": int(row.roll), - "tier": int(row.tier), "crit": bool(row.get("crit", false)), "tick": int(row.value)})) - check(settlement.begin_battle({"level_index": 1, "node_depth": 4, "hero_hp": int(_db.hero.max_hp), "node_type": "boss"}), "fresh 池回归战斗启动(Boss 行)") - # 停手轮:零挖掘零封印 → 零授予 → 池恒空;Boss 拍 = 开轮摇号结果(伤害技/普攻兑付伤害行、硬化施放行不计) - for i in range(6): - if settlement.battle_result != "": - break - settlement.minesweeper.settle_batch([{"action": "stop"}]) - check(ticks.size() >= 2, "非施放攻击拍采样充足(%d 拍——增益施放行零兑付为设计语义不计)" % ticks.size()) - var all_full := true - for t in ticks: - var base_factor: float = float(t.tier) * (float(_db.settlement.crit_multiplier) / 100.0 if t.crit else 1.0) - var rolled_base := int(floor(float(t.baseline) * base_factor / 100.0)) - var expected: int = maxi(int(_db.settlement.damage_floor), rolled_base + int(t.get("attach", 0))) - if int(t.tick) != expected or int(t.tick) <= 0: - all_full = false - check(all_full, "fresh 池非蓄力拍 d_tick = max(1, 掷点档位基线)(Boss 攻击链健康——Bug#2 回归断言)") - func _encounter_replay(seed_val: int) -> Array: var out: Array = [] var rng = load("res://core/rng_service.gd").new() diff --git a/game/tests/unit/battle_settlement/roll_multiplier_test.gd b/game/tests/unit/battle_settlement/roll_multiplier_test.gd index f8969ccb..7f571479 100644 --- a/game/tests/unit/battle_settlement/roll_multiplier_test.gd +++ b/game/tests/unit/battle_settlement/roll_multiplier_test.gd @@ -33,6 +33,7 @@ func _init() -> void: _smoke_armor_roll() _smoke_pool_wiring() _smoke_damage_types() + _smoke_attack_chain_fresh_pool() quit(Kit.finish("roll_multiplier_test")) @@ -424,3 +425,36 @@ func _find_seal_target(minesweeper, want_mine: bool) -> Dictionary: if revealed_set.has(n) and (minesweeper.compute_move_path(n).size() > 0 or n == minesweeper.hero_pos()): return {"seal_cell": c, "hero_cell": n} return {} + + +# ---- 战斗段 fresh 池攻击链回归(playtest-2026-09-12 报告 Bug#2 沉淀—— +# 「Boss 攻击拍零兑现」= 叠满触底 ×0;本断言钉死: +# 池为空时攻击链必须按掷点档位足额兑现,口径: +# d_tick = max(damage_floor, pool_damage(floor(基线×档位%), 0, 0)),档位读数随行重建可归因)---- + +func _smoke_attack_chain_fresh_pool() -> void: + print("--- 战斗结算·fresh 池攻击链回归(Bug#2·掷点口径)---") + var rng = load("res://core/rng_service.gd").new() + rng.set_master_seed(20260913) + var settlement = load("res://core/battle_orchestrator.gd").new(_db, rng) + var ticks: Array = [] # {baseline, attach, roll, tier, crit, tick}——敌行动伤害行重建 + settlement.step_row.connect(func(row): + if row.type == "damage" and row.source_class == "enemy_action": + ticks.append({"baseline": int(row.baseline), "attach": int(row.get("attach", 0)), "roll": int(row.roll), + "tier": int(row.tier), "crit": bool(row.get("crit", false)), "tick": int(row.value)})) + Kit.check("fresh 池回归战斗启动(Boss 行)", + settlement.begin_battle({"level_index": 1, "node_depth": 4, "hero_hp": int(_db.hero.max_hp), "node_type": "boss"})) + # 停手轮:零挖掘零封印 → 零授予 → 池恒空;Boss 拍 = 开轮摇号结果(伤害技/普攻兑付伤害行、硬化施放行不计) + for i in range(6): + if settlement.battle_result != "": + break + settlement.minesweeper.settle_batch([{"action": "stop"}]) + Kit.check("非施放攻击拍采样充足(%d 拍——增益施放行零兑付为设计语义不计)" % ticks.size(), ticks.size() >= 2) + var all_full := true + for t in ticks: + var base_factor: float = float(t.tier) * (float(_db.settlement.crit_multiplier) / 100.0 if t.crit else 1.0) + var rolled_base := int(floor(float(t.baseline) * base_factor / 100.0)) + var expected: int = maxi(int(_db.settlement.damage_floor), rolled_base + int(t.get("attach", 0))) + if int(t.tick) != expected or int(t.tick) <= 0: + all_full = false + Kit.check("fresh 池非蓄力拍 d_tick = max(1, 掷点档位基线)(Boss 攻击链健康——Bug#2 回归断言)", all_full) diff --git a/reports/批B-断言迁移账本-2026-10-22.md b/reports/批B-断言迁移账本-2026-10-22.md index 20166995..a7116e52 100644 --- a/reports/批B-断言迁移账本-2026-10-22.md +++ b/reports/批B-断言迁移账本-2026-10-22.md @@ -285,6 +285,7 @@ - `_smoke_armor_roll`(15 条):15/15 验红(条3 含一次无效首试换点,共 16 轮)。变异点——damage_math.gd:36 档位边界比较 `>`→`>=`(红「查档分布」双迭代+「EV 锚」连带——纯函数共面);settlement.tres roll_tier_discounts 75→74(红「EV 锚」1572≠1575,连带查档双迭代+AC11 落域);damage_controller.gd:540 暴击判定恒假(**首试无效变异**——「nat20 种子可达」只查掷点值==crit_roll 不查标记,判路面不被触及;该轮实际验红条4/条5 记为下两条的顺带证据)→换点 :539 roll 上界收窄 20 不可达(红「种子可达」seed=-1,连带条4/条5——种子扫描共同源);:375 hero 载荷 crit 标记写入恒假(红「crit 标记留档」红唯一 1/20);:369 暴击倍率传参 200→100(红「普通分量 ×2」红唯一);status_container.gd:52 续时刷新分支 pass 化(红「削弱续时」红唯一);:40 幅度快照 −1 偏移(红「削弱池读数=行值」红唯一);damage_math.gd:38 档值 +7 偏移出域(红「AC11 逐拍落域」,连带查档双迭代+EV 锚——纯函数共面;「折扣档流动」保持绿);damage_controller.gd:539 掷点折叠恒 nat 面(红「折扣档流动」——采样 distinct 恒 1 穷尽返空 ×0 拍连带「AC11 逐拍落域」);:515 board_blast 下限拆除恒 0(红「零 v=0 伤害行」红唯一——流中确有群伤行);:374 hero 载荷 tier 键 pass 化(红「掷点读数留档」红唯一);:504 board_typed 载荷塞 roll 键(红「棋盘行零掷点字段」红唯一);damage_math.gd counter_component 三点隔离变异:贴底特例 `sum==1→99`(红「贴底下限」红唯一)、负和特例 `sum<0→99`(红「触底穿透」红唯一)、空桶早退 `return 0→1`(红「空桶恒 0」红唯一)。 - `_smoke_pool_wiring`(4 条):4/4 验红。变异点——damage_controller.gd:271 hero 侧 atk_type 加 "_x" 后缀(红「单分量基线在位」——payload 分量键改名 normal 键失位;armor_roll 套「普通分量 ×2」同键消费连带属预期形态);status_effects.tres attack_up magnitude 50→40(红「增伤 ×1.5」140≠150 红唯一);sapped magnitude −25→−10(红「乏力 ×0.75」90≠75 红唯一);fortify magnitude −50→−20(红「硬化折半方向」80≠50 红唯一)。 - `_smoke_damage_types`(10 条):10/10 验红(条3 含一次无效首试换点,共 11 轮)。变异点——enemy.tres goblin 行 armor_type light→heavy:27(红「goblin 护甲」+armor_roll「普通分量 ×2」连带——goblin 是 crit 探针攻击目标);bugbear 行 armor_type light→heavy:73(红唯一 1/34);ogre_chief 行 armor_type light→heavy:126(**首试无效变异**——该条 spawn 直呼第 9 参 "boss" 实落 hero_armor_type 形参、row_kind 缺省 battle(源套形态照迁),(1,4) battle 域 band_of ceil 落带命中 hobgoblin band3 行、ogre_chief 属 boss 域不在键域)→换点 hobgoblin 行 armor_type light→heavy:98(红唯一 1/34——实证解析落带);settlement.tres normal.light 0→1:33(红「普通行矩阵值」+套1 矩阵证词/armor_roll ×2 连带——同表源);pierce.heavy 0→1:40(红唯一);magic.ward −1→1:44(红唯一);grant_segment.gd:312 归因行类型 seal_miss→seal_mis(红「seal_miss 归因行」×0 红唯一);:316 标错负向路由 pass 化(红「负向字典行」×0 红唯一);:290 标中正向路由 pass 化(红「正向字典行」×0 红唯一);damage_controller.gd:539 armor_roll 流换全局未播种 randi_range(红「同种子回放逐行相同」——G3 同款确定性击破形态;套1 矩阵证词连带属预期)。 +- `_smoke_attack_chain_fresh_pool`(3 条):3/3 验红。变异点——battle_orchestrator.gd:304 begin_battle 受理守卫 `!= 0`→`>= 0` 恒拒(红「fresh 池回归战斗启动」;该守卫为全宿主战斗共同入口,其余四套战斗面 16 项连带红属其自然半径);damage_controller.gd:479 敌技行类型 damage→damage_x(红「非施放攻击拍采样充足」×0 拍;套1 矩阵证词/载荷与套2 AC11 双条为敌方行共同源连带);:447 敌技乘区 enemy_output 池注值 50(红「fresh 池 d_tick 掷点口径」——pooled=floor(rolled×1.5) 偏离 fresh 池零池口径;套1 矩阵证词连带)。 ## 十、支援线 9 项待裁闭合(2026-10-22 主会话裁)