W5: sim一轮裁定落地+二轮校准 — 冤煞独立表(wrath_layers 22行)/宿慧渐近封顶F-1/跳过钳制F-2/验收门#2#3#10#13#14修订;二轮4/5 FAIL转PASS,#13 R4残留0.396(带外0.021),硬门#5#10不回归,红线9.5e15→7.007B,test_runner 750检查8/8用例
This commit is contained in:
1 parent
c534e95458
commit
c0a5c52cb7
37 files changed
+49293
-153
No files matched your search
@@ -83,8 +83,11 @@ godot --headless --path . -s res://src/tools/import_main.gd -- --validate-only
|
||||
`data/sheets/*.csv` →(SheetImporter,本仓库 `src/tools/`)→ `data/build/*.json`(提交)→(W3 `.tres`)→ DataRegistry。
|
||||
单向流动:游戏永不写 `data/`;sim 与游戏读同一份 build。契约见 `README.md` + 架构 §3。
|
||||
|
||||
**表清单(W3 = 9 张)**:`generators` / `upgrades` / `meta_upgrades` / `halls` / `hall_palettes` /
|
||||
`boss_battles` / `events` / `balance_tuning` / **`camera`(W3 新增,一行一殿)**。
|
||||
**表清单(W5 = 10 张)**:`generators` / `upgrades` / `meta_upgrades` / `halls` / `hall_palettes` /
|
||||
`boss_battles` / `events` / `balance_tuning` / `camera`(W3 新增,一行一殿) /
|
||||
**`wrath_layers`(W5 新增,一行一层:`layer_index`/`effect`/`cost`)**。
|
||||
`wrath_layers` 补登 [B§12] 表清单漏登项——原落点是 `balance_tuning` 标量 `tune_wrath_bonus`
|
||||
+ 经济核心线性乘层数(架构债,W5 裁定 P-25 拆为独立表,逐行 effect/cost 数据自解释)。
|
||||
新增表 = 加 schema + 加 `.csv` + 进 `SheetImporter` 白名单,**不重编号既有 ID**。
|
||||
|
||||
**W3 相机参数为什么独立成表**(`camera.csv`,不是给 `halls.csv` 加列):
|
||||
|
||||
@@ -98,42 +98,21 @@
|
||||
"kind": "number",
|
||||
"num": 22,
|
||||
"text": "",
|
||||
"desc_cn": "[B§3.2] 冤煞层总数 22"
|
||||
},
|
||||
{
|
||||
"id": "tune_wrath_cost_base",
|
||||
"kind": "number",
|
||||
"num": 8,
|
||||
"text": "",
|
||||
"desc_cn": "[B§3.2] 第 n 层成本 = round(8 × n^1.8)"
|
||||
},
|
||||
{
|
||||
"id": "tune_wrath_cost_exp",
|
||||
"kind": "number",
|
||||
"num": 1.8,
|
||||
"text": "",
|
||||
"desc_cn": "[B§3.2] 冤煞层成本指数"
|
||||
},
|
||||
{
|
||||
"id": "tune_wrath_bonus",
|
||||
"kind": "number",
|
||||
"num": 0.25,
|
||||
"text": "",
|
||||
"desc_cn": "[B§3.2] 每层全局 +25%(加法,进全局乘区)"
|
||||
"desc_cn": "[B§3.2] 冤煞层总数 22(与 wrath_layers.csv 行数交叉校验;效果/成本已逐行入该表,W5 G-1)"
|
||||
},
|
||||
{
|
||||
"id": "tune_wrath_penalty",
|
||||
"kind": "number",
|
||||
"num": 0.03,
|
||||
"num": 0.04,
|
||||
"text": "",
|
||||
"desc_cn": "[B§3.2] 每层宿慧获取削减 +3%"
|
||||
"desc_cn": "[B§3.2] 每层宿慧获取削减 +4%(W5 裁定 P-26:−3% → −4%)"
|
||||
},
|
||||
{
|
||||
"id": "tune_wrath_penalty_cap",
|
||||
"kind": "number",
|
||||
"num": 0.3,
|
||||
"num": 0.4,
|
||||
"text": "",
|
||||
"desc_cn": "[B§3.2] 宿慧削减封顶 30%"
|
||||
"desc_cn": "[B§3.2] 宿慧削减封顶 40%(W5 裁定 P-26:30% → 40%;m07 改 20%)"
|
||||
},
|
||||
{
|
||||
"id": "tune_suihui_div",
|
||||
@@ -149,13 +128,6 @@
|
||||
"text": "",
|
||||
"desc_cn": "[B§4.1] 宿慧公式乘数"
|
||||
},
|
||||
{
|
||||
"id": "tune_suihui_global_pct",
|
||||
"kind": "number",
|
||||
"num": 0.03,
|
||||
"text": "",
|
||||
"desc_cn": "[B§1/§4.2] 每级宿慧全局产出 +3%(加法,进全局乘区)"
|
||||
},
|
||||
{
|
||||
"id": "tune_enthrone_bonus",
|
||||
"kind": "number",
|
||||
@@ -168,7 +140,7 @@
|
||||
"kind": "number",
|
||||
"num": 5,
|
||||
"text": "",
|
||||
"desc_cn": "[B§4.2] 每 5 级宿慧 → 前 3 档班底各 +25 级(m04 可加快为 4)"
|
||||
"desc_cn": "[B§4.2] 每 5 级宿慧 → 前 3 档班底各 +25 级(m04 可加快为 4;每档封顶见 tune_skip_level_cap_per_gen)"
|
||||
},
|
||||
{
|
||||
"id": "tune_skip_gens",
|
||||
@@ -184,6 +156,13 @@
|
||||
"text": "",
|
||||
"desc_cn": "[B§4.2] 跳过机制每档 +25 级"
|
||||
},
|
||||
{
|
||||
"id": "tune_skip_level_cap_per_gen",
|
||||
"kind": "number",
|
||||
"num": 50,
|
||||
"text": "",
|
||||
"desc_cn": "[B§4.2] W5 裁定 P-27(F-2):跳过每档获赠 = min(floor(宿慧/5)×25, 本值)(原无封顶 → R2 开盘白送 2850 级)"
|
||||
},
|
||||
{
|
||||
"id": "tune_enthrone_rebirths",
|
||||
"kind": "number",
|
||||
@@ -295,6 +274,20 @@
|
||||
"num": 1,
|
||||
"text": "",
|
||||
"desc_cn": "[systems-spec §1.2 B3] 开场冲锋开关(1 = 启用;门 #11 首轮数据回来前默认 1)"
|
||||
},
|
||||
{
|
||||
"id": "tune_suihui_global_max",
|
||||
"kind": "number",
|
||||
"num": 0.5,
|
||||
"text": "",
|
||||
"desc_cn": "[B§4.2] W5 裁定 P-27(F-1):宿慧全局加成渐近上限 = 0.50×(1−e^(−宿慧/scale))(旧 +3%/级线性无界 → R2 开盘 ×6.79、红线 9.5e15 的根因)"
|
||||
},
|
||||
{
|
||||
"id": "tune_suihui_global_scale",
|
||||
"kind": "number",
|
||||
"num": 420,
|
||||
"text": "",
|
||||
"desc_cn": "[B§4.2] W5 裁定 P-27(F-1):渐近衰减尺度(宿慧)。查点:193→+18.4%;386→+30.1%;579→+37.4%;772→+42.0%;∞→+50%"
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -23,7 +23,7 @@
|
||||
"king_en": "King Qinguang",
|
||||
"motif_cn": "孽镜台(照心)",
|
||||
"motif_en": "Mirror of Karma",
|
||||
"target_min": 25,
|
||||
"target_min": 10,
|
||||
"gate_merit": 2000,
|
||||
"unlock_gen": "gen_03_guizu",
|
||||
"unlock_gate": "up_gate_guizu",
|
||||
@@ -37,7 +37,7 @@
|
||||
"king_en": "King Chujiang",
|
||||
"motif_cn": "寒冰狱",
|
||||
"motif_en": "Ice Hell",
|
||||
"target_min": 42,
|
||||
"target_min": 20,
|
||||
"gate_merit": 30000,
|
||||
"unlock_gen": "gen_04_biliao",
|
||||
"unlock_gate": "up_gate_biliao",
|
||||
@@ -51,7 +51,7 @@
|
||||
"king_en": "King Songdi",
|
||||
"motif_cn": "剥皮亭",
|
||||
"motif_en": "Flaying Pavilion",
|
||||
"target_min": 62,
|
||||
"target_min": 36,
|
||||
"gate_merit": 300000,
|
||||
"unlock_gen": "gen_05_tangpu",
|
||||
"unlock_gate": "up_gate_tangpu",
|
||||
@@ -65,7 +65,7 @@
|
||||
"king_en": "King Wuguan",
|
||||
"motif_cn": "沸汤/毒蛇",
|
||||
"motif_en": "Scalding Cauldron",
|
||||
"target_min": 84,
|
||||
"target_min": 56,
|
||||
"gate_merit": 2000000,
|
||||
"unlock_gen": "gen_06_nanmin",
|
||||
"unlock_gate": "up_gate_nanmin",
|
||||
@@ -79,7 +79,7 @@
|
||||
"king_en": "King Yama",
|
||||
"motif_cn": "叫唤地狱/铁床",
|
||||
"motif_en": "Wailing Hell",
|
||||
"target_min": 105,
|
||||
"target_min": 80,
|
||||
"gate_merit": 10000000,
|
||||
"unlock_gen": "gen_07_shuban",
|
||||
"unlock_gate": "up_gate_shuban",
|
||||
@@ -93,7 +93,7 @@
|
||||
"king_en": "King Biancheng",
|
||||
"motif_cn": "石碾",
|
||||
"motif_en": "Stone Roller",
|
||||
"target_min": 125,
|
||||
"target_min": 102,
|
||||
"gate_merit": 40000000,
|
||||
"unlock_gen": "gen_08_bingfang",
|
||||
"unlock_gate": "up_gate_bingfang",
|
||||
@@ -107,7 +107,7 @@
|
||||
"king_en": "King Taishan",
|
||||
"motif_cn": "热油火坑",
|
||||
"motif_en": "Boiling Oil Pit",
|
||||
"target_min": 143,
|
||||
"target_min": 122,
|
||||
"gate_merit": 120000000,
|
||||
"unlock_gen": "gen_09_wodi",
|
||||
"unlock_gate": "up_gate_wodi",
|
||||
@@ -121,7 +121,7 @@
|
||||
"king_en": "King Dushi",
|
||||
"motif_cn": "泥犁/大石",
|
||||
"motif_en": "Avici Stone",
|
||||
"target_min": 160,
|
||||
"target_min": 142,
|
||||
"gate_merit": 350000000,
|
||||
"unlock_gen": "gen_10_xingzhe",
|
||||
"unlock_gate": "up_gate_xingzhe",
|
||||
@@ -135,7 +135,7 @@
|
||||
"king_en": "King Pingdeng",
|
||||
"motif_cn": "拔舌/铁树",
|
||||
"motif_en": "Tongue-Ripping Iron Tree",
|
||||
"target_min": 175,
|
||||
"target_min": 164,
|
||||
"gate_merit": 800000000,
|
||||
"unlock_gen": "gen_11_yinhun",
|
||||
"unlock_gate": "up_gate_yinhun",
|
||||
|
||||
@@ -92,16 +92,16 @@
|
||||
"name_en": "Easy Conscience",
|
||||
"effect_type": "wrath_penalty_set",
|
||||
"target_id": "",
|
||||
"effect_param": 0.15,
|
||||
"effect_param": 0.2,
|
||||
"cost_suihui": 15,
|
||||
"max_rank": 1,
|
||||
"condition": "none",
|
||||
"desc_cn": "冤气对宿慧的削减 30%→15%"
|
||||
"desc_cn": "冤气对宿慧的削减 40%→20%"
|
||||
},
|
||||
{
|
||||
"id": "meta_08",
|
||||
"name_cn": "敕封恩典",
|
||||
"name_en": "Grace of Enthronement",
|
||||
"name_cn": "幽冥恩荫",
|
||||
"name_en": "Shadow Patronage",
|
||||
"effect_type": "global_pct",
|
||||
"target_id": "",
|
||||
"effect_param": 0.25,
|
||||
|
||||
@@ -0,0 +1,144 @@
|
||||
{
|
||||
"sheet": "wrath_layers",
|
||||
"schema_version": 0,
|
||||
"columns": [
|
||||
"id",
|
||||
"layer_index",
|
||||
"effect",
|
||||
"cost"
|
||||
],
|
||||
"rows": [
|
||||
{
|
||||
"id": "wrath_layer_01",
|
||||
"layer_index": 1,
|
||||
"effect": 0.15,
|
||||
"cost": 8
|
||||
},
|
||||
{
|
||||
"id": "wrath_layer_02",
|
||||
"layer_index": 2,
|
||||
"effect": 0.15,
|
||||
"cost": 28
|
||||
},
|
||||
{
|
||||
"id": "wrath_layer_03",
|
||||
"layer_index": 3,
|
||||
"effect": 0.15,
|
||||
"cost": 58
|
||||
},
|
||||
{
|
||||
"id": "wrath_layer_04",
|
||||
"layer_index": 4,
|
||||
"effect": 0.15,
|
||||
"cost": 97
|
||||
},
|
||||
{
|
||||
"id": "wrath_layer_05",
|
||||
"layer_index": 5,
|
||||
"effect": 0.15,
|
||||
"cost": 145
|
||||
},
|
||||
{
|
||||
"id": "wrath_layer_06",
|
||||
"layer_index": 6,
|
||||
"effect": 0.15,
|
||||
"cost": 201
|
||||
},
|
||||
{
|
||||
"id": "wrath_layer_07",
|
||||
"layer_index": 7,
|
||||
"effect": 0.15,
|
||||
"cost": 266
|
||||
},
|
||||
{
|
||||
"id": "wrath_layer_08",
|
||||
"layer_index": 8,
|
||||
"effect": 0.15,
|
||||
"cost": 338
|
||||
},
|
||||
{
|
||||
"id": "wrath_layer_09",
|
||||
"layer_index": 9,
|
||||
"effect": 0.15,
|
||||
"cost": 418
|
||||
},
|
||||
{
|
||||
"id": "wrath_layer_10",
|
||||
"layer_index": 10,
|
||||
"effect": 0.15,
|
||||
"cost": 505
|
||||
},
|
||||
{
|
||||
"id": "wrath_layer_11",
|
||||
"layer_index": 11,
|
||||
"effect": 0.15,
|
||||
"cost": 599
|
||||
},
|
||||
{
|
||||
"id": "wrath_layer_12",
|
||||
"layer_index": 12,
|
||||
"effect": 0.15,
|
||||
"cost": 701
|
||||
},
|
||||
{
|
||||
"id": "wrath_layer_13",
|
||||
"layer_index": 13,
|
||||
"effect": 0.15,
|
||||
"cost": 809
|
||||
},
|
||||
{
|
||||
"id": "wrath_layer_14",
|
||||
"layer_index": 14,
|
||||
"effect": 0.15,
|
||||
"cost": 925
|
||||
},
|
||||
{
|
||||
"id": "wrath_layer_15",
|
||||
"layer_index": 15,
|
||||
"effect": 0.15,
|
||||
"cost": 1047
|
||||
},
|
||||
{
|
||||
"id": "wrath_layer_16",
|
||||
"layer_index": 16,
|
||||
"effect": 0,
|
||||
"cost": 1176
|
||||
},
|
||||
{
|
||||
"id": "wrath_layer_17",
|
||||
"layer_index": 17,
|
||||
"effect": 0,
|
||||
"cost": 1312
|
||||
},
|
||||
{
|
||||
"id": "wrath_layer_18",
|
||||
"layer_index": 18,
|
||||
"effect": 0,
|
||||
"cost": 1454
|
||||
},
|
||||
{
|
||||
"id": "wrath_layer_19",
|
||||
"layer_index": 19,
|
||||
"effect": 0,
|
||||
"cost": 1603
|
||||
},
|
||||
{
|
||||
"id": "wrath_layer_20",
|
||||
"layer_index": 20,
|
||||
"effect": 0,
|
||||
"cost": 1758
|
||||
},
|
||||
{
|
||||
"id": "wrath_layer_21",
|
||||
"layer_index": 21,
|
||||
"effect": 0,
|
||||
"cost": 1919
|
||||
},
|
||||
{
|
||||
"id": "wrath_layer_22",
|
||||
"layer_index": 22,
|
||||
"effect": 0,
|
||||
"cost": 2087
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -0,0 +1,58 @@
|
||||
{
|
||||
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
||||
"$id": "wrath_layers.schema.json",
|
||||
"title": "wrath_layers 表 schema v0(冤煞层 22 层逐行效果/成本,W5 补登 G-1)",
|
||||
"description": "为什么独立成表(W5 sim 一轮裁定报告 §4.2 缺口 G-1):[B§12] 七张表清单漏登冤煞层——[B§3.2] 定义了 22 层效果/成本但从未给 CSV 落点,原实现是 balance_tuning 标量 tune_wrath_bonus=0.25 配 economy_state.gd 线性乘层数(架构债:改一层效果要改代码)。本表 22 行 = 一层一行;effect = 该层购入后加入全局乘区的加法值(L1-15 = 0.15;L16-22 = 0.00,W5 裁定 P-25:+25%/层线性到底 → 15 层后归零,合计封顶 +225%,16-22 层保留购买入口作收藏/成就向,叙事'怨煞噬主,过盛不顶用');cost = 该层冤气成本 = round(8 × n^1.8)([B§3.2] 原公式逐行落盘,公式参数 base/exp/bonus 三行已从 balance_tuning 移除)。削减速(−4%/层封顶 −40%)不随层变,按纪律留 balance_tuning 公式行(tune_wrath_penalty/tune_wrath_penalty_cap);层总数 tune_wrath_layers=22 与本表行数由 BalanceData.check_references 交叉校验。稳定 ID:wrath_layer_NN,永不重编号(年更冤案包若加层 = 加行并同步 tune_wrath_layers,走 ADR)。",
|
||||
"x-supported-keywords": [
|
||||
"type", "properties", "required", "items", "enum", "pattern",
|
||||
"minimum", "maximum", "minLength", "minItems", "maxItems",
|
||||
"additionalProperties", "const"
|
||||
],
|
||||
"x-unique": ["id", "layer_index"],
|
||||
"type": "object",
|
||||
"required": ["sheet", "schema_version", "columns", "rows"],
|
||||
"properties": {
|
||||
"sheet": { "const": "wrath_layers" },
|
||||
"schema_version": { "const": 0 },
|
||||
"columns": {
|
||||
"type": "array",
|
||||
"items": { "type": "string" },
|
||||
"minItems": 4
|
||||
},
|
||||
"rows": {
|
||||
"type": "array",
|
||||
"minItems": 22,
|
||||
"maxItems": 22,
|
||||
"items": {
|
||||
"type": "object",
|
||||
"required": ["id", "layer_index", "effect", "cost"],
|
||||
"properties": {
|
||||
"id": {
|
||||
"type": "string",
|
||||
"pattern": "^wrath_layer_[0-9]{2}$",
|
||||
"description": "稳定字符串 ID;永不重编号/复用(与 layer_index 对齐:wrath_layer_01 = 第 1 层)"
|
||||
},
|
||||
"layer_index": {
|
||||
"type": "integer",
|
||||
"minimum": 1,
|
||||
"maximum": 22,
|
||||
"description": "层序号(1 起;22 层为 [B§3.2] 锁定总数,删行 = 设计动作走 ADR)"
|
||||
},
|
||||
"effect": {
|
||||
"type": "number",
|
||||
"minimum": 0,
|
||||
"maximum": 1,
|
||||
"description": "该层加入全局乘区的加法值(W5 裁定:L1-15 = 0.15;L16-22 = 0.00 归零)"
|
||||
},
|
||||
"cost": {
|
||||
"type": "integer",
|
||||
"minimum": 0,
|
||||
"description": "该层冤气成本 = round(8 × n^1.8)([B§3.2] 公式逐行落盘;gen_balance_sheets.py 生成,单测交叉校验)"
|
||||
}
|
||||
},
|
||||
"additionalProperties": false
|
||||
}
|
||||
}
|
||||
},
|
||||
"additionalProperties": false
|
||||
}
|
||||
@@ -11,19 +11,16 @@ tune_offline_band3_h,number,24,,[B§8] 离线 8-24h 速率 40%
|
||||
tune_offline_band3_rate,number,0.4,,[B§8] 离线 8-24h 速率
|
||||
tune_offline_band4_rate,number,0.1,,[B§8] 离线 >24h 速率 10%
|
||||
tune_offline_cap_h,number,72,,[B§8] 离线硬上限 72h 封顶
|
||||
tune_wrath_layers,number,22,,[B§3.2] 冤煞层总数 22
|
||||
tune_wrath_cost_base,number,8,,[B§3.2] 第 n 层成本 = round(8 × n^1.8)
|
||||
tune_wrath_cost_exp,number,1.8,,[B§3.2] 冤煞层成本指数
|
||||
tune_wrath_bonus,number,0.25,,[B§3.2] 每层全局 +25%(加法,进全局乘区)
|
||||
tune_wrath_penalty,number,0.03,,[B§3.2] 每层宿慧获取削减 +3%
|
||||
tune_wrath_penalty_cap,number,0.3,,[B§3.2] 宿慧削减封顶 30%
|
||||
tune_wrath_layers,number,22,,[B§3.2] 冤煞层总数 22(与 wrath_layers.csv 行数交叉校验;效果/成本已逐行入该表,W5 G-1)
|
||||
tune_wrath_penalty,number,0.04,,[B§3.2] 每层宿慧获取削减 +4%(W5 裁定 P-26:−3% → −4%)
|
||||
tune_wrath_penalty_cap,number,0.4,,[B§3.2] 宿慧削减封顶 40%(W5 裁定 P-26:30% → 40%;m07 改 20%)
|
||||
tune_suihui_div,number,1000000,,[B§4.1] 宿慧 = floor(√(本轮累计阴德/1e6) × 5)
|
||||
tune_suihui_mult,number,5,,[B§4.1] 宿慧公式乘数
|
||||
tune_suihui_global_pct,number,0.03,,[B§1/§4.2] 每级宿慧全局产出 +3%(加法,进全局乘区)
|
||||
tune_enthrone_bonus,number,0.25,,[B§4.4] 阴司敕封自动全局恩典 +25%(与 m08 商品字面重叠,见 provenance P-4)
|
||||
tune_skip_interval,number,5,,[B§4.2] 每 5 级宿慧 → 前 3 档班底各 +25 级(m04 可加快为 4)
|
||||
tune_skip_interval,number,5,,[B§4.2] 每 5 级宿慧 → 前 3 档班底各 +25 级(m04 可加快为 4;每档封顶见 tune_skip_level_cap_per_gen)
|
||||
tune_skip_gens,number,3,,[B§4.2] 跳过机制覆盖前 3 档班底
|
||||
tune_skip_levels,number,25,,[B§4.2] 跳过机制每档 +25 级
|
||||
tune_skip_level_cap_per_gen,number,50,,"[B§4.2] W5 裁定 P-27(F-2):跳过每档获赠 = min(floor(宿慧/5)×25, 本值)(原无封顶 → R2 开盘白送 2850 级)"
|
||||
tune_enthrone_rebirths,number,2,,[B§4.4] 阴司敕封触发:转世 ≥2(约第 2-3 轮,累计 8-12h 为其 pacing 后果)
|
||||
tune_restart_curve,text,0,1:0.6:0.4:0.3,[B§4.3] 重开曲线目标(第 5 轮触底 ≥0.25×);模拟器门 #13 断言
|
||||
tune_event_timeout_default,text,0,opt_a,[B§7] 冤魂申诉超时默认 = 超度(opt_a)
|
||||
@@ -40,3 +37,5 @@ tune_boss_kappa_base,number,0.01,,[systems-spec §1.2 B2] 殿王战点击伤害
|
||||
tune_boss_kappa_slope,number,0.052,,[systems-spec §1.2 B2] κ 随法器线进度斜率:κ = (base + slope × 已购点击升级/12) × (1 + m06阶×0.30);满配 κ = 0.0806
|
||||
tune_boss_intro_cap,number,0.1,,[systems-spec §1.2 B3] 开场冲锋伤害封顶 = HP × 本值(0.10;旧公式 20% 已废止)
|
||||
tune_boss_intro_enabled,number,1,,[systems-spec §1.2 B3] 开场冲锋开关(1 = 启用;门 #11 首轮数据回来前默认 1)
|
||||
tune_suihui_global_max,number,0.5,,[B§4.2] W5 裁定 P-27(F-1):宿慧全局加成渐近上限 = 0.50×(1−e^(−宿慧/scale))(旧 +3%/级线性无界 → R2 开盘 ×6.79、红线 9.5e15 的根因)
|
||||
tune_suihui_global_scale,number,420,,[B§4.2] W5 裁定 P-27(F-1):渐近衰减尺度(宿慧)。查点:193→+18.4%;386→+30.1%;579→+37.4%;772→+42.0%;∞→+50%
|
||||
|
Binary file not shown.
Binary file not shown.
Binary file not shown.
@@ -1,11 +1,11 @@
|
||||
id,no,king_cn,king_en,motif_cn,motif_en,target_min,gate_merit,unlock_gen,unlock_gate,palette_id,is_prestige_gate
|
||||
hall_01_qinguang,1,秦广王,King Qinguang,孽镜台(照心),Mirror of Karma,25,2000,gen_03_guizu,up_gate_guizu,pal_hall_01,false
|
||||
hall_02_chujiang,2,楚江王,King Chujiang,寒冰狱,Ice Hell,42,30000,gen_04_biliao,up_gate_biliao,pal_hall_02,false
|
||||
hall_03_songdi,3,宋帝王,King Songdi,剥皮亭,Flaying Pavilion,62,300000,gen_05_tangpu,up_gate_tangpu,pal_hall_03,false
|
||||
hall_04_wuguan,4,五官王,King Wuguan,沸汤/毒蛇,Scalding Cauldron,84,2000000,gen_06_nanmin,up_gate_nanmin,pal_hall_04,false
|
||||
hall_05_yama,5,阎罗王,King Yama,叫唤地狱/铁床,Wailing Hell,105,10000000,gen_07_shuban,up_gate_shuban,pal_hall_05,false
|
||||
hall_06_biancheng,6,卞城王,King Biancheng,石碾,Stone Roller,125,40000000,gen_08_bingfang,up_gate_bingfang,pal_hall_06,false
|
||||
hall_07_taishan,7,泰山王,King Taishan,热油火坑,Boiling Oil Pit,143,120000000,gen_09_wodi,up_gate_wodi,pal_hall_07,false
|
||||
hall_08_dushi,8,都市王,King Dushi,泥犁/大石,Avici Stone,160,350000000,gen_10_xingzhe,up_gate_xingzhe,pal_hall_08,false
|
||||
hall_09_pingdeng,9,平等王,King Pingdeng,拔舌/铁树,Tongue-Ripping Iron Tree,175,800000000,gen_11_yinhun,up_gate_yinhun,pal_hall_09,false
|
||||
hall_01_qinguang,1,秦广王,King Qinguang,孽镜台(照心),Mirror of Karma,10,2000,gen_03_guizu,up_gate_guizu,pal_hall_01,false
|
||||
hall_02_chujiang,2,楚江王,King Chujiang,寒冰狱,Ice Hell,20,30000,gen_04_biliao,up_gate_biliao,pal_hall_02,false
|
||||
hall_03_songdi,3,宋帝王,King Songdi,剥皮亭,Flaying Pavilion,36,300000,gen_05_tangpu,up_gate_tangpu,pal_hall_03,false
|
||||
hall_04_wuguan,4,五官王,King Wuguan,沸汤/毒蛇,Scalding Cauldron,56,2000000,gen_06_nanmin,up_gate_nanmin,pal_hall_04,false
|
||||
hall_05_yama,5,阎罗王,King Yama,叫唤地狱/铁床,Wailing Hell,80,10000000,gen_07_shuban,up_gate_shuban,pal_hall_05,false
|
||||
hall_06_biancheng,6,卞城王,King Biancheng,石碾,Stone Roller,102,40000000,gen_08_bingfang,up_gate_bingfang,pal_hall_06,false
|
||||
hall_07_taishan,7,泰山王,King Taishan,热油火坑,Boiling Oil Pit,122,120000000,gen_09_wodi,up_gate_wodi,pal_hall_07,false
|
||||
hall_08_dushi,8,都市王,King Dushi,泥犁/大石,Avici Stone,142,350000000,gen_10_xingzhe,up_gate_xingzhe,pal_hall_08,false
|
||||
hall_09_pingdeng,9,平等王,King Pingdeng,拔舌/铁树,Tongue-Ripping Iron Tree,164,800000000,gen_11_yinhun,up_gate_yinhun,pal_hall_09,false
|
||||
hall_10_zhuanlun,10,转轮王,King of the Wheel,轮回道(六道环),Wheel of Rebirth,180,1500000000,none,none,pal_hall_10,true
|
||||
|
Binary file not shown.
@@ -5,8 +5,8 @@ meta_03,宿慧通透,Perspicacious Wisdom,suihui_gain_pct,,0.15,8,3,none,宿慧
|
||||
meta_04,天生熟练,Born Skilled,skip_interval,,4,12,1,none,跳过机制从每 5 级加快为每 4 级
|
||||
meta_05,阴司人脉,Netherworld Connections,offline_pct,,0.25,6,1,none,离线效率 +25%
|
||||
meta_06,斩鬼刃,Ghost-Slaying Blade,boss_click_pct,,0.3,10,1,none,殿王战点击伤害 +30%
|
||||
meta_07,心安理得,Easy Conscience,wrath_penalty_set,,0.15,15,1,none,冤气对宿慧的削减 30%→15%
|
||||
meta_08,敕封恩典,Grace of Enthronement,global_pct,,0.25,20,2,none,全局 +25%(每阶)
|
||||
meta_07,心安理得,Easy Conscience,wrath_penalty_set,,0.2,15,1,none,冤气对宿慧的削减 40%→20%
|
||||
meta_08,幽冥恩荫,Shadow Patronage,global_pct,,0.25,20,2,none,全局 +25%(每阶)
|
||||
meta_09,阴阳眼,Yin-Yang Eye,event_freq_pct,,0.2,10,1,none,事件触发频率 +20%
|
||||
meta_10,超度加速,Salvation Acceleration,souls_mult,,2,8,1,none,超度计数获取 ×2
|
||||
meta_11,老马识途,Old Horse Knows the Way,bulk_unlock,,0,5,1,none,开局即可用批量 ×10
|
||||
|
||||
|
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
@@ -0,0 +1,23 @@
|
||||
id,layer_index,effect,cost
|
||||
wrath_layer_01,1,0.15,8
|
||||
wrath_layer_02,2,0.15,28
|
||||
wrath_layer_03,3,0.15,58
|
||||
wrath_layer_04,4,0.15,97
|
||||
wrath_layer_05,5,0.15,145
|
||||
wrath_layer_06,6,0.15,201
|
||||
wrath_layer_07,7,0.15,266
|
||||
wrath_layer_08,8,0.15,338
|
||||
wrath_layer_09,9,0.15,418
|
||||
wrath_layer_10,10,0.15,505
|
||||
wrath_layer_11,11,0.15,599
|
||||
wrath_layer_12,12,0.15,701
|
||||
wrath_layer_13,13,0.15,809
|
||||
wrath_layer_14,14,0.15,925
|
||||
wrath_layer_15,15,0.15,1047
|
||||
wrath_layer_16,16,0,1176
|
||||
wrath_layer_17,17,0,1312
|
||||
wrath_layer_18,18,0,1454
|
||||
wrath_layer_19,19,0,1603
|
||||
wrath_layer_20,20,0,1758
|
||||
wrath_layer_21,21,0,1919
|
||||
wrath_layer_22,22,0,2087
|
||||
|
@@ -0,0 +1,19 @@
|
||||
[remap]
|
||||
|
||||
importer="csv_translation"
|
||||
type="Translation"
|
||||
uid="uid://yoqc8bb688f4"
|
||||
|
||||
[deps]
|
||||
|
||||
files=["res://data/sheets/wrath_layers.layer.translation", "res://data/sheets/wrath_layers.effect.translation", "res://data/sheets/wrath_layers.cost.translation"]
|
||||
|
||||
source_file="res://data/sheets/wrath_layers.csv"
|
||||
dest_files=["res://data/sheets/wrath_layers.layer.translation", "res://data/sheets/wrath_layers.effect.translation", "res://data/sheets/wrath_layers.cost.translation"]
|
||||
|
||||
[params]
|
||||
|
||||
compress=1
|
||||
delimiter=0
|
||||
unescape_keys=false
|
||||
unescape_translations=true
|
||||
Binary file not shown.
Binary file not shown.
@@ -0,0 +1,214 @@
|
||||
# F《怨返》sim 二轮校准对比报告(Round-2 Comparison)
|
||||
|
||||
> **撰写**:程基岩(engineering-lead)| **委托**:游承峰(主理人)| **日期**:2026-10-21
|
||||
> **上游**:`design/gdd/2026-10-20-F-sim-round1-adjudication.md`(下称 **[裁]**,用户 U-1~U-4 四项拍板全采纳)
|
||||
> **对照物**:`tests/sim_reports/report-2026-10-20.json`(一轮,commit `c534e95`)vs `tests/sim_reports/report-2026-10-21.json`(二轮,本文)
|
||||
> **纪律**:数值从 [裁] 照抄不发明;本文所有"实测"值均来自二轮报告字段或本机验证日志原文。
|
||||
|
||||
---
|
||||
|
||||
## 0. 结论速览
|
||||
|
||||
| 项 | 结果 |
|
||||
|---|---|
|
||||
| 一轮 5 个 FAIL 门(#2/#3/#12/#13/#14) | **4 个转 PASS**(#2/#3/#12/#14);**#13 残留 FAIL**——R4=0.40 超 ±25% 带上限 0.375,差 0.021(5.6% 边际超差) |
|
||||
| 硬门 #5 / #10 | **双 PASS 不回归**(182min ∈[120,300];双断言 单轮 11.831B + restart lifetime 7.007B 均 ≤1e14) |
|
||||
| 红线([裁] §2.5) | **根治确认**:restart lifetime 峰值 9.4979e15(一轮)→ **7.007B**(二轮),降幅约 6 个数量级;1e14 红线纪律未放宽 |
|
||||
| 验证序列 | `--import` exit=0 → import_all **PASS(10 表/238 行/0 违规)** → validate PASS → test_runner **750 检查 8/8 用例全过** → 漂移门**零差异**(gen 重跑前后 SHA-256 逐字节一致)→ 主场景 `--quit-after 200` **exit=0 零 ERROR** |
|
||||
| 阻塞项 | **git 不可用**(本环境无 git.exe:PATH/全盘常见根目录/pygit2/dulwich 均不可用)→ commit「W5 sim 一轮裁定落地 + 二轮校准」待主理人提供 git 或代为提交 |
|
||||
| 待裁定 | #13 R4 边际残留处置(选项见 §3);devour 轮后 H10 越红线观测登记(见 §4.3,不阻塞) |
|
||||
|
||||
**"五 FAIL 全转 PASS"未达成——诚实结论是 4/5。** #13 从 R2=0.06 的崩塌态恢复到 R2=0.48/R3=0.42 入带、仅 R4=0.396 贴带外,属 [裁] §4.5 预告的"设计起点待二轮校准"残差,非实现 bug(论证见 §3)。
|
||||
|
||||
---
|
||||
|
||||
## 1. 落地清单(对照 [裁] §4.1/§4.2/§4.3/§7)
|
||||
|
||||
### 1.1 G-1:冤煞层数据落点(架构债拆除)
|
||||
|
||||
- **定位结论**:冤煞层原无独立表——落点是 `balance_tuning` 标量 `tune_wrath_bonus=0.25` + `economy_state.gd` 线性乘层数([B§12] 表清单漏登,[裁] §4.2 G-1 登记项)。
|
||||
- **新建**:`data/sheets/wrath_layers.csv`(22 行:`id/layer_index/effect/cost`)+ `data/schema/wrath_layers.schema.json` + `src/core/data/wrath_layer_def.gd`(`WrathLayerDef`)+ `BalanceData` 载入/索引(`wrath_layer(idx)` / `wrath_layer_effect_sum(layers)`)+ `check_references()` 交叉校验。
|
||||
- **生成链**:`gen_balance_sheets.py` 表清单 9→10 张、新增常量与 `wrath_layer_cost(n)`、`self_check()` 增 W5 断言(meta/halls/wrath_layers 交叉校验 + tune 双源防回潮)。
|
||||
- **文档补登**:`CLAUDE.md` 表清单「W3 = 9 张」→「W5 = 10 张」并注明补登 [B§12] 漏登;架构文档(`docs/architecture/`,C 盘设计仓)属文策渊辖地,**未越权修改**——已在 §7 列为设计侧待办。
|
||||
|
||||
### 1.2 CSV 改动([裁] §4.1 总表 20 行,全部照抄落盘)
|
||||
|
||||
| # | 表/列 | 原值 | 新值 | 二轮实测印证 |
|
||||
|---|---|---|---|---|
|
||||
| 1-2 | `wrath_layers` effect L1-L15 / L16-L22 | 0.25 | **0.15 / 0.00** | devour 轮 22 层终态、层数时间线 1→22 可复盘(M-3) |
|
||||
| 3 | 冤煞削减速(tune) | −3%/层 cap −30% | **−4%/层 cap −40%**(`tune_wrath_penalty` 0.03→0.04 / cap 0.3→0.4) | #12 转 PASS(§2) |
|
||||
| 4 | `meta_07` 心安理得 effect_param | 0.3(削减 30%→15%) | **0.2(削减 40%→20%)** | desc 列同步 |
|
||||
| 5-7 | `balance_tuning` 新增 3 行 | — | **tune_suihui_global_max=0.50 / tune_suihui_global_scale=420 / tune_skip_level_cap_per_gen=50** | #13/#10 根治(§3/§4) |
|
||||
| 8-16 | `halls` 到达目标列 H1-H9 | 25/42/62/84/105/125/143/160/175 | **10/20/36/56/80/102/122/142/164** | #3 greedy 全殿入带(§2) |
|
||||
| 17 | `halls` H10 目标 | 180 | **180(不改)** | 门 #5 口径不变 |
|
||||
| 18 | `meta_08` 显示名 | 敕封恩典 | **幽冥恩荫(Shadow Patronage)** | [裁§3 P-4] 既定消歧落盘 |
|
||||
| 19 | `meta_04` 天生熟练 | (P2 备选) | **不改,二轮再定** | 按 U-5 维持 |
|
||||
| 20 | `halls` 殿门阈值列 | 2K…1.5B | **不改(显式声明)** | 经济曲线零动的验证:三策略 H10 时刻与一轮逐分不差(182/215/220min) |
|
||||
|
||||
### 1.3 代码公式([裁] §4.2:F-1/F-2 落地,F-3 不采用)
|
||||
|
||||
- **F-1**(`economy_state.recompute` 宿慧全局项):`3%×宿慧` → `0.50×(1−e^(−宿慧/420))`,加法进全局乘区,读 `tune_suihui_global_max/scale`(`_suihui_global_add()`)。
|
||||
- **F-2**(跳过机制,`_apply_rebirth_start_levels`):每档获赠 = `min(floor(宿慧/5)×25, tune_skip_level_cap_per_gen)`;m04 用 `floor(宿慧/4)`。
|
||||
- **F-3 不采用**:走逐行 0.00 数据自解释([裁] §4.2 推荐路径),零钳制代码。
|
||||
- **G-1 联动**:全局区 `gadd = _suihui_global_add() + data.wrath_layer_effect_sum(wrath_layers)`(替代旧 `tune_wrath_bonus` 线性乘层数)。
|
||||
|
||||
### 1.4 验收门修订([裁] §4.3 四条)+ sim 输出([裁] §7 补测清单)
|
||||
|
||||
- **#2**:购买事件计数 → **不同条目数**(`(kind, target_id)` 去重 ∈[3,6]),测量策略 novice;`simulator.gd` purchases 逐条目记 `{t,kind,target_id,count}`(M-1)。
|
||||
- **#3/#14**:对照新目标表 ±20%(旧分段容差废止),主口径 **greedy**;`sim_main.gd` primary 合并逻辑显式化(#1/#2 采 novice、其余采 greedy)。
|
||||
- **#10**:**双断言**(单轮峰值 ≤1e14 且 restart 5 轮 lifetime 峰值 ≤1e14,`gate_peak_double`)。
|
||||
- **#13**:容差显式 ±25%(R1-R4);R5 起触底 ≥0.25× 口径不变(本轮 8h 预算只跑到 R4+部分 R5,触底支路未覆盖,见 §7.3)。
|
||||
- **M-2**:restart 轮 `buy_meta:true`(宿慧商店全买,真实玩家口径);**M-3**:devour 轮进 `runs` 数组;**M-6**:restart lifetime 进门 #10 断言。
|
||||
|
||||
---
|
||||
|
||||
## 2. 14 门 + cross 一轮→二轮对照
|
||||
|
||||
> 主口径 = primary(#1/#2 采 novice,其余采 greedy,[裁] §4.3);greedy/random 的策略噪声按裁定进 cross 观测。
|
||||
|
||||
| 门 | 一轮(10-20) | 二轮(10-21) | 判定 |
|
||||
|---|---|---|---|
|
||||
| #1 首购点击 ∈[10,20] | novice 16 / greedy 15 / random 15 | 16 / 15 / 15 | 维持 PASS |
|
||||
| #2 前 5min(新口径:不同条目 ∈[3,6]) | 事件计数 23/15/15 **FAIL** | novice **5 条目 PASS**(greedy/random 各 2,同条目重复购买,非主口径) | **转 PASS** |
|
||||
| #3 殿门到达表 ±20% | greedy H1 8/25min=32%…H10 182/180 **FAIL** | greedy **8/10=80% / 20/20=100% / 36/36 / 56/56 / 79/80=99% / 102/102 / 122/122 / 142/142 / 164/164 / 182/180=101%** | **转 PASS** |
|
||||
| #4 最大购买间隔 ≤60min | 9/1/1 min | 9/1/1 min | 维持 PASS |
|
||||
| #5 到 H10 ∈[120,300]min(**硬门**) | 182/215/220 min | 182/215/220 min(逐分不差) | **硬门不回归** |
|
||||
| #6 无墙(最差窗口 ≥1.0×) | 4.03×/21.60×/10.80× | 同值 | 维持 PASS |
|
||||
| #7 cross 策略极差 <1.5× | 1.21× | 1.21× | 维持 PASS |
|
||||
| #8 回本时间 | t2 120s…t6 293s | 同值 | 维持 PASS |
|
||||
| #9 离线契约 v2(a/b/c) | a/b/c PASS | a/b/c PASS(β 口径仍 deferred,M-4) | 维持 PASS |
|
||||
| #10 终局峰值 ≤1e14(**硬门**) | 单轮 11.831B PASS——但 restart lifetime **9.4979e15 越界在旧口径盲区** | **双断言:单轮 11.831B + restart lifetime 7.007B,均 ≤1e14** | **转 PASS(口径扩展+根治)** |
|
||||
| #11 BossBattle | deferred | deferred(M-5) | 维持 |
|
||||
| #12 怨煞取舍 devour/pure ∈(0.3,3.0) | **0.21×**(38min vs 182min)FAIL | **0.34×**(62min vs 182min)PASS | **转 PASS** |
|
||||
| #13 重开曲线 1:0.6:0.4:0.3(±25%) | R2=0.06/R3=0.03/R4=0.02 **FAIL** | R1=1.00 / **R2=0.48 ✓**(带[0.45,0.75])/ **R3=0.42 ✓**(带[0.30,0.50])/ **R4=0.40 ✗**(带[0.225,0.375],超 0.021) | **残留 FAIL**(§3) |
|
||||
| #14 殿门标定 ∈[80%,120%] | greedy H1 34%…H10 101% **FAIL** | greedy **84/101/101/100/99/100/100/100/100/101%** 全入带 | **转 PASS** |
|
||||
|
||||
**主口径汇总**:13 项评门中 12 PASS + #13 FAIL;#11 deferred。硬门 5/10 双 true。
|
||||
**注意**:sim 控制台行「主口径未过门 = []」只遍历 primary——#7/#12/#13 是报告顶层独立字段(`cross`/`wrath_tradeoff`/`restart`),#13 的 FAIL **不出现**在该摘要行里,读 CI 日志时以 JSON 顶层 `restart.pass` 为准(观测记录,非 bug)。
|
||||
|
||||
---
|
||||
|
||||
## 3. #13 专项:R4 边际残留分析
|
||||
|
||||
### 3.1 实测数据(二轮 restart 轮:greedy + 商店全买,8h 预算,rebirths=4)
|
||||
|
||||
| 轮 | 转世时刻 | 本轮间隔 | 比率 | 目标(带) | 判定 | 本轮 suihui_gain |
|
||||
|---|---|---|---|---|---|---|
|
||||
| R1 | — | 10896s(181.6min) | 1.00 | 1.00 | ✓ | 193 |
|
||||
| R2 | t=10896s | 5218s(87.0min) | 0.48 | 0.60([0.45,0.75]) | ✓ | 279 |
|
||||
| R3 | t=16114s | 4573s(76.2min) | 0.42 | 0.40([0.30,0.50]) | ✓ | 279 |
|
||||
| R4 | t=20687s | 4312s(71.9min) | **0.396** | 0.30([0.225,0.375]) | **✗ 超 0.021** | 279 |
|
||||
|
||||
终局:`suihui=892`(毛获 193+279×3=1030,商店消费 138)、`wrath_layers=0`、班底级数 [70,60,50,30,20,20](前三档 50 级封顶痕迹 + 途中购买)、`peak_lifetime=7.007B`。
|
||||
|
||||
### 3.2 归因:校准残差,非实现 bug
|
||||
|
||||
1. **公式严格按 [裁] §2.4 落地并有单测逐点背书**:F-1 渐近查点(193→+18.4% / 386→+30.1% / 579→+37.4% / 772→+42.0% / 892→+44.0% / ∞→+50%)与 F-2 钳制(`min(floor(宿慧/5)×25,50)`)均在 `test_economy_state.gd`(101 检查)断言内;750 检查全过。
|
||||
2. **门严格按 [裁] §4.3 落地**:±25% 容差、R1-R4 目标曲线,`gates.gd:evaluate_restart` 一行未偏。
|
||||
3. **残差来源 = [裁] §4.5 预估表的线性模型盲区**:预估用「182min ÷ 总倍率」直接除,未计成本指数增长/解锁门/购买节奏对倍率的**阻尼**。实测各轮比预估**慢**:R2 85→87.0min(+2.0)、R3 70→76.2min(+6.2)、R4 62→71.9min(+9.9)——偏差逐轮放大,比率因此系统性高出预估(+0.02/+0.04/+0.056)。R2/R3 目标带宽余量大(0.60/0.40),吸收了偏差;R4 目标 0.30 的带上限 0.375 < 0.396,成为唯一漏点。
|
||||
4. **M-2 商店口径生效的证据**:R2 起 suihui_gain 193→279(商店加速输出 → 每轮阴德 ~2.1×),这正是"含商店口径比解析预估更善加速"方向的一致证据——预估表本身标注了此口径更严,但除式模型仍高估了倍率效力。
|
||||
5. **曲线形态健康度**:R1→R4 = 1:0.48:0.42:0.40,仍单调递减。R4 之后走向本轮 sim 未测(8h 预算只完成 R1-R4,R5 进行中被截断);按 [裁] §4.5 预估表(R5≈0.32 / R10+≈0.26)叠加本轮实测偏差方向外推,R10+ ≈0.28-0.32(**外推值,未经 sim 验证**),仍 ≫0.25 触底线。对比一轮 1:0.06:0.03:0.02 的崩塌态,P0 级设计缺陷(内容烧穿 + 红线根因)已根治。**残留是"贴带外 5.6%"的校准问题,不是"3 小时主线 10 分钟烧完"的机制问题。**
|
||||
|
||||
### 3.3 处置选项(**待设计侧/用户拍板,工程不自行旋钮**)
|
||||
|
||||
| 选项 | 内容 | 工程评估 |
|
||||
|---|---|---|
|
||||
| **A 接受实测曲线为校准则** | 更新 [B§4.3] 重开目标曲线为 1:0.48:0.42:0.40(R4 目标 0.40,±25% 带宽不变),或等价地把 R4 目标记 0.40 | 数据自洽优先,不动经济;叙事仍满足"前密后疏 + ≥0.25 触底"(R4 后走向按 §3.2-5 外推仍 ≫0.25)。需文策渊出修订条 |
|
||||
| **B 放宽 R4 容差** | 前 4 轮 ±25%→±35%(R4 上限 0.405,0.396 入带) | 最小改动;但需注意 [裁] §2.4 曾**明确否决**"改验收目标"方案——彼时是 10× 烧穿(0.06 vs 0.6),本次为 6.7% 边际超差,性质不同,仍须设计侧显式批准 |
|
||||
| **C 参数微调** | scale 420→600 / m08 +25%→+15% 每阶 / skip cap 50→35 及其组合 | **单旋钮不干净**(定量见下);需设计侧选定方向后工程跑变体 sim(每个 ~10s)再拍板 |
|
||||
| **D 维持 FAIL 进 W6** | #13 非硬门(硬门仅 #5/#10),informational 通道已记录;W6 转正评估时连同 M-4(β 标定)一并处理 | 零风险;#13 的 P0 救治目标(防烧穿+红线)已达成,残余不影响玩家体验底线 |
|
||||
|
||||
**选项 C 定量备忘**(工程侧算术,供拍板参考;全经济响应需变体 sim 确认):
|
||||
- `scale 420→600`:宿慧 579-892 区间的宿慧项分量 ×1.374~×1.440 降为 ×1.357~×1.387(−4.2%~−5.3% 分量),折算比率约 −1.5~−2%(阻尼后)→ R4 ≈0.38-0.39,**单独不足以**入带;
|
||||
- `m08 降阶`:压后期但同时压 R2——R2 现贴 0.45 下界仅 0.03 余量,有跌穿风险([裁] §3.1 预留该旋钮本是防 R2 过慢,方向相反);
|
||||
- `skip cap 50→35`:R2-R4 开盘各慢一档,R2 同样面临 0.45 下界风险。
|
||||
- 结论:若设计侧要"参数派"过门,预计需 scale+skip cap 组合,且必然以 R2 贴边为代价——**工程建议优先 A 或 D**。
|
||||
|
||||
---
|
||||
|
||||
## 4. 红线闭环与新观测登记
|
||||
|
||||
### 4.1 [裁] §2.5 红线越界根治确认
|
||||
|
||||
| 口径 | 一轮 | 二轮 | 红线 |
|
||||
|---|---|---|---|
|
||||
| restart lifetime 峰值 | **9.4979e15(越界 95×)** | **7.007B** | ≤1e14 ✓ |
|
||||
| 单轮峰值(greedy) | 11.831B | 11.831B | ≤1e14 ✓ |
|
||||
| 标准三策略各轮峰值 | 2.732B/11.831B/2.497B | 同值 | ✓ |
|
||||
|
||||
机制确认:宿慧 892 时 F-1 给 +44.0%(封顶 +50%),全局长尾 ≤×2.25 量级 → 终局累计封在 ~1e10 量级,与 [裁] §2.4 预估(≤3e12)同量级且更紧。"银行式刷宿慧"两端封死:√(1e12/1e6)×5=5000 宿慧仍只 +49.9%。
|
||||
|
||||
### 4.2 工程闩锁(二道防线)实战记录
|
||||
|
||||
- test_runner stderr 出现 `BigNumber 超红线:1.000Qa > 1e14(上下文:test)`——`test_economy_formulas.gd:117` **故意触发**红线哨兵的断言用例,0 失败,属预期。
|
||||
- sim stderr 出现 `BigNumber 超红线:100.014T > 1e14(上下文:EconomyState.tick)`——devour 压力轮触发闩锁报错,sim 不崩、exit=0,二道防线按设计工作。
|
||||
|
||||
### 4.3 新观测登记(不阻塞本轮,建议 W6 处理)
|
||||
|
||||
**devour 轮 H10 后越红线**:devour 轮(#12 压力场景)`peak_lifetime=2.498e14`(越线 25×)。构成:满 22 层怨煞 ×3.25 使购买力在 H10 后不枯竭(终态 output 1.08e11/s vs 最便宜升级 8e11,约 7.4s 即可再买一级)→ 挂机 2.7h 复现"数字通胀"形态。定性:与 [裁] §2.5 已登记的"愿景档边界"同族(后 H10 无界膨胀),且 devour 是超出标准路线的压力场景;门 #10 双断言按 [裁] §4.3 的主线路口径(greedy 单轮 + restart lifetime)判定,devour 不在其内。**建议**:W6 敕封/愿景档实装前校准项中,明确 #10 的"单轮峰值"是否取 max-over-runs(若取,需先设计侧处理后 H10 膨胀:gen12 rate 下调或 lifetime 显式软上限,即 [裁] §2.5 已列选项)。
|
||||
|
||||
---
|
||||
|
||||
## 5. 每项改动实测效果
|
||||
|
||||
| 改动 | 实测效果 | 对应门 |
|
||||
|---|---|---|
|
||||
| G-1 冤煞独立表 + effect 剖面(L1-15=0.15/L16-22=0)+ 削减速 −4%/cap 40% + m07 20% | #12:0.21×→**0.34×**(devour 38min→62min vs pure 182min 不变);devour 层数时间线 1→22 全程可复盘(M-3 达成);成就 #20(≥20 层)仍可达(devour 终态 22 层) | #12 转 PASS |
|
||||
| 同上——标准路线零影响验证 | 三策略 `wrath_layers` 全程 0;cross 1.21× 与一轮逐值不差 | #7 不回归 |
|
||||
| F-1 宿慧全局渐近 | #13 R2 0.06→0.48;红线 restart 9.5e15→7.007B;宿慧商店购买力不变(R2 开盘 193 宿慧 > 全店可购成本,商店正常运转——终局钱包 892 = 毛获 1030 − 商店消费 138) | #13/#10 根治 |
|
||||
| F-2 跳过每档 cap 50 | R2 开盘白送 150 级/3 档(原 2850 级);restart 终局班底 [70,60,50,30,20,20] 可见封顶形态;m04 贬值按 U-5 维持 P2 | #13 根治 |
|
||||
| halls 目标列改写(阈值不动) | #3 greedy 全殿 ∈[80%,120%](H1 贴 80% 下界为最紧点,[裁] §2.2 预判命中);novice/random 的 #3/#14 策略噪声按裁定分流进 cross(1.21× PASS),不再误报 pacing | #3/#14 转 PASS |
|
||||
| #2 不同条口径 + target_id | novice 前 300s 共 5 个不同 `(kind,target_id)`:`gen_01_youhun` 级数(重复购买只计 1)、`up_click_1`@127s、`up_eff_gen_01_youhun_1`@191s、`gen_02_yinbing`@263s、`up_eff_gen_01_youhun_2`@279s——与 [B§9]"gen2 及前几条效率升级"的预期构成逐项对上;greedy/random 各 2 条目(同条目重复购买)不再误报 | #2 转 PASS |
|
||||
| M-2 商店口径 | R2 起 suihui_gain 193→279;#13 曲线含真实玩家加速 | #13 口径真实化 |
|
||||
|
||||
**零经济改动的交叉验证**:殿门阈值、班底、升级、事件全部未动 → 三策略 H10 时刻一轮/二轮**逐分不差**(182/215/220min)、#4/#6/#8/#9 逐值相同——证明二轮所有门变化全部来自裁定内的目标表/口径/公式修改,无漂移性附带损伤。
|
||||
|
||||
---
|
||||
|
||||
## 6. 验证序列(全绿,证据留存 `logs/`,该目录已 gitignore)
|
||||
|
||||
| 步骤 | 命令 | 结果 |
|
||||
|---|---|---|
|
||||
| 1 | `godot --headless --path . --import` | exit=0 |
|
||||
| 2 | `-s res://src/tools/import_main.gd` | **PASS(10 表/238 行/0 违规)**,wrath_layers 22 行在列 |
|
||||
| 3 | `-s res://src/tools/import_main.gd -- --validate-only` | **PASS(build 目录全部合规)** |
|
||||
| 4 | `-s res://tests/unit/test_runner.gd` | **PASS(750 检查全过)**:number_format 14 / economy_formulas 160 / balance_data 78 / economy_state 101 / camera_data 86 / event_director 41 / boss_battle 230 / offline_contract 40 |
|
||||
| 5 | 漂移门(git 不可用,改 Python 等价) | gen 脚本重跑前后 `data/sheets`(88 文件)+ `data/build`(10 文件)**SHA-256 逐字节一致**;import_all 差异化「~0 变更」 |
|
||||
| 6 | `-s res://src/core/sim/sim_main.gd` | exit=0;报告落 `tests/sim_reports/report-2026-10-21.json`;硬门 {"5": true, "10": true};sim 确定性(重跑报告逐值一致) |
|
||||
| 7 | `--quit-after 200`(主场景 stage_root.tscn) | exit=0,**零 ERROR** |
|
||||
|
||||
**确定性备注**:sim 无时钟依赖(RandomStrategy 种子 7、固定步长),二轮报告重跑逐值一致;`report-2026-10-21.json` 为可复现产物。
|
||||
|
||||
---
|
||||
|
||||
## 7. 待办与阻塞
|
||||
|
||||
### 7.1 阻塞:git 提交(环境缺失)
|
||||
|
||||
本环境 **git.exe 不可用**(PATH 无、常见安装根目录全盘无、Python 无 pygit2/dulwich)。以下提交待主理人提供 git 路径或代为执行:
|
||||
|
||||
- **提交信息**:「W5 sim 一轮裁定落地 + 二轮校准」
|
||||
- **改动文件**(D:\wrath-of-the-dead,均相对 HEAD `c534e95` 的新增/修改):
|
||||
- 数据:`data/sheets/wrath_layers.csv`(新)、`data/sheets/balance_tuning.csv`、`data/sheets/halls.csv`、`data/sheets/meta_upgrades.csv`;`data/build/wrath_layers.json`(新)及内容受影响的重生成 build JSON(`balance_tuning`/`halls`/`meta_upgrades`;其余 6 表 build 与 HEAD 逐字节一致,已由漂移门哈希证实)
|
||||
- Schema:`data/schema/wrath_layers.schema.json`(新)
|
||||
- 代码:`src/core/data/wrath_layer_def.gd`(新)、`balance_data.gd`、`economy_state.gd`、`prestige_model.gd`、`sim/gates.gd`、`sim/simulator.gd`、`sim/sim_main.gd`、`tools/gen_balance_sheets.py`、`tools/import_main.gd`、`tools/sheet_importer.gd`(R15/R16 预存 bug 修复)
|
||||
- 测试:`tests/unit/cases/test_economy_state.gd`、`test_economy_formulas.gd`、`test_balance_data.gd`
|
||||
- 文档:`CLAUDE.md`(表清单 9→10 补登)、`docs/engineering/2026-10-20-f-sim-round2-comparison.md`(本文件)、`tests/sim_reports/report-2026-10-21.json`
|
||||
- **提交前检查**(git 可用后):`git status` 应只含上述文件;`logs/` 已被 .gitignore 忽略(临时探查产物不入库)。
|
||||
|
||||
### 7.2 待裁定(按优先级)
|
||||
|
||||
1. **#13 R4 残留**:选项 A/B/C/D(§3.3),工程建议 A 或 D;若选 C,工程立即可跑变体 sim 定量。
|
||||
2. **devour 后 H10 越红线**(§4.3):是否纳入 #10 断言口径 + 设计侧处理选项,建议 W6 敕封校准项一并处理。
|
||||
3. **设计侧文档补登**:[B§12] 表清单补登 `wrath_layers`(架构文档在 C 盘设计仓,属文策渊);若采选项 A,需同步 [B§4.3] 重开目标曲线修订条。
|
||||
|
||||
### 7.3 W6 输入备忘
|
||||
|
||||
- M-4:门 #9-b 的 β 口径标定(离线 8h 推进比)仍缺数据;
|
||||
- M-5:门 #11(BossBattle 接入后)与 P-10/P-15 的 #11-d 触发条件;
|
||||
- #13 触底支路(R5 起 ≥0.25×)本轮未覆盖——8h 预算只完成 R1-R4;如需验证触底支路,restart 预算提至 10-12h;
|
||||
- 任务 #22/#27(W3/W4 批次提交)同受 git 缺失阻塞,可一并处理。
|
||||
|
||||
---
|
||||
|
||||
*报告完。二轮结论:裁定落地完整、硬门不回归、红线根治;#13 残留为 5.6% 边际校准残差,选项与定量已备,待拍板。*
|
||||
@@ -20,6 +20,7 @@ const SHEET_FILES: Array[String] = [
|
||||
"generators", "upgrades", "halls", "hall_palettes",
|
||||
"boss_battles", "events", "meta_upgrades", "balance_tuning",
|
||||
"camera", # W3:per-hall 相机 rig 行(camera.csv;每殿恰一行)
|
||||
"wrath_layers", # W5:冤煞层 22 行(wrath_layers.csv;[B§12] 漏登补登,G-1)
|
||||
]
|
||||
|
||||
var generators: Array[GeneratorDef] = []
|
||||
@@ -30,6 +31,7 @@ var palettes: Array[PaletteDef] = []
|
||||
var bosses: Array[BossDef] = []
|
||||
var events: Array[EventDef] = []
|
||||
var cameras: Array[CameraDef] = [] # W3:per-hall 相机 rig
|
||||
var wrath_layers: Array[WrathLayerDef] = [] # W5:冤煞层 22 行(一层一行)
|
||||
|
||||
var load_errors: Array[String] = []
|
||||
|
||||
@@ -43,6 +45,7 @@ var _camera_by_hall := {}
|
||||
var _palette_by_hall := {}
|
||||
var _event_by_id := {}
|
||||
var _tune := {} # id -> {"kind": String, "num": float, "text": String}
|
||||
var _wrath_by_index := {} # W5:layer_index -> WrathLayerDef
|
||||
|
||||
|
||||
## 从目录载入全部表(缺表 = load_errors,不静默)
|
||||
@@ -72,6 +75,7 @@ static func load_from_dir(dir: String) -> BalanceData:
|
||||
"events": bd._load_events(rows)
|
||||
"meta_upgrades": bd._load_meta(rows)
|
||||
"balance_tuning": bd._load_tuning(rows)
|
||||
"wrath_layers": bd._load_wrath_layers(rows)
|
||||
bd._build_indexes()
|
||||
bd.load_errors.append_array(bd.check_references())
|
||||
return bd
|
||||
@@ -245,6 +249,16 @@ func _load_tuning(rows: Array) -> void:
|
||||
}
|
||||
|
||||
|
||||
func _load_wrath_layers(rows: Array) -> void:
|
||||
for r in rows:
|
||||
var d := WrathLayerDef.new()
|
||||
d.id = str(r.get("id", ""))
|
||||
d.layer_index = int(r.get("layer_index", 0))
|
||||
d.effect = float(r.get("effect", 0))
|
||||
d.cost = int(r.get("cost", 0))
|
||||
wrath_layers.append(d)
|
||||
|
||||
|
||||
# ----------------------------------------------------------------------------
|
||||
# 索引与查询
|
||||
# ----------------------------------------------------------------------------
|
||||
@@ -267,6 +281,8 @@ func _build_indexes() -> void:
|
||||
_palette_by_hall[d.hall_id] = d
|
||||
for d in events:
|
||||
_event_by_id[d.id] = d
|
||||
for d in wrath_layers:
|
||||
_wrath_by_index[d.layer_index] = d
|
||||
|
||||
|
||||
func generator(id: String) -> GeneratorDef:
|
||||
@@ -307,6 +323,20 @@ func event(id: String) -> EventDef:
|
||||
return _event_by_id.get(id)
|
||||
|
||||
|
||||
## W5:冤煞层行(layer_index 1 起;越界返回 null——buy_wrath_layer 先查上限)
|
||||
func wrath_layer(layer_index: int) -> WrathLayerDef:
|
||||
return _wrath_by_index.get(layer_index)
|
||||
|
||||
|
||||
## W5:前 layers 层的 effect 合计(全局乘区加法;recompute 非热路径,逐行求和)
|
||||
func wrath_layer_effect_sum(layers: int) -> float:
|
||||
var sum := 0.0
|
||||
for d in wrath_layers:
|
||||
if d.layer_index <= layers:
|
||||
sum += d.effect
|
||||
return sum
|
||||
|
||||
|
||||
## 全局调参数(balance_tuning.csv);缺失返回 default 并记 load_errors
|
||||
func tune_num(key: String, default_value: float) -> float:
|
||||
var row: Variant = _tune.get(key)
|
||||
@@ -368,4 +398,19 @@ func check_references() -> Array[String]:
|
||||
for c in cameras:
|
||||
if _hall_by_id.get(c.hall_id) == null:
|
||||
errs.append("camera.%s.hall_id 引用了不存在的殿:%s" % [c.id, c.hall_id])
|
||||
# W5:冤煞层表完整性(wrath_layers.csv;G-1 补登)
|
||||
# ① tune_wrath_layers 与表行数交叉校验(双源必须一致)
|
||||
# ② layer_index 从 1 连续递增(一行一层,无跳号/重号——x-unique 已挡重号)
|
||||
var wrath_total := 0
|
||||
if _tune.has("tune_wrath_layers"):
|
||||
wrath_total = int(_tune["tune_wrath_layers"].num)
|
||||
if wrath_total != wrath_layers.size():
|
||||
errs.append("wrath_layers:tune_wrath_layers=%d 与表行数 %d 不一致(改层总数 = 加行 + 同步调参,走 ADR)" % [
|
||||
wrath_total, wrath_layers.size()])
|
||||
for i in wrath_layers.size():
|
||||
var wl := wrath_layers[i]
|
||||
if wl.layer_index != i + 1:
|
||||
errs.append("wrath_layers:第 %d 行 layer_index=%d(应从 1 连续递增)" % [i + 1, wl.layer_index])
|
||||
if wl.effect < 0.0:
|
||||
errs.append("wrath_layers.%s:effect 为负(%f)" % [wl.id, wl.effect])
|
||||
return errs
|
||||
@@ -0,0 +1,24 @@
|
||||
class_name WrathLayerDef
|
||||
extends RefCounted
|
||||
|
||||
# ============================================================================
|
||||
# WrathLayerDef —— 冤煞层单行定义(wrath_layers.csv / W5 补登 G-1)
|
||||
#
|
||||
# 落点史(架构债的来历):[B§12] 七张表清单漏登冤煞层——[B§3.2] 定义了 22 层
|
||||
# 效果/成本但从未给 CSV 落点,W2-W4 的实现是 balance_tuning 标量
|
||||
# tune_wrath_bonus=0.25 + economy_state.gd 线性乘层数(改一层效果要改代码)。
|
||||
# W5 sim 一轮裁定报告 §4.2 缺口 G-1 要求独立成表,工程照办。
|
||||
#
|
||||
# 字段口径(与 schema description 同步):
|
||||
# layer_index —— 层序号(1..22;与 id 对齐)
|
||||
# effect —— 该层购入后加入全局乘区的加法值(L1-15 = 0.15;
|
||||
# L16-22 = 0.00,合计封顶 +225%;W5 裁定 P-25)
|
||||
# cost —— 该层冤气成本 = round(8 × n^1.8)([B§3.2] 公式逐行落盘)
|
||||
#
|
||||
# core 作用域纪律:纯数据、无 Node、无场景树依赖(架构 §2.2)。
|
||||
# ============================================================================
|
||||
|
||||
var id: String = ""
|
||||
var layer_index: int = 0
|
||||
var effect: float = 0.0
|
||||
var cost: int = 0
|
||||
@@ -0,0 +1 @@
|
||||
uid://b8jbk5kyq6q4m
|
||||
@@ -65,17 +65,18 @@ var mutiny_left: float = 0.0 # 剩余秒数
|
||||
var _click_base: float = 1.0
|
||||
var _suihui_div: float = 1e6
|
||||
var _suihui_mult: float = 5.0
|
||||
var _suihui_global_pct: float = 0.03
|
||||
var _suihui_global_max: float = 0.5 # W5 F-1:宿慧全局渐近上限(tune_suihui_global_max)
|
||||
var _suihui_global_scale: float = 420.0 # W5 F-1:渐近衰减尺度(tune_suihui_global_scale)
|
||||
var _enthrone_bonus: float = 0.25
|
||||
var _skip_interval: int = 5
|
||||
var _skip_gens: int = 3
|
||||
var _skip_levels: int = 25
|
||||
var _skip_level_cap: int = 50 # W5 F-2:跳过每档获赠封顶(tune_skip_level_cap_per_gen)
|
||||
var _enthrone_rebirths: int = 2
|
||||
var _enthrone_suihui_req: int = 60
|
||||
var _souls_div: float = 10000.0
|
||||
var _wrath_bonus: float = 0.25
|
||||
var _wrath_penalty: float = 0.03
|
||||
var _wrath_penalty_cap: float = 0.3
|
||||
var _wrath_penalty: float = 0.04 # W5 裁定:每层宿慧削减 +4%(原 +3%)
|
||||
var _wrath_penalty_cap: float = 0.4 # W5 裁定:削减封顶 40%(原 30%;m07 改 20%)
|
||||
|
||||
var _mult: MultiplierSet # 三乘区计算器(输入由 recompute 写入)
|
||||
var _red_line_reported := false # 红线越界只报首次(防 sim 长跑每 tick 刷屏)
|
||||
@@ -90,17 +91,24 @@ func _init(p_data: BalanceData) -> void:
|
||||
_click_base = data.tune_num("tune_click_base", 1.0)
|
||||
_suihui_div = data.tune_num("tune_suihui_div", 1e6)
|
||||
_suihui_mult = data.tune_num("tune_suihui_mult", 5.0)
|
||||
_suihui_global_pct = data.tune_num("tune_suihui_global_pct", 0.03)
|
||||
# W5 裁定 F-1(sim 一轮裁定 §2.4):宿慧全局加成由"+3%/级线性无界"改为
|
||||
# 渐近封顶 0.50×(1−e^(−宿慧/420))——R2 开盘 ×6.79、红线 9.5e15 的根因。
|
||||
# 旧 tune_suihui_global_pct 行已移除(线性公式被取代,防双源)。
|
||||
_suihui_global_max = data.tune_num("tune_suihui_global_max", 0.5)
|
||||
_suihui_global_scale = data.tune_num("tune_suihui_global_scale", 420.0)
|
||||
_enthrone_bonus = data.tune_num("tune_enthrone_bonus", 0.25)
|
||||
_skip_interval = int(data.tune_num("tune_skip_interval", 5.0))
|
||||
_skip_gens = int(data.tune_num("tune_skip_gens", 3.0))
|
||||
_skip_levels = int(data.tune_num("tune_skip_levels", 25.0))
|
||||
# W5 裁定 F-2:跳过每档获赠 = min(floor(宿慧/5)×25, 50)(原无封顶 → R2 白送 2850 级)
|
||||
_skip_level_cap = int(data.tune_num("tune_skip_level_cap_per_gen", 50.0))
|
||||
_enthrone_rebirths = int(data.tune_num("tune_enthrone_rebirths", 2.0))
|
||||
_enthrone_suihui_req = int(data.tune_num("tune_enthrone_suihui_req", 60.0))
|
||||
_souls_div = data.tune_num("tune_souls_div", 10000.0)
|
||||
_wrath_bonus = data.tune_num("tune_wrath_bonus", 0.25)
|
||||
_wrath_penalty = data.tune_num("tune_wrath_penalty", 0.03)
|
||||
_wrath_penalty_cap = data.tune_num("tune_wrath_penalty_cap", 0.3)
|
||||
# W5 裁定(sim 一轮裁定 §2.3 配套):削减速 −3%/层封顶 −30% → −4%/层封顶 −40%。
|
||||
# 冤煞层效果/成本已逐行入 wrath_layers.csv(G-1),tune_wrath_bonus/cost_* 已移除。
|
||||
_wrath_penalty = data.tune_num("tune_wrath_penalty", 0.04)
|
||||
_wrath_penalty_cap = data.tune_num("tune_wrath_penalty_cap", 0.4)
|
||||
gen_levels.resize(data.generators.size())
|
||||
recompute()
|
||||
|
||||
@@ -361,11 +369,16 @@ func save_soul(lump: float) -> void:
|
||||
poll_halls()
|
||||
|
||||
|
||||
## 下一层怨煞成本([B§3.2]:round(8 × n^1.8),n 从 1 起)
|
||||
## 下一层怨煞成本(W5 G-1:读 wrath_layers.csv 逐行 cost 列,公式参数已入表)
|
||||
func wrath_layer_cost() -> int:
|
||||
return PrestigeModel.wrath_layer_cost(wrath_layers + 1,
|
||||
data.tune_num("tune_wrath_cost_base", 8.0),
|
||||
data.tune_num("tune_wrath_cost_exp", 1.8))
|
||||
var row := data.wrath_layer(wrath_layers + 1)
|
||||
if row != null:
|
||||
return row.cost
|
||||
# 表外(理论不可达:buy_wrath_layer 先查上限):回退最末行成本供 UI 显示
|
||||
if data.wrath_layers.is_empty():
|
||||
return 0
|
||||
var last: WrathLayerDef = data.wrath_layers.back()
|
||||
return last.cost
|
||||
|
||||
|
||||
## 买一层怨煞;返回 {ok, reason, layers}
|
||||
@@ -382,7 +395,7 @@ func buy_wrath_layer() -> Dictionary:
|
||||
return {"ok": true, "reason": OK, "layers": wrath_layers}
|
||||
|
||||
|
||||
## 冤气对宿慧的削减率(每层 +3% 封顶 30%;m07 改 15%,[B§3.2])
|
||||
## 冤气对宿慧的削减率(W5 裁定:每层 +4% 封顶 40%;m07 改 20%,[B§3.2])
|
||||
func wrath_penalty() -> float:
|
||||
var override_cap := 0.0
|
||||
var m07 := data.meta("meta_07")
|
||||
@@ -463,7 +476,10 @@ func _apply_rebirth_start_levels() -> void:
|
||||
if m04 != null and meta_ranks.get("meta_04", 0) > 0:
|
||||
interval = int(m04.effect_param)
|
||||
var skips := PrestigeModel.skip_count(suihui, interval)
|
||||
var bonus := skips * _skip_levels
|
||||
# W5 裁定 F-2(sim 一轮裁定 §2.4):每档获赠 = min(floor(宿慧/间隔) × 25, 50)
|
||||
# (原无封顶:193 宿慧 → 38 次触发 ×25 级 ×3 档 = 2850 级 ≈ R1 第 120 分钟
|
||||
# 状态开盘,第二轮 10 分钟烧穿 3h 主线;钳到 150 级后仍有清晰体感)
|
||||
var bonus: int = mini(skips * _skip_levels, _skip_level_cap)
|
||||
var cover := int(mini(float(_skip_gens), float(gen_levels.size())))
|
||||
for i in cover:
|
||||
gen_levels[i] += bonus
|
||||
@@ -481,6 +497,20 @@ func _apply_rebirth_start_levels() -> void:
|
||||
# 乘区重算(购买/轮回/敕封后调用;非热路径)
|
||||
# ----------------------------------------------------------------------------
|
||||
|
||||
## W5 裁定 F-1(sim 一轮裁定 §2.4):宿慧全局加成 = max × (1 − e^(−宿慧/scale))
|
||||
## 旧口径 +3%/级线性无界(193 宿慧 → +579% = ×6.79)是重开崩塌(R2=0.06)与
|
||||
## 红线越界(9.5e15)的根因;渐近函数同时封死两端——低宿慧区实践不可达
|
||||
## (首次转世必得 ≈193),"银行式刷宿慧"(挂 1e12 再转世得 5000)也只到 +50%。
|
||||
func _suihui_global_add() -> float:
|
||||
if _suihui_global_scale <= 0.0:
|
||||
return 0.0
|
||||
var s := float(suihui)
|
||||
if s <= 0.0:
|
||||
return 0.0
|
||||
var decay: float = exp(-s / _suihui_global_scale)
|
||||
return _suihui_global_max * (1.0 - decay)
|
||||
|
||||
|
||||
func recompute() -> void:
|
||||
# 点击区:L1-4 为 ×2/级(计数);L5-12 法器附加进全局区(P-15,[B§1] 公式口径)
|
||||
var click_levels := 0
|
||||
@@ -496,14 +526,18 @@ func recompute() -> void:
|
||||
eff[u.target_gen] = int(eff.get(u.target_gen, 0)) + 1
|
||||
for gid in eff:
|
||||
_mult.set_gen_eff(gid, eff[gid])
|
||||
# 全局区加法总和([B§1]:宿慧×3% + 法器附加 + 冤煞层 + 敕封 25% + m08 + m12)
|
||||
# 全局区加法总和([B§1]:宿慧渐近 + 法器附加 + 冤煞层 + 敕封 25% + m08 + m12)
|
||||
# ⚠ 防双重计入约束(systems-spec §1.2 B2 / 第三章 P-10 耦合条,用户 2026-10-20 拍板):
|
||||
# L5-12 的 click_output_pct(8×+1% 产出/s)进全局区 ⇒ 提升产出/s ⇒ **同时**提升
|
||||
# 军列 DPS 与殿王战点击伤害(click_dmg = P × κ)。这是可接受的(点击树本就该是
|
||||
# boss 战投资),但 **不得**再把它计入 κ 的分子——κ 只按"已购点击升级条数/12"
|
||||
# (BossBattle.click_line_ratio)计算,杜绝二次放大。改此函数前先读 systems-spec §1.2。
|
||||
var gadd := float(suihui) * _suihui_global_pct
|
||||
gadd += float(wrath_layers) * _wrath_bonus
|
||||
# W5 裁定 F-1(sim 一轮裁定 §2.4):宿慧全局项 3%×宿慧(线性无界)→
|
||||
# 0.50×(1−e^(−宿慧/420)) 渐近封顶。查点:193→+18.4%;386→+30.1%;
|
||||
# 579→+37.4%;772→+42.0%;1550→+48.8%;∞→+50%(同时堵死"银行式刷宿慧")。
|
||||
var gadd: float = _suihui_global_add()
|
||||
# W5 G-1:冤煞层效果逐行求和(wrath_layers.csv;L1-15 = +15%/层,L16-22 = 0)
|
||||
gadd += data.wrath_layer_effect_sum(wrath_layers)
|
||||
if enthroned:
|
||||
gadd += _enthrone_bonus
|
||||
for u in data.upgrades:
|
||||
|
||||
@@ -6,9 +6,12 @@ extends RefCounted
|
||||
#
|
||||
# 公式([B§4],参数全部来自 balance_tuning.csv,代码零硬编码):
|
||||
# 宿慧获得 = floor(√(本轮累计阴德 / div) × mult) × (1 + 宿慧获取加成)
|
||||
# × (1 - 冤气削减) 削减封顶 30%(m07 可降至 15%)
|
||||
# 跳过机制:每 skip_interval 级宿慧 → 前 skip_gens 档班底各 +skip_levels 级
|
||||
# (m04 把间隔 5 改为 4;工程裁定叠加,见 provenance P-11)
|
||||
# × (1 - 冤气削减) 削减封顶 40%(m07 可降至 20%;W5 裁定)
|
||||
# 跳过机制:每 skip_interval 级宿慧 → 前 skip_gens 档班底各 +skip_levels 级,
|
||||
# 每档封顶 skip_level_cap(W5 裁定 F-2;m04 把间隔 5 改为 4;
|
||||
# 工程裁定叠加,见 provenance P-11)
|
||||
# 宿慧全局加成(economy_state.recompute):0.50×(1−e^(−宿慧/420)) 渐近封顶
|
||||
# (W5 裁定 F-1;旧 3%/级线性无界已废止,tune_suihui_global_pct 移除)
|
||||
# 敕封触发:转世 ≥ enthrone_rebirths([B§4.4] 约第 2-3 轮)
|
||||
# 重开曲线目标:1 : 0.6 : 0.4 : 0.3,第 5 轮起触底 ≥0.25×(门 #13 断言)
|
||||
#
|
||||
@@ -31,12 +34,14 @@ static func suihui_gain(merit_run: float, div: float, mult: float, gain_pct: flo
|
||||
|
||||
|
||||
## 冤煞层成本([B§3.2]:第 n 层 = round(base × n^exp),n 从 1 起)
|
||||
## W5 起成本已逐行落 wrath_layers.csv(运行时读表);本函数保留为**公式基准**——
|
||||
## gen_balance_sheets.py 生成 cost 列与 test_economy_formulas 交叉校验用。
|
||||
static func wrath_layer_cost(layer_index: int, base: float, exp: float) -> int:
|
||||
var n := float(maxi(1, layer_index))
|
||||
return int(round(base * pow(n, exp)))
|
||||
|
||||
|
||||
## 冤气对宿慧的削减率(每层 +3%,封顶 30%;m07 改为 15%)
|
||||
## 冤气对宿慧的削减率(W5 裁定:每层 +4%,封顶 40%;m07 改 20%)
|
||||
static func wrath_penalty(layers: int, per_layer: float, cap: float, override_cap: float) -> float:
|
||||
var effective_cap := cap
|
||||
if override_cap > 0.0:
|
||||
|
||||
+46
-9
@@ -8,6 +8,13 @@ extends RefCounted
|
||||
# W2 状态:#11(殿王战胜率)deferred——BossBattle 逻辑 W3 落地后接入;
|
||||
# #12 用"策略级吞噬对照"近似(事件流 W3 接入后换真口径)。
|
||||
# 硬门(W6 起 CI 红):#5 主线时长 / #10 数值安全;其余 informational(§7.2)。
|
||||
#
|
||||
# W5 门定义修订(sim 一轮裁定报告 §4.3,用户四项拍板全采纳):
|
||||
# #2 前 5min 购买**事件计数** → **不同条目数**((kind,target_id) 去重,∈[3,6])
|
||||
# #3 对照 halls.csv 新到达目标列(10/20/36/56/80/102/122/142/164/180)±20%
|
||||
# #14 同 #3 目标表;主口径 greedy(novice/random 噪声归 cross 门观测)
|
||||
# #10 单轮峰值 → **双断言**(单轮 + restart 5 轮 lifetime 均 ≤1e14,见 gate_peak_double)
|
||||
# #13 前 4 轮容差 ±40% → ±25%(R5 起触底 ≥0.25× 口径不变)
|
||||
# ============================================================================
|
||||
|
||||
const HARD_GATES: Array[int] = [5, 10] # W6 起 CI 硬门(架构 §7.2)
|
||||
@@ -19,10 +26,12 @@ static func evaluate_report(report: Dictionary, data: BalanceData) -> Dictionary
|
||||
# #1 首购点击 ∈[10,20]
|
||||
var c1 := int(report.get("clicks_before_first_purchase", 0))
|
||||
g[1] = {"pass": c1 >= 10 and c1 <= 20, "detail": "首购点击 %d(目标 [10,20])" % c1}
|
||||
# #2 前 5 分钟购买 ∈[3,6]
|
||||
var c2 := int(report.get("purchases_first_5min", 0))
|
||||
g[2] = {"pass": c2 >= 3 and c2 <= 6, "detail": "前 5min 购买 %d 次(目标 [3,6])" % c2}
|
||||
# #3 解锁时间表(前 30min ±50%,之后 ±30%)
|
||||
# #2 前 5min 不同条目数 ∈[3,6](W5 修订 §4.3:口径 = (kind,target_id) 去重;
|
||||
# [B§9] 原文预期构成是"新东西首次亮相"而非同一 growth 条目的重复级数购买;
|
||||
# sim purchases 逐条目记录 target_id 是复测前提,M-1)
|
||||
var c2 := _distinct_items_first_5min(report)
|
||||
g[2] = {"pass": c2 >= 3 and c2 <= 6, "detail": "前 5min 不同条目 %d(目标 [3,6])" % c2}
|
||||
# #3 解锁时间表(W5 修订 §4.3:对照 halls.csv 新到达目标列 ±20%;主口径 greedy)
|
||||
g[3] = _gate_hall_table(report)
|
||||
# #4 购买间隔无 >60min 塌陷
|
||||
g[4] = _gate_purchase_gap(report)
|
||||
@@ -36,17 +45,41 @@ static func evaluate_report(report: Dictionary, data: BalanceData) -> Dictionary
|
||||
g[8] = _gate_payback(data)
|
||||
# #9 离线契约 v2(P-8 裁定:拆 a/b/c 三条;a 条由 FAIL 转 PASS)
|
||||
g[9] = gate_offline_v2(data)
|
||||
# #10 终局 ≤1e14
|
||||
# #10 终局 ≤1e14(单报告口径;W5 修订 §4.3:主口径另叠加 restart lifetime
|
||||
# 双断言——见 gate_peak_double,由 sim_main 组装进 primary)
|
||||
var peak := float(report.get("peak_lifetime", 0.0))
|
||||
g[10] = {"pass": peak <= BigNumber.RED_LINE,
|
||||
"detail": "峰值累计 %s(红线 1e14)" % NumberFormat.short(peak, 3)}
|
||||
# #11 殿王战(W3 deferred)
|
||||
g[11] = {"pass": true, "detail": "deferred:BossBattle 逻辑 W3 接入后评估", "deferred": true}
|
||||
# #14 殿门标定 ∈[80%,120%]
|
||||
# #14 殿门标定 ∈[80%,120%](W5 修订 §4.3:目标表随 halls.csv 更新;主口径 greedy,
|
||||
# novice/random 的策略噪声进 cross 门观测而非 pacing 判定)
|
||||
g[14] = _gate_hall_calibration(report)
|
||||
return g
|
||||
|
||||
|
||||
## 门 #10 双断言(W5 修订 §4.3):单轮峰值 ≤1e14 **且** restart 5 轮 lifetime 峰值 ≤1e14。
|
||||
## 首轮越界 9.5e15 正发生在旧单轮口径的盲区(restart 末段挂机通胀)。
|
||||
static func gate_peak_double(single_peak: float, restart_peak: float) -> Dictionary:
|
||||
var ok := single_peak <= BigNumber.RED_LINE and restart_peak <= BigNumber.RED_LINE
|
||||
return {"pass": ok,
|
||||
"detail": "单轮峰值 %s;restart lifetime %s(红线 1e14)" % [
|
||||
NumberFormat.short(single_peak, 3), NumberFormat.short(restart_peak, 3)]}
|
||||
|
||||
|
||||
## 门 #2 口径(W5 修订):前 5min 购买的**不同条目**数。
|
||||
## 条目 = (kind, target_id) 元组——同一班底的重复级数购买/同一条升级只计 1 次
|
||||
## ([B§9] 预期构成 = gen2 首购 + 前几条效率升级等"新东西首次亮相")。
|
||||
static func _distinct_items_first_5min(report: Dictionary) -> int:
|
||||
var seen := {}
|
||||
for p in report.get("purchases", []):
|
||||
if float(p.t) > 300.0:
|
||||
continue
|
||||
var key := "%s|%s" % [str(p.get("kind", "?")), str(p.get("target_id", "?"))]
|
||||
seen[key] = true
|
||||
return seen.size()
|
||||
|
||||
|
||||
## 跨策略门 #7(主导策略极差 <1.5×):入参 = 各策略报告数组
|
||||
static func evaluate_cross(reports: Array) -> Dictionary:
|
||||
var times: Array = []
|
||||
@@ -98,10 +131,11 @@ static func evaluate_restart(report: Dictionary) -> Dictionary:
|
||||
for i in intervals.size():
|
||||
var ratio := float(intervals[i]) / base
|
||||
var want: float = targets[i] if i < targets.size() else PrestigeModel.RESTART_FLOOR
|
||||
# 容差:前 4 轮 ±40%,第 5 轮起只查触底 ≥0.25×
|
||||
# 容差(W5 修订 §4.3):前 4 轮 ±25%(原 ±40% 过宽,R2=0.06 也能混过 0.6 的下半带);
|
||||
# 第 5 轮起只查触底 ≥0.25×(口径不变)
|
||||
var good: bool
|
||||
if i < targets.size():
|
||||
good = absf(ratio - want) <= 0.4 * want
|
||||
good = absf(ratio - want) <= 0.25 * want
|
||||
else:
|
||||
good = ratio <= PrestigeModel.RESTART_FLOOR * 1.2
|
||||
if not good:
|
||||
@@ -129,7 +163,10 @@ static func _gate_hall_table(report: Dictionary) -> Dictionary:
|
||||
if target_sec <= 0.0:
|
||||
continue
|
||||
var ratio := float(h.at_sec) / target_sec
|
||||
var tol := 0.5 if target_sec <= 1800.0 else 0.3 # 目标 ≤30min 的殿 ±50%
|
||||
# W5 修订 §4.3:全段 ±20%(旧"前 30min ±50%/之后 ±30%"的分段容差随
|
||||
# halls.csv 新目标列 10/20/36/…/164/180 一并废止——目标列已按 sim
|
||||
# 实测重标,不再需要前段放宽;主口径 greedy)
|
||||
var tol := 0.2
|
||||
if ratio < 1.0 - tol or ratio > 1.0 + tol:
|
||||
ok = false
|
||||
parts.append("H%d %.0f/%.0fmin" % [int(h.no), float(h.at_sec) / 60.0, target_sec / 60.0])
|
||||
|
||||
@@ -33,6 +33,7 @@ func _initialize() -> void:
|
||||
var r := Simulator.run(data, strategy, {"max_sec": 4.0 * 3600.0})
|
||||
reports.append(r)
|
||||
report.runs.append(r)
|
||||
var greedy_report: Dictionary = reports[1] # 主口径报告(#3/#10/#14 均采 greedy)
|
||||
# 每报告门(各策略全量评)
|
||||
for r in reports:
|
||||
report.gates[str(r.strategy)] = SimGates.evaluate_report(r, data)
|
||||
@@ -45,16 +46,25 @@ func _initialize() -> void:
|
||||
report.primary = primary
|
||||
# 跨策略门 #7
|
||||
report.cross = SimGates.evaluate_cross(reports)
|
||||
# 门 #13 重开曲线(greedy 5 轮,6h 预算)
|
||||
# 门 #13 重开曲线(greedy 4 轮 + 宿慧商店全买,8h 预算)
|
||||
# W5 M-2:含商店口径(m08×2 +50% / m01/m02 白送级数)才是真实玩家重启曲线
|
||||
# (裁定 §4.5 预估表即此口径);预算 6h→8h:预估 R1-R4 累计 ≈399min,
|
||||
# 6h 会在第 4 轮转世前截断(旧口径 R2-R4 仅 ~20min 所以从未暴露)。
|
||||
var restart_report := Simulator.run(data, GreedyStrategy.new(),
|
||||
{"max_sec": 6.0 * 3600.0, "rebirths": 4})
|
||||
{"max_sec": 8.0 * 3600.0, "rebirths": 4, "buy_meta": true})
|
||||
report.restart = SimGates.evaluate_restart(restart_report)
|
||||
report.runs.append(restart_report)
|
||||
# 门 #10 双断言(W5 修订 §4.3):primary 单轮口径叠加 restart 5 轮 lifetime 口径
|
||||
# (首轮越界 9.5e15 正发生在旧单轮口径盲区——restart 末段挂机通胀)
|
||||
primary[10] = SimGates.gate_peak_double(
|
||||
float(greedy_report.get("peak_lifetime", 0.0)),
|
||||
float(restart_report.get("peak_lifetime", 0.0)))
|
||||
# 门 #12 怨气取舍对照(greedy devour vs pure,各 4h)
|
||||
var pure := Simulator.run(data, GreedyStrategy.new(), {"max_sec": 4.0 * 3600.0})
|
||||
var devour := Simulator.run(data, GreedyStrategy.new(),
|
||||
{"max_sec": 4.0 * 3600.0, "devour": true})
|
||||
report.wrath_tradeoff = SimGates.evaluate_wrath_tradeoff(pure, devour)
|
||||
report.runs.append(devour) # W5 M-3:devour 轮进 runs(层数构成/wrath_layers 时间线可复盘)
|
||||
# 硬门状态汇总(W6 起 CI 红;W2 informational)
|
||||
var hard := {}
|
||||
for gate_no in SimGates.HARD_GATES:
|
||||
|
||||
+45
-15
@@ -10,17 +10,25 @@ extends RefCounted
|
||||
# W2 范围:策略 novice/greedy/random;事件/殿王战未接入(W3),
|
||||
# 因此门 #11 在 gates.gd 标记 deferred;门 #12 用"策略级吞噬对照"近似
|
||||
# (wrath 入口 devour API 已就绪,W3 换真事件流)。
|
||||
#
|
||||
# W5 补测落地(sim 一轮裁定报告 §7):
|
||||
# M-1:purchases 逐条目记录(kind + target_id + count)——门 #2"不同条目"
|
||||
# 口径的复测前提(旧日志只有聚合 count,无法去重);
|
||||
# M-2:restart 运行消费宿慧商店(opts.buy_meta:按购买力全买 m01-m12)——
|
||||
# [B§4.2] 重启曲线在含商店口径下才真实(m08×2 +50% / m01/m02 白送级数);
|
||||
# M-3:timeline 快照补 wrath_layers + devour 运行进 runs 数组(sim_main)。
|
||||
# ============================================================================
|
||||
|
||||
const SNAPSHOT_INTERVAL := 60 # 里程碑快照间隔(秒)
|
||||
|
||||
|
||||
## 跑一个策略。opts:{max_sec, seed, rebirths, devour}
|
||||
## 跑一个策略。opts:{max_sec, seed, rebirths, devour, buy_meta}
|
||||
## 返回报告 Dictionary( gates.gd 的输入)。
|
||||
static func run(data: BalanceData, strategy: SimStrategy, opts: Dictionary = {}) -> Dictionary:
|
||||
var max_sec := float(opts.get("max_sec", 4.0 * 3600.0))
|
||||
var rebirths_max := int(opts.get("rebirths", 0))
|
||||
var devour := bool(opts.get("devour", false))
|
||||
var buy_meta := bool(opts.get("buy_meta", false)) # W5 M-2:restart 消费宿慧商店
|
||||
var econ := EconomyState.new(data)
|
||||
var t := 0.0
|
||||
var halls: Array = []
|
||||
@@ -30,8 +38,8 @@ static func run(data: BalanceData, strategy: SimStrategy, opts: Dictionary = {})
|
||||
var clicks := 0
|
||||
var clicks_before_first := 0
|
||||
var first_purchase_sec := -1.0
|
||||
var prev_bought := 0
|
||||
var prev_levels_sum := 0
|
||||
var prev_bought_ids: Dictionary = econ.bought.duplicate()
|
||||
var prev_gen_levels: Array[int] = econ.gen_levels.duplicate()
|
||||
var prev_halls := 0
|
||||
var abort_reason := "max_sec"
|
||||
while t < max_sec:
|
||||
@@ -51,37 +59,47 @@ static func run(data: BalanceData, strategy: SimStrategy, opts: Dictionary = {})
|
||||
halls.append({"no": no, "at_sec": t,
|
||||
"target_min": data.hall_by_no(no).target_min if data.hall_by_no(no) else 0.0})
|
||||
prev_halls = econ.halls_passed
|
||||
# 购买事件(升级购入 + 班底级数增长)
|
||||
if econ.bought.size() > prev_bought:
|
||||
# 购买事件(W5 M-1:逐条目记录 kind + target_id + count——
|
||||
# 门 #2"不同条目数"口径按 (kind,target_id) 去重,聚合计数无法复测)
|
||||
for uid in econ.bought:
|
||||
if prev_bought_ids.has(uid):
|
||||
continue
|
||||
if first_purchase_sec < 0.0:
|
||||
first_purchase_sec = t
|
||||
clicks_before_first = clicks
|
||||
purchases.append({"t": t, "kind": "upgrade", "count": econ.bought.size() - prev_bought})
|
||||
prev_bought = econ.bought.size()
|
||||
var lv_sum := 0
|
||||
for lv in econ.gen_levels:
|
||||
lv_sum += lv
|
||||
if lv_sum > prev_levels_sum:
|
||||
purchases.append({"t": t, "kind": "upgrade",
|
||||
"target_id": str(uid), "count": 1})
|
||||
prev_bought_ids = econ.bought.duplicate()
|
||||
for gi in econ.gen_levels.size():
|
||||
var lv: int = econ.gen_levels[gi]
|
||||
if lv <= prev_gen_levels[gi]:
|
||||
continue
|
||||
if first_purchase_sec < 0.0:
|
||||
first_purchase_sec = t
|
||||
clicks_before_first = clicks
|
||||
purchases.append({"t": t, "kind": "generator", "count": lv_sum - prev_levels_sum})
|
||||
prev_levels_sum = lv_sum
|
||||
purchases.append({"t": t, "kind": "generator",
|
||||
"target_id": econ.data.generators[gi].id, "count": lv - prev_gen_levels[gi]})
|
||||
prev_gen_levels = econ.gen_levels.duplicate()
|
||||
# 里程碑快照
|
||||
if int(t) % SNAPSHOT_INTERVAL == 0:
|
||||
timeline.append({
|
||||
"t": t, "merit": econ.merit, "run_total": econ.merit_run_total,
|
||||
"output": econ.output_per_sec(), "levels": econ.gen_levels.duplicate(),
|
||||
"halls": econ.halls_passed, "suihui": econ.suihui,
|
||||
"wrath_layers": econ.wrath_layers,
|
||||
"min_upgrade_cost": _min_visible_upgrade_cost(econ),
|
||||
})
|
||||
# prestige(H10 达成 → 转世,重计时钟)
|
||||
if rebirths_max > 0 and econ.prestige_available() and rebirths.size() < rebirths_max:
|
||||
var r := econ.do_prestige()
|
||||
rebirths.append({"at_sec": t, "suihui_gain": int(r.get("suihui_gain", 0))})
|
||||
# 转世重置本轮购买跟踪(开局白送级数/已购清空不算"购买事件")
|
||||
prev_halls = 0
|
||||
prev_bought = 0
|
||||
prev_levels_sum = 0
|
||||
prev_bought_ids = econ.bought.duplicate()
|
||||
prev_gen_levels = econ.gen_levels.duplicate()
|
||||
# W5 M-2:按购买力全买宿慧商店(真实玩家口径;#13 预估曲线即此口径)
|
||||
if buy_meta:
|
||||
_buy_all_metas(econ)
|
||||
if econ.halls_passed >= data.halls.size():
|
||||
abort_reason = "h10_reached"
|
||||
return {
|
||||
@@ -114,6 +132,18 @@ static func _count_before(purchases: Array, sec: float) -> int:
|
||||
return n
|
||||
|
||||
|
||||
## W5 M-2:按购买力全买宿慧商店(循环至无可购——m08 max_rank 2 要买满两阶)。
|
||||
## 顺序无关(全部可购即全买);m12 条件未达(gen12 未解锁)时 meta_available 自然挡下。
|
||||
static func _buy_all_metas(econ: EconomyState) -> void:
|
||||
var changed := true
|
||||
while changed:
|
||||
changed = false
|
||||
for m in econ.data.meta_upgrades:
|
||||
if econ.meta_available(m):
|
||||
econ.buy_meta(m.id)
|
||||
changed = true
|
||||
|
||||
|
||||
## 当前最便宜"可见且未购"升级成本(门 #6 无卡墙检查用;INF = 无)
|
||||
static func _min_visible_upgrade_cost(econ: EconomyState) -> float:
|
||||
var best := INF
|
||||
|
||||
+118
-24
@@ -17,12 +17,17 @@ gen_balance_sheets.py —— Balance Bible v1.0 → CSV 落表 + build JSON 生
|
||||
- 稳定字符串 ID:永不重编号、永不复用(W1 已分配的 ID 原样保留)
|
||||
- 本脚本只写 data/sheets/ 与 data/build/,不碰 src/
|
||||
|
||||
表清单(8 张):
|
||||
表清单(9 张,本脚本生成):
|
||||
[B§12] 七张内容表:generators / upgrades / halls / hall_palettes /
|
||||
boss_battles / events / meta_upgrades
|
||||
+ balance_tuning(架构 §2.1 已列名;容纳 [B§3.2 冤煞层 / §4 prestige 参数 /
|
||||
+ balance_tuning(架构 §2.1 已列名;容纳 [B§3.2 冤煞削减速 / §4 prestige 参数 /
|
||||
§8 离线衰减表 / §1 三乘区软上限] —— 这些全局参数在七张内容表中无归属行,
|
||||
按数据驱动红线"零硬编码"必须入表)
|
||||
+ wrath_layers(W5 补登,裁定报告 §4.2 缺口 G-1:[B§12] 表清单漏登冤煞层表。
|
||||
22 行 layer_index/effect/cost;effect L1-15=0.15 / L16-22=0.00(W5 裁定
|
||||
§4.1 #1/#2:+25%/层线性到底 → 15 层后归零,合计封顶 +225%);
|
||||
cost = round(8×n^1.8)([B§3.2] 原公式的逐行落盘,公式参数 base/exp/bonus
|
||||
三行已从 balance_tuning 移除——表即唯一源,零硬编码)
|
||||
|
||||
[B] prose 与表格不一致处的采信规则(详见 docs/engineering/2026-10-19-f-w2-csv-provenance.md):
|
||||
P-1 速率 prose "gen2 起 = 8^(n-1)" 与表值(gen2=1=8^0)差一;采信表值 → rate=8^(n-2)
|
||||
@@ -61,6 +66,21 @@ gen_balance_sheets.py —— Balance Bible v1.0 → CSV 落表 + build JSON 生
|
||||
全部依据 design/gdd/2026-10-20-F-systems-spec.md §1.2
|
||||
P-24(W4 补登)W3 的 7 行 balance_tuning(相机 5 行 + boss_preview/event_first)
|
||||
原为 CSV 手改、生成器漏登——本次一并补登,防重跑丢行
|
||||
P-25 ~ P-28(W5,sim 一轮裁定报告 2026-10-20-F-sim-round1-adjudication §4.1;
|
||||
用户四项拍板全采纳,工程照抄数值不发明):
|
||||
P-25 冤煞层 effect:+25%/层 ×22(线性到底)→ L1-15=0.15 / L16-22=0.00,
|
||||
合计封顶 +225%(裁定 #1/#2:代价 10 层封顶而收益 22 层不封顶 =
|
||||
第 11 层起零成本纯收益,devour 4.8× 速通关、门 #12 FAIL)
|
||||
P-26 冤煞削减速:−3%/层封顶 −30% → −4%/层封顶 −40%;m07 心安理得
|
||||
削减 30%→15% 联动改为 40%→20%(裁定 #3/#4,保"减免一半"语义)
|
||||
P-27 宿慧全局加成:+3%×宿慧(线性无界)→ 0.50×(1−e^(−宿慧/420))
|
||||
渐近封顶(裁定 #5/#6,F-1;R2 开盘 ×6.79 → ×1.18,红线 9.5e15 根治);
|
||||
跳过机制每档赠级 min(floor(宿慧/5)×25, 50)(裁定 #7,F-2)
|
||||
P-28 halls.csv 到达目标列 H1-H9 改 10/20/36/56/80/102/122/142/164
|
||||
(H10 保持 180;殿门阈值列一行不动——[B§6] 目标列与 [B§9] 事件表
|
||||
矛盾,过期的是目标列,经济曲线不动只修验收尺子)
|
||||
P-29 m08 更名:敕封恩典 → 幽冥恩荫 / Shadow Patronage([裁§3 P-4] 既定
|
||||
消歧——与敕封自动 +25% 字面重叠,本轮确认落盘)
|
||||
P-14 tune_souls_div=10000 新增([B§6]"超度 = floor(本轮累计阴德÷10,000)",
|
||||
叙事计数器不设闸门);GDD §4.1 的超度事件计数口路由 W3 事件系统承接
|
||||
P-15 法器附加(点击 L5-12,CSV click_output_pct)乘区口径:[B§1] 总公式与
|
||||
@@ -114,18 +134,25 @@ def gen_rate(n: int) -> float:
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
# [B§6] 十殿总表。gate_merit = 殿门条件(本轮累计阴德,单计数器 [B§0.1])
|
||||
#
|
||||
# target_min(到达目标,分钟)= 验收尺子(门 #3/#14 对照),**不是经济曲线**:
|
||||
# W5 裁定 P-28(sim 一轮裁定报告 §2.2):[B§6] 目标列(25/42/62/…/175/180)与
|
||||
# [B§9] 事件表(H1@8-10min)及冤气解锁链(H1≤12min)三者不能同时为真——过期的
|
||||
# 是目标列。H1/H2 取 [B§9] 带中值(设计锚点不许漂移);H3-H9 取 sim 首轮 greedy
|
||||
# 实测取整(设计起点,待二轮校准);H10 保持 180([B§6] 原值,门 #5 已 PASS)。
|
||||
# 殿门阈值列(gate_merit)一行不动——经济曲线不动,只修验收尺子。
|
||||
# ---------------------------------------------------------------------------
|
||||
HALLS = [
|
||||
# (id, no, king_cn, king_en[临时], motif_cn, motif_en[临时], target_min, gate_merit, unlock_gen, unlock_gate, palette_id, is_prestige_gate)
|
||||
("hall_01_qinguang", 1, "秦广王", "King Qinguang", "孽镜台(照心)", "Mirror of Karma", 25, 2000, "gen_03_guizu", "up_gate_guizu", "pal_hall_01", "false"),
|
||||
("hall_02_chujiang", 2, "楚江王", "King Chujiang", "寒冰狱", "Ice Hell", 42, 30000, "gen_04_biliao", "up_gate_biliao", "pal_hall_02", "false"),
|
||||
("hall_03_songdi", 3, "宋帝王", "King Songdi", "剥皮亭", "Flaying Pavilion", 62, 300000, "gen_05_tangpu", "up_gate_tangpu", "pal_hall_03", "false"),
|
||||
("hall_04_wuguan", 4, "五官王", "King Wuguan", "沸汤/毒蛇", "Scalding Cauldron", 84, 2000000, "gen_06_nanmin", "up_gate_nanmin", "pal_hall_04", "false"),
|
||||
("hall_05_yama", 5, "阎罗王", "King Yama", "叫唤地狱/铁床", "Wailing Hell", 105, 10000000, "gen_07_shuban", "up_gate_shuban", "pal_hall_05", "false"),
|
||||
("hall_06_biancheng",6, "卞城王", "King Biancheng","石碾", "Stone Roller", 125, 40000000, "gen_08_bingfang","up_gate_bingfang","pal_hall_06", "false"),
|
||||
("hall_07_taishan", 7, "泰山王", "King Taishan", "热油火坑", "Boiling Oil Pit", 143, 120000000, "gen_09_wodi", "up_gate_wodi", "pal_hall_07", "false"),
|
||||
("hall_08_dushi", 8, "都市王", "King Dushi", "泥犁/大石", "Avici Stone", 160, 350000000, "gen_10_xingzhe", "up_gate_xingzhe", "pal_hall_08", "false"),
|
||||
("hall_09_pingdeng", 9, "平等王", "King Pingdeng", "拔舌/铁树", "Tongue-Ripping Iron Tree",175, 800000000, "gen_11_yinhun", "up_gate_yinhun", "pal_hall_09", "false"),
|
||||
("hall_01_qinguang", 1, "秦广王", "King Qinguang", "孽镜台(照心)", "Mirror of Karma", 10, 2000, "gen_03_guizu", "up_gate_guizu", "pal_hall_01", "false"),
|
||||
("hall_02_chujiang", 2, "楚江王", "King Chujiang", "寒冰狱", "Ice Hell", 20, 30000, "gen_04_biliao", "up_gate_biliao", "pal_hall_02", "false"),
|
||||
("hall_03_songdi", 3, "宋帝王", "King Songdi", "剥皮亭", "Flaying Pavilion", 36, 300000, "gen_05_tangpu", "up_gate_tangpu", "pal_hall_03", "false"),
|
||||
("hall_04_wuguan", 4, "五官王", "King Wuguan", "沸汤/毒蛇", "Scalding Cauldron", 56, 2000000, "gen_06_nanmin", "up_gate_nanmin", "pal_hall_04", "false"),
|
||||
("hall_05_yama", 5, "阎罗王", "King Yama", "叫唤地狱/铁床", "Wailing Hell", 80, 10000000, "gen_07_shuban", "up_gate_shuban", "pal_hall_05", "false"),
|
||||
("hall_06_biancheng",6, "卞城王", "King Biancheng","石碾", "Stone Roller", 102, 40000000, "gen_08_bingfang","up_gate_bingfang","pal_hall_06", "false"),
|
||||
("hall_07_taishan", 7, "泰山王", "King Taishan", "热油火坑", "Boiling Oil Pit", 122, 120000000, "gen_09_wodi", "up_gate_wodi", "pal_hall_07", "false"),
|
||||
("hall_08_dushi", 8, "都市王", "King Dushi", "泥犁/大石", "Avici Stone", 142, 350000000, "gen_10_xingzhe", "up_gate_xingzhe", "pal_hall_08", "false"),
|
||||
("hall_09_pingdeng", 9, "平等王", "King Pingdeng", "拔舌/铁树", "Tongue-Ripping Iron Tree",164, 800000000, "gen_11_yinhun", "up_gate_yinhun", "pal_hall_09", "false"),
|
||||
("hall_10_zhuanlun",10, "转轮王", "King of the Wheel", "轮回道(六道环)","Wheel of Rebirth", 180, 1500000000, "none", "none", "pal_hall_10", "true"),
|
||||
]
|
||||
|
||||
@@ -191,8 +218,8 @@ META_UPGRADES = [
|
||||
("meta_04", "天生熟练", "Born Skilled", "skip_interval", "", 4, 12, 1, "none", "跳过机制从每 5 级加快为每 4 级"),
|
||||
("meta_05", "阴司人脉", "Netherworld Connections","offline_pct", "", 0.25, 6, 1, "none", "离线效率 +25%"),
|
||||
("meta_06", "斩鬼刃", "Ghost-Slaying Blade", "boss_click_pct", "", 0.30, 10, 1, "none", "殿王战点击伤害 +30%"),
|
||||
("meta_07", "心安理得", "Easy Conscience", "wrath_penalty_set", "", 0.15, 15, 1, "none", "冤气对宿慧的削减 30%→15%"),
|
||||
("meta_08", "敕封恩典", "Grace of Enthronement","global_pct", "", 0.25, 20, 2, "none", "全局 +25%(每阶)"),
|
||||
("meta_07", "心安理得", "Easy Conscience", "wrath_penalty_set", "", 0.20, 15, 1, "none", "冤气对宿慧的削减 40%→20%"),
|
||||
("meta_08", "幽冥恩荫", "Shadow Patronage", "global_pct", "", 0.25, 20, 2, "none", "全局 +25%(每阶)"),
|
||||
("meta_09", "阴阳眼", "Yin-Yang Eye", "event_freq_pct", "", 0.20, 10, 1, "none", "事件触发频率 +20%"),
|
||||
("meta_10", "超度加速", "Salvation Acceleration","souls_mult", "", 2, 8, 1, "none", "超度计数获取 ×2"),
|
||||
("meta_11", "老马识途", "Old Horse Knows the Way","bulk_unlock", "", 0, 5, 1, "none", "开局即可用批量 ×10"),
|
||||
@@ -200,7 +227,30 @@ META_UPGRADES = [
|
||||
]
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
# [B§3.2] 冤煞层 22 层参数 / [B§8] 离线衰减表 / [B§4] prestige 参数 / [B§1] 软上限
|
||||
# [B§3.2] 冤煞层 22 层 → **独立成表 wrath_layers.csv**(W5 裁定 G-1 补登)
|
||||
# [B§12] 七张表清单漏登冤煞层;原落点 = balance_tuning 标量(tune_wrath_bonus)
|
||||
# + economy_state.gd 线性乘层数(架构债)。W5 起逐行落表:
|
||||
# effect:L1-L15 = 0.15 / L16-L22 = 0.00(W5 裁定 P-25:+25%/层线性到底 →
|
||||
# 15 层后归零,合计封顶 +225%;16-22 层保留入口作收藏/成就向,
|
||||
# 叙事"怨煞噬主,过盛不顶用")
|
||||
# cost :第 n 层 = round(8 × n^1.8)([B§3.2] 原公式逐行落盘;公式与
|
||||
# PrestigeModel.wrath_layer_cost / 单测 test_economy_formulas 一致)
|
||||
# 削减速(−4%/层封顶 −40%)不随层变,按纪律留 balance_tuning 公式行。
|
||||
# ---------------------------------------------------------------------------
|
||||
WRATH_LAYERS_TOTAL = 22
|
||||
WRATH_EFFECT_FULL = 0.15 # W5 裁定 P-25:每层全局加法 +15%
|
||||
WRATH_EFFECT_LAST_LAYER = 15 # W5 裁定 P-25:第 16 层起 effect 归零
|
||||
WRATH_COST_BASE = 8.0 # [B§3.2] 成本公式基数
|
||||
WRATH_COST_EXP = 1.8 # [B§3.2] 成本公式指数
|
||||
|
||||
|
||||
def wrath_layer_cost(n: int) -> int:
|
||||
"""[B§3.2] 第 n 层成本 = round(8 × n^1.8),n 从 1 起。"""
|
||||
return int(round(WRATH_COST_BASE * (float(n) ** WRATH_COST_EXP)))
|
||||
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
# [B§8] 离线衰减表 / [B§4] prestige 参数 / [B§1] 软上限
|
||||
# → balance_tuning.csv(key-value 行;架构 §2.1)
|
||||
# ---------------------------------------------------------------------------
|
||||
TUNING = [
|
||||
@@ -217,19 +267,16 @@ TUNING = [
|
||||
("tune_offline_band3_rate","number", 0.4, "", "[B§8] 离线 8-24h 速率"),
|
||||
("tune_offline_band4_rate","number", 0.1, "", "[B§8] 离线 >24h 速率 10%"),
|
||||
("tune_offline_cap_h", "number", 72, "", "[B§8] 离线硬上限 72h 封顶"),
|
||||
("tune_wrath_layers", "number", 22, "", "[B§3.2] 冤煞层总数 22"),
|
||||
("tune_wrath_cost_base", "number", 8, "", "[B§3.2] 第 n 层成本 = round(8 × n^1.8)"),
|
||||
("tune_wrath_cost_exp", "number", 1.8, "", "[B§3.2] 冤煞层成本指数"),
|
||||
("tune_wrath_bonus", "number", 0.25, "", "[B§3.2] 每层全局 +25%(加法,进全局乘区)"),
|
||||
("tune_wrath_penalty", "number", 0.03, "", "[B§3.2] 每层宿慧获取削减 +3%"),
|
||||
("tune_wrath_penalty_cap", "number", 0.3, "", "[B§3.2] 宿慧削减封顶 30%"),
|
||||
("tune_wrath_layers", "number", 22, "", "[B§3.2] 冤煞层总数 22(与 wrath_layers.csv 行数交叉校验;效果/成本已逐行入该表,W5 G-1)"),
|
||||
("tune_wrath_penalty", "number", 0.04, "", "[B§3.2] 每层宿慧获取削减 +4%(W5 裁定 P-26:−3% → −4%)"),
|
||||
("tune_wrath_penalty_cap", "number", 0.4, "", "[B§3.2] 宿慧削减封顶 40%(W5 裁定 P-26:30% → 40%;m07 改 20%)"),
|
||||
("tune_suihui_div", "number", 1000000, "", "[B§4.1] 宿慧 = floor(√(本轮累计阴德/1e6) × 5)"),
|
||||
("tune_suihui_mult", "number", 5, "", "[B§4.1] 宿慧公式乘数"),
|
||||
("tune_suihui_global_pct", "number", 0.03, "", "[B§1/§4.2] 每级宿慧全局产出 +3%(加法,进全局乘区)"),
|
||||
("tune_enthrone_bonus", "number", 0.25, "", "[B§4.4] 阴司敕封自动全局恩典 +25%(与 m08 商品字面重叠,见 provenance P-4)"),
|
||||
("tune_skip_interval", "number", 5, "", "[B§4.2] 每 5 级宿慧 → 前 3 档班底各 +25 级(m04 可加快为 4)"),
|
||||
("tune_skip_interval", "number", 5, "", "[B§4.2] 每 5 级宿慧 → 前 3 档班底各 +25 级(m04 可加快为 4;每档封顶见 tune_skip_level_cap_per_gen)"),
|
||||
("tune_skip_gens", "number", 3, "", "[B§4.2] 跳过机制覆盖前 3 档班底"),
|
||||
("tune_skip_levels", "number", 25, "", "[B§4.2] 跳过机制每档 +25 级"),
|
||||
("tune_skip_level_cap_per_gen","number", 50, "", "[B§4.2] W5 裁定 P-27(F-2):跳过每档获赠 = min(floor(宿慧/5)×25, 本值)(原无封顶 → R2 开盘白送 2850 级)"),
|
||||
("tune_enthrone_rebirths", "number", 2, "", "[B§4.4] 阴司敕封触发:转世 ≥2(约第 2-3 轮,累计 8-12h 为其 pacing 后果)"),
|
||||
("tune_restart_curve", "text", 0, "1:0.6:0.4:0.3", "[B§4.3] 重开曲线目标(第 5 轮触底 ≥0.25×);模拟器门 #13 断言"),
|
||||
("tune_event_timeout_default","text", 0, "opt_a", "[B§7] 冤魂申诉超时默认 = 超度(opt_a)"),
|
||||
@@ -248,6 +295,9 @@ TUNING = [
|
||||
("tune_boss_kappa_slope", "number", 0.052, "", "[systems-spec §1.2 B2] κ 随法器线进度斜率:κ = (base + slope × 已购点击升级/12) × (1 + m06阶×0.30);满配 κ = 0.0806"),
|
||||
("tune_boss_intro_cap", "number", 0.1, "", "[systems-spec §1.2 B3] 开场冲锋伤害封顶 = HP × 本值(0.10;旧公式 20% 已废止)"),
|
||||
("tune_boss_intro_enabled","number", 1, "", "[systems-spec §1.2 B3] 开场冲锋开关(1 = 启用;门 #11 首轮数据回来前默认 1)"),
|
||||
# ---- W5 宿慧全局渐近封顶(sim 一轮裁定 §2.4 F-1;用户 2026-10-20 拍板) ----
|
||||
("tune_suihui_global_max", "number", 0.5, "", "[B§4.2] W5 裁定 P-27(F-1):宿慧全局加成渐近上限 = 0.50×(1−e^(−宿慧/scale))(旧 +3%/级线性无界 → R2 开盘 ×6.79、红线 9.5e15 的根因)"),
|
||||
("tune_suihui_global_scale","number", 420, "", "[B§4.2] W5 裁定 P-27(F-1):渐近衰减尺度(宿慧)。查点:193→+18.4%;386→+30.1%;579→+37.4%;772→+42.0%;∞→+50%"),
|
||||
]
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
@@ -320,6 +370,7 @@ EVENT_COLS = ["id", "name_cn", "name_en", "trigger_min_min", "trigger_max_min",
|
||||
META_COLS = ["id", "name_cn", "name_en", "effect_type", "target_id", "effect_param",
|
||||
"cost_suihui", "max_rank", "condition", "desc_cn"]
|
||||
TUNING_COLS = ["id", "kind", "num", "text", "desc_cn"]
|
||||
WRATH_LAYER_COLS = ["id", "layer_index", "effect", "cost"]
|
||||
|
||||
|
||||
def fnum(v) -> str:
|
||||
@@ -491,6 +542,18 @@ def build_rows():
|
||||
})
|
||||
sheets["balance_tuning"] = (TUNING_COLS, rows)
|
||||
|
||||
# --- wrath_layers([B§3.2] / W5 G-1:22 行 effect/cost 逐行落表) ----------
|
||||
rows = []
|
||||
for n in range(1, WRATH_LAYERS_TOTAL + 1):
|
||||
effect = WRATH_EFFECT_FULL if n <= WRATH_EFFECT_LAST_LAYER else 0.0
|
||||
rows.append({
|
||||
"id": "wrath_layer_%02d" % n,
|
||||
"layer_index": n,
|
||||
"effect": effect,
|
||||
"cost": wrath_layer_cost(n),
|
||||
})
|
||||
sheets["wrath_layers"] = (WRATH_LAYER_COLS, rows)
|
||||
|
||||
return sheets
|
||||
|
||||
|
||||
@@ -523,6 +586,10 @@ def self_check(sheets) -> None:
|
||||
assert h["gate_merit"] == eg, "gate %s" % h["id"]
|
||||
assert sum(1 for h in halls if h["is_prestige_gate"] is True) == 1
|
||||
assert halls[-1]["is_prestige_gate"] is True
|
||||
# W5 裁定 P-28:到达目标列 10 行改写(殿门阈值不动,只修验收尺子)
|
||||
expect_targets = [10, 20, 36, 56, 80, 102, 122, 142, 164, 180]
|
||||
for h, et in zip(halls, expect_targets):
|
||||
assert float(h["target_min"]) == et, "target_min %s" % h["id"]
|
||||
# 升级 108 条 + meta 12 条([B§2] 配比)
|
||||
ups = sheets["upgrades"][1]
|
||||
assert len(ups) == 108, "upgrades 行数 %d" % len(ups)
|
||||
@@ -570,7 +637,6 @@ def self_check(sheets) -> None:
|
||||
# 冤煞成本公式 spot check(round(8×n^1.8) 由 core 代码求值,此处验公式输入)
|
||||
tune = {t["id"]: t for t in sheets["balance_tuning"][1]}
|
||||
assert tune["tune_wrath_layers"]["num"] == 22
|
||||
assert tune["tune_wrath_cost_base"]["num"] == 8
|
||||
assert tune["tune_offline_cap_h"]["num"] == 72
|
||||
# P-14:超度除数 + 敕封宿慧门槛(GDD §3.4)
|
||||
assert tune["tune_souls_div"]["num"] == 10000
|
||||
@@ -578,11 +644,22 @@ def self_check(sheets) -> None:
|
||||
assert tune["tune_enthrone_rebirths"]["num"] == 2
|
||||
assert tune["tune_suihui_div"]["num"] == 1000000
|
||||
assert tune["tune_suihui_mult"]["num"] == 5
|
||||
assert tune["tune_suihui_global_pct"]["num"] == 0.03
|
||||
assert tune["tune_enthrone_bonus"]["num"] == 0.25
|
||||
assert tune["tune_skip_interval"]["num"] == 5
|
||||
assert tune["tune_skip_gens"]["num"] == 3
|
||||
assert tune["tune_skip_levels"]["num"] == 25
|
||||
# W5 宿慧渐近封顶 + 跳过钳制(sim 一轮裁定 §2.4 F-1/F-2;用户拍板)
|
||||
assert tune["tune_suihui_global_max"]["num"] == 0.5
|
||||
assert tune["tune_suihui_global_scale"]["num"] == 420
|
||||
assert tune["tune_skip_level_cap_per_gen"]["num"] == 50
|
||||
# W5 冤煞削减速加深(裁定 §2.3 配套 U-3b)
|
||||
assert tune["tune_wrath_penalty"]["num"] == 0.04
|
||||
assert tune["tune_wrath_penalty_cap"]["num"] == 0.4
|
||||
# 已被 wrath_layers.csv 表取代/迁入的调参行必须不存在(防双源)
|
||||
assert "tune_wrath_bonus" not in tune, "effect 已逐行入 wrath_layers.csv"
|
||||
assert "tune_wrath_cost_base" not in tune, "cost 已逐行入 wrath_layers.csv"
|
||||
assert "tune_wrath_cost_exp" not in tune, "cost 已逐行入 wrath_layers.csv"
|
||||
assert "tune_suihui_global_pct" not in tune, "线性公式已被渐近公式取代"
|
||||
assert tune["tune_click_base"]["num"] == 1
|
||||
assert tune["tune_click_zone_cap"]["num"] == 16
|
||||
assert tune["tune_gen_zone_cap"]["num"] == 8
|
||||
@@ -603,6 +680,23 @@ def self_check(sheets) -> None:
|
||||
metas = sheets["meta_upgrades"][1]
|
||||
assert len(metas) == 12
|
||||
assert [m["cost_suihui"] for m in metas] == [3, 5, 8, 12, 6, 10, 15, 20, 10, 8, 5, 25]
|
||||
# W5 裁定 P-26/P-29:m07 削减联动 40%→20%;m08 更名幽冥恩荫([裁§3 P-4] 消歧)
|
||||
m07 = [m for m in metas if m["id"] == "meta_07"][0]
|
||||
assert float(m07["effect_param"]) == 0.2, "m07 削减 40%→20%"
|
||||
m08 = [m for m in metas if m["id"] == "meta_08"][0]
|
||||
assert m08["name_cn"] == "幽冥恩荫", "m08 更名(P-4 消歧)"
|
||||
assert m08["name_en"] == "Shadow Patronage", "m08 英文名同步消歧"
|
||||
# W5 G-1:wrath_layers.csv 22 行(effect/cost 逐行;[B§12] 漏登补登)
|
||||
wl = sheets["wrath_layers"][1]
|
||||
assert len(wl) == 22, "冤煞层 22 行"
|
||||
assert [int(w["layer_index"]) for w in wl] == list(range(1, 23)), "layer_index 1..22 连续"
|
||||
assert sum(1 for w in wl if float(w["effect"]) == 0.15) == 15, "L1-15 = +15%/层"
|
||||
assert sum(1 for w in wl if float(w["effect"]) == 0.0) == 7, "L16-22 归零(合计封顶 +225%)"
|
||||
assert tune["tune_wrath_layers"]["num"] == len(wl), "调参行与表行数交叉校验"
|
||||
for w in wl: # 成本列 = [B§3.2] 公式逐行落盘(与 PrestigeModel/单测同公式)
|
||||
assert int(w["cost"]) == wrath_layer_cost(int(w["layer_index"])), "L%s cost" % w["layer_index"]
|
||||
costs = [int(w["cost"]) for w in wl]
|
||||
assert costs == sorted(costs) and len(set(costs)) == 22, "成本严格递增(购买梯度)"
|
||||
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
|
||||
@@ -29,8 +29,12 @@ func _initialize() -> void:
|
||||
func _run_import() -> int:
|
||||
print("=== SheetImporter import_all:sheets → build/*.json(schema 校验 + 差异化报告)===")
|
||||
var report := SheetImporter.import_all()
|
||||
# 注意:import_all 的 sheets 元素是 import_sheet 返回的 **Dictionary**
|
||||
# (不是 ImportReport 实例)——不能直接 .summary()(首跑实证 R15:
|
||||
# Nonexistent function 'summary' in base 'Dictionary')。聚合报告的
|
||||
# summary()/ok() 是 ImportReport 方法,可用;逐表摘要走下面的 helper。
|
||||
for s in report.sheets:
|
||||
print(s.summary())
|
||||
print(_sheet_summary(s))
|
||||
print(report.summary())
|
||||
if report.ok():
|
||||
print("RESULT: PASS(%d 表 / %d 行 / 0 违规)" % [report.sheets.size(), report.row_count])
|
||||
@@ -39,6 +43,21 @@ func _run_import() -> int:
|
||||
return 1
|
||||
|
||||
|
||||
## 逐表摘要(import_sheet 的 Dictionary → 可读日志行)
|
||||
func _sheet_summary(s: Dictionary) -> String:
|
||||
var rows: Array = s.get("typed_rows", [])
|
||||
var head := "表 %s:%d 行(+%d 新增 / ~%d 变更 / -%d 删除)→ %s" % [
|
||||
str(s.get("sheet", "?")), rows.size(),
|
||||
int(s.get("added", 0)), int(s.get("changed", 0)), int(s.get("removed", 0)),
|
||||
str(s.get("json_path", "未写盘")).get_file()]
|
||||
var lines := PackedStringArray([head])
|
||||
for v in s.get("violations", []):
|
||||
lines.append(" [违规] " + str(v))
|
||||
for n in s.get("notes", []):
|
||||
lines.append(" [备注] " + str(n))
|
||||
return "\n".join(lines)
|
||||
|
||||
|
||||
func _run_validate() -> int:
|
||||
print("=== SheetImporter validate:data/build 对 schema 合规性 ===")
|
||||
var violations := SheetImporter.validate(SheetImporter.BUILD_DIR)
|
||||
|
||||
@@ -517,12 +517,24 @@ static func _check_schema_keywords(schema: Dictionary) -> String:
|
||||
return "schema 使用了本工具未支持的关键词:%s(支持集:%s)" % [str(bad), str(SUPPORTED_KEYWORDS)]
|
||||
|
||||
|
||||
## 递归检查 schema 关键词白名单。
|
||||
## ⚠ 语义修正(首跑实证 R16):`properties` 的**键是属性名**(如 sheet/columns),
|
||||
## 不是 schema 关键词——旧实现把 properties 字典当节点走,于是每张表的四大属性名
|
||||
## 都被误报为"未支持关键词",import_all 自 W1 起从未真正导入过任何表(build 全靠
|
||||
## gen_balance_sheets.py 侧生成)。正确走法:properties 按**值**逐个递归;
|
||||
## items/additionalProperties 按值递归(Dictionary 或 Dictionary 数组)。
|
||||
static func _walk_schema(node: Dictionary, bad: PackedStringArray) -> void:
|
||||
for k in node.keys():
|
||||
var ks := str(k)
|
||||
if not ks.begins_with("x-") and not SUPPORTED_KEYWORDS.has(ks) and not META_KEYWORDS.has(ks):
|
||||
bad.append(ks)
|
||||
for key in ["properties", "items", "additionalProperties"]:
|
||||
var props_v: Variant = node.get("properties", null)
|
||||
if props_v is Dictionary:
|
||||
for pk in props_v:
|
||||
var pv: Variant = props_v[pk]
|
||||
if pv is Dictionary:
|
||||
_walk_schema(pv, bad)
|
||||
for key in ["items", "additionalProperties"]:
|
||||
if node.has(key):
|
||||
var v: Variant = node[key]
|
||||
if v is Dictionary:
|
||||
|
||||
File diff suppressed because it is too large.
Load diff
@@ -37,6 +37,32 @@ func run(a, data: BalanceData) -> void:
|
||||
a.eq(data.tune_text("tune_restart_curve", ""), "1:0.6:0.4:0.3", "重开曲线文本")
|
||||
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()))
|
||||
# 每殿恰一场殿王战 + 色板
|
||||
|
||||
@@ -29,9 +29,11 @@ func run(a, _data: BalanceData) -> void:
|
||||
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")
|
||||
a.near(PrestigeModel.wrath_penalty(10, 0.03, 0.3, 0.0), 0.3, 1e-9, "冤气削减封顶 30%")
|
||||
a.near(PrestigeModel.wrath_penalty(10, 0.03, 0.3, 0.15), 0.15, 1e-9, "m07 改 15%")
|
||||
a.near(PrestigeModel.wrath_penalty(5, 0.03, 0.3, 0.0), 0.15, 1e-9, "5 层 = 15%")
|
||||
# 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")
|
||||
@@ -40,6 +42,41 @@ func run(a, _data: BalanceData) -> void:
|
||||
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%)。
|
||||
|
||||
@@ -8,6 +8,8 @@ func run(a, data: BalanceData) -> void:
|
||||
_test_upgrades_and_meta(a, data)
|
||||
_test_wrath(a, data)
|
||||
_test_prestige(a, data)
|
||||
_test_suihui_asymptotic(a, data)
|
||||
_test_skip_cap(a, data)
|
||||
_test_enthrone(a, data)
|
||||
_test_event_and_offline(a, data)
|
||||
|
||||
@@ -82,12 +84,14 @@ func _test_wrath(a, data: BalanceData) -> void:
|
||||
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")
|
||||
a.eq(e.wrath_layer_cost(), 8, "第 1 层成本 8(wrath_layers.csv 逐行)")
|
||||
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%")
|
||||
# W5 裁定 P-25:每层全局 +25% → +15%(合计 15 层后封顶 +225%)
|
||||
a.near(e.global_mult(), 1.15, 1e-9, "全局 ×1.15(每层 +15%)")
|
||||
# W5 裁定 P-26:宿慧削减 +3%/层 → +4%/层(封顶 40%)
|
||||
a.near(e.wrath_penalty(), 0.04, 1e-9, "宿慧削减 4%")
|
||||
e.wrath = 0.0
|
||||
var r2: Dictionary = e.buy_wrath_layer()
|
||||
a.true_(not bool(r2.get("ok", false)), "冤气不足买不了")
|
||||
@@ -97,6 +101,11 @@ func _test_wrath(a, data: BalanceData) -> void:
|
||||
a.eq(e.wrath_layers, 22, "22 层上限")
|
||||
var r3: Dictionary = e.buy_wrath_layer()
|
||||
a.true_(not bool(r3.get("ok", false)), "满层后再买失败")
|
||||
# W5:L1-15 各 +15%(合计 +225% = ×3.25);L16-22 effect = 0(过盛不顶用)
|
||||
a.near(e.global_mult(), 1.0 + 15.0 * 0.15, 1e-9, "满层全局 ×3.25(15 层后归零)")
|
||||
a.near(e.wrath_penalty(), 0.4, 1e-9, "22 层削减封顶 40%")
|
||||
# 成本列逐行 = round(8×n^1.8)(表即公式落盘;抽检首/中/末)
|
||||
a.eq(e.wrath_layer_cost(), 2087, "满层后下一层成本回退末行 2087")
|
||||
|
||||
|
||||
# ---- 轮回转世 ----
|
||||
@@ -113,11 +122,80 @@ func _test_prestige(a, data: BalanceData) -> void:
|
||||
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 级")
|
||||
# W5 裁定 F-2:跳过每档封顶 50 级(193/5=38 次 ×25 = 950 → 钳到 50;
|
||||
# 注意 do_prestige 先清零班底([B§4.1] 全清)再加跳过,故原有 50 级不计入)
|
||||
a.eq(e.gen_levels[0], 50, "跳过封顶:193 宿慧 → 50 级/档(旧口径 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, "宿慧全局加成")
|
||||
# 第二轮更快(宿慧全局渐近加成,F-1)
|
||||
var smax: float = data.tune_num("tune_suihui_global_max", 0.5)
|
||||
var sscale: float = data.tune_num("tune_suihui_global_scale", 420.0)
|
||||
a.near(e.global_mult(), 1.0 + smax * (1.0 - exp(-193.0 / sscale)), 1e-9, "宿慧全局渐近加成(193 → +18.4%)")
|
||||
|
||||
|
||||
# ---- 宿慧全局渐近封顶(W5 裁定 F-1:线性无界 → 0.50×(1−e^(−宿慧/420)))----
|
||||
func _test_suihui_asymptotic(a, data: BalanceData) -> void:
|
||||
var e := EconomyState.new(data)
|
||||
var smax: float = data.tune_num("tune_suihui_global_max", 0.5)
|
||||
var sscale: float = data.tune_num("tune_suihui_global_scale", 420.0)
|
||||
e.suihui = 0
|
||||
e.recompute()
|
||||
a.near(e.global_mult(), 1.0, 1e-9, "0 宿慧 → 无加成")
|
||||
# 裁定 §2.4 查点表:193→+18.4%;386→+30.1%;579→+37.4%;772→+42.0%
|
||||
for s in [193, 386, 579, 772, 1550, 5000]:
|
||||
e.suihui = s
|
||||
e.recompute()
|
||||
var want: float = 1.0 + smax * (1.0 - exp(-float(s) / sscale))
|
||||
a.near(e.global_mult(), want, 1e-9, "宿慧 %d → 加成 %.4f" % [s, want - 1.0])
|
||||
# 渐近上限:宿慧 → ∞ 也只到 +50%(封死"银行式刷宿慧"死亡螺旋)
|
||||
e.suihui = 100000000
|
||||
e.recompute()
|
||||
a.near(e.global_mult(), 1.0 + smax, 1e-6, "巨量宿慧仍封顶 +50%")
|
||||
# 单调不减(渐近函数的基本性质)
|
||||
var prev := 0.0
|
||||
for s in [0, 10, 50, 100, 193, 386, 579, 772, 1550, 5000]:
|
||||
e.suihui = s
|
||||
e.recompute()
|
||||
var gm := e.global_mult()
|
||||
a.true_(gm >= prev - 1e-12, "宿慧加成单调不减 @%d" % s)
|
||||
prev = gm
|
||||
|
||||
|
||||
# ---- 跳过机制钳制(W5 裁定 F-2:每档 min(floor(宿慧/5)×25, 50))----
|
||||
func _test_skip_cap(a, data: BalanceData) -> void:
|
||||
var cap: int = int(data.tune_num("tune_skip_level_cap_per_gen", 50.0))
|
||||
a.eq(cap, 50, "调参:每档封顶 50 级")
|
||||
var e := EconomyState.new(data)
|
||||
# 公式直测:_apply_rebirth_start_levels 是纯应用函数。走 do_prestige 测不了
|
||||
# 低宿慧区——H10 门 1.5e9 决定每轮 gain ≥ 193(38 次触发必触顶)。
|
||||
_apply_skip(e, 5)
|
||||
a.eq(e.gen_levels[0], 25, "5 宿慧 → 25 级/档(未触顶)")
|
||||
_apply_skip(e, 10)
|
||||
a.eq(e.gen_levels[0], 50, "10 宿慧 → 50 级/档(恰触顶)")
|
||||
_apply_skip(e, 400)
|
||||
a.eq(e.gen_levels[0], 50, "400 宿慧 → 仍 50 级/档(钳制生效)")
|
||||
# 三档覆盖:前 3 档各 +50(skip_gens = 3)
|
||||
a.eq(e.gen_levels[1], 50, "第 2 档同获赠")
|
||||
a.eq(e.gen_levels[2], 50, "第 3 档同获赠")
|
||||
a.eq(e.gen_levels[3], 0, "第 4 档不受跳过覆盖")
|
||||
# 集成:do_prestige 后(gain 193 入账)R2 开盘 = 50 级/档
|
||||
e.merit_run_total = 1.5e9
|
||||
var r: Dictionary = e.do_prestige()
|
||||
a.true_(bool(r.get("ok", false)), "轮回(集成)")
|
||||
a.eq(e.gen_levels[0], 50, "do_prestige 后 50 级/档(钳制生效;旧口径 950)")
|
||||
# m04(间隔 5→4):400/4=100 次 ×25 = 2500 → 同样钳到 50
|
||||
var rm: Dictionary = e.buy_meta("meta_04")
|
||||
a.true_(bool(rm.get("ok", false)), "买 m04 天生熟练(间隔 4)")
|
||||
_apply_skip(e, 400)
|
||||
a.eq(e.gen_levels[0], 50, "m04 下仍钳到 50 级/档")
|
||||
|
||||
|
||||
## 测试辅助:清零班底级数 → 设宿慧 → 应用跳过/开局加成(_apply 为加法,须先清零)
|
||||
func _apply_skip(e: EconomyState, suihui_v: int) -> void:
|
||||
for i in e.gen_levels.size():
|
||||
e.gen_levels[i] = 0
|
||||
e.suihui = suihui_v
|
||||
e._apply_rebirth_start_levels()
|
||||
|
||||
|
||||
# ---- 阴司敕封 + gen12 愿景档 ----
|
||||
@@ -136,11 +214,14 @@ func _test_enthrone(a, data: BalanceData) -> void:
|
||||
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(宿慧+敕封)")
|
||||
# 全局区 = 1 + 宿慧100 渐近加成 + 敕封 25%(W5 F-1:宿慧项改渐近公式)
|
||||
var smax: float = data.tune_num("tune_suihui_global_max", 0.5)
|
||||
var sscale: float = data.tune_num("tune_suihui_global_scale", 420.0)
|
||||
var want_global: float = 1.0 + smax * (1.0 - exp(-100.0 / sscale)) + 0.25
|
||||
a.near(e.global_mult(), want_global, 1e-9, "全局 = 1 + 宿慧渐近 + 敕封 25%(≈×1.356)")
|
||||
# gen12 产出接入
|
||||
e.gen_levels[11] = 1
|
||||
a.near(e.output_per_sec(), 1073741824.0 * 4.25, 1.0, "gen12 1 级产出")
|
||||
a.near(e.output_per_sec(), 1073741824.0 * want_global, 1.0, "gen12 1 级产出")
|
||||
|
||||
|
||||
# ---- 事件瞬时区 + 离线加法(契约 v2:长明灯 ×2.31 → 加法 +30%) ----
|
||||
|
||||
Reference in new issue
Block a user