feat(balance): 关间大奖励 10→5 + L2 五处血量收紧——双合格线扫描收敛(用户拍板 2026-09-23)
- adventure.tres: level_clear_hp_bonus 10→5(刀一:关间补给收窄) - enemy.tres L2: 群行 22→26×3 / 24→28、蛛化卓尔精灵 112→130(刀二=B包第7轮留档收紧候选L2部分;L3 未动) - smoke_all.gd: 满配锚 (400,200)→(900,400)——L2 抬血后旧档不再满通,先例式抬锚(B包 200/100→400/200 同款) - 读数:零强化过第二关率 普通 15→2% / 完美 40→15%;营地循环爬升形态成立(第4局0%→第37局100%) - 冒烟 553 项 0 失败三闸过;verifier 双轮扫描报告 production/qa/balance-verifier-20260923-043341/050222.md(worktree)
This commit is contained in:
1 parent
3309aae2a3
commit
a4edb1e7f8
3 files changed
+23
-23
No files matched your search
@@ -4,7 +4,7 @@
|
||||
|
||||
[resource]
|
||||
script = ExtResource("1")
|
||||
level_clear_hp_bonus = 10
|
||||
level_clear_hp_bonus = 5
|
||||
keystone_per_level = 10
|
||||
|
||||
; 冒险结构实现批(2026-09-21 建表——registry adventure_table 条目同批注记更新):
|
||||
|
||||
@@ -140,7 +140,7 @@ rows = [{
|
||||
"display_name": "熊地精猎群",
|
||||
"unit_count": 2,
|
||||
"unit_count_max": 3,
|
||||
"hp": 22,
|
||||
"hp": 26,
|
||||
"atk": 2,
|
||||
"atk_min": 1,
|
||||
"atk_max": 3,
|
||||
@@ -162,7 +162,7 @@ rows = [{
|
||||
"enemy_id": "giant_spider",
|
||||
"display_name": "巨蜘蛛",
|
||||
"unit_count": 2,
|
||||
"hp": 24,
|
||||
"hp": 28,
|
||||
"atk": 2,
|
||||
"atk_min": 1,
|
||||
"atk_max": 3,
|
||||
@@ -205,10 +205,10 @@ rows = [{
|
||||
"node_depth": 6,
|
||||
"enemy_id": "giant_spider",
|
||||
"display_name": "巨蜘蛛巢群",
|
||||
"unit_count": 2,
|
||||
"unit_count_max": 3,
|
||||
"hp": 22,
|
||||
"atk": 1,
|
||||
"unit_count": 2,
|
||||
"unit_count_max": 3,
|
||||
"hp": 26,
|
||||
"atk": 1,
|
||||
"atk_min": 1,
|
||||
"atk_max": 2,
|
||||
"pool": [{
|
||||
@@ -228,10 +228,10 @@ rows = [{
|
||||
"node_depth": 7,
|
||||
"enemy_id": "giant_spider",
|
||||
"display_name": "巨蜘蛛巢群",
|
||||
"unit_count": 2,
|
||||
"unit_count_max": 3,
|
||||
"hp": 22,
|
||||
"atk": 2,
|
||||
"unit_count": 2,
|
||||
"unit_count_max": 3,
|
||||
"hp": 26,
|
||||
"atk": 2,
|
||||
"atk_min": 1,
|
||||
"atk_max": 3,
|
||||
"pool": [{
|
||||
@@ -252,7 +252,7 @@ rows = [{
|
||||
"enemy_id": "drider",
|
||||
"display_name": "蛛化卓尔精灵",
|
||||
"unit_count": 1,
|
||||
"hp": 112,
|
||||
"hp": 130,
|
||||
"atk": 3,
|
||||
"atk_min": 2,
|
||||
"atk_max": 4,
|
||||
|
||||
@@ -124,7 +124,7 @@ func _smoke_adventure_table() -> void:
|
||||
func _smoke_adventure_api() -> void:
|
||||
print("--- 冒险结构 API 闸(重复开始拒绝 · 放弃两态受理)---")
|
||||
var adr = load("res://core/adventure_runner.gd").new(_db, _fresh_rng(42))
|
||||
adr.set_hero_override(400, 200) # 首战速胜档(放弃的非战斗受理要走到选路态)
|
||||
adr.set_hero_override(900, 400) # 首战速胜档(放弃的非战斗受理要走到选路态)
|
||||
check(adr.start_adventure(42), "冒险启动受理(主种子注入恰一次——state=running)")
|
||||
check(not adr.start_adventure(43), "进行中重复 start_adventure 拒绝(重开须待结算完毕)")
|
||||
check(adr.runner().current_battle() != null, "首战在飞(接口①开始关卡直达战斗节点)")
|
||||
@@ -170,10 +170,10 @@ func _smoke_adventure() -> void:
|
||||
miss += 1
|
||||
check(miss == 0, "行集内每个战斗/Boss 节点在 board_gen + enemy 有精确行(缺失 %d)" % miss)
|
||||
# ② 满配通关 + ④ 大奖励兑付(恰 2 次 · 读数=表值 · 回满=新上限 · 覆盖值通道传播 L2/L3 首战上限)
|
||||
var st: Dictionary = autoplay.run_adventure(_db, 42, 400, 200)
|
||||
var st: Dictionary = autoplay.run_adventure(_db, 42, 900, 400)
|
||||
var sum: Dictionary = st["summary"]
|
||||
check(String(st["result"]) == "completed" and bool(sum.get("cleared", false)),
|
||||
"满配通关(42 / atk+400 / hp+200——cleared=true;v2 怪阶梯后旧 200/100 档不再满配)")
|
||||
"满配通关(42 / atk+900 / hp+400——cleared=true;v2 怪阶梯后旧 200/100 档不再满配)")
|
||||
check(int(sum.get("levels_cleared", -1)) == 3, "通关几关 = 3(levels_cleared)")
|
||||
check(int(sum.get("keystone_total", -1)) == 3 * int(_db.adventure.keystone_per_level),
|
||||
"钥石合计 = 3 × keystone_per_level(%d)" % int(sum.get("keystone_total", -1)))
|
||||
@@ -191,7 +191,7 @@ func _smoke_adventure() -> void:
|
||||
reward_ok = false
|
||||
check(reward_ok, "大奖励读数:hp_bonus=表值 · 新上限累加 · 回满=新上限 · 钥石逐关注账")
|
||||
var seq: Array = st["encounter_max_hp_seq"]
|
||||
var k := 3.0 # hp+200 ⇒ TunePanel 百分比后乘 ×3(加算先加、百分比后乘——生效次序口径)
|
||||
var k := 5.0 # hp+400 ⇒ TunePanel 百分比后乘 ×5(加算先加、百分比后乘——生效次序口径)
|
||||
var exp_base := maxi(1, int(round(float(int(_db.hero.max_hp)) * k)))
|
||||
var exp_l2 := maxi(1, int(round(float(int(_db.hero.max_hp) + hp_bonus) * k)))
|
||||
var exp_l3 := maxi(1, int(round(float(int(_db.hero.max_hp) + 2 * hp_bonus) * k)))
|
||||
@@ -202,7 +202,7 @@ func _smoke_adventure() -> void:
|
||||
check(idx_l2 > 0 and idx_l3 > idx_l2,
|
||||
"L2/L3 首战上限入参 = 基础+加算(%d→%d——大奖励经覆盖值通道传播)" % [exp_l2, exp_l3])
|
||||
# ③ 种子域可复现(同种子两局:summary + 上限序列 + 行进序列逐位一致)
|
||||
var st2: Dictionary = autoplay.run_adventure(_db, 42, 400, 200)
|
||||
var st2: Dictionary = autoplay.run_adventure(_db, 42, 900, 400)
|
||||
check(st2["summary"] == sum and st2["encounter_max_hp_seq"] == seq
|
||||
and st2["visited_ids"] == st["visited_ids"],
|
||||
"同种子两局逐位可复现(summary/上限序列/行进序列——主种子单点派生)")
|
||||
@@ -242,7 +242,7 @@ func _smoke_adventure() -> void:
|
||||
"L2 败北败退明细:层号=2 · 节点在案(数值验证取数面 2026-09-22)")
|
||||
# ⑥ 重复宣布拒绝(settle 后再调 _on_level_finished——摘要零变化)
|
||||
var adr6 = load("res://core/adventure_runner.gd").new(_db, _fresh_rng(7))
|
||||
adr6.set_hero_override(400, 200)
|
||||
adr6.set_hero_override(900, 400)
|
||||
check(adr6.start_adventure(7), "重复拒绝场景:冒险启动(seed 7)")
|
||||
var b6 = adr6.runner().current_battle()
|
||||
var st6 := _adv_st()
|
||||
@@ -273,7 +273,7 @@ func _smoke_adventure() -> void:
|
||||
var same := {}
|
||||
for s in range(42, 92):
|
||||
var a8 = load("res://core/adventure_runner.gd").new(_db, _fresh_rng(s))
|
||||
a8.set_hero_override(400, 200)
|
||||
a8.set_hero_override(900, 400)
|
||||
if not a8.start_adventure(s):
|
||||
continue
|
||||
if _adv_drive_to_shop(a8, _adv_st(), autoplay):
|
||||
@@ -313,7 +313,7 @@ func _smoke_adventure() -> void:
|
||||
"同一公式两个落点逐位一致(LevelRunner.rest_heal_amount 内置默认)")
|
||||
# ⑩ 放弃(战斗中拒绝 · 非战斗期受理同失败型结算)
|
||||
var a10 = load("res://core/adventure_runner.gd").new(_db, _fresh_rng(15))
|
||||
a10.set_hero_override(400, 200)
|
||||
a10.set_hero_override(900, 400)
|
||||
check(a10.start_adventure(15), "放弃场景:冒险启动(seed 15——首战在飞)")
|
||||
check(not a10.abandon(), "战斗中 abandon 拒绝(战斗域单事务在飞)")
|
||||
var b10 = a10.runner().current_battle()
|
||||
@@ -2907,7 +2907,7 @@ func _smoke_shop_room() -> void:
|
||||
var shop_run := {}
|
||||
for s in range(42, 92):
|
||||
var runner = load("res://core/level_runner.gd").new(_db, _fresh_rng(s))
|
||||
runner.set_hero_override(400, 200) # 行进段快速通关档(购买断言与百分比轴正交——加算区单独断言)
|
||||
runner.set_hero_override(900, 400) # 行进段快速通关档(购买断言与百分比轴正交——加算区单独断言)
|
||||
runner.start_level(2, s)
|
||||
var st := {"result": "", "rounds": 0, "refreshes": 0, "mine_hits": 0, "hero_dmg": 0, "policy": "normal"}
|
||||
var guard := 40
|
||||
@@ -3481,7 +3481,7 @@ func _smoke_save() -> void:
|
||||
|
||||
# ⑨ 摘要集成(冒险结构批产物驱动):run_adventure 真局摘要 → apply 原语 → 域读数 → 写盘读回保持
|
||||
var autoplay = load("res://smoke/level_autoplay.gd")
|
||||
var st9: Dictionary = autoplay.run_adventure(_db, 42, 400, 200)
|
||||
var st9: Dictionary = autoplay.run_adventure(_db, 42, 900, 400)
|
||||
var f9 = sm_script.new(paths[8])
|
||||
f9.apply_adventure_summary(st9.get("summary", {}))
|
||||
var kpl := int(_db.adventure.keystone_per_level)
|
||||
@@ -3492,7 +3492,7 @@ func _smoke_save() -> void:
|
||||
"集成三关首杀标记齐")
|
||||
check(f9.recent_summaries().size() == 1 and int(f9.recent_summaries()[0].get("master_seed", -1)) == 42,
|
||||
"集成 recent 1 条且 seed 42")
|
||||
var st9b: Dictionary = autoplay.run_adventure(_db, 42, 400, 200)
|
||||
var st9b: Dictionary = autoplay.run_adventure(_db, 42, 900, 400)
|
||||
f9.apply_adventure_summary(st9b.get("summary", {}))
|
||||
check(f9.clear_count(1) == 2 and f9.clear_count(2) == 2 and f9.clear_count(3) == 2, "第二局后通关次数全 2")
|
||||
check(f9.keystone_balance() == 6 * kpl, "第二局后余额翻倍(6 × keystone_per_level)")
|
||||
|
||||
Reference in new issue
Block a user