Files
gplan-2/game/data/schemas/shop_table.gd
T
DKChan 9a72394652 chore(代码卫生): 头注存量清偿批——82 文件按两类白名单改写为 ## 文档注释载体
按 code-conventions §1.4.1 第三轮定稿执行:core 22+schemas 18+presentation 根 14+views 28,全部头注 #→##、删日期/变更叙事/GDD 与架构反向链接/字段与域清单/机制描述,保留职责摘要+真实使用约束(防事故禁令/单一入口/信号契约每信号一行)。main.gd 31→5 行、save_manager 45→5 行、adventure_runner 37→5 行为最大单件。子代理分模块执行(波一 core+schemas、波二 presentation+views,并发≤2)。验收=tools/verify_comment_only_change.py 逐字节校验(82 文件头注区外逐行一致=零行为变更)+audit_file_headers 全绿;纯注释批免冒烟(先例 5843270)
2026-10-16 23:28:07 +08:00

106 lines
6.2 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.
## VERTICAL SLICE - NOT FOR PRODUCTION
## 商店表 schema:GP 掉落/关级加值/商品/共享池货架行族 + 爬价因子的类型化读取(行值 provisional;垂直切片验证:商店房 GP 购买兑现局内成长)。
## 消费面一律走 ConfigDB.shop_* 访问器,禁直读行集。
## 行族不记库存:货架=上限即库存,账本单点在冒险侧;products+加法定价=legacy 面(shop=off 对照),现役走 pool_shelf。
class_name ShopTable
extends Resource
@export var gp_drops: Array[Dictionary] = [] # Array[Dictionary] 键 tier
@export var level_gp_bonus: Array[Dictionary] = [] # Array[Dictionary] 键 level_index
@export var products: Array[Dictionary] = [] # Array[Dictionary] 键 product_id
@export var price_level_bonus: Array[Dictionary] = [] # Array[Dictionary] 键 level_index
@export var pool_shelf: Array[Dictionary] = [] # Array[Dictionary] 键 kind_id(迭代 11 第②批 T1)
@export var price_a: float = 0.0 # 进店已购次数爬价因子(provisional——0 = 未投值即致命域)
@export var price_b: float = 0.0 # 跨关递增因子(provisional)
const GP_TIERS := ["normal", "elite", "boss"]
const PRODUCT_ATTRS := ["atk", "max_hp", "armor_class"]
const SHELF_KINDS := ["attack", "max_hp", "armor", "ap", "feat_ticket", "heal"] # 货架候选词表(四切边后种 + T5 门票行 + T6 heal 补回复〔默认原则:分类内成员都入该渠道池〕——奇物批迭代15②)
func validate() -> Array:
var errs: Array[Dictionary] = []
# 行族空护栏(legacy 四轴 + pool_shelf 皆为 ConfigDB 消费面——缺族即致命)
for family in ["gp_drops", "level_gp_bonus", "products", "price_level_bonus", "pool_shelf"]:
if get(family).is_empty():
errs.append({"category": "empty_table", "message": "ShopTable 行族为空: %s" % family})
# gp_drops:tier 词表封闭 + 掷定域 + 均值锚 + tier 唯一
var seen_tier := {}
for row in gp_drops:
var tier: String = row.get("tier", "")
if not GP_TIERS.has(tier):
errs.append({"category": "enum", "message": "gp_drops tier 出域 {normal, elite, boss}: %s" % tier})
if seen_tier.has(tier):
errs.append({"category": "dup_key", "message": "gp_drops tier 重复: %s" % tier})
seen_tier[tier] = true
if String(row.get("display_name", "")) == "":
errs.append({"category": "domain", "message": "gp_drops %s display_name 空" % tier})
var rmin: int = int(row.get("roll_min", -1))
var mean: int = int(row.get("mean", -1))
var rmax: int = int(row.get("roll_max", -1))
if rmin < 0 or mean < 0 or rmax < 0 or rmax > 999:
errs.append({"category": "domain", "message": "gp_drops %s 掷定域越域 [0,999]: %d..%d..%d" % [tier, rmin, mean, rmax]})
if rmin > mean or mean > rmax:
errs.append({"category": "cross_field", "message": "gp_drops %s 违反 roll_min(%d) ≤ mean(%d) ≤ roll_max(%d)——均值恒等期望锚" % [tier, rmin, mean, rmax]})
# level_gp_bonus / price_level_bonus:level_index 连续从 1 递增 + 加值域
for family in ["level_gp_bonus", "price_level_bonus"]:
var arr: Array[Variant] = get(family)
var seen := {}
for row in arr:
var li: int = int(row.get("level_index", 0))
if seen.has(li):
errs.append({"category": "dup_key", "message": "%s level_index 重复: %d" % [family, li]})
seen[li] = true
var bonus: int = int(row.get("bonus", -1))
if bonus < 0 or bonus > 999:
errs.append({"category": "domain", "message": "%s level %d bonus 越域 [0,999]: %d" % [family, li, bonus]})
for i in arr.size():
var li: int = int(arr[i].get("level_index", 0))
if li != i + 1:
errs.append({"category": "structural", "message": "%s level_index 不连续(须从 1 连续递增): 位 %d = %d" % [family, i + 1, li]})
break
# products:product_id 唯一 + attr 词表 + 价格域 [1,999]
var seen_pid := {}
for row in products:
var pid: String = row.get("product_id", "")
if pid == "":
errs.append({"category": "domain", "message": "products product_id 空"})
continue
if seen_pid.has(pid):
errs.append({"category": "dup_key", "message": "products product_id 重复: %s" % pid})
seen_pid[pid] = true
if String(row.get("display_name", "")) == "":
errs.append({"category": "domain", "message": "%s display_name 空" % pid})
var attr: String = row.get("attr", "")
if not PRODUCT_ATTRS.has(attr):
errs.append({"category": "enum", "message": "%s attr 出域 {atk, max_hp, armor_class}: %s" % [pid, attr]})
var flat: int = int(row.get("flat_value", 0))
if flat < 1 or flat > 999:
errs.append({"category": "domain", "message": "%s flat_value 越域 [1,999]: %d" % [pid, flat]})
var base: int = int(row.get("base_price", 0))
if base < 1 or base > 999:
errs.append({"category": "domain", "message": "%s base_price 越域 [1,999]: %d" % [pid, base]})
var inc: int = int(row.get("price_increment", -1))
if inc < 0 or inc > 999:
errs.append({"category": "domain", "message": "%s price_increment 越域 [0,999]: %d" % [pid, inc]})
# pool_shelf:kind_id 词表封闭(四切边后种)+ 唯一 + display_name + base_price 域 [1,999](迭代 11 第②批 T1)
var seen_kind := {}
for row in pool_shelf:
var kind: String = row.get("kind_id", "")
if not SHELF_KINDS.has(kind):
errs.append({"category": "enum", "message": "pool_shelf kind_id 出域(四切边后种封闭词表): %s" % kind})
if seen_kind.has(kind):
errs.append({"category": "dup_key", "message": "pool_shelf kind_id 重复: %s" % kind})
seen_kind[kind] = true
if String(row.get("display_name", "")) == "":
errs.append({"category": "domain", "message": "pool_shelf %s display_name 空" % kind})
var base: int = int(row.get("base_price", 0))
if base < 1 or base > 999:
errs.append({"category": "domain", "message": "pool_shelf %s base_price 越域 [1,999]: %d" % [kind, base]})
# 价格因子域(乘法语义——A/b 均 ≥1 单调不降;上界防手滑投值;provisional 值本体归难度曲线与Boss)
if price_a < 1.0 or price_a > 3.0:
errs.append({"category": "domain", "message": "price_a 越域 [1.0,3.0]: %f" % price_a})
if price_b < 1.0 or price_b > 2.0:
errs.append({"category": "domain", "message": "price_b 越域 [1.0,2.0]: %f" % price_b})
return errs