From cff741ea2af0102992edcaf2e2a572abd9048bff Mon Sep 17 00:00:00 2001 From: DKChan <524912269@qq.com> Date: Mon, 12 Oct 2026 23:43:21 +0800 Subject: [PATCH] =?UTF-8?q?fix(=E8=BF=AD=E4=BB=A322=E5=8F=8D=E5=93=BA?= =?UTF-8?q?=E2=91=A4=E8=A1=A5):=20=E8=AF=95=E7=82=BC=E9=95=90C=E5=8C=BA?= =?UTF-8?q?=E5=B1=95=E7=A4=BA=E8=A1=8C=E2=80=94=E2=80=94charges=3D0?= =?UTF-8?q?=E4=BB=B6=E8=A2=AB=5Freseed=5Fattune=5Fcharges=E6=B3=A8?= =?UTF-8?q?=E5=85=A5=E5=BE=AA=E7=8E=AF=E8=B7=B3=E8=BF=87=E4=B8=8D=E5=85=A5?= =?UTF-8?q?=E9=AA=91=E5=BA=93=E5=AD=98,=E8=80=8CC=E5=8C=BA=E6=A7=BD?= =?UTF-8?q?=E6=8A=95=E5=BD=B1=E9=81=8D=E5=8E=86=E9=AA=91=E5=BA=93=E5=AD=98?= =?UTF-8?q?=E2=86=92=E8=AF=95=E7=82=BC=E9=95=90C=E5=8C=BA=E4=B8=8D?= =?UTF-8?q?=E5=8F=AF=E8=A7=81/=E6=82=AC=E5=81=9C=E6=B5=AE=E7=AA=97?= =?UTF-8?q?=E8=BF=9B=E5=BA=A6=E6=97=A0=E5=A4=84=E6=89=BF=E8=BD=BD(?= =?UTF-8?q?=E8=BF=BD=E8=AE=A4=E6=89=B9=E9=9B=86=E6=88=90=E7=BC=BA=E5=8F=A3?= =?UTF-8?q?,=E5=8D=95=E6=B5=8B=E5=8F=AA=E6=B5=8B=E8=AF=BB=E6=95=B0?= =?UTF-8?q?=E5=8F=A3=E6=9C=AA=E8=A6=86=E7=9B=96=E6=8A=95=E5=BD=B1=E9=93=BE?= =?UTF-8?q?)=E3=80=82=E4=BF=AE=E5=A4=8D=3Dinventory=5Fprojection=E6=9C=AB?= =?UTF-8?q?=E6=AE=B5=E8=BF=BD=E5=8A=A0=E8=87=AA=E5=8A=A8=E5=85=91=E4=BB=98?= =?UTF-8?q?=E4=BB=B6=E5=B1=95=E7=A4=BA=E8=A1=8C(=E5=90=88=E6=88=90handle?= =?UTF-8?q?=3D-1=E9=9D=9E=E5=BA=93=E5=AD=98=E5=8F=A5=E6=9F=84+note?= =?UTF-8?q?=E7=A7=AF=E7=82=B9N/8+=E6=A7=BD=E7=82=B9=E5=87=BB=E8=B5=B0?= =?UTF-8?q?=E8=AF=B4=E6=98=8Etoast=E4=B8=8D=E8=BF=9B=E4=B8=A4=E6=AD=A5?= =?UTF-8?q?=E4=BA=A4=E4=BA=92);=20use=5Fattune=5Fconvert=E5=88=A0=E9=99=A4?= =?UTF-8?q?=E9=81=97=E7=95=99=E5=AD=A4=E5=84=BF=E5=87=BD=E6=95=B0=E5=A4=B4?= =?UTF-8?q?=E6=B3=A8=E9=87=8A=E6=B8=85=E4=B8=80;=20=E5=8D=95=E6=B5=8B?= =?UTF-8?q?=E6=96=B0=E5=A2=9E=E2=91=A3b=E5=B1=95=E7=A4=BA=E8=A1=8C?= =?UTF-8?q?=E6=96=AD=E8=A8=80=E4=B8=A4=E6=9D=A1(=E8=A3=85=E9=85=8D?= =?UTF-8?q?=E5=8D=B3=E5=85=A5=E6=8A=95=E5=BD=B1handle=3D-1+note=3D?= =?UTF-8?q?=E7=A7=AF=E7=82=B90/8/=E5=BC=80=E6=A0=BC=E5=90=8E1/8=E7=BB=84?= =?UTF-8?q?=E5=90=88=E6=A0=B9=E9=87=8D=E6=9F=A5=E9=93=BE)+StubAutoInvRunne?= =?UTF-8?q?r=E7=A9=BA=E9=AA=91=E5=BA=93=E5=AD=98=E6=A1=A9=E3=80=82?= =?UTF-8?q?=E9=87=8D=E9=97=B8=E5=85=A8=E7=BB=BF:=20=E5=86=92=E7=83=9F898/0?= =?UTF-8?q?+=E5=8D=95=E6=B5=8B22=E5=A5=97+probe=5Fgate=20--full+render=5Fg?= =?UTF-8?q?ate=20golden=203=E5=B1=8F0.00%+doc=E4=B8=89=E9=97=B8=E5=AF=B9?= =?UTF-8?q?=E5=9F=BA=E7=BA=BF=E9=9B=B6=E6=96=B0=E5=A2=9E(=E6=AD=BB?= =?UTF-8?q?=E9=93=BE3/=E6=8B=94=E6=97=971/gdd=5Flint=E4=B8=89=E6=96=87?= =?UTF-8?q?=E4=BB=B6=E8=A1=A8=E6=A0=BC=E5=8D=A0=E6=AF=94FAIL=E5=9D=87?= =?UTF-8?q?=E5=AE=9E=E8=AF=81=E5=AD=98=E9=87=8F=3D79aac07=E7=89=88?= =?UTF-8?q?=E6=9C=AC=E5=AF=B9=E6=AF=94=E8=A1=A8=E6=A0=BC=E8=A1=8C=E9=9B=B6?= =?UTF-8?q?=E5=8F=98=E5=8C=96)+=E7=86=B5=E5=A2=9E=E9=97=B8PASS;=2006?= =?UTF-8?q?=E8=A3=81=E5=86=B3=E5=B0=8F=E8=8A=82=E4=B8=8E=E5=AE=9E=E7=8E=B0?= =?UTF-8?q?=E6=8A=A5=E5=91=8A=E2=91=A4=E6=9D=A1=E8=A1=A5=E9=9B=86=E6=88=90?= =?UTF-8?q?=E8=A1=A5=E4=B8=81=E6=B3=A8=E8=AE=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- design/gdd/06-待办清单.md | 2 ++ design/qa/iter22-实现报告-2026-10-12.md | 2 +- game/core/battle_orchestrator.gd | 3 -- .../treasure_interact_controller.gd | 22 ++++++++++++++- game/tests/unit/core/treasure_effects_test.gd | 28 +++++++++++++++++++ 5 files changed, 52 insertions(+), 5 deletions(-) diff --git a/design/gdd/06-待办清单.md b/design/gdd/06-待办清单.md index 77a947e4..90900f5e 100644 --- a/design/gdd/06-待办清单.md +++ b/design/gdd/06-待办清单.md @@ -186,6 +186,8 @@ **B 单七条反哺落文**(实现报告 §三,用户逐点裁「落文」全落):①②③秘宝.md v3.0(目录三表实态列/试炼镐自动兑付换代/代价轴转化获取行含战斗级重置与兑付时序/解锁条件表实录〔钥石 10/25+四条件件三计数键〕/全部「实装批落地前」句换代);④元进度.md v1.17(秘宝匣行实装实录+柜台纪律排期态消解+P1 定价换代);⑤camp.md v1.3(秘宝匣柜台呈现细则节+暂停层 12 行只读概览+退役/封存件口径消解);⑥存档序列化.md v1.6(vision_used 域行+vision_counter_used 断点随件+bonus_aux_carry 退役+v6 扩列不升版注);⑦行动经济.md v0.12(finish_round_stop 转存率参数化注记)。连带:07㉑ 观测点随⑤换代;术语表 v1.2 补「自动兑付/真视使用计数」两词条。 +**⑤呈现集成补丁(2026-10-12 修复批)**:追认批遗留一缺陷——charges=0 件被 `_reseed_attune_charges` 注入循环跳过〔不入骑库存〕,而 C 区槽投影遍历骑库存→试炼镐在 C 区不可见、悬停浮窗进度无处承载。修复=C 区投影末段追加**自动兑付件展示行**(合成 handle=-1 非库存句柄+note 进度,槽点击走说明 toast 不进两步交互);孤儿函数头注释清一并修。重闸全绿:冒烟 898/0+单测 22 套〔新增④b 展示行断言两条〕+probe --full+render_gate golden 0.00%+doc 三闸对基线零新增(死链 3/拔旗 1/gdd_lint 三文件表格占比 FAIL 均实证存量——79aac07 版本对比表格行零变化)+熵增闸 PASS。 + #### 迭代 20 专长实装批 GDD 反哺点(五条清单——2026-10-11 随批登记,逐点待用户裁决后另批落文) diff --git a/design/qa/iter22-实现报告-2026-10-12.md b/design/qa/iter22-实现报告-2026-10-12.md index 29885a99..200cb103 100644 --- a/design/qa/iter22-实现报告-2026-10-12.md +++ b/design/qa/iter22-实现报告-2026-10-12.md @@ -22,7 +22,7 @@ 2. **回补点 2 消解**【追认】:迭代 20 已删 venom_edge/flag_burst,本批实删 12 行(非 14)。 3. **回补点 3 执行形态**【追认】:treasure_inventory **部分拆除+保留注记**——拆除=替换子交互死通道全清(装配不可变实现面保证);保留=库存类本体(新目录主动件线香/天眼的骑库存承载在役:handle 注入+use_treasure 受理+断点 aux_items 快照)。卡片「拆除或保留注记」双路线并写的第三形态,理由=T3 复用现役机制零新建。 4. **试炼镐两级积点单级化**【追认+积点账生命周期裁战斗级(每场战斗清零——设计留白处 2026-10-12 用户裁)】:设计「每开 4 安全格积 1 点、满 2 点换 AP+1」→ 实现=ap_charge_safe charge_n=8 滑耗(行为等价:每 8 格兑 1 AP,免上限滑动消耗)——代拍板白名单「订阅行等价实现细节」;desc 保留设计原文两级表述(反哺批⑤ 后随自动兑付换代)。 -5. **试炼镐受理口与入口**【**推翻·改自动兑付**(2026-10-12 用户裁,反哺落文批执行):满 charge_n=8 自动当轮 grant_ap、无玩家发起入口——HUD 兑换钮整链(convert_pressed 信号/转发/接线/set_convert_state)退役、use_attune_convert 受理口消解、行内 counter_spend 受理闸删除、desc 换代「每开 8 个安全格,当轮 AP +1(自动)」;兑付时序=揭示先于本格扣费(cell_revealed 批先于 spend),AP 归零恰逢满点时先兑再扣、轮次不因本格结束;进度显示挂 C 区秘宝槽悬停浮窗(attune_convert_state 读数口改造为进度投影);单测④段重写自动兑付断言,冒烟 898/0+单测 22 套+probe click/full 反哺批重跑全绿】:原实现绕库存直呼 use_attune_convert(charges=0 零骑库存)+HUD 行动条兑换钮——卡片未列明入口形态,本批落 HUD 最小入口。 +5. **试炼镐受理口与入口**【**推翻·改自动兑付**(2026-10-12 用户裁,反哺落文批执行):满 charge_n=8 自动当轮 grant_ap、无玩家发起入口——HUD 兑换钮整链(convert_pressed 信号/转发/接线/set_convert_state)退役、use_attune_convert 受理口消解、行内 counter_spend 受理闸删除、desc 换代「每开 8 个安全格,当轮 AP +1(自动)」;兑付时序=揭示先于本格扣费(cell_revealed 批先于 spend),AP 归零恰逢满点时先兑再扣、轮次不因本格结束;进度显示挂 C 区秘宝槽悬停浮窗(attune_convert_state 读数口改造为进度投影);单测④段重写自动兑付断言,冒烟 898/0+单测 22 套+probe click/full 反哺批重跑全绿。**呈现集成补丁(同日修复批)**:charges=0 件不入骑库存〔注入循环跳过〕致 C 区原无试炼镐槽、浮窗进度无处承载——C 区投影末段补自动兑付件展示行(合成 handle=-1+note 进度+点击说明 toast);单测新增④b 展示行断言两条;重闸全绿(含 render_gate golden 0.00%+doc 三闸存量对比+熵增闸)】:原实现绕库存直呼 use_attune_convert(charges=0 零骑库存)+HUD 行动条兑换钮——卡片未列明入口形态,本批落 HUD 最小入口。 6. **解锁条件表落位**:卡片 T1「attunement_growth.tres 改造为解锁条件表」——该表已被迭代 21 删除,落位改为 treasure_items 行内 unlock_requires(单一事实源,schema 校验单点)。 7. **计数键换代**:UNLOCK_COUNTER_KEYS 旧键 clear_count(旧工坊按关累计语义)与 C6 通关口径不符,换名 adventure_cleared(生涯通关局数)+扩 vision_used——旧键零行消费安全换名。 8. **vision_used 承载**:save v6 meta 域补零新键(不升版本,迭代 21 先例)+断点随件 vision_counter_used;计数点=use_treasure 受理成功(真视类 kind),冒险共享 dict 聚合、收束 add_vision_used 入档。 diff --git a/game/core/battle_orchestrator.gd b/game/core/battle_orchestrator.gd index 79f47daa..8a05926e 100644 --- a/game/core/battle_orchestrator.gd +++ b/game/core/battle_orchestrator.gd @@ -263,9 +263,6 @@ 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) # 积点制件进度读数(迭代 22 反哺批⑤——自动兑付无玩家发起入口,读数口=C 区秘宝槽悬停浮窗进度行: # assembled=装配在册/points=本战安全格进度(charge_n 取余)/need=charge_n/item_id=装配行 id。 # 未装配=assembled false) diff --git a/game/presentation/treasure_interact_controller.gd b/game/presentation/treasure_interact_controller.gd index 70bcdf60..f5137d1b 100644 --- a/game/presentation/treasure_interact_controller.gd +++ b/game/presentation/treasure_interact_controller.gd @@ -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: @@ -113,6 +117,7 @@ func inventory_projection() -> Array: 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", "")) @@ -120,6 +125,7 @@ func inventory_projection() -> Array: 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", "")), @@ -129,6 +135,20 @@ func inventory_projection() -> Array: "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 diff --git a/game/tests/unit/core/treasure_effects_test.gd b/game/tests/unit/core/treasure_effects_test.gd index 50b41a9a..4bf8880b 100644 --- a/game/tests/unit/core/treasure_effects_test.gd +++ b/game/tests/unit/core/treasure_effects_test.gd @@ -94,6 +94,23 @@ func _init() -> void: 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) var adr5 = runner_s.new(db, rng5) @@ -319,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 []