卡①T4(核心数据面结构收敛批): 效果引擎四域拆分——rebuild三装载域(_load_feat_triggers/_load_attune_triggers/_push_tree_rules+单规则助手,调用序feats→treasure→tree逐字=装载声明序冻结)/_cond_ok四算子域(_cmp_ok出参聚合/_ends_with_ok/_has_ok/_counter_op_ok,unknown-op致命路径与判定语义逐字)/bucket_of elif收口if序(前缀判定序round→lvl→adv→battle逐字)/validate_trigger_row三键域(_vtr_when_keys/_vtr_do_keys+_vtr_from_refs悬空域,static同形,错误追加序逐字);四词表常量零diff,8键全清,效果面6套件全绿(138checks adventure_feats)
This commit is contained in:
1 parent
331d6b039a
commit
989c489c55
1 file changed
+166
-106
+166
-106
@@ -94,6 +94,13 @@ func _init(db_ref: ConfigDb = null) -> void:
|
||||
## 在 dispatch 的 round_start 特判内整桶 clear,adventure 桶随宿主字典引用跨战持久——无副本搬运)。
|
||||
func rebuild(feat_ids: Array, item_ids: Array, tree_rules: Array = []) -> void:
|
||||
_triggers.clear()
|
||||
_load_feat_triggers(feat_ids)
|
||||
_load_attune_triggers(item_ids)
|
||||
_push_tree_rules(tree_rules)
|
||||
|
||||
|
||||
## 特性订阅装载域(feats 表序→按持有集过滤→行内数组序——装载声明序第一段)
|
||||
func _load_feat_triggers(feat_ids: Array) -> void:
|
||||
if db != null and db.feats != null:
|
||||
for row in db.feats.rows:
|
||||
var fid := String(row.get("feat_id", ""))
|
||||
@@ -101,6 +108,10 @@ func rebuild(feat_ids: Array, item_ids: Array, tree_rules: Array = []) -> void:
|
||||
continue
|
||||
for tr in (row.get("triggers", []) as Array):
|
||||
_push_trigger("feat", fid, tr, row)
|
||||
|
||||
|
||||
## 同调秘宝订阅装载域(treasure 同调行序→按装备集过滤→行内数组序——装载声明序第二段)
|
||||
func _load_attune_triggers(item_ids: Array) -> void:
|
||||
if db != null:
|
||||
for row in db.treasure_attunement_rows():
|
||||
var iid := String(row.get("item_id", ""))
|
||||
@@ -108,44 +119,51 @@ func rebuild(feat_ids: Array, item_ids: Array, tree_rules: Array = []) -> void:
|
||||
continue
|
||||
for tr in (row.get("triggers", []) as Array):
|
||||
_push_trigger("attune", iid, tr, row)
|
||||
# 树规则合成订阅(六键按 v0.8 三组双态):posture 两键=「每关首轮窗」语义
|
||||
# 〔battle_index==1 且 round_index==1;battle_index=关卡域战斗序由 enc 携带〕;
|
||||
# sense 两组=每关限次〔level 桶计数器 lt 上限闸 + 命中即 counter_add 记账双行——同事件双行同
|
||||
# 预评估态见闸同记,序=装载序确定;寿命随 LevelRunner.level_counters 每关 new 天然按关清零〕;
|
||||
# economy 两组零订阅行——消费点=GP 掉落乘算与商品计价折价的 tree_rules 成员判定。数值全 provisional 归 M4。
|
||||
|
||||
|
||||
## 树规则合成订阅域(六键按 v0.8 三组双态——装载声明序第三段):posture 两键=「每关首轮窗」语义
|
||||
## 〔battle_index==1 且 round_index==1;battle_index=关卡域战斗序由 enc 携带〕;
|
||||
## sense 两组=每关限次〔level 桶计数器 lt 上限闸 + 命中即 counter_add 记账双行——同事件双行同
|
||||
## 预评估态见闸同记,序=装载序确定;寿命随 LevelRunner.level_counters 每关 new 天然按关清零〕;
|
||||
## economy 两组零订阅行——消费点=GP 掉落乘算与商品计价折价的 tree_rules 成员判定。数值全 provisional 归 M4。
|
||||
func _push_tree_rules(tree_rules: Array) -> void:
|
||||
for key_v in tree_rules:
|
||||
var rk := String(key_v)
|
||||
match rk:
|
||||
"posture_first_strike":
|
||||
_push_trigger("tree", rk, {"on": "round_start",
|
||||
"when": [{"fact": "battle_index", "op": "eq", "value": 1},
|
||||
{"fact": "round_index", "op": "eq", "value": 1}],
|
||||
"do": {"kind": "grant_ap", "mode": "queue", "value": 1}}, {})
|
||||
"posture_bulwark":
|
||||
_push_trigger("tree", rk, {"on": "damage_taken",
|
||||
"when": [{"fact": "battle_index", "op": "eq", "value": 1},
|
||||
{"fact": "round_index", "op": "eq", "value": 1}],
|
||||
"do": {"kind": "shield", "value": 1}}, {})
|
||||
"sense_sharp":
|
||||
# 锋=踩中危险格伤害减半·每关限次——mine_hit 挂点现成(damage_mult 收集→halve_pct,
|
||||
# 与惊巢反制同路径;伤害在结算战斗段末兑付,探索阶段零改动)
|
||||
_push_trigger("tree", rk, {"on": "mine_hit",
|
||||
"when": [{"fact": "counter", "id": "lvl_tree_sense_sharp_used", "op": "lt", "value": 2}],
|
||||
"do": {"kind": "damage_mult", "value": 50}}, {})
|
||||
_push_trigger("tree", rk, {"on": "mine_hit",
|
||||
"when": [{"fact": "counter", "id": "lvl_tree_sense_sharp_used", "op": "lt", "value": 2}],
|
||||
"do": {"kind": "counter_add", "counter_id": "lvl_tree_sense_sharp_used",
|
||||
"value": 1}}, {})
|
||||
"sense_guard":
|
||||
# 守=标错返还行动点·每关限次(契约 12 失误补偿——seal_missed 由 _judge_seal 去重闸后
|
||||
# 发射;queue=下一轮开轮兑现,末轮判出无下一轮=合法作废自动成立)
|
||||
_push_trigger("tree", rk, {"on": "seal_missed",
|
||||
"when": [{"fact": "counter", "id": "lvl_tree_sense_guard_used", "op": "lt", "value": 2}],
|
||||
"do": {"kind": "grant_ap", "mode": "queue", "value": 1}}, {})
|
||||
_push_trigger("tree", rk, {"on": "seal_missed",
|
||||
"when": [{"fact": "counter", "id": "lvl_tree_sense_guard_used", "op": "lt", "value": 2}],
|
||||
"do": {"kind": "counter_add", "counter_id": "lvl_tree_sense_guard_used",
|
||||
"value": 1}}, {})
|
||||
_push_tree_rule(String(key_v))
|
||||
|
||||
|
||||
## 单树规则合成行 push(六键 match 分派——词表封闭,未知键零订阅零扰动)
|
||||
func _push_tree_rule(rk: String) -> void:
|
||||
match rk:
|
||||
"posture_first_strike":
|
||||
_push_trigger("tree", rk, {"on": "round_start",
|
||||
"when": [{"fact": "battle_index", "op": "eq", "value": 1},
|
||||
{"fact": "round_index", "op": "eq", "value": 1}],
|
||||
"do": {"kind": "grant_ap", "mode": "queue", "value": 1}}, {})
|
||||
"posture_bulwark":
|
||||
_push_trigger("tree", rk, {"on": "damage_taken",
|
||||
"when": [{"fact": "battle_index", "op": "eq", "value": 1},
|
||||
{"fact": "round_index", "op": "eq", "value": 1}],
|
||||
"do": {"kind": "shield", "value": 1}}, {})
|
||||
"sense_sharp":
|
||||
# 锋=踩中危险格伤害减半·每关限次——mine_hit 挂点现成(damage_mult 收集→halve_pct,
|
||||
# 与惊巢反制同路径;伤害在结算战斗段末兑付,探索阶段零改动)
|
||||
_push_trigger("tree", rk, {"on": "mine_hit",
|
||||
"when": [{"fact": "counter", "id": "lvl_tree_sense_sharp_used", "op": "lt", "value": 2}],
|
||||
"do": {"kind": "damage_mult", "value": 50}}, {})
|
||||
_push_trigger("tree", rk, {"on": "mine_hit",
|
||||
"when": [{"fact": "counter", "id": "lvl_tree_sense_sharp_used", "op": "lt", "value": 2}],
|
||||
"do": {"kind": "counter_add", "counter_id": "lvl_tree_sense_sharp_used",
|
||||
"value": 1}}, {})
|
||||
"sense_guard":
|
||||
# 守=标错返还行动点·每关限次(契约 12 失误补偿——seal_missed 由 _judge_seal 去重闸后
|
||||
# 发射;queue=下一轮开轮兑现,末轮判出无下一轮=合法作废自动成立)
|
||||
_push_trigger("tree", rk, {"on": "seal_missed",
|
||||
"when": [{"fact": "counter", "id": "lvl_tree_sense_guard_used", "op": "lt", "value": 2}],
|
||||
"do": {"kind": "grant_ap", "mode": "queue", "value": 1}}, {})
|
||||
_push_trigger("tree", rk, {"on": "seal_missed",
|
||||
"when": [{"fact": "counter", "id": "lvl_tree_sense_guard_used", "op": "lt", "value": 2}],
|
||||
"do": {"kind": "counter_add", "counter_id": "lvl_tree_sense_guard_used",
|
||||
"value": 1}}, {})
|
||||
|
||||
|
||||
func _push_trigger(source: String, id: String, tr: Dictionary, row: Dictionary) -> void:
|
||||
@@ -203,13 +221,14 @@ func dispatch(ctx: EffectContext, event: String, payload: Dictionary, facts: Cal
|
||||
return hits
|
||||
|
||||
|
||||
## 计数器归属桶解析(前缀规则唯一出处——round_/lvl_/adv_ 显式桶,其余落 battle 缺省桶)。
|
||||
## 计数器归属桶解析(前缀规则唯一出处——round_/lvl_/adv_ 显式桶,其余落 battle 缺省桶;
|
||||
## 前缀判定序 round→lvl→adv→battle 缺省逐字)
|
||||
static func bucket_of(ctx: EffectContext, counter_id: String) -> Dictionary[Variant, Variant]:
|
||||
if counter_id.begins_with("round_"):
|
||||
return ctx.round_bucket
|
||||
elif counter_id.begins_with("lvl_"):
|
||||
if counter_id.begins_with("lvl_"):
|
||||
return ctx.level_bucket
|
||||
elif counter_id.begins_with("adv_"):
|
||||
if counter_id.begins_with("adv_"):
|
||||
return ctx.adventure_bucket
|
||||
return ctx.battle_bucket
|
||||
|
||||
@@ -262,41 +281,68 @@ func _cond_ok(ctx: EffectContext, c: Dictionary, payload: Dictionary, facts: Cal
|
||||
var val = c.get("value", null)
|
||||
var actual = _fact_value(ctx, fact, c, payload, facts)
|
||||
match op:
|
||||
"eq":
|
||||
return str(actual) == str(val)
|
||||
"neq":
|
||||
return str(actual) != str(val)
|
||||
"gt":
|
||||
return int(actual) > int(val)
|
||||
"gte":
|
||||
return int(actual) >= int(val)
|
||||
"lt":
|
||||
return int(actual) < int(val)
|
||||
"lte":
|
||||
return int(actual) <= int(val)
|
||||
"eq", "neq", "gt", "gte", "lt", "lte":
|
||||
return _cmp_ok(op, actual, val)
|
||||
"ends_with":
|
||||
if val is Array:
|
||||
for v in (val as Array):
|
||||
if String(actual).ends_with(String(v)):
|
||||
return true
|
||||
return false
|
||||
return String(actual).ends_with(String(val))
|
||||
return _ends_with_ok(actual, val)
|
||||
"has":
|
||||
# 在场判定(fact 查询面落法——白名单覆盖):value 缺省=非空判定
|
||||
# (terrain_kind fact:伤害型变异集非空=挖开伤害型地形格/邻格有伤害型地形/地形伤种类在场);
|
||||
# value 给定=数组包含判定(保留泛用面)。
|
||||
if c.has("value"):
|
||||
if actual is Array:
|
||||
return (actual as Array).has(val)
|
||||
return false
|
||||
if actual is Array:
|
||||
return not (actual as Array).is_empty()
|
||||
return actual != null and String(actual) != "" # null 安全(敌技伤害载荷无 terrain_kind 时事实面回落 null,判「不在场」而非抛错)
|
||||
return _has_ok(c, actual)
|
||||
"mod_zero", "mod_eq", "advantageous", "gte_ref", "lt_ref":
|
||||
return _counter_op_ok(ctx, c, op, actual)
|
||||
assert(false, "[效果引擎] when 算子出域: %s" % op)
|
||||
return false
|
||||
|
||||
|
||||
## 比较算子域(eq/neq/gt/gte/lt/lte 六比较——str 逐字与 int 投影语义逐字)
|
||||
func _cmp_ok(op: String, actual: Variant, val: Variant) -> bool:
|
||||
var out := false
|
||||
match op:
|
||||
"eq":
|
||||
out = str(actual) == str(val)
|
||||
"neq":
|
||||
out = str(actual) != str(val)
|
||||
"gt":
|
||||
out = int(actual) > int(val)
|
||||
"gte":
|
||||
out = int(actual) >= int(val)
|
||||
"lt":
|
||||
out = int(actual) < int(val)
|
||||
"lte":
|
||||
out = int(actual) <= int(val)
|
||||
return out
|
||||
|
||||
|
||||
## 后缀匹配域(ends_with——值数组任一命中即真)
|
||||
func _ends_with_ok(actual: Variant, val: Variant) -> bool:
|
||||
if val is Array:
|
||||
for v in (val as Array):
|
||||
if String(actual).ends_with(String(v)):
|
||||
return true
|
||||
return false
|
||||
return String(actual).ends_with(String(val))
|
||||
|
||||
|
||||
## 在场判定域(has——fact 查询面落法,白名单覆盖):value 缺省=非空判定
|
||||
## (terrain_kind fact:伤害型变异集非空=挖开伤害型地形格/邻格有伤害型地形/地形伤种类在场);
|
||||
## value 给定=数组包含判定(保留泛用面)
|
||||
func _has_ok(c: Dictionary, actual: Variant) -> bool:
|
||||
if c.has("value"):
|
||||
if actual is Array:
|
||||
return (actual as Array).has(c.get("value"))
|
||||
return false
|
||||
if actual is Array:
|
||||
return not (actual as Array).is_empty()
|
||||
return actual != null and String(actual) != "" # null 安全(敌技伤害载荷无 terrain_kind 时事实面回落 null,判「不在场」而非抛错)
|
||||
|
||||
|
||||
## 计数器与矩阵算子域(mod_zero/mod_eq 取模、advantageous 克制矩阵、gte_ref/lt_ref 计数器比较——读经 ctx)
|
||||
func _counter_op_ok(ctx: EffectContext, c: Dictionary, op: String, actual: Variant) -> bool:
|
||||
match op:
|
||||
"mod_zero":
|
||||
var m := int(val)
|
||||
var m := int(c.get("value", null))
|
||||
return m > 0 and int(actual) % m == 0
|
||||
"mod_eq":
|
||||
var me_m := int(val)
|
||||
var me_m := int(c.get("value", null))
|
||||
return me_m > 0 and int(actual) % me_m == int(c.get("ref", 0))
|
||||
"advantageous":
|
||||
# 克制矩阵正面判定(matchup = "{attack_type}_vs_{armor}"——矩阵值 > 0 = 克制成立)
|
||||
@@ -305,7 +351,6 @@ func _cond_ok(ctx: EffectContext, c: Dictionary, payload: Dictionary, facts: Cal
|
||||
return int(actual) >= counter(ctx, String(c.get("ref", "")))
|
||||
"lt_ref":
|
||||
return int(actual) < counter(ctx, String(c.get("ref", "")))
|
||||
assert(false, "[效果引擎] when 算子出域: %s" % op)
|
||||
return false
|
||||
|
||||
|
||||
@@ -350,44 +395,59 @@ static func validate_trigger_row(rid: String, row: Dictionary, triggers: Array,
|
||||
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[Variant, Variant] = 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 出域(事实词汇封闭 %d 项): %s" % [rid, FACTS.size(), 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[Variant, Variant] = 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]})
|
||||
# 计数器前缀归属合法性(.tres 行路径——写错前缀加载致命;判据单点 counter_id_legal,与 _push_trigger 同源)
|
||||
if do_d.has("counter_id"):
|
||||
var cid := String(do_d.counter_id)
|
||||
if not counter_id_legal(cid):
|
||||
errs.append({"category": "enum", "message": "%s counter_id 前缀非法(meta_ 出域/引擎不接存档级): %s" % [rid, cid]})
|
||||
# value_from/delta_from/mult_from/cap_from 引用面:行字段存在性(悬空=加载致命)——
|
||||
# do 与 when 两侧同面(when value_from=dawn_order effective_rounds 先例)
|
||||
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]})
|
||||
for c_v in (tr.get("when", []) as Array):
|
||||
var c_w: Dictionary[Variant, Variant] = c_v as Dictionary
|
||||
if c_w.has("value_from"):
|
||||
var wfld := String(c_w.get("value_from", ""))
|
||||
if wfld != "" and not row.has(wfld):
|
||||
errs.append({"category": "dangling", "message": "%s when.value_from 悬空(行无字段 %s)" % [rid, wfld]})
|
||||
_vtr_when_keys(rid, tr, errs)
|
||||
_vtr_do_keys(rid, tr, row, errs)
|
||||
return mine_covered
|
||||
|
||||
|
||||
## when 键域校验:键白名单/fact 词表/算子词表(追加序承原位——when 键→fact→op)
|
||||
static func _vtr_when_keys(rid: String, tr: Dictionary, errs: Array) -> void:
|
||||
for c_v in (tr.get("when", []) as Array):
|
||||
var c: Dictionary[Variant, Variant] = 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 出域(事实词汇封闭 %d 项): %s" % [rid, FACTS.size(), fact]})
|
||||
if not OPS.has(String(c.get("op", "eq"))):
|
||||
errs.append({"category": "enum", "message": "%s when 算子出域: %s" % [rid, String(c.get("op", ""))]})
|
||||
|
||||
|
||||
## do 键域校验:键白名单(零裸 flat 护栏)/效果类型闭集/计数器前缀合法性+value_from 引用悬空域
|
||||
static func _vtr_do_keys(rid: String, tr: Dictionary, row: Dictionary, errs: Array) -> void:
|
||||
var do_d: Dictionary[Variant, Variant] = 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]})
|
||||
# 计数器前缀归属合法性(.tres 行路径——写错前缀加载致命;判据单点 counter_id_legal,与 _push_trigger 同源)
|
||||
if do_d.has("counter_id"):
|
||||
var cid := String(do_d.counter_id)
|
||||
if not counter_id_legal(cid):
|
||||
errs.append({"category": "enum", "message": "%s counter_id 前缀非法(meta_ 出域/引擎不接存档级): %s" % [rid, cid]})
|
||||
_vtr_from_refs(rid, tr, row, errs)
|
||||
|
||||
|
||||
## value_from/delta_from/mult_from/cap_from 引用面:行字段存在性(悬空=加载致命)——
|
||||
## do 与 when 两侧同面(when value_from=dawn_order effective_rounds 先例)
|
||||
static func _vtr_from_refs(rid: String, tr: Dictionary, row: Dictionary, errs: Array) -> void:
|
||||
var do_d: Dictionary[Variant, Variant] = tr.get("do", {}) as Dictionary
|
||||
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]})
|
||||
for c_v in (tr.get("when", []) as Array):
|
||||
var c_w: Dictionary[Variant, Variant] = c_v as Dictionary
|
||||
if c_w.has("value_from"):
|
||||
var wfld := String(c_w.get("value_from", ""))
|
||||
if wfld != "" and not row.has(wfld):
|
||||
errs.append({"category": "dangling", "message": "%s when.value_from 悬空(行无字段 %s)" % [rid, wfld]})
|
||||
|
||||
|
||||
## 组合规则(需求卡片 §3.4 六族——效果类型的必填属性,发射点施加面引用)
|
||||
|
||||
## 加法族(数值相加,可交换):add_ticket_rider、attack_bonus、grant_material、grant_ap(非 transfer)、
|
||||
|
||||
Reference in new issue
Block a user