Merge branch 'master' into iter23-forge-20261012
# Conflicts: # design/gdd/systems/表现与支撑/存档序列化.md
This commit is contained in:
commit
3392ea7e2d
19 files changed
+257
-332
No files matched your search
@@ -77,7 +77,7 @@ var _flag_consumed := {} # 兑付资格以雷格实例为键
|
||||
# 同调装配运行态(迭代 11 第①批 T5——begin_battle 经 enc.attunement 注入;off=空集全部效果零扰动)
|
||||
var attunement: Array = [] # 装备中同调件 item_id 集
|
||||
var _attune_charges_ref: Dictionary = {} # 充能账本共享引用(迭代 11 第①批 T6——use_treasure 消费直改)
|
||||
var _attune_safe_seen := 0 # 积点制件 battle 域安全开格计数(迭代 22 T3 通用化——装配集 ap_charge_safe 行扫描;积点账本=行 triggers counter_spend 声明的计数器,旧 dig_charge_bank 硬编码随行退役)
|
||||
var _attune_safe_seen := 0 # 积点制件 battle 域安全开格计数(迭代 22 T3 通用化——装配集 ap_charge_safe 行扫描;反哺批⑤ 2026-10-12 用户裁:满 charge_n 自动兑付当轮 AP+1,无玩家发起入口)
|
||||
# ---- 效果引擎扩签运行态(迭代 20 专长实装批 T1——新效果类型施加面;空订阅零扰动)----
|
||||
var _fx_hero_ac_base := -1 # 主角 AC 基线快照(enc.hero_armor_class;-1=表值兜底未解析)
|
||||
var _fx_ac_round := 0 # ac_bonus 本轮累积器(封印桩形态——round_start 清零)
|
||||
@@ -204,9 +204,9 @@ func _attune_has(item_id: String) -> bool:
|
||||
return attunement.has(item_id)
|
||||
|
||||
|
||||
# 装配集只读出口(迭代 19 卡④立——呈现桥消费面现归 attune_param_sum〔迭代 22 T4 换代〕;本口保留
|
||||
# board_view.set_fog_lantern。_attune_has 契约化出口,save v6 只读访问器先例;private 面内部调用
|
||||
# 零改动。只读零副作用——呈现侧判定专用,非结算写入口)
|
||||
# 装配集只读出口(迭代 19 卡④立——呈现桥消费面现归 attune_param_sum〔迭代 22 T4 换代〕。
|
||||
# _attune_has 契约化出口,save v6 只读访问器先例;private 面内部调用零改动。只读零副作用——
|
||||
# 呈现侧判定专用,非结算写入口)
|
||||
func attune_has(item_id: String) -> bool:
|
||||
return _attune_has(item_id)
|
||||
|
||||
@@ -251,7 +251,7 @@ func _reseed_attune_charges(reset: String) -> void:
|
||||
continue
|
||||
var want := int(arow.get("charges_per_adventure", 0))
|
||||
if want < 1:
|
||||
continue # charges=0=积点制(试炼镐——不走骑库存面,受理=use_attune_convert 积点口)
|
||||
continue # charges=0=自动兑付件(试炼镐——不走骑库存面,兑付=_on_cell_revealed 积点段自动 grant_ap)
|
||||
if _attune_charges_ref != null:
|
||||
_attune_charges_ref[iid] = want
|
||||
if treasure_inventory != null:
|
||||
@@ -263,50 +263,16 @@ func _reseed_attune_charges(reset: String) -> void:
|
||||
treasure_inventory.add_item(iid, "attunement", Vector2i(-1, -1), 0)
|
||||
|
||||
|
||||
# 积点制主动件受理(迭代 22 秘宝批 T3——试炼镐「转化获取」唯一入口:不经库存 handle
|
||||
# 〔charges=0 零骑库存〕,受理闸=行 triggers counter_spend 积点账〔dig_reveal 通用化计数段
|
||||
# 逐 charge_n 积 1 点〕;消耗成功才兑付当轮 AP=magnitude。返回 use_treasure 同构 verdict)
|
||||
func use_attune_convert(item_id: String) -> Dictionary:
|
||||
var arow: Dictionary = db.treasure_item_row(item_id)
|
||||
if arow.is_empty() or String(arow.get("form", "")) != "active_charged" \
|
||||
or not (arow.get("effect_kinds", []) as Array).has("ap_charge_safe") \
|
||||
or not _attune_has(item_id):
|
||||
return {"ok": false, "reason": "非装配积点件"}
|
||||
if action_economy.phase != action_economy.PHASE_ACTIVE:
|
||||
return {"ok": false, "reason": "非挖掘期(使用窗口=Active)"}
|
||||
var bank_id := ""
|
||||
for tr_v in (arow.get("triggers", []) as Array):
|
||||
var dd: Dictionary = (tr_v as Dictionary).get("do", {}) as Dictionary
|
||||
if String(dd.get("kind", "")) == "counter_spend":
|
||||
bank_id = String(dd.get("counter_id", ""))
|
||||
break
|
||||
if bank_id == "":
|
||||
return {"ok": false, "reason": "行缺积点受理闸"}
|
||||
if not _fx.counter_spend(bank_id, 1):
|
||||
var cn := int(arow.get("charge_n", 0))
|
||||
return {"ok": false, "reason": "%s:安全格积点未达(%d/%d)" % [String(arow.get("display_name", "")), _attune_safe_seen % cn if cn > 0 else 0, cn]}
|
||||
if not action_economy.grant_ap(int(arow.get("magnitude", 0))):
|
||||
return {"ok": false, "reason": "行动点加量被拒(相位防御)"}
|
||||
# 兑付反馈=AP 条即时刷新(use_treasure 同款纪律——结算明细无道具行:效果即时可见零明细行)
|
||||
return {"ok": true, "item_id": item_id}
|
||||
|
||||
|
||||
# 积点制件受理状态读数(迭代 22 秘宝批 T4——HUD 兑换钮态数据源:assembled=装配在册/
|
||||
# points=积点账现值/need=受理闸阈值〔行 counter_spend value〕。未装配=assembled false)
|
||||
# 积点制件进度读数(迭代 22 反哺批⑤——自动兑付无玩家发起入口,读数口=C 区秘宝槽悬停浮窗进度行:
|
||||
# assembled=装配在册/points=本战安全格进度(charge_n 取余)/need=charge_n/item_id=装配行 id。
|
||||
# 未装配=assembled false)
|
||||
func attune_convert_state() -> Dictionary:
|
||||
var row := _attune_charge_safe_row()
|
||||
if row.is_empty() or String(row.get("form", "")) != "active_charged":
|
||||
return {"assembled": false, "points": 0, "need": 0, "display_name": ""}
|
||||
var bank := ""
|
||||
var need := 1
|
||||
for tr_v in (row.get("triggers", []) as Array):
|
||||
var dd: Dictionary = (tr_v as Dictionary).get("do", {}) as Dictionary
|
||||
if String(dd.get("kind", "")) == "counter_spend":
|
||||
bank = String(dd.get("counter_id", ""))
|
||||
need = maxi(1, int(dd.get("value", 1)))
|
||||
break
|
||||
return {"assembled": true, "points": _fx.counter(bank) if bank != "" else 0, "need": need,
|
||||
"display_name": String(row.get("display_name", ""))}
|
||||
return {"assembled": false, "points": 0, "need": 0, "display_name": "", "item_id": ""}
|
||||
var cn := int(row.get("charge_n", 0))
|
||||
return {"assembled": true, "points": _attune_safe_seen % cn if cn > 0 else 0, "need": cn,
|
||||
"display_name": String(row.get("display_name", "")), "item_id": String(row.get("item_id", ""))}
|
||||
|
||||
|
||||
# 特性求值(内容数据驱动扩展批 T3——_feat_flags_for 挂点求值退役:效果行为=数据行 triggers 订阅,
|
||||
@@ -622,6 +588,18 @@ func _on_cell_revealed(evt: Dictionary) -> void:
|
||||
# fx_reveal 通道事件旁路缓冲(迭代 20 T1——专长揭示的奖励由 _flush_pending_reveals 兑付点
|
||||
# 直接入账,此处缓冲会导致二次兑付)。
|
||||
if battle_result == "" and not _fx_revealing:
|
||||
# 积点自动兑付(迭代 11 同调批 T6 → 迭代 22 秘宝批 T3 通用化 → 反哺批⑤ 2026-10-12 用户裁:
|
||||
# 满 charge_n 直接当轮 grant_ap,无玩家发起入口、无积点账中转〔账即时清空,battle 域重置
|
||||
# 自然无感〕。落位=揭示缓冲点——事件序 cell_revealed 批先于本格扣费,AP 归零恰逢积点满时
|
||||
# 先兑再扣,轮次不因本格结束;授予段已无积点段(本段唯一计数点)。fx_reveal 旁路不计数=
|
||||
# 沿现役缓冲路径口径〔天眼开格不计积点〕。grant_ap 相位防御在 ACTIVE 挖格链内恒过)
|
||||
if String(evt.get("kind", "")) == "safe":
|
||||
var cs_row: Dictionary = _attune_charge_safe_row()
|
||||
if not cs_row.is_empty():
|
||||
_attune_safe_seen += 1
|
||||
var cn_b: int = int(cs_row.get("charge_n", 999))
|
||||
if cn_b > 0 and _attune_safe_seen % cn_b == 0:
|
||||
action_economy.grant_ap(int(cs_row.get("magnitude", 1)))
|
||||
if bool(evt.get("resource", false)):
|
||||
# 身份快照随缓冲捕获(批次隔离——轮内刷新后 mapping 已换批,授予必须用缓冲期身份,
|
||||
# 防旧图已挖格在轮末错拿新图同坐标身份)。雷格同样携带(雷安同池——负向兑付的来源格)
|
||||
@@ -721,23 +699,6 @@ func _settle() -> void:
|
||||
"奥术矢", "board", int((spell_hits[0] as Dictionary).get("value", 0)),
|
||||
DamageController.TARGET_FRONT_ALIVE, ri, evt.cell, "magic")
|
||||
_submit(spell_t, false)
|
||||
# 积点制计数(迭代 11 同调批 T6 → 迭代 22 秘宝批 T3 通用化:装配集 ap_charge_safe 行
|
||||
# 〔新目录=试炼镐;旧 dig_charge id 特判随行退役摘除〕——模判定留编排器侧:「每 N 格积
|
||||
# 1 点」在发射点施加架构下无法行内表达先增后判(when 于 dispatch 预评估),逐位等价优先;
|
||||
# 积点账本 counter_id=行 triggers counter_spend 声明单点,charge_n 读行零字面量)
|
||||
var cs_row: Dictionary = _attune_charge_safe_row()
|
||||
if not cs_row.is_empty():
|
||||
_attune_safe_seen += 1
|
||||
var cn_b: int = int(cs_row.get("charge_n", 999))
|
||||
if cn_b > 0 and _attune_safe_seen % cn_b == 0:
|
||||
var bank_b := ""
|
||||
for tr_b in (cs_row.get("triggers", []) as Array):
|
||||
var dd_b: Dictionary = (tr_b as Dictionary).get("do", {}) as Dictionary
|
||||
if String(dd_b.get("kind", "")) == "counter_spend":
|
||||
bank_b = String(dd_b.get("counter_id", ""))
|
||||
break
|
||||
if bank_b != "":
|
||||
_fx.counter_add(bank_b, 1)
|
||||
elif evt.kind == "mine":
|
||||
# 插旗不可逆四情况②:插雷格再挖开 = 只受挖雷一层惩罚(mine_hit 照常兑付——惊动巢穴),
|
||||
# 标中不发(旗已随挖掘擦除、不入轮末判定基线)。
|
||||
@@ -1018,11 +979,6 @@ func use_treasure(handle: int, target: Vector2i) -> Dictionary:
|
||||
if kinds.has("ap_grant"):
|
||||
if not action_economy.grant_ap(int(v.magnitude)):
|
||||
return {"ok": false, "reason": "行动点加量被拒(相位防御)"}
|
||||
if kinds.has("ap_charge_safe"):
|
||||
# 积点件兑付(迭代 11 同调批 T6——临时 AP 当轮生效;库存通道积点件已由 use_attune_convert
|
||||
# 承载〔charges=0 零骑库存〕,本分支保留=charges>0 且挂 ap_charge_safe 的历史形态兼容)
|
||||
if not action_economy.grant_ap(int(v.magnitude)):
|
||||
return {"ok": false, "reason": "行动点加量被拒(相位防御)"}
|
||||
if kinds.has("safe_dig"):
|
||||
# 天眼安全格直开(迭代 22 秘宝批 T3——C5 裁全额兑付:fx_reveal 通道复用=免 AP 零相位、
|
||||
# 连锁与格面资源与普通挖格同链;危险格仅真视显示不移除=契约 3;有旗格跳过=旗=玩家承诺不代开)
|
||||
|
||||
@@ -90,13 +90,13 @@ func discard_item(handle: int) -> bool:
|
||||
|
||||
# 板级零信息可用性预判(图标置灰/入口禁用判据——GDD「整张图都没东西可看」级):
|
||||
# 真视恒可用(零雷窗口=信息非空);AP 类恒可用(组合判据取 OR——任一效果有信息即可用);
|
||||
# 纯预读行 = 板上还有未开格才可用。
|
||||
# 纯预读行 = 板上还有未开格才可用。(积点件不入使用面——反哺批⑤自动兑付无玩家入口)
|
||||
func _usable_now(item_id: String, board_has_preview_info: Callable) -> bool:
|
||||
var row: Dictionary = _item_row(item_id)
|
||||
if row.is_empty():
|
||||
return false
|
||||
var kinds: Array = row.get("effect_kinds", [])
|
||||
if kinds.has("mine_reveal") or kinds.has("ap_grant") or kinds.has("ap_charge_safe"):
|
||||
if kinds.has("mine_reveal") or kinds.has("ap_grant"):
|
||||
return true
|
||||
return bool(board_has_preview_info.call()) if board_has_preview_info.is_valid() else true
|
||||
|
||||
|
||||
@@ -12,8 +12,9 @@ script = ExtResource("1")
|
||||
; 真视类工具累计使用(本批新增计数域)。全部数值 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)。
|
||||
; 主动件:线香(battle 级充能)/天眼(level 级充能)charge_reset 扩签;试炼镐=自动兑付(charges=0 无上限,
|
||||
; ap_charge_safe 满 charge_n=8 自动当轮 grant_ap——2026-10-12 反哺批⑤用户裁:无玩家发起入口、
|
||||
; 旧行 counter_spend 受理闸随裁删除;挖格扣 AP 后、轮末判定前兑付;战斗级重置=账即时清空自然无感)。
|
||||
rows = [{
|
||||
"item_id": "morning_order",
|
||||
"display_name": "晨操令",
|
||||
@@ -56,7 +57,7 @@ rows = [{
|
||||
"item_id": "trial_pick",
|
||||
"display_name": "试炼镐",
|
||||
"dimension_tags": ["action"],
|
||||
"desc": "每开 4 安全格积 1 点,满 2 点换当轮 AP +1",
|
||||
"desc": "每开 8 个安全格,当轮 AP +1(自动)",
|
||||
"tier": "common",
|
||||
"effect_kinds": ["ap_charge_safe"],
|
||||
"target": "none",
|
||||
@@ -66,15 +67,7 @@ rows = [{
|
||||
"slot_cost": 1,
|
||||
"charges_per_adventure": 0,
|
||||
"charge_n": 8,
|
||||
"unlock_keystone_cost": 10,
|
||||
"triggers": [{
|
||||
"on": "treasure_used",
|
||||
"do": {
|
||||
"kind": "counter_spend",
|
||||
"counter_id": "trial_pick_bank",
|
||||
"value": 1
|
||||
}
|
||||
}]
|
||||
"unlock_keystone_cost": 10
|
||||
}, {
|
||||
"item_id": "refresh_practice",
|
||||
"display_name": "刷新练习",
|
||||
|
||||
@@ -235,7 +235,6 @@ func _build_ui() -> void:
|
||||
info_panel.treasure_slot_clicked.connect(_treasure_ui.on_slot_clicked) # 迭代 7 T4——两步交互第一步
|
||||
board_zone.stop_pressed.connect(_on_stop_pressed)
|
||||
board_zone.refresh_confirmed.connect(_on_refresh_confirmed)
|
||||
board_zone.convert_pressed.connect(_on_convert_pressed) # 积点兑换(迭代 22 秘宝批 T4——试炼镐 HUD 入口)
|
||||
board_zone.legend_toggled.connect(_on_legend_toggled)
|
||||
board_zone.hover_forbidden.connect(_on_hover_forbidden)
|
||||
board_zone.chord_attempted.connect(_on_chord_attempted)
|
||||
@@ -1240,32 +1239,10 @@ func _refresh_presentations() -> void:
|
||||
# 每个核心信号/写调用返回后的全量重查装配(更新触发注记——无推送信号,命令式重查)
|
||||
var refresh_remaining: int = maxi(0, int(db.action_economy.refresh_cap_per_round) - _refresh_used_round)
|
||||
HudPresenter.refresh(stage, info_panel, ap_bar, settlement, runner, _level_active, db, refresh_remaining)
|
||||
_sync_convert_button()
|
||||
_treasure_ui.refresh_slots() # C 区秘宝槽重查(反哺批⑤——试炼镐积点进度随挖格刷新悬停浮窗)
|
||||
_sync_settlement_visuals()
|
||||
|
||||
|
||||
# 积点兑换钮态(迭代 22 秘宝批 T4——读数口命令式重查;未装配=隐藏零占位)
|
||||
func _sync_convert_button() -> void:
|
||||
if settlement == null:
|
||||
board_zone.ap_bar.set_convert_state(false, 0, 0, "")
|
||||
return
|
||||
var cs: Dictionary = settlement.attune_convert_state()
|
||||
board_zone.ap_bar.set_convert_state(bool(cs.get("assembled", false)), int(cs.get("points", 0)),
|
||||
int(cs.get("need", 0)), String(cs.get("display_name", "")))
|
||||
|
||||
|
||||
func _on_convert_pressed() -> void:
|
||||
if settlement == null:
|
||||
return
|
||||
var v: Dictionary = settlement.use_attune_convert("trial_pick")
|
||||
if not bool(v.get("ok", false)):
|
||||
board_zone.toast.show_toast(String(v.get("reason", "无法兑换")), "warn")
|
||||
return
|
||||
logger.log_action("convert", Vector2i(-1, -1), true)
|
||||
board_view.refresh()
|
||||
_refresh_presentations()
|
||||
|
||||
|
||||
func _sync_settlement_visuals() -> void:
|
||||
# 结算阶段(round_end → 下一轮):D 区去饱和+金橙偏移锁输入(明度不变)+ 明细带展开 84px
|
||||
var settling := _is_settling()
|
||||
|
||||
@@ -52,7 +52,8 @@ func active_selection() -> int:
|
||||
return _use_selection
|
||||
|
||||
|
||||
# 槽点击(第一步):AP 类(target=none)点击即用(无目标);空间类进/出选中态(toggle 取消)。
|
||||
# 槽点击(第一步):AP 类(target=none)点击即用(无目标);空间类进/出选中态(toggle 取消);
|
||||
# 自动兑付件展示行(handle<0)无使用动作——点击给说明提示(反哺批⑤)。
|
||||
func on_slot_clicked(slot_handle: int) -> void:
|
||||
var settlement = _settlement_get.call()
|
||||
var runner = _runner_get.call()
|
||||
@@ -62,6 +63,9 @@ func on_slot_clicked(slot_handle: int) -> void:
|
||||
_use_selection = 0
|
||||
refresh_slots()
|
||||
return
|
||||
if slot_handle < 0:
|
||||
toast.show_toast("自动兑付件:满足条件自动生效,无需手动使用", "info")
|
||||
return
|
||||
var rec: Dictionary = {}
|
||||
for r in inventory_projection():
|
||||
if int(r.get("handle", 0)) == slot_handle:
|
||||
@@ -112,9 +116,16 @@ func inventory_projection() -> Array:
|
||||
cb = func(_c: Vector2i) -> bool:
|
||||
return ms.has_unrevealed() # 只读查询面(排雷玩法 has_unrevealed——手搓全板双循环收口)
|
||||
var out: Array = []
|
||||
var cs: Dictionary = settlement.attune_convert_state() if settlement != null else {}
|
||||
var auto_seen := false # 自动兑付件是否已随骑库存出现(恒否——charges=0 不入骑库存;守合成行重复)
|
||||
for rec in runner.treasure_inventory.query_inventory(cb):
|
||||
var arow: Dictionary = db.treasure_item_row(String(rec.get("item_id", "")))
|
||||
var dn := String(arow.get("display_name", ""))
|
||||
# 积点进度浮窗行(反哺批⑤——自动兑付件 C 区悬停 tooltip 补 N/M 进度;件 id 锁定=装配行唯一)
|
||||
var note := ""
|
||||
if bool(cs.get("assembled", false)) and String(cs.get("item_id", "")) == String(rec.get("item_id", "")):
|
||||
note = "积点 %d/%d" % [int(cs.get("points", 0)), int(cs.get("need", 0))]
|
||||
auto_seen = true
|
||||
out.append({
|
||||
"handle": int(rec.get("handle", 0)),
|
||||
"item_id": String(rec.get("item_id", "")),
|
||||
@@ -122,7 +133,22 @@ func inventory_projection() -> Array:
|
||||
"name": dn,
|
||||
"used": bool(rec.get("used", false)),
|
||||
"usable": bool(rec.get("usable", true)),
|
||||
"note": note,
|
||||
})
|
||||
# 自动兑付件展示行(反哺批⑤补——charges=0 不入骑库存〔_reseed_attune_charges 跳过注入〕,
|
||||
# C 区四槽末尾补合成行承载悬停进度;handle=-1 非库存句柄:槽点击走说明 toast 分支不进两步交互)
|
||||
if bool(cs.get("assembled", false)) and not auto_seen:
|
||||
var adn := String(cs.get("display_name", ""))
|
||||
if adn != "":
|
||||
out.append({
|
||||
"handle": -1,
|
||||
"item_id": String(cs.get("item_id", "")),
|
||||
"glyph": adn.left(1),
|
||||
"name": adn,
|
||||
"used": false,
|
||||
"usable": true,
|
||||
"note": "积点 %d/%d" % [int(cs.get("points", 0)), int(cs.get("need", 0))],
|
||||
})
|
||||
return out
|
||||
|
||||
|
||||
|
||||
@@ -13,7 +13,6 @@ extends PanelContainer
|
||||
signal stop_pressed
|
||||
signal refresh_confirmed
|
||||
signal legend_toggled
|
||||
signal convert_pressed # 积点兑换意图(迭代 22 秘宝批 T4——写口唯一=BattleOrchestrator.use_attune_convert)
|
||||
|
||||
const COL_GOLD := UiKit.GOLD
|
||||
const COL_DOT_OFF := UiKit.DOT_OFF
|
||||
@@ -22,7 +21,6 @@ const COL_INK := UiKit.INK
|
||||
var _dots: HBoxContainer
|
||||
var _ap_label: Label
|
||||
var _btn_stop: Button
|
||||
var _btn_convert: Button # 积点兑换钮(迭代 22 秘宝批 T4——试炼镐 HUD 入口;未装配隐藏)
|
||||
var _btn_legend: Button
|
||||
var _btn_refresh: Button
|
||||
var _refresh_sub: Label
|
||||
@@ -63,12 +61,6 @@ func _init() -> void:
|
||||
_btn_stop.pressed.connect(_emit_stop_pressed)
|
||||
row.add_child(_btn_stop)
|
||||
|
||||
_btn_convert = UiKit.button("兑换", 0.0) # 行板紧凑钮豁免——积点兑换(试炼镐;未装配隐藏)
|
||||
_btn_convert.size_flags_vertical = Control.SIZE_SHRINK_CENTER
|
||||
_btn_convert.visible = false
|
||||
_btn_convert.pressed.connect(func(): convert_pressed.emit())
|
||||
row.add_child(_btn_convert)
|
||||
|
||||
var spacer := Control.new()
|
||||
spacer.size_flags_horizontal = Control.SIZE_EXPAND_FILL
|
||||
row.add_child(spacer)
|
||||
@@ -136,15 +128,6 @@ func set_refresh_cost(cost: int) -> void:
|
||||
_confirm_lab.text = "RAP−%d · 旧板旗作废" % cost
|
||||
|
||||
|
||||
# 积点兑换钮(迭代 22 秘宝批 T4——试炼镐转化获取 HUD 入口:装配时在列〔visible〕、
|
||||
# 积点未达 disabled;文案=件名+进度。未装配=隐藏零占位)
|
||||
func set_convert_state(assembled: bool, points: int, need: int, display_name: String) -> void:
|
||||
_btn_convert.visible = assembled
|
||||
if assembled:
|
||||
_btn_convert.text = "%s %d/%d" % [display_name, points, need]
|
||||
_btn_convert.disabled = points < need
|
||||
|
||||
|
||||
func set_refresh_state(remaining: int, ready: bool) -> void:
|
||||
_refresh_sub.text = "RAP−%d · 剩 %d 次" % [refresh_cost, remaining]
|
||||
_btn_refresh.disabled = not ready
|
||||
|
||||
@@ -18,7 +18,6 @@ var _board_area: Control # resized 命名转发用(原 lambda 局部捕获
|
||||
signal action_requested(cell: Vector2i, kind: String)
|
||||
signal stop_pressed
|
||||
signal refresh_confirmed
|
||||
signal convert_pressed # 积点兑换意图转发(迭代 22 秘宝批 T4——试炼镐 HUD 入口,源=ap_bar)
|
||||
signal legend_toggled
|
||||
signal hover_forbidden(cell: Vector2i)
|
||||
signal chord_attempted(cell: Vector2i)
|
||||
@@ -83,7 +82,6 @@ func _init() -> void:
|
||||
board_view.chord_attempted.connect(_forward_chord)
|
||||
ap_bar.stop_pressed.connect(_emit_stop_pressed)
|
||||
ap_bar.refresh_confirmed.connect(_emit_refresh_confirmed)
|
||||
ap_bar.convert_pressed.connect(_emit_convert_pressed)
|
||||
ap_bar.legend_toggled.connect(_emit_legend_toggled)
|
||||
|
||||
|
||||
@@ -107,10 +105,6 @@ func _emit_stop_pressed() -> void:
|
||||
stop_pressed.emit()
|
||||
|
||||
|
||||
func _emit_convert_pressed() -> void:
|
||||
convert_pressed.emit()
|
||||
|
||||
|
||||
func _emit_refresh_confirmed() -> void:
|
||||
refresh_confirmed.emit()
|
||||
|
||||
|
||||
@@ -220,4 +220,8 @@ func set_treasure_inventory(items: Array, selected_handle: int) -> void:
|
||||
var border_col: Color = UiKit.GOLD if selected else UiKit.PANEL_BORDER
|
||||
slot.add_theme_stylebox_override("panel",
|
||||
UiKit.panel_flat(UiKit.PANEL_DATA, border_col, 0, 1 if not selected else 2, Vector4(4, 4, 4, 4)))
|
||||
slot.tooltip_text = "%s%s" % [String(rec.get("name", "")), "(已用)" if used else ("(不可用——当前无有效目标)" if not usable else "")]
|
||||
# note=积点进度行(反哺批⑤——自动兑付件悬停浮窗补「积点 N/M」,进度随挖格经组合根重查刷新)
|
||||
var note := String(rec.get("note", ""))
|
||||
slot.tooltip_text = "%s%s%s" % [String(rec.get("name", "")),
|
||||
"(%s)" % note if note != "" else "",
|
||||
"(已用)" if used else ("(不可用——当前无有效目标)" if not usable else "")]
|
||||
@@ -71,19 +71,45 @@ func _init() -> void:
|
||||
var ob4 = orch_s.new(db, rng4)
|
||||
Kit.check_quiet(ob4.begin_battle({"level_index": 1, "node_depth": 0, "hero_hp": int(db.hero.max_hp), "attunement": ["trial_pick"]}),
|
||||
"试炼镐:装配起战")
|
||||
var v_bad: Dictionary = ob4.use_attune_convert("trial_pick")
|
||||
Kit.check_quiet(not bool(v_bad.get("ok", true)) and String(v_bad.get("reason", "")).contains("积点未达"),
|
||||
"试炼镐边界:积点未达拒绝零副作用(受理闸 counter_spend)")
|
||||
# 自动兑付(反哺批⑤ 2026-10-12 用户裁):无玩家入口——揭示缓冲点即时计数,满 charge_n 自动
|
||||
# grant_ap(cell_revealed 先于本格扣费→AP 归零恰逢满点时先兑再扣、轮不结束)。直调揭示处理器
|
||||
# 构造 7+1 格序列(缓冲路径与真挖格同链;授予段无积点段无二次计数)
|
||||
var ap_before4 := int(ob4.action_economy._ap)
|
||||
ob4._fx.counter_add("trial_pick_bank", 1) # 直摆积点(模拟 8 安全格积点——计数链断言归冒烟集成段)
|
||||
Kit.check_quiet(bool(ob4.use_attune_convert("trial_pick").get("ok", false))
|
||||
and int(ob4.action_economy._ap) == ap_before4 + 1,
|
||||
"试炼镐正常:满点兑付当轮 AP +1(counter_spend 消耗+grant_ap)")
|
||||
for _i7 in 7:
|
||||
ob4._on_cell_revealed({"kind": "safe", "cell": Vector2i(0, _i7)})
|
||||
Kit.check_quiet(int(ob4.action_economy._ap) == ap_before4,
|
||||
"试炼镐边界:7 格未达阈值零兑付(AP 不变)")
|
||||
ob4._on_cell_revealed({"kind": "safe", "cell": Vector2i(0, 7)})
|
||||
Kit.check_quiet(int(ob4.action_economy._ap) == ap_before4 + 1,
|
||||
"试炼镐正常:第 8 格自动兑付当轮 AP+1(无玩家入口)")
|
||||
var cs4: Dictionary = ob4.attune_convert_state()
|
||||
Kit.check_quiet(bool(cs4.get("assembled", false)) and int(cs4.get("points", -1)) == 0
|
||||
and int(cs4.get("need", -1)) == 8 and String(cs4.get("item_id", "")) == "trial_pick",
|
||||
"试炼镐读数口:兑付后进度归零(8 取余)、阈值=charge_n、C 区浮窗数据源")
|
||||
var rng4b = load("res://core/rng_service.gd").new(); rng4b.set_master_seed(252)
|
||||
var ob4b = orch_s.new(db, rng4b)
|
||||
ob4b.begin_battle({"level_index": 1, "node_depth": 0, "hero_hp": int(db.hero.max_hp)})
|
||||
Kit.check_quiet(not bool(ob4b.use_attune_convert("trial_pick").get("ok", true)),
|
||||
"试炼镐反例:未装配拒绝(且积点清账——用后清账滑耗)")
|
||||
ob4b._on_cell_revealed({"kind": "safe", "cell": Vector2i(0, 0)})
|
||||
var ap_base := int(db.action_economy.ap_per_round)
|
||||
Kit.check_quiet(int(ob4b.action_economy._ap) == ap_base and not bool(ob4b.attune_convert_state().get("assembled", true)),
|
||||
"试炼镐反例:未装配零兑付零计数(AP=整轮表值、读数口 assembled=false)")
|
||||
|
||||
# ④b 自动兑付件 C 区展示行(反哺批⑤补——charges=0 不入骑库存〔_reseed 注入循环跳过〕,
|
||||
# 展示行=C 区悬停浮窗进度唯一承载:handle=-1 非库存句柄+note 进度;空骑库存桩直构投影链)
|
||||
var rng4c = load("res://core/rng_service.gd").new(); rng4c.set_master_seed(253)
|
||||
var ob4c = orch_s.new(db, rng4c)
|
||||
ob4c.begin_battle({"level_index": 1, "node_depth": 0, "hero_hp": int(db.hero.max_hp), "attunement": ["trial_pick"]})
|
||||
var ctrl4 = load("res://presentation/treasure_interact_controller.gd").new(db, null, null, null, null,
|
||||
func(): return ob4c, func(): return StubAutoInvRunner.new())
|
||||
var proj4: Array = ctrl4.inventory_projection()
|
||||
Kit.check_quiet(proj4.size() == 1 and int(proj4[0].get("handle", 0)) == -1
|
||||
and String(proj4[0].get("item_id", "")) == "trial_pick"
|
||||
and String(proj4[0].get("note", "")) == "积点 0/8",
|
||||
"试炼镐 C 区展示行:装配即入投影(handle=-1 合成行+悬停进度 note=积点 N/8——charges=0 不入骑库存的浮窗承载)")
|
||||
ob4c._on_cell_revealed({"kind": "safe", "cell": Vector2i(0, 0)})
|
||||
var proj4b: Array = ctrl4.inventory_projection()
|
||||
Kit.check_quiet(String(proj4b[0].get("note", "")) == "积点 1/8",
|
||||
"试炼镐展示行进度刷新:开格后 note=积点 1/8(组合根重查链)")
|
||||
|
||||
# ⑤ 刷新练习(存量账一次性加仓/临时账不动)
|
||||
var rng5 = load("res://core/rng_service.gd").new(); rng5.set_master_seed(261)
|
||||
@@ -310,3 +336,14 @@ func _cell_at(orch, c: Vector2i) -> Vector2i:
|
||||
if b != null and b.in_bounds(c):
|
||||
return c
|
||||
return Vector2i(-9, -9)
|
||||
|
||||
|
||||
# 自动兑付件展示行测试桩(反哺批⑤——空骑库存 runner 桩:charges=0 件不入骑库存,
|
||||
# 展示行合成逻辑在 treasure_interact_controller.inventory_projection 末段)
|
||||
class StubAutoInvRunner:
|
||||
extends RefCounted
|
||||
var treasure_inventory: StubAutoInv = StubAutoInv.new()
|
||||
class StubAutoInv:
|
||||
extends RefCounted
|
||||
func query_inventory(_cb: Callable) -> Array:
|
||||
return []
|
||||
Reference in new issue
Block a user