## PriceFormula — 价格计算的唯一实现处 ## 纯静态函数:无状态、不依赖 ShopManager / PlayerStats / 场景树,故可脱离游戏进程单元测试 ## 本模块**不认识**「属性/武器/装备」,只认识 {price_base, price_growth, curve} —— ## 划分点在数据里,故货架 B(核心抽取)与子计划 ④(出售退款)可直接复用。 ## 权威来源:docs_dev/specs/2026-07-31-shelf-c-attribute-shop-design.md §2.1 class_name PriceFormula extends RefCounted ## 命名为 PriceCurve 而非 Curve:Godot 引擎自带全局类 `Curve`(曲线资源), ## 嵌套枚举若同名会被解析器拒绝("member Curve shadows a native class"), ## 与 class_name 是否注册无关,故不能叫 Curve。此为本任务对简报字面代码的 ## 唯一必要偏离,详见 task-1-report.md。 enum PriceCurve { GEOMETRIC, LINEAR, FLAT } const _CURVE_BY_NAME: Dictionary[String, PriceCurve] = { "geometric": PriceCurve.GEOMETRIC, "linear": PriceCurve.LINEAR, "flat": PriceCurve.FLAT, } ## JSON 的 curve 字符串 → 枚举;未知值 push_error 并回退 GEOMETRIC static func curve_from_string(s: String) -> PriceCurve: if _CURVE_BY_NAME.has(s): return _CURVE_BY_NAME[s] push_error("PriceFormula: 未知 curve「%s」,回退 geometric" % s) return PriceCurve.GEOMETRIC ## 唯一的价格入口 ## spec —— 数据文件里的定价段,读 price_base / price_growth / curve ## purchased —— 已购次数(0 = 首次购买) ## 返回 int(金币是整数),下限 1:免费购买无意义,且 0 价会让「买不起」的判定失效 static func compute(spec: Dictionary, purchased: int) -> int: var base: float = float(spec.get("price_base", 0.0)) var growth: float = float(spec.get("price_growth", 1.0)) var n: int = maxi(purchased, 0) var curve: PriceCurve = curve_from_string(String(spec.get("curve", "geometric"))) var raw: float = 0.0 match curve: PriceCurve.LINEAR: raw = base + float(n) * growth PriceCurve.FLAT: raw = base _: raw = base * pow(growth, float(n)) return maxi(roundi(raw), 1)