T1(迭代22秘宝批): 新目录12行全量换代+schema扩签——treasure_items.tres 旧12行删除新12行落表(晨操令/阔视野带/试炼镐/刷新练习/储备罐/巢穴预告/线香/双管装填/远程镐/刷新执照/天眼/信标网络; 三档7/3/2; 契约8逐件解锁分配=钥石8+条件4); schema扩 tier/charge_reset/unlock_keystone_cost 三键+TIERS/CHARGE_RESETS 词表+TARGETS扩cell+参数面kind六型+REVEAL_KINDS护栏扩面+charges=0积点制合法态+解锁互斥校验+UNLOCK_COUNTER_KEYS换代(adventure_cleared对齐C6通关口径/vision_used新增); 引擎EVENTS+board_installed/ACTIVE_KINDS+safe_dig/EFFECT_KINDS+mine_count_preview; V13旧断言摘除换代(fog_lantern_wiring_test全文件退役+run_all注册摘除/violation护栏主语换sky_eye/feat_vouchers电池主语换incense_stick/smoke提灯段换V1V2新目录断言段+装配充能刷新段换主语)。冒烟887/0+单元21套+探针全绿〔秘宝批 V1/V2/V12/V13/V14部分〕
This commit is contained in:
1 parent
5a2ab8cdde
commit
48b0696158
9 files changed
+331
-263
No files matched your search
@@ -19,10 +19,12 @@ extends RefCounted
|
||||
## 事件词汇(迭代 20 专长实装批 T1 扩签——16→18:+dig_stop 停手挂点〔弃图兑换〕
|
||||
## +battle_won 战斗胜利〔战地包扎〕;迭代 21 天赋树批 T3 扩签 18→19:+flag_missed 标错判定
|
||||
## 〔危险直觉·守挂点——_judge_flag 去重闸后发射,契约 12 触发主语=当回合标错动作;
|
||||
## 命名避让 _emit_row 在册 source_class 名 flag_miss〕;原发射点不动)
|
||||
## 命名避让 _emit_row 在册 source_class 名 flag_miss〕;迭代 22 秘宝实装批 T3 扩签 19→20:
|
||||
## +board_installed 装板完成〔巢穴预告——每板恰一次,战斗板生成/重建发射点〕;原发射点不动)
|
||||
const EVENTS := ["dig_reveal", "dig_paid", "flag_hit", "mine_hit", "attack_commit", "clamp_check",
|
||||
"armor_roll", "kill", "damage_taken", "enemy_hp_threshold", "round_start", "flag_settle",
|
||||
"round_end", "reward_roll", "treasure_used", "charge_full", "dig_stop", "battle_won", "flag_missed"]
|
||||
"round_end", "reward_roll", "treasure_used", "charge_full", "dig_stop", "battle_won", "flag_missed",
|
||||
"board_installed"]
|
||||
|
||||
## 扫雷侧事件集(🔴 流派扫雷触发铁律新形态:每流派 ≥1 行订阅本集事件——schema 加载校验。
|
||||
## 原 MINE_HOOKS 的同义迁移:挖掘/标旗/轮末结算面事件)
|
||||
@@ -43,7 +45,11 @@ const EFFECT_KINDS := ["add_ticket_rider", "modify_ticket", "damage_mult", "open
|
||||
# preview_area=资源类型预告〔示警烟火——3×3 邻域资源类型,不揭安危位置〕;
|
||||
# target_attack_bonus=单位标记加伤〔处刑台——敌血量阈值挂单位字典,主角攻击面通用消费〕
|
||||
"heal", "ac_bonus", "damage_reduce", "bonus_delta", "blast_scaled", "preview_area",
|
||||
"target_attack_bonus"]
|
||||
"target_attack_bonus",
|
||||
# 迭代 22 秘宝实装批 T3 扩签一型:mine_count_preview=危险格数量预告(巢穴预告——board_installed
|
||||
# 订阅 do;只报数量不标位置、不碰危险格分布=棋盘事实不可变契约;参数面常时 kind 不入本词表——
|
||||
# 它们无订阅行,schema 行内 effect_kinds 校验走 treasure_item_table 自有词表)
|
||||
"mine_count_preview"]
|
||||
# 注:rewrite_board 已除名(迭代 20 T9——净化工兵随老 27 件退役,V14 连带清理;
|
||||
# 编排器消费分支 T1 先行摘除)
|
||||
|
||||
@@ -80,7 +86,9 @@ const DO_KEYS := ["kind", "value", "value_from", "delta", "delta_from", "mult",
|
||||
"value_event", "value_counter", "domain", "axis"]
|
||||
|
||||
## 主动件分发通道(不经事件订阅——刷新/显影/移除是玩家主动动作;use_treasure 按 kind 分发)
|
||||
const ACTIVE_KINDS := ["reveal_tiles", "preview", "grant_ap", "remove_mines", "refresh_pick"]
|
||||
## 迭代 22 秘宝实装批 T3 扩签:+safe_dig 安全格直开(天眼——3×3 内安全格按普通挖格规则全额兑付
|
||||
## 含连锁展开与格面资源,危险格仅真视显示不移除——棋盘事实不可变契约;免行动点即效果本身,C5 裁)
|
||||
const ACTIVE_KINDS := ["reveal_tiles", "preview", "grant_ap", "remove_mines", "refresh_pick", "safe_dig"]
|
||||
|
||||
# ---- 订阅集与计数器账本 ----
|
||||
var _triggers: Array = [] # [{source, id, on, when, do}](装载序=声明序,重建时定死)
|
||||
|
||||
@@ -36,8 +36,11 @@ extends Resource
|
||||
@export var rows: Array = [] # Array[Dictionary] 键 item_id
|
||||
|
||||
# 计数键封闭枚举(原 AttunementGrowthTable.COUNTER_KEYS——迭代 21 T5 谓词表退役后就地内联;
|
||||
# boss_kill_count/clear_count 计数域保留〔各有非槽位硬消费,卡片 T0⑥〕)
|
||||
const UNLOCK_COUNTER_KEYS := ["clear_count", "boss_kill_count"]
|
||||
# 迭代 22 T1 换代:clear_count(旧工坊按关累计渠道)与 C6 通关口径(通关=打通整局冒险)不符,
|
||||
# 换名 adventure_cleared(生涯通关局数,save_manager 生涯计数域在役)并扩 vision_used(真视类工具
|
||||
# 累计使用——信标网络行为条件计数,本批新增;use_treasure 受理成功处累计、冒险收束导出入档);
|
||||
# 旧 clear_count 零行消费,换名安全)
|
||||
const UNLOCK_COUNTER_KEYS := ["adventure_cleared", "boss_kill_count", "vision_used"]
|
||||
|
||||
const DIMENSIONS := ["info", "risk", "action", "plan", "counter"]
|
||||
# 同调批扩 enum(迭代 11 第①批 T1)——新增九 kind 全部条件触发/机制修正类;mine_reveal/ap_grant 语义不变。
|
||||
@@ -49,17 +52,34 @@ const DIMENSIONS := ["info", "risk", "action", "plan", "counter"]
|
||||
const EFFECT_KINDS := ["mine_reveal", "reward_preview", "ap_grant",
|
||||
"mine_hit_halve", "reflect_damage", "ap_rounds_front", "ap_charge_safe", "cell_removal",
|
||||
"reward_weight_bias", "bonus_refresh",
|
||||
"reveal_tiles", "preview", "grant_ap", "remove_mines", "refresh_pick"]
|
||||
const TARGETS := ["none", "area_3x3", "board_wide"]
|
||||
"reveal_tiles", "preview", "grant_ap", "remove_mines", "refresh_pick",
|
||||
# 迭代 22 秘宝实装批 T1 扩签八型:
|
||||
# 常时参数面六型(无事件订阅——开局/装板参数注入,注入面按装配集 kind 分发读取):
|
||||
# light_radius_bonus=微光半径加值〔阔视野带〕/rap_transfer_mult=停手转存率千分比〔储备罐 125=1.25〕/
|
||||
# dig_range_bonus=挖掘距离加值〔远程镐〕/flag_range_free=插旗不限相邻〔信标网络〕/
|
||||
# refresh_stock_grant=三选一刷新存量一次性加仓〔刷新练习〕/shop_refresh_bonus=商店免费刷新加值〔刷新执照〕;
|
||||
# 主动分发两型:safe_dig=安全格直开(天眼——走普通挖格规则全额兑付,C5 裁)/mine_count_preview=危险格数量预告(巢穴预告)
|
||||
"light_radius_bonus", "rap_transfer_mult", "dig_range_bonus", "flag_range_free",
|
||||
"refresh_stock_grant", "shop_refresh_bonus", "safe_dig", "mine_count_preview"]
|
||||
const TARGETS := ["none", "area_3x3", "board_wide", "cell"] # 迭代 22 T1 扩 cell=单格真视(线香——≤3×3 窄域契约内)
|
||||
const USE_PHASES := ["active_dig"]
|
||||
const FORMS := ["", "passive", "active_charged"]
|
||||
# 档位词表(迭代 22 T1——槽位档位约束数据面:槽位可装 ≤ 槽位档位的件;词表沿 feats/adventure TIERS)
|
||||
const TIERS := ["common", "excellent", "rare", "legendary"]
|
||||
# 充能重置周期(迭代 22 T1 扩签——现役仅 adventure=每冒险;battle=每战重置〔线香〕/level=每关重置〔天眼〕)
|
||||
const CHARGE_RESETS := ["adventure", "battle", "level"]
|
||||
# magnitude 消费面(≥1 校验):grant_ap 与同调 N 值 kind;其余 kind 活行 magnitude 恒 0
|
||||
const MAGNITUDE_KINDS := ["ap_grant", "reflect_damage", "ap_rounds_front",
|
||||
"ap_charge_safe", "reward_weight_bias", "bonus_refresh", "grant_ap"]
|
||||
"ap_charge_safe", "reward_weight_bias", "bonus_refresh", "grant_ap",
|
||||
"light_radius_bonus", "rap_transfer_mult", "dig_range_bonus", "flag_range_free",
|
||||
"refresh_stock_grant", "shop_refresh_bonus"]
|
||||
# 真视类 kind(迭代 22 T1 护栏扩面——活行 target 必须 ∈ {area_3x3, cell}:真视窄域 ≤3×3 契约)
|
||||
const REVEAL_KINDS := ["mine_reveal", "reveal_tiles"]
|
||||
# 🔴 零裸 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", "triggers", "desc"]
|
||||
"unlock_requires", "effective_rounds", "charge_n", "triggers", "desc",
|
||||
"tier", "charge_reset", "unlock_keystone_cost"] # 迭代 22 T1 扩三键(档位/充能周期/钥石购买价)
|
||||
|
||||
|
||||
func validate() -> Array:
|
||||
@@ -123,9 +143,11 @@ func validate() -> Array:
|
||||
if kind_seen.has(kind):
|
||||
errs.append({"category": "dup_key", "message": "%s effect_kind 重复: %s" % [iid, kind]})
|
||||
kind_seen[kind] = true
|
||||
# 承重护栏①真视窄域:mine_reveal 活行 target 必须 area_3x3(一次最多 3×3,禁全图看雷)
|
||||
if kind_seen.has("mine_reveal") and target != "area_3x3":
|
||||
errs.append({"category": "load_bearing", "message": "%s 真视窄域护栏:mine_reveal 行 target 必须 area_3x3,实得 %s(秘宝 GDD 结构冻结)" % [iid, target]})
|
||||
# 承重护栏①真视窄域:真视类活行 target 必须 area_3x3 或 cell(一次最多 3×3,禁全图看雷;
|
||||
# 迭代 22 T1 护栏扩面——reveal_tiles 与新 cell 档纳入同护栏,线香单格=cell ⊂ 3×3 契约内)
|
||||
for rv in REVEAL_KINDS:
|
||||
if kind_seen.has(String(rv)) and not (target == "area_3x3" or target == "cell"):
|
||||
errs.append({"category": "load_bearing", "message": "%s 真视窄域护栏:%s 行 target 必须 area_3x3 或 cell,实得 %s(秘宝 GDD 结构冻结)" % [iid, String(rv), target]})
|
||||
# 承重护栏②board_wide 仅恢复推理类:全图域行禁替推理效果
|
||||
if target == "board_wide" and kind_seen.has("mine_reveal"):
|
||||
errs.append({"category": "load_bearing", "message": "%s board_wide 行 effect_kinds 不得含 mine_reveal(全图域仅恢复推理原料类——Alpha 重定后落位)" % iid})
|
||||
@@ -145,11 +167,39 @@ func validate() -> Array:
|
||||
if form != "":
|
||||
if int(row.get("slot_cost", 1)) != 1:
|
||||
errs.append({"category": "load_bearing", "message": "%s 同调占位统一 1 槽(slot_cost 恒 1——底稿裁决 5,schema 强制)" % iid})
|
||||
# 档位必填(迭代 22 T1——槽位档位约束数据面:件档≤格档判定的取数源)
|
||||
var tier: String = String(row.get("tier", ""))
|
||||
if not TIERS.has(tier):
|
||||
errs.append({"category": "domain", "message": "%s 同调行 tier 必填且 ∈ %s,实得 %s" % [iid, str(TIERS), tier]})
|
||||
var charges: int = int(row.get("charges_per_adventure", 0))
|
||||
if form == "passive" and charges != 0:
|
||||
errs.append({"category": "cross_field", "message": "%s passive 行 charges_per_adventure 应 0,实得 %d" % [iid, charges]})
|
||||
if form == "active_charged" and charges < 1:
|
||||
errs.append({"category": "cross_field", "message": "%s active_charged 行 charges_per_adventure 应 ≥1,实得 %d" % [iid, charges]})
|
||||
if form == "active_charged" and charges < 0:
|
||||
errs.append({"category": "domain", "message": "%s active_charged 行 charges_per_adventure 越域 ≥0,实得 %d" % [iid, charges]})
|
||||
if form == "active_charged" and charges == 0:
|
||||
# 充能 0=积点制/滑耗制合法态(迭代 22 T1——试炼镐转化获取,无固定充能上限):
|
||||
# 必须带使用闸——ap_charge_safe 滑耗(安全格积点)或 treasure_used+counter_spend 受理闸,二者缺一即孤儿行
|
||||
var has_gate := kind_seen.has("ap_charge_safe")
|
||||
if not has_gate and row.has("triggers"):
|
||||
for tr_v in (row.get("triggers", []) as Array):
|
||||
if String((tr_v as Dictionary).get("do", {}).get("kind", "")) == "counter_spend":
|
||||
has_gate = true
|
||||
break
|
||||
if not has_gate:
|
||||
errs.append({"category": "cross_field", "message": "%s active_charged 行 charges=0(积点制)须带 ap_charge_safe 或 counter_spend 受理闸,实得二者皆无" % iid})
|
||||
# 充能重置周期(迭代 22 T1 扩签:adventure 缺省/battle 每战/level 每关;仅 active_charged 行可设)
|
||||
var creset: String = String(row.get("charge_reset", "adventure"))
|
||||
if not CHARGE_RESETS.has(creset):
|
||||
errs.append({"category": "enum", "message": "%s charge_reset 出域 %s: %s" % [iid, str(CHARGE_RESETS), creset]})
|
||||
if form != "active_charged" and row.has("charge_reset") and creset != "adventure":
|
||||
errs.append({"category": "cross_field", "message": "%s 非 active_charged 行 charge_reset 仅可缺省(adventure),实得 %s" % [iid, creset]})
|
||||
# 解锁混合制字段校验(迭代 22 T1 契约 6:钥石购买价与条件谓词互斥——每件单解锁方式,混合不做)
|
||||
var price: int = int(row.get("unlock_keystone_cost", 0))
|
||||
var ureq_count: int = (row.get("unlock_requires", []) as Array).size()
|
||||
if price != 0 and ureq_count > 0:
|
||||
errs.append({"category": "cross_field", "message": "%s 解锁方式互斥:unlock_keystone_cost 与 unlock_requires 不得并存(每件单解锁方式,契约 6)" % iid})
|
||||
if price < 0 or price > 999:
|
||||
errs.append({"category": "domain", "message": "%s unlock_keystone_cost 越域 [0,999](0=非购买件缺省),实得 %d" % [iid, price]})
|
||||
var eff_rounds: int = int(row.get("effective_rounds", 0))
|
||||
if eff_rounds < 0 or eff_rounds > 999:
|
||||
errs.append({"category": "domain", "message": "%s effective_rounds 越域 [0,999]: %d" % [iid, eff_rounds]})
|
||||
|
||||
@@ -4,115 +4,34 @@
|
||||
|
||||
[resource]
|
||||
script = ExtResource("1")
|
||||
; 迭代 19 卡④(2026-10-08):表尾追加 fog_lantern 魔法提灯(提灯载体道具批——视野外扩 +2 纯呈现载体行;
|
||||
; 空效果行 live 形态=triggers 显式空数组,与显影尘 deferred 形态的形态差=「激活 vs 封存」);行字段值=用户「按推荐」全收 2026-10-08。
|
||||
; 迭代 11 第①批 T1(2026-10-03):追加七件同调行(form 非空——永不入过渡渠道);值全 provisional 归 难度曲线与Boss。
|
||||
; nest_pendulum 已换装 active_charged(迭代 11 第①批);blast_kit 已换装 cell_removal+active_charged(迭代 13 T8/D6——中立移除雷格启用);sapper_order/显影尘/地穴全图卷/罗盘 T7 逐件销账。
|
||||
; 迭代 22 秘宝体系实现重构落地批 T1(2026-10-12):新目录 12 行全量换代(设计权威=秘宝.md「目录(重设计 v1)」;
|
||||
; 旧 12 行删除——venom_edge/flag_burst 已随迭代 20 专长批迁出删除,本批实删 12 行)。三档=普通 7/优秀 3/稀有 2
|
||||
; (传说留空=空集合法,迭代 20 追认③先例)。解锁混合制(契约 8 逐件分配锁定表,2026-10-11 用户裁 C1):
|
||||
; 钥石购买件 unlock_keystone_cost(provisional 占位);条件件 unlock_requires 谓词行——计数键
|
||||
; adventure_cleared=生涯通关局数(C6 裁:通关=打通整局冒险)/boss_kill_count=生涯 Boss 击杀/vision_used=
|
||||
; 真视类工具累计使用(本批新增计数域)。全部数值 provisional 归调参批(契约 7)。
|
||||
; 常时参数面件(无订阅行——效果=开局/装板参数注入,非事件订阅):阔视野带/储备罐/远程镐/信标网络/刷新练习/
|
||||
; 刷新执照六件 effect_kinds 挂参数 kind,由注入面按装配集 kind 分发读取(_attune_refresh_x_total 先例)。
|
||||
; 主动件:线香(battle 级充能)/天眼(level 级充能)charge_reset 扩签;试炼镐=积点制(charges=0 无上限,
|
||||
; ap_charge_safe 滑耗单级化——设计「4 格积 1 点满 2 点换 AP」两级结构的行为等价实现,8 格兑 1 AP)。
|
||||
rows = [{
|
||||
"item_id": "probe_dust",
|
||||
"display_name": "显影尘",
|
||||
"dimension_tags": ["info", "counter"],
|
||||
"desc": "效果失义待重定",
|
||||
"effect_kinds": [],
|
||||
"target": "none",
|
||||
"magnitude": 0,
|
||||
"use_phase": "active_dig",
|
||||
"deferred": true
|
||||
}, {
|
||||
"item_id": "sapper_order",
|
||||
"display_name": "工兵令",
|
||||
"item_id": "morning_order",
|
||||
"display_name": "晨操令",
|
||||
"dimension_tags": ["action"],
|
||||
"desc": "AP +2",
|
||||
"effect_kinds": ["ap_grant"],
|
||||
"target": "none",
|
||||
"magnitude": 2,
|
||||
"use_phase": "active_dig",
|
||||
"retired": true
|
||||
}, {
|
||||
"item_id": "loot_compass",
|
||||
"display_name": "探宝罗盘",
|
||||
"dimension_tags": ["plan"],
|
||||
"desc": "预读 3×3",
|
||||
"effect_kinds": ["reward_preview"],
|
||||
"target": "area_3x3",
|
||||
"magnitude": 0,
|
||||
"use_phase": "active_dig",
|
||||
"retired": true
|
||||
}, {
|
||||
"item_id": "nest_pendulum",
|
||||
"display_name": "探巢摆钟",
|
||||
"dimension_tags": ["risk"],
|
||||
"desc": "真视 3×3",
|
||||
"effect_kinds": ["mine_reveal"],
|
||||
"target": "area_3x3",
|
||||
"magnitude": 0,
|
||||
"use_phase": "active_dig",
|
||||
"form": "active_charged",
|
||||
"slot_cost": 1,
|
||||
"charges_per_adventure": 2
|
||||
}, {
|
||||
"item_id": "catacomb_scroll",
|
||||
"display_name": "地穴全图卷",
|
||||
"dimension_tags": ["info", "plan"],
|
||||
"desc": "效果失义待重定",
|
||||
"effect_kinds": [],
|
||||
"target": "board_wide",
|
||||
"magnitude": 0,
|
||||
"use_phase": "active_dig",
|
||||
"deferred": true
|
||||
}, {
|
||||
"item_id": "blast_kit",
|
||||
"display_name": "爆破工兵包",
|
||||
"dimension_tags": ["action", "risk"],
|
||||
"desc": "AP +4 真视 3×3 移除雷格",
|
||||
"effect_kinds": ["ap_grant", "mine_reveal", "cell_removal"],
|
||||
"target": "area_3x3",
|
||||
"magnitude": 4,
|
||||
"use_phase": "active_dig",
|
||||
"form": "active_charged",
|
||||
"slot_cost": 1,
|
||||
"charges_per_adventure": 2
|
||||
}, {
|
||||
"item_id": "nest_counter",
|
||||
"display_name": "惊巢反制",
|
||||
"dimension_tags": ["risk"],
|
||||
"desc": "踩雷惩罚减半+反弹2",
|
||||
"target": "none",
|
||||
"magnitude": 2,
|
||||
"use_phase": "active_dig",
|
||||
"form": "passive",
|
||||
"slot_cost": 1,
|
||||
"triggers": [{
|
||||
"on": "mine_hit",
|
||||
"do": {
|
||||
"kind": "damage_mult",
|
||||
"value": 50
|
||||
}
|
||||
}, {
|
||||
"on": "mine_hit",
|
||||
"do": {
|
||||
"kind": "open_ticket",
|
||||
"value_from": "magnitude",
|
||||
"channel": "reflect"
|
||||
}
|
||||
}]
|
||||
}, {
|
||||
"item_id": "dawn_order",
|
||||
"display_name": "工兵晨令",
|
||||
"dimension_tags": ["action"],
|
||||
"desc": "前3轮每轮AP+1",
|
||||
"desc": "每场战斗第 1 轮 AP +1",
|
||||
"tier": "common",
|
||||
"target": "none",
|
||||
"magnitude": 1,
|
||||
"use_phase": "active_dig",
|
||||
"form": "passive",
|
||||
"slot_cost": 1,
|
||||
"effective_rounds": 3,
|
||||
"unlock_keystone_cost": 10,
|
||||
"triggers": [{
|
||||
"on": "round_start",
|
||||
"when": [{
|
||||
"fact": "round_index",
|
||||
"op": "lte",
|
||||
"value_from": "effective_rounds"
|
||||
"op": "eq",
|
||||
"value": 1
|
||||
}],
|
||||
"do": {
|
||||
"kind": "grant_ap",
|
||||
@@ -121,64 +40,192 @@ rows = [{
|
||||
}
|
||||
}]
|
||||
}, {
|
||||
"item_id": "dig_charge",
|
||||
"display_name": "掘进蓄能",
|
||||
"item_id": "wide_scout_band",
|
||||
"display_name": "阔视野带",
|
||||
"dimension_tags": ["info"],
|
||||
"desc": "类型微光范围 8 格→12 格",
|
||||
"tier": "common",
|
||||
"target": "none",
|
||||
"magnitude": 4,
|
||||
"use_phase": "active_dig",
|
||||
"form": "passive",
|
||||
"slot_cost": 1,
|
||||
"unlock_keystone_cost": 10,
|
||||
"effect_kinds": ["light_radius_bonus"]
|
||||
}, {
|
||||
"item_id": "trial_pick",
|
||||
"display_name": "试炼镐",
|
||||
"dimension_tags": ["action"],
|
||||
"desc": "积点换AP+1",
|
||||
"desc": "每开 4 安全格积 1 点,满 2 点换当轮 AP +1",
|
||||
"tier": "common",
|
||||
"effect_kinds": ["ap_charge_safe"],
|
||||
"target": "none",
|
||||
"magnitude": 1,
|
||||
"use_phase": "active_dig",
|
||||
"form": "active_charged",
|
||||
"slot_cost": 1,
|
||||
"charges_per_adventure": 2,
|
||||
"charge_n": 3,
|
||||
"charges_per_adventure": 0,
|
||||
"charge_n": 8,
|
||||
"unlock_keystone_cost": 10,
|
||||
"triggers": [{
|
||||
"on": "treasure_used",
|
||||
"do": {
|
||||
"kind": "counter_spend",
|
||||
"counter_id": "dig_charge_bank",
|
||||
"counter_id": "trial_pick_bank",
|
||||
"value": 1
|
||||
}
|
||||
}]
|
||||
}, {
|
||||
"item_id": "luck_coin",
|
||||
"display_name": "偏运硬币",
|
||||
"dimension_tags": ["risk"],
|
||||
"desc": "稀有资源权重+2",
|
||||
"target": "none",
|
||||
"magnitude": 2,
|
||||
"use_phase": "active_dig",
|
||||
"form": "passive",
|
||||
"slot_cost": 1,
|
||||
"triggers": [{
|
||||
"on": "reward_roll",
|
||||
"do": {
|
||||
"kind": "bias_rewards",
|
||||
"value_from": "magnitude"
|
||||
}
|
||||
}]
|
||||
}, {
|
||||
"item_id": "pick_refresh",
|
||||
"display_name": "三选一刷新件",
|
||||
"dimension_tags": ["info"],
|
||||
"desc": "三选一刷新+1",
|
||||
"effect_kinds": ["bonus_refresh"],
|
||||
"item_id": "refresh_practice",
|
||||
"display_name": "刷新练习",
|
||||
"dimension_tags": ["plan"],
|
||||
"desc": "三选一刷新存量 +1(装配即得一次性加仓)",
|
||||
"tier": "common",
|
||||
"target": "none",
|
||||
"magnitude": 1,
|
||||
"use_phase": "active_dig",
|
||||
"form": "passive",
|
||||
"slot_cost": 1
|
||||
"slot_cost": 1,
|
||||
"unlock_keystone_cost": 10,
|
||||
"effect_kinds": ["refresh_stock_grant"]
|
||||
}, {
|
||||
"item_id": "fog_lantern",
|
||||
"display_name": "魔法提灯",
|
||||
"item_id": "reserve_jar",
|
||||
"display_name": "储备罐",
|
||||
"dimension_tags": ["action"],
|
||||
"desc": "停手转存率 1:1 → 1.25:1",
|
||||
"tier": "common",
|
||||
"target": "none",
|
||||
"magnitude": 125,
|
||||
"use_phase": "active_dig",
|
||||
"form": "passive",
|
||||
"slot_cost": 1,
|
||||
"unlock_keystone_cost": 10,
|
||||
"effect_kinds": ["rap_transfer_mult"]
|
||||
}, {
|
||||
"item_id": "nest_forecast",
|
||||
"display_name": "巢穴预告",
|
||||
"dimension_tags": ["info"],
|
||||
"desc": "灯光区半径+2",
|
||||
"effect_kinds": [],
|
||||
"desc": "装板后揭示本板危险格数量",
|
||||
"tier": "common",
|
||||
"target": "none",
|
||||
"magnitude": 0,
|
||||
"use_phase": "active_dig",
|
||||
"form": "passive",
|
||||
"slot_cost": 1,
|
||||
"triggers": []
|
||||
"unlock_keystone_cost": 10,
|
||||
"triggers": [{
|
||||
"on": "board_installed",
|
||||
"do": {
|
||||
"kind": "mine_count_preview"
|
||||
}
|
||||
}]
|
||||
}, {
|
||||
"item_id": "incense_stick",
|
||||
"display_name": "线香",
|
||||
"dimension_tags": ["info"],
|
||||
"desc": "每战一次:真视单格",
|
||||
"tier": "common",
|
||||
"effect_kinds": ["reveal_tiles"],
|
||||
"target": "cell",
|
||||
"magnitude": 0,
|
||||
"use_phase": "active_dig",
|
||||
"form": "active_charged",
|
||||
"slot_cost": 1,
|
||||
"charges_per_adventure": 1,
|
||||
"charge_reset": "battle",
|
||||
"unlock_keystone_cost": 10
|
||||
}, {
|
||||
"item_id": "twin_loader",
|
||||
"display_name": "双管装填",
|
||||
"dimension_tags": ["action"],
|
||||
"desc": "每战前 2 轮各 AP +1",
|
||||
"tier": "excellent",
|
||||
"target": "none",
|
||||
"magnitude": 1,
|
||||
"use_phase": "active_dig",
|
||||
"form": "passive",
|
||||
"slot_cost": 1,
|
||||
"unlock_keystone_cost": 25,
|
||||
"triggers": [{
|
||||
"on": "round_start",
|
||||
"when": [{
|
||||
"fact": "round_index",
|
||||
"op": "lte",
|
||||
"value": 2
|
||||
}],
|
||||
"do": {
|
||||
"kind": "grant_ap",
|
||||
"mode": "queue",
|
||||
"value_from": "magnitude"
|
||||
}
|
||||
}]
|
||||
}, {
|
||||
"item_id": "ranged_pick",
|
||||
"display_name": "远程镐",
|
||||
"dimension_tags": ["action"],
|
||||
"desc": "挖掘距离 +1(可挖距英雄 2 格的格)",
|
||||
"tier": "excellent",
|
||||
"target": "none",
|
||||
"magnitude": 1,
|
||||
"use_phase": "active_dig",
|
||||
"form": "passive",
|
||||
"slot_cost": 1,
|
||||
"unlock_requires": [{
|
||||
"key": "adventure_cleared",
|
||||
"threshold": 1
|
||||
}],
|
||||
"effect_kinds": ["dig_range_bonus"]
|
||||
}, {
|
||||
"item_id": "refresh_license",
|
||||
"display_name": "刷新执照",
|
||||
"dimension_tags": ["plan"],
|
||||
"desc": "商店免费刷新 +2/店",
|
||||
"tier": "excellent",
|
||||
"target": "none",
|
||||
"magnitude": 2,
|
||||
"use_phase": "active_dig",
|
||||
"form": "passive",
|
||||
"slot_cost": 1,
|
||||
"unlock_requires": [{
|
||||
"key": "boss_kill_count",
|
||||
"threshold": 3
|
||||
}],
|
||||
"effect_kinds": ["shop_refresh_bonus"]
|
||||
}, {
|
||||
"item_id": "sky_eye",
|
||||
"display_name": "天眼",
|
||||
"dimension_tags": ["info"],
|
||||
"desc": "每关一次:选 3×3,危险格显示且安全格直接开",
|
||||
"tier": "rare",
|
||||
"effect_kinds": ["reveal_tiles", "safe_dig"],
|
||||
"target": "area_3x3",
|
||||
"magnitude": 0,
|
||||
"use_phase": "active_dig",
|
||||
"form": "active_charged",
|
||||
"slot_cost": 1,
|
||||
"charges_per_adventure": 1,
|
||||
"charge_reset": "level",
|
||||
"unlock_requires": [{
|
||||
"key": "adventure_cleared",
|
||||
"threshold": 3
|
||||
}, {
|
||||
"key": "boss_kill_count",
|
||||
"threshold": 4
|
||||
}]
|
||||
}, {
|
||||
"item_id": "beacon_network",
|
||||
"display_name": "信标网络",
|
||||
"dimension_tags": ["risk"],
|
||||
"desc": "插旗不限相邻(可对任何未开格插旗)",
|
||||
"tier": "rare",
|
||||
"target": "none",
|
||||
"magnitude": 1,
|
||||
"use_phase": "active_dig",
|
||||
"form": "passive",
|
||||
"slot_cost": 1,
|
||||
"unlock_requires": [{
|
||||
"key": "vision_used",
|
||||
"threshold": 10
|
||||
}],
|
||||
"effect_kinds": ["flag_range_free"]
|
||||
}]
|
||||
+66
-39
@@ -232,34 +232,61 @@ func _smoke_adventure_table() -> void:
|
||||
"cap 占位在域(案②提前退役——99=实质无上限,实数归调参批)〔专长批 V8 形态面〕")
|
||||
check(Attunement.slots(_db, null) == 0,
|
||||
"同调位读数源=树同调位节点点亮数(迭代 21 T4 槽位收编——null 档求值 0;谓词表已退役)〔天赋树批 V14〕")
|
||||
# 迭代 19 卡④——提灯载体行(fog_lantern):新行加载/schema/同调目录投影+装配→战斗贯通(核心层半边;
|
||||
# 呈现半边归 ui_input_probe case⑮ 载体级段——测试三形态契约 9)
|
||||
var lantern_row: Dictionary = _db.treasure_items.row_by_id("fog_lantern")
|
||||
check(not lantern_row.is_empty() and String(lantern_row.get("display_name", "")) == "魔法提灯"
|
||||
and String(lantern_row.get("desc", "")) == "灯光区半径+2"
|
||||
and String(lantern_row.get("form", "")) == "passive" and int(lantern_row.get("slot_cost", -1)) == 1
|
||||
and (lantern_row.get("dimension_tags", []) as Array) == ["info"]
|
||||
and (lantern_row.get("effect_kinds", []) as Array).is_empty()
|
||||
and lantern_row.has("triggers") and (lantern_row.get("triggers", []) as Array).is_empty()
|
||||
and String(lantern_row.get("target", "")) == "none" and int(lantern_row.get("magnitude", -1)) == 0
|
||||
and String(lantern_row.get("use_phase", "")) == "active_dig"
|
||||
and not lantern_row.has("unlock_requires")
|
||||
and not bool(lantern_row.get("retired", false)) and not bool(lantern_row.get("deferred", false)),
|
||||
"提灯载体行 fog_lantern:行字段逐键=裁值(魔法提灯/灯光区半径+2/passive/slot_cost 1/[info]/空效果/显式 triggers 空数组/none/0/active_dig/unlock 键省略=已解锁/活行非封存)")
|
||||
var att_lantern := {}
|
||||
for r in _db.treasure_attunement_rows():
|
||||
if String(r.get("item_id", "")) == "fog_lantern":
|
||||
att_lantern = r
|
||||
check(not att_lantern.is_empty() and String(att_lantern.get("display_name", "")) == "魔法提灯",
|
||||
"同调目录投影:fog_lantern 在装配词表且 display_name=魔法提灯(营地工坊目录九件→十件)")
|
||||
# 迭代 22 T1——新目录 12 件全量换代(V1/V2 断言落点;旧提灯段随 fog_lantern 行退役摘除,
|
||||
# 装配→战斗贯通与空装配基线本体保留换主语 morning_order)
|
||||
var trows: Array = _db.treasure_attunement_rows()
|
||||
var tid_set := {}
|
||||
for r in trows:
|
||||
tid_set[String(r.get("item_id", ""))] = true
|
||||
check(trows.size() == 12 and tid_set.size() == 12,
|
||||
"新目录 12 件全量落表(旧 12 行删除;装配词表=活行 12 件零重复)〔秘宝批 V1〕")
|
||||
var new_names := {"morning_order": "晨操令", "wide_scout_band": "阔视野带", "trial_pick": "试炼镐",
|
||||
"refresh_practice": "刷新练习", "reserve_jar": "储备罐", "nest_forecast": "巢穴预告",
|
||||
"incense_stick": "线香", "twin_loader": "双管装填", "ranged_pick": "远程镐",
|
||||
"refresh_license": "刷新执照", "sky_eye": "天眼", "beacon_network": "信标网络"}
|
||||
var names_ok := tid_set.size() == new_names.size()
|
||||
for r in trows:
|
||||
var iid2 := String(r.get("item_id", ""))
|
||||
if not new_names.has(iid2) or String(r.get("display_name", "")) != String(new_names[iid2]):
|
||||
names_ok = false
|
||||
check(names_ok, "命名锁定:12 件 item_id 与 display_name 逐件=正式名(C2 代号即名)〔秘宝批 V2 初筛〕")
|
||||
var keystone_ids := ["morning_order", "wide_scout_band", "trial_pick", "refresh_practice",
|
||||
"reserve_jar", "nest_forecast", "incense_stick", "twin_loader"]
|
||||
var cond_reqs := {"ranged_pick": {"adventure_cleared": 1}, "refresh_license": {"boss_kill_count": 3},
|
||||
"sky_eye": {"adventure_cleared": 3, "boss_kill_count": 4}, "beacon_network": {"vision_used": 10}}
|
||||
var tier_map := {"common": 0, "excellent": 0, "rare": 0}
|
||||
var alloc_ok := trows.size() == 12
|
||||
for r in trows:
|
||||
var iid3 := String(r.get("item_id", ""))
|
||||
var ureqs: Array = r.get("unlock_requires", []) as Array
|
||||
if keystone_ids.has(iid3):
|
||||
if int(r.get("unlock_keystone_cost", 0)) < 1 or not ureqs.is_empty():
|
||||
alloc_ok = false
|
||||
elif cond_reqs.has(iid3):
|
||||
var want: Dictionary = cond_reqs[iid3]
|
||||
if int(r.get("unlock_keystone_cost", 0)) != 0 or ureqs.size() != want.size():
|
||||
alloc_ok = false
|
||||
for req_v in ureqs:
|
||||
var req: Dictionary = req_v as Dictionary
|
||||
if int(want.get(String(req.get("key", "")), -1)) != int(req.get("threshold", -1)):
|
||||
alloc_ok = false
|
||||
else:
|
||||
alloc_ok = false
|
||||
var t: String = String(r.get("tier", ""))
|
||||
if not tier_map.has(t):
|
||||
alloc_ok = false
|
||||
else:
|
||||
tier_map[t] += 1
|
||||
check(alloc_ok and tier_map["common"] == 7 and tier_map["excellent"] == 3 and tier_map["rare"] == 2,
|
||||
"逐行解锁方式与契约 8 分配一致(钥石 8 件带价格、条件 4 件带谓词行互斥)+三档 7/3/2〔秘宝批 V1〕")
|
||||
var orch_l = load("res://core/battle_orchestrator.gd").new(_db, _fresh_rng(191))
|
||||
check(orch_l.begin_battle({"level_index": 1, "node_depth": 0, "hero_hp": int(_db.hero.max_hp), "attunement": ["fog_lantern"]})
|
||||
and orch_l.attune_has("fog_lantern"),
|
||||
"装配→战斗贯通:enc.attunement=[fog_lantern] 起战 attune_has=true(注入面+只读出口)")
|
||||
check(orch_l.begin_battle({"level_index": 1, "node_depth": 0, "hero_hp": int(_db.hero.max_hp), "attunement": ["morning_order"]})
|
||||
and orch_l.attune_has("morning_order"),
|
||||
"装配→战斗贯通:enc.attunement=[morning_order] 起战 attune_has=true(注入面+只读出口)〔秘宝批换主语〕")
|
||||
var orch_e = load("res://core/battle_orchestrator.gd").new(_db, _fresh_rng(192))
|
||||
check(orch_e.begin_battle({"level_index": 1, "node_depth": 0, "hero_hp": int(_db.hero.max_hp)})
|
||||
and not orch_e.attune_has("fog_lantern"),
|
||||
"空装配基线:不带 attunement 起战 attune_has=false(off 态零扰动)")
|
||||
and not orch_e.attune_has("morning_order"),
|
||||
"空装配基线:不带 attunement 起战 attune_has=false(off 态零扰动)〔秘宝批换主语〕")
|
||||
|
||||
|
||||
# ② 冒险结构 API 闸(状态机受理面——重复开始拒绝 / 入口停点 / 放弃两态)
|
||||
@@ -4667,23 +4694,23 @@ func _meta_settle_and_workshop() -> void:
|
||||
sv_a.set_tree_level("att_socket1", 1)
|
||||
check(Attunement.slots(_db, sv_a) == 1,
|
||||
"树上点亮同调位 1 → Slots=1(槽位收编树节点——Q2 裁甲)")
|
||||
check(mp_a.toggle_attunement("nest_counter") and mp_a.toggle_attunement("dawn_order") == false,
|
||||
"装配持久写入 + 满位禁选(Slots 1 装第二件拒绝)")
|
||||
check(mp_a.toggle_attunement("nest_counter") and mp_a.toggle_attunement("dawn_order"),
|
||||
"卸下恒可再装配(换装语义——装配序数组承载)")
|
||||
check(mp_a.toggle_attunement("morning_order") and mp_a.toggle_attunement("twin_loader") == false,
|
||||
"装配持久写入 + 满位禁选(Slots 1 装第二件拒绝)〔秘宝批 V5 换主语〕")
|
||||
check(mp_a.toggle_attunement("morning_order") and mp_a.toggle_attunement("twin_loader"),
|
||||
"卸下恒可再装配(换装语义——装配序数组承载)〔秘宝批换主语;营地换装=冒险开始前合法面,装配不可变只锁运行中〕")
|
||||
var sv_a2 = _meta_new_save(_META_SMOKE_PATHS[7])
|
||||
sv_a2.set_attunement_equipped(["luck_coin"])
|
||||
sv_a2.set_attunement_equipped(["morning_order"])
|
||||
var mp_a2 = load("res://core/meta_progression.gd").new(_db, sv_a2)
|
||||
check((mp_a2.attune_camp_status()["equipped"] as Array).has("luck_coin"),
|
||||
"装配关系读回持久(reload 后投影一致)")
|
||||
check((mp_a2.attune_camp_status()["equipped"] as Array).has("morning_order"),
|
||||
"装配关系读回持久(reload 后投影一致——写新件 id)〔秘宝批 V15〕")
|
||||
# ⑫ 充能重置 / 刷新双计数器(迭代 11 第①批;clamp white-box 断言随 attunement_growth 谓词表
|
||||
# 退役摘除——迭代 21 T5,V20 摘除清单)
|
||||
var a12 = load("res://core/adventure_runner.gd").new(_db, _fresh_rng(12))
|
||||
check(a12.start_adventure(12, {"attunement": ["dig_charge", "nest_pendulum"]}),
|
||||
"充能重置场景:装配冒险启动(seed 12)")
|
||||
check(int(a12.attune_charges.get("dig_charge", -1)) == 2 and int(a12.attune_charges.get("nest_pendulum", -1)) == 2,
|
||||
"充能账本按装备 active_charged 件重置(每冒险 charges_per_adventure 表值)")
|
||||
a12._attunement = ["pick_refresh"]
|
||||
check(a12.start_adventure(12, {"attunement": ["incense_stick", "sky_eye"]}),
|
||||
"充能重置场景:装配冒险启动(seed 12)〔秘宝批 V8 换主语〕")
|
||||
check(int(a12.attune_charges.get("incense_stick", -1)) == 1 and int(a12.attune_charges.get("sky_eye", -1)) == 1,
|
||||
"充能账本按装备 active_charged 件重置(新目录表值:线香 battle 级 1 次/天眼 level 级 1 次——周期重置点归 V8 逐形态面)")
|
||||
a12._attunement = []
|
||||
a12._attune_refresh_x = 1
|
||||
a12._attune_refresh_y = 2
|
||||
a12._curio_pending = {"candidates": [{"kind": "gp", "tier": "common"}, {"kind": "attack", "tier": "common"}, {"kind": "max_hp", "tier": "common"}], "payload": {}}
|
||||
@@ -4693,8 +4720,8 @@ func _meta_settle_and_workshop() -> void:
|
||||
and a12.refresh_curio() == false,
|
||||
"刷新双计数器——X 耗尽转 Y 池、池竭拒绝(x0y2 → y0 → 第四次 false 零副作用)")
|
||||
a12._reset_refresh_x()
|
||||
check(a12.attune_refresh_left() == 1,
|
||||
"刷新 X 每碰三选一重置(不结转——重碰面 x 回表值 1)")
|
||||
check(a12._attune_refresh_x == 0 and a12.attune_refresh_left() == 0,
|
||||
"刷新 X 每碰三选一重置(不结转;新目录无 bonus_refresh 行源——X 机制保留恒 0 空转,存量加仓走 _refresh_stock=刷新练习 V8)〔秘宝批换代〕")
|
||||
# ⑬ 主菜单开局传参面(迭代 19 卡⓪①③——开新/续玩两入口同调三键随开局下传防回归:真实入口此前
|
||||
# 三键恒空(缺陷①),冒烟夹具直呼 runner 参数面拦不住——此处直呼 main.build_adventure_params
|
||||
# 单测统一构造面(static 免实例化整菜单场景;真实两入口共用本构造),取值与营地投影同源)
|
||||
|
||||
@@ -43,7 +43,7 @@ func _suites() -> Array:
|
||||
{"path": "res://tests/unit/contracts/system_contracts_test.gd", "expect": 0},
|
||||
{"path": "res://tests/unit/presentation/ui_font_asset_test.gd", "expect": 0},
|
||||
{"path": "res://tests/unit/presentation/terrain_tile_sets_test.gd", "expect": 0},
|
||||
{"path": "res://tests/unit/core/fog_lantern_wiring_test.gd", "expect": 0}, # 迭代 19 卡④——提灯载体装配链(行加载/schema/只读出口双态/enc 注入面)
|
||||
# fog_lantern_wiring_test 随提灯载体行退役摘除(迭代 22 T1——V13 旧验证约束同生死;呈现桥换代断言归 T4 阔视野带参数面)
|
||||
{"path": "res://tests/unit/core/effect_words_t1_test.gd", "expect": 0},
|
||||
{"path": "res://tests/unit/core/tree_rules_v11_test.gd", "expect": 0}, # 迭代 21 天赋树批 V11——六键合成行闭集校验 # 迭代 20 T1——词表扩签封闭性(V1:新词在册/出域四路被拒/adventure 计数器往返/mod_eq 预评估口径)
|
||||
{"path": "res://tests/unit/core/pool_case_d_test.gd", "expect": 0}, # 迭代 20 T2——池结构案D 行为(V6 令牌三态/V7 曝光槽 2+1 回退/V8 概率上限解耦提前退役)
|
||||
|
||||
@@ -55,12 +55,12 @@ func _init() -> void:
|
||||
# V9-5 同调电池:待分配充能 + 玩家点选(禁自动替选反例)+ 跨层写充能账
|
||||
Kit.check_quiet(a._apply_curio_pick("attune_battery", "rare", 1), "同调电池兑付受理〔专长批 V9〕")
|
||||
Kit.check_quiet(a.battery_pending() == 1, "同调电池:待分配充能 1〔专长批 V9〕")
|
||||
Kit.check_quiet(not a.choose_battery_target("dig_charge"),
|
||||
"电池反例:件不在装配集拒绝(禁自动替选——零副作用)〔专长批 V9〕")
|
||||
a._attunement = ["dig_charge", "nest_pendulum"] # 注入装配集(dig_charge=active_charged)
|
||||
a.attune_charges = {"dig_charge": 2, "nest_pendulum": 2}
|
||||
Kit.check_quiet(a.choose_battery_target("dig_charge") and int(a.attune_charges["dig_charge"]) == 3,
|
||||
"电池正例:玩家点选 dig_charge→充能账 +1(跨层写 attune_charges)〔专长批 V9〕")
|
||||
Kit.check_quiet(not a.choose_battery_target("incense_stick"),
|
||||
"电池反例:件不在装配集拒绝(禁自动替选——零副作用)〔专长批 V9·秘宝批换主语〕")
|
||||
a._attunement = ["incense_stick"] # 注入装配集(incense_stick=新目录 active_charged)
|
||||
a.attune_charges = {"incense_stick": 1}
|
||||
Kit.check_quiet(a.choose_battery_target("incense_stick") and int(a.attune_charges["incense_stick"]) == 2,
|
||||
"电池正例:玩家点选 incense_stick→充能账 +1(跨层写 attune_charges)〔专长批 V9·秘宝批换主语〕")
|
||||
Kit.check_quiet(a.battery_pending() == 0, "电池:分配后待账清零〔专长批 V9〕")
|
||||
|
||||
# V9-6 全链:凭证令牌兑付=牌库摘牌(选中即消尽)
|
||||
|
||||
@@ -1,60 +0,0 @@
|
||||
# VERTICAL SLICE - NOT FOR PRODUCTION
|
||||
# 提灯载体 fog_lantern 装配链单测(迭代 19 卡④ T3——测试三形态之「呈现桥判定=注入装配集 stub 的
|
||||
# 单测 + 行加载单测」(需求卡片契约 9);probe=case⑮ 载体级段 / smoke=现有套件加断言,另两形态不在本件)。
|
||||
# 覆盖:真实表行加载+schema 校验零违例 / 行字段裁值逐键 / 同调目录词表收录 / attune_has 只读出口
|
||||
# 双态(组合根 _sync_fog_lantern 消费面)/ begin_battle enc 注入面。
|
||||
# 运行:godot --headless --path game --script res://tests/unit/core/fog_lantern_wiring_test.gd(expect 0)
|
||||
extends SceneTree
|
||||
|
||||
const Kit := preload("res://tests/unit/test_kit.gd") # check/汇总退出样板单点(静默收集通道)
|
||||
|
||||
|
||||
func _init() -> void:
|
||||
# ① 行加载+schema 校验(真实 treasure_items.tres——活行空 effect_kinds 豁免以 row.has("triggers")
|
||||
# 为条件(treasure_item_table.gd:111),triggers 键漏写=加载红——本断言钉住该易错点)
|
||||
var tbl = load("res://data/tables/treasure_items.tres")
|
||||
Kit.check_quiet(tbl != null and tbl.validate().is_empty(),
|
||||
"fog_lantern 入表后 TreasureItemTable.validate 零违例(KEY_WHITELIST/活行校验全过)")
|
||||
var row: Dictionary = tbl.row_by_id("fog_lantern") if tbl != null else {}
|
||||
Kit.check_quiet(not row.is_empty() and String(row.get("display_name", "")) == "魔法提灯"
|
||||
and String(row.get("desc", "")) == "灯光区半径+2"
|
||||
and String(row.get("form", "")) == "passive" and int(row.get("slot_cost", -1)) == 1
|
||||
and row.has("triggers") and (row.get("triggers", []) as Array).is_empty()
|
||||
and (row.get("effect_kinds", []) as Array).is_empty()
|
||||
and String(row.get("target", "")) == "none" and int(row.get("magnitude", -1)) == 0
|
||||
and String(row.get("use_phase", "")) == "active_dig"
|
||||
and (row.get("dimension_tags", []) as Array) == ["info"]
|
||||
and not row.has("unlock_requires")
|
||||
and not bool(row.get("retired", false)) and not bool(row.get("deferred", false)),
|
||||
"行字段逐键=用户「按推荐」裁值(魔法提灯/灯光区半径+2/passive/slot_cost 1/显式 triggers 空/none/0/active_dig/[info]/unlock 键省略=已解锁/活行)")
|
||||
var in_att := false
|
||||
for r in (tbl.attunement_rows() as Array):
|
||||
if String(r.get("item_id", "")) == "fog_lantern":
|
||||
in_att = true
|
||||
Kit.check_quiet(in_att, "同调目录词表收录 fog_lantern(attunement_rows=form 非空活行口径)")
|
||||
|
||||
# ② 数据表宿主(②③需 db)
|
||||
var db = load("res://core/config_db.gd").new()
|
||||
if not db.load_tables("res://data/tables", false):
|
||||
print("[fog_lantern_wiring_test] FAIL — 数值表加载失败")
|
||||
quit(1)
|
||||
return
|
||||
|
||||
# ③ 呈现桥判定 stub:装配集直注→只读出口双态(组合根 _sync_fog_lantern 消费面——不经完整战斗)
|
||||
var rng_a = load("res://core/rng_service.gd").new()
|
||||
rng_a.set_master_seed(191) # 播种(EC7 未播种取数致命——begin_battle 板生成取号前提)
|
||||
var orch = load("res://core/battle_orchestrator.gd").new(db, rng_a)
|
||||
orch.attunement = ["fog_lantern"]
|
||||
Kit.check_quiet(orch.attune_has("fog_lantern"), "attune_has(fog_lantern)=true(装配集在册)")
|
||||
Kit.check_quiet(not orch.attune_has("luck_coin"), "attune_has(luck_coin)=false(他件不误判)")
|
||||
orch.attunement = []
|
||||
Kit.check_quiet(not orch.attune_has("fog_lantern"), "attune_has(fog_lantern)=false(空集=复原语义读数源)")
|
||||
|
||||
# ④ begin_battle enc 注入面(runner→enc.attunement→orchestrator 运行态)
|
||||
var rng_b = load("res://core/rng_service.gd").new()
|
||||
rng_b.set_master_seed(192)
|
||||
var orch2 = load("res://core/battle_orchestrator.gd").new(db, rng_b)
|
||||
Kit.check_quiet(orch2.begin_battle({"level_index": 1, "node_depth": 0, "hero_hp": int(db.hero.max_hp), "attunement": ["fog_lantern"]})
|
||||
and orch2.attune_has("fog_lantern"), "begin_battle enc.attunement 注入→attune_has=true(每战装配链装载)")
|
||||
|
||||
quit(Kit.finish("fog_lantern_wiring_test", "PASS — 行加载/schema 校验/同调词表收录/只读出口双态/enc 注入面 全绿"))
|
||||
@@ -1 +0,0 @@
|
||||
uid://jlkj801c81qd
|
||||
@@ -1,6 +1,8 @@
|
||||
# 致命类用例(独立进程,期望退出码 1)
|
||||
# treasure_target_violation——真视窄域护栏(秘宝 GDD 结构冻结,迭代 7 T1):mine_reveal 行 target
|
||||
# treasure_target_violation——真视窄域护栏(秘宝 GDD 结构冻结,迭代 7 T1):真视类行 target
|
||||
# 越域至 board_wide 时,TreasureItemTable.validate 必须报 load_bearing 错、load_tables 整体拒绝。
|
||||
# 迭代 22 T1:注入主语换代 sky_eye(新目录真视行 reveal_tiles——旧 nest_pendulum 行随 12 行换代退役;
|
||||
# 护栏本体扩面=mine_reveal/reveal_tiles 两 kind 同守 REVEAL_KINDS)。
|
||||
# 运行:godot --headless --path game --script res://tests/unit/data_config/treasure_target_violation_test.gd
|
||||
# 退出码协议:1 = 校验正确拒绝(预期);2 = 违规表被放行(回归信号)。
|
||||
# 时序注:纯加载期校验——不触运行期 fatal 通道,断言 load_tables 返回 false + 诊断在案即 quit(1)。
|
||||
@@ -20,17 +22,12 @@ func _inject_violation() -> bool:
|
||||
return false
|
||||
var s := f.get_as_text()
|
||||
f.close()
|
||||
# 探巢摆钟(mine_reveal 活行)target area_3x3 → board_wide:双护栏同时命中
|
||||
var bad := s.replace('"item_id": "nest_pendulum",\r\n"display_name": "探巢摆钟",', '"item_id": "nest_pendulum",\r\n"display_name": "探巢摆钟",')
|
||||
if bad == s:
|
||||
# 换行形态回退(LF)
|
||||
bad = s.replace('"item_id": "nest_pendulum",\n"display_name": "探巢摆钟",', '"item_id": "nest_pendulum",\n"display_name": "探巢摆钟",')
|
||||
# 直接改 target:摆钟行是全表唯一的 mine_reveal 单维行——把它的 area_3x3 改 board_wide
|
||||
# (罗盘 retired 行同值 area_3x3 但 retired 免校验——替换须定位摆钟块内)
|
||||
# 直接改 target:天眼行是全表唯一的 reveal_tiles 真视行——把它的 area_3x3 改 board_wide
|
||||
# (护栏扩面后真视类 kind 全守——越域行命中 REVEAL_KINDS 护栏)
|
||||
var blocks := s.split("}, {")
|
||||
var hit := false
|
||||
for i in blocks.size():
|
||||
if '"item_id": "nest_pendulum"' in blocks[i]:
|
||||
if '"item_id": "sky_eye"' in blocks[i]:
|
||||
blocks[i] = blocks[i].replace('"target": "area_3x3"', '"target": "board_wide"')
|
||||
hit = true
|
||||
s = "}, {".join(blocks)
|
||||
|
||||
Reference in new issue
Block a user