Boss 战修复(Plan B,用户拍板): - HP 公式 15xPxhall_factor -> HP = P x boss_army_seconds_n(S=23.0→28.0 递增, 每场军列约 23-28 秒清空,战斗时长成为可直接书写的设计旋钮,结构性消除 高殿 P 抵消导致不可胜的旧 bug);hall_factor 降级为纯叙事/视觉参数 - 新增 souls_par 列(0→90000):开场冲锋 intro_dmg = HP x 10% x clamp(souls/souls_par,0,1), 上限 20%->10%;删 hp_factor/intro_dmg_souls_factor/intro_dmg_cap_ratio 三列 - 点击伤害 P x κ x combo_mult,κ = (0.010 + 0.052 x click_ratio) x (1 + 0.30 x m06_owned), click_ratio = 已购点击升级 / 12(κ 0.010→0.0806,满配点击占比约 20.5%±3pp) - 防双重计入:L5-12 点击升级 +1% output/s 留全局区(抬 P 同时抬军列 DPS 与点击 伤害,可接受),不得再计入 κ 分子(recompute 注释固化) 离线契约 v2(P-8,改契约不改表): - OfflineModel.settle 第三参 offline_mult -> offline_add(加法);各档效率 min(rate+add, 1.0) 硬顶 100%,离线永不超在线 - 长明灯 x1.15 乘性 -> +5%/级 加法(满级 +30%,各档封顶 100%) - 0-2h 100% 保持;8h = 6.2 等效小时(77.5% 效率) - Gate #9 拆 9a/9b/9c:9a FAIL->PASS(0-2h 全额 + 8h∈[5.5,6.5]), 9b 长明灯满级 8h∈[7.5,8.0] 且 ≤100%,9c 任意配置效率 ≤100% 数据与工具: - gen_balance_sheets.py 补登 W3 遗留 7 行 tune(防重跑静默丢失),self_check 更新 - boss_battles/upgrades schema 同步(offline_mult->offline_add enum,漏改会违反导入) 测试(runner 7->8 用例,Node 交叉验证 145 断言全过): - 可胜性哨兵重写为「十殿全可胜」:每殿 S_n<30、军列+点击≥HP、余时∈[2,8]、 满配余时差≥4、点击占比∈[15,25]、H10≈20.5%±3pp - κ 四档断言(0.010/0.036/0.062/0.0806,分母 12) - 新增 test_offline_contract.gd:契约 v2 数值面 + 9a/9b/9c 全 PASS + β 缓议
169 lines
6.7 KiB
GDScript
169 lines
6.7 KiB
GDScript
extends RefCounted
|
||
|
||
# 用例:EconomyState 状态机(点击/购买/殿门/冤气/prestige/敕封)
|
||
|
||
func run(a, data) -> void:
|
||
_test_first_purchase(a, data)
|
||
_test_hall_gate(a, data)
|
||
_test_upgrades_and_meta(a, data)
|
||
_test_wrath(a, data)
|
||
_test_prestige(a, data)
|
||
_test_enthrone(a, data)
|
||
_test_event_and_offline(a, data)
|
||
|
||
|
||
# ---- 首购循环:15 点击 → 买 gen1 → 产出 0.1/s(GDD demo 验证点)----
|
||
func _test_first_purchase(a, data) -> void:
|
||
var e := EconomyState.new(data)
|
||
a.near(e.merit, 0.0, 1e-9, "初始阴德 0")
|
||
a.near(e.output_per_sec(), 0.0, 1e-9, "初始产出 0")
|
||
for _i in 15:
|
||
e.click()
|
||
a.near(e.merit, 15.0, 1e-9, "15 次点击 = 15 阴德")
|
||
a.near(e.click_value(), 1.0, 1e-9, "点击价值 = 1")
|
||
var r: Dictionary = e.buy_generator(0, 1)
|
||
a.true_(bool(r.get("ok", false)), "15 阴德可买游魂×1")
|
||
a.eq(e.gen_levels[0], 1, "游魂 1 级")
|
||
a.near(e.merit, 0.0, 1e-9, "买后阴德 0")
|
||
a.near(e.output_per_sec(), 0.1, 1e-9, "产出 0.1/s")
|
||
var r2: Dictionary = e.buy_generator(0, 1)
|
||
a.true_(not bool(r2.get("ok", false)), "0 阴德再买失败")
|
||
e.merit = 100.0
|
||
var r3: Dictionary = e.buy_upgrade("up_click_1")
|
||
a.true_(bool(r3.get("ok", false)), "买指诀·倍力 I(50)")
|
||
a.near(e.click_value(), 2.0, 1e-9, "点击价值 ×2")
|
||
|
||
|
||
# ---- 殿门单计数器闸门 ----
|
||
func _test_hall_gate(a, data) -> void:
|
||
var e := EconomyState.new(data)
|
||
a.false_(e.generator_unlocked(2), "gen3 初始锁定")
|
||
e.merit_run_total = 1999.0
|
||
e.tick(0.1)
|
||
a.eq(e.halls_passed, 0, "1999 不过 H1")
|
||
e.merit_run_total = 2000.0
|
||
e.tick(0.1)
|
||
a.eq(e.halls_passed, 1, "2000 过 H1(单计数器闸门)")
|
||
a.true_(e.upgrade_visible(data.upgrade("up_eff_gen_03_guizu_1")), "H1 后 gen3 效率可见")
|
||
a.true_(e.upgrade_visible(data.upgrade("up_gate_guizu")), "H1 后入职文书可见")
|
||
a.false_(e.generator_unlocked(2), "过殿但未买文书 → gen3 仍锁")
|
||
e.merit = 1000.0
|
||
var r: Dictionary = e.buy_upgrade("up_gate_guizu")
|
||
a.true_(bool(r.get("ok", false)), "买鬼卒班入职文书(800)")
|
||
a.true_(e.generator_unlocked(2), "双闸齐 → gen3 解锁")
|
||
var r2: Dictionary = e.buy_generator(2, 1)
|
||
a.true_(bool(r2.get("ok", false)), "gen3 可购")
|
||
|
||
|
||
# ---- 升级/宿慧商店 ----
|
||
func _test_upgrades_and_meta(a, data) -> void:
|
||
var e := EconomyState.new(data)
|
||
e.suihui = 10
|
||
var r: Dictionary = e.buy_meta("meta_01")
|
||
a.true_(bool(r.get("ok", false)), "买枕旧梦(3 宿慧)")
|
||
a.eq(e.suihui, 7, "扣 3 宿慧")
|
||
a.eq(int(e.meta_ranks.get("meta_01", 0)), 1, "meta_01 阶 1")
|
||
var r2: Dictionary = e.buy_meta("meta_01")
|
||
a.true_(not bool(r2.get("ok", false)), "meta_01 一阶限购")
|
||
e.suihui = 100
|
||
var r3: Dictionary = e.buy_meta("meta_03")
|
||
a.true_(bool(r3.get("ok", false)), "买宿慧通透(8)")
|
||
# 效率升级进班底区
|
||
e.merit = 100000.0
|
||
e.gen_levels[0] = 10
|
||
var r4: Dictionary = e.buy_upgrade("up_eff_gen_01_youhun_1")
|
||
a.true_(bool(r4.get("ok", false)), "买游魂操练 I(83)")
|
||
a.near(e.gen_mult(0), 2.0, 1e-9, "班底区 ×2(+100%)")
|
||
|
||
|
||
# ---- 冤气线 ----
|
||
func _test_wrath(a, data) -> void:
|
||
var e := EconomyState.new(data)
|
||
e.devour(100.0)
|
||
a.near(e.wrath, 100.0, 1e-9, "吞噬 +100 冤气")
|
||
a.eq(e.devour_count, 1, "吞噬计数")
|
||
a.eq(e.wrath_layer_cost(), 8, "第 1 层成本 8")
|
||
var r: Dictionary = e.buy_wrath_layer()
|
||
a.true_(bool(r.get("ok", false)), "买第 1 层怨煞")
|
||
a.eq(e.wrath_layers, 1, "1 层")
|
||
a.near(e.global_mult(), 1.25, 1e-9, "全局 ×1.25(每层 +25%)")
|
||
a.near(e.wrath_penalty(), 0.03, 1e-9, "宿慧削减 3%")
|
||
e.wrath = 0.0
|
||
var r2: Dictionary = e.buy_wrath_layer()
|
||
a.true_(not bool(r2.get("ok", false)), "冤气不足买不了")
|
||
e.wrath = 1e6
|
||
for _i in 21:
|
||
e.buy_wrath_layer()
|
||
a.eq(e.wrath_layers, 22, "22 层上限")
|
||
var r3: Dictionary = e.buy_wrath_layer()
|
||
a.true_(not bool(r3.get("ok", false)), "满层后再买失败")
|
||
|
||
|
||
# ---- 轮回转世 ----
|
||
func _test_prestige(a, data) -> void:
|
||
var e := EconomyState.new(data)
|
||
a.false_(e.prestige_available(), "初始不可轮回")
|
||
e.merit_run_total = 1.5e9
|
||
a.true_(e.prestige_available(), "H10 门达成 → 可轮回")
|
||
a.eq(e.suihui_gain(), 193, "1.5B → 193 宿慧")
|
||
e.gen_levels[0] = 50
|
||
e.merit = 123.0
|
||
var r: Dictionary = e.do_prestige()
|
||
a.true_(bool(r.get("ok", false)), "执行轮回")
|
||
a.eq(e.suihui, 193, "宿慧入账")
|
||
a.eq(e.rebirths, 1, "转世 1 次")
|
||
a.near(e.merit, 0.0, 1e-9, "阴德清零")
|
||
a.eq(e.gen_levels[0], 950, "跳过机制:193/5=38 ×25 = 950 级")
|
||
a.eq(e.halls_passed, 0, "殿门进度重置")
|
||
a.eq(e.bought.size(), 0, "升级清空")
|
||
# 第二轮更快(宿慧全局 +3%)
|
||
a.near(e.global_mult(), 1.0 + 193 * 0.03, 1e-9, "宿慧全局加成")
|
||
|
||
|
||
# ---- 阴司敕封 + gen12 愿景档 ----
|
||
func _test_enthrone(a, data) -> void:
|
||
var e := EconomyState.new(data)
|
||
e.rebirths = 2
|
||
e.suihui = 100
|
||
a.true_(e.enthrone_ready(), "转世 2 + 宿慧 100 → 敕封就绪")
|
||
e.merit_run_total = 1.5e9
|
||
e.merit = 1e12
|
||
var r: Dictionary = e.buy_upgrade("up_gate_tianzi")
|
||
a.true_(bool(r.get("ok", false)), "买敕封诏书(800B)")
|
||
a.true_(e.enthrone_available(), "受敕可用")
|
||
a.false_(e.generator_unlocked(11), "未受敕 → gen12 仍锁(P-12)")
|
||
var r2: Dictionary = e.do_enthrone()
|
||
a.true_(bool(r2.get("ok", false)), "执行受敕")
|
||
a.true_(e.enthroned, "enthroned 旗标")
|
||
a.true_(e.generator_unlocked(11), "受敕 → gen12 解锁")
|
||
# 全局区 = 1 + 宿慧100×3% + 敕封 25% = 4.25
|
||
a.near(e.global_mult(), 4.25, 1e-9, "全局 ×4.25(宿慧+敕封)")
|
||
# gen12 产出接入
|
||
e.gen_levels[11] = 1
|
||
a.near(e.output_per_sec(), 1073741824.0 * 4.25, 1.0, "gen12 1 级产出")
|
||
|
||
|
||
# ---- 事件瞬时区 + 离线加法(契约 v2:长明灯 ×2.31 → 加法 +30%) ----
|
||
func _test_event_and_offline(a, data) -> void:
|
||
var e := EconomyState.new(data)
|
||
e.gen_levels[0] = 10
|
||
var base_out := e.output_per_sec()
|
||
e.set_event_mult(5.0)
|
||
a.near(e.output_per_sec(), base_out * 5.0, 1e-9, "事件 ×5 瞬时区")
|
||
e.set_event_mult(1.0)
|
||
a.near(e.offline_add(), 0.0, 1e-9, "无长明灯 → 加法 +0")
|
||
e.halls_passed = 4 # 离线升级出现条件
|
||
e.merit = 1e9
|
||
var r: Dictionary = e.buy_upgrade("up_offline_1")
|
||
a.true_(bool(r.get("ok", false)), "买长明灯 I")
|
||
a.near(e.offline_add(), 0.05, 1e-9, "长明灯 I → 加法 +5%(旧 ×1.15 乘性已废止)")
|
||
for i in range(2, 7):
|
||
var ri: Dictionary = e.buy_upgrade("up_offline_%d" % i)
|
||
a.true_(bool(ri.get("ok", false)), "买长明灯 %d" % i)
|
||
a.near(e.offline_add(), 0.30, 1e-9, "长明灯 6 级满 = 加法 +30%(各档速率硬顶 100%)")
|
||
# m05 阴司人脉(每阶 +25% 加法,max_rank 1)
|
||
e.suihui = 100
|
||
var rm: Dictionary = e.buy_meta("meta_05")
|
||
a.true_(bool(rm.get("ok", false)), "买阴司人脉")
|
||
a.near(e.offline_add(), 0.55, 1e-9, "+ m05 = 加法 +55%(仍由 OfflineModel 钳各档 ≤100%)")
|