diff --git a/game/core/battle_orchestrator.gd b/game/core/battle_orchestrator.gd index f5ba6acc..b0f88b79 100644 --- a/game/core/battle_orchestrator.gd +++ b/game/core/battle_orchestrator.gd @@ -632,6 +632,13 @@ func use_aux(handle: int, target: Vector2i) -> Dictionary: # 掘进蓄能兑付(迭代 11 同调批 T6——临时 AP 当轮生效,grant_ap 同 sapper_order 通道) if not action_economy.grant_ap(int(v.magnitude)): return {"ok": false, "reason": "行动点加量被拒(相位防御)"} + if kinds.has("cell_removal"): + # 爆破工兵包兑付(迭代 13 T8/D6——中立移除雷格:未揭示/无旗/是雷过滤归排雷玩法; + # P1 甲邻接数字冻结零重算、清图分母零涉(雷格不入分母);空集拒绝零消耗—— + # consume 之前 return(拒绝面注记扩「③内零消耗分支」),拒绝 reason 可呈现) + var blasted: Array = board.remove_mines_in(v.resolved) + if blasted.is_empty(): + return {"ok": false, "reason": "爆破工兵包:3×3 区域内无可移除雷格(须未揭示且未插旗)"} var rec: Dictionary = aux_inventory.consume(handle) # 同调主动件充能扣减(迭代 11 第①批 T6——共享账本直改:adventure/level/settlement 同一字典引用) if not rec.is_empty() and String(rec.get("source_class", "")) == "attunement": diff --git a/game/core/minesweeper_rules.gd b/game/core/minesweeper_rules.gd index 548bf0ba..b7b4e736 100644 --- a/game/core/minesweeper_rules.gd +++ b/game/core/minesweeper_rules.gd @@ -20,6 +20,7 @@ var action_economy: ActionEconomy var _board: BoardData = null var _revealed := {} # Vector2i → {"kind": "safe"/"mine", "digit": int} var _flags := {} # Vector2i → true(棋盘单态;跨轮保留随图存续) +var _removed := {} # Vector2i → true(迭代 13 T8/D6——中立移除雷格集;随 install/retire 清空) var _hero := Vector2i.ZERO var _spawn: Dictionary[Vector2i, bool] = {} @@ -73,6 +74,26 @@ func clear_map_cleared() -> bool: return safe_remaining() == 0 +# ---- 中立移除(迭代 13 T8/D6——P1 甲:邻接数字=原始雷数冻结零重算;P2 甲:移除格呈现退色降档; +# 移除集=未揭示、无旗、是雷——旗判定基线零回溯;雷格不入清图分母/连锁/C_dig 模拟,判定逻辑零改动) ---- + +func remove_mines_in(cells: Array) -> Array: + var out: Array = [] + for c in cells: + var cell: Vector2i = c + if not _board.in_bounds(cell) or is_revealed(cell) or has_flag(cell) or not _board.is_mine(cell): + continue + if _removed.has(cell): + continue + _removed[cell] = true + out.append(cell) + return out + + +func is_removed(c: Vector2i) -> bool: + return _removed.has(c) + + # 未开格存在查询(aux 道具 usable 预判消费——全板扫描只读面) func has_unrevealed() -> bool: for y in _board.height: @@ -100,6 +121,7 @@ func install_board(b: BoardData, during_round := false) -> Dictionary: _board = b _revealed.clear() _flags.clear() + _removed.clear() _spawn = {} for c in b.spawn_cells(): _spawn[c] = true @@ -127,6 +149,7 @@ func retire_board(during_round := false) -> Dictionary: _board = null _revealed.clear() _flags.clear() + _removed.clear() return _outcome(true, "executed", "", "") @@ -303,6 +326,8 @@ func _board_face_dig(c: Vector2i) -> String: return "not_adjacent" if is_revealed(c): return "target_revealed" + if _removed.has(c): + return "target_removed" # 迭代 13 T8/D6——中立移除格不可交互(拒绝先于消耗,pattern 1 board_face 腿) # 旗不拦挖掘(插旗不可逆批 2026-09-19):有旗格直接挖 = 对承诺的兑现,兑付改判归 战斗结算。 return "" @@ -356,6 +381,8 @@ func _do_flag_place(c: Vector2i) -> Dictionary: sub = "target_revealed" elif has_flag(c): sub = "flag_present" + elif _removed.has(c): + sub = "target_removed" # 迭代 13 T8/D6——中立移除格不可交互 if sub != "": return _outcome(false, "rejected", "board_face", sub) if not action_economy.try_spend("flag_place"): diff --git a/game/data/tables/aux_items.tres b/game/data/tables/aux_items.tres index 1b6b1688..db17404f 100644 --- a/game/data/tables/aux_items.tres +++ b/game/data/tables/aux_items.tres @@ -5,7 +5,7 @@ [resource] script = ExtResource("1") ; 迭代 11 第①批 T1(2026-10-03):追加七件同调行(form 非空——永不入过渡渠道);值全 provisional 归 难度曲线与Boss。 -; nest_pendulum/blast_kit 维持过渡行,T7 渠道退役时原位换装 form=active_charged;sapper_order/显影尘/地穴全图卷/罗盘 T7 逐件销账。 +; nest_pendulum 已换装 active_charged(迭代 11 第①批);blast_kit 已换装 cell_removal+active_charged(迭代 13 T8/D6——中立移除雷格启用);sapper_order/显影尘/地穴全图卷/罗盘 T7 逐件销账。 rows = [{ "item_id": "probe_dust", "display_name": "显影尘", @@ -57,11 +57,13 @@ rows = [{ "item_id": "blast_kit", "display_name": "爆破工兵包", "dimension_tags": ["action", "risk"], -"effect_kinds": ["ap_grant", "mine_reveal"], +"effect_kinds": ["ap_grant", "mine_reveal", "cell_removal"], "target": "area_3x3", "magnitude": 4, "use_phase": "active_dig", -"deferred": true +"form": "active_charged", +"slot_cost": 1, +"charges_per_adventure": 2 }, { "item_id": "venom_edge", "display_name": "淬毒刃纹", diff --git a/game/presentation/aux_interact_controller.gd b/game/presentation/aux_interact_controller.gd index ffcc7133..dcff5fd8 100644 --- a/game/presentation/aux_interact_controller.gd +++ b/game/presentation/aux_interact_controller.gd @@ -95,6 +95,7 @@ func attempt_use(handle: int, cell: Variant = null) -> void: _use_selection = 0 refresh_slots() refresh_overlays() + board_view.refresh() # 迭代 13 T8/D6——移除格即时落图(无移除态的件 diff 零变化幂等) var arow: Dictionary = db.aux_item_row(String(v.get("item_id", ""))) toast.show_toast("已使用 %s" % String(arow.get("display_name", "")), "info") diff --git a/game/presentation/views/board_cell_unit.gd b/game/presentation/views/board_cell_unit.gd index 024848ba..d98f3995 100644 --- a/game/presentation/views/board_cell_unit.gd +++ b/game/presentation/views/board_cell_unit.gd @@ -118,6 +118,10 @@ var fog_state := 0: if fog_state != v: fog_state = v queue_redraw() +var removed_dim := false: # 中立移除退色层(T8/D6——BoardView paint 按排雷玩法 is_removed 写入) + set(v): + removed_dim = v + queue_redraw() func _draw() -> void: @@ -256,6 +260,10 @@ func _draw() -> void: draw_rect(Rect2(Vector2.ZERO, Vector2(edge, edge)), FOG_MEMORY_PLATE, true) if glyph != "": _draw_glyph(glyph, FOG_MEMORY_INK, maxi(18, int(ceil(edge * 0.5)))) # 字号下限 18(§7.4 冻结公式同源) + # ⑦ 中立移除退色层(迭代 13 T8/D6——P2 甲退色降档:暗幕压顶全层覆盖,暗淡记忆态同族呈现语义; + # 顶层于迷雾之上——移除格不再参与迷雾语义。本实现移除集=未揭示雷格(无数字无旗印)) + if removed_dim: + draw_rect(Rect2(Vector2.ZERO, Vector2(edge, edge)), Color(0.12, 0.10, 0.09, 0.62), true) # 南立面(D 档件一——墙格南缘内侧,自底边向上:双段暗带在下、口沿高光线贴其上沿): diff --git a/game/presentation/views/board_view.gd b/game/presentation/views/board_view.gd index 1a73135c..c0fc3a84 100644 --- a/game/presentation/views/board_view.gd +++ b/game/presentation/views/board_view.gd @@ -316,7 +316,7 @@ func refresh() -> void: var hero: Vector2i = _minesweeper.hero_pos() _diggable.clear() for n in _board.neighbors8(hero): - if not _minesweeper.is_revealed(n): + if not _minesweeper.is_revealed(n) and not _minesweeper.is_removed(n): _diggable[n] = true for y in _board.height: for x in _board.width: @@ -684,6 +684,7 @@ func _paint_cell(c: Vector2i, hero: Vector2i) -> void: return var revealed: bool = _minesweeper.is_revealed(c) var flag: bool = _minesweeper.has_flag(c) + var removed: bool = _minesweeper.is_removed(c) # 迭代 13 T8/D6——中立移除格(P2 甲退色降档) var is_hero: bool = c == hero var glyph := "" var bg: Color @@ -691,6 +692,10 @@ func _paint_cell(c: Vector2i, hero: Vector2i) -> void: # 旗槽统一维护(T17 修复):旗格=封印旗纹理;其余格清 null(插旗格挖开后残留在 tex_flag # 会让 _draw 无条件把旗印画在已开格上——tex_flag 绘制无 revealed 条件)。缺盘走字形回退。 u.tex_flag = _flag_tex if (flag and not revealed and _flag_tex != null) else null + if removed: + revealed = false # 移除格固定未开呈现基座(退色暗幕层承载;雷格本无数字——P1 甲周边数字冻结) + flag = false + u.tex_flag = null if revealed: var rec: Dictionary = _minesweeper.reveal_record(c) # E2 收口:已开记录经查询面 if rec.get("kind", "") == "mine": @@ -809,6 +814,7 @@ func _paint_cell(c: Vector2i, hero: Vector2i) -> void: u.fog_state = (2 if revealed else 1) if fogged else 0 else: u.fog_state = 0 + u.removed_dim = removed u.queue_redraw()