Files
game-code-4/tests/unit/cases/test_economy_formulas.gd
T

120 lines
7.9 KiB
GDScript
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
extends RefCounted
# 用例:核心公式(MultiplierSet / PrestigeModel / OfflineModel)
func run(a, _data: BalanceData) -> void:
# ---- MultiplierSet 三乘区 + 软上限 ----
var m := MultiplierSet.new(16.0, 8.0, 64.0)
m.set_click_levels(4, 0.0, 0.01)
a.near(m.click_mult(), 16.0, 1e-9, "点击区 4 级 = ×16")
m.set_click_levels(5, 0.0, 0.01)
a.near(m.click_mult(), 16.0, 1e-9, "点击区 5 级仍钳 ×16")
m.set_gen_eff("gen_01_youhun", 6)
a.near(m.gen_mult("gen_01_youhun"), 7.0, 1e-9, "班底区 6 级 = ×7")
m.set_gen_eff("gen_01_youhun", 99)
a.near(m.gen_mult("gen_01_youhun"), 8.0, 1e-9, "班底区钳 ×8")
m.set_global_add(63.0)
a.near(m.global_mult(), 64.0, 1e-9, "全局区 ×64")
m.set_global_add(100.0)
a.near(m.global_mult(), 64.0, 1e-9, "全局区钳 ×64")
m.set_click_levels(4, 8.0, 0.01)
a.near(m.click_value(1.0, 1000.0), 96.0, 1e-6, "click_value = 1×16 + 1000×8%")
# ---- PrestigeModel ----
a.eq(PrestigeModel.suihui_gain(1.5e9, 1e6, 5.0, 0.0, 0.0), 193, "宿慧 1.5B → 193")
a.eq(PrestigeModel.suihui_gain(1.25e7, 1e6, 5.0, 0.0, 0.0), 17, "宿慧 12.5M → 17")
a.eq(PrestigeModel.suihui_gain(1.5e9, 1e6, 5.0, 0.0, 0.3), 135, "宿慧 30% 削减 → 135")
a.eq(PrestigeModel.suihui_gain(1.5e9, 1e6, 5.0, 0.45, 0.0), 279, "宿慧 m03×3 → 279")
a.eq(PrestigeModel.suihui_gain(0.0, 1e6, 5.0, 0.0, 0.0), 0, "零累计 → 0 宿慧")
a.eq(PrestigeModel.wrath_layer_cost(1, 8.0, 1.8), 8, "怨煞层 1 成本 8")
a.eq(PrestigeModel.wrath_layer_cost(2, 8.0, 1.8), 28, "怨煞层 2 成本 28")
a.eq(PrestigeModel.wrath_layer_cost(22, 8.0, 1.8), 2087, "怨煞层 22 成本 2087")
# W5 新参数(裁定 P-26):削减速 −4%/层封顶 −40%;m07 改 20%
a.near(PrestigeModel.wrath_penalty(10, 0.04, 0.4, 0.0), 0.4, 1e-9, "冤气削减封顶 40%")
a.near(PrestigeModel.wrath_penalty(10, 0.04, 0.4, 0.20), 0.20, 1e-9, "m07 改 20%")
a.near(PrestigeModel.wrath_penalty(5, 0.04, 0.4, 0.0), 0.2, 1e-9, "5 层 = 20%")
a.near(PrestigeModel.wrath_penalty(9, 0.04, 0.4, 0.0), 0.36, 1e-9, "9 层 = 36%(未触顶)")
a.eq(PrestigeModel.skip_count(23, 5), 4, "skip 23/5 = 4")
a.eq(PrestigeModel.skip_count(23, 4), 5, "skip 23/4 = 5(m04)")
a.near(PrestigeModel.restart_target(0), 1.0, 1e-9, "重开曲线 R1")
a.near(PrestigeModel.restart_target(1), 0.48, 1e-9, "重开曲线 R2(v1.1 校准值)")
a.near(PrestigeModel.restart_target(2), 0.42, 1e-9, "重开曲线 R3(v1.1 校准值)")
a.near(PrestigeModel.restart_target(3), 0.40, 1e-9, "重开曲线 R4(v1.1 校准值)")
a.near(PrestigeModel.restart_target(4), 0.25, 1e-9, "重开曲线 R5 触底")
a.true_(PrestigeModel.enthrone_available(2, 2), "敕封:转世 2 可")
a.true_(not PrestigeModel.enthrone_available(1, 2), "敕封:转世 1 不可")
# ---- W5 G-1:wrath_layers.csv 22 行(效果/成本逐行;[B§12] 漏登补登)----
var wl := _data.wrath_layers
a.eq(wl.size(), 22, "冤煞层 22 行")
var sum_effect := 0.0
var prev_cost := -1
for row in wl:
a.eq(row.layer_index, wl.find(row) + 1, "layer_index 从 1 连续(%s)" % row.id)
# 成本列 = round(8×n^1.8) 逐行一致(表 = 公式落盘,双源交叉校验)
a.eq(row.cost, PrestigeModel.wrath_layer_cost(row.layer_index, 8.0, 1.8),
"成本 = 公式(%s)" % row.id)
a.true_(row.cost > prev_cost, "成本严格递增(%s)" % row.id)
prev_cost = row.cost
# effect 剖面:L1-15 = 0.15;L16-22 = 0.00(合计封顶 +225%)
if row.layer_index <= 15:
a.near(row.effect, 0.15, 1e-9, "L%d effect = 0.15" % row.layer_index)
else:
a.near(row.effect, 0.0, 1e-9, "L%d effect = 0(归零)" % row.layer_index)
sum_effect += row.effect
a.near(sum_effect, 2.25, 1e-9, "22 层合计 effect = +225%(15 层封顶)")
a.near(_data.wrath_layer_effect_sum(15), 2.25, 1e-9, "effect_sum(15) = +225%")
a.near(_data.wrath_layer_effect_sum(10), 1.5, 1e-9, "effect_sum(10) = +150%")
a.near(_data.wrath_layer_effect_sum(22), 2.25, 1e-9, "effect_sum(22) 仍 +225%(16-22 归零)")
a.near(_data.wrath_layer_effect_sum(0), 0.0, 1e-9, "effect_sum(0) = 0")
a.eq(_data.wrath_layer(1).cost, 8, "wrath_layer(1) 成本 8")
a.eq(_data.wrath_layer(22).cost, 2087, "wrath_layer(22) 成本 2087")
a.true_(_data.wrath_layer(23) == null, "wrath_layer(23) 越界 = null")
# W5 新调参(裁定 F-1/F-2):宿慧渐近 + 跳过封顶
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, "削减速 0.04/层")
a.near(_data.tune_num("tune_wrath_penalty_cap", 0.0), 0.4, 1e-9, "削减速封顶 0.40")
a.false_(_data.has_tune("tune_wrath_bonus"), "tune_wrath_bonus 已迁入表(防双源)")
a.false_(_data.has_tune("tune_suihui_global_pct"), "tune_suihui_global_pct 已被渐近公式取代")
# ---- OfflineModel 分带 + 72h 封顶 + 时钟回拨 + 长明灯加法 + 硬顶 ----
# W4 契约 v2(systems-spec §2.4/§2.5):第三参数由 offline_mult(乘性)改为
# offline_add(加法,直接加在各档速率上,各档硬顶 100%)。
var r1: Dictionary = OfflineModel.settle(3600.0, 10.0, 0.0, 2.0, 1.0, 8.0, 0.7, 24.0, 0.4, 0.1, 72.0)
a.near(r1["effective_hours"], 1.0, 1e-9, "离线 1h = 1h 等效")
a.near(r1["merit"], 36000.0, 1e-6, "离线 1h × 10/s")
var r8: Dictionary = OfflineModel.settle(8.0 * 3600.0, 10.0, 0.0, 2.0, 1.0, 8.0, 0.7, 24.0, 0.4, 0.1, 72.0)
a.near(r8["effective_hours"], 6.2, 1e-9, "离线 8h = 6.2h 等效(契约 v2:77.5%)")
a.near(r8["merit"], 223200.0, 1e-6, "离线 8h 收益")
var r24: Dictionary = OfflineModel.settle(24.0 * 3600.0, 10.0, 0.0, 2.0, 1.0, 8.0, 0.7, 24.0, 0.4, 0.1, 72.0)
a.near(r24["effective_hours"], 12.6, 1e-9, "离线 24h = 12.6h 等效(契约 v2)")
var r100: Dictionary = OfflineModel.settle(100.0 * 3600.0, 10.0, 0.0, 2.0, 1.0, 8.0, 0.7, 24.0, 0.4, 0.1, 72.0)
a.near(r100["effective_hours"], 17.4, 1e-9, "离线 100h → 72h 封顶 = 17.4h 等效(24.2%)")
var rneg: Dictionary = OfflineModel.settle(-5.0, 10.0, 0.0, 2.0, 1.0, 8.0, 0.7, 24.0, 0.4, 0.1, 72.0)
a.near(rneg["merit"], 0.0, 1e-9, "时钟回拨 → 0")
a.near(OfflineModel.ratio_8h_over_1h(2.0, 1.0, 8.0, 0.7, 24.0, 0.4, 0.1), 6.2, 1e-9,
"历史口径比率 6.2(契约 v2 起门 #9 改判等效小时,见 SimGates.gate_offline_v2)")
# 长明灯加法:+30%(6 级)⇒ 2-8h 档 70%+30% = 100%(硬顶)⇒ 8h = 8.0h(效率 100%)
var r8l: Dictionary = OfflineModel.settle(8.0 * 3600.0, 10.0, 0.30, 2.0, 1.0, 8.0, 0.7, 24.0, 0.4, 0.1, 72.0)
a.near(r8l["effective_hours"], 8.0, 1e-9, "长明灯满级 8h = 8.0h 等效(硬顶 100%)")
a.near(r8l["merit"], 288000.0, 1e-6, "长明灯满级 8h 收益")
# 加法不越过硬顶:+55%(6 级 + m05)仍 = 8.0h;8-24h 档 40%+30% = 70%
var r8m: Dictionary = OfflineModel.settle(8.0 * 3600.0, 10.0, 0.55, 2.0, 1.0, 8.0, 0.7, 24.0, 0.4, 0.1, 72.0)
a.near(r8m["effective_hours"], 8.0, 1e-9, "加法 +55% 仍钳 8.0h(0-2h/2-8h 双档顶格)")
var r24l: Dictionary = OfflineModel.settle(24.0 * 3600.0, 10.0, 0.30, 2.0, 1.0, 8.0, 0.7, 24.0, 0.4, 0.1, 72.0)
a.near(r24l["effective_hours"], 2.0 + 6.0 + 16.0 * 0.7, 1e-9, "长明灯满级 24h = 19.2h(8-24h 档 70%)")
# 效率硬顶:任意加成下等效 ≤ 实际(离线不得优于在线)
for dur_h in [1.0, 8.0, 24.0, 72.0]:
for add in [0.0, 0.30, 0.55, 5.0]:
var rr: Dictionary = OfflineModel.settle(dur_h * 3600.0, 10.0, add,
2.0, 1.0, 8.0, 0.7, 24.0, 0.4, 0.1, 72.0)
a.true_(float(rr["effective_hours"]) <= dur_h + 1e-9,
"效率硬顶:%s h 离线 加法 +%s ⇒ 等效 %.2f h ≤ %s h" % [
str(dur_h), str(add), float(rr["effective_hours"]), str(dur_h)])
# ---- BigNumber 红线 ----
a.true_(BigNumber.assert_within(1e13, "test"), "1e13 不过红线")
a.true_(not BigNumber.assert_within(1e15, "test"), "1e15 触红线")