- Package B 迭代七轮:enemy HP 阶梯重锚+阶段拔高(L2/L3 14 行+伤害轴 atk 3)、AP 6→8、 clear_blast 26/18/35→32/24/40、heal_minor 加强、hero max_hp 20、d3 缩板 10×10(板随战斗时长配) - 数值设计批(game-balancer 工作流):关卡怪物成长×永久锻造对齿,forge base_price 10→20 - 三阶段快照验证(report_M0/M1/M2):墙真实存在、锻造单调开门,拍板 B 接受现曲线 - 详见 qa-data/iteration_log.md(九段台账)与 数值设计_关卡成长×永久成长_v1.md - smoke 工具入库:adventure_monte_carlo.gd / calibrate_boards.gd;qa-data 原始 fulllog 不入库
95 lines
4.3 KiB
Python
95 lines
4.3 KiB
Python
# -*- coding: utf-8 -*-
|
||
"""
|
||
关卡怪物成长 × 永久成长 对齿模型(game-balancer 工作流 step 2-3)
|
||
链条模型:逐节点 击杀轮=t_kill=敌总血/我方DPS;承伤/轮=实测口径;池血衰减+战斗治疗;
|
||
裕度 m=进场池血/承伤每轮 − t_kill → 经验分段映射胜率(用第 6 轮 MC 实测校准,±10~15pp)。
|
||
阶段 S0-S3 = 永久锻造累计(atk+ / hp+ / ac+),ac 每点 ≈ 承伤 -7%(近似,标 provisional)。
|
||
输出:阶段×关卡 到达boss率/通关率 矩阵(v1=第6轮现役怪=校准组;v2=阶段拔高提案=设计组)。
|
||
"""
|
||
DPS_DIG = {1: 5.9, 2: 7.1, 3: 6.3} # 实测输出/轮 − 主角免费攻2(第6轮 normal)
|
||
HEAL_K = 0.85 # 治疗每战 ≈ 0.85×击杀轮(第6轮实测拟合)
|
||
|
||
# (关, 节点, 数量期望, 单位血v1, 单位血v2, atk v1, atk v2, 承伤/轮v1实测, boss)
|
||
NODES = [
|
||
(1, 0, 1.5, 8, 8, 2, 2, 0.79, False),
|
||
(1, 1, 2.5, 4, 4, 2, 2, 0.65, False),
|
||
(1, 2, 1.0, 50, 50, 2, 2, 1.09, False),
|
||
(1, 3, 2.5, 14, 14, 2, 2, 1.94, False),
|
||
(1, 4, 1.0, 72, 72, 2, 2, 1.12, True),
|
||
(2, 0, 1.0, 45, 50, 2, 2, 1.08, False),
|
||
(2, 1, 2.5, 18, 20, 2, 2, 1.99, False),
|
||
(2, 4, 2.0, 20, 22, 2, 2, 1.80, False),
|
||
(2, 5, 1.0, 68, 85, 2, 3, 1.32, False),
|
||
(2, 6, 2.5, 18, 20, 1, 1, 1.62, False),
|
||
(2, 7, 2.5, 18, 20, 2, 2, 1.80, False),
|
||
(2, 9, 1.0, 80,105, 2, 3, 1.32, True),
|
||
(3, 0, 1.0, 50, 60, 2, 3, 1.03, False),
|
||
(3, 1, 2.0, 25, 28, 2, 3, 1.53, False),
|
||
(3, 4, 2.5, 20, 22, 2, 3, 1.90, False),
|
||
(3, 5, 1.0, 76, 95, 2, 3, 1.40, False),
|
||
(3, 6, 2.5, 20, 22, 2, 3, 2.15, False),
|
||
(3, 7, 2.5, 20, 22, 2, 3, 2.15, False),
|
||
(3, 9, 1.0, 92,125, 2, 3, 1.06, True),
|
||
]
|
||
# 缺实测的行用同原型插值填的(2,4)/(2,7)/(3,4)/(3,5) 按双单位/单体原型估。
|
||
|
||
def win(m):
|
||
if m <= -5: return 0.35
|
||
if m <= -3: return 0.48
|
||
if m <= -1.5: return 0.60
|
||
if m <= 0: return 0.68
|
||
if m <= 2: return 0.80
|
||
if m <= 5: return 0.90
|
||
if m <= 9: return 0.95
|
||
return 0.97
|
||
|
||
def run_level(L, atk_up, hp_up, ac_up, ver, pool0, bonus, verbose=False):
|
||
dps = DPS_DIG[L] + 2 + atk_up
|
||
fac = 1.0 - 0.07 * ac_up
|
||
pool = pool0
|
||
reach = 1.0
|
||
for (l, d, u, h1, h2, a1, a2, intake1, boss) in NODES:
|
||
if l != L: continue
|
||
hp = u * (h2 if ver == 2 else h1)
|
||
atk = (a2 if ver == 2 else a1)
|
||
intake = intake1 * (atk / a1) * fac
|
||
if ver == 2: intake *= 1.0 # v2 承伤已按 atk 比例走上面一行
|
||
t_kill = hp / dps
|
||
t_live = pool / intake
|
||
m = t_live - t_kill
|
||
p = win(m)
|
||
if verbose:
|
||
print(f" L{L} d{d}{' BOSS' if boss else '':>5} hp={hp:5.0f} dps={dps:4.1f} tkill={t_kill:4.1f} intake={intake:4.2f} tlive={t_live:4.1f} m={m:+5.1f} p={p:.2f}")
|
||
yield_p = reach * p
|
||
# boss 到达率在进入该点时即定格
|
||
if boss and verbose is not None:
|
||
boss_reach = reach
|
||
pool -= t_kill * intake * (0.5 + 0.5 * p) # 败北也吃部分伤(平均 ~50%*tkill 承伤)
|
||
pool += HEAL_K * t_kill * p # 治疗只在胜局兑现大头
|
||
reach = yield_p
|
||
return boss_reach, reach
|
||
|
||
def stage_curve(atk_up, hp_up, ac_up, ver, bonus=10, tag=""):
|
||
out = {}
|
||
pool = 20 + hp_up
|
||
for L in (1, 2, 3):
|
||
poolL = pool + bonus * (L - 1)
|
||
r, c = run_level(L, atk_up, hp_up, ac_up, ver, poolL, bonus)
|
||
out[L] = (r, c, poolL)
|
||
pool = pool + bonus if c > 0.001 else pool # 通关才拿关间奖励
|
||
print(f"{tag} atk+{atk_up} hp+{hp_up} ac+{ac_up}: "
|
||
f"L1 达boss -/通关 {out[1][1]*100:4.1f}% | "
|
||
f"L2 达boss {out[2][0]*100:4.1f}% 通关 {out[2][1]*100:4.1f}% | "
|
||
f"L3 达boss {out[3][0]*100:4.1f}% 通关 {out[3][1]*100:4.1f}%")
|
||
return out
|
||
|
||
print("=== 校准组 v1(第6轮现役怪,模型 vs 实测)===")
|
||
print("实测: L1通关 normal49.7/perfect85 | L2条件通过53/77.6 | L2 boss胜率65/97 | L3 boss胜率47/67 | 全通关 10/39.7")
|
||
stage_curve(0, 0, 0, 1, tag="S0 fresh")
|
||
print()
|
||
print("=== 设计组 v2(阶段拔高提案)===")
|
||
stage_curve(0, 0, 0, 2, tag="S0 fresh ")
|
||
stage_curve(2, 6, 1, 2, tag="S1 ≈5次L1刷 ")
|
||
stage_curve(4, 12, 2, 2, tag="S2 ≈再刷L2 ")
|
||
stage_curve(6, 18, 3, 2, tag="S3 毕业 ")
|