extends RefCounted # 用例:BalanceData 载入 + 跨表引用 + CSV/Bible 关键值(数据门) func run(a, data: BalanceData) -> void: a.true_(data.load_errors.is_empty(), "load_errors 为空(%s)" % str(data.load_errors)) a.eq(data.generators.size(), 12, "12 班底") a.eq(data.upgrades.size(), 108, "108 升级") a.eq(data.meta_upgrades.size(), 12, "12 宿慧商品") a.eq(data.halls.size(), 10, "10 殿") a.eq(data.palettes.size(), 10, "10 色板") a.eq(data.bosses.size(), 10, "10 殿王战") a.eq(data.events.size(), 4, "4 事件") # 关键数值(Balance Bible v1.0 逐值一致) a.near(data.generators[11].base_rate, 1073741824.0, 0.5, "gen12 rate = 8^10") a.near(data.generators[1].payback_seconds(), 120.0, 0.5, "gen2 回本 120s") a.near(data.generators[5].payback_seconds(), 293.0, 0.5, "gen6 回本 293s") a.near(data.generators[11].payback_seconds(), 1118.0, 0.5, "gen12 回本 1118s") a.near(data.hall_by_no(1).gate_merit, 2000.0, 0.5, "H1 门 2K") a.near(data.hall_by_no(10).gate_merit, 1.5e9, 0.5, "H10 门 1.5B") a.true_(data.hall_by_no(10).is_prestige_gate, "H10 = prestige 门") a.near(data.boss_for_hall("hall_01_qinguang").boss_army_seconds, 23.0, 1e-9, "H1 殿王军列单推秒数 S_1 = 23(方案 B;旧 HP 系数 15 已废止)") a.near(data.boss_for_hall("hall_10_zhuanlun").boss_army_seconds, 28.0, 1e-9, "H10 殿王军列单推秒数 S_10 = 28") a.eq(data.boss_for_hall("hall_01_qinguang").souls_par, 0, "H1 超度基准 0(无开场加成)") a.eq(data.boss_for_hall("hall_10_zhuanlun").souls_par, 90000, "H10 超度基准 90000") # 敕封诏书(P-12:requires = enthrone_ready) var edict := data.upgrade("up_gate_tianzi") a.true_(edict != null, "敕封诏书存在") a.eq(edict.requires, "enthrone_ready", "诏书 requires = enthrone_ready") a.eq(edict.cost, 800000000000, "诏书成本 800B") # 调参数(balance_tuning) a.near(data.tune_num("tune_souls_div", 0.0), 10000.0, 1e-9, "超度除数 10000") a.near(data.tune_num("tune_enthrone_suihui_req", 0.0), 60.0, 1e-9, "敕封宿慧门槛 60") a.near(data.tune_num("tune_enthrone_rebirths", 0.0), 2.0, 1e-9, "敕封转世门槛 2") a.eq(data.tune_text("tune_restart_curve", ""), "1:0.48:0.42:0.40", "重开曲线文本(v1.1 校准值)") a.near(data.tune_num("tune_wrath_layers", 0.0), 22.0, 1e-9, "冤煞 22 层") a.near(data.tune_num("tune_click_base", 0.0), 1.0, 1e-9, "点击基础值 1") # W5 裁定调参(sim 一轮裁定 §2.3/§2.4):宿慧渐近 + 跳过封顶 + 削减速加深 a.near(data.tune_num("tune_suihui_global_max", 0.0), 0.5, 1e-9, "宿慧渐近上限 0.50") a.near(data.tune_num("tune_suihui_global_scale", 0.0), 420.0, 1e-9, "宿慧衰减尺度 420") a.near(data.tune_num("tune_skip_level_cap_per_gen", 0.0), 50.0, 1e-9, "跳过每档封顶 50") a.near(data.tune_num("tune_wrath_penalty", 0.0), 0.04, 1e-9, "削减速 4%/层") a.near(data.tune_num("tune_wrath_penalty_cap", 0.0), 0.4, 1e-9, "削减速封顶 40%") a.false_(data.has_tune("tune_wrath_bonus"), "tune_wrath_bonus 已迁入 wrath_layers.csv") a.false_(data.has_tune("tune_wrath_cost_base"), "tune_wrath_cost_base 已迁入 wrath_layers.csv") a.false_(data.has_tune("tune_wrath_cost_exp"), "tune_wrath_cost_exp 已迁入 wrath_layers.csv") a.false_(data.has_tune("tune_suihui_global_pct"), "tune_suihui_global_pct 已被渐近公式取代") # W5 G-1:冤煞层表(22 行;m07/m08 联动) a.eq(data.wrath_layers.size(), 22, "wrath_layers 22 行") a.near(data.wrath_layers[0].effect, 0.15, 1e-9, "L1 effect 0.15") a.near(data.wrath_layers[14].effect, 0.15, 1e-9, "L15 effect 0.15") a.near(data.wrath_layers[15].effect, 0.0, 1e-9, "L16 effect 0(归零)") a.eq(data.wrath_layers[0].cost, 8, "L1 成本 8") a.eq(data.wrath_layers[21].cost, 2087, "L22 成本 2087") var m07 := data.meta("meta_07") a.near(m07.effect_param, 0.20, 1e-9, "m07 削减 40%→20%(W5 联动)") a.eq(data.meta("meta_08").name_cn, "幽冥恩荫", "m08 更名幽冥恩荫(P-4 消歧)") # W5 裁定 P-28:halls 到达目标列新值(H10 保持 180;殿门阈值不动) var expect_targets := [10, 20, 36, 56, 80, 102, 122, 142, 164, 180] for i in expect_targets.size(): a.eq(int(data.halls[i].target_min), expect_targets[i], "H%d 到达目标 %d min" % [i + 1, expect_targets[i]]) a.near(data.halls[0].gate_merit, 2000.0, 0.5, "H1 殿门阈值不动(2K)") a.near(data.halls[9].gate_merit, 1.5e9, 0.5, "H10 殿门阈值不动(1.5B)") # 跨表引用完整性(schema 管单表;这里查跨表) a.true_(data.check_references().is_empty(), "跨表引用无悬挂(%s)" % str(data.check_references())) # 每殿恰一场殿王战 + 色板 for h in data.halls: a.true_(data.boss_for_hall(h.id) != null, "%s 有 boss 行" % h.id) a.true_(data.palette_for_hall(h.id) != null, "%s 有色板行" % h.id)