From f8e02b0a0b41c99ec3127dd8bccd8f134bca6744 Mon Sep 17 00:00:00 2001 From: Joywayer Date: Mon, 3 Aug 2026 11:19:23 +0800 Subject: [PATCH] =?UTF-8?q?fix(shop):=20pct=20=E5=90=88=E5=B9=B6=E5=85=AC?= =?UTF-8?q?=E5=BC=8F=E6=8C=89=20combine=20=E5=88=86=E6=94=AF=E5=8F=96?= =?UTF-8?q?=E5=80=BC=EF=BC=8C=E4=BF=AE=E6=AD=A3=20inverse=20=E5=B1=9E?= =?UTF-8?q?=E6=80=A7=E7=AE=97=E9=94=99?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit _apply_attr_purchases() 原公式 merged=(1+step)^n−1 只对 AttributeFormula 的 hybrid 分支(f=1+v)成立;inverse 分支用 f=1−v,四个可售属性里 cast_delay_mod 恰是 inverse+pct,实际把 f 算成 2−1.1^n 而非设计意图的 0.9^n——n=7 时应得 0.478,实得 ≈0.0513,可购买次数从设计的约 22 次被砍到约 7 次即撞 soft,且 全程 f≥0 走不到越界钳制分支,零诊断。 这是 Task 2 简报 spec 本身推导错误(简报只在 hybrid 下验证过等价性),非 实现偏差;评审已订正 spec 与计划(68e3edb)。现按订正后的公式补上按 combine 分支取值:hybrid 用 merged=(1+step)^n−1,inverse 用 merged=1−(1−step)^n,flat 与 combine 无关不变。 补测显式覆盖此前遗漏的 inverse+pct 组合(此前运行时验证只买过 move_speed/hp_max/cpu_limit,唯独没买过 cast_delay_mod——测试盲区精确盖住 了 bug 所在处):n=1..3/7 逐点数值比对(容差 1e-6),并确认 soft 封顶购买 次数从 ~7 恢复到 ~22;hybrid/flat 对照组数值不变。 Co-Authored-By: Claude Opus 5 --- scripts/autoloads/shop_manager.gd | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/scripts/autoloads/shop_manager.gd b/scripts/autoloads/shop_manager.gd index d600604..8d037b6 100644 --- a/scripts/autoloads/shop_manager.gd +++ b/scripts/autoloads/shop_manager.gd @@ -181,8 +181,16 @@ func _apply_attr_purchases() -> void: continue var mode: String = String(sp.get("mode", "flat")) var step: float = float(sp.get("step", 0.0)) - # pct 合并:n 次 +step 在连乘下等价于单条 (1+step)^n − 1 - var merged: float = (pow(1.0 + step, float(n)) - 1.0) if mode == "pct" else (step * float(n)) + # pct 合并必须按属性的 combine 分支——AttributeFormula 对 hybrid 用 f=1+v、对 inverse 用 f=1-v, + # 故两者的等价单条值不同。写错会让 inverse 属性(cast_delay_mod)的曲线整体偏离且零诊断。 + var combine: String = String(_attr_def.get(id, {}).get("combine", "hybrid")) + var merged: float = 0.0 + if mode == "pct": + # hybrid: 需 f=(1+step)^n → merged=(1+step)^n−1 + # inverse: 需 f=(1−step)^n → merged=1−(1−step)^n + merged = (1.0 - pow(1.0 - step, float(n))) if combine == "inverse" else (pow(1.0 + step, float(n)) - 1.0) + else: + merged = step * float(n) # flat 线性可加,与 combine 无关 PlayerStats.add_modifier(id, mode, merged, MOD_SOURCE_SHOP_C) ## 存档:只存次数,加成是派生物(回读时经 _apply_attr_purchases 重建)