Files
gplan-2/game/data/schemas/shop_table.gd
T
DKChan 03c4b4c933 docs: 文档正确性审查批+去毒+命名统一+天赋树成文等十一批落籍(2026-10-09 用户令)
一、里程碑语义立规:M3=Alpha 完整实现/M4=Beta 完整实现,未明令关闭 M3 前只排 M3 需求(roadmap M-4 节头立规注+M-3 节头口径指针+迭代 21+ 行注+06 倍率差条注);迭代 20/21/22 规划冻结(roadmap 迭代 20 行注——先解决眼前问题,重启=用户直接发令)
二、文档正确性审查批三波:全 GDD 29 份过审——状态记录按代码证据订正/里程碑删前缀(M-x+迭代N→迭代N,裸 M-4→Beta 阶段(未排期))/退役词退役件当现役清零/在役旧实现节加隔离横幅;重件=秘宝.md v1.7 老正文深层清算(横幅重写消「过渡形态已退役」误读/沿革节换代/六件旧件登记摘除/验收与 charges 矛盾订正)+奇物 v3.8+冒险结构 v0.18+关卡节点地图 v1.7+图生成 v0.7+难度曲线与Boss v0.26+战斗结算 v0.27+敌人系统 v0.16+地图战斗资源 v0.21+增益状态 v0.13+战斗表现 v0.6+元进度 v1.9+生涯 v0.3+00 v1.3+02 v1.16+03 v1.1+ux 八份(battle 23 处/camp/shop/node-reward/level-clear/interaction-patterns/settlement-summary/level-map)
三、去毒批:奇物 v3.7(魔法道具→秘宝/档名三档→四级/门票与刷新「尚未入表」假话订正/验收第 3 条改令牌口径/资源成员指路凭证件表)+秘宝 v1.6(速览旧目录退役标注/退役件示例换现役)
四、道具退役素材库新建(design/research/道具退役素材库.md,案乙已追认):秘宝退役 9 件含去向+专长退役 27 件名单+待核 4 行;魔法提灯(fog_lantern)裁退役(06 条目已裁+秘宝.md 注记换代+素材库迁表一;拆线归实装批)
五、B2/B3/B4 裁决落文:元进度.md 道具工坊行删旧写新(v1.10——旧六行登记作废、指路秘宝新目录+解锁门槛谓词分级);奇物.md P1「两项合成高阶项」注销(v3.9——用户定性脏信息);§3 刷新句按最新口径换代(刷新券替代、不进持有集)
六、天赋树独立成文(B1 裁决):新建 design/gdd/systems/跨局循环/天赋树.md v0.1(33 节点机制全按 meta_tree.tres 实态+迭代 12 落籍裁决+被删底稿 git 取证——脊柱行门槛/钥石单币/Fork A/B 面/存档 v5 域/注入双通道)+元进度.md 定名节换代(v1.11)+02-系统清单跨局循环区加行(v1.17)
七、A 类卫生包:版本历史表理排四份(秘宝/奇物含 v2.7 断裂行修复/敌人系统/图生成,只调行序)+缺号注记三处(增益状态 v0.6 未考/冒险结构 v0.15/关卡节点地图 v1.6=MC-1 批)+node-reward v2.2 双号改 a/b+07 补建版本历史表+06 删「设置与本地化」空节+「文档/结构闸存量欠账」块挪文末「文档与结构」节+「L1 商店编排」两悬空指针改指 GP 换算失衡条+难度曲线两处过期指向核销注记(v0.27)+B5「现役 UI/文案两处自相冲突」登记 06 待办(battle_narrator.gd:160 旧话/hero_info_panel 两段同标「特性」——随后续迭代修)
八、命名统一(用户令「任务书」全库改「需求卡片」):167 文件约 800 处(design/ 全部文档+roadmap+CLAUDE.md+active.md+entities.yaml+game/ 注释与数据批注);两文件改名(需求卡片-M4数值批/需求卡片-冒险前资源配比预设批);残留=自造短语全量清单(黑话证据文档故意跳过)
九、CLAUDE.md:批次工作流标准清单收口段新增第 12 条「文档同步闸」(需求卡片必列关联文档同步面、合并前同步完毕方算收口,原 12/13 顺延);呈报六问铁规适用范围补立(前序批随批落籍)
十、active.md 快照节+工作日志 414-421(并行会话 416 黑话清扫条目按共享工作日志惯例一并入库);06 中并行会话「active.md 定性与裁剪」条目未提交,按零吞并纪律留在工作区未入库

零测试(文档批两入口铁规);主区前序脏件(.gitignore/.zcode/config.json/playnote/project.godot/.zcodeignore/美术审计报告 html 等)未带
2026-10-09 19:12:46 +08:00

119 lines
7.7 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
# Validation Question: 玩家能否在 Boss 前商店房用战斗掉落 GP 购买三属性锻造档,兑现「数值提升→后续战斗改善」的局内成长闭环(P1)
# Date: 2026-09-21(GP+商店房实施批——2026-09-20 用户拍板,设计权威 design/research/proposal-gp-shop-room-2026-09-20.md 裁决记录)
# 数据配置 ShopTable schema(GP 冒险钱包 × 商店房 行族四轴)。
# 行族四轴(数据契约对齐 ConfigDB.shop_* 访问器——消费面一律走访问器,禁直读行集):
# gp_drops = 战斗掉落掷定行(键 tier:normal/elite/boss 封闭词表;掷定 = roll_min..roll_max 均匀整数,
# mean = 期望锚——roll_min ≤ mean ≤ roll_max,行动经济 条款①期望当量锚同款纪律);elite 为预留行
#(当前无消费方,随精英节点内容批启用)。level_gp_bonus = 关级掉落加值行(level_index 连续从 1 递增)。
# products = 商品行(键 product_id;三件全陈列无刷新无摇号——2026-09-20 拍板);
# 现价公式 = base_price + price_level_bonus(关卡) + price_increment × 该商品已购档数(已购档数在 冒险结构)。
# price_level_bonus = 关级定价加值行(level_index 连续从 1 递增)。
# pool_shelf = 共享池货架行(M-4 迭代 11 第②批 T1——需求卡片 v1.3 P1 共享池/P4 ceil):键 kind_id 词表
# 封闭 = 四切边后种(SHELF_KINDS:attack/max_hp/armor/ap——GP 袋负交易切边、规则改写型特性三轴 doctrine 切边);
# 库存=上限即库存(账本在 冒险结构 _curio_taken 单点共享,行族不记库存);price_a/price_b = 乘法价格
# 因子(公式 ceil(base × b^(关序−1) × A^(本次进店已购次数)),provisional 投值——P5 甲研究拍板后置追认)。
# products 行族 + 加法定价随 legacy 模式(shop=off 对照承载)保留,退役归 off 锚换代批。
# 行值全部 provisional 归 难度曲线与Boss(用户拍板骨架先行、数值整体后置)。
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 = 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