Files
spellforge/scripts/domain/attribute_formula.gd
T
joywayerandClaude Opus 5 ecf765d03e feat(attr): AttributeFormula 公式模块——hybrid 连乘 / inverse 反向下限 / add_int 拒 pct
公式集中于单一纯静态模块,无状态零依赖,故可脱离游戏进程单元断言。
乘算用连乘而非线性求和:三条 +20% 得 ×1.728 而非 ×1.6,避免后期线性失控。
add_int 对离散预算拒绝 pct 并 push_error,而非静默取整掩盖配置错误。

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-07-31 10:46:20 +08:00

55 lines
2.3 KiB
GDScript
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
## AttributeFormula — 属性合成公式的唯一实现处
## 纯静态函数:无状态、不依赖 PlayerStats / EventBus / 场景树,故可脱离游戏进程单元测试
## 权威来源:docs_dev/specs/2026-07-31-player-attributes-design.md §2.1 / §2.3
class_name AttributeFormula
extends RefCounted
enum Combine { HYBRID, INVERSE, ADD_INT }
const _COMBINE_NAMES: Dictionary = {
"hybrid": Combine.HYBRID,
"inverse": Combine.INVERSE,
"add_int": Combine.ADD_INT,
}
## JSON 的 combine 字符串 → 枚举;未知值 push_error 并回退 HYBRID
static func combine_from_string(s: String) -> Combine:
if _COMBINE_NAMES.has(s):
return _COMBINE_NAMES[s]
push_error("AttributeFormula: 未知 combine「%s」,回退 hybrid" % s)
return Combine.HYBRID
## 唯一的公式入口
## base —— attributes.json 的基准值
## mods —— [{"mode": "flat"|"pct", "value": float}, ...];调用方负责只传本属性的加成
## attr_def —— attributes.json 中该属性的定义(读 combine / hard
## 返回统一为 floatadd_int 属性由调用方做 int() 转换(公式模块不感知目标字段类型)
static func compute(base: float, mods: Array, attr_def: Dictionary) -> float:
var combine: Combine = combine_from_string(String(attr_def.get("combine", "hybrid")))
var hard: float = float(attr_def.get("hard", 0.0))
var flat_sum: float = 0.0
var pct_prod: float = 1.0
for m in mods:
var mode: String = String(m.get("mode", "flat"))
var v: float = float(m.get("value", 0.0))
if mode == "flat":
flat_sum += v
elif mode == "pct":
if combine == Combine.ADD_INT:
push_error("AttributeFormula: add_int 属性不接受 pct 加成(value=%f),已忽略" % v)
continue
# 连乘而非线性求和:三条 +20% = ×1.728 而非 ×1.6,避免后期线性失控
pct_prod *= (1.0 + v) if combine == Combine.HYBRID else (1.0 - v)
else:
push_error("AttributeFormula: 未知 mode「%s」,已忽略" % mode)
match combine:
Combine.ADD_INT:
var ri: float = floorf(base + flat_sum)
return clampf(ri, 0.0, hard) if hard > 0.0 else maxf(0.0, ri)
Combine.INVERSE:
# 越低越快:hard 是**下限**
return maxf(hard, (base + flat_sum) * pct_prod)
_:
var r: float = maxf(0.0, (base + flat_sum) * pct_prod)
return minf(r, hard) if hard > 0.0 else r # hard=0.0 约定为「不钳制」