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:
1 parent
d7def000a3
commit
855bce4534
3 files changed
+93
-63
No files matched your search
@@ -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 {}
|
||||
@@ -284,6 +284,7 @@
|
||||
- `_smoke_enemy_attack_type`(4 条):4/4 验红。变异点——enemy.tres:26 goblin attack_type normal→pierce(红唯一 1/4,越轨行 goblin:pierce);unit_container.gd:110 快照注入硬编码空串(红 3/4——快照为载荷/矩阵共同源,条3 条4 连带属预期形态);damage_controller.gd:471 敌方技载荷 attack_type 置空串(红唯一 1/4);damage_controller.gd:577 `_counter_delta` 查表短路恒中性(红唯一 1/4)。
|
||||
- `_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 矩阵证词连带属预期)。
|
||||
|
||||
## 十、支援线 9 项待裁闭合(2026-10-22 主会话裁)
|
||||
|
||||
|
||||
Reference in new issue
Block a user