merge: M-3迭代7魔法道具内容+元进度数值标定 T0-T8全落——AuxItemTable六行+掉落投放(解锁门控空集零投放)+库存四步受理+三选一奖励节点+HUD两步交互+叠加层呈现+工坊封存呈现+换算率复核读数(6/9/1 vs 实测1.7/4.1/0.0 U1呈报);重闸全绿(冒烟577/0+五探针+单测12套+doc三闸熵增零新增+机检11/11+MC剥additive 0/400逐位);出口=T9目检(检查单已交);台账259-263
# Conflicts: # game/presentation/views/node_overlay.gd
This commit is contained in:
commit
fd39a58aee
35 files changed
+1990
-19
No files matched your search
+147
-2
@@ -67,6 +67,8 @@ var shop_overlay: ShopOverlay # 商店覆盖层(GP+商店房实施
|
||||
var _adventure_gp_view := 0 # GP 冒险钱包呈现侧影子(迭代 6 T7——终局面板 GP 行取数面,
|
||||
# wallet_changed gain/buy 载荷=入账后总额 level_runner.gd:482/539)
|
||||
var _adventure_gp_final := 0 # 收束清零拍暂存的最终合计("clear" 到达时自影子转存)
|
||||
var _aux_use_selection := 0 # 魔法道具选中句柄(迭代 7 T4——0=未选中;选中期棋盘点击=使用目标拾取)
|
||||
var _aux_unlocked := {} # aux 解锁门控集(迭代 7 T5——工坊解锁×活行交集,冒险开始组装)
|
||||
var camp_overlay: CampOverlay # 营地覆盖层(元进度实现批——主菜单营地入口兑付呈现)
|
||||
var tune_panel: TunePanel
|
||||
|
||||
@@ -115,6 +117,7 @@ func _build_ui() -> void:
|
||||
settlement_fx = battle_ui.settlement_fx
|
||||
log_view.review_requested.connect(_open_review_from_band)
|
||||
board_zone.action_requested.connect(_on_board_action)
|
||||
info_panel.aux_slot_clicked.connect(_on_aux_slot_clicked) # 迭代 7 T4——两步交互第一步
|
||||
board_zone.stop_pressed.connect(_on_stop_pressed)
|
||||
board_zone.refresh_confirmed.connect(_on_refresh_confirmed)
|
||||
board_zone.legend_toggled.connect(_on_legend_toggled)
|
||||
@@ -147,6 +150,7 @@ func _build_ui() -> void:
|
||||
legend_overlay.closed.connect(_on_modal_closed.bind(legend_overlay))
|
||||
review_overlay.closed.connect(_on_modal_closed.bind(review_overlay))
|
||||
node_overlay.continue_pressed.connect(_on_node_continue)
|
||||
# 迭代 7 T5——item_chosen 连接在奖励分支首唤时防重接线(上方)
|
||||
level_screen.route_chosen.connect(_on_route_chosen)
|
||||
level_screen.abandon_requested.connect(_on_abandon_requested) # 放弃入口(2026-09-21 用户拍板——台账 119)
|
||||
shop_overlay.buy_requested.connect(_on_shop_buy)
|
||||
@@ -248,7 +252,7 @@ func _start_adventure() -> void:
|
||||
# 永久强化注入(元进度实现批):冒险开始参数面——meta 现算 override 显式传参(全零 = 白板)
|
||||
# 首次冒险脚本(关卡节点图生成 v0.4):存档布尔位 false = 全关固定模板 0(教学重放);置位后逐关抽签
|
||||
var first_script: bool = not save_manager.is_first_adventure_done()
|
||||
if not adventure.start_adventure(seed_val, {"hero_override": meta.hero_override() if meta != null else {}, "first_script": first_script}):
|
||||
if not adventure.start_adventure(seed_val, {"hero_override": meta.hero_override() if meta != null else {}, "first_script": first_script, "aux_unlocked": _aux_unlocked_set()}):
|
||||
_fatal_screen("冒险启动失败——见输出日志")
|
||||
return
|
||||
|
||||
@@ -282,7 +286,9 @@ func _on_runner_node(node: Dictionary, info: Dictionary) -> void:
|
||||
log_view.append_bb(Narrator.node_banner(runner, node, t))
|
||||
elif t == "reward":
|
||||
_open_modal(node_overlay)
|
||||
node_overlay.show_reward()
|
||||
node_overlay.item_chosen.connect(_on_reward_item_chosen) if not node_overlay.item_chosen.is_connected(_on_reward_item_chosen) else null
|
||||
node_overlay.show_reward_items(_reward_node_choices())
|
||||
log_view.append_bb(Narrator.reward_line())
|
||||
log_view.append_bb(Narrator.reward_line())
|
||||
elif t == "rest":
|
||||
var healed: int = int(info.get("healed", 0))
|
||||
@@ -304,6 +310,8 @@ func _on_runner_node(node: Dictionary, info: Dictionary) -> void:
|
||||
# 大奖励兑付(非末关通关恰一次):复用 _inter_overlay(label + 确认按钮,零新增交互范式);
|
||||
# 文案装配归 Narrator
|
||||
func _on_big_reward(reward: Dictionary) -> void:
|
||||
if int(reward.get("aux_cleared", 0)) > 0:
|
||||
board_zone.toast.show_toast("上关剩余 %d 件魔法道具已随关卡结束清空" % int(reward.get("aux_cleared", 0)), "info") # 迭代 7 T4 清空反馈
|
||||
_inter_label.text = Narrator.big_reward_text(reward)
|
||||
_inter_overlay.visible = true
|
||||
_refresh_presentations()
|
||||
@@ -722,6 +730,136 @@ func _on_shop_leave() -> void:
|
||||
runner.continue_after_node()
|
||||
|
||||
|
||||
# ---- 魔法道具 HUD 接线(迭代 7 T4——库存条+两步交互+叠加层呈现;数据源=runner 级库存只读面)----
|
||||
|
||||
# ---- 奖励节点三选一(迭代 7 T5——拍板②丙:奖励屏=小构筑点;「节点奖励=功能道具正式渠道」兑现)----
|
||||
# aux 解锁门控集组装(迭代 7 T5——拍板③甲:工坊解锁 ∩ 活行词表;罗盘退役/失义件不入集)
|
||||
func _aux_unlocked_set() -> Dictionary:
|
||||
var out := {}
|
||||
if meta == null:
|
||||
return out
|
||||
for row in db.aux_active_rows():
|
||||
var iid := String(row.get("item_id", ""))
|
||||
if meta.save.item_unlocked(iid):
|
||||
out[iid] = true
|
||||
return out
|
||||
|
||||
|
||||
|
||||
# 摇取面:活行 ∩ 工坊解锁集(拍板③甲——解锁进投放池同源口径);池 ≤3 全列(当前三件=选一即全列),
|
||||
# 池扩充后加权摇三(确定性摇取:读 seed 流外——呈现侧零 RNG 消费纪律 → 全列前 3 按注册序)。
|
||||
func _reward_node_choices() -> Array:
|
||||
if runner == null or runner.aux_inventory == null:
|
||||
return []
|
||||
var out: Array = []
|
||||
for row in db.aux_active_rows():
|
||||
var iid := String(row.get("item_id", ""))
|
||||
if not _aux_unlocked.has(iid):
|
||||
continue # 未解锁不入奖励池(与掉落投放同门控)
|
||||
out.append({
|
||||
"item_id": iid,
|
||||
"display_name": String(row.get("display_name", "")),
|
||||
"glyph": String(row.get("display_name", "?")).left(1),
|
||||
})
|
||||
if out.size() >= 3:
|
||||
break
|
||||
return out
|
||||
|
||||
|
||||
# 选择兑付:入关卡域库存(来源归因 reward_node)→ 收屏 → 兑付确认回选路(零自动推进同款)
|
||||
func _on_reward_item_chosen(item_id: String) -> void:
|
||||
if runner == null or runner.aux_inventory == null:
|
||||
return
|
||||
runner.grant_aux_item(item_id, "reward_node")
|
||||
node_overlay.close_reward()
|
||||
_refresh_aux_slots()
|
||||
board_zone.toast.show_toast("获得 %s(入关卡背包)" % String(db.aux_item_row(item_id).get("display_name", item_id)), "info")
|
||||
_on_node_continue()
|
||||
|
||||
|
||||
# 槽点击(第一步):AP 类(target=none)点击即用(无目标);空间类进/出选中态(toggle 取消)。
|
||||
func _on_aux_slot_clicked(slot_handle: int) -> void:
|
||||
if settlement == null or runner == null or runner.aux_inventory == null:
|
||||
return
|
||||
if slot_handle == 0:
|
||||
_aux_use_selection = 0
|
||||
_refresh_aux_slots()
|
||||
return
|
||||
var rec: Dictionary = {}
|
||||
for r in _aux_inventory_projection():
|
||||
if int(r.get("handle", 0)) == slot_handle:
|
||||
rec = r
|
||||
break
|
||||
if rec.is_empty() or bool(rec.get("used", false)):
|
||||
return
|
||||
var arow: Dictionary = db.aux_item_row(String(rec.get("item_id", "")))
|
||||
if String(arow.get("target", "none")) == "none":
|
||||
_attempt_aux_use(slot_handle, Vector2i(-9, -9)) # AP 类:无目标即用
|
||||
return
|
||||
if not bool(rec.get("usable", true)):
|
||||
board_zone.toast.show_toast("当前无可预读的未开格", "warn")
|
||||
return
|
||||
_aux_use_selection = 0 if _aux_use_selection == slot_handle else slot_handle # toggle 取消
|
||||
_refresh_aux_slots()
|
||||
if _aux_use_selection != 0:
|
||||
board_zone.toast.show_toast("%s:点击目标格使用(9 宫窗口),再点道具取消" % String(rec.get("name", "")), "info")
|
||||
|
||||
|
||||
# 使用受理(第二步;core 侧 use_aux 四步编排——拒绝零消耗 toast 可辨认)
|
||||
func _attempt_aux_use(handle: int, cell: Vector2i) -> void:
|
||||
if settlement == null:
|
||||
return
|
||||
var v: Dictionary = settlement.use_aux(handle, cell)
|
||||
if not bool(v.ok):
|
||||
board_zone.toast.show_toast(String(v.get("reason", "无法使用")), "warn")
|
||||
return
|
||||
_aux_use_selection = 0
|
||||
_refresh_aux_slots()
|
||||
_refresh_aux_overlays()
|
||||
var arow: Dictionary = db.aux_item_row(String(v.get("item_id", "")))
|
||||
board_zone.toast.show_toast("已使用 %s" % String(arow.get("display_name", "")), "info")
|
||||
|
||||
|
||||
# 库存投影(C 区四槽取数面——字形=名首字;usable=板级零信息预判回调接排雷玩法只读面)
|
||||
func _aux_inventory_projection() -> Array:
|
||||
if runner == null or runner.aux_inventory == null:
|
||||
return []
|
||||
var ms = settlement.minesweeper if settlement != null else null
|
||||
var cb := Callable()
|
||||
if ms != null:
|
||||
cb = func(_c: Vector2i) -> bool:
|
||||
for y in ms.current_board().height:
|
||||
for x in ms.current_board().width:
|
||||
if not ms.is_revealed(Vector2i(x, y)):
|
||||
return true
|
||||
return false
|
||||
var out: Array = []
|
||||
for rec in runner.aux_inventory.query_inventory(cb):
|
||||
var arow: Dictionary = db.aux_item_row(String(rec.get("item_id", "")))
|
||||
var dn := String(arow.get("display_name", ""))
|
||||
out.append({
|
||||
"handle": int(rec.get("handle", 0)),
|
||||
"item_id": String(rec.get("item_id", "")),
|
||||
"glyph": dn.left(1) if dn != "" else "?",
|
||||
"name": dn,
|
||||
"used": bool(rec.get("used", false)),
|
||||
"usable": bool(rec.get("usable", true)),
|
||||
})
|
||||
return out
|
||||
|
||||
|
||||
func _refresh_aux_slots() -> void:
|
||||
info_panel.set_aux_inventory(_aux_inventory_projection(), _aux_use_selection)
|
||||
|
||||
|
||||
# 叠加层投影注入(use 成功/三清后——棋盘标记与预读徽章重算)
|
||||
func _refresh_aux_overlays() -> void:
|
||||
if runner == null or runner.aux_inventory == null or board_view == null:
|
||||
return
|
||||
var ov: Dictionary = runner.aux_inventory.query_overlays()
|
||||
board_view.set_aux_overlays(ov.get("mine_reveal", []), ov.get("reward_preview", []))
|
||||
|
||||
|
||||
func _on_wallet_changed(event: String, gp: int, extra: Dictionary) -> void:
|
||||
# wallet 行族转发(到账/购买/清零——试玩日志验收取数面)+ 常驻余额与在开商店覆盖层重刷
|
||||
logger.log_wallet(event, gp, extra)
|
||||
@@ -742,9 +880,16 @@ func _on_board_action(cell: Vector2i, kind: String) -> void:
|
||||
# 玩家动作 → 核心写调用的唯一通道(模态/无战斗拒绝在此收口)
|
||||
if _input_locked():
|
||||
return
|
||||
# 魔法道具选中态劫持(迭代 7 T4——两步交互第二步):点格=使用目标拾取,不落挖格;
|
||||
# 只劫持挖掘点击(move/flag 语义不冲突——选中期玩家仍可移动/插旗)
|
||||
if _aux_use_selection != 0 and kind == "dig":
|
||||
_attempt_aux_use(_aux_use_selection, cell)
|
||||
return
|
||||
var outcomes: Array = settlement.minesweeper.settle_batch([{"action": kind, "cell": cell}])
|
||||
var accepted: bool = not outcomes.is_empty() and bool(outcomes[0].accepted)
|
||||
logger.log_action(kind, cell, accepted)
|
||||
if runner != null and runner.aux_inventory != null:
|
||||
_refresh_aux_slots() # 迭代 7 T4——授予发生在 settle_batch 结算段内(同步走完,行尾重查)
|
||||
_handle_outcome_feedback(outcomes[0] if not outcomes.is_empty() else {})
|
||||
# settle_batch 内部同步走完 结算→战斗结束→关卡推进(事件同步发射)——关卡终局时 settlement 已被
|
||||
# runner 置空,清图演出判定须先判 settlement(基线既有重入隐患,2026-09-13 加固)
|
||||
|
||||
Reference in new issue
Block a user