工程(断言归位波1): adventure_feats+feat_vouchers+curio_refresh_paid 断言级内部直查改钉公开可观测面——adventure_feats 25 行改钉(44 命中片段:29 断言 _hits_of→测试侧本地等价过滤钉公开 fx.dispatch 返回值+5 状态钉面:信号载荷/公开查询口/件出口)+2 例外(hero_info_panel._feat_section 无公开读数口);feat_vouchers 10 改钉(pick_curio/consume_pool_purchase 真实路径×4+step_row insurance_used 行载荷×3+等价式×3)+4 例外(_pending_rap/_time_sand_queue 无公开读口,_perfect_* 判题前零态无公开面);curio_refresh_paid 7/7 全改钉(refresh_y 直换×4+gp_cost 报价公式等价式×2+free_left 恒等式×1);三套件单跑全绿(138/49/21 checks),check 调用数改前后一致零删断言,标签逐字未动,产品码零改动;例外 6 处按 §8.2 受控例外口径登记
This commit is contained in:
1 parent
d219dd3ddb
commit
5277848151
3 files changed
+99
-61
No files matched your search
@@ -44,6 +44,15 @@ func _smoke_find_token(candidates: Array, kind: String, tier: String) -> Diction
|
||||
return {}
|
||||
|
||||
|
||||
# 效果命中分桶(公开 dispatch 返回值的本地过滤——断言钉公开可观测面;编排器私有过滤器的测试侧等价承载)
|
||||
func _hits_kind(hits: Array, kind: String) -> Array:
|
||||
var out: Array = []
|
||||
for h in hits:
|
||||
if String((h as Dictionary).get("kind", "")) == kind:
|
||||
out.append(h)
|
||||
return out
|
||||
|
||||
|
||||
# ② 冒险结构 API 闸(状态机受理面——重复开始拒绝 / 入口停点 / 放弃两态)
|
||||
|
||||
|
||||
@@ -355,9 +364,11 @@ func _smoke_adventure() -> void:
|
||||
Kit.check("购买 hp_up 受理(出账 + 加算区)", r8.buy_product("hp_up"))
|
||||
var acc_shop: int = a8.journal().bonus_total("max_hp") # L1 三选一后 + 商店 3(首件随种子)
|
||||
Kit.check("统一冒险加算区含商店值(max_hp=%d ≥ 商店 3——L1 三选一件值另计)" % acc_shop, acc_shop >= 3)
|
||||
var l2_cap := {"payload": {}} # 公开信号面采集(curio_choice_presented 停点载荷——容器写回规避 lambda 按值捕获)
|
||||
a8.stop().curio_choice_presented.connect(func(p): l2_cap["payload"] = p)
|
||||
a8._on_level_finished({"result": "victory", "hp": int(r8.hero_hp), "node_index": r8.node_index,
|
||||
"node_id": r8.current_node_id(), "node_type": "shop"}) # 模拟 L2 关卡完成(victory 载荷直调——非末关)
|
||||
Kit.check("L2 关卡完成三选一停点在案(直调兑付前——零自动推进)〔拆件批 V2〕", not a8.stop()._pending.is_empty())
|
||||
Kit.check("L2 关卡完成三选一停点在案(直调兑付前——零自动推进)〔拆件批 V2〕", not (l2_cap["payload"] as Dictionary).is_empty())
|
||||
Kit.check("未兑付推进拒绝(选择停点零自动推进契约)", not a8.continue_to_next_level())
|
||||
var l2_cands: Array = a8.stop()._pending["candidates"]
|
||||
var l2_pick: Dictionary = l2_cands[0]
|
||||
@@ -438,7 +449,7 @@ func _smoke_adventure() -> void:
|
||||
a13.stop().present_node_curio([{"kind": "gp", "tier": "common"}])
|
||||
var gp13: int = a13.wallet().gp
|
||||
Kit.check("奖励节点 GP 件入账(钱包「奖励入账」收口——+%d)" % int(_db.adventure.curio_value("gp", "common")), a13.stop().apply_node_curio("gp", "common") and a13.wallet().gp == gp13 + int(_db.adventure.curio_value("gp", "common")))
|
||||
Kit.check("节点停点态兑付后清零(恰一次语义同构)", a13.stop()._node_pending.is_empty())
|
||||
Kit.check("节点停点态兑付后清零(恰一次语义同构)", (a13.stop().node_curio_pending_state().get("candidates", []) as Array).is_empty())
|
||||
var s10: Dictionary = a10.summary
|
||||
Kit.check("放弃摘要:abandoned · 未打穿(已获大奖励不追回——同失败型结算)", String(s10.get("result", "")) == "abandoned" and not bool(s10.get("cleared", true)))
|
||||
|
||||
@@ -462,7 +473,7 @@ func _smoke_feats() -> void:
|
||||
feat_tokens += 1
|
||||
var tk := String((t as Dictionary).get("tier", ""))
|
||||
tier_counts[tk] = int(tier_counts.get(tk, 0)) + 1
|
||||
Kit.check("专长带入池:30 件四级直映射(普通 12/优秀 9/稀有 9/传说 0)——牌库 102+30=132〔专长批 V2+卡② 完美保险迁入〕", feat_tokens == 30 and int(tier_counts.get("common", 0)) == 12 and int(tier_counts.get("excellent", 0)) == 9 and int(tier_counts.get("rare", 0)) == 9 and a_r0._curio.deck.size() == 132)
|
||||
Kit.check("专长带入池:30 件四级直映射(普通 12/优秀 9/稀有 9/传说 0)——牌库 102+30=132〔专长批 V2+卡② 完美保险迁入〕", feat_tokens == 30 and int(tier_counts.get("common", 0)) == 12 and int(tier_counts.get("excellent", 0)) == 9 and int(tier_counts.get("rare", 0)) == 9 and a_r0.deck().deck.size() == 132)
|
||||
# ② 旧 27 件零残留钉面(V2——arcane_ember 系旧件表首行;全仓 grep 零残留归静态核查)
|
||||
Kit.check("旧 27 件已退役:arcane_ember/magma_body 表内零残留〔专长批 V2〕", _db.feats.row_by_id("arcane_ember").is_empty() and _db.feats.row_by_id("magma_body").is_empty())
|
||||
Kit.check("迁出收尾:treasure_items 无 venom_edge/seal_burst 行(同调目录自然收窄)〔专长批 V13〕", _db.treasure_items.row_by_id("venom_edge").is_empty() and _db.treasure_items.row_by_id("seal_burst").is_empty())
|
||||
@@ -513,7 +524,7 @@ func _smoke_feats() -> void:
|
||||
for t in a_r._curio.deck:
|
||||
if String((t as Dictionary).get("kind", "")) == "relic":
|
||||
deck_relic += 1
|
||||
Kit.check("专长带入池:5 行 relic 每件 1 张(四级 rarity 直映射)——牌库 102+5=107", deck_relic == 5 and a_r._curio.deck.size() == 107)
|
||||
Kit.check("专长带入池:5 行 relic 每件 1 张(四级 rarity 直映射)——牌库 102+5=107", deck_relic == 5 and a_r.deck().deck.size() == 107)
|
||||
# 渠道白名单断言(渠道轴定位:关卡完成渠道只出专长/节点渠道零专长)
|
||||
var feat_seen: Dictionary = {}
|
||||
var node_relic_seen := false
|
||||
@@ -550,7 +561,7 @@ func _smoke_feats() -> void:
|
||||
a_t.stop()._deck.ticket_pity = int(a_t.db.adventure.feat_ticket_pity_step)
|
||||
var rg_t: RandomNumberGenerator = a_t.rng.open_stream("reward_pick")
|
||||
Kit.check("A6 保底触发(pity=5 → 第 6 次展示必出——概率无关)", a_t.deck().feat_ticket_consider(rg_t))
|
||||
Kit.check("A6 触发后清零", a_t.stop()._deck.ticket_pity == 0)
|
||||
Kit.check("A6 触发后清零", a_t.deck().ticket_pity == 0)
|
||||
a_t.stop()._deck.ticket_sold = int(a_t.db.adventure.feat_ticket_limit)
|
||||
a_t.stop()._deck.ticket_pity = int(a_t.db.adventure.feat_ticket_pity_step)
|
||||
Kit.check("A6 限购满不再触发(保底冻结)", not a_t.deck().feat_ticket_consider(rg_t))
|
||||
@@ -593,13 +604,13 @@ func _smoke_feats() -> void:
|
||||
fx.rebuild(["geologist"], [], [])
|
||||
var geo_hits: Array = fx.dispatch(orch.fx_host().counters_ctx, "dig_reveal", {"new_resource_type": true})
|
||||
apply_fx.call(geo_hits)
|
||||
Kit.check("地质学家:首开新类型集 1 点〔专长批 V3〕", orch._hits_of(geo_hits, "counter_add").size() == 1)
|
||||
Kit.check("地质学家:首开新类型集 1 点〔专长批 V3〕", _hits_kind(geo_hits, "counter_add").size() == 1)
|
||||
EffectEngine.counter_add(orch.fx_host().counters_ctx, "geo_types", 2) # 手动基数补齐(row1 已落账 1+2=3——满 4 种的预评估现值)
|
||||
var geo_hits2: Array = fx.dispatch(orch.fx_host().counters_ctx, "dig_reveal", {"new_resource_type": true})
|
||||
apply_fx.call(geo_hits2)
|
||||
Kit.check("地质学家:满 4 种(预评估现值 3+本格)→揭示 1 格·计数清零〔专长批 V3〕", orch._hits_of(geo_hits2, "reveal_tiles").size() == 1 and EffectEngine.counter(orch.fx_host().counters_ctx, "geo_types") == 0)
|
||||
Kit.check("地质学家:满 4 种(预评估现值 3+本格)→揭示 1 格·计数清零〔专长批 V3〕", _hits_kind(geo_hits2, "reveal_tiles").size() == 1 and EffectEngine.counter(orch.fx_host().counters_ctx, "geo_types") == 0)
|
||||
var geo_hits3: Array = fx.dispatch(orch.fx_host().counters_ctx, "dig_reveal", {"new_resource_type": false})
|
||||
Kit.check("地质学家反例:同类型重复首开不叠点〔专长批 V3〕", orch._hits_of(geo_hits3, "counter_add").is_empty())
|
||||
Kit.check("地质学家反例:同类型重复首开不叠点〔专长批 V3〕", _hits_kind(geo_hits3, "counter_add").is_empty())
|
||||
fx.rebuild(["hard_hat"], [], [])
|
||||
apply_fx.call(fx.dispatch(orch.fx_host().counters_ctx, "dig_reveal", {}))
|
||||
apply_fx.call(fx.dispatch(orch.fx_host().counters_ctx, "dig_reveal", {}))
|
||||
@@ -613,29 +624,29 @@ func _smoke_feats() -> void:
|
||||
fx.rebuild(["skip_mining"], [], [])
|
||||
var sk_zero: Array = fx.dispatch(orch.fx_host().counters_ctx, "dig_reveal", {"is_blank_zero": true})
|
||||
apply_fx.call(sk_zero)
|
||||
Kit.check("跳格采掘:空白 0 格攒 1 点〔专长批 V3〕", orch._hits_of(sk_zero, "counter_add").size() == 1)
|
||||
Kit.check("跳格采掘:空白 0 格攒 1 点〔专长批 V3〕", _hits_kind(sk_zero, "counter_add").size() == 1)
|
||||
EffectEngine.counter_add(orch.fx_host().counters_ctx, "skip_pts", 1) # 手动基数补齐(已落账 1+1=2——满 3 点的预评估现值)
|
||||
var sk_full: Array = fx.dispatch(orch.fx_host().counters_ctx, "dig_reveal", {"is_blank_zero": true})
|
||||
apply_fx.call(sk_full)
|
||||
Kit.check("跳格采掘:满 3 点→揭示 1 格〔专长批 V3〕", orch._hits_of(sk_full, "reveal_tiles").size() == 1)
|
||||
Kit.check("跳格采掘反例:普通开格不计点〔专长批 V3〕", orch._hits_of(fx.dispatch(orch.fx_host().counters_ctx, "dig_reveal", {"is_blank_zero": false}), "counter_add").is_empty())
|
||||
Kit.check("跳格采掘:满 3 点→揭示 1 格〔专长批 V3〕", _hits_kind(sk_full, "reveal_tiles").size() == 1)
|
||||
Kit.check("跳格采掘反例:普通开格不计点〔专长批 V3〕", _hits_kind(fx.dispatch(orch.fx_host().counters_ctx, "dig_reveal", {"is_blank_zero": false}), "counter_add").is_empty())
|
||||
fx.rebuild(["blast_accounting"], [], [])
|
||||
for i in 5:
|
||||
var ba_hits: Array = fx.dispatch(orch.fx_host().counters_ctx, "dig_paid", {"ap_cost": 1})
|
||||
for h in ba_hits:
|
||||
if String(h.get("kind", "")) == "counter_add":
|
||||
EffectEngine.counter_add(orch.fx_host().counters_ctx, String(h.get("counter_id", "")), 1)
|
||||
Kit.check("爆破会计:本轮挖格花费≥5→+1 GP〔专长批 V3〕", orch._hits_of(fx.dispatch(orch.fx_host().counters_ctx, "round_end", {}), "grant_gp").size() == 1)
|
||||
Kit.check("爆破会计:本轮挖格花费≥5→+1 GP〔专长批 V3〕", _hits_kind(fx.dispatch(orch.fx_host().counters_ctx, "round_end", {}), "grant_gp").size() == 1)
|
||||
fx.rebuild(["frontier_miner"], [], [])
|
||||
Kit.check("边陲矿工:边缘格产出 +1·中心格反例零产出〔专长批 V3〕",
|
||||
orch._hits_of(fx.dispatch(orch.fx_host().counters_ctx, "dig_reveal", {"is_edge_cell": true}), "grant_material").size() == 1
|
||||
and orch._hits_of(fx.dispatch(orch.fx_host().counters_ctx, "dig_reveal", {"is_edge_cell": false}), "grant_material").is_empty())
|
||||
_hits_kind(fx.dispatch(orch.fx_host().counters_ctx, "dig_reveal", {"is_edge_cell": true}), "grant_material").size() == 1
|
||||
and _hits_kind(fx.dispatch(orch.fx_host().counters_ctx, "dig_reveal", {"is_edge_cell": false}), "grant_material").is_empty())
|
||||
# 封印系
|
||||
fx.rebuild(["seal_echo"], [], [])
|
||||
apply_fx.call(fx.dispatch(orch.fx_host().counters_ctx, "seal_hit", {}))
|
||||
apply_fx.call(fx.dispatch(orch.fx_host().counters_ctx, "seal_hit", {}))
|
||||
var se_hits: Array = fx.dispatch(orch.fx_host().counters_ctx, "round_end", {})
|
||||
Kit.check("封印回响:标中计数≥2→轮末返 1 AP(下轮 queue)〔专长批 V3〕", orch._hits_of(se_hits, "grant_ap").size() == 1 and String((orch._hits_of(se_hits, "grant_ap")[0] as Dictionary).get("mode", "")) == "queue")
|
||||
Kit.check("封印回响:标中计数≥2→轮末返 1 AP(下轮 queue)〔专长批 V3〕", _hits_kind(se_hits, "grant_ap").size() == 1 and String((_hits_kind(se_hits, "grant_ap")[0] as Dictionary).get("mode", "")) == "queue")
|
||||
fx.rebuild(["seal_smith"], [], [])
|
||||
var sm_remove := 0
|
||||
for i in 3:
|
||||
@@ -647,10 +658,10 @@ func _smoke_feats() -> void:
|
||||
Kit.check("封印匠:标中每第 3 次→中立移除恰一次(频率闸死)〔专长批 V3〕", sm_remove == 1)
|
||||
fx.rebuild(["seal_stake"], [], [])
|
||||
Kit.check("封印桩:标中本轮 AC +N(round 域——round_start 清零)〔专长批 V3〕",
|
||||
orch._hits_of(fx.dispatch(orch.fx_host().counters_ctx, "seal_hit", {}), "ac_bonus").size() == 1
|
||||
and String((orch._hits_of(fx.dispatch(orch.fx_host().counters_ctx, "seal_hit", {}), "ac_bonus")[0] as Dictionary).get("mode", "")) == "round")
|
||||
_hits_kind(fx.dispatch(orch.fx_host().counters_ctx, "seal_hit", {}), "ac_bonus").size() == 1
|
||||
and String((_hits_kind(fx.dispatch(orch.fx_host().counters_ctx, "seal_hit", {}), "ac_bonus")[0] as Dictionary).get("mode", "")) == "round")
|
||||
fx.rebuild(["warning_beacon"], [], [])
|
||||
Kit.check("示警烟火:标中揭示 3×3 资源类型(不揭安危位置)〔专长批 V3〕", orch._hits_of(fx.dispatch(orch.fx_host().counters_ctx, "seal_hit", {}), "preview_area").size() == 1)
|
||||
Kit.check("示警烟火:标中揭示 3×3 资源类型(不揭安危位置)〔专长批 V3〕", _hits_kind(fx.dispatch(orch.fx_host().counters_ctx, "seal_hit", {}), "preview_area").size() == 1)
|
||||
# 踩雷/受伤系
|
||||
fx.rebuild(["pain_memory"], [], [])
|
||||
apply_fx.call(fx.dispatch(orch.fx_host().counters_ctx, "mine_hit", {}))
|
||||
@@ -666,13 +677,13 @@ func _smoke_feats() -> void:
|
||||
for h in fw_hits:
|
||||
if String(h.get("kind", "")) == "shield":
|
||||
fw_shield += int(h.get("value", 0))
|
||||
Kit.check("保险丝反例:单次 <5 不攒点不触发〔专长批 V3〕", orch._hits_of(fx.dispatch(orch.fx_host().counters_ctx, "damage_taken", {"kind": "terrain", "amount": 3}), "shield").is_empty())
|
||||
Kit.check("保险丝反例:单次 <5 不攒点不触发〔专长批 V3〕", _hits_kind(fx.dispatch(orch.fx_host().counters_ctx, "damage_taken", {"kind": "terrain", "amount": 3}), "shield").is_empty())
|
||||
for h in fx.dispatch(orch.fx_host().counters_ctx, "damage_taken", {"kind": "terrain", "amount": 6}):
|
||||
if String(h.get("kind", "")) == "counter_add":
|
||||
EffectEngine.counter_add(orch.fx_host().counters_ctx, String(h.get("counter_id", "")), int(h.get("value", 0)))
|
||||
Kit.check("保险丝:首点不出盾(2 点才出——预评估口径)〔专长批 V3〕", fw_shield == 0)
|
||||
fx.rebuild(["blood_insight"], [], [])
|
||||
Kit.check("见血开窍:踩雷揭示 1 格〔专长批 V3〕", orch._hits_of(fx.dispatch(orch.fx_host().counters_ctx, "mine_hit", {}), "reveal_tiles").size() == 1)
|
||||
Kit.check("见血开窍:踩雷揭示 1 格〔专长批 V3〕", _hits_kind(fx.dispatch(orch.fx_host().counters_ctx, "mine_hit", {}), "reveal_tiles").size() == 1)
|
||||
fx.rebuild(["trap_instinct"], [], [])
|
||||
apply_fx.call(fx.dispatch(orch.fx_host().counters_ctx, "mine_hit", {}))
|
||||
var ti_hits: Array = fx.dispatch(orch.fx_host().counters_ctx, "attack_commit", {"atk": 10, "target": "敌", "matchup": "", "dig_streak": 0, "nest_count": 0})
|
||||
@@ -688,67 +699,67 @@ func _smoke_feats() -> void:
|
||||
fx.rebuild(["trap_burst"], [], [])
|
||||
var tb_hits: Array = fx.dispatch(orch.fx_host().counters_ctx, "mine_hit", {"damage": 8})
|
||||
Kit.check("陷阱爆发:全体敌雷伤×倍率直伤(blast_scaled——施加面值=damage×mult)〔专长批 V3〕",
|
||||
orch._hits_of(tb_hits, "blast_scaled").size() == 1
|
||||
and float((orch._hits_of(tb_hits, "blast_scaled")[0] as Dictionary).get("mult", 0)) > 1.0)
|
||||
_hits_kind(tb_hits, "blast_scaled").size() == 1
|
||||
and float((_hits_kind(tb_hits, "blast_scaled")[0] as Dictionary).get("mult", 0)) > 1.0)
|
||||
fx.rebuild(["blood_honey"], [], [])
|
||||
Kit.check("血蜜:踩雷回复 N 生命〔专长批 V3〕", orch._hits_of(fx.dispatch(orch.fx_host().counters_ctx, "mine_hit", {}), "heal").size() == 1)
|
||||
Kit.check("血蜜:踩雷回复 N 生命〔专长批 V3〕", _hits_kind(fx.dispatch(orch.fx_host().counters_ctx, "mine_hit", {}), "heal").size() == 1)
|
||||
fx.rebuild(["stone_skin"], [], [])
|
||||
var ss_hits: Array = fx.dispatch(orch.fx_host().counters_ctx, "damage_taken", {"kind": "enemy_skill", "amount": 5, "source": "s", "round": 1})
|
||||
Kit.check("石肤:受伤 AC+1(本场域 cap 3——达上限不再涨由累积器封顶)〔专长批 V3〕",
|
||||
orch._hits_of(ss_hits, "ac_bonus").size() == 1
|
||||
and int((orch._hits_of(ss_hits, "ac_bonus")[0] as Dictionary).get("cap", 0)) == 3)
|
||||
_hits_kind(ss_hits, "ac_bonus").size() == 1
|
||||
and int((_hits_kind(ss_hits, "ac_bonus")[0] as Dictionary).get("cap", 0)) == 3)
|
||||
fx.rebuild(["last_stand"], [], [])
|
||||
Kit.check("背水:生命≤50% 减伤·过半血反例零减伤〔专长批 V3〕",
|
||||
orch._hits_of(fx.dispatch(orch.fx_host().counters_ctx, "damage_taken", {"kind": "enemy_skill", "amount": 5, "source": "s", "round": 1, "hp_ratio": 40}), "damage_reduce").size() == 1
|
||||
and orch._hits_of(fx.dispatch(orch.fx_host().counters_ctx, "damage_taken", {"kind": "enemy_skill", "amount": 5, "source": "s", "round": 2, "hp_ratio": 80}), "damage_reduce").is_empty())
|
||||
_hits_kind(fx.dispatch(orch.fx_host().counters_ctx, "damage_taken", {"kind": "enemy_skill", "amount": 5, "source": "s", "round": 1, "hp_ratio": 40}), "damage_reduce").size() == 1
|
||||
and _hits_kind(fx.dispatch(orch.fx_host().counters_ctx, "damage_taken", {"kind": "enemy_skill", "amount": 5, "source": "s", "round": 2, "hp_ratio": 80}), "damage_reduce").is_empty())
|
||||
# 跨族桥
|
||||
fx.rebuild(["breaker_strike"], [], [])
|
||||
Kit.check("破封一击:挖开带封印危险格 +1 层·无封印反例零触发〔专长批 V3〕",
|
||||
orch._hits_of(fx.dispatch(orch.fx_host().counters_ctx, "mine_hit", {"dug_under_seal": true}), "counter_add").size() == 1
|
||||
and orch._hits_of(fx.dispatch(orch.fx_host().counters_ctx, "mine_hit", {"dug_under_seal": false}), "counter_add").is_empty())
|
||||
_hits_kind(fx.dispatch(orch.fx_host().counters_ctx, "mine_hit", {"dug_under_seal": true}), "counter_add").size() == 1
|
||||
and _hits_kind(fx.dispatch(orch.fx_host().counters_ctx, "mine_hit", {"dug_under_seal": false}), "counter_add").is_empty())
|
||||
# 节奏系
|
||||
fx.rebuild(["map_exchange"], [], [])
|
||||
var me_hits: Array = fx.dispatch(orch.fx_host().counters_ctx, "dig_stop", {"ap_left": 4})
|
||||
apply_fx.call(me_hits)
|
||||
EffectEngine.counter_add(orch.fx_host().counters_ctx, "stop_swap", 4) # value_event="ap_left" 解析归施加面(action_economy 载荷取值)——冒烟手动落账
|
||||
Kit.check("弃图兑换:停手剩余 AP≥3 入账〔专长批 V3〕", orch._hits_of(me_hits, "counter_add").size() == 1)
|
||||
Kit.check("弃图兑换:停手剩余 AP≥3 入账〔专长批 V3〕", _hits_kind(me_hits, "counter_add").size() == 1)
|
||||
var me_atk := 0
|
||||
for h in orch._hits_of(fx.dispatch(orch.fx_host().counters_ctx, "attack_commit", {"atk": 10, "target": "敌", "matchup": "", "dig_streak": 0, "nest_count": 0}), "attack_bonus"):
|
||||
me_atk = EffectEngine.counter(orch.fx_host().counters_ctx, String(h.get("value_counter", "")))
|
||||
Kit.check("弃图兑换:折为攻击伤害=剩余 AP 全额·用后清零〔专长批 V3〕", me_atk == 4)
|
||||
Kit.check("弃图兑换反例:剩余 AP<3 不触发〔专长批 V3〕", orch._hits_of(fx.dispatch(orch.fx_host().counters_ctx, "dig_stop", {"ap_left": 2}), "counter_add").is_empty())
|
||||
Kit.check("弃图兑换反例:剩余 AP<3 不触发〔专长批 V3〕", _hits_kind(fx.dispatch(orch.fx_host().counters_ctx, "dig_stop", {"ap_left": 2}), "counter_add").is_empty())
|
||||
fx.rebuild(["last_drop"], [], [])
|
||||
var ld_hits: Array = fx.dispatch(orch.fx_host().counters_ctx, "round_start", {"round": 2, "ap_exhausted_last": true})
|
||||
Kit.check("一滴不剩:上轮 AP 耗尽→+1 AP〔专长批 V3〕", orch._hits_of(ld_hits, "grant_ap").size() == 1)
|
||||
Kit.check("一滴不剩反例:上轮有余不发〔专长批 V3〕", orch._hits_of(fx.dispatch(orch.fx_host().counters_ctx, "round_start", {"round": 3, "ap_exhausted_last": false}), "grant_ap").is_empty())
|
||||
Kit.check("一滴不剩:上轮 AP 耗尽→+1 AP〔专长批 V3〕", _hits_kind(ld_hits, "grant_ap").size() == 1)
|
||||
Kit.check("一滴不剩反例:上轮有余不发〔专长批 V3〕", _hits_kind(fx.dispatch(orch.fx_host().counters_ctx, "round_start", {"round": 3, "ap_exhausted_last": false}), "grant_ap").is_empty())
|
||||
fx.rebuild(["market_close"], [], [])
|
||||
for i in 8:
|
||||
for h in fx.dispatch(orch.fx_host().counters_ctx, "dig_reveal", {}):
|
||||
if String(h.get("kind", "")) == "counter_add":
|
||||
EffectEngine.counter_add(orch.fx_host().counters_ctx, String(h.get("counter_id", "")), 1)
|
||||
Kit.check("收盘:本轮开格≥8→+1 GP〔专长批 V3〕", orch._hits_of(fx.dispatch(orch.fx_host().counters_ctx, "round_end", {}), "grant_gp").size() == 1)
|
||||
Kit.check("收盘:本轮开格≥8→+1 GP〔专长批 V3〕", _hits_kind(fx.dispatch(orch.fx_host().counters_ctx, "round_end", {}), "grant_gp").size() == 1)
|
||||
# 战斗系
|
||||
fx.rebuild(["execution_scholar"], [], [])
|
||||
Kit.check("斩首学者:击杀揭示 1 格〔专长批 V3〕", orch._hits_of(fx.dispatch(orch.fx_host().counters_ctx, "kill", {"target": "敌", "overflow": 0}), "reveal_tiles").size() == 1)
|
||||
Kit.check("斩首学者:击杀揭示 1 格〔专长批 V3〕", _hits_kind(fx.dispatch(orch.fx_host().counters_ctx, "kill", {"target": "敌", "overflow": 0}), "reveal_tiles").size() == 1)
|
||||
fx.rebuild(["executioner"], [], [])
|
||||
var ex_hits: Array = fx.dispatch(orch.fx_host().counters_ctx, "enemy_hp_threshold", {"unit": "e1", "pct": 30, "is_boss": false})
|
||||
Kit.check("处刑台:敌血量≤30% 挂单位标记加伤·阈值外反例零命中〔专长批 V3〕",
|
||||
orch._hits_of(ex_hits, "target_attack_bonus").size() == 1
|
||||
and orch._hits_of(fx.dispatch(orch.fx_host().counters_ctx, "enemy_hp_threshold", {"unit": "e1", "pct": 60, "is_boss": false}), "target_attack_bonus").is_empty())
|
||||
_hits_kind(ex_hits, "target_attack_bonus").size() == 1
|
||||
and _hits_kind(fx.dispatch(orch.fx_host().counters_ctx, "enemy_hp_threshold", {"unit": "e1", "pct": 60, "is_boss": false}), "target_attack_bonus").is_empty())
|
||||
fx.rebuild(["field_dressing"], [], [])
|
||||
Kit.check("战地包扎:战斗胜利回复 N 生命(battle_won 新挂点)〔专长批 V3〕", orch._hits_of(fx.dispatch(orch.fx_host().counters_ctx, "battle_won", {"round": 2}), "heal").size() == 1)
|
||||
Kit.check("战地包扎:战斗胜利回复 N 生命(battle_won 新挂点)〔专长批 V3〕", _hits_kind(fx.dispatch(orch.fx_host().counters_ctx, "battle_won", {"round": 2}), "heal").size() == 1)
|
||||
# 契约尖点
|
||||
fx.rebuild(["blood_tax"], [], [])
|
||||
Kit.check("血税:双向同局账本(踩陷阱−2max_hp/封印命中+1atk——bonus_delta 战末汇入)〔专长批 V3〕",
|
||||
orch._hits_of(fx.dispatch(orch.fx_host().counters_ctx, "mine_hit", {}), "bonus_delta").size() == 1
|
||||
and String((orch._hits_of(fx.dispatch(orch.fx_host().counters_ctx, "seal_hit", {}), "bonus_delta")[0] as Dictionary).get("axis", "")) == "atk")
|
||||
_hits_kind(fx.dispatch(orch.fx_host().counters_ctx, "mine_hit", {}), "bonus_delta").size() == 1
|
||||
and String((_hits_kind(fx.dispatch(orch.fx_host().counters_ctx, "seal_hit", {}), "bonus_delta")[0] as Dictionary).get("axis", "")) == "atk")
|
||||
# 迁入 2 件
|
||||
fx.rebuild(["venom_edge"], [], [])
|
||||
Kit.check("淬毒刃纹(迁入):克制正面(magic_vs_heavy 矩阵值>0)追加·中性面反例零触发〔专长批 V3〕",
|
||||
orch._hits_of(fx.dispatch(orch.fx_host().counters_ctx, "clamp_check", {"matchup": "magic_vs_heavy"}), "modify_ticket").size() == 1
|
||||
and orch._hits_of(fx.dispatch(orch.fx_host().counters_ctx, "clamp_check", {"matchup": "normal_vs_light"}), "modify_ticket").is_empty())
|
||||
_hits_kind(fx.dispatch(orch.fx_host().counters_ctx, "clamp_check", {"matchup": "magic_vs_heavy"}), "modify_ticket").size() == 1
|
||||
and _hits_kind(fx.dispatch(orch.fx_host().counters_ctx, "clamp_check", {"matchup": "normal_vs_light"}), "modify_ticket").is_empty())
|
||||
fx.rebuild(["seal_burst"], [], [])
|
||||
Kit.check("封印爆裂(迁入):标中全体敌群伤〔专长批 V3〕", orch._hits_of(fx.dispatch(orch.fx_host().counters_ctx, "seal_hit", {}), "open_ticket").size() == 1)
|
||||
Kit.check("封印爆裂(迁入):标中全体敌群伤〔专长批 V3〕", _hits_kind(fx.dispatch(orch.fx_host().counters_ctx, "seal_hit", {}), "open_ticket").size() == 1)
|
||||
# 零持有
|
||||
var orch0 = load("res://core/battle_orchestrator.gd").new(_db, _fresh_rng(74))
|
||||
orch0.fx_host().rebuild_subscriptions([], [], [])
|
||||
|
||||
@@ -28,20 +28,21 @@ func _init() -> void:
|
||||
Kit.check_quiet(adr.stop().curio_stop_pending() == true, "关卡完成停点在途=谓词 true")
|
||||
adr.refresh_bank()._refresh_x = 1
|
||||
adr.refresh_bank()._refresh_y = 2
|
||||
Kit.check_quiet(adr.stop().refresh_curio() and adr.refresh_bank()._refresh_x == 0 and adr.refresh_bank()._refresh_y == 2, "X 优先消耗(x1y2→x0y2)")
|
||||
Kit.check_quiet(adr.stop().refresh_curio() and adr.refresh_bank()._refresh_y == 1, "X 穷转 Y 池(y2→y1)")
|
||||
Kit.check_quiet(adr.stop().refresh_curio() and adr.refresh_bank().refresh_y() == 2
|
||||
and adr.refresh_bank().free_left() == adr.refresh_bank().refresh_y() + adr.refresh_bank().refresh_stock(), "X 优先消耗(x1y2→x0y2)")
|
||||
Kit.check_quiet(adr.stop().refresh_curio() and adr.refresh_bank().refresh_y() == 1, "X 穷转 Y 池(y2→y1)")
|
||||
|
||||
# ---- ③ GP 付费档:计数递增爬价 + 零触碰免费位 ----
|
||||
Kit.check_quiet(adr.refresh_bank().gp_cost() == base, "首刷报价=基价(免费位尚余 y1,报价独立于免费位)")
|
||||
Kit.check_quiet(adr.stop().refresh_curio_paid() and adr.refresh_bank()._refresh_y == 1, "付费刷新不触碰免费位(y1 保持)")
|
||||
Kit.check_quiet(adr.stop().refresh_curio_paid() and adr.refresh_bank().refresh_y() == 1, "付费刷新不触碰免费位(y1 保持)")
|
||||
Kit.check_quiet(adr.refresh_bank().gp_cost() == int(ceil(float(base) * curve)), "二刷价爬升=ceil(基价×曲线)(已付费刷=1)")
|
||||
Kit.check_quiet(adr.stop().refresh_curio_paid() and adr.refresh_bank().gp_cost() == int(ceil(float(base) * curve * curve)), "三刷价再爬升=ceil(基价×曲线²)(已付费刷=2)")
|
||||
|
||||
# ---- ④ 停点重建清零付费计数(对齐商店进店清零——不结转)----
|
||||
adr.stop().present_node_curio(_cands())
|
||||
Kit.check_quiet(adr.refresh_bank()._paid_refreshes == 0 and adr.refresh_bank().gp_cost() == base, "节点停点重建=付费计数清零回基价")
|
||||
Kit.check_quiet(adr.refresh_bank().gp_cost() == base, "节点停点重建=付费计数清零回基价")
|
||||
adr.stop().refresh_curio_paid()
|
||||
Kit.check_quiet(adr.refresh_bank()._paid_refreshes == 1, "付费刷新计数在途递增(=1)")
|
||||
Kit.check_quiet(adr.refresh_bank().gp_cost() == int(ceil(float(base) * curve)), "付费刷新计数在途递增(=1)")
|
||||
adr.stop().present_node_curio(_cands())
|
||||
Kit.check_quiet(adr.refresh_bank().gp_cost() == base, "再碰三选一付费计数仍清零(同 X 余量不结转口径)")
|
||||
|
||||
@@ -56,10 +57,10 @@ func _init() -> void:
|
||||
var bp_y := {"level_index": 1, "hero_hp": 10, "attune_refresh_y": 2, "graph_gen_v2": 1}
|
||||
var adr_r = load("res://core/adventure_runner.gd").new(db, load("res://core/rng_service.gd").new())
|
||||
Kit.check_quiet(adr_r.resume_adventure(bp_y, {"hero_override": {}, "attune_refresh_y": 3}), "续玩受理(最小断点+参数面)")
|
||||
Kit.check_quiet(adr_r.refresh_bank()._refresh_y == 2, "断点有键=Y 余量随断点还原(花 1 剩 2——不再整额重注入=满血复活堵死)")
|
||||
Kit.check_quiet(adr_r.refresh_bank().refresh_y() == 2, "断点有键=Y 余量随断点还原(花 1 剩 2——不再整额重注入=满血复活堵死)")
|
||||
var adr_o = load("res://core/adventure_runner.gd").new(db, load("res://core/rng_service.gd").new())
|
||||
Kit.check_quiet(adr_o.resume_adventure({"level_index": 1, "hero_hp": 10, "graph_gen_v2": 1}, {"hero_override": {}, "attune_refresh_y": 3}), "旧断点续玩受理(快照缺键)")
|
||||
Kit.check_quiet(adr_o.refresh_bank()._refresh_y == 3, "旧断点缺键=回退参数面整额注入(旧档行为零变化)")
|
||||
Kit.check_quiet(adr_o.refresh_bank().refresh_y() == 3, "旧断点缺键=回退参数面整额注入(旧档行为零变化)")
|
||||
|
||||
quit(Kit.finish("curio_refresh_paid"))
|
||||
|
||||
|
||||
@@ -32,8 +32,9 @@ func _init() -> void:
|
||||
|
||||
# V9-1 刷新券:入存量账(冒险级)——反例=写进 _attune_refresh_x(X 每停点重置会吞存量)
|
||||
a.refresh_bank().reset_x() # X 归零基线(模拟新停点)
|
||||
Kit.check_quiet(a.stop()._apply_curio_pick("refresh", "excellent", 1), "刷新券兑付受理〔专长批 V9〕")
|
||||
Kit.check_quiet(a.refresh_bank().refresh_stock() == 1 and a.refresh_bank()._refresh_x == 0,
|
||||
a.stop()._pending = {"candidates": [{"kind": "refresh", "tier": "excellent"}]} # 停点候选直写(构造面——pick_curio 真实入口前置)
|
||||
Kit.check_quiet(a.stop().pick_curio("refresh", "excellent"), "刷新券兑付受理〔专长批 V9〕")
|
||||
Kit.check_quiet(a.refresh_bank().refresh_stock() == 1 and a.refresh_bank().free_left() == a.refresh_bank().refresh_stock() + a.refresh_bank().refresh_y(),
|
||||
"F-1 修复:刷新券入存量账、X 账零写入(写错账反例不复发)〔专长批 V9〕")
|
||||
a.refresh_bank().reset_x() # 再碰停点——X 重置但存量不吞
|
||||
Kit.check_quiet(a.refresh_bank().refresh_stock() == 1 and a.refresh_bank().free_left() == 1,
|
||||
@@ -50,19 +51,21 @@ func _init() -> void:
|
||||
Kit.check_quiet(deck_refresh_before == 0 or true, "牌库 refresh 令牌读数在域(投放 %d)" % deck_refresh_before)
|
||||
|
||||
# V9-2 储备金袋:待注入账 + 战首注入(节点级)
|
||||
Kit.check_quiet(a.stop()._apply_curio_pick("rap", "rare", 3), "储备金袋兑付受理〔专长批 V9〕")
|
||||
a.stop()._pending = {"candidates": [{"kind": "rap", "tier": "rare"}]} # 停点候选直写(构造面——pick_curio 真实入口前置)
|
||||
Kit.check_quiet(a.stop().pick_curio("rap", "rare"), "储备金袋兑付受理〔专长批 V9〕")
|
||||
Kit.check_quiet(a.stop()._pending_rap == 3, "储备金袋:待注入 RAP +3(节点级账)〔专长批 V9〕")
|
||||
|
||||
# V9-3 时沙:下一战首轮 AP 队列(回合级池增量)
|
||||
Kit.check_quiet(a.stop()._apply_curio_pick("time_sand", "rare", 2), "时沙兑付受理〔专长批 V9〕")
|
||||
a.stop()._pending = {"candidates": [{"kind": "time_sand", "tier": "rare"}]} # 停点候选直写(构造面——pick_curio 真实入口前置)
|
||||
Kit.check_quiet(a.stop().pick_curio("time_sand", "rare"), "时沙兑付受理〔专长批 V9〕")
|
||||
Kit.check_quiet(a.stop()._time_sand_queue == 2, "时沙:首轮 AP 队列 +2(池增量非上限)〔专长批 V9〕")
|
||||
|
||||
# V23 两件出池(R1——同调电池删除/完美保险迁专长)
|
||||
Kit.check_quiet(not db.adventure.CURIO_KINDS.has("attune_battery")
|
||||
and not db.adventure.CURIO_KINDS.has("perfect_insurance"),
|
||||
"出池词表:CURIO_KINDS 零两件(三选一池物理不可再出)〔卡② R1〕")
|
||||
Kit.check_quiet(not a.stop()._apply_curio_pick("attune_battery", "rare", 1)
|
||||
and not a.stop()._apply_curio_pick("perfect_insurance", "rare", 1),
|
||||
Kit.check_quiet(not a.stop().consume_pool_purchase("attune_battery", "rare")
|
||||
and not a.stop().consume_pool_purchase("perfect_insurance", "rare"),
|
||||
"出池反例:两件兑付不再受理(牌库无令牌=拒绝零副作用)〔卡② R1〕")
|
||||
Kit.check_quiet(not a.has_method("choose_battery_target") and not a.has_method("battery_pending"),
|
||||
"电池符号清零:runner 无点选函数与 getter(编译级孤儿面)〔卡② R1〕")
|
||||
@@ -73,7 +76,11 @@ func _init() -> void:
|
||||
a._loadout.set_attunement(["incense_stick"])
|
||||
a._loadout_seeded = false # 模拟首关 bind 时点(分派走 seed_for_adventure 分支)
|
||||
a._loadout_on_level_inventory() # 种行(首关 bind 时点语义)
|
||||
Kit.check_quiet(a._loadout.charges_left("incense_stick", a.runner().treasure_inventory) == 1,
|
||||
var incense_left := 0
|
||||
for r in a.runner().treasure_inventory.snapshot_inventory():
|
||||
if String(r.get("item_id", "")) == "incense_stick" and String(r.get("source_class", "")) == "attunement" and not bool(r.get("used", false)):
|
||||
incense_left += 1
|
||||
Kit.check_quiet(incense_left == 1,
|
||||
"账本保留:种行按装备表值投行(线香 battle 级 1——attune_charges 语义零变化)〔卡② R1〕")
|
||||
# V24 配额净删锚(R3——「净删」口径,rare 9→7/总量 104→102)
|
||||
var rare_sum := 0
|
||||
@@ -99,7 +106,7 @@ func _init() -> void:
|
||||
a._curio.deck = [{"kind": "gp", "tier": "common"}, {"kind": "heal", "tier": "excellent"}]
|
||||
a.stop()._pending = {"candidates": [{"kind": "gp", "tier": "common"}]}
|
||||
var gp_taken_before := int(a._curio.taken.get("gp", 0))
|
||||
Kit.check_quiet(a.stop().pick_curio("gp", "common") and int(a._curio.taken.get("gp", 0)) == gp_taken_before + 1,
|
||||
Kit.check_quiet(a.stop().pick_curio("gp", "common") and int(a.deck().taken.get("gp", 0)) == gp_taken_before + 1,
|
||||
"留任小GP 袋:GP 通道兑付受理(gp 计数入账——路由零变化)〔专长批 V10〕")
|
||||
var hp_before: int = a.stats().hero_hp
|
||||
a.stop()._pending = {"candidates": [{"kind": "heal", "tier": "excellent"}]}
|
||||
@@ -165,17 +172,30 @@ func _init() -> void:
|
||||
if safe_cells.size() >= 2:
|
||||
break
|
||||
Kit.check_quiet(safe_cells.size() == 2, "保险 rig:两枚安全格定位(去重闸按格实例——限次样本须异格)〔卡② R2〕")
|
||||
var rows_orch: Array[Dictionary] = []
|
||||
orch.step_row.connect(func(row): rows_orch.append(row)) # step_row 公开信号面(insurance_used 载荷/seal_miss highlight=豁免账与误标账观测面)
|
||||
Kit.check_quiet(int(orch._perfect_hit_false) == 0 and int(orch._perfect_forgiven) == 0,
|
||||
"保险前置:误标账与豁免账双零起〔卡② R2〕")
|
||||
orch._grant_seg._judge_seal({"cell": safe_cells[0], "hit": false}, 1)
|
||||
Kit.check_quiet(int(orch._perfect_hit_false) == 1,
|
||||
"计数纯净:首次标错 _perfect_hit_false 落 1 未被回退改写(契约 2)〔卡② R2〕")
|
||||
Kit.check_quiet(int(orch._perfect_forgiven) == 1,
|
||||
var ins_row := {}
|
||||
for r in rows_orch:
|
||||
if String(r.get("effect_id", "")) == "insurance_used":
|
||||
ins_row = r
|
||||
Kit.check_quiet(not ins_row.is_empty() and int(ins_row.get("forgiven", -1)) == 1,
|
||||
"豁免一次:首次标错 _perfect_forgiven=1(forgive_seal_miss 派发)〔卡② R2〕")
|
||||
Kit.check_quiet(int(orch.action_economy.pending_ap_delta()) == 1,
|
||||
"事件不吞:同一标错的 seal_missed 仍被危险直觉·守收到(queue AP+1)〔卡② R2〕")
|
||||
orch._grant_seg._judge_seal({"cell": safe_cells[1], "hit": false}, 2)
|
||||
Kit.check_quiet(int(orch._perfect_hit_false) == 2 and int(orch._perfect_forgiven) == 1,
|
||||
var ins_count := 0
|
||||
var miss_hl_last := ""
|
||||
for r in rows_orch:
|
||||
if String(r.get("effect_id", "")) == "insurance_used":
|
||||
ins_count += 1
|
||||
if String(r.get("type", "")) == "seal_miss":
|
||||
miss_hl_last = String(r.get("highlight", ""))
|
||||
Kit.check_quiet(ins_count == 1 and miss_hl_last == "perfect_broken",
|
||||
"限次:第二次标错不获豁免(forgiven 恒 1——when counter lt 1)〔卡② R2〕")
|
||||
Kit.check_quiet(not orch.perfect_sweep_earned(),
|
||||
"判定相减:误标 2 − 豁免 1 = 有效 1 → 完美不成立〔卡② R2 真值表〕")
|
||||
@@ -195,9 +215,15 @@ func _init() -> void:
|
||||
"bonus_ref": {"atk": 0, "max_hp": 0, "armor_class": 0}, "adventure_counters": {},
|
||||
"voucher_rap": 0, "voucher_time_sand": 0, "node_type": "battle"}),
|
||||
"次战 rig:第二战编排启动(feats 同件)〔卡② R2〕")
|
||||
var rows_orch2: Array[Dictionary] = []
|
||||
orch2.step_row.connect(func(row): rows_orch2.append(row)) # step_row 公开信号面(insurance_used 载荷=豁免账观测面)
|
||||
var sc2 = safe_cells[0]
|
||||
orch2._grant_seg._judge_seal({"cell": sc2, "hit": false}, 1)
|
||||
Kit.check_quiet(int(orch2._perfect_forgiven) == 1 and int(orch2._perfect_hit_false) == 1,
|
||||
var ins_row2 := {}
|
||||
for r in rows_orch2:
|
||||
if String(r.get("effect_id", "")) == "insurance_used":
|
||||
ins_row2 = r
|
||||
Kit.check_quiet(not ins_row2.is_empty() and int(ins_row2.get("forgiven", -1)) == 1,
|
||||
"跨战清零:domain=battle 豁免账每战重建——次战首次标错再豁免一次〔卡② R2〕")
|
||||
Kit.check_quiet(EffectEngineKindProbe(db), "词表闭集:forgive_seal_miss 在 EFFECT_KINDS(出域即加载致命——扩签合规)〔卡② R4〕")
|
||||
|
||||
|
||||
Reference in new issue
Block a user