feat(shop): 设计器「属性」页扩展 shop 段五字段
mode/curve 下拉存 key 不存双语显示串;UI.spin 的 min 取 0 以免 Range 的 抵消误差把浮点噪声写进权威数据文件(E3-① 实测);price_base 存 float 而非 int——JSON.parse_string 对所有 JSON 数字一律解析为 float,存 int 会使往返逐位比较恒假失败,且与 price_formula.gd 的 float() 读取一致。 Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
@@ -9,9 +9,14 @@ const PATH = "res://data/attributes.json"
|
|||||||
const COMBINE_KEYS = ["hybrid", "inverse", "add_int"]
|
const COMBINE_KEYS = ["hybrid", "inverse", "add_int"]
|
||||||
const COMBINE_LABELS = ["混合 hybrid", "反向 inverse", "整数加 add_int"]
|
const COMBINE_LABELS = ["混合 hybrid", "反向 inverse", "整数加 add_int"]
|
||||||
const ATTR_ORDER = ["cpu_limit", "move_speed", "cast_delay_mod", "hp_max"]
|
const ATTR_ORDER = ["cpu_limit", "move_speed", "cast_delay_mod", "hp_max"]
|
||||||
|
const MODE_KEYS = ["flat", "pct"]
|
||||||
|
const MODE_LABELS = ["固定量 flat", "百分比 pct"]
|
||||||
|
const CURVE_KEYS = ["geometric", "linear", "flat"]
|
||||||
|
const CURVE_LABELS = ["几何 geometric", "线性 linear", "固定 flat"]
|
||||||
|
|
||||||
var _data: Dictionary = {}
|
var _data: Dictionary = {}
|
||||||
var _rows: Dictionary = {} # attr_id → {"base": SpinBox, "soft": SpinBox, "hard": SpinBox, "combine": OptionButton}
|
var _rows: Dictionary = {} # attr_id → {"base": SpinBox, "soft": SpinBox, "hard": SpinBox, "combine": OptionButton}
|
||||||
|
var _shop_rows: Dictionary = {} # attr_id → {"mode","step","price_base","price_growth","curve"} 控件
|
||||||
var _status: Label
|
var _status: Label
|
||||||
var _loaded: bool = false # 加载失败时禁止写回,见 _save
|
var _loaded: bool = false # 加载失败时禁止写回,见 _save
|
||||||
|
|
||||||
@@ -49,8 +54,28 @@ func _ready() -> void:
|
|||||||
grid.add_child(sp_base); grid.add_child(sp_soft); grid.add_child(sp_hard); grid.add_child(op)
|
grid.add_child(sp_base); grid.add_child(sp_soft); grid.add_child(sp_hard); grid.add_child(op)
|
||||||
_rows[attr_id] = {"base": sp_base, "soft": sp_soft, "hard": sp_hard, "combine": op}
|
_rows[attr_id] = {"base": sp_base, "soft": sp_soft, "hard": sp_hard, "combine": op}
|
||||||
add_child(HSeparator.new())
|
add_child(HSeparator.new())
|
||||||
|
add_child(UI.header("🛒 货架 C — 可售配置(无 shop 段 = 不可购买)"))
|
||||||
|
var g2 := GridContainer.new(); g2.columns = 6; add_child(g2)
|
||||||
|
for h2 in ["属性", "增量类型 mode", "每级 step", "首价 price_base", "涨幅 growth", "曲线 curve"]:
|
||||||
|
var l2 := Label.new(); l2.text = h2; l2.modulate = Color(0.7, 0.8, 1.0)
|
||||||
|
g2.add_child(l2)
|
||||||
|
for attr_id2 in ATTR_ORDER:
|
||||||
|
var sp: Dictionary = _data.get(attr_id2, {}).get("shop", {})
|
||||||
|
g2.add_child(UI.cell_label(String(_data.get(attr_id2, {}).get("display_name", attr_id2))))
|
||||||
|
var mi: int = MODE_KEYS.find(String(sp.get("mode", "flat")))
|
||||||
|
var op_mode := UI.opt(MODE_LABELS, mi if mi >= 0 else 0)
|
||||||
|
var sp_step := UI.spin(0.0, 99999.0, 0.01, float(sp.get("step", 0.0)))
|
||||||
|
var sp_pbase := UI.spin(0.0, 99999.0, 1.0, float(sp.get("price_base", 0.0)))
|
||||||
|
var sp_grow := UI.spin(0.0, 99999.0, 0.01, float(sp.get("price_growth", 1.0)))
|
||||||
|
var ci: int = CURVE_KEYS.find(String(sp.get("curve", "geometric")))
|
||||||
|
var op_curve := UI.opt(CURVE_LABELS, ci if ci >= 0 else 0)
|
||||||
|
g2.add_child(op_mode); g2.add_child(sp_step); g2.add_child(sp_pbase)
|
||||||
|
g2.add_child(sp_grow); g2.add_child(op_curve)
|
||||||
|
_shop_rows[attr_id2] = {"mode": op_mode, "step": sp_step,
|
||||||
|
"price_base": sp_pbase, "price_growth": sp_grow, "curve": op_curve}
|
||||||
|
add_child(HSeparator.new())
|
||||||
var tip := Label.new()
|
var tip := Label.new()
|
||||||
tip.text = "hard=0 在 hybrid / add_int 下表示不钳制;inverse 的 hard 是「下限」,填 0 即钳到 0(与 hybrid 相反);add_int 拒绝 pct 加成;soft 本期不参与计算(留给货架 C)。"
|
tip.text = "hard=0 在 hybrid / add_int 下表示不钳制;inverse 的 hard 是「下限」,填 0 即钳到 0(与 hybrid 相反);add_int 拒绝 pct 加成;soft 本期不参与计算(留给货架 C)。cpu_limit 的 mode 必须是 flat(add_int 拒绝 pct);shop 段缺失即该属性不可购买。"
|
||||||
# dock 的 ScrollContainer 禁用横向滚动,不换行的话这句会被右侧裁掉(正是最需要看到的半句)
|
# dock 的 ScrollContainer 禁用横向滚动,不换行的话这句会被右侧裁掉(正是最需要看到的半句)
|
||||||
tip.autowrap_mode = TextServer.AUTOWRAP_WORD_SMART
|
tip.autowrap_mode = TextServer.AUTOWRAP_WORD_SMART
|
||||||
tip.modulate = Color(0.7, 0.7, 0.7)
|
tip.modulate = Color(0.7, 0.7, 0.7)
|
||||||
@@ -99,6 +124,18 @@ func _collect() -> Dictionary:
|
|||||||
entry["hard"] = _clean(r["hard"].value)
|
entry["hard"] = _clean(r["hard"].value)
|
||||||
# 存 key,不存双语显示串;selected 恒为 0..2(UI.opt 构造时已 clampi,本页此后不再赋值)
|
# 存 key,不存双语显示串;selected 恒为 0..2(UI.opt 构造时已 clampi,本页此后不再赋值)
|
||||||
entry["combine"] = COMBINE_KEYS[r["combine"].selected]
|
entry["combine"] = COMBINE_KEYS[r["combine"].selected]
|
||||||
|
var r2: Dictionary = _shop_rows.get(attr_id, {})
|
||||||
|
if not r2.is_empty():
|
||||||
|
var shop_entry: Dictionary = entry.get("shop", {}).duplicate(true)
|
||||||
|
shop_entry["mode"] = MODE_KEYS[r2["mode"].selected] # 存 key 不存显示串
|
||||||
|
shop_entry["step"] = _clean(float(r2["step"].value))
|
||||||
|
# 注意:不用 int()——JSON.parse_string 对所有 JSON 数字(含无小数点的字面量,
|
||||||
|
# 如源文件的 "price_base": 120)一律解析为 float,若此处存 int 则往返比较时
|
||||||
|
# str(120) != str(120.0) 恒假失败,与 price_formula.gd 的 float() 读取方式一致
|
||||||
|
shop_entry["price_base"] = _clean(float(r2["price_base"].value))
|
||||||
|
shop_entry["price_growth"] = _clean(float(r2["price_growth"].value))
|
||||||
|
shop_entry["curve"] = CURVE_KEYS[r2["curve"].selected]
|
||||||
|
entry["shop"] = shop_entry
|
||||||
out[attr_id] = entry
|
out[attr_id] = entry
|
||||||
return out
|
return out
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user