# VERTICAL SLICE - NOT FOR PRODUCTION # Validation Question: 七核心流派各 ≥3 件入局内随机渠道后,标签+档位激活引擎能否机械判「成型」、 # 专长带能否挂进令牌池稀有/罕见档随机投放(P0——迭代 12 双层 BD 实施批 T1) # Date: 2026-10-06(内容数据驱动扩展批 T3——行换代:hook/effects 挂点形态退役,triggers 事件订阅形态 # 唯一合法行形——旧 23 挂点枚举消亡:事件名+效果类型取代,任务书 R4 裁决) # 概念指路:本表的专长,与 adventure.tres 的属性值提升、资源,同属一个对象—— # 「奇物」(一次冒险内各渠道给予玩家的增益总称)。定义见 design/gdd/systems/冒险循环/奇物.md。 # 它们是它分类轴上的枚举(专长 / 属性值提升 / 资源),不是三套系统;本表承载「专长」(专长 Feat)的逐项定义。 # (2026-10-05 命名统一 + 分类重构:旧称「流派件」→「规则改写型特性」→ 现定名「专长」; # 表名与 feat_id 沿用历史命名,与统一词族对齐归后续批次——见 06-待办清单「命名统一」条目。 # 目标渠道:专长走关底 Boss 击败后专属三选一(不新增节点类型),见奇物文档 2.1 节。) # 数据配置 FeatTable schema(奇物·专长定义表;行 = Dictionary 键 feat_id,Rule 4 豁免 # 定义表——TreasureItemTable 先例)。 # 行字段:feat_id 主键 / display_name / rarity ∈ {common, rare, rarest}(对齐令牌池三档命名—— # 投放档映射:common/rare→稀有令牌档、rarest→罕见令牌档;relic 令牌永不入普通档)/ # archetype ∈ ARCHETYPES 七流派标签 / desc 效果说明(文案表值化——呈现层读行,零硬编码)/ # triggers 订阅行数组(订阅哪个事件 on / 什么条件 when / 什么效果 do——效果引擎 EffectEngine # 统一解释执行;四词表封闭校验=EffectEngine.validate_trigger_row 单一事实源)。 # 档位激活(整合定稿 设计工具 1——以撒套装/小骨铭文):同标签计数 ≥2→档一(流派核心规则)/≥4→档二 # (完全体);散件单体保底=每件效果独立生效,档位只做质变(反例 B-2)——引擎纯函数 FeatsEngine。 # 🔴 层级纪律(任务书红线 2):专长只走局内随机渠道(三选一/商店/格面)——本表行永不入同调位 # (treasure_items 表)/局外树(T8 节点表);扫雷触发点铁律:每流派 ≥1 行订阅扫雷侧事件 # (EffectEngine.MINE_EVENTS——加载校验,违反=红线①触碰面)。 class_name FeatTable extends Resource @export var rows: Array = [] # Array[Dictionary] 键 feat_id ## 流派标签词表(七核心——喂雷/淘金不在本批,R5 甲/缓议) const ARCHETYPES := ["magic", "pierce", "normal", "dig", "flag", "charge", "devour"] ## 稀有度词表(对齐令牌池三档;投放档映射 relic→rare / rarest→rarest) const RARITIES := ["common", "rare", "rarest"] ## 行键白名单(🔴 零裸 flat 同族护栏——键出域=加载致命;triggers/desc=T3 换代新形态) const ROW_KEYS := ["feat_id", "display_name", "rarity", "archetype", "triggers", "desc", "note"] ## trigger 行键(订阅行三字段:on/when?/do) const TRIGGER_KEYS := ["on", "when", "do"] func validate() -> Array: var errs: Array = [] if rows.is_empty(): return errs # 空表合法态(T1 基建先行——逐流派填行) var seen := {} # 流派扫雷覆盖聚合(🔴 红线①铁律——每流派 ≥1 行订阅扫雷侧事件) var arch_mine := {} # archetype → bool for row in rows: var rid: String = row.get("feat_id", "") if rid == "": errs.append({"category": "domain", "message": "feat_id 空"}) continue if seen.has(rid): errs.append({"category": "dup_key", "message": "feat_id 重复: %s" % rid}) continue seen[rid] = true if String(row.get("display_name", "")) == "": errs.append({"category": "domain", "message": "%s display_name 空" % rid}) if not RARITIES.has(String(row.get("rarity", ""))): errs.append({"category": "enum", "message": "%s rarity 出域 %s" % [rid, str(RARITIES)]}) var arch := String(row.get("archetype", "")) if not ARCHETYPES.has(arch): errs.append({"category": "enum", "message": "%s archetype 出域 %s" % [rid, str(ARCHETYPES)]}) if not row.has("triggers"): errs.append({"category": "domain", "message": "%s 缺 triggers(订阅形态唯一合法行形)" % rid}) elif EffectEngine.validate_trigger_row(rid, row, row.get("triggers", []) as Array, errs): arch_mine[arch] = true for k in row.keys(): if not ROW_KEYS.has(String(k)): errs.append({"category": "zero_flat", "message": "%s 行键出白名单: %s" % [rid, String(k)]}) # 🔴 红线① 扫雷触发点铁律:**有行的流派**各 ≥1 行订阅扫雷侧事件(MINE_EVENTS 同义校验) for arch in archs_with_rows(): if not bool(arch_mine.get(arch, false)): errs.append({"category": "load_bearing", "message": "流派 %s 无扫雷结算触发点行(🔴 红线①铁律——每流派 ≥1 件订阅扫雷侧事件)" % String(arch)}) return errs func archs_with_rows() -> Array: var out := {} for row in rows: out[String(row.get("archetype", ""))] = true return out.keys() func row_by_id(feat_id: String) -> Dictionary: for row in rows: if String(row.get("feat_id", "")) == feat_id: return row return {}