merge: 单关测试直入口退役——唯一试玩入口=完整三关冒险(用户指令 2026-09-23)
This commit is contained in:
commit
7040dbc51f
13 files changed
+58
-109
No files matched your search
@@ -12,7 +12,7 @@
|
||||
|---|---|---|---|
|
||||
| 第一层 | 地精洞窟 | 分支节点图(战斗 / 随机道具 / 恢复点 / Boss 等节点型) | 已落地(正式序列首关) |
|
||||
| 第二层 | 幽暗地域 | 同一分支节点图模板复用,第二关深度轴行值填充 | 已落地(正式序列已生效) |
|
||||
| 第三层 | 灰矮人矿城 | 同一分支节点图模板复用,第三关深度轴行值填充 | 已落地(正式序列已生效;测试直入口保留) |
|
||||
| 第三层 | 灰矮人矿城 | 同一分支节点图模板复用,第三关深度轴行值填充 | 已落地(正式序列已生效) |
|
||||
|
||||
现行节点行集与行值读 `data/tables/level.tres`(registry 为准)。再扩关卡走扩展批流程:先填深度轴行值、再接正式序列推进,不新造节点链结构。
|
||||
|
||||
@@ -62,7 +62,7 @@ MVP 不加新状态;扩容走 status_effects.tres 加行 + registry 登记。
|
||||
|
||||
垂直切片阶段明确砍掉或推迟的内容,写在这里防止回潮:
|
||||
|
||||
- 更多关卡(N>3)——第三关已按扩展批流程落地(行集 + 测试直入口);三关正式序列已生效(冒险结构实现批 2026-09-21)
|
||||
- 更多关卡(N>3)——第三关已按扩展批流程落地(行集);三关正式序列已生效(冒险结构实现批 2026-09-21),唯一试玩入口 = 完整冒险(单关测试直入口退役,2026-09-23 用户拍板)
|
||||
- 精英节点与词缀系统——只预留了字段位,不定义语义
|
||||
- 地形变异扩展内容——首批四类型已落地,反制道具与全局作用域排 Alpha(2026-09-20 用户拍板)
|
||||
- 道具/增益之间的组合协同(遗物式联动)
|
||||
|
||||
@@ -170,7 +170,7 @@ GP(显示名「金币」)是冒险内的一次性属性提升货币:战斗
|
||||
|
||||
重开 = 全新一轮冒险:注入新主种子、从第一关、满血、空手——不是"重打刚才那一关"。上一局清零的是生命账本、库存与种子;唯一保留面是冒险摘要,它给每次死亡一个可对照的坐标("这局到第二层"),重开因此是新局面而不是复读。
|
||||
|
||||
主动放弃按与失败同型结算:已获得的大奖励不追回、已到手的保留,摘要标记未打穿。放弃请求只在非战斗期受理,战斗进行中一律拒绝(战斗域单事务在飞)。放弃的界面入口挂在[关卡节点地图](关卡节点地图.md)的选路覆盖层上——选路停点天然是非战斗期,按钮只在冒险模式开放(单关测试直入口没有可放弃的冒险对象);战斗进行中没有选路停点,入口因此天然不可达,拒绝分支仅作防御兜底。
|
||||
主动放弃按与失败同型结算:已获得的大奖励不追回、已到手的保留,摘要标记未打穿。放弃请求只在非战斗期受理,战斗进行中一律拒绝(战斗域单事务在飞)。放弃的界面入口挂在[关卡节点地图](关卡节点地图.md)的选路覆盖层上——选路停点天然是非战斗期,按钮只在冒险模式开放(选路覆盖层只在冒险模式出现);战斗进行中没有选路停点,入口因此天然不可达,拒绝分支仅作防御兜底。
|
||||
|
||||
主种子(本文含义:冒险开始时注入的一个随机种子,本局全部随机性都派生自它)在冒险开始时注入恰一次。冒险内的雷图生成、奖励抽取、遭遇掷骰与 GP 掉落掷定(消费 gp_drop 封闭流)全部派生自它,冒险内不重置、不逐关播种——早期切片"每关开局各自播种"是没有冒险层时的历史简化,已改写为全冒险单一种子。冒险的可复现域 = 主种子 + 各随机流计数器,供复盘与快照(见[存档序列化](../表现与支撑/存档序列化.md))。重开抽到的种子与上一局相同是允许的(随机源范围小,撞种子不算错误),但生成新种子不得复用玩法里的随机数。
|
||||
|
||||
@@ -263,7 +263,7 @@ GP(显示名「金币」)是冒险内的一次性属性提升货币:战斗
|
||||
- 收束次序:通关宣布到达时库存已被关卡节点地图先行清空;重复的关卡结束宣布被拒绝,账本与摘要零变化。
|
||||
- 覆盖义务:冒烟断言——行集内每个战斗与关底节点(关、深)在敌人与棋盘生成的数值表中有精确行;序列关数 = 行集关数。
|
||||
- 生效前提未兑现(第二关行缺行):以单关冒险运行(合法态),两关断言显式跳过而非失败。
|
||||
- 放弃:战斗中的放弃请求被拒绝;非战斗期放弃按失败同型结算,已获大奖励不追回;放弃入口仅在选路停点呈现且只在冒险模式开放(单关测试直入口无放弃按钮)。
|
||||
- 放弃:战斗中的放弃请求被拒绝;非战斗期放弃按失败同型结算,已获大奖励不追回;放弃入口仅在选路停点呈现且只在冒险模式开放。
|
||||
- 种子域:冒险内零随机流自开,一切随机派生自主种子(含 GP 掉落掷定的 gp_drop 封闭流);同种子同操作序列两局逐位可复现。
|
||||
- GP 账本封闭:钱包只有三个收口——战斗完成入账恰一次(掉落掷定 + 关级加值 + 战斗内缓冲合计)、商店购买出账、冒险收束清零;战斗内缓冲与钱包隔离,战斗进行中钱包零变动。
|
||||
- GP 不留痕:GP 不入存档、不入冒险摘要;重开后钱包从零开始。
|
||||
@@ -284,3 +284,4 @@ GP(显示名「金币」)是冒险内的一次性属性提升货币:战斗
|
||||
| v0.5 | 2026-09-20 | **GP+商店房批(用户拍板——与关卡节点地图 v1.1 / 战斗结算 v0.23 / 地图战斗资源 v0.15 / 难度曲线与Boss v0.18 / registry / 切片同批)**:① 新增「GP 冒险账本」节——钱包三收口(战斗完成统一入账 / 商店购买出账 / 冒险收束清零)+ 战斗内缓冲隔离语义(格面兑付入缓冲、战斗完成统一到账、战斗域零钱包状态);② 统一冒险加算区成文——商店购买与关卡大奖励上限提升同一本账(三轴 {攻击, 生命上限, 护甲等级},经覆盖值通道生效;购血 = 上限与当前生命同步 +Δ);③ GP 掉落掷定消费 gp_drop 封闭随机流(主种子派生)登记进主种子节与调参表;④ GP 不入存档、不入冒险摘要;范围表 / 大奖励表 / 依赖表 / 验收标准同步。数值全 provisional-pending-曲线调参批,行值读 shop.tres |
|
||||
| v0.6 | 2026-09-21 | **冒险结构实现批落地登记(切片 AdventureRunner + LevelRunner 账本外置 + AdventureTable 建表——与切片代码 / registry / 03 / 06 / roadmap 同批)**:本批只记实现批状态,正文规则口径零改动。落地面 = 三关正式序列生效(首页「开始冒险」)、接口契约四件套正式侧承载(开始关卡 start_level_external / 战斗结果上报共享账本直写 / 治疗封顶回报 apply_rest / 关卡结束 level_finished)、生命账本与 GP 冒险账本上交冒险结构层、大奖励非末关恰兑付一次(末关钥石照记)、冒险摘要五件事产出、主种子恰一次注入(registry rng_service new_adventure 调用权同批登记)、结算受理只算一次;06 待办「两关序列未生效」「切片行进代码与定稿的接口漂移」「冒险表未建表」三条随批解决移除。**规划书冲突按代码为准登记两处**:①大奖励 `_pending_next_level` 置位先于 emit(信号同步派发——处理器内立即确认需标记已就位);②放弃受理补 state=running 守卫(契约 7 结算受理只算一次的 abandoned 侧对齐) |
|
||||
| v0.7 | 2026-09-21 | **放弃入口界面呈现批(用户拍板「放弃接口也要有」——台账 119,推翻本文原「MVP 无界面入口、呈现后置」条款)**:① 放弃入口挂[关卡节点地图](关卡节点地图.md)选路覆盖层(选路停点 = 天然非战斗期;战斗中拒绝转为防御兜底分支——入口在战斗期不可达);② 入口只在冒险模式开放,单关测试直入口没有可放弃的冒险对象;③ 正文改现行口径(放弃节 / 验收标准放弃条),P1 后置表「放弃入口的界面呈现」随落地移除(同表「两关序列生效」系 v0.6 已落地漏收口,顺手同口径移除);④ 验收闸 = ui_probe 三断言(默认隐藏 / 冒险模式可见 / 首战中按下被拒 state 保持 running)+ 冒烟既有放弃两态 API 断言 |
|
||||
| v0.8 | 2026-09-23 | **单关测试直入口退役(用户拍板——唯一试玩入口 = 完整三关冒险)**:正文改现行口径两处(放弃节「按钮只在冒险模式开放」的理由从「单关直入口无冒险对象」改为「选路覆盖层只在冒险模式出现」;验收标准放弃条同步去单关直入口从句)——放弃语义对象(整局冒险)与拒绝分支零改动。版本历史行(v0.7)按 ADR 纪律不回改 |
|
||||
@@ -95,7 +95,7 @@ SaveManager 不依赖任何玩法系统就能工作:它是被动的承载方
|
||||
|
||||
写盘是原子操作:先写临时文件(`<路径>.tmp`),写完改名覆盖正式档——写一半断电不留烂档。
|
||||
|
||||
单局测试入口不写档:关卡直入口(L2/L3)与调试两层路径不接写盘——测试模式不污染生涯数据;只有正式冒险(AdventureRunner)收束才入账。
|
||||
单局测试入口不写档:调试两层与 headless 单关测试路径(LevelRunner.start_level,仅 QA 工具使用)不接写盘——测试模式不污染生涯数据;只有正式冒险(AdventureRunner)收束才入账。
|
||||
|
||||
### 版本与迁移
|
||||
|
||||
@@ -157,3 +157,4 @@ MVP 不要求本系统的闭环([不做清单](../../05-不做清单.md)把单
|
||||
|---|---|---|
|
||||
| v0.1 | 2026-09-15 | 自归档线索整合为范围草案(旧体系未单独成文) |
|
||||
| v1.0 | 2026-09-21 | **存档序列化批(SaveManager 落地)**:格式裁决 JSON 单档 `user://save.json`;数据模型逐域成文(元进度四件 + 最近冒险摘要 cap 10);读写时机(启动读盘/冒险收束写盘/营地即时写/测试入口不写)+ tmp+rename 原子写;版本策略(高版本拒读禁写/低版本链式迁移/缺域补齐);损坏兜底(.corrupt.bak 备份 + 默认新档);待设计问题清单六条全部裁决成文(1/2/3/5/6 入核心规则,4 = 单档 MVP 多档留 P2)。自范围草案升定稿 |
|
||||
| v1.1 | 2026-09-23 | 单关测试直入口(L2/L3)退役(用户拍板——唯一试玩入口 = 完整冒险):不写档条款改口径为「调试两层与 headless 单关测试路径(LevelRunner.start_level,仅 QA 工具)」;写盘面零改动(正式冒险收束唯一写档点不变) |
|
||||
@@ -77,7 +77,7 @@ entities:
|
||||
format: JSON 单档(人可读可调试;字典键一律 String)
|
||||
version: SAVE_FORMAT_VERSION=1(registry schema_version 同源;高版本拒读 + 禁写盘 + 内存默认新档运行;低版本读档时链式迁移 register_migration,任一步失败按损坏兜底)
|
||||
domains: meta 域六件——keystone_balance(内容 owner=元进度)/ forge_levels 三档 max_hp·atk·armor_class(元进度)/ item_unlocks(元进度·道具工坊消费)/ level_clear_counts(元进度)/ boss_first_kill(元进度)/ recent_summaries cap 10 冒险摘要五件事副本(内容 owner=冒险结构;元素附 boss_drops 副本——Boss 两档金额入账随元进度实现批 2026-09-21 接通,apply_adventure_summary 第二参)
|
||||
write_timing: 启动读盘;正式冒险收束(adventure_finished → apply_adventure_summary)写盘;营地每笔钥石变更后即时写(元进度实现批接线);单关测试入口与调试两层不写档
|
||||
write_timing: 启动读盘;正式冒险收束(adventure_finished → apply_adventure_summary)写盘;营地每笔钥石变更后即时写(元进度实现批接线);调试两层与单关测试路径(LevelRunner.start_level,仅 QA 工具)不写档
|
||||
atomic_write: tmp + rename 原子写(写一半断电不留烂档——钥石不丢判据承载)
|
||||
corruption_policy: 坏档改名 <path>.corrupt.bak(已存在覆盖)+ 默认新档继续 + 警告留痕(不静默丢档不 crash)
|
||||
domain_boundary: 行动点/RAP/道具库存/生命账本/GP 不入档(局内资源单局清零;冒烟断言承载)
|
||||
|
||||
@@ -12,7 +12,7 @@
|
||||
|
||||
1. 用 Godot 4.7.2 打开本目录(含 `project.godot` 的文件夹)
|
||||
2. 按 F5 运行(主场景 `presentation/main.tscn`)
|
||||
3. **主入口:`▶ 开始冒险(三关连探:地精洞窟 → 幽暗地域 → 灰矮人矿城)`**——一条命走完三关(冒险结构实现批 2026-09-21:生命/GP/加算区跨关同账、非末关通关发大奖励〔上限提升+血回满+钥石〕、任意战斗倒下冒险终、结算屏出冒险摘要五件事;选路停点可「放弃冒险」(同失败结算,2026-09-21 用户拍板补入口));首关节点链:战→战→赏→战→战→疗→王。`▶ 测试直入口 · 第二关 / 第三关` 保留单关试玩模式
|
||||
3. **主入口:`▶ 开始冒险(三关连探:地精洞窟 → 幽暗地域 → 灰矮人矿城)`**——一条命走完三关(冒险结构实现批 2026-09-21:生命/GP/加算区跨关同账、非末关通关发大奖励〔上限提升+血回满+钥石〕、任意战斗倒下冒险终、结算屏出冒险摘要五件事;选路停点可「放弃冒险」(同失败结算,2026-09-21 用户拍板补入口));首关节点链:战→战→赏→战→战→疗→王。唯一试玩入口 = 完整冒险——单关测试直入口(L2/L3)已退役(2026-09-23 用户拍板)
|
||||
4. `测试用 · 角色数值调整板`:攻击/生命百分比加成(模拟天赋树解锁)+ 批量模拟(输出通关率/承伤期望/败北节点分布)
|
||||
|
||||
headless 冒烟(55 项断言,含关卡线性推进/满配通关/裸装败北/回放确定性,约 30 秒):
|
||||
@@ -169,7 +169,7 @@ Godot_v4.7.2-stable_win64_console.exe --headless --path . --script res://smoke/s
|
||||
|
||||
## L2 试玩采集清单(分支节点图批 2026-09-17——关卡 2「幽暗地域」试玩观测项)
|
||||
|
||||
入口:首页"▶ 测试直入口 · 第二关 · 幽暗地域(分支节点图试玩——岔路口选下一跳)"(测试模式直入口,种子框同用;正式序列走「开始冒险」主入口)。
|
||||
入口:「开始冒险」主入口推进到第二关段(单关测试直入口已退役——2026-09-23 用户拍板,唯一试玩入口 = 完整三关冒险;种子框同用)。
|
||||
|
||||
- **选路行为**:战斗胜利/兑付确认后弹出选路覆盖层(整图 + 候选按钮)——玩家是否理解"零自动推进、每跳都要选";单候选节点(恢复点→编号 6)是否被读成"卡住"。
|
||||
- **岔路使用率**:四处真实岔路的走向分布(入口 0→[1,2];战斗 1→[3,4];奖励 2→[4,5];深层 4→[6,7])——奖励点路线 vs 纯战斗路线的选择比例;整图渲染是否被实际用来规划(对比只点按钮的玩家)。
|
||||
|
||||
@@ -46,15 +46,6 @@ static func debug_open_line(seed_val: int, level: int, level_mode: bool) -> Stri
|
||||
seed_val, level, "(关卡模式 · HP 延续)" if level_mode else ""]
|
||||
|
||||
|
||||
# 关卡终局文案(result = victory/defeat;载荷 = runner level_finished 快照)
|
||||
static func level_end_text(result: String, payload: Dictionary, effective_max_hp: int) -> String:
|
||||
if result == "victory":
|
||||
return "关卡通关!\n剩余 HP %d/%d" % [
|
||||
int(payload.get("hp", 0)), effective_max_hp]
|
||||
return "关卡失败……探险者倒在了节点 %d(%s)。" % [
|
||||
int(payload.get("node_index", 0)) + 1, String(payload.get("node_type", ""))]
|
||||
|
||||
|
||||
# 调试战斗终局文案(level_end = 关内两层模式的关卡末)
|
||||
static func battle_end_text(result: String, level_end: bool) -> String:
|
||||
if level_end:
|
||||
|
||||
@@ -7,14 +7,14 @@
|
||||
# debug_session.gd(规范 1.1 审视线 + 调试语义单一实现)。
|
||||
# 组合根(composition root):唯一的模式流转与 core↔view 接线处。
|
||||
# 职责边界:① 构建四区视图并接线信号(节点构建归 ui_assembler.gd——规范 1.1,本类只接线)
|
||||
# ② 模式管理(完整关卡 关卡节点地图 runner / 调试两层——后者编排归 debug_session.gd;单场原语仅探针使用)
|
||||
# ② 模式管理(正式冒险 AdventureRunner——唯一试玩入口;调试两层编排归 debug_session.gd;单场原语仅探针使用)
|
||||
# ③ 核心写调用只在此处发生(minesweeper.settle_batch / 刷新编排入口 / runner 推进;
|
||||
# E4 收口:加成值零表写——面板百分比经 runner.set_hero_override / debug_session 生效值 Callable
|
||||
# 以 encounter 参数入战斗,db.hero 运行期只读)
|
||||
# ④ 全屏 States 状态机(挖掘/结算/终局)与一次性提示去重。
|
||||
# 2026-09-15 格面资源批:道具窗口与库存面板随可选类道具删除下线——E 区移除,窗口接线/选择序列删除。
|
||||
# GP+商店房实施批(2026-09-21):商店覆盖层挂接与信号接线(装配器零信号连接纪律——句柄返回、
|
||||
# 本类连接,仿 lv2btn 模式)+ runner.wallet_changed 转发试玩日志(wallet 行族)+ A 区顶栏金币余额。
|
||||
# 本类连接)+ runner.wallet_changed 转发试玩日志(wallet 行族)+ A 区顶栏金币余额。
|
||||
# 渲染与文案归 views/,核心状态→文案装配归 hud_presenter.gd 与 battle_narrator.gd,节点构建归
|
||||
# ui_assembler.gd,模态层级归 modal_stack.gd,批量模拟编排归 tune_sim_controller.gd,调试模式编排归
|
||||
# debug_session.gd——本类不拼呈现字符串。
|
||||
@@ -31,7 +31,7 @@ const MetaProgressionScript := preload("res://core/meta_progression.gd") # 元
|
||||
|
||||
var db
|
||||
var settlement = null # 当前战斗编排器(关卡与调试模式统一读它)
|
||||
var runner = null # 关卡节点地图 图版推进器(完整关卡模式;冒险模式 = 每关重取 adventure.runner())
|
||||
var runner = null # 关卡推进器(冒险模式每关重取 adventure.runner();单关 UI 直入口已退役——LevelRunner 仅存 headless 测试面)
|
||||
var adventure = null # 冒险结构编排器(冒险结构实现批——三关连探;转发信号照 runner 接线原样对接)
|
||||
var save_manager = null # 存档序列化承载(存档序列化批——启动读盘/冒险收束写盘;只经访问器与 apply 原语,禁读内部结构)
|
||||
var meta = null # 元进度账本服务(元进度实现批——余额/定价/购买/工坊解锁/Boss两档入账/注入计算;零信号纯被动)
|
||||
@@ -163,9 +163,7 @@ func _build_ui() -> void:
|
||||
var start: Dictionary = UiAssembler.build_start_overlay(self, db)
|
||||
_start_overlay = start.overlay
|
||||
_seed_edit = start.seed_edit
|
||||
start.lvbtn.pressed.connect(_start_full_level.bind(1))
|
||||
start.lv2btn.pressed.connect(_start_full_level.bind(2))
|
||||
start.lv3btn.pressed.connect(_start_full_level.bind(3))
|
||||
start.lvbtn.pressed.connect(_start_adventure_from_menu)
|
||||
start.tunebtn.pressed.connect(_show_tune_panel)
|
||||
start.dbgbtn.pressed.connect(_start_debug_levels)
|
||||
start.campbtn.pressed.connect(_open_camp)
|
||||
@@ -216,36 +214,11 @@ func _input_locked() -> bool:
|
||||
or _start_overlay.visible or _inter_overlay.visible or settlement == null
|
||||
|
||||
|
||||
# ==================== 完整关卡模式(关卡节点地图 图版推进器)====================
|
||||
# ==================== 冒险模式入口(唯一试玩入口——单关测试直入口退役 2026-09-23 用户拍板)====================
|
||||
|
||||
func _start_full_level(level_index: int = 1) -> void:
|
||||
func _start_adventure_from_menu() -> void:
|
||||
_start_overlay.visible = false
|
||||
if level_index == 1:
|
||||
_start_adventure() # 冒险首关即 L1——正式序列入口(冒险结构实现批)
|
||||
return
|
||||
# E4:加成经 runner.set_hero_override → encounter 参数入战斗(零表写——无双写叠加隐患)
|
||||
runner = LevelRunner.new(db, get_node("/root/RngService"))
|
||||
runner.set_hero_override(tune_panel.atk_pct(), tune_panel.hp_pct())
|
||||
runner.step_row.connect(_on_step_row)
|
||||
runner.round_started.connect(_on_round_started)
|
||||
runner.board_changed.connect(_on_board_changed)
|
||||
runner.node_entered.connect(_on_runner_node)
|
||||
runner.choices_presented.connect(_on_choices_presented)
|
||||
runner.level_finished.connect(_on_level_finished)
|
||||
runner.wallet_changed.connect(_on_wallet_changed)
|
||||
_level_active = true
|
||||
_adventure_mode = false
|
||||
route_overlay.set_abandon_available(false) # 单关测试直入口无冒险可放弃(放弃语义对象 = 整局冒险)
|
||||
_reset_run_scope()
|
||||
log_view.clear()
|
||||
var seed_val := _seed_value()
|
||||
logger.start_session(seed_val) # 各战斗的 attach 在 _on_runner_node 内(settlement 逐战创建)
|
||||
if not runner.start_level(level_index, seed_val):
|
||||
_fatal_screen("关卡启动失败——见输出日志")
|
||||
return
|
||||
log_view.append_bb(Narrator.level_open_line(String(runner.level_row.get("display_name", "")),
|
||||
seed_val, int(db.hero.atk), int(db.hero.max_hp),
|
||||
tune_panel.atk_pct() > 0 or tune_panel.hp_pct() > 0))
|
||||
_start_adventure()
|
||||
|
||||
|
||||
# 冒险模式(三关连探——AdventureRunner 编排;转发信号签名与 runner 一致,接线照原样对接;
|
||||
@@ -322,28 +295,6 @@ func _on_runner_node(node: Dictionary, info: Dictionary) -> void:
|
||||
_refresh_presentations()
|
||||
|
||||
|
||||
func _on_level_finished(payload: Dictionary) -> void:
|
||||
_level_active = false
|
||||
var result: String = String(payload.get("result", ""))
|
||||
settlement = null
|
||||
_close_modal(route_overlay) # 终局兜底(放弃入口新场景:选路层在开态——走模态栈恢复其遮挡面;未开过时 close 容错)
|
||||
_sync_settlement_visuals() # → 全关
|
||||
info_panel.set_status_cleared_feedback() # 状态槽全清可见反馈(增益状态×4④)
|
||||
stage.gray_all_enemies() # 死亡兜底:站桩灰化残位(禁瞬消语义的战斗收尾面)
|
||||
if result == "victory":
|
||||
# 胜利终局 overlay(金蜡封落于棋盘中央)
|
||||
_end_overlay.open_victory(Narrator.level_end_text("victory", payload, runner.effective_max_hp()),
|
||||
"返回冒险", board_view.get_global_rect())
|
||||
else:
|
||||
_end_overlay.open_defeat(Narrator.level_end_text("defeat", payload, 0),
|
||||
"返回", board_view.get_global_rect())
|
||||
logger.log_level_end(payload) # 试玩时间线:关卡终局
|
||||
runner.restore_hero_base() # 关卡结束——覆盖值归零(下次从面板重新应用)
|
||||
strip_view.refresh(runner)
|
||||
_open_modal(_end_overlay)
|
||||
_refresh_presentations()
|
||||
|
||||
|
||||
# ---- 冒险模式终局面(大奖励屏 / 冒险结算屏——冒险结构实现批)----
|
||||
|
||||
# 大奖励兑付(非末关通关恰一次):复用 _inter_overlay(label + 确认按钮,零新增交互范式);
|
||||
@@ -364,7 +315,7 @@ func _on_adventure_finished(summary: Dictionary) -> void:
|
||||
info_panel.set_status_cleared_feedback() # 状态槽全清可见反馈(增益状态×4④)
|
||||
stage.gray_all_enemies() # 死亡兜底:站桩灰化残位(禁瞬消语义的战斗收尾面)
|
||||
# 存档入账(元进度实现批):settle = Boss 两档入账 + 工坊解锁 + 摘要入档 + 写盘(唯一写档点不变——
|
||||
# 单关测试入口与调试两层不经过本处理器,天然不写档不污染生涯数据)。
|
||||
# 调试两层不经过本处理器,天然不写档不污染生涯数据)。
|
||||
var detail: Dictionary = {}
|
||||
if meta != null:
|
||||
detail = meta.settle_adventure(summary)
|
||||
@@ -490,7 +441,7 @@ func _show_board_fx_for_node(node_type: String = "") -> void:
|
||||
|
||||
|
||||
func _on_battle_finished(payload: Dictionary) -> void:
|
||||
# 仅调试模式接线(完整关卡的结束归 关卡节点地图 runner._on_level_finished)
|
||||
# 仅调试模式接线(冒险的关卡结束归 AdventureRunner._on_level_finished——大奖励/冒险终局分派)
|
||||
var result: String = String(payload.get("result", ""))
|
||||
_sync_settlement_visuals() # → 全关(battle_over 反馈面)
|
||||
stage.gray_all_enemies() # 死亡兜底:站桩灰化残位(禁瞬消语义的战斗收尾面)
|
||||
|
||||
@@ -85,7 +85,7 @@ static func build_overlays(host: Control, db, base_atk: int, base_hp: int) -> Di
|
||||
var end_overlay := BattleEndOverlay.new()
|
||||
host.add_child(end_overlay)
|
||||
|
||||
# 商店覆盖层(GP+商店房实施批 2026-09-21——商店房节点兑付呈现;按钮接线归组合根 lv2btn 模式)
|
||||
# 商店覆盖层(GP+商店房实施批 2026-09-21——商店房节点兑付呈现;按钮接线归组合根,装配器零信号连接)
|
||||
var shop_overlay := ShopOverlay.new()
|
||||
host.add_child(shop_overlay)
|
||||
|
||||
@@ -129,13 +129,9 @@ static func build_start_overlay(host: Control, db = null) -> Dictionary:
|
||||
seed_edit.custom_minimum_size = Vector2(120, 0)
|
||||
seed_row.add_child(seed_edit)
|
||||
|
||||
# 冒险结构实现批(2026-09-21):lvbtn = 正式「开始冒险」入口(三关序列);L2/L3 保留测试直入口
|
||||
# 唯一试玩入口 = 正式「开始冒险」(三关序列);单关测试直入口(L2/L3)退役(2026-09-23 用户拍板)
|
||||
var lvbtn := UiKit.button("▶ 开始冒险(三关连探:地精洞窟 → 幽暗地域 → 灰矮人矿城)")
|
||||
box.add_child(lvbtn)
|
||||
var lv2btn := UiKit.button("▶ 测试直入口 · 第二关 · 幽暗地域(分支节点图试玩——岔路口选下一跳)")
|
||||
box.add_child(lv2btn)
|
||||
var lv3btn := UiKit.button("▶ 测试直入口 · 第三关 · 灰矮人矿城(基线红档属预期,配合调整板加成试玩)")
|
||||
box.add_child(lv3btn)
|
||||
var tunebtn := UiKit.button("测试用 · 角色数值调整板(模拟天赋树属性提升)")
|
||||
box.add_child(tunebtn)
|
||||
var dbgbtn := UiKit.button("调试 · 连续关卡两层(HP 关内延续)")
|
||||
@@ -151,7 +147,7 @@ static func build_start_overlay(host: Control, db = null) -> Dictionary:
|
||||
box.add_child(help)
|
||||
|
||||
return {"overlay": overlay, "box": box, "seed_edit": seed_edit,
|
||||
"lvbtn": lvbtn, "lv2btn": lv2btn, "lv3btn": lv3btn, "tunebtn": tunebtn, "dbgbtn": dbgbtn,
|
||||
"lvbtn": lvbtn, "tunebtn": tunebtn, "dbgbtn": dbgbtn,
|
||||
"campbtn": campbtn}
|
||||
|
||||
|
||||
|
||||
@@ -7,7 +7,7 @@
|
||||
# 无任何写面;图形为程序化占位质量(占位纪律)。
|
||||
# 放弃入口(2026-09-21 用户拍板「放弃接口也要有」——台账 119;推翻 冒险结构.md「MVP 无界面入口」
|
||||
# 后置条款):选路停点 = 天然非战斗期(接口契约:战斗中放弃一律拒绝),按钮常驻本层底部;
|
||||
# 可见性归组合根(冒险模式开、单关测试直入口关——放弃的语义对象是"整局冒险")。
|
||||
# 可见性归组合根(只在冒险模式开——放弃的语义对象是"整局冒险";调试两层无节点图天然不可达)。
|
||||
class_name RouteOverlay
|
||||
extends Control
|
||||
|
||||
@@ -25,7 +25,7 @@ const NODE_LABELS := {"battle": "战", "reward": "赏", "rest": "疗", "boss": "
|
||||
var _runner = null
|
||||
var _btn_box: VBoxContainer
|
||||
var _title: Label
|
||||
var abandon_btn: Button # 放弃入口(可见性归组合根 set_abandon_available——冒险模式开/单关测试直入口关)
|
||||
var abandon_btn: Button # 放弃入口(可见性归组合根 set_abandon_available——只在冒险模式开)
|
||||
|
||||
|
||||
func _init() -> void:
|
||||
@@ -58,7 +58,7 @@ func _init() -> void:
|
||||
visible = false
|
||||
|
||||
|
||||
# 放弃入口可见性(组合根在冒险启动/单关直入口启动时切换——语义对象 = 整局冒险)
|
||||
# 放弃入口可见性(组合根在冒险启动时开、默认关——语义对象 = 整局冒险)
|
||||
func set_abandon_available(v: bool) -> void:
|
||||
abandon_btn.visible = v
|
||||
|
||||
|
||||
@@ -24,7 +24,7 @@ var _tested_legend := false
|
||||
var _tested_review := false
|
||||
var _tested_refresh_chain := false
|
||||
var _tested_tooltip := false
|
||||
var _tested_l2 := false # 分支节点图批:L2 入口行为段(首页直入口 + 岔路选路真实点击)
|
||||
var _inter_confirms := 0 # 大奖励屏确认计数(冒险推进停点——首见确认推进 L2,再见 = L2 通关收口)
|
||||
var _route_clicks := 0 # 选路覆盖层点击计数(岔路使用率观测面)
|
||||
|
||||
|
||||
@@ -84,9 +84,9 @@ func _ready() -> void:
|
||||
var iso_reset = load("res://core/save_manager.gd").new("user://smoke_click_probe_reset.json")
|
||||
iso_reset.load_from_disk()
|
||||
main.meta = load("res://core/meta_progression.gd").new(main.db, iso_reset)
|
||||
main.tune_panel.set_sliders(200, 100)
|
||||
main.tune_panel.set_sliders(400, 200) # 高加成保 L1 可通关——L2 岔路选路段只能经冒险推进到达(单关直入口退役)
|
||||
var t1 := Time.get_ticks_msec()
|
||||
main._start_full_level()
|
||||
main._start_adventure_from_menu()
|
||||
var t_entry := Time.get_ticks_msec() - t1
|
||||
# 性能 AC:进入战斗屏到首格可点 ≤500ms(棋盘 install 完成口径);
|
||||
# 场景实例化冷启动总时长(含全部脚本首载编译——引擎启动域,非 AC 口径)另列观测
|
||||
@@ -98,7 +98,7 @@ func _ready() -> void:
|
||||
_problems.append("首格未可点(cells=0)")
|
||||
print("[click_probe] 首格可点计时 %dms(进入战斗屏口径,≤500ms AC)· 场景冷启动 %dms(含 UI 构建 %dms,观测项)" % [
|
||||
first_cell_ms, t_total, t_ui_ready])
|
||||
var action_budget := 9000
|
||||
var action_budget := 20000
|
||||
while not _done and action_budget > 0:
|
||||
action_budget -= 1
|
||||
await get_tree().process_frame
|
||||
@@ -117,24 +117,33 @@ func _ready() -> void:
|
||||
main.shop_overlay.leave_pressed.emit()
|
||||
_flags_placed.clear()
|
||||
continue
|
||||
if main._inter_overlay.visible:
|
||||
# 大奖励屏(冒险级停点——非末关通关恰一次):首见确认推进 L2(真实按钮信号路径);再见 = L2 已通关,收口
|
||||
if not main._input_locked():
|
||||
_problems.append("大奖励屏打开时输入未锁定")
|
||||
_inter_confirms += 1
|
||||
if _inter_confirms == 1:
|
||||
var next_btn: Button = _find_button_by_prefix(main._inter_overlay, "进入下一层")
|
||||
if next_btn == null:
|
||||
_problems.append("大奖励屏确认按钮缺失")
|
||||
else:
|
||||
next_btn.pressed.emit()
|
||||
await get_tree().process_frame
|
||||
await get_tree().process_frame
|
||||
if main.runner == null or int(main.runner.level_row.get("level_index", -1)) != 2:
|
||||
_problems.append("大奖励确认后未推进到第二关(level_index != 2)")
|
||||
else:
|
||||
_done = true
|
||||
print("[click_probe] 第二关大奖励屏(L2 通关)——探针收口 · 选路口点击 %d 次" % _route_clicks)
|
||||
break
|
||||
_flags_placed.clear()
|
||||
continue
|
||||
if main._end_overlay.is_open():
|
||||
# 终局 overlay 模态断言(pattern 6:打开时输入锁定)
|
||||
# 冒险终局(失败/放弃/打穿)——单关直入口退役后无二段入口,见终局即收口(模态断言照旧)
|
||||
if not main._input_locked():
|
||||
_problems.append("终局 overlay 打开时输入未锁定")
|
||||
if not _tested_l2:
|
||||
# L1 终局 → 首页直入口切换 L2(分支节点图批行为段:真实"返回"路径 + start_level(2))
|
||||
_tested_l2 = true
|
||||
print("[click_probe] L1 结束:%s——切换关卡 2 试玩入口" % main._end_overlay.verdict_text().replace("\n", " "))
|
||||
main._on_battle_end_continue() # 终局出口(真实"返回"按钮处理器——全量清理回开始层)
|
||||
if not main._start_overlay.visible:
|
||||
_problems.append("终局返回后未回到开始覆盖层")
|
||||
main.tune_panel.set_sliders(200, 100)
|
||||
main._start_full_level(2)
|
||||
if main.runner == null or int(main.runner.level_row.get("level_index", -1)) != 2:
|
||||
_problems.append("关卡 2 直入口启动失败(level_index != 2)")
|
||||
continue
|
||||
_done = true
|
||||
print("[click_probe] 关卡结束:%s · 选路口点击 %d 次" % [
|
||||
print("[click_probe] 冒险终局:%s · 选路口点击 %d 次" % [
|
||||
main._end_overlay.verdict_text().replace("\n", " "), _route_clicks])
|
||||
break
|
||||
if main.settlement == null or main.runner == null:
|
||||
|
||||
@@ -10,7 +10,7 @@ func _ready() -> void:
|
||||
var main = load("res://presentation/main.tscn").instantiate()
|
||||
add_child(main)
|
||||
await get_tree().process_frame
|
||||
main._start_full_level()
|
||||
main._start_adventure_from_menu()
|
||||
for i in range(3):
|
||||
await get_tree().process_frame
|
||||
var win := get_window()
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
# VERTICAL SLICE - NOT FOR PRODUCTION
|
||||
# 实现 GDD:design/ux/battle.md(场景级 headless 探针——四区布局实例化断言;entry 17②③)。
|
||||
# Date: 2026-09-12(战斗屏改造批扩展;基础 = 2026-09-11 首战棋盘探针——既有断言全保留)
|
||||
# 项目运行模式(autoload 在位)实例化 main.tscn,直接驱动 _start_full_level(),
|
||||
# 项目运行模式(autoload 在位)实例化 main.tscn,直接驱动 _start_adventure_from_menu()(完整冒险——唯一试玩入口),
|
||||
# 断言四区真实构建(棋盘/进度条/主角站桩/敌方站桩/AP 点阵/明细带/数据框;E 区道具面板已删除;
|
||||
# 2026-09-20 全站桩拍板——英雄卡/敌人卡断言随站桩改造批换装)。
|
||||
# 运行:Godot_console.exe --headless --path . res://smoke/ui_probe.tscn
|
||||
@@ -14,9 +14,9 @@ func _ready() -> void:
|
||||
add_child(main)
|
||||
await get_tree().process_frame
|
||||
var problems: Array = []
|
||||
# ---- 放弃入口(2026-09-21 用户拍板——台账 119):默认隐藏(单关测试直入口无冒险可放弃)----
|
||||
# ---- 放弃入口(2026-09-21 用户拍板——台账 119):默认隐藏(非冒险模式无冒险可放弃——开始层/调试两层)----
|
||||
if main.route_overlay.abandon_btn == null or main.route_overlay.abandon_btn.visible:
|
||||
print("[ui_probe] FAIL — 放弃按钮默认应隐藏(单关测试直入口关)")
|
||||
print("[ui_probe] FAIL — 放弃按钮默认应隐藏(非冒险模式关)")
|
||||
get_tree().quit(1)
|
||||
return
|
||||
# ---- 营地覆盖层(元进度实现批——主菜单入口/开合/余额文案/购买禁用态;
|
||||
@@ -58,7 +58,7 @@ func _ready() -> void:
|
||||
var iso_zero = load("res://core/save_manager.gd").new("user://smoke_ui_probe_camp.json")
|
||||
iso_zero.load_from_disk()
|
||||
main.meta = load("res://core/meta_progression.gd").new(main.db, iso_zero)
|
||||
main._start_full_level()
|
||||
main._start_adventure_from_menu()
|
||||
await get_tree().process_frame
|
||||
await get_tree().process_frame
|
||||
# ---- 放弃入口·冒险模式可见 + 战斗中按下被拒(真实按钮路径——入口挂选路停点,战斗中拒绝为防御分支)----
|
||||
|
||||
@@ -61,7 +61,7 @@ func _ready() -> void:
|
||||
# (攻击 ×2 / 生命 +50%)——旧缺陷(残留值被当基线再乘)在 encounter 参数链上同样被抓获
|
||||
main.tune_panel.set_sliders(100, 50)
|
||||
main.tune_panel.press_apply_for_probe()
|
||||
main._start_full_level() # 完整关卡路径(_start_single 按语义清零滑条 = 恒基线,不承载加成断言)
|
||||
main._start_adventure_from_menu() # 完整冒险路径(唯一试玩入口;_start_single 按语义清零滑条 = 恒基线,不承载加成断言)
|
||||
await get_tree().process_frame
|
||||
await get_tree().process_frame
|
||||
var hero: Dictionary = main.settlement.presentation_snapshot().hero
|
||||
|
||||
Reference in new issue
Block a user