test(迁移): 批 B 波 1 G4 套4 伤害类型克制十条迁入 roll_multiplier_test.gd——剪切挂载绿(宿主 34 检查)+变异 10/10 验红(条3 首试无效换 hobgoblin 行已记账:spawn 第9参落 hero_armor_type 形参、battle 域 ceil 落带实证);套内独占 _run_seal_backlash_round 随迁,_find_seal_target 过渡副本(G5 四套仍消费原件保留);smoke_all.gd 同批删函数节头与调用行;闸01 剩余面 984 绿

This commit is contained in:
DKChan committed 2026-10-23 03:16:50 +08:00
1 parent d7def000a3
commit 855bce4534
3 files changed
+93 -63

No files matched your search

-63
View File
@@ -162,7 +162,6 @@ func _run_core_smoke(db, rng) -> void:
_smoke_level()
_smoke_seal_ap_exhausted()
_smoke_active_refresh()
_smoke_damage_types()
_smoke_playtest_logger()
_smoke_battle_log_view()
_smoke_global_theme()
@@ -1868,68 +1867,6 @@ func _active_refresh_replay() -> Array:
return rows
# ---- 攻击类型 × 护甲克制 + 标错惩罚冒烟(护甲快照/克制矩阵/充能/反噬三选一)----
func _smoke_damage_types() -> void:
print("--- 攻击类型 × 护甲克制 + 标错惩罚 ---")
# ① 护甲类型快照传播(spawn 行值 → 单位字典)
var enemy_system = load("res://core/unit_container.gd").new(_db)
check(enemy_system.spawn(1, 0, int(_db.hero.max_hp)) and String(enemy_system.all_enemies()[0].armor_type) == "light", "goblin 护甲 = light(轻甲——教学位)")
var enemy_system_b = load("res://core/unit_container.gd").new(_db)
check(enemy_system_b.spawn(1, 2, int(_db.hero.max_hp)) and String(enemy_system_b.all_enemies()[0].armor_type) == "light", "bugbear 护甲 = light(护甲类型重配批 2026-09-18:关卡 1 全轻甲)")
var enemy_system_c = load("res://core/unit_container.gd").new(_db)
check(enemy_system_c.spawn(1, 4, int(_db.hero.max_hp), [], -1, -1, [], "", "boss") and String(enemy_system_c.all_enemies()[0].armor_type) == "light", "ogre_chief 护甲 = light(Boss 行集——护甲类型重配批 2026-09-18:关卡 1 全轻甲)")
# ② 克制矩阵表值在位(三档点数 克制 +1 / 中性 0 / 被克 −1,加法核非 percent)
var am: Dictionary = _db.settlement.armor_effectiveness
check(int(am.normal.light) == 0 and int(am.normal.ward) == 1 and int(am.normal.heavy) == -1, "普通行:轻甲 0 / 魔法护甲 +1 / 重甲 −1(加法核)")
check(int(am.pierce.light) == -1 and int(am.pierce.ward) == 1 and int(am.pierce.heavy) == 0, "穿刺行:轻甲 −1 / 魔法护甲 +1 / 重甲 0 中性(用户拍板)")
check(int(am.magic.light) == 0 and int(am.magic.ward) == -1 and int(am.magic.heavy) == 1, "魔法行:轻甲 0 / 魔法护甲 −1 / 重甲 +1(加法核)")
# ③ 标错(类型化负向兑付)+ 标中正向兑付(封印命中只兑格面资源正向;Boss 行多轮样本;板真相直读保证 hit/miss 确定性)
var run1 = _run_seal_backlash_round(20260912)
var miss_rows := 0
var negative_rows := 0
var hit_rows := 0
for row in run1.rows:
if row.get("type", "") == "seal_miss":
miss_rows += 1
if String(row.get("source_class", "")) == "seal_miss" and String(row.get("type", "")) in ["effect", "damage"]:
negative_rows += 1 # 标错的负向兑付行(该安全格资源的负向字典行——effect/直伤)
if String(row.get("source_class", "")) == "seal_hit":
hit_rows += 1 # 标中的正向兑付行(该危险格资源的正向字典行——标中只走格面资源正向)
check(miss_rows >= 1, "标错封印产生 seal_miss 归因行(×%d)" % miss_rows)
check(negative_rows >= 1, "标错封印兑付该安全格资源的负向字典行(×%d——attack/defense/weaken 效果行或 heal 直伤行)" % negative_rows)
check(hit_rows >= 1, "封印命中兑付该危险格资源的正向字典行(×%d——充能退役后无魔法分量,正向=格面资源)" % hit_rows)
# ④ 同种子回放(极性路由零随机——同种子逐行相同)
var run2 = _run_seal_backlash_round(20260912)
check(JSON.stringify(run1.rows) == JSON.stringify(run2.rows), "标错惩罚轮回放断言:同种子步骤流逐行相同(类型化负向兑付确定性)")
# 构造轮:标 1 面"安全格封印"(必 miss → 该格资源负向兑付)+ 标 1 面"雷封印"(必 hit → 正向兑付 + 充能)后停手收轮。
# 返回 sealed safe 格与其 cell_type(Ready 域内查询——类型化断言的数据面)。
func _run_seal_backlash_round(seed_val: int) -> Dictionary:
var rng = load("res://core/rng_service.gd").new()
rng.set_master_seed(seed_val)
var settlement = load("res://core/battle_orchestrator.gd").new(_db, rng)
var rows: Array = []
settlement.step_row.connect(func(row): rows.append(row))
if not settlement.begin_battle({"level_index": 1, "node_depth": 4, "hero_hp": int(_db.hero.max_hp), "node_type": "boss"}):
return {"rows": rows, "safe_cell": Vector2i(-1, -1), "safe_type": ""}
var minesweeper = settlement.minesweeper
var safe_t := _find_seal_target(minesweeper, false)
var mine_t := _find_seal_target(minesweeper, true)
var safe_type := ""
if not safe_t.is_empty():
var ident = settlement.query_reward_identity(safe_t.seal_cell)
safe_type = String(ident.get("cell_type", "")) if ident != null else ""
if safe_t.hero_cell != minesweeper.hero_pos():
minesweeper.settle_batch([{"action": "move", "cell": safe_t.hero_cell}])
minesweeper.settle_batch([{"action": "seal_place", "cell": safe_t.seal_cell}])
if not mine_t.is_empty():
if mine_t.hero_cell != minesweeper.hero_pos():
minesweeper.settle_batch([{"action": "move", "cell": mine_t.hero_cell}])
minesweeper.settle_batch([{"action": "seal_place", "cell": mine_t.seal_cell}])
minesweeper.settle_batch([{"action": "stop"}])
return {"rows": rows, "safe_cell": safe_t.get("seal_cell", Vector2i(-1, -1)), "safe_type": safe_type}
# 板真相直读找封印目标:未开 + 指定雷/安全属性 + 存在可达已开邻格(测试允许读板真相——排雷玩法 冒烟同口径)
@@ -32,6 +32,7 @@ func _init() -> void:
_smoke_enemy_attack_type()
_smoke_armor_roll()
_smoke_pool_wiring()
_smoke_damage_types()
quit(Kit.finish("roll_multiplier_test"))
@@ -332,3 +333,94 @@ func _hero_attack_row_with(opts: Dictionary, hero_atk_val: int, seed_val: int) -
if String(row.get("type", "")) == "damage" and String(row.get("source_class", "")) == "hero_attack":
return row
return {}
# ---- 攻击类型 × 护甲克制 + 标错惩罚冒烟(护甲快照/克制矩阵/充能/反噬三选一)----
func _smoke_damage_types() -> void:
print("--- 攻击类型 × 护甲克制 + 标错惩罚 ---")
# ① 护甲类型快照传播(spawn 行值 → 单位字典)
var enemy_system = load("res://core/unit_container.gd").new(_db)
Kit.check("goblin 护甲 = light(轻甲——教学位)",
enemy_system.spawn(1, 0, int(_db.hero.max_hp)) and String(enemy_system.all_enemies()[0].armor_type) == "light")
var enemy_system_b = load("res://core/unit_container.gd").new(_db)
Kit.check("bugbear 护甲 = light(护甲类型重配批 2026-09-18:关卡 1 全轻甲)",
enemy_system_b.spawn(1, 2, int(_db.hero.max_hp)) and String(enemy_system_b.all_enemies()[0].armor_type) == "light")
var enemy_system_c = load("res://core/unit_container.gd").new(_db)
Kit.check("ogre_chief 护甲 = light(Boss 行集——护甲类型重配批 2026-09-18:关卡 1 全轻甲)",
enemy_system_c.spawn(1, 4, int(_db.hero.max_hp), [], -1, -1, [], "", "boss") and String(enemy_system_c.all_enemies()[0].armor_type) == "light")
# ② 克制矩阵表值在位(三档点数 克制 +1 / 中性 0 / 被克 −1,加法核非 percent)
var am: Dictionary = _db.settlement.armor_effectiveness
Kit.check("普通行:轻甲 0 / 魔法护甲 +1 / 重甲 −1(加法核)",
int(am.normal.light) == 0 and int(am.normal.ward) == 1 and int(am.normal.heavy) == -1)
Kit.check("穿刺行:轻甲 −1 / 魔法护甲 +1 / 重甲 0 中性(用户拍板)",
int(am.pierce.light) == -1 and int(am.pierce.ward) == 1 and int(am.pierce.heavy) == 0)
Kit.check("魔法行:轻甲 0 / 魔法护甲 −1 / 重甲 +1(加法核)",
int(am.magic.light) == 0 and int(am.magic.ward) == -1 and int(am.magic.heavy) == 1)
# ③ 标错(类型化负向兑付)+ 标中正向兑付(封印命中只兑格面资源正向;Boss 行多轮样本;板真相直读保证 hit/miss 确定性)
var run1 = _run_seal_backlash_round(20260912)
var miss_rows := 0
var negative_rows := 0
var hit_rows := 0
for row in run1.rows:
if row.get("type", "") == "seal_miss":
miss_rows += 1
if String(row.get("source_class", "")) == "seal_miss" and String(row.get("type", "")) in ["effect", "damage"]:
negative_rows += 1 # 标错的负向兑付行(该安全格资源的负向字典行——effect/直伤)
if String(row.get("source_class", "")) == "seal_hit":
hit_rows += 1 # 标中的正向兑付行(该危险格资源的正向字典行——标中只走格面资源正向)
Kit.check("标错封印产生 seal_miss 归因行(×%d)" % miss_rows, miss_rows >= 1)
Kit.check("标错封印兑付该安全格资源的负向字典行(×%d——attack/defense/weaken 效果行或 heal 直伤行)" % negative_rows, negative_rows >= 1)
Kit.check("封印命中兑付该危险格资源的正向字典行(×%d——充能退役后无魔法分量,正向=格面资源)" % hit_rows, hit_rows >= 1)
# ④ 同种子回放(极性路由零随机——同种子逐行相同)
var run2 = _run_seal_backlash_round(20260912)
Kit.check("标错惩罚轮回放断言:同种子步骤流逐行相同(类型化负向兑付确定性)",
JSON.stringify(run1.rows) == JSON.stringify(run2.rows))
# 构造轮:标 1 面"安全格封印"(必 miss → 该格资源负向兑付)+ 标 1 面"雷封印"(必 hit → 正向兑付 + 充能)后停手收轮。
# 返回 sealed safe 格与其 cell_type(Ready 域内查询——类型化断言的数据面)。
func _run_seal_backlash_round(seed_val: int) -> Dictionary:
var rng = load("res://core/rng_service.gd").new()
rng.set_master_seed(seed_val)
var settlement = load("res://core/battle_orchestrator.gd").new(_db, rng)
var rows: Array = []
settlement.step_row.connect(func(row): rows.append(row))
if not settlement.begin_battle({"level_index": 1, "node_depth": 4, "hero_hp": int(_db.hero.max_hp), "node_type": "boss"}):
return {"rows": rows, "safe_cell": Vector2i(-1, -1), "safe_type": ""}
var minesweeper = settlement.minesweeper
var safe_t := _find_seal_target(minesweeper, false)
var mine_t := _find_seal_target(minesweeper, true)
var safe_type := ""
if not safe_t.is_empty():
var ident = settlement.query_reward_identity(safe_t.seal_cell)
safe_type = String(ident.get("cell_type", "")) if ident != null else ""
if safe_t.hero_cell != minesweeper.hero_pos():
minesweeper.settle_batch([{"action": "move", "cell": safe_t.hero_cell}])
minesweeper.settle_batch([{"action": "seal_place", "cell": safe_t.seal_cell}])
if not mine_t.is_empty():
if mine_t.hero_cell != minesweeper.hero_pos():
minesweeper.settle_batch([{"action": "move", "cell": mine_t.hero_cell}])
minesweeper.settle_batch([{"action": "seal_place", "cell": mine_t.seal_cell}])
minesweeper.settle_batch([{"action": "stop"}])
return {"rows": rows, "safe_cell": safe_t.get("seal_cell", Vector2i(-1, -1)), "safe_type": safe_type}
# 板真相直读找封印目标:未开 + 指定雷/安全属性 + 存在可达已开邻格(测试允许读板真相——排雷玩法 冒烟同口径)
# (过渡副本——G5 四套仍消费,smoke_all.gd 原件保留;宿主侧一致副本承共享 helper 双份过渡形态,收尾批去重)
func _find_seal_target(minesweeper, want_mine: bool) -> Dictionary:
var revealed: Array = minesweeper.revealed_cells()
var revealed_set := {}
for c in revealed:
revealed_set[c] = true
for y in minesweeper.current_board().height:
for x in minesweeper.current_board().width:
var c := Vector2i(x, y)
if minesweeper.is_revealed(c) or minesweeper.has_seal(c):
continue
if minesweeper.current_board().is_mine(c) != want_mine:
continue
for n in minesweeper.current_board().neighbors8(c):
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 {}