词汇表落码:feats/treasure 两表 trigger 订阅形态 schema 换代+护栏迁移(T2——内容数据驱动扩展批)
schema 校验换代,数据行迁移前共存过渡(旧 hook/effect_kinds 校验保留,行为零变——冒烟 783 项 0 失败):
FeatTable:
- 行字段换代目标 hook/effects → triggers:[{on,when,do}](订阅哪个事件/什么条件/什么效果)
- triggers 校验收口 EffectEngine.validate_trigger_row 静态方法(单一事实源——事件/效果/fact/算子
四词表全引用 EffectEngine 闭集常量,禁本表复抄)
- 行键白名单扩 triggers/desc(文案表值化预留)
- 悬空引用校验:do.value_from/delta_from/mult_from/cap_from 引用的行字段不存在=加载致命
- 🔴 流派扫雷触发铁律新形态:每流派 ≥1 行订阅扫雷侧事件(MINE_EVENTS=dig_reveal/dig_paid/
flag_hit/mine_hit/flag_settle/round_end/reward_roll)或旧形态 hook∈MINE_HOOKS——流派级聚合判定
- triggers 与 hook 禁并存(换代单形态);缺两者=行错误
TreasureItemTable:
- 行键白名单扩 triggers/desc;passive 行 triggers 与 effect_kinds 禁并存
- 主动件 kind 词族换代挂账:新词 reveal_tiles/preview/grant_ap/remove_mines/refresh_pick
(效果引擎 ACTIVE_KINDS 同名闭集)入 EFFECT_KINDS 与旧词共存至 T4 迁移完成
EffectEngine 补 validate_trigger_row 静态校验面(schema 共用)。
fact 条件词汇 9 项封闭落码核对:迁移设计全部现状条件可装入 9 项(matchup/is_first_dig_of_battle/
terrain_kind/target_armor_class/flags_count/charge_layers/nest_count/round_index/counter)——
未触发闭集缺口停机点。
This commit is contained in:
1 parent
7d157b3c4c
commit
225765f3f7
3 files changed
+96
-21
No files matched your search
@@ -245,7 +245,49 @@ func _counter_delta_of(matchup: String) -> int:
|
||||
return int(row.get(String(parts[1]), 0))
|
||||
|
||||
|
||||
# ---- 组合规则(任务书 §3.4 六族——效果类型的必填属性,发射点施加面引用) ----
|
||||
## ---- 加载期校验(schema 侧共用——单一事实源;悬空引用/词表出域=致命) ----
|
||||
|
||||
## trigger 行校验:返回该行是否含扫雷侧事件订阅(流派铁律聚合面)。
|
||||
## row 用于 value_from 类引用的字段存在性判定(悬空=加载致命)。
|
||||
static func validate_trigger_row(rid: String, row: Dictionary, triggers: Array, errs: Array) -> bool:
|
||||
var mine_covered := false
|
||||
for tr_v in triggers:
|
||||
var tr: Dictionary = tr_v as Dictionary
|
||||
for k in tr.keys():
|
||||
if not ["on", "when", "do"].has(String(k)):
|
||||
errs.append({"category": "zero_flat", "message": "%s trigger 键出白名单: %s" % [rid, String(k)]})
|
||||
var on := String(tr.get("on", ""))
|
||||
if not EVENTS.has(on):
|
||||
errs.append({"category": "enum", "message": "%s 订阅事件出域(事件词汇封闭): %s" % [rid, on]})
|
||||
elif MINE_EVENTS.has(on):
|
||||
mine_covered = true
|
||||
for c_v in (tr.get("when", []) as Array):
|
||||
var c: Dictionary = c_v as Dictionary
|
||||
for k in c.keys():
|
||||
if not WHEN_KEYS.has(String(k)):
|
||||
errs.append({"category": "zero_flat", "message": "%s when 键出白名单: %s" % [rid, String(k)]})
|
||||
var fact := String(c.get("fact", ""))
|
||||
if not FACTS.has(fact):
|
||||
errs.append({"category": "enum", "message": "%s fact 出域(事实词汇封闭 9 项): %s" % [rid, fact]})
|
||||
if not OPS.has(String(c.get("op", "eq"))):
|
||||
errs.append({"category": "enum", "message": "%s when 算子出域: %s" % [rid, String(c.get("op", ""))]})
|
||||
var do_d: Dictionary = tr.get("do", {}) as Dictionary
|
||||
for k in do_d.keys():
|
||||
if not DO_KEYS.has(String(k)):
|
||||
errs.append({"category": "zero_flat", "message": "%s do 键出白名单: %s(机制轴禁无条件属性加项)" % [rid, String(k)]})
|
||||
var kind := String(do_d.get("kind", ""))
|
||||
if not EFFECT_KINDS.has(kind):
|
||||
errs.append({"category": "enum", "message": "%s 效果类型出域(解释器闭集): %s" % [rid, kind]})
|
||||
# value_from/delta_from/mult_from/cap_from 引用面:行字段存在性(悬空=加载致命)
|
||||
for vf_k in ["value_from", "delta_from", "mult_from", "cap_from"]:
|
||||
if do_d.has(vf_k):
|
||||
var fld := String(do_d.get(vf_k, ""))
|
||||
if fld != "" and not row.has(fld):
|
||||
errs.append({"category": "dangling", "message": "%s do.%s 悬空(行无字段 %s)" % [rid, vf_k, fld]})
|
||||
return mine_covered
|
||||
|
||||
|
||||
## 组合规则(任务书 §3.4 六族——效果类型的必填属性,发射点施加面引用)
|
||||
|
||||
## 加法族(数值相加,可交换):add_ticket_rider、attack_bonus、grant_material、grant_ap(非 transfer)、
|
||||
## counter_add、shield——发射点逐条累加收集器。
|
||||
|
||||
@@ -33,6 +33,8 @@ const ARCHETYPES := ["magic", "pierce", "normal", "dig", "flag", "charge", "devo
|
||||
const RARITIES := ["common", "rare", "rarest"]
|
||||
|
||||
## 挂点枚举(结算段槽——首批 23 点位;每 hook 恰一流派域消费,T2-T6 接线)
|
||||
## 内容数据驱动扩展批 T2 挂账:hook 词族随 T3 专长迁移退役(triggers 事件订阅形态取代——
|
||||
## 旧字段校验保留共存至迁移完成,过渡期两形态同行校验)。
|
||||
const HOOKS := [
|
||||
# 魔法流
|
||||
"hero_attack_rider", # 普攻命中后追加必中魔法伤(奥术余烬/魔能共鸣)
|
||||
@@ -78,12 +80,23 @@ const EFFECT_KEYS := ["value", "value2", "tier_value", "per_stack", "cap", "ap_c
|
||||
"trade_atk", "trade_hit", "shield_per_layer", "spike_mult", "layers_to_shield",
|
||||
"neutralize_range", "counter_damage", "resource_kind", "rider_kind", "note"]
|
||||
|
||||
## ---- 内容数据驱动扩展批 T2 新形态词汇(triggers 事件订阅行)----
|
||||
## 行字段换代目标:hook/effects → triggers: [{on, when?, do}]——订阅哪个事件/什么条件/什么效果。
|
||||
## 事件/效果/fact/算子四词表全部引用 EffectEngine 闭集常量(单一事实源,禁本表复抄)。
|
||||
const TRIGGER_KEYS := ["on", "when", "do"]
|
||||
|
||||
|
||||
func _validate_triggers(rid: String, row: Dictionary, triggers: Array, errs: Array) -> bool:
|
||||
return EffectEngine.validate_trigger_row(rid, row, triggers, errs)
|
||||
|
||||
|
||||
func validate() -> Array:
|
||||
var errs: Array = []
|
||||
if rows.is_empty():
|
||||
return errs # 空表合法态(T1 基建先行——T2 起逐流派填行)
|
||||
var seen := {}
|
||||
# 流派扫雷覆盖聚合(🔴 红线①铁律——两形态共存判定:triggers 行按扫雷侧事件、hook 行按 MINE_HOOKS)
|
||||
var arch_mine := {} # archetype → bool
|
||||
for row in rows:
|
||||
var rid: String = row.get("feat_id", "")
|
||||
if rid == "":
|
||||
@@ -100,32 +113,43 @@ func validate() -> Array:
|
||||
var arch := String(row.get("archetype", ""))
|
||||
if not ARCHETYPES.has(arch):
|
||||
errs.append({"category": "enum", "message": "%s archetype 出域 %s" % [rid, str(ARCHETYPES)]})
|
||||
var hook := String(row.get("hook", ""))
|
||||
if not HOOKS.has(hook):
|
||||
errs.append({"category": "enum", "message": "%s hook 出域(挂点枚举封闭): %s" % [rid, hook]})
|
||||
var has_triggers: bool = row.has("triggers")
|
||||
var has_hook: bool = row.has("hook")
|
||||
if has_triggers:
|
||||
if String(row.get("hook", "")) != "":
|
||||
errs.append({"category": "domain", "message": "%s triggers 与 hook 并存(换代单形态——迁移期禁双挂)" % rid})
|
||||
if _validate_triggers(rid, row, row.get("triggers", []) as Array, errs):
|
||||
arch_mine[arch] = true
|
||||
elif has_hook:
|
||||
var hook := String(row.get("hook", ""))
|
||||
if not HOOKS.has(hook):
|
||||
errs.append({"category": "enum", "message": "%s hook 出域(挂点枚举封闭): %s" % [rid, hook]})
|
||||
if MINE_HOOKS.has(hook):
|
||||
arch_mine[arch] = true
|
||||
else:
|
||||
errs.append({"category": "domain", "message": "%s 缺 triggers/hook(换代后行必须声明订阅)" % rid})
|
||||
for k in row.keys():
|
||||
if not ["feat_id", "display_name", "rarity", "archetype", "hook", "effects", "note"].has(String(k)):
|
||||
if not ["feat_id", "display_name", "rarity", "archetype", "hook", "effects", "triggers", "desc", "note"].has(String(k)):
|
||||
errs.append({"category": "zero_flat", "message": "%s 行键出白名单: %s" % [rid, String(k)]})
|
||||
var fx: Dictionary = row.get("effects", {}) as Dictionary
|
||||
for ek in fx.keys():
|
||||
if not EFFECT_KEYS.has(String(ek)):
|
||||
errs.append({"category": "zero_flat", "message": "%s effects 键出白名单: %s(机制轴禁无条件属性加项)" % [rid, String(ek)]})
|
||||
# 🔴 红线① 扫雷触发点铁律:**有行的流派**各 ≥1 行 hook ∈ MINE_HOOKS(部分填充合法——T2-T6
|
||||
# 逐流派渐进;七流派全量覆盖完成度由批次一出口断言承载,加载闸不卡渐进填行)
|
||||
var archs_with_rows := {}
|
||||
for row in rows:
|
||||
archs_with_rows[String(row.get("archetype", ""))] = true
|
||||
for arch in archs_with_rows.keys():
|
||||
var covered := false
|
||||
for row in rows:
|
||||
if String(row.get("archetype", "")) == String(arch) and MINE_HOOKS.has(String(row.get("hook", ""))):
|
||||
covered = true
|
||||
break
|
||||
if not covered:
|
||||
# 🔴 红线① 扫雷触发点铁律:**有行的流派**各 ≥1 行订阅扫雷侧事件(triggers 新形态)或
|
||||
# hook ∈ MINE_HOOKS(旧形态过渡)
|
||||
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:
|
||||
|
||||
@@ -38,19 +38,23 @@ const DIMENSIONS := ["info", "risk", "action", "plan", "counter"]
|
||||
# 同调批扩 enum(迭代 11 第①批 T1)——新增九 kind 全部条件触发/机制修正类;mine_reveal/ap_grant 语义不变。
|
||||
# cell_removal = 爆破工兵包中立移除格(T7 原位换装时启用——T6 影响评估前置);mine_hit_halve 系固定
|
||||
# 「减半」语义不消费 magnitude(反弹 N 由 reflect_damage 行 magnitude 承载)。
|
||||
# 内容数据驱动扩展批 T2 挂账:主动件 kind 词族换代(reveal_tiles/preview/grant_ap/remove_mines/
|
||||
# refresh_pick——效果引擎 ACTIVE_KINDS 同名闭集),被动件 effect_kinds 词族随 T4 秘宝迁移退役
|
||||
# (passive 行改 triggers 事件订阅形态);旧词保留共存至迁移完成。
|
||||
const EFFECT_KINDS := ["mine_reveal", "reward_preview", "ap_grant", "venom_rider", "flag_burst",
|
||||
"mine_hit_halve", "reflect_damage", "ap_rounds_front", "ap_charge_safe", "cell_removal",
|
||||
"reward_weight_bias", "bonus_refresh"]
|
||||
"reward_weight_bias", "bonus_refresh",
|
||||
"reveal_tiles", "preview", "grant_ap", "remove_mines", "refresh_pick"]
|
||||
const TARGETS := ["none", "area_3x3", "board_wide"]
|
||||
const USE_PHASES := ["active_dig"]
|
||||
const FORMS := ["", "passive", "active_charged"]
|
||||
# magnitude 消费面(≥1 校验):ap_grant 与同调 N 值 kind;其余 kind 活行 magnitude 恒 0
|
||||
# magnitude 消费面(≥1 校验):grant_ap 与同调 N 值 kind;其余 kind 活行 magnitude 恒 0
|
||||
const MAGNITUDE_KINDS := ["ap_grant", "venom_rider", "flag_burst", "reflect_damage", "ap_rounds_front",
|
||||
"ap_charge_safe", "reward_weight_bias", "bonus_refresh"]
|
||||
"ap_charge_safe", "reward_weight_bias", "bonus_refresh", "grant_ap"]
|
||||
# 🔴 零裸 flat 结构护栏:行键白名单封闭(键出域=加载致命)——机制轴禁无条件属性加项的表结构承载
|
||||
const KEY_WHITELIST := ["item_id", "display_name", "dimension_tags", "effect_kinds", "target",
|
||||
"magnitude", "use_phase", "retired", "deferred", "form", "charges_per_adventure", "slot_cost",
|
||||
"unlock_requires", "effective_rounds", "charge_n"]
|
||||
"unlock_requires", "effective_rounds", "charge_n", "triggers", "desc"]
|
||||
|
||||
|
||||
func validate() -> Array:
|
||||
@@ -90,6 +94,11 @@ func validate() -> Array:
|
||||
for k in row.keys():
|
||||
if not KEY_WHITELIST.has(String(k)):
|
||||
errs.append({"category": "zero_flat", "message": "%s 行键出白名单: %s(KEY_WHITELIST 外键禁入)" % [iid, String(k)]})
|
||||
# triggers 事件订阅行(内容数据驱动扩展批 T2——被动件换代形态;与 effect_kinds 互斥共存校验)
|
||||
if row.has("triggers"):
|
||||
if (row.get("effect_kinds", []) as Array).size() > 0 and not bool(row.get("retired", false)):
|
||||
errs.append({"category": "domain", "message": "%s triggers 与 effect_kinds 并存(换代单形态——被动件迁移期禁双挂)" % iid})
|
||||
EffectEngine.validate_trigger_row(iid, row, row.get("triggers", []) as Array, errs)
|
||||
var form: String = String(row.get("form", ""))
|
||||
if not FORMS.has(form):
|
||||
errs.append({"category": "enum", "message": "%s form 出域 %s: %s" % [iid, str(FORMS), form]})
|
||||
|
||||
Reference in new issue
Block a user