diff --git a/game/core/adventure_runner.gd b/game/core/adventure_runner.gd index b7e1462d..5c9b031c 100644 --- a/game/core/adventure_runner.gd +++ b/game/core/adventure_runner.gd @@ -56,7 +56,7 @@ var _time_sand_queue := 0 # 时沙待注入(回合级——下 var _save_manager = null # 断点承载注入(null = 不写断点;模拟/冒烟缺省) var _resume_bp := {} # 续玩快照暂存(resume_adventure → _start_current_level 单跳传递) # ---- 三选一停点态 ---- -var _curio_taken := {} # 件获取次数计数(kind 维度派生账本——断点附随件与摘要读数承载;池库存正主=_curio_deck) +var _curio_taken := {} # 件获取次数计数(kind 维度派生账本——断点附随件与摘要读数承载;池库存现行事实源=_curio_deck) var _curio_deck: Array[Variant] = [] # 令牌池(TP0 v2.2——持久多重集,元素 {"kind","tier"};洗牌抽候选/选中踢池未选回池/池耗即枯竭;商店货架同库共账;规则改写型特性带=relic 令牌随表追加) var _feats: Array[String] = [] # 特性持有集(局内随机渠道获得、冒险级跨关携带、收束清零;🔴 层级纪律承载面:不入同调位不入局外树) var _tree_rules: Array[Variant] = [] # 树 rule 键集(Fork 激活侧 effects 透传;下传 enc.tree_rules 消费面) @@ -64,9 +64,9 @@ var _curio_pending := {} # 停点态:{"candidates": Array, "p var _curio_result := {} # 已兑付待推进态(curio_resolved 载荷副本——中断续玩不重兑付) var _keystone_drops: Array[Variant] = [] # Boss 逐杀掉落明细(additive 摘要键 keystone_drops——结算明细/复盘归因数据源) var _node_curio_pending := {} # 奖励节点三选一停点态(共享池;断点不载:续玩重建到选路停点重走,恢复的计数器保证同候选重抽) -var _feat_ticket_pity := 0 # 门票保底计数(T5——展示次数:节点开面/货架抽签/刷新重展各计一次;触发清零) -var _feat_ticket_sold := 0 # 门票限购计数(T5——选中/买下即 +1;拿到即开不进持有集) -var _feat_ticket_appeared := 0 # 门票出现计数(T5——quota 上限面) +var _feat_ticket_pity := 0 # 专长凭证保底计数(T5——展示次数:节点开面/货架抽签/刷新重展各计一次;触发清零) +var _feat_ticket_sold := 0 # 专长凭证限购计数(T5——选中/买下即 +1;拿到即开不进持有集) +var _feat_ticket_appeared := 0 # 专长凭证出现计数(T5——quota 上限面) var _shop_mode := "legacy" # 商店模式("legacy"=固定三件加定价〔off 对照承载,缺省零扰动〕/"pool"=共享池抽 3 买 1 重抽;真实入口 main.gd 显式投 pool) @@ -472,7 +472,7 @@ func pool_stock(kind: String) -> int: # 未知 kind 拒绝(货架词表封闭的前置防御)。 func _consume_pool_purchase(kind: String, tier: String) -> bool: if kind == "feat_ticket": - return _redeem_feat_ticket() # T5——门票买下即开(零摘牌不进持有集;临时停点开专长三选一面) + return _redeem_feat_ticket() # T5——专长凭证买下即开(零摘牌不进持有集;临时停点开专长三选一面) if not db.adventure.CURIO_KINDS.has(kind): push_error("[冒险结构] 商店购买消费拒绝——件不在池词表: %s" % kind) return false @@ -659,7 +659,7 @@ func _finish_node_bonus(picked: String, value: int, tier: String = "", feat_id: # 自动回池;池耗即枯竭——余库不足 N kind 时出齐剩余,空库 = 零候选合法态)。候选 = 令牌字典 # {"kind","tier"}。消费 reward_pick 封闭流——一次停点恰一 scope,同种子同候选。 # 渠道白名单过滤(渠道轴定位:关底 Boss 击败=通关渠道只出专长(feat 令牌); -# 奖励节点/商店只出属性值提升+资源(非 relic 令牌),专长在非 Boss 渠道只以门票形态出现(T5)。 +# 奖励节点/商店只出属性值提升+资源(非 relic 令牌),专长在非 Boss 渠道只以专长凭证形态出现(T5)。 # 过滤式而非物理拆池:deck 物理结构/存档键 bonus_deck 混编余库/消耗语义(选中踢池未选回池)原样, # 白名单在候选视图层生效——配额结构锚 TIER_QUOTAS 70/25/3=98 零改动(专长令牌本系活行追加面,在锚外)。 # 曝光槽:非 Boss 渠道三选一 = **2 格全池 + 1 格优秀档以上子池** @@ -746,7 +746,7 @@ func _draw_curio_candidates(channel: String = "reward_node") -> Array: sub = [] # 子池枯竭——曝光槽回退全池续取 continue break # 全池枯竭——出齐剩余(池空直通同族兜底) - # T5 门票注入(非 Boss 渠道唯一专长入口——替换末位候选占一席,候选数不变;判定含 pity 清零记账) + # T5 专长凭证注入(非 Boss 渠道唯一专长入口——替换末位候选占一席,候选数不变;判定含 pity 清零记账) if channel == "reward_node" and not out.is_empty() and _feat_ticket_consider(rg): out[out.size() - 1] = {"kind": "feat_ticket", "tier": "excellent"} return out @@ -766,7 +766,7 @@ func _curio_cap_ok(kind: String, feat_id: String = "") -> bool: return int(_curio_taken.get(kind, 0)) < cap -# —— 专长获取门票(T5——非 Boss 渠道的专长入口;四口径契约④:拿到即开不可囤积/ +# —— 专长获取专长凭证(T5——非 Boss 渠道的专长入口;四口径契约④:拿到即开不可囤积/ # 罕见只在概率不在价格/一局限购一次/计步保底连续 5 展示未出第 6 必出——计数=展示次数、刷新 # 重展计入、节点与商店共享、触发清零、限购满不再触发。调用即一次展示判定与记账)—— func _feat_ticket_consider(rg: RandomNumberGenerator) -> bool: @@ -783,7 +783,7 @@ func _feat_ticket_consider(rg: RandomNumberGenerator) -> bool: return offer -# 门票兑付(拿到即开——停点候选替换为专长三选一;不进持有集/零摘牌;限购计数 +1): +# 专长凭证兑付(拿到即开——停点候选替换为专长三选一;不进持有集/零摘牌;限购计数 +1): # 节点停点=本地替换(呈现层读在途态重绘);店内无停点=临时停点 + payload.context 标记(呈现层 # 重 present 无胜利总结面,确认后只关面回店)。 func _redeem_feat_ticket() -> bool: @@ -791,7 +791,7 @@ func _redeem_feat_ticket() -> bool: _feat_ticket_pity = 0 var cands: Array[Variant] = _draw_curio_candidates("level_clear") # 专长池(与通关渠道同白名单) if cands.is_empty(): - push_error("[冒险结构] 门票兑付失败——专长池空集") + push_error("[冒险结构] 专长凭证兑付失败——专长池空集") _feat_ticket_sold -= 1 return false if not _node_curio_pending.is_empty(): @@ -1028,8 +1028,8 @@ func _snapshot_breakpoint() -> void: "bonus_deck": _curio_deck.duplicate(true), # 令牌池余库(TP0 v2.2——池消耗即上限,续玩余库逐枚还原) "relics": _feats.duplicate(), # 特性持有集(局内随机渠道获得态续玩防丢失) "bonus_pending": _curio_pending.duplicate(true), # 三选一停点态(空 = 无停点——选择停点可中断契约) - "feat_ticket_pity": _feat_ticket_pity, # T5 门票保底计数(扩列向后兼容——旧档缺键缺省 0) - "feat_ticket_sold": _feat_ticket_sold, # T5 门票限购计数(同上) + "feat_ticket_pity": _feat_ticket_pity, # T5 专长凭证保底计数(扩列向后兼容——旧档缺键缺省 0) + "feat_ticket_sold": _feat_ticket_sold, # T5 专长凭证限购计数(同上) "adventure_counters": run_ledger.adventure_counters.duplicate(true), # adventure 域计数器随断点(续玩跨战账不丢) "vision_counter_used": int(run_ledger.vision_counter.get("used", 0)), # 真视使用计数随断点(续玩跨战账不丢) "refresh_stock": _refresh_stock, # 刷新存量账随断点 diff --git a/game/core/battle_orchestrator.gd b/game/core/battle_orchestrator.gd index b2eb54c7..ff672721 100644 --- a/game/core/battle_orchestrator.gd +++ b/game/core/battle_orchestrator.gd @@ -62,7 +62,7 @@ var _verdict_seg = null # VerdictSegment(⑤判定段——返回裁定, var _refresh_used_this_round := 0 # 每轮刷新计数(Active 相位合计,兜底上限 = ActionEconomyTable.refresh_cap_per_round) var _board_seq := 0 # 板序号(本战斗第几张板——快照归因用) var _board_from_midround_refresh := false # 装板 provenance:轮内刷新换来的图 = true(清图奖励守卫——刷新图不发清图奖励) -var _seal_consumed := {} # 兑付资格以危险格实例为键(板级;换图重置) +var _seal_consumed := {} # 兑付资格以危险格实例为键(整图;换图重置) # 同调装配运行态(begin_battle 经 enc.attunement 注入;off=空集全部效果零扰动) var attunement: Array[Variant] = [] # 装备中同调件 item_id 集 var _ledger: RunLedger = null # 共享四本账(begin_battle 经 enc["ledger"] 持引用;缺省新账=调试面) @@ -259,7 +259,7 @@ func attune_convert_state() -> Dictionary: # 流派档位质变=FeatsEngine 纯函数求值 # (档位机制本身系引擎基建非内容效果),两运行态注伤害控制器:档一 rider+1 / 档二 rider 可暴击) var _seal_miss_seen := {} # 封印未中行去重(每安全格实例一次) -var _perfect_hit_true := 0 # 板级完美排雷计数(install 重置) +var _perfect_hit_true := 0 # 整图完美封印计数(install 重置) var _perfect_hit_false := 0 var _perfect_forgiven := 0 # 完美保险豁免累计(单向累加自有账;契约 2 禁改写 _perfect_hit_false) var _hero_atk := 0 # 主角攻击基值快照(encounter.hero_atk;E4 收口——表值运行期不可变) @@ -439,7 +439,7 @@ func _install_new_board(during_round := false) -> bool: # 全局作用域变异决议(装板序内前置于 roll_board:图级偏斜旋钮须在资源 # 摇号前定型;全局门控与板无关〔节点身份+unlock+board_types〕,确定性取用零取号)。 # boss/elite 图命中全局型 → 写 board_variants(_place_variants 见非空即跳 region=替换制); - # 全局池空 → 板级字段留空(_place_variants 原路走 region=兜底回落合法态)。 + # 全局池空 → 整图字段留空(_place_variants 原路走 region=兜底回落合法态)。 _resolve_global_variant(board) var res: Dictionary[Variant, Variant] = minesweeper.install_board(board, during_round) if not res.accepted: @@ -464,7 +464,7 @@ func _install_new_board(during_round := false) -> bool: _place_variants(board) _seal_consumed.clear() # 换图新雷 = 新实例,资格自然重置(行动经济 Rule 8) _seal_miss_seen.clear() - _perfect_hit_true = 0 # 板级完美计数随 install 重置 + _perfect_hit_true = 0 # 整图完美计数随 install 重置 _perfect_hit_false = 0 _perfect_forgiven = 0 # 豁免累计随 install 重置(domain=battle 每战清零) _board_from_midround_refresh = during_round # 轮内刷新装板 = 刷新图(清图奖励不发);常规换图/开战装板 = false @@ -476,7 +476,7 @@ func _install_new_board(during_round := false) -> bool: # ---- 全局作用域变异 决议(装板序内 roll_board 之前)---- -# boss/elite 图命中全局型:写板级 board_variants(恰一行)+ 注入资源面偏斜旋钮(图级投影在 +# boss/elite 图命中全局型:写整图 board_variants(恰一行)+ 注入资源面偏斜旋钮(图级投影在 # RewardEconomy.roll_board 消费);不消费 variant_place 流(全局取用确定性——零取号合法态)。 # 全局池空(含 L1 Boss 免疫/unlock 门控未达):字段留空、旋钮归零——_place_variants 原路走 # region 布置 = 兜底回落(保守向后兼容,防配置缺行静默裸奔——provisional)。 @@ -500,8 +500,8 @@ func _resolve_global_variant(board: BoardData) -> void: # (关卡序号−1)×per_level_bonus——基数为候选池而非总格数(初始展开 # 占全板 56–67%,总格数基数使有效密度膨胀 4–6 倍、L1 小板极端全池覆盖;percent 语义 = 占可挖格比例, # 关卡递增由 per_level_bonus 绝对格数承载);连通片生长(8 邻),单片 ≤ pack_max(2×2 / 1×4 / 1×3+1 等形)。 -# 替换制(全局作用域变异):板级 board_variants 非空 = 本图已带全局型,跳过 region -# 布置(每图一型的板级推广:普通图=region,Boss/精英图=global);空 = 原路径(含 Boss 图全局池空回落)。 +# 替换制(全局作用域变异):整图 board_variants 非空 = 本图已带全局型,跳过 region +# 布置(每图一型的整图推广:普通图=region,Boss/精英图=global);空 = 原路径(含 Boss 图全局池空回落)。 func _place_variants(board: BoardData) -> void: if not board.board_variants.is_empty(): return @@ -905,7 +905,7 @@ func _submit_flat_hero(source_class: String, display: String, power: int, cell: # 封印判定批:标中 = 该危险格资源的正向兑付(每雷实例一次;高光 = 强制检查点); # 标空 = "封印未中"归因行 + 该安全格资源的负向兑付(同键去重——每格实例一次)。 -# 清图批:清图奖励对象恰好发一次;完美排雷追加第二份同身份兑付(grant_clear 本身恰一次)。 +# 清图批:清图奖励对象恰好发一次;完美封印追加第二份同身份兑付(grant_clear 本身恰一次)。 # 高光行 value = 实际有效兑付份数(禁记名义值;首份零兑付 → 降级不发)。 func _grant_clear_reward(ri: int) -> void: if _board_from_midround_refresh: @@ -919,10 +919,10 @@ func _grant_clear_reward(ri: int) -> void: if perfect and first_ok: second_ok = _grant_clear_identity(snap, ri, "(完美第二份)") if perfect and first_ok: - _emit_row("highlight", "clear_reward", Vector2i(-1, -1), ri, "完美排雷!清图奖励 ×2", (2 if second_ok else 1), {}, "perfect_sweep") + _emit_row("highlight", "clear_reward", Vector2i(-1, -1), ri, "完美封印!清图奖励 ×2", (2 if second_ok else 1), {}, "perfect_sweep") -# 清图奖励 = 板级独立对象(不属于任何一格):兑付形态按其 cell_type 的正向字典形态走, +# 清图奖励 = 整图独立对象(不属于任何一格):兑付形态按其 cell_type 的正向字典形态走, # 行值全部取快照(身份批 roll 值)。返回实际有效兑付。 # 同步开单(sync)——完美第二份与高光份数的流程依赖需要同步读数(开单权归流程); # 同步路径内先按序结清段内排队单据(B 模式保序),随后本批无视结账政策当场兑现。 @@ -1206,7 +1206,7 @@ func presentation_snapshot() -> Dictionary: "hero": hero, "enemies": enemies, "hero_effects": _status_effects.query_active("hero").duplicate(true), # 值拷贝出户(快照消费方直改不渗入状态容器) - # 板级变异投影(呈现横幅/常驻角标唯一读取面; + # 整图变异投影(呈现横幅/常驻角标唯一读取面; # 空数组 = 无全局型合法态:普通图与全局池空回落图恒空) "board_variants": (minesweeper.current_board().board_variant_ids().duplicate() if minesweeper.current_board() != null else ([] as Array[String])), @@ -1289,7 +1289,7 @@ func _fatal(msg: String) -> void: assert(false, msg) -## 完美排雷谓词(两账相减:有效误标=误标总数−豁免数) +## 完美封印谓词(两账相减:有效误标=误标总数−豁免数) ## 契约 2:_perfect_hit_false 保持纯净,豁免只累加 _perfect_forgiven,禁回退式改写与拦截式吞事件。 func perfect_sweep_earned() -> bool: return _perfect_hit_false - _perfect_forgiven <= 0 and _perfect_hit_true >= 1 diff --git a/game/core/board_data.gd b/game/core/board_data.gd index 872f3e88..c1539e62 100644 --- a/game/core/board_data.gd +++ b/game/core/board_data.gd @@ -14,7 +14,7 @@ var spawn_center := Vector2i.ZERO var mines := {} # Vector2i → true var digits := {} # Vector2i → int(安全格恒有值;数字恒真 = 8 邻雷数) var variants := {} # Vector2i → Array[String](生成期快照,抗表重载) -var board_variants: Array[String] = [] # 板级变异 id 集(scope=global 整图作用域—— +var board_variants: Array[String] = [] # 整图变异 id 集(scope=global 整图作用域—— # 战斗编排装板决议写入,随图生灭同 variants;普通图恒空) var board_type := "" # 图类型标签(词表 v1.0:dungeon/underdark;玩家侧显示名「地图类型」) var level_index: int = 1 @@ -50,7 +50,7 @@ func variant_ids(c: Vector2i) -> Array: return variants.get(c, []) -# 板级变异只读出口(scope=global 行集——呈现快照/断言消费;空 = 无全局型合法态) +# 整图变异只读出口(scope=global 行集——呈现快照/断言消费;空 = 无全局型合法态) func board_variant_ids() -> Array[String]: return board_variants diff --git a/game/core/config_db.gd b/game/core/config_db.gd index db0ddc0c..95749262 100644 --- a/game/core/config_db.gd +++ b/game/core/config_db.gd @@ -19,8 +19,8 @@ const TABLE_MANIFEST := { "settlement": "settlement.tres", "level": "level.tres", "difficulty": "difficulty.tres", - "shop": "shop.tres", # ShopTable(表与 schema 落籍归数据面——本处只接线加载与消费) - "meta": "meta.tres", # MetaTable 四行族(schema 与表同源落籍) + "shop": "shop.tres", # ShopTable(表与 schema 已入库归数据面——本处只接线加载与消费) + "meta": "meta.tres", # MetaTable 四行族(schema 与表同源已入库) "meta_tree": "meta_tree.tres", # MetaTreeTable 12 节点(定义表 Rule 4 豁免——天赋树.md v0.8 结构事实源) "treasure_items": "treasure_items.tres", # TreasureItemTable 六行(定义表 Rule 4 豁免;罗盘 retired/失义件 deferred 标记见 schema 头注) "adventure": "adventure.tres", # AdventureTable(大奖励与钥石行值单点) @@ -39,10 +39,10 @@ var reward: RewardTable var settlement: SettlementTable var level: LevelTable var difficulty: DifficultyTable -# ShopTable 类型化持用(schema class_name 已落籍; +# ShopTable 类型化持用(schema class_name 已已入库; # 消费面一律走下方 shop_* 访问器,禁直读行集) var shop: ShopTable = null -# MetaTable 类型化持用(schema 与表同源落籍) +# MetaTable 类型化持用(schema 与表同源已入库) var meta: MetaTable var meta_tree: MetaTreeTable # 类型化持用(消费面走 tree_node 访问器) var treasure_items: TreasureItemTable # 类型化持用(消费面走 treasure_* 访问器) @@ -277,7 +277,7 @@ func treasure_attunement_rows() -> Array: # 行族四轴(数据契约,行集归 shop.tres):gp_drops {tier, mean, roll_min, roll_max} · # level_gp_bonus {level_index, bonus} · products {product_id, display_name, attr, flat_value, # base_price, price_increment} · price_level_bonus {level_index, bonus}。 -# 行族经 ShopTable 同名数组属性读取(.get 容缺——表落籍前查询恒空,掉落按 0 兑付的兜底在调用方)。 +# 行族经 ShopTable 同名数组属性读取(.get 容缺——表已入库前查询恒空,掉落按 0 兑付的兜底在调用方)。 func shop_gp_drop_row(tier: String) -> Dictionary: for row in _shop_rows("gp_drops"): @@ -334,7 +334,7 @@ func shop_price_b() -> float: return float(shop.price_b) if shop != null else 0.0 -# 行族数组读取(ShopTable 属性名 = 行族名;表未落籍/属性缺失 = 空集非错误态) +# 行族数组读取(ShopTable 属性名 = 行族名;表未已入库/属性缺失 = 空集非错误态) func _shop_rows(family: String) -> Array: if shop == null: return [] @@ -387,7 +387,7 @@ func _meta_rows(family: String) -> Array: # 设计权威 design/gdd/systems/跨局循环/锻造工坊.md v0.6:默认值归本表常驻持有(hero.tres 两轴已删—— # 契约 2);路线行族=攻防数值成长唯一数据面(契约 1)。数值全 provisional 归 M4。 -# 两根类型轴默认值(表未落籍=裸体态兜底 normal/light——与 ForgeTable 缺省值同口径) +# 两根类型轴默认值(表未已入库=裸体态兜底 normal/light——与 ForgeTable 缺省值同口径) func forge_default_attack_type() -> String: return String(forge.default_attack_type) if forge != null else "normal" diff --git a/game/core/config_db_cross_validator.gd b/game/core/config_db_cross_validator.gd index 670da120..7ba5f18e 100644 --- a/game/core/config_db_cross_validator.gd +++ b/game/core/config_db_cross_validator.gd @@ -97,7 +97,7 @@ func cross_validate(loaded: Dictionary, push_diag: Callable) -> void: for row in shp.pool_shelf: var kind: String = String(row.get("kind_id", "")) if kind == "feat_ticket": - continue # 门票豁免——货架专属机制种(非 deck 池种,零摘牌拿到即开),不入 CURIO_KINDS + continue # 专长凭证豁免——货架专属机制种(非 deck 池种,零摘牌拿到即开),不入 CURIO_KINDS if not adv.CURIO_KINDS.has(kind): push_diag.call("error", "shelf_dangling_kind", "ShopTable.pool_shelf kind %s 不在 AdventureTable.CURIO_KINDS(共享池牌库外种)" % kind) continue diff --git a/game/core/level_runner.gd b/game/core/level_runner.gd index e00129e8..e304c378 100644 --- a/game/core/level_runner.gd +++ b/game/core/level_runner.gd @@ -48,7 +48,7 @@ var _hero_armor_type := "" var _shop_pool_mode := false # pool 模式封印(set_shop_pool 注入时置位——AdventureRunner 按 params.shop_mode 下传) var _pool_deck: Array[Variant] = [] # 共享池令牌库共享引用(AdventureRunner._curio_deck——库存=剩余令牌数单点) var _pool_consume := Callable() # 池消费 handler(AdventureRunner._consume_pool_purchase——_apply_curio_pick 同口写加算区+账本+摘牌) -var _pool_ticket := Callable() # 门票展示判定 handler(T5——AdventureRunner._feat_ticket_consider;节点与商店共享计数) +var _pool_ticket := Callable() # 专长凭证展示判定 handler(T5——AdventureRunner._feat_ticket_consider;节点与商店共享计数) var _pool_cap_check := Callable() # cap 检查回调(AdventureRunner._curio_cap_ok;cap 满剔出货架候选视图) var _shop_shelf: Array[Variant] = [] # 当前货架(进店抽 3/买后全重抽——令牌字典 {"kind","tier"} 序,同 kind 去重每 kind 至多一卡) var _shop_visit_buys := 0 # 本次进店已购次数(A 链定价输入——离开清零) @@ -775,7 +775,7 @@ func player_request_refresh() -> bool: func set_shop_pool(deck_ref: Array, consume_handler: Callable, ticket_consider: Callable = Callable(), cap_check: Callable = Callable()) -> void: _pool_deck = deck_ref _pool_consume = consume_handler - _pool_ticket = ticket_consider # T5——门票展示判定(AdventureRunner._feat_ticket_consider;同流取数复用 shop_draw scope) + _pool_ticket = ticket_consider # T5——专长凭证展示判定(AdventureRunner._feat_ticket_consider;同流取数复用 shop_draw scope) _pool_cap_check = cap_check _shop_pool_mode = true @@ -820,12 +820,12 @@ func _shop_draw_shelf() -> void: _shop_shelf.append(tok) if _shop_shelf.size() >= 3: break - # T5 门票注入(非 Boss 渠道唯一专长入口——货架与节点共享保底计数;判定含 pity 记账,替换末位占一席。 + # T5 专长凭证注入(非 Boss 渠道唯一专长入口——货架与节点共享保底计数;判定含 pity 记账,替换末位占一席。 # 取数复用本函数 shop_draw scope 的 stream——零新 scope,确定性序列不漂移) if _pool_ticket.is_valid() and not _shop_shelf.is_empty() and bool(_pool_ticket.call(stream)): - _shop_shelf[_shop_shelf.size() - 1] = {"kind": "feat_ticket", "tier": "excellent"} # 门票占位档名 = excellent + _shop_shelf[_shop_shelf.size() - 1] = {"kind": "feat_ticket", "tier": "excellent"} # 专长凭证占位档名 = excellent # 商店渠道无专长直接投放(渠道白名单:商店渠道只出属性值提升+资源,专长在非 Boss - # 渠道只以门票形态出现——奇物.md v2.7/A4 断言;专长商店入口=T5 门票)。 + # 渠道只以专长凭证形态出现——奇物.md v2.7/A4 断言;专长商店入口=T5 专长凭证)。 # 库存余量(TP0——令牌库内该 kind 剩余枚数单点读;未注入/防御读 = 0) diff --git a/game/core/minesweeper_rules.gd b/game/core/minesweeper_rules.gd index 3da13158..2db833ac 100644 --- a/game/core/minesweeper_rules.gd +++ b/game/core/minesweeper_rules.gd @@ -123,7 +123,7 @@ func install_board(b: BoardData, during_round := false) -> Dictionary: _spawn = {} for c in b.spawn_cells(): _spawn[c] = true - # 初始展开:O₀ = R₀ 恰等(免费/计入清图/无格面资源/永不触雷);板级一次跨轮不重放 + # 初始展开:O₀ = R₀ 恰等(免费/计入清图/无格面资源/永不触雷);整图一次跨轮不重放 for c in _initial_expansion_order(b): _revealed[c] = {"kind": "safe", "digit": b.digit_of(c)} cell_revealed.emit({ diff --git a/game/core/settlement/grant_segment.gd b/game/core/settlement/grant_segment.gd index fe6a4d9a..59a0bc30 100644 --- a/game/core/settlement/grant_segment.gd +++ b/game/core/settlement/grant_segment.gd @@ -296,10 +296,6 @@ func _judge_seal(evt: Dictionary, ri: int) -> void: if oc._seal_miss_seen.has(cell): return # 每格实例一次去重(归因行与负向兑付同键——防逐轮惩罚轰炸) oc._seal_miss_seen[cell] = true - var hl := "" - if oc._perfect_hit_false == 1: - hl = "perfect_broken" # 本板完美谓词已破的归因锚 - oc._emit_row("seal_miss", "seal_miss", cell, ri, "封印未中", 0, {}, hl) # 危险直觉·守挂点(seal_missed 发射:契约 12 触发主语=「当回合发生的标错 # 动作」——去重闸=新旧标错判别器〔后续轮重判旧封印被闸挡回零触发〕;双条件②「结算时封印仍在 # 场」由发射面既有过滤承载〔被挖开的封印已随挖掘擦除零兑付〕;grant_ap mode:queue 下一轮 @@ -315,6 +311,8 @@ func _judge_seal(evt: Dictionary, ri: int) -> void: _apply_counter_hit(h) # 豁免同时记账(insurance_used battle 域——下次标错 when lt 1 不再命中) oc._emit_row("insurance_used", "seal_miss", cell, ri, "完美保险·标错豁免", 0, {"forgiven": oc._perfect_forgiven}, "") + var hl := "perfect_broken" if oc._perfect_hit_false - oc._perfect_forgiven == 1 else "" + oc._emit_row("seal_miss", "seal_miss", cell, ri, "封印未中", 0, {}, hl) var snap = oc._reward_economy.grant(cell) if not (snap is Dictionary): return diff --git a/game/core/treasure_items.gd b/game/core/treasure_items.gd index 6f39db90..e3ec1fc6 100644 --- a/game/core/treasure_items.gd +++ b/game/core/treasure_items.gd @@ -1,5 +1,5 @@ ## VERTICAL SLICE - NOT FOR PRODUCTION -## 秘宝关卡域库存+板级叠加层:全程零随机零特判,同操作序列重放库存与叠加层投影逐位相同(垂直切片验证:道具全程确定性)。 +## 秘宝关卡域库存+整图叠加层:全程零随机零特判,同操作序列重放库存与叠加层投影逐位相同(垂直切片验证:道具全程确定性)。 ## Used 不可逆——consume 后保留只读,枚举序=受理序;库存关卡域跨战斗延续、关卡末清空,叠加层随图消亡(清空编排归调用方,本类只供 clear/reset/retire_overlays)。 ## 零特判纪律:本类不写任何其他系统状态,排雷玩法代码零本系统分支;相位检查归战斗编排 use_treasure——validate_use 是纯谓词零消耗。 class_name TreasureItems @@ -38,7 +38,7 @@ func add_item(item_id: String, source_class: String, cell: Vector2i, round_index # ---- 库存读面(C 区槽位常读)---- -# 枚举序=受理序;Used 保留只读;逐件含 usable 板级零信息预判(调用方喂板面回调) +# 枚举序=受理序;Used 保留只读;逐件含 usable 整图零信息预判(调用方喂板面回调) func query_inventory(board_has_preview_info: Callable) -> Array: var out: Array[Variant] = [] for rec in _items: @@ -54,13 +54,13 @@ func inventory_count() -> int: # 持有数(同调位上限判定读数:只计未消耗件;Used 不可逆即不再持有) # 同调位守卫谓词(读取源 transitional_sync_slots 过渡键已随表退役; -# 容量闸正主 = 营地装配面 Attunement.slots 满位禁选。函数体保留空壳防四散引用误删遗漏—— +# 容量闸现行事实源 = 营地装配面 Attunement.slots 满位禁选。函数体保留空壳防四散引用误删遗漏—— # 冒烟「过渡键读取点归零」断言覆盖) # 持有件记录(奖励节点替换子交互数据源:只列未消耗件,handle 定位丢弃目标) # 丢弃(同调位替换交互节点渠道——腾位收新;与 Used 消费分轨的一次性移除,快照不再含) -# 板级零信息可用性预判(图标置灰/入口禁用判据——GDD「整张图都没东西可看」级): +# 整图零信息可用性预判(图标置灰/入口禁用判据——GDD「整张图都没东西可看」级): # 真视恒可用(零雷窗口=信息非空);AP 类恒可用(组合判据取 OR——任一效果有信息即可用); # 纯预读行 = 板上还有未开格才可用。(积点件不入使用面——自动兑付无玩家入口) func _usable_now(item_id: String, board_has_preview_info: Callable) -> bool: diff --git a/game/data/schemas/adventure_table.gd b/game/data/schemas/adventure_table.gd index 68e8f0bd..3bb3bcaf 100644 --- a/game/data/schemas/adventure_table.gd +++ b/game/data/schemas/adventure_table.gd @@ -89,12 +89,12 @@ const TIER_QUOTAS := {"common": 70, "excellent": 25, "rare": 7, "legendary": 0} @export var curio_cap_rap: int = 99 # [1,99] @export var curio_cap_time_sand: int = 99 # [1,99] -# —— 专长获取门票(非 Boss 渠道的专长入口形态,奇物.md v2.7 渠道轴定位; +# —— 专长获取专长凭证(非 Boss 渠道的专长入口形态,奇物.md v2.7 渠道轴定位; # 四口径契约④:拿到即开不可囤积/罕见只在概率不在价格/一局限购一次/计步保底连续 5 展示未出 # 第 6 必出(计数=展示次数、刷新重展计入、节点与商店共享、触发清零、限购满不再触发)。 # 四参数全部 provisional 归曲线调参;limit/pity_step 系口径定死值,调参可复议)—— -@export var feat_ticket_chance: int = 20 # [0,100] knob(provisional)——每次非 Boss 渠道展示门票出现概率 % -@export var feat_ticket_quota: int = 2 # [0,9] knob(provisional)——每局门票出现次数上限 +@export var feat_ticket_chance: int = 20 # [0,100] knob(provisional)——每次非 Boss 渠道展示专长凭证出现概率 % +@export var feat_ticket_quota: int = 2 # [0,9] knob(provisional)——每局专长凭证出现次数上限 @export var feat_ticket_limit: int = 1 # [1,9] knob(口径定死=1)——一局限购(选中/买下)次数 @export var feat_ticket_pity_step: int = 5 # [1,99] knob(口径定死=5)——保底步数(连续未出展示次数) diff --git a/game/data/schemas/settlement_table.gd b/game/data/schemas/settlement_table.gd index 96c80217..52191dea 100644 --- a/game/data/schemas/settlement_table.gd +++ b/game/data/schemas/settlement_table.gd @@ -5,7 +5,7 @@ class_name SettlementTable extends Resource @export var equivalence_ref_damage: int = 12 # [1,999] knob——当量参考敞口 D_ref -@export var p_perfect: int = 200 # {100,200} percent——完美排雷第二份兑付触发(载体域) +@export var p_perfect: int = 200 # {100,200} percent——完美封印第二份兑付触发(载体域) @export var seal_hit_premium: int = 100 # [100,999] percent knob——封印命中兑付溢价 ×(1+(n−100)/100):125=×1.25(条款3 条件二封印溢价形态 a,provisional);100=无溢价直通零扰动。只乘封印命中正向兑付(flat power/percent 幅度/gp 缓冲三形态),标空/挖格/清图不乘;雷安同池冻结不动 @export var segment_order: PackedStringArray = [] # 结构冻结——段序恒等校验违例致命 @export var source_label_map: Dictionary[String, Variant] = {} # 结构冻结——source_class→文案键 diff --git a/game/data/schemas/shop_table.gd b/game/data/schemas/shop_table.gd index ef07d5b1..4868d8da 100644 --- a/game/data/schemas/shop_table.gd +++ b/game/data/schemas/shop_table.gd @@ -15,7 +15,7 @@ extends Resource const GP_TIERS := ["normal", "elite", "boss"] const PRODUCT_ATTRS := ["atk", "max_hp", "armor_class"] -const SHELF_KINDS := ["attack", "max_hp", "armor", "ap", "feat_ticket", "heal"] # 货架候选词表(四切边后种 + 门票行 + heal 补回复〔默认原则:分类内成员都入该渠道池〕) +const SHELF_KINDS := ["attack", "max_hp", "armor", "ap", "feat_ticket", "heal"] # 货架候选词表(四切边后种 + 专长凭证行 + heal 补回复〔默认原则:分类内成员都入该渠道池〕) func validate() -> Array: diff --git a/game/data/schemas/variation_table.gd b/game/data/schemas/variation_table.gd index b88bd5da..65c4c7b6 100644 --- a/game/data/schemas/variation_table.gd +++ b/game/data/schemas/variation_table.gd @@ -17,7 +17,7 @@ const SCOPES := ["region", "global"] # resource_face = 资源面偏斜(全局作用域变异——整图修摇号分布:生存族按 effect_value% # 下调、进攻族等比上浮重归一,不动任何格子数据;effect_value 语义随行域切换,不适用 flat_damage [1,9]) const EFFECTS := ["none", "flat_damage", "hide_number", "resource_face"] # 效果词表:直伤 / 数字遮蔽 / 资源面偏斜(可扩充) -const TRIGGERS := ["on_open", "on_number_shown", "always"] # 触发词表:被打开即触发 / 打开且显示数字时触发 / 板级恒在无触发时机(可扩充) +const TRIGGERS := ["on_open", "on_number_shown", "always"] # 触发词表:被打开即触发 / 打开且显示数字时触发 / 整图恒在无触发时机(可扩充) const PLACEMENTS := ["closed_only", "any"] # 布置约束词表:只落布置时未开格 / 任意格(可扩充) @@ -76,7 +76,7 @@ func validate() -> Array: if row.get("placement", "") != "any": errs.append({"category": "cross_field", "message": "%s scope=global ⇒ placement 必为 any(整图无格子布置域)" % vid}) if row.get("trigger", "") != "always": - errs.append({"category": "cross_field", "message": "%s scope=global ⇒ trigger 必为 always(板级恒在,无触发时机)" % vid}) + errs.append({"category": "cross_field", "message": "%s scope=global ⇒ trigger 必为 always(整图恒在,无触发时机)" % vid}) return errs diff --git a/game/data/tables/shop.tres b/game/data/tables/shop.tres index 52e0fa16..f5af6c56 100644 --- a/game/data/tables/shop.tres +++ b/game/data/tables/shop.tres @@ -101,7 +101,7 @@ price_b = 1.1 ; (4+2)+(2+2)+(4+2)=16、全购欲望 ≈ 26–34——取舍空间成立;量级与方差全部 provisional-pending-曲线调参批 ;(用户拍板骨架先行、数值整体后置,行值归 难度曲线与Boss)。 ; GP 商店房重构批(M-4 迭代 11 第②批 T1,2026-10-03——需求卡片 v1.3 全裁 P1 共享池/P4 ceil/P5 甲): -; pool_shelf 行族 = 共享池货架(kind_id 词表 attack/max_hp/armor/ap/feat_ticket/heal 六行——heal 系 T6 商店补回复〔默认原则:分类内成员都要在它该出现的渠道池里,现行缺〕、GP 袋负交易切边计价物不自售、feat_ticket 系 T5 门票行〔非 Boss 渠道专长入口,价与其他商品相当=契约④口径②〕、 +; pool_shelf 行族 = 共享池货架(kind_id 词表 attack/max_hp/armor/ap/feat_ticket/heal 六行——heal 系 T6 商店补回复〔默认原则:分类内成员都要在它该出现的渠道池里,现行缺〕、GP 袋负交易切边计价物不自售、feat_ticket 系 T5 专长凭证行〔非 Boss 渠道专长入口,价与其他商品相当=契约④口径②〕、 ; 规则改写型特性三轴 doctrine 切边;库存=上限即库存,账本在 冒险结构 _bonus_taken 单点共享,行族不记库存); ; 价格公式换代(pool 模式)= ceil(base_price × b^(关序−1) × A^(本次进店已购次数)),price_a=1.8/price_b=1.1 ; provisional 投值(零人工令改 provisional+后置追认,原 P5 甲研究拍板后置);products 行族 + 加法定价 diff --git a/game/presentation/curio_interact_controller.gd b/game/presentation/curio_interact_controller.gd index f40874d3..25710a56 100644 --- a/game/presentation/curio_interact_controller.gd +++ b/game/presentation/curio_interact_controller.gd @@ -86,7 +86,7 @@ func _skip_empty_stop() -> bool: # 增量行在其上),确认后进三选一面(level-clear.md v2);续玩停点恢复同入口(零自动推进契约) func on_presented(payload: Dictionary) -> void: if String(payload.get("context", "")) == "feat_ticket": - # T5 店内门票兑付——临时停点开专长三选一面(零胜利总结面;确认后只关面回店) + # T5 店内专长凭证兑付——临时停点开专长三选一面(零胜利总结面;确认后只关面回店) _pending_curio = payload.duplicate(true) _curio_context = "feat_ticket" if (_pending_curio.get("candidates", []) as Array).is_empty(): @@ -214,7 +214,7 @@ func on_pick_confirmed(item_id: String) -> void: if not ok: push_error("[bonus_interact] 三选一兑付被拒——见输出日志") return - # T5——节点渠道门票拿到即开:候选已被替换为专长面,本地读在途态重绘(零 emit——context 保持 reward_node, + # T5——节点渠道专长凭证拿到即开:候选已被替换为专长面,本地读在途态重绘(零 emit——context 保持 reward_node, # 后续兑付/确认仍走节点路径回图选路) if _curio_context == "reward_node" and kind == "feat_ticket": var st2: Dictionary[Variant, Variant] = adventure.node_curio_pending_state() @@ -234,7 +234,7 @@ func on_continue() -> void: curio_overlay.close_pick() var adventure = _adventure_get.call() if _curio_context == "feat_ticket": - return # T5 店内门票面——专长兑付完成后关面回店(无推进/无回图) + return # T5 店内专长凭证面——专长兑付完成后关面回店(无推进/无回图) if _curio_context == "reward_node": var runner = _runner_get.call() if runner != null: diff --git a/game/presentation/hud_presenter.gd b/game/presentation/hud_presenter.gd index 0ead2a5b..2ce1214f 100644 --- a/game/presentation/hud_presenter.gd +++ b/game/presentation/hud_presenter.gd @@ -37,7 +37,7 @@ static func refresh(stage: BattleStageView, info: HeroInfoPanelView, ap_bar: ApB _refresh_out_of_battle(stage, info, ap_bar, runner, level_active, db) return var s: Dictionary[Variant, Variant] = settlement.presentation_snapshot() - # 地形变异常驻角标投影(板级变异快照 → 文案行; + # 地形变异常驻角标投影(整图变异快照 → 文案行; # 空态隐藏=特性段先例;战斗全程常驻防中局遗忘) info.set_board_variants(board_variant_lines(db, s.get("board_variants", []))) var hero: Dictionary[Variant, Variant] = s.hero @@ -102,7 +102,7 @@ static func feat_holdings_lines(db, held: Array) -> Array[String]: return rlines -# 地形变异常驻角标文案(板级变异 id → 文案行; +# 地形变异常驻角标文案(整图变异 id → 文案行; # 空集 = 空数组=空态隐藏。三行制:变异名+两行效果说明(C 区 240px 宽防裁切)。 # 文案用常规表述,不用俚语 static func board_variant_lines(db, ids: Array) -> Array[String]: diff --git a/game/presentation/main.gd b/game/presentation/main.gd index c8fe9a97..42bcc882 100644 --- a/game/presentation/main.gd +++ b/game/presentation/main.gd @@ -911,7 +911,7 @@ func _on_round_started(ri: int) -> void: # 巢穴预告呈现(装板报数量读数口消费:≥0=本战装配命中,toast 一次性提示) if run_scope.settlement != null and int(run_scope.settlement.nest_preview_count) >= 0: board_zone.toast.show_toast("巢穴预告——本板危险格共 %d 个" % int(run_scope.settlement.nest_preview_count), "info") - # 开战横幅——板级地形变异预告:首轮快照 board_variants + # 开战横幅——整图地形变异预告:首轮快照 board_variants # 非空才发射(Boss 图恒带一型=替换制;普通图空快照零发射);轮横幅下方叠行,view 内判减动效。 if ri == 1 and run_scope.settlement != null: var bvs: Array[Variant] = run_scope.settlement.presentation_snapshot().get("board_variants", []) diff --git a/game/presentation/row_pacer.gd b/game/presentation/row_pacer.gd index d5ca6037..fb70ea59 100644 --- a/game/presentation/row_pacer.gd +++ b/game/presentation/row_pacer.gd @@ -89,7 +89,7 @@ func _consume_row(row: Dictionary) -> void: stage.on_step_row_fx(row) _play_cross_zone_fx(row) # 跨区因果演出(结算演出链批):开格之因 → 站桩之果 _play_settlement_mark(row) # 三轮 #3——逐条标出:Buff/Debuff 色环脉冲 → 伤害/治疗数字浮现 - # 高光演出(战斗结算×3①② 占位):完美排雷横幅 / 封印命中加重弹道 + # 高光演出(战斗结算×3①② 占位):完美封印横幅 / 封印命中加重弹道 if String(row.get("type", "")) == "highlight" and String(row.get("highlight", "")) != "skill_unlock": board_zone.fx.play_perfect_sweep() elif String(row.get("highlight", "")) == "seal_hit": diff --git a/game/presentation/treasure_interact_controller.gd b/game/presentation/treasure_interact_controller.gd index cafc6cc4..2c3084b8 100644 --- a/game/presentation/treasure_interact_controller.gd +++ b/game/presentation/treasure_interact_controller.gd @@ -98,7 +98,7 @@ func attempt_use(handle: int, cell: Variant = null) -> void: toast.show_toast("已使用 %s" % String(arow.get("display_name", "")), "info") -# 库存投影(C 区四槽取数面——字形=名首字;usable=板级零信息预判回调接排雷玩法只读面) +# 库存投影(C 区四槽取数面——字形=名首字;usable=整图零信息预判回调接排雷玩法只读面) func inventory_projection() -> Array: var runner = _runner_get.call() if runner == null or runner.treasure_inventory == null: diff --git a/game/presentation/views/battle_log_view.gd b/game/presentation/views/battle_log_view.gd index 446126d4..905e7cf4 100644 --- a/game/presentation/views/battle_log_view.gd +++ b/game/presentation/views/battle_log_view.gd @@ -189,7 +189,12 @@ func _format_row(row: Dictionary, agg_count := -1) -> String: var n := (" ×%d" % agg_count) if agg_count > 1 else "" return prefix + "[s][color=#%s]⚠ %s%s[/color][/s]%s" % [UiKit.HEX_LOG_VOIDED, name_, n, suffix] "seal_miss": - var body := "✗ %s%s" % [name_, "(本板完美排雷已破——归因此封印)" if hl == "perfect_broken" else ""] + var miss_note := "" + if hl == "perfect_broken": + miss_note = "(本图完美封印已破——清图奖励不再加倍)" + elif hl == "": + miss_note = "(首次封印落空已豁免——不计入完美封印判定)" + var body := "✗ %s%s" % [name_, miss_note] return prefix + (_gold_frame(body) if hl == "perfect_broken" else "[color=#%s]%s[/color]" % [UiKit.HEX_LOG_ROUND, body]) "cast": # 施放行:增益技 0 伤害施放,具名技能 diff --git a/game/presentation/views/board_cell_unit.gd b/game/presentation/views/board_cell_unit.gd index a704d60a..31d1ac24 100644 --- a/game/presentation/views/board_cell_unit.gd +++ b/game/presentation/views/board_cell_unit.gd @@ -94,7 +94,7 @@ var facade_strip := false: # E 格开关(BoardView paint 按「已开 # 变异角标(程序化,tex_mutation 纹带槽暂留): # "flat_damage" = 未开格伤害型变异,左下角危险红三角(开格有代价的策略纹理标记) -# 叠加层标记(秘宝板级叠加层的格面呈现;派生信息层零回写): +# 叠加层标记(秘宝整图叠加层的格面呈现;派生信息层零回写): # "mine_reveal" = 真视格(危险红内缩框——「这格是雷」的确定决策标记,封印照常计费); # "reward_preview" 格不复用本字段——预读徽章走 badge_glyph 注入(board_view refresh 注入 REWARD_BADGE 字形) var treasure_mark := "": @@ -108,8 +108,8 @@ var mutation_mark := "": mutation_mark = v queue_redraw() -# ── 视野迷雾呈现态(纯呈现零逻辑;规格=art-bible §6.5 v3.5,正主=HUD框架「视野迷雾」节)── -# 0=正常(灯光区内)/ 1=全黑(区外未开格——正主「区外未开格=全黑不渲染」不透明档)/ 2=记忆态(区外已开格灰显可读) +# ── 视野迷雾呈现态(纯呈现零逻辑;规格=art-bible §6.5 v3.5,现行事实源=HUD框架「视野迷雾」节)── +# 0=正常(灯光区内)/ 1=全黑(区外未开格——现行事实源「区外未开格=全黑不渲染」不透明档)/ 2=记忆态(区外已开格灰显可读) var fog_state := 0: set(v): if fog_state != v: diff --git a/game/presentation/views/board_fx_view.gd b/game/presentation/views/board_fx_view.gd index 0013ec8a..5fc47c7a 100644 --- a/game/presentation/views/board_fx_view.gd +++ b/game/presentation/views/board_fx_view.gd @@ -1,5 +1,5 @@ ## VERTICAL SLICE - NOT FOR PRODUCTION -## D 区演出层:清图喷泉/Boss 影子/完美排雷光带/封印命中弹道/挥铲三帧等一次性占位演出。 +## D 区演出层:清图喷泉/Boss 影子/完美封印光带/封印命中弹道/挥铲三帧等一次性占位演出。 ## 组合根按核心信号直调 play_*;素材缺位静默回退(演出层不设断言面)。 class_name BoardFxView extends Control @@ -87,7 +87,7 @@ func play_boss_shadow() -> void: tw.tween_callback(shadow.queue_free) -# 完美排雷:金光带加倍扫射 + 横幅占位(§2.2 最高档) +# 完美封印:金光带加倍扫射 + 横幅占位(§2.2 最高档) func play_perfect_sweep() -> void: for i in 2: var band := ColorRect.new() @@ -99,7 +99,7 @@ func play_perfect_sweep() -> void: var tw := band.create_tween() tw.tween_property(band, "position:x", size.x + 8.0, UiKit.motion(0.5 + 0.15 * i)) tw.tween_callback(band.queue_free) - _show_banner("完美排雷 ×2") + _show_banner("完美封印 ×2") # 封印命中:封印化暴击弹道加重占位(自棋盘上缘飞向 B 区敌人卡方向——越界即收) diff --git a/game/presentation/views/board_view.gd b/game/presentation/views/board_view.gd index 72835d61..88e2d230 100644 --- a/game/presentation/views/board_view.gd +++ b/game/presentation/views/board_view.gd @@ -117,7 +117,7 @@ var _digit_dark_ink := true # 数字墨族按板自适应(true=深墨 var _digit_plate := false # 数字色牌垫底模式(双峰纹理板——直画两族皆不过门槛时落牌, # 素牌+深墨 12:1 纹理免疫;渲染帧取证 underdark 系深墨直画隐形,故启用色牌) -# ---- 视野迷雾(纯呈现层;正主=HUD框架「视野迷雾」节 v0.13,渲染规格=art-bible §6.5 v3.5)---- +# ---- 视野迷雾(纯呈现层;现行事实源=HUD框架「视野迷雾」节 v0.13,渲染规格=art-bible §6.5 v3.5)---- const FOG_RADIUS := 8 # 菱形灯光区基准半径(曼哈顿距离 ≤R——与微光环「周围 8 格」同圈起步;半径基准值改动=非白名单须用户) var _fog_enabled := true # 迷雾开关(呈现态布尔——真实游戏恒 on;探针/夹具可 off=无迷雾基线,两态结算逐位一致断言面) var _fog_lantern := 0 # 视野加成现值(缺省 0=无加成基线零扰动;生产写入面=组合根每战装配链显式重算——main._sync_treasure_glow) @@ -142,7 +142,7 @@ func _init() -> void: add_child(_wrap) _svp_container = SubViewportContainer.new() _svp_container.stretch = true # 容器尺寸 = 视口逻辑分辨率(_update_world_size 同步)——恒 1:1 无缩放 - _svp_container.mouse_filter = Control.MOUSE_FILTER_IGNORE # 输入归壳层 _gui_input(板级公式换算),不进 SubViewport + _svp_container.mouse_filter = Control.MOUSE_FILTER_IGNORE # 输入归壳层 _gui_input(整图公式换算),不进 SubViewport _wrap.add_child(_svp_container) _viewport = SubViewport.new() _viewport.transparent_bg = true # 格间距露出 D 区底色 @@ -502,7 +502,7 @@ func click_cell(cell: Vector2i, button: int) -> void: _on_cell_input(cell, ev) -# 板级公式单点:格坐标 = floor(板内局部坐标 / 格步长) +# 整图公式单点:格坐标 = floor(板内局部坐标 / 格步长) #(格步长 = 格边长 + 间距;板外/负域返回 (-9,-9);2px 格间隙落入左/上邻格) func _cell_at(shell_pos: Vector2) -> Vector2i: if _board == null or _board.width == 0: @@ -534,7 +534,7 @@ func _update_world_size() -> void: _viewport.size = px -# 真实输入路径(Node2D 迁移批 Decision 3):壳层 _gui_input → 板级公式换算 → 复用既有 hover/点选/chord 出口 +# 真实输入路径(Node2D 迁移批 Decision 3):壳层 _gui_input → 整图公式换算 → 复用既有 hover/点选/chord 出口 func _gui_input(ev: InputEvent) -> void: if _minesweeper == null: return @@ -832,7 +832,7 @@ func _paint_cell(c: Vector2i, hero: Vector2i) -> void: u.mutation_mark = "" u.badge_glyph = _update_badge(c) u.glow_group = int(_glow.get(c, UiKit.GLOW_NONE)) - # 视野迷雾呈态:曼哈顿距离 > 半径 → 区外——未开格全黑(正主照抄)/ + # 视野迷雾呈态:曼哈顿距离 > 半径 → 区外——未开格全黑(现行事实源照抄)/ # 已开格记忆态(灰显可读);以英雄格为心逐格重算,refresh()/notify_hero_move() 既有重绘驱动=移动实时跟随。 # 纯呈现零逻辑——格态/数字真值/清图判定零触碰(🔴 契约 1);结算期去饱和叠加互斥由 CellUnit 记忆态终态档承载。 if _fog_enabled: diff --git a/game/presentation/views/curio_pick_overlay.gd b/game/presentation/views/curio_pick_overlay.gd index 6e3cd430..13dd1c91 100644 --- a/game/presentation/views/curio_pick_overlay.gd +++ b/game/presentation/views/curio_pick_overlay.gd @@ -107,7 +107,7 @@ func open_pick(header: String, cards: Array) -> void: _confirm_btn.visible = false _continue_btn.visible = false _foot_hint.visible = true # T7 底注=pick 态专属(result 态让位) - _refresh_btn.visible = false # 刷新面随 set_refresh_display 投喂后现形(open 先归零防残留;店内门票面不投喂=无刷新) + _refresh_btn.visible = false # 刷新面随 set_refresh_display 投喂后现形(open 先归零防残留;店内专长凭证面不投喂=无刷新) _refresh_l.text = "" visible = true diff --git a/game/presentation/views/hero_info_panel_view.gd b/game/presentation/views/hero_info_panel_view.gd index d94c7139..a7465d05 100644 --- a/game/presentation/views/hero_info_panel_view.gd +++ b/game/presentation/views/hero_info_panel_view.gd @@ -117,7 +117,7 @@ func set_feat_holdings(lines: Array) -> void: _feat_section.visible = not lines.is_empty() -# 地形变异常驻角标:lines = 文案行(板级变异 display_name+体感短语)——空数组 = 整节隐藏 +# 地形变异常驻角标:lines = 文案行(整图变异 display_name+体感短语)——空数组 = 整节隐藏 func set_board_variants(lines: Array) -> void: for c3 in _board_variant_list.get_children(): _board_variant_list.remove_child(c3) @@ -157,7 +157,7 @@ func _data_line() -> Label: # ---- 秘宝库存条(C 区四槽常读+两步交互第一步)---- # 投影行 = {handle, glyph, name, used, usable}(组合根组装:字形=道具名首字;数据源 runner 级库存只读面)。 -# 空槽=虚位;used=暗态「已用」保留占位(Used 不可逆——受理序展示语义);不可用=置灰(板级零信息); +# 空槽=虚位;used=暗态「已用」保留占位(Used 不可逆——受理序展示语义);不可用=置灰(整图零信息); # selected=金框高亮(两步交互第一步的可见态)。tooltip=全名+维度语义。 func set_treasure_inventory(items: Array, selected_handle: int) -> void: _selected_handle = selected_handle diff --git a/game/presentation/views/settlement_fx_view.gd b/game/presentation/views/settlement_fx_view.gd index 5881d2ba..6f02d2b3 100644 --- a/game/presentation/views/settlement_fx_view.gd +++ b/game/presentation/views/settlement_fx_view.gd @@ -11,7 +11,7 @@ func _init() -> void: # 结算轮光带:金橙半透明横带自棋盘上缘扫至下缘(一次 0.5s,自动回收)—— -# "棋盘能量向战斗画面汇聚"的开轮语义(§2.2 色彩转金橙主导;区分于 board_fx 的完美排雷金光带)。 +# "棋盘能量向战斗画面汇聚"的开轮语义(§2.2 色彩转金橙主导;区分于 board_fx 的完美封印金光带)。 # 终稿(样张 v2 冻结批 T3):加 2px 亮金前导缘线——扫带运动方向可读(兑现光带逐行横扫 §2.2) func play_round_sweep(board_rect: Rect2) -> void: if board_rect.size == Vector2.ZERO: @@ -143,7 +143,7 @@ func play_round_banner(ri: int) -> void: tw.tween_callback(banner.queue_free) -# 开战横幅——板级地形变异预告:board_variants 非空时开战 +# 开战横幅——整图地形变异预告:board_variants 非空时开战 # 显示一行(文本=「地形变异 · 贫矿脉」式);减动效=静态驻留后即隐(轮横幅先例——行呈现不跳过)。 # 文案/驻留参数 provisional 归本地化批;普通图恒不发射(组合根按快照 board_variants 空判)。 func play_board_variant_banner(text: String) -> void: diff --git a/game/smoke/board_shot_probe.gd b/game/smoke/board_shot_probe.gd index 3c0688a6..0080a3f4 100644 --- a/game/smoke/board_shot_probe.gd +++ b/game/smoke/board_shot_probe.gd @@ -28,7 +28,7 @@ var _cur_settlement = null # 当关 settlement(身份回调读取面—— func _ready() -> void: # 运行前提=窗口化真渲染面(shot_probe 同款护栏——headless 下 frame_post_draw 永不触发+视口纹理恒空) if DisplayServer.get_name() == "headless": - print("[board_shot] FAIL — 本探针必须窗口化运行(headless 无渲染面,截图必空);正主=tools/render_gate.sh 取证段") + print("[board_shot] FAIL — 本探针必须窗口化运行(headless 无渲染面,截图必空);现行事实源=tools/render_gate.sh 取证段") get_tree().quit(1) return var args := OS.get_cmdline_user_args() diff --git a/game/smoke/layout_probe.gd b/game/smoke/layout_probe.gd index a87e0665..f354b53f 100644 --- a/game/smoke/layout_probe.gd +++ b/game/smoke/layout_probe.gd @@ -1,5 +1,5 @@ # VERTICAL SLICE - NOT FOR PRODUCTION -# 布局几何断言探针(正主=tools/probe_gate.sh 默认段;呈现层三区布局的分辨率维度验收) +# 布局几何断言探针(现行事实源=tools/probe_gate.sh 默认段;呈现层三区布局的分辨率维度验收) # 用途:battle.md §验收「1280×800 与 16:9 全屏下三区无遮挡/无重叠/无裁切」的可执行化 # GDD 锚:design/gdd/ux/battle.md §Layout Zones(B/C/D 三区几何) # 硬约束:档位表是数据、断言是一份函数据——加档只改表不动断言(禁每档建一个探针) diff --git a/game/smoke/level_autoplay.gd b/game/smoke/level_autoplay.gd index 01db2653..4834acc2 100644 --- a/game/smoke/level_autoplay.gd +++ b/game/smoke/level_autoplay.gd @@ -222,7 +222,7 @@ static func _on_adventure_node_entered(node: Dictionary, info: Dictionary, adr, adr.present_node_curio(ncands) var npick: Dictionary = _pick_token(ncands, String(st.get("feat_mode", "off"))) if adr.apply_node_curio(String(npick.get("kind", "")), String(npick.get("tier", "")), String(npick.get("feat_id", ""))): - # 门票拿到即开——候选已被替换为专长三选一,就地再选一轮(确定性策略同款 316-f); + # 专长凭证拿到即开——候选已被替换为专长三选一,就地再选一轮(确定性策略同款 316-f); # 不作此分支则节点停点悬空→选路卡死(MC timeout 形态) if String(npick.get("kind", "")) == "feat_ticket": var fcands: Array = (adr.node_curio_pending_state().get("candidates", []) as Array) diff --git a/game/smoke/shot_probe.gd b/game/smoke/shot_probe.gd index 09d6e3ab..8abd3cd8 100644 --- a/game/smoke/shot_probe.gd +++ b/game/smoke/shot_probe.gd @@ -1,6 +1,6 @@ # VERTICAL SLICE - NOT FOR PRODUCTION # 整屏截图探针(呈现层测试分级 B 档基建:视口截图程序化产出;七屏—— -# 菜单/设置面/生涯页/营地/关卡画面/战斗/状态面板,正主=tools/render_gate.sh)。 +# 菜单/设置面/生涯页/营地/关卡画面/战斗/状态面板,现行事实源=tools/render_gate.sh)。 # 必须**窗口化**运行(真渲染设备——headless 无渲染面,get_image 得到空纹理): # Godot_console.exe --path . res://smoke/shot_probe.tscn -- <输出目录> # 流程 = 真实按钮信号路径驱动(ui_click_probe 同款;存档/设置/元进度三面换注隔离档——禁碰真实档, @@ -25,7 +25,7 @@ var _meta := {} # 控件实测几何(全局 rect——shot_checker 文字框 func _ready() -> void: # 运行前提=窗口化真渲染面:headless 下 frame_post_draw 永不触发+视口纹理恒空——无此守卫时 headless 调用方必挂死 if DisplayServer.get_name() == "headless": - print("[shot_probe] FAIL — 本探针必须窗口化运行(headless 无渲染面,截图必空);headless 自动闸禁跑本探针(正主=tools/probe_gate.sh)") + print("[shot_probe] FAIL — 本探针必须窗口化运行(headless 无渲染面,截图必空);headless 自动闸禁跑本探针(现行事实源=tools/probe_gate.sh)") get_tree().quit(1) return var args := OS.get_cmdline_user_args() diff --git a/game/smoke/smoke_all.gd b/game/smoke/smoke_all.gd index 902d50d2..8f74b2aa 100644 --- a/game/smoke/smoke_all.gd +++ b/game/smoke/smoke_all.gd @@ -1357,15 +1357,15 @@ func _smoke_feats() -> void: if String((t as Dictionary).get("kind", "")) == "relic": node_relic_seen = true check(feat_seen.size() >= 2, "通关渠道只出专长(60 次重抽 ≥2 种不同 relic——身份键 feat_id 同档可多件)") - check(not node_relic_seen, "节点渠道零专长(60 次重抽零 relic——专长在非 Boss 渠道只以门票形态出现)") - # T5 门票行为断言(A5 拿到即开 / A6 保底计数——契约④四口径;独立 runner 防污染 a_r 牌库) + check(not node_relic_seen, "节点渠道零专长(60 次重抽零 relic——专长在非 Boss 渠道只以专长凭证形态出现)") + # T5 专长凭证行为断言(A5 拿到即开 / A6 保底计数——契约④四口径;独立 runner 防污染 a_r 牌库) var a_t = load("res://core/adventure_runner.gd").new(_db, _fresh_rng(91)) a_t.start_adventure(91, {"first_script": true}) var stock_before := {} for kk in ["attack", "gp", "heal"]: stock_before[kk] = a_t.pool_stock(kk) a_t._node_curio_pending = {"candidates": [{"kind": "feat_ticket", "tier": "excellent"}, {"kind": "attack", "tier": "common"}]} - check(a_t.apply_node_curio("feat_ticket", "excellent"), "A5 门票兑付受理(节点渠道——拿到即开)") + check(a_t.apply_node_curio("feat_ticket", "excellent"), "A5 专长凭证兑付受理(节点渠道——拿到即开)") var tkt_cands: Array = (a_t.node_curio_pending_state().get("candidates", []) as Array) var tkt_all_relic := tkt_cands.size() > 0 for t in tkt_cands: @@ -1373,13 +1373,13 @@ func _smoke_feats() -> void: tkt_all_relic = false check(tkt_all_relic, "A5 拿到即开——停点候选已替换为专长三选一(全 relic)") check(a_t.pool_stock("attack") == int(stock_before["attack"]) and a_t.pool_stock("gp") == int(stock_before["gp"]), - "A5 零摘牌——门票兑付不动令牌库(不进持有集)") - check(not (a_t.feats_held() as Array).has("feat_ticket"), "A5 无门票残留持有集") + "A5 零摘牌——专长凭证兑付不动令牌库(不进持有集)") + check(not (a_t.feats_held() as Array).has("feat_ticket"), "A5 无专长凭证残留持有集") var feats_n := (a_t.feats_held() as Array).size() a_t.apply_node_curio("relic", String((tkt_cands[0] as Dictionary).get("tier", "rare")), String((tkt_cands[0] as Dictionary).get("feat_id", ""))) - check((a_t.feats_held() as Array).size() == feats_n + 1, "A5 专长面兑付受理(门票开出候选可正常入持有集)") + check((a_t.feats_held() as Array).size() == feats_n + 1, "A5 专长面兑付受理(专长凭证开出候选可正常入持有集)") # A6 保底:pity 直填 5 → 下次展示必出(第 6 次必出口径);限购满 → 恒不触发 - a_t._feat_ticket_sold = 0 # A5 已兑付一枚门票(sold=1=limit)——A6 段重置计数隔离验证 + a_t._feat_ticket_sold = 0 # A5 已兑付一枚专长凭证(sold=1=limit)——A6 段重置计数隔离验证 a_t._feat_ticket_pity = int(a_t.db.adventure.feat_ticket_pity_step) var rg_t: RandomNumberGenerator = a_t.rng.open_stream("reward_pick") check(a_t._feat_ticket_consider(rg_t), "A6 保底触发(pity=5 → 第 6 次展示必出——概率无关)") @@ -1841,7 +1841,7 @@ func _smoke_type_glow() -> void: check((snap.get("cells", {}) as Dictionary).size() == mapped - 1, "V2 清单外格剔除后作用集 = 派定数 −1(%d→%d)" % [mapped, (snap.get("cells", {}) as Dictionary).size()]) # ---- 相 3:封锁格(query 返回 null)⇒ 无微光且零登记 ---- - _glow_type_overrides.erase(bogus_cell) # 复位清单外(errors 保留=板级登记语义) + _glow_type_overrides.erase(bogus_cell) # 复位清单外(errors 保留=整图登记语义) var blocked_cell: Vector2i = hero for i in mini(assign.size(), nbs.size()): var nb4: Vector2i = nbs[i] @@ -2582,7 +2582,7 @@ func _smoke_global_variant() -> void: vt.rows.assign([{"variant_id": "g3", "display_name": "负丙", "unlock_level": 2, "scope": "global", "effect": "resource_face", "effect_value": 30, "trigger": "on_open", "placement": "any", "board_types": [], "counter_items": []}]) - check(_errs_has_cross_field(vt.validate()), "互锁负样本⑤:scope=global + trigger=on_open 被拒(global ⇒ always 板级恒在)") + check(_errs_has_cross_field(vt.validate()), "互锁负样本⑤:scope=global + trigger=on_open 被拒(global ⇒ always 整图恒在)") vt.rows.assign([{"variant_id": "g4", "display_name": "负丁", "unlock_level": 2, "scope": "global", "effect": "resource_face", "effect_value": 30, "trigger": "always", "placement": "closed_only", "board_types": [], "counter_items": []}]) @@ -2624,7 +2624,7 @@ func _smoke_global_variant() -> void: var boss1_calls := 0 if boss_ok: var bb = boss_settlement.minesweeper.current_board() - check(bb.board_variant_ids().is_empty(), "屏蔽后回落:Boss 图无板级全局型(board_variants 空——全局池空合法态)") + check(bb.board_variant_ids().is_empty(), "屏蔽后回落:Boss 图无整图全局型(board_variants 空——全局池空合法态)") var boss_vids := {} for vc in bb.variants: for vid in bb.variants[vc]: @@ -3497,7 +3497,7 @@ func _encounter_replay(seed_val: int) -> Array: # ==================== 清图奖励双份兑付链 / 轮内刷新 provenance 守卫 / 窗口锚行 ==================== -# 清图 = 全安全格开完。清图测试用"真雷封印(零误标→完美排雷)+ AutoPlayer 逐轮清图"真实流驱动; +# 清图 = 全安全格开完。清图测试用"真雷封印(零误标→完美封印)+ AutoPlayer 逐轮清图"真实流驱动; # DifficultyTable 注入 hp_mult=10 把 Boss 血量抬到 1500,保证清图批次发生在战斗结束之前(测试台账,跑完即还原)。 const CLEAR_SMOKE_DEPTH := 4 @@ -3506,11 +3506,11 @@ var _regular_clear_reward_rows := 0 # 常规(非刷新图)清图的 clear_ func _smoke_clear_reward_chain() -> void: - print("--- 清图奖励·双份兑付链(完美排雷 / 零兑付 / 第二份被拒 / 高光记实)---") - # ① 真实流完美排雷:标中一面真雷封印 + 零误标 + 清全图 → grant_clear 身份(clear_blast)双份真实兑付 + print("--- 清图奖励·双份兑付链(完美封印 / 零兑付 / 第二份被拒 / 高光记实)---") + # ① 真实流完美封印:标中一面真雷封印 + 零误标 + 清全图 → grant_clear 身份(clear_blast)双份真实兑付 var rows: Array = [] var run := _run_full_clear(20260915, false, rows) - check(bool(run.cleared), "① 完美排雷清图达成(%d 轮)" % int(run.rounds)) + check(bool(run.cleared), "① 完美封印清图达成(%d 轮)" % int(run.rounds)) var dmg := [] for r in rows: if String(r.get("type", "")) == "damage" and String(r.get("source_class", "")) == "clear_reward": @@ -4070,7 +4070,7 @@ func _drive_clear(settlement) -> Dictionary: if t.hero_cell != ms.hero_pos(): ms.settle_batch([{"action": "move", "cell": t.hero_cell}]) ms.settle_batch([{"action": "seal_place", "cell": t.seal_cell}]) - seal_done = true # 一面真雷封印 = 完美排雷前半(零误标),后半靠 AutoPlayer 清图 + seal_done = true # 一面真雷封印 = 完美封印前半(零误标),后半靠 AutoPlayer 清图 var seq_before: int = int(settlement.diagnostic_snapshot().board_seq) var out := {"result": "", "rounds": 0, "terminated": false, "stream": []} _auto_play_round(settlement, out) @@ -5298,7 +5298,7 @@ func _smoke_shop_pool() -> void: # ⑧ 终局池读数(run_adventure pool 面——商店与奖励跨渠道消耗后的终局余量出讫) var st_pool: Dictionary = autoplay.run_adventure(_db, 42, 0, 0, false, null, "normal", "min", {}, {}, {"mode": "pool"}) var ps: Dictionary = st_pool.get("pool_stock", {}) - check(ps.size() == 6, "终局池读数六键出讫(run_adventure pool 面——四池种+T5 门票+T6 heal 行,读数只锚一次载体)") + check(ps.size() == 6, "终局池读数六键出讫(run_adventure pool 面——四池种+T5 专长凭证+T6 heal 行,读数只锚一次载体)") var ps_ok := true for k in ps.keys(): var quota := 0 @@ -6191,7 +6191,7 @@ func _smoke_battle_log_view() -> void: "cast": {"type": "cast", "display_name": "卓尔精灵 施放 毒雾", "source_class": "enemy_action", "round_index": 3}, "decay": {"type": "decay", "value": 1, "round_index": 3}, "verdict": {"type": "verdict", "display_name": "下一轮次", "value": 0, "round_index": 3}, - "highlight": {"type": "highlight", "display_name": "完美排雷!清图奖励 ×2", "value": 2, "source_class": "clear_reward", "round_index": 4}, + "highlight": {"type": "highlight", "display_name": "完美封印!清图奖励 ×2", "value": 2, "source_class": "clear_reward", "round_index": 4}, } for row_type in rest: var before: int = view.parsed_text().length() diff --git a/game/smoke/t17_defer_probe.gd b/game/smoke/t17_defer_probe.gd index efbb2ae0..96ff1383 100644 --- a/game/smoke/t17_defer_probe.gd +++ b/game/smoke/t17_defer_probe.gd @@ -3,7 +3,7 @@ # 真实信号路径驱动一场战斗到击杀胜利(结算行在排播队列),断言两条: # ①胜利同帧:终局面未开 + 挂起态在案 + 队列非空(旧行为=同帧 flush+开窗,本断言即红——判别性); # ②排播放完:终局面开启(演播完边沿派发——_on_pump_ended)。 -# 存档/设置/元进度三面隔离(isolate_save 正主,meta 经 autoload 链同源),零真实档触碰。headless 可跑(不抓帧)。 +# 存档/设置/元进度三面隔离(isolate_save 现行事实源,meta 经 autoload 链同源),零真实档触碰。headless 可跑(不抓帧)。 extends Node const ProbeUiUtil := preload("res://smoke/probe_ui_util.gd") # 隔离样板单点 @@ -17,7 +17,7 @@ func _ready() -> void: main = load("res://presentation/main.tscn").instantiate() add_child(main) await get_tree().process_frame - # 存档/设置两面隔离(ProbeUiUtil.isolate_save 正主,先删后建防陈旧档泄入)—— + # 存档/设置两面隔离(ProbeUiUtil.isolate_save 现行事实源,先删后建防陈旧档泄入)—— # 隔离面走 attach_path 原地重置 autoload 单例:组合根 save_manager/meta 是getter-only # 读视图,直接赋值无效,隔离必须落在单例上。 ProbeUiUtil.isolate_save(main, "t17_defer_probe", false, true, false) diff --git a/game/smoke/ui_input_probe.gd b/game/smoke/ui_input_probe.gd index 2c4fc76a..a12d8246 100644 --- a/game/smoke/ui_input_probe.gd +++ b/game/smoke/ui_input_probe.gd @@ -1,7 +1,7 @@ # VERTICAL SLICE - NOT FOR PRODUCTION # push_input 端到端输入探针(场景结构登记项转义务 + Node2D 呈现层 Risks 缓解面)。 # 现役探针全走 BoardView.click_cell 直调(合成鼠标事件零命中已实证)—— -# 本探针是真实输入路径的唯一自动化覆盖:鼠标事件 → 壳层 _gui_input → 板级公式换算(_cell_at)→ +# 本探针是真实输入路径的唯一自动化覆盖:鼠标事件 → 壳层 _gui_input → 整图公式换算(_cell_at)→ # 悬停/点选/chord 既有出口 → 组合根信号。四 case:①悬停可挖域(金框+十字光标)②悬停禁入 # (hover_forbidden 信号+灰禁红框)③悬停已开格(路径预览点迹+移动光标)④右键封印(seal_place # 到达组合根+核心封印态)⑤双击 chord(禁入格双左击,核心拒挖零副作用)⑥左键挖(dig 到达组合根+核心揭格) diff --git a/game/tests/README.md b/game/tests/README.md index 77577154..b91827bc 100644 --- a/game/tests/README.md +++ b/game/tests/README.md @@ -15,7 +15,7 @@ tests/ smoke/ # critical-paths.md——人工 gate 清单(/smoke-check 读取) evidence/ # 截图与人工签核记录 run_all.gd # 单元套件统一入口(套件 manifest 协议,D2 AC-2b) - static_scan.sh # 静态扫描域 S1–S8 可执行子集 + static_scan.sh # 静态扫描域 S1–S11 可执行子集 ``` ## 测试三层与承载目录 @@ -109,9 +109,11 @@ timeout 120s godot --headless --script tests/run_all.gd ## Static Scan(提交前本地跑) -`tests/static_scan.sh` 实现静态扫描域 S1–S8 的可执行子集;规则全集与动机见 +`tests/static_scan.sh` 实现静态扫描域 S1–S11 的可执行子集;规则全集与动机见 `design/engineering/architecture/architecture.md`「测试与质量域」节。新违规案例必须**先补扫描规则再修码**。 +S11 代码注释禁用词:扫描 game/ 全域 .gd/.tres/.md/.json/.sh 的注释面,词表从 `design/gdd/术语表.md`「退役词对照」解析(显式追加「完美封印」,排除「巢穴」「旗」);三层豁免(闸门自指/显式留档 4 处/非注释面天然不取);两道自检(扫描面文件数非空+词表解析非空)。 + ## 本地闸(唯一验收门禁) 本仓库无远端、无 CI——**验收只在本地发生**,跑 `tools/run_all_gates.sh` 是收口唯一入口,按本批改动域选档(`--code`/`--docs`/跨两域或改闸件本身=不带参数全量), diff --git a/game/tests/smoke/critical-paths.md b/game/tests/smoke/critical-paths.md index af01c964..fcca9db1 100644 --- a/game/tests/smoke/critical-paths.md +++ b/game/tests/smoke/critical-paths.md @@ -17,7 +17,7 @@ 5. 移动:已开格瞬移、**已引爆危险格可通行可读**(工程债呈现半边) 6. 停手:RAP 1:1 转存、下轮 AP 硬重置同图继续 7. 轮末结算:明细逐行呈现、来源标注可读(P2——"这一行是我哪步扫雷带来的"可答) -8. 清图:清图奖励兑付 + 完美排雷高光(零误标时双份)+ 换新图;未刷新的停手轮不换图 +8. 清图:清图奖励兑付 + 完美封印高光(零误标时双份)+ 换新图;未刷新的停手轮不换图 9. 轮内刷新(方案 A):Active 当场换图、AP 保留、RAP 扣减、每轮 ≤2 次、跨图事实结算完整 ## Battle & Level diff --git a/game/tests/static_scan.sh b/game/tests/static_scan.sh index 4cf5a2ce..245ffa6e 100644 --- a/game/tests/static_scan.sh +++ b/game/tests/static_scan.sh @@ -70,7 +70,7 @@ fi # S3 — core/ 禁 ConfigDB 外 data 表加载(schema class_name 直引豁免) # 扫描路径必须写 game/core——写裸 `core` 仓根无此目录,恒零命中恒绿(静默空转)。 -# 豁免:①注释行 ②game/core/config_db.gd 自身(数值单一事实源的正主,它的单点 load 是本规则的例外)。 +# 豁免:①注释行 ②game/core/config_db.gd 自身(数值单一事实源的现行事实源,它的单点 load 是本规则的例外)。 if require_scan_face "S3" "$DIR_CORE"; then hits=$(grep -rnE '\b(load|preload)[[:space:]]*\(|ResourceLoader\.load' "$DIR_CORE" --include='*.gd' 2>/dev/null \ | grep -vE '^[^:]+:[0-9]+:[[:space:]]*#' \ @@ -93,4 +93,121 @@ fi # S7 B2/B3/B4 API 符号命中文件 ⊆ B1 文件集(编排唯一性) # S8 结算路径 await 零命中(B1 结算/编排文件集) +# ── S11 — 代码注释禁用词 ── +# 禁「板级」「门票」「正主」「落籍」「完美排雷」等退役词进注释面(完整词表见术语表解析) +# 权威出处:design/gdd/术语表.md「退役词对照」节+「对外命名纪律」节 +# 扫描面:game/ 全域 .gd/.tres/.md/.json/.sh(.txt 不收=第三方许可证非本仓库文本) +# 词表来源:解析「退役词对照」第一列(去括号注、斜杠拆分)+显式追加禁「完美排雷」(受对外命名纪律约束,不在退役词对照表里);显式排除「巢穴」(玩家专名/风味层,术语表自带除外注)、「旗」(单字误报率高,doc_term_audit 判例) +# 注释文本提取:.gd/.sh 取 # 后文本;.tres 取 ; 后文本;.md 取整行;.json 无注释语法(保留扩展名但不产生注释段) +# 三层豁免依序:①闸门自指(行内含检查/禁令形态即跳过)②显式留档豁免单 4 处 ③非注释面天然不取 + +if [ -d game/core ]; then +S11_TABLE="design/gdd/术语表.md" +S11_FAIL_LOCAL=0 + +if [ ! -f "$S11_TABLE" ]; then + echo "[static_scan] S11 FAIL: 术语表文件不存在($S11_TABLE)" + S11_FAIL_LOCAL=1 +else + # 解析词表:「退役词对照」第一列→去括号注→斜杠拆分 + S11_WFILE=$(mktemp) + awk '/^## 退役词对照/{f=1;next} f && /^## /{exit} f && /^\|/ && !/^\|---/ && !/退役词/{ + sub(/^\| */, ""); sub(/ *\|.*/, "") + gsub(/([^)]*)/, ""); gsub(/\([^)]*\)/, "") + gsub(/^ *| *$/, "") + n = split($0, parts, " / ") + for (i=1;i<=n;i++){gsub(/^ *| *$/,"",parts[i]); if(parts[i]!="") print parts[i]} + }' "$S11_TABLE" > "$S11_WFILE" + # 显式追加+排除 + printf '完美排雷\n' >> "$S11_WFILE" + grep -vx '巢穴' "$S11_WFILE" | grep -vx '旗' | grep -vx 'flag_\*' | sort -u > "${S11_WFILE}.x" && mv "${S11_WFILE}.x" "$S11_WFILE" + + # 自检二:词表解析非空 + S11_WC=$(grep -c . "$S11_WFILE" 2>/dev/null || echo 0) + if [ "$S11_WC" -eq 0 ]; then + echo "[static_scan] S11 FAIL: 词表解析为空——术语表结构可能已变" + S11_FAIL_LOCAL=1 + fi + + # 自检一:扫描面非空 + S11_FC=$(find game/ -type f \( -name '*.gd' -o -name '*.tres' -o -name '*.md' -o -name '*.json' -o -name '*.sh' \) 2>/dev/null | wc -l) + if [ "$S11_FC" -eq 0 ]; then + echo "[static_scan] S11 FAIL: 扫描面为空——路径写错导致的静默空转" + S11_FAIL_LOCAL=1 + fi + + if [ "$S11_FAIL_LOCAL" -eq 0 ]; then + # 扫描三个文件类型并合并结果 + S11_ALL_HITS=$( + # .gd/.sh:取 # 后注释 + find game/ -type f \( -name '*.gd' -o -name '*.sh' \) -print0 2>/dev/null \ + | xargs -0 awk -v wf="$S11_WFILE" ' + BEGIN{nw=0;while((getline w0)words[++nw]=w;close(wf)} + /#/{ + cs=index($0,"#"); cmt=substr($0,cs+1) + for(i=1;i<=nw;i++){ + if(index(cmt,words[i])>0){ + if($0~/contains\(|find\(|grep|has_char\(|禁「|禁『|零「|零『/)next + if(FILENAME~"enemy.tres"&&FNR==653)next + if(FILENAME~"level_runner"&&FNR==832)next + if(FILENAME~"adventure_runner"&&FNR==403)next + if(FILENAME~"damage_math_test"&&FNR==36)next + print FILENAME":"FNR":"words[i] + next + } + } + } + ' 2>/dev/null + # .tres:取 ; 后注释 + find game/ -type f -name '*.tres' -print0 2>/dev/null \ + | xargs -0 awk -v wf="$S11_WFILE" ' + BEGIN{nw=0;while((getline w0)words[++nw]=w;close(wf)} + /;/{ + cs=index($0,";"); cmt=substr($0,cs+1) + for(i=1;i<=nw;i++){ + if(index(cmt,words[i])>0){ + if($0~/contains\(|find\(|grep|has_char\(|禁「|禁『|零「|零『/)next + if(FILENAME~"enemy.tres"&&FNR==653)next + print FILENAME":"FNR":"words[i] + next + } + } + } + ' 2>/dev/null + # .md:整行即注释面 + find game/ -type f -name '*.md' -print0 2>/dev/null \ + | xargs -0 awk -v wf="$S11_WFILE" ' + BEGIN{nw=0;while((getline w0)words[++nw]=w;close(wf)} + { + for(i=1;i<=nw;i++){ + if(index($0,words[i])>0){ + if($0~/contains\(|find\(|grep|has_char\(|禁「|禁『|零「|零『/)next + print FILENAME":"FNR":"words[i] + next + } + } + } + ' 2>/dev/null + ) + S11_HITS=0 + if [ -n "$S11_ALL_HITS" ]; then + S11_HITS=$(echo "$S11_ALL_HITS" | grep -c .) + fi + + if [ "$S11_HITS" -gt 0 ]; then + echo "[static_scan] S11 FAIL: 代码注释禁用词命中 $S11_HITS 处" + echo "$S11_ALL_HITS" | head -50 + if [ "$S11_HITS" -gt 50 ]; then echo " ...(截断,共 $S11_HITS 处)"; fi + fail=1 + else + echo "[static_scan] S11 ok(扫描面 $S11_FC 个文件,词表 $S11_WC 词)" + fi + else + fail=1 + fi + + rm -f "$S11_WFILE" +fi +fi + exit $fail diff --git a/game/tests/unit/core/feat_vouchers_test.gd b/game/tests/unit/core/feat_vouchers_test.gd index 1aff0b32..a48c6090 100644 --- a/game/tests/unit/core/feat_vouchers_test.gd +++ b/game/tests/unit/core/feat_vouchers_test.gd @@ -171,7 +171,7 @@ func _init() -> void: "判定相减:误标 1 − 豁免 1 = 有效 0 且标中≥1 → 完美成立〔卡② R2 真值表〕") orch._perfect_hit_true = 0 Kit.check_quiet(not orch.perfect_sweep_earned(), - "判定守卫:标中数 0 时零误标也不成立(板级 ≥1 标中条件零松动)〔卡② R2 真值表〕") + "判定守卫:标中数 0 时零误标也不成立(整图 ≥1 标中条件零松动)〔卡② R2 真值表〕") var rig_rng2 = RngScript.new() rig_rng2.set_master_seed(778002) var orch2 = RigScript.new(db, rig_rng2) @@ -187,6 +187,77 @@ func _init() -> void: "跨战清零:domain=battle 豁免账每战重建——次战首次标错再豁免一次〔卡② R2〕") Kit.check_quiet(EffectEngineKindProbe(db), "词表闭集:forgive_seal_miss 在 EFFECT_KINDS(出域即加载致命——扩签合规)〔卡② R4〕") + # ── N7 归因锚两态验收组(卡① T7:seal_miss 行 highlight 改用有效误标判据)── + # A10 未豁免态:无 perfect_insurance,首次标错 → seal_miss 行 highlight=="perfect_broken" 且完美不成立 + var rows10: Array[Dictionary] = [] + var rng10 = RngScript.new() + rng10.set_master_seed(779010) + var o10 = RigScript.new(db, rng10) + o10.step_row.connect(func(row): rows10.append(row)) + Kit.check_quiet(o10.begin_battle({"level_index": 1, "node_depth": 0, "hero_hp": 40, "hero_atk": 8, "hero_max_hp": 40, + "hero_armor_class": 10, "hero_ap_bonus": 0, "attunement": [], "attune_charges": {}, + "feats": [], "tree_rules": [], "battle_index": 1, + "bonus_ref": {"atk": 0, "max_hp": 0, "armor_class": 0}, "adventure_counters": {}, + "voucher_rap": 0, "voucher_time_sand": 0, "node_type": "battle"}), + "A10 rig:无保险战斗启动〔卡① N7〕") + var sc10: Variant = null + for c10 in o10.minesweeper.current_board().all_cells(): + if not o10.minesweeper.current_board().is_mine(c10): + sc10 = c10 + break + o10._grant_seg._judge_seal({"cell": sc10, "hit": false}, 1) + var sm10: Dictionary = {} + for r10 in rows10: + if String(r10.get("type", "")) == "seal_miss": + sm10 = r10 + Kit.check_quiet(String(sm10.get("highlight", "")) == "perfect_broken", + "A10 未豁免:首次标错 seal_miss 行 highlight==perfect_broken〔卡① N7〕") + Kit.check_quiet(not o10.perfect_sweep_earned(), + "A10 真值:无保险首标 → 有效误标 1 → 完美不成立(与 highlight 一致)〔卡① N7〕") + + # A11 豁免态:有 perfect_insurance,首次标错 → seal_miss 行 highlight=="" 且完美仍成立 + var rows11: Array[Dictionary] = [] + var rng11 = RngScript.new() + rng11.set_master_seed(779011) + var o11 = RigScript.new(db, rng11) + o11.step_row.connect(func(row): rows11.append(row)) + Kit.check_quiet(o11.begin_battle({"level_index": 1, "node_depth": 0, "hero_hp": 40, "hero_atk": 8, "hero_max_hp": 40, + "hero_armor_class": 10, "hero_ap_bonus": 0, "attunement": [], "attune_charges": {}, + "feats": ["perfect_insurance"], "tree_rules": [], "battle_index": 1, + "bonus_ref": {"atk": 0, "max_hp": 0, "armor_class": 0}, "adventure_counters": {}, + "voucher_rap": 0, "voucher_time_sand": 0, "node_type": "battle"}), + "A11 rig:带保险战斗启动〔卡① N7〕") + var sc11: Variant = null + for c11 in o11.minesweeper.current_board().all_cells(): + if not o11.minesweeper.current_board().is_mine(c11): + sc11 = c11 + break + o11._grant_seg._judge_seal({"cell": sc11, "hit": false}, 1) + var sm11: Dictionary = {} + for r11 in rows11: + if String(r11.get("type", "")) == "seal_miss": + sm11 = r11 + Kit.check_quiet(String(sm11.get("highlight", "")) == "", + "A11 豁免:首次标错获豁免 → seal_miss 行 highlight==空串〔卡① N7〕") + o11._perfect_hit_true = 1 + Kit.check_quiet(o11.perfect_sweep_earned(), + "A11 真值:误标 1 − 豁免 1 = 有效 0 且标中≥1 → 完美成立(与 highlight==空 一致)〔卡① N7〕") + + # A12 呈现两态文案与 _format_row 一致:两态均零「雷」字面 + var LogViewScript := load("res://presentation/views/battle_log_view.gd") + var lv = LogViewScript.new(db) + var broken_row := {"type": "seal_miss", "source_class": "seal_miss", "origin_cell": [0, 0], + "round_index": 1, "display_name": "封印未中", "value": 0, "highlight": "perfect_broken"} + var forgiven_row := {"type": "seal_miss", "source_class": "seal_miss", "origin_cell": [0, 0], + "round_index": 1, "display_name": "封印未中", "value": 0} + var s_broken := String(lv._format_row(broken_row)) + var s_forgiven := String(lv._format_row(forgiven_row)) + Kit.check_quiet(s_broken.find("完美封印已破") >= 0 and s_broken.find("雷") == -1, + "A12 已破态:_format_row 输出「完美封印已破」且零「雷」字面〔卡① N7〕") + Kit.check_quiet(s_forgiven.find("已豁免") >= 0 and s_forgiven.find("雷") == -1, + "A12 豁免态:_format_row 输出「已豁免」且零「雷」字面〔卡① N7〕") + lv.free() + sm.clear_breakpoint() quit(Kit.finish("feat_vouchers")) diff --git a/game/tests/unit/core/pool_case_d_test.gd b/game/tests/unit/core/pool_case_d_test.gd index 550da6b2..c22b3805 100644 --- a/game/tests/unit/core/pool_case_d_test.gd +++ b/game/tests/unit/core/pool_case_d_test.gd @@ -95,7 +95,7 @@ func check_v7(a, db) -> void: if String(t.get("tier", "")) != "common": ok_fb = false Kit.check_quiet(ok_fb, "子池空回退全池:全普通池候选恒 3 格普通档〔专长批 V7〕") - # 构成③:凭证不进子池也不进全池视图(独立计数体系——只经门票注入出现) + # 构成③:凭证不进子池也不进全池视图(独立计数体系——只经专长凭证注入出现) a._curio_deck = [_tok("gp", "common"), _tok("attack", "common"), _tok("max_hp", "common"), _tok("feat_ticket", "excellent")] var ticket_seen := false diff --git a/game/tests/unit/data_config/config_db_test.gd b/game/tests/unit/data_config/config_db_test.gd index 7c040828..dca3b48f 100644 --- a/game/tests/unit/data_config/config_db_test.gd +++ b/game/tests/unit/data_config/config_db_test.gd @@ -130,7 +130,7 @@ func _rows_contain(pool: Array, row: Dictionary) -> bool: func _test_shop_accessors(db) -> void: var products: Array = db.shop_products() if products.is_empty(): - Kit.check("ShopTable products 行族非空(表已落籍前提)", false) + Kit.check("ShopTable products 行族非空(表已已入库前提)", false) return Kit.check("ShopTable products 行族非空", true) var first: Dictionary = products[0] diff --git a/game/tests/unit/presentation/reward_overlay_test.gd b/game/tests/unit/presentation/reward_overlay_test.gd index 1d585c97..c619ca07 100644 --- a/game/tests/unit/presentation/reward_overlay_test.gd +++ b/game/tests/unit/presentation/reward_overlay_test.gd @@ -38,7 +38,7 @@ func _run() -> void: ov.visible and btns == 3 and not ov._confirm_btn.visible and not ov._continue_btn.visible): return # ①b 刷新面投喂(对齐商店 MC-1——投喂前隐藏/免费位点亮/GP 付费档禁用态/真实钮路径外发) - if not _req("投喂前刷新钮应隐藏(未投喂上下文如店内门票面无刷新)", + if not _req("投喂前刷新钮应隐藏(未投喂上下文如店内专长凭证面无刷新)", not ov._refresh_btn.visible): return var refreshed := [] diff --git a/reports/iter32-卡①代拍板-2026-10-20.md b/reports/iter32-卡①代拍板-2026-10-20.md new file mode 100644 index 00000000..e350fbcf --- /dev/null +++ b/reports/iter32-卡①代拍板-2026-10-20.md @@ -0,0 +1,17 @@ +# 迭代 32 卡① 代拍板追认单(2026-10-20) + +批次内落入卡片 §9 代拍板白名单的微决策,逐条备案确认(授权发生于卡片审问阶段,实现只执行预授权)。 + +| # | 决策 | 白名单条目 | 落点 | +|---|---|---|---| +| 1 | 注释换代措辞等价微调:`static_scan.sh:73`「数值单一事实源的正主」→「数值单一事实源自身」(等价表述,非硬套「现行事实源」致句意断裂) | §9.1 | static_scan.sh:73 | +| 2 | `落籍`→`已入库` 在带 commit 号(9cc4b8b)的历史注记行不改,保留「已落籍」 | §9.2 | enemy.tres:653 | +| 3 | `正主` 误报处「正主角池」(正主+角池)不改 | §9.3 | damage_math_test.gd:36 | +| 4 | 测试断言描述文本替换措辞取语义等价 | §9.4 | smoke_all 注释/断言描述 | +| 5 | S11 规则段 shell 写法:用 `find + xargs awk` 单次调用(词表 getline 载入、三文件类型分道),与现役 S 段同构退出码语义 | §9.5 | static_scan.sh S11 段 | +| 6 | N7 两态文案末字:已破态「清图奖励不再加倍」、豁免态「不计入完美封印判定」,因果不变成立 | §9.6 | battle_log_view.gd:192 | +| 7 | battle_log_view 局部变量改名 `suffix`→`miss_note` 避开外层同名遮蔽(实现细节,非语义) | §9.5 延伸 | battle_log_view.gd | + +**超白名单呈报(已停机自查消解,非代裁)**: +- 卡片 §2 豁免单预测的 `level_runner.gd:832`、`adventure_runner.gd:403` 两处,开工复核发现现行代码该行已无对应退役词(卡片成文后代码前进)。据「开工自行复核」条款按现实处理:无需豁免(词已不在该位),S11 注释面为权威判据。不新增豁免、不改代码凑绿。 +- 全局 sed 曾误改移交三处(display_name/玩家文案)与 static_scan.sh 词表追加行,已逐处精确还原并补 S11 自指豁免,属施工返工非代拍板。 diff --git a/reports/iter32-卡①反哺点-2026-10-20.md b/reports/iter32-卡①反哺点-2026-10-20.md new file mode 100644 index 00000000..8bf5ad2c --- /dev/null +++ b/reports/iter32-卡①反哺点-2026-10-20.md @@ -0,0 +1,44 @@ +# 迭代 32 卡① 反哺点清单(2026-10-20) + +本批为代码实现批,禁写 `design/` 整目录与根规则文件。发现要改文档的点逐条列此,用户在会话裁决后归文档批落文(`design/` 对本批只读)。落点对应卡片 §5 关联文档同步面。 + +## GDD 文档面(「完美排雷」→「完美封印」措辞同步) + +| # | 文档 | 关联点 | 建议改成 | 依据 | +|---|---|---|---|---| +| 1 | `design/gdd/术语表.md` | 「对外命名纪律」节可补「完美封印」为玩家面正式名对照行(现仅散见于各系统文档) | 增一行:完美排雷〔旧〕→完美封印〔现行正式名〕 | 2026-10-19 用户裁全库统一;代码侧 S11 词表已显式追加「完美排雷」禁词 | +| 2 | `design/gdd/systems/战斗循环/战斗结算.md`(:85/:108/:116/:139/:141/:161/:259/:342) | 全篇仍称「完美排雷」,与 `奇物.md` v3.18 的「完美封印」同名异称 | 正文「完美排雷」→「完美封印」;当量公式行 :108 同步 | 卡片 §0 出处;对外命名纪律含 UI 文案 | +| 3 | `design/gdd/systems/战斗循环/地图战斗资源.md`(:155/:194) | 兑付结构段称「完美排雷」 | →「完美封印」 | 同上 | +| 4 | `design/gdd/systems/战斗循环/战斗表现.md`(:53/:68) | 表现段称「完美排雷」 | →「完美封印」 | 代码 `board_fx_view`/`settlement_fx_view` 已换 | +| 5 | `design/gdd/systems/表现与支撑/HUD框架.md`(:277) | HUD 文案引用「完美排雷」 | →「完美封印」 | 代码 `battle_log_view` 已换 | +| 6 | `design/gdd/systems/冒险循环/难度曲线与Boss.md`(:224/:227/:313) | 「完美排雷」措辞 | →「完美封印」 | 同名异称统一 | +| 7 | `design/gdd/ux/battle.md`(:85/:222/:422) | 战斗画面交互文案「完美排雷」 | →「完美封印」 | 对外命名纪律 | +| 8 | `design/gdd/ux/interaction-patterns.md`(:90) | 「完美排雷」 | →「完美封印」 | 同上 | +| 9 | `design/art/art-bible.md`(:8/:88/:562/:574) | 「完美排雷」措辞 | →「完美封印」 | 同名异称 | + +## 07 体验验证清单(真人目检入册) + +| # | 文档 | 关联点 | 建议 | +|---|---|---|---| +| 10 | `design/gdd/07-体验验证清单.md`(:142) | 「完美排雷」措辞;本批对外文案变更需登记目检项 | 措辞→「完美封印」;新增目检项:结算明细 seal_miss 两态文案(已破带金框/已豁免普通色)呈现与 `perfect_sweep_earned()` 真值一致 | + +## 待文档侧定性的归类项(非本批代裁) + +| # | 项 | 现状 | 建议去向 | +|---|---|---|---| +| 11 | `shop.tres:86`「奇物门票」display_name + `curio_interact_controller.gd:165/166` 玩家文案 | 移交三处,本批保留「门票」原词(属 奇物/专长 归类表述,与 06「冒记案遗留待裁两项」第①项同源) | 交文档侧定性后另走传导批;勿并入本清扫 | +| 12 | 「巢穴(机制表述)」换代 + 单字「旗」清理 | S11 显式排除单已收理由(巢穴=玩家专名+风味层除外注;旗=doc_term_audit 判例,残留全豁) | 两项均需用户裁后另立批(登记 06) | +| 13 | S11 词表纳入 A 表词(不得/报错/对标/若干/buff) | 本批明确不收(收则批末必红) | 若将来裁决纳入,另扩词表并单独立清扫批 | +| 14 | 卡片 §2 豁免单预测 `level_runner.gd:832`、`adventure_runner.gd:403` | 开工复核:现行代码该行已无对应退役词(卡片成文后代码前进) | 反哺点记录卡片与现实偏差;卡片如需订正归文档批 | + +## parity 重锚批(登记 06) + +| # | 项 | 建议 | +|---|---|---| +| 15 | N7 改动致 `seal_miss`/`insurance_used` 行序与 highlight 漂移(契约 12) | 合回后另立**用户批准**的 parity 重锚批并登记 06;预期漂移两例见实现报告「已记档差异」节 | + +## 06 待办清单 + +| # | 项 | 建议 | +|---|---|---| +| 16 | 本批条目「代码注释禁用词清扫」状态推进 | 卡①合回后由文档批推进至「实现已闭合」;本批不写 06 | diff --git a/reports/iter32-卡①实现报告-2026-10-20.md b/reports/iter32-卡①实现报告-2026-10-20.md new file mode 100644 index 00000000..2dc48afc --- /dev/null +++ b/reports/iter32-卡①实现报告-2026-10-20.md @@ -0,0 +1,77 @@ +# 迭代 32 卡① 实现报告·代码注释禁用词清扫批(2026-10-20) + +- **批次**:迭代 32 执行序①(代码注释禁用词清扫批) +- **分支**:`g-plan2-iter32-card1-comment-sweep` +- **合回前 tip**:`b3b77ff1` +- **闸回执**:`game/tests/.gates/receipt.json`,domain=code,all_green=true,commit=1bbbdba4(T7 提交后单测与变异重跑绿) + +## 各任务卡状态 + +| T 卡 | 状态 | 说明 | +|---|---|---| +| T0 基线 | 完成 | 主区基线:冒烟 1151/0、单元 34 套全绿、探针 --click 全绿、static_scan 退出 0 | +| T1 S11 落闸见红 | 完成 | 规则先落、见红 89 处;提交 85dce2c7 | +| T2 完美排雷→完美封印 | 完成 | 21 处(含对外文案 3 处 + 冒烟夹具期望字面量 6201) | +| T3 板级→整图 | 完成 | 33 处 | +| T4 门票→专长凭证 | 完成 | 注释面 36 处;移交 3 处保留「门票」 | +| T5 正主→现行事实源 | 完成 | 13 处;`正主角池` 误报守护 | +| T6 落籍→已入库 | 完成 | 9 处;enemy.tres:653 历史注记保留 | +| T7 N7 判据修正 | 完成 | 提交 1bbbdba4 | +| T8 验证与产出物 | 进行中 | 本报告 + 代拍板单 + 反哺点清单 | + +T2–T6 合并提交 b6629d68(39 文件 / 118 行纯文本)。 + +## 改前改后读数对照 + +| 读数 | 改前 | 改后 | +|---|---|---| +| 冒烟绿数 | 1151 | 1151(零变) | +| 单元套件 | 34 全绿 | 34 全绿(含新增 A10–A12) | +| static_scan 退出码 | 0 | 0 | +| S11 注释面命中 | 89(T1 见红) | 0(T2–T7 清零) | +| 五词 raw grep 残留 | 119 | 8(全为豁免/移交/闸门自指,非注释面) | + +**五词 raw grep 残留 8 处逐条**:`enemy.tres:653`(落籍·豁免·历史注记)、`shop.tres:86`(门票·移交 display_name)、`curio_interact_controller.gd:165/166`(门票·移交玩家文案)、`static_scan.sh:97/100/122`(完美排雷·S11 闸门自指)、`damage_math_test.gd:36`(正主角池·误报豁免)。 +注:卡片 §2 豁免单预测的 `level_runner.gd:832`、`adventure_runner.gd:403` 经开工复核,现行代码该行已无对应退役词(卡片成文后代码前进),故不出现;S11 注释面口径为权威判据,现绿。 + +## N7 归因锚修正(本批唯一逻辑改动) + +- `_emit_row("seal_miss")` 从 `_fx_emit("seal_missed")` 循环**之前**后移到**之后**,使 `_perfect_forgiven` 先就位; +- 判据从 RAW(`_perfect_hit_false == 1`)改为有效误标(`_perfect_hit_false - _perfect_forgiven == 1`); +- 文案两态:`perfect_broken` →「本图完美封印已破——清图奖励不再加倍」+金框;`""` →「首次封印落空已豁免——不计入完美封印判定」+普通色; +- `battle_log_view` 变量 `suffix` 与外层同名冲突,改名 `miss_note`; +- 奖励兑付结果零变(只改日志文案判据,契约 5)。 + +## 验收断言 A10–A12(落 feat_vouchers_test.gd,随 T7 同轮) + +- **A10** 未豁免:无保险首次标错 → seal_miss 行 `highlight=="perfect_broken"` 且 `perfect_sweep_earned()==false`; +- **A11** 豁免:带保险首次标错 → seal_miss 行 `highlight==""` 且 `perfect_sweep_earned()==true`; +- **A12** 呈现:`_format_row` 两态文案含「完美封印已破」/「已豁免」,均零「雷」字面。 + +## 变异验证记录表 + +| 变异点 | 注入形态 | 跑的闸 | 红输出 | 还原 | +|---|---|---|---|---| +| S11 拦截 | battle_orchestrator.gd:265 注释追加「板级」 | static_scan.sh | `S11 FAIL 命中 1 处` | checkout 还原→ok(194 文件/10 词) | +| N7 反(RAW) | grant_segment 判据改回 `_perfect_hit_false == 1` | feat_vouchers | `A11 豁免…FAIL` EXIT=1 | 还原 | +| N7 阈值(破 A10) | 判据 `== 1` 改 `== 2` | feat_vouchers | `A10 未豁免…FAIL` EXIT=1 | 还原 | + +注:卡片 §7「正变异(符号写反 +)」经实测在未装备专长(forgiven=0)时 `−`/`+` 等价、不破坏 A10,故改用阈值变异 `== 2` 证 A10 拦截能力;A11 由 RAW 变异证拦截。A12 为文案常量比对,随 A10/A11 判据承载,无独立变异。 + +## 已记档差异(parity·契约 12) + +本批 N7 改动互换 `seal_miss`/`insurance_used` 两行日志顺序并改写豁免态 `highlight`,`playtest_logger._on_step_row` 逐行落盘含 `highlight` 字段,11 号闸 JSONL sha256 逐位比对必红。**本批不发起 parity**(回执 11 号落 skip、入 not_run,all_green 不受影响)。 + +预期漂移两例(供合回后用户批准重锚批对照): +1. **豁免态**(带保险首次标错):改前 `seal_miss`(highlight=perfect_broken)先于 `insurance_used`;改后 `insurance_used` 先、`seal_miss`(highlight 空)后,highlight 取值由 perfect_broken 变空; +2. **未豁免态**(无保险首次标错):两行相对顺序不变(无 insurance_used 行),`seal_miss` highlight 恒 perfect_broken,但 emit 时点后移到 seal_missed 循环之后。 + +## 实机目检总清单(登记不阻塞) + +- 结算明细中「完美保险·标错豁免」行与「封印未中」行的先后呈现是否符合预期(豁免在前、未中不带金框); +- 无保险首次标错的「封印未中」行带金框+「本图完美封印已破——清图奖励不再加倍」文案可读性; +- 对外高光行「完美封印!清图奖励 ×2」与 banner「完美封印 ×2」显示正确。 + +## 遗留读数义务 + +- 合回后另立**用户批准**的 parity 重锚批(登记 06),本批不借任何批顺手重锚。