接手前任中断的 T3 半成品(脏文件三件:battle_orchestrator/effects engine/feats.tres),方向核实无误后续做收口; 承接修正四处随本提交留痕:①perfect_defense 的 when 用了 fact 封闭 9 项外的 flags_hit_all(装载校验必红)—— 改 flags_count gte 1 保守判定,全中闸=flag_settle 发射点施加面承载(载荷字段仅供观测);②has 算子语义与行 不匹配(数组包含对 String 恒假)——落非空在场判定(value 缺省)+数组包含(value 给定),查询面落法=代拍板 白名单;③前任漏写 _harmful_adjacent 助手(flag_hit 发射点调用必炸);④counter_add set 键语义 bool() 吞 0 (清零行 set:0 被当 false 走加零通道)——改 has(set) 置值模式,四处施加点同修。 本提交主干(专长族全量迁移——任务书 §六 T3): - damage_controller:feat_flags 旗面整体退役,五事件施加面接线——attack_commit 命中随单据 context 携带 (发射点=开单入口,任务书 §3.1 定稿位;主角攻击单恒段内首单,开单现场=结账现场),rider/改写/加值/ 段数/状态五族按迁移前算序施加(重锤两拍/专注/spike 恒全额/猎弱移档/魔网湛蓝猎手克制直调/整备每层 +1/厚积满层倍乘/奥术+猎巢+执拗 rider 合计后档位暴击);armor_roll 免掷恒折扣、clamp_check 双面 (hero+board_typed)delta 窗口、kill 溢出弹射(landed×value%)、damage_taken shield 加法族合计。 _feat_clamp_bonus/13 处旗消费点拆除。 - battle_orchestrator:_combat_segment 换代(dig_streak/charge_layers 注伤害控制器运行态;连珠矢段数 施加位紧随主角攻击单开立=迁移前开单位,flush 兑现序逐位一致);round_start 发射位前移至行动经济轮 切换前(树规则 grant_ap queue 当轮入队当轮兑现——先手压制首轮语义锚);深挖快照滚动拆除(计数器 reset_at 声明承载);熔火/连击旧计数变量退役。 - action_economy:feat_ap_carry/feat_dig_extra/deep_paid_count 旧注入旗拆除;dig_paid 施加面落地 (counter_spend 对价:AP 富余付全价积计数、不足 fallback 只付基础 1——2026-10-04 降级口径逐位保留)。 - feat_table schema:HOOKS 23 挂点枚举/MINE_HOOKS/EFFECT_KEYS/hook+effects 双形态校验全删——triggers 订阅形态唯一合法行形(行键白名单收口 feat_id/display_name/rarity/archetype/triggers/desc/note)。 - feats_engine:hooks_for 挂点投影退役(订阅装载序=feats 表序,由效果引擎 rebuild 承载)。 - battle_narrator:专长卡片文案表值化(summaries 硬编码映射拆除,读行 desc——27 件措辞逐字迁移)。 - smoke 断言面随迁(任务书 v1.1 补列项):构造表 5 行换代 triggers 形态;挂点投影断言换代订阅装载面; ④-⑧ 求值断言(_feat_flags_for 直呼+旗读数)全量改写为 rebuild+dispatch 命中面(27 件逐事件覆盖); 深挖钻头付费开掘回归闸改 counter_spend 计数器面;特性卡 desc 直读断言新增。 映射表对拍注记(行为等价优先,.tres 尾注同步留痕):猎巢人/矿工的执拗映射表标 modify_ticket/attack_bonus, 现行为必中附加通道(hero_rider 后置于乘区与下限)——落 add_ticket_rider(per 取数载荷);整备军备现行为 双效果(轮末转蓄力+每层首段攻 +1)——两行订阅;深挖钻头 per-round 计数器对(paid/given)复刻旧 v2 跨轮不对称语义(given 不随轮重置)。 验证:冒烟 800 项 0 失败(三闸过)· 单元 17 套全绿 · S1 魔法流对拍预检=MC formed/off 两态与 T0 pre 锚 (83000 种子段)同种子逐位一致(2×5 局,三档只测不判)——14 件迁移行实战斗承载零分岔。 设计权威:design/research/研究-内容数据驱动扩展架构-2026-10-06.md(案乙)。 任务书:design/research/任务书-内容数据驱动扩展批-2026-10-06.md §六 T3、§五映射表、§七契约 2/4。
91 lines
5.4 KiB
GDScript
91 lines
5.4 KiB
GDScript
# 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 {}
|