feat(slice): 措辞收口+数值对齐+场景一/三拍板落地批——①registry 指路化收口:主角条目去 MVP 值改读 hero.tres、技能条目七行枚举(补收撕咬/毒爆)+倍率冷却保底指路 skills.tres、敌人条目五敌种枚举+池权重 EV 读数指路 enemy.tres、charge_grants/equivalence_ref_damage/board_gen 参考行删旧值改指路、中点锚改 floor 向下取整口径(与切片校验式对齐);②刷新临时名全链退役:refresh_max_per_round→refresh_cap_per_round、request_refresh_active→request_refresh、can_request_refresh→can_refresh(8 文件 grep 零残留)+行动经济「字段名对齐待批」注记收口;③五区残留清零:玩家可见副标题改战斗屏四区、build_five_zone→build_battle_ui、探针文案/注释 11 处;④行动经济 schema 默认值 8/8→6/6 随压速批+明细字号抬标 14px(HUD框架可访问性下限)+RAP−8 字面量 6 处改表值驱动(ap_bar_view.set_refresh_cost 装配注入通道,toast 同步动态化);⑤意图徽标三档占位(普攻—/伤害技⚔/增益技✦/重击类蓄力)——技能名退出徽标堵剧透(2026-09-18 用户拍板,终稿动画三档归样张后,美术清单 §2.3 在案);⑥R1 进度解析口径修订(数据配置 v0.4 用户两段拍板):ceil 向上取整保证偏难+超出最大行封顶取最大值+域越界 Fatal 诊断进程退出码 1(config_db _ceil_key/_fatal 通道+config_fatal_probe 探针实测退出码 1+冒烟 ceil/clamp 两断言)+registry enemy_table 进度键 ceil 同步;⑦tune 探针断言表值驱动修复(旧字面量 6/50、12/75 随数值压缩批失效,改读 db 基线派生);⑧06 待办四条目(意图徽标占位小修已解决/分辨率档位 1280×800+1920×1080 定案/变异对初始展开影响语义挂起)+美术资源依赖清单成文(场景一产物);冒烟 296 全绿+ui/click/layout/tune 四探针 PASS+fatal 探针退出码 1(伤害道具批、护甲重配批、数值纪律收口批归并行会话 a2fc39f/cdc226e 在先提交,行动经济改名 hunks 本批全链收口)
This commit is contained in:
1 parent
a2fc39ff17
commit
0da19a5b09
24 files changed
+346
-115
No files matched your search
@@ -0,0 +1,131 @@
|
||||
# 美术资源依赖清单(Art Assets Checklist)
|
||||
|
||||
> **性质**:表现层升级批与战斗表现批的生产侧清单——把散在战斗表现 / HUD框架 / 关卡节点地图 / 敌人系统里的资产需求收拢成一张可执行的工单视图。**规范效力归各 owner 文档**(战斗表现、美术圣经、04-美术音频方向),本文只补「生产视角的需求规格」,冲突时以 owner 文档为准。
|
||||
> **建立**:2026-09-18 场景一(战斗画面呈现)讨论产物。意图动画三档为用户当日拍板,文档改写随实施批。
|
||||
|
||||
## 0. 生产通道与通用规格
|
||||
|
||||
**两条生产通道**:
|
||||
|
||||
- ✦ **ComfyUI(用户自跑)**:角色、插画级素材。每个敌种/主角建议出 **2–3 版候选**供裁决,不直接出终稿。
|
||||
- ⚙ **脚本管线(代理出)**:图标、格面、样张类精度资产(先例:`samples/generate_hero_sample.py` 站姿样张)。
|
||||
|
||||
**风格宪法**:全部资产受 [art-bible](art-bible.md) 约束,出图前先读三节——
|
||||
|
||||
| 条款 | 对出图的具体要求 |
|
||||
|---|---|
|
||||
| 一句话视觉规则 | 明快的地牢,轻快的扫荡,仔细的推理——**明亮像素幻想,全年龄,非暗黑**,角色 2~3 头身 |
|
||||
| 原则一「预告上格」 | 格内绘制优先级 **数字 > 小人 > 旗 > 徽章 > 变异纹理 > 底色**;徽章不得遮挡数字字形区 |
|
||||
| 原则二「明亮为皮,对比为骨」 | 高亮度暖倾向;格底相对亮度 L≥0.30、HSV 饱和 ≤0.40;数字墨 L≤0.027(对比 ≥4.5:1) |
|
||||
| 原则三「一砖一世界」 | 变体优先换色板不加新资产;危险状态必须**形状+颜色双通道**(色弱灰度可辨) |
|
||||
| 剪影哲学(§3.1) | **所有角色自带轮廓通道:亮色描边+落影底盘**,识别不依赖背景;五类原型见各条目 |
|
||||
| 语义色规则(§4.2) | 红只说危险(旗朱 `#C63D22` / 危险红 `#A8321F`)、金只说收益(`#F0A828`)、蓝只说己方(`#2E6E8E`)、**紫赤 `#8F2F6A` 为 Boss 独占,HSV 色相 300°–345° 全场禁入带** |
|
||||
| UI 形状语法(§3.3) | 半拟物:面板=石板圆角矩形(与地砖同圆角率),按钮=可按的砖,仪式确认=圆形蜡封;数据区直角细线无纹理 |
|
||||
|
||||
**参考图**:`design/art/references/`(Into the Breach / Moonlighter / Peglin 等九款×2 张)。
|
||||
|
||||
---
|
||||
|
||||
## 1. P0 —— 样张(一切终稿资产的硬前置)
|
||||
|
||||
### 1.1 格子样张(砖面形态定稿闸)⚙
|
||||
|
||||
- **要什么**:一张按 art-bible §1.4 参数画成的格子风格试验图。内容清单(缺项即无效):未开格(覆尘完整砖)、已开格(碎裂裸露,含 0 与 1–8 全档数字)、雷格(被惊动的巢穴纹)、旗、小人两态(独立占格+与数字同格)、biome 色板变体组(四槽换色至少两套)。
|
||||
- **风格/规格**:色板 token 直接取 §4.1(掩尘 `#C9AF83`、裸土 `#B39A78`、数字墨三档、旗朱、危险红、奖励金、小人蓝);砖面=圆角方形衍生,只以完整度叙事。
|
||||
- **验收**:§1.4 四项按序判定(数字可读性 WCAG ≥4.5:1 硬指标 → 格态三形灰度可辨 → 焦点预算 → biome 换皮抽测)。**通过 = 砖面形态与色板冻结**。
|
||||
- **现状**:验收标准已成文,测试未跑。
|
||||
|
||||
### 1.2 战斗一屏样张(双舞台,2–3 版候选)⚙格面骨架 + ✦角色剪影候选
|
||||
|
||||
- **要什么**:按双舞台布局(战斗画面与扫雷图同屏常驻)出的整屏试验图。要锁的四件事:**角色剪影方向 / 动画方案 / 战斗空间 / 敌人层绘制优先级插入位置**;顺带裁决**敌人卡形态:卡片式 vs 站桩式(无框立绘+底座)**——两版候选各出一版。
|
||||
- **风格/规格**:敌人剪影按五类原型出(见 2.2);战斗舞台背景=明亮地窟,紫赤仅 Boss。
|
||||
- **验收**:战斗表现「一屏样张的验收标准」(已成文)。
|
||||
- **联动**:样张未过,**不启动任何终稿资产与动画设计**(文档明文的排期硬前置);HUD框架「格边长两档定值」条款将由表现层升级批按分辨率档位计算口径改写(2026-09-18 用户拍板:固定几档分辨率、窗口不可调、格子量增加则格边长相应变小;**候选档位 1280×800 + 1920×1080 待拍板**)。
|
||||
|
||||
---
|
||||
|
||||
## 2. P1 —— 角色级(样张通过后开工,ComfyUI)
|
||||
|
||||
### 2.1 主角战斗小人
|
||||
|
||||
- **要什么**:待机 / 攻击 / 受击 三态起步(移动态样张后定);透明底 PNG。
|
||||
- **风格/规格**:小人原型——**窄、直立、对称,轮廓凹凸 ≤2**;2~3 头身两档下剪影均成立;主色小人蓝 `#2E6E8E`;格内占位最窄、不吞数字位。
|
||||
- **现状**:站姿样张已有(`samples/hero-standing-pose.png`,脚本管线产物),战斗三态未出。
|
||||
|
||||
### 2.2 六敌种形象
|
||||
|
||||
| 敌种 | 剪影原型(§3.1) | 风格要点 |
|
||||
|---|---|---|
|
||||
| 地精 goblin | 普通怪:近圆墩形,宽≥高,零锐角 | Peglin 式胖体量,先读轮廓后读颜色 |
|
||||
| 熊地精 bugbear | 普通怪或精英档(加一处垂直延伸:角/冠/棘) | 第一关显示名「熊地精」 |
|
||||
| 食人魔酋长 ogre_chief | 精英档:普通怪形+恰一处垂直延伸,底盘不变 | 重甲语义可走色板不作形状独占 |
|
||||
| 巨蜘蛛 giant_spider | 普通怪(多足轮廓注意凹凸计数控制) | 群行 [2,3],同屏最多 3 只,剪影需小体量可辨 |
|
||||
| 兄弟精(bugbear 变体) | 与熊地精**同剪影换色板**(L2 幽暗地域部族) | 换色不换形——biome 换皮原则的角色侧应用 |
|
||||
| 蛛化卓尔精灵 drider(Boss) | **敌类唯一允许锐角与不对称**,体量最大 | 紫赤 `#8F2F6A` 色相独占;「形状独占+色相独占」双通道 |
|
||||
|
||||
- **通用规格**:亮色描边+落影底盘轮廓通道硬规则;透明底 PNG;每敌种 2–3 版候选。
|
||||
- **联动**:显示名以 registry / 敌人表为准(兄弟精=熊地精复用,2026-09-17 用户拍板)。
|
||||
|
||||
### 2.3 意图准备动画三档(2026-09-18 用户拍板)
|
||||
|
||||
- **要什么**:用**动作动画**替代文字徽标预告敌方下一拍,三档:
|
||||
1. **普通攻击 = 常态准备动画**——待机姿态本身就是预示,不另做动作;
|
||||
2. **攻击技能 = 特殊准备动画**——放光、高举武器等「摇号感」动作;
|
||||
3. **重击/硬化类 = 蓄力动作或防御姿态**。
|
||||
- **风格/规格**:三档在**灰度/剪影层也可辨**(双通道纪律);每档动画时长与结算节拍对齐(预告时序 = 下一拍、挖掘期全程可见)。
|
||||
- **联动**:HUD框架「意图徽标不预告技能名与数值」条款由本拍板承接为动画承载(文字与技能名彻底退出);战斗表现「特殊技两型动画」输入清单按三档改写;映射按 enemy_id 全局恒定(跨 run 禁重掷)。
|
||||
- **现状**:占位符号已落地(2026-09-18:普通攻击「—」/ ⚔ / ✦ / 重击类「蓄力」,技能名退出徽标);终稿动画待样张后开工。
|
||||
|
||||
---
|
||||
|
||||
## 3. P2 —— 图标与格面(脚本管线,可与样张并行)
|
||||
|
||||
### 3.1 格面资源徽章 14 枚(七型 × 正负)⚙
|
||||
|
||||
- **要什么**:增伤 / 护甲 / 恢复 / 爆裂 / 削弱 / 穿刺 / 魔法,各正负一枚(负向:反噬 / 伏击加层 / 恢复倒扣 / 失衡 / 削弱自伤 / 穿刺陷阱 / 魔法反噬)。
|
||||
- **风格/规格**:图标键契约 §4.6(冻结);**极性色相槽只有两族——有利兑付=金族、有害兑付=红族**,不新增语义色;徽章=附属小图标,非完整凸形(不构成第二焦点),栈位在旗之下、变异纹理之上。
|
||||
- **现状**:程序化占位徽标(文本/符号),够试玩不够观感。
|
||||
|
||||
### 3.2 关卡节点图图标组 ⚙/✦
|
||||
|
||||
- **要什么**:四类节点图标(战斗 / 奖励 / 恢复 / Boss)+ 图版行进器形象(棋子)。
|
||||
- **风格/规格**:容器走石板圆角语法;Boss 节点可用紫赤;奖励节点可用奖励金;恢复节点绿=自然生机(零逻辑语义,仅氛围);行进器=小人同族蓝。
|
||||
- **联动**:正式节点图 UI 设计未成文(登记待办:排魔法道具内容批后与美术批同期待拍板);HUD框架义务清单漏「关卡节点地图」行,随批补。
|
||||
|
||||
### 3.3 雷 / 旗 / 数字格面像素化 ⚙
|
||||
|
||||
- **要什么**:格子样张通过后按冻结参数出全套砖面资产(含 biome 换色板组)。
|
||||
- **前置**:§1.1 格子样张通过。
|
||||
- **现状**:程序化绘制,可读性达标(对比硬指标已是现行实现依据),观感待升级。
|
||||
|
||||
---
|
||||
|
||||
## 4. P3 —— 演出类(战斗打磨项,样张后排期)
|
||||
|
||||
| 资产 | 需求 | 风格/规格要点 |
|
||||
|---|---|---|
|
||||
| 受击反馈 / 死亡表现 / 顺位标记 | 敌人系统登记的资产需求**下限三类** | 死亡=血条归零后**灰化+碎裂退场,禁止瞬间消失**;顺位标记需在敌多时可读 |
|
||||
| 特殊技动画终稿 | 并入 §2.3 三档意图动画,不另起体系 | 攻/防两型旧口径由三档替代 |
|
||||
| 连锁坍塌显形演出 | 连锁展开触发时的连锁演出 | 与音频方向同批配对登记;「坍塌显形」=连锁展开的玩家可见名 |
|
||||
| 弹道/退场等动画密度 | 战斗表现输入清单,方案未定 | 样张锁动画方案后启动 |
|
||||
|
||||
---
|
||||
|
||||
## 5. 明确不在本清单
|
||||
|
||||
- **音乐音效**:文档定稿「MVP 占位即可,核心循环验证后再定」。
|
||||
- **地形变异专属纹理**:变异表为空,纹带种类待地形变异批定夺(形状通道规则已备)。
|
||||
- **精英/Boss 编码位相关新资产**:随关卡节点地图改键批裁决后再议。
|
||||
|
||||
## 6. 执行顺序(依赖链)
|
||||
|
||||
```
|
||||
格子样张(1.1) ──┬─> 雷旗数字格面(3.3)
|
||||
│
|
||||
战斗一屏样张(1.2) ──> 角色终稿(2.1/2.2) ──> 意图动画三档(2.3) ──> 演出类(P3)
|
||||
│
|
||||
└─> 敌人卡形态裁决(卡片式 vs 站桩式,用户看图拍板)
|
||||
徽章(3.1)/节点图(3.2) —— 独立线,可随时插队
|
||||
```
|
||||
|
||||
**用户侧待拍板小项**(场景一遗留):① ~~占位期意图符号小修~~——已落地(2026-09-18,技能名退出徽标);② ~~分辨率档位~~——已定案(1280×800 + 1920×1080 两档,后续调整走修订)。
|
||||
+47
-1
@@ -58,6 +58,14 @@
|
||||
|
||||
**状态**:待办
|
||||
|
||||
#### 变异对初始展开(开局免费点开区域)的影响语义
|
||||
|
||||
**现状**:2026-09-18 用户拍板:雾格移除后变异体系暂缓,本项挂起随首批变异定稿一并迭代。两件挂账——① 数据层残留一处「带变异的 0 格不参与初始展开传播」分支(board_data.gd,变异表为空从未触发),与排雷玩法规则层的展开实现口径分裂(规则层不看变异);② 变异格该不该影响开局免费展开、影响规则是什么,未定稿。届时二选一:删死分支对齐「零特判」纪律,或在文档登记该行为为正式语义
|
||||
|
||||
**归属**:地形变异首批类型定稿批
|
||||
|
||||
**状态**:待办
|
||||
|
||||
### 魔法道具
|
||||
|
||||
#### 显影尘效果重定
|
||||
@@ -336,7 +344,7 @@
|
||||
|
||||
#### 雷格与安全格的资源分布差异化(Alpha 批)
|
||||
|
||||
**现状**:现行雷安同池——安全格与雷格从同一类型池、同一权重分布摇定类型身份(结构冻结项,地图战斗资源 v0.4 七项之一)。用户 2026-09-17 拍板要做这件差异化的事,定位 **Alpha 版本**上线;垂直切片期先「把游戏做完整」不动结构(读数基线刚被护甲换装+技能池批与数值压缩批归零,验收重测与真人试玩未跑)。调研底座已交付:[proposal-reward-cell-differentiation-2026-09-17.md](../research/proposal-reward-cell-differentiation-2026-09-17.md)——三条候选路径(双池切分〔旧提案 mine_cell 有成案可翻〕/ 单池双列 weight_mine / 修饰位摇后过滤);差异化必破「雷安同池」冻结项、走 GDD 修订流程(用户已明示冻结约束执行侧不约束 owner,允许下破冻结即合法修订);纯权重调整零破冻结但有 9 处连带同步位(含 2 处 v0.7 漏网过期注释实证);外部无「同池不同权」中间态先例
|
||||
**现状**:现行雷安同池——安全格与雷格从同一类型池、同一权重分布摇定类型身份(结构冻结项,地图战斗资源 v0.4 七项之一)。用户 2026-09-17 拍板要做这件差异化的事,定位 **Alpha 版本**上线;垂直切片期先「把游戏做完整」不动结构(读数基线刚被护甲换装+技能池批与数值压缩批归零,验收重测与真人试玩未跑)。调研底座已交付:[proposal-reward-cell-differentiation-2026-09-17.md](../research/proposal-reward-cell-differentiation-2026-09-17.md)——三条候选路径(双池切分〔旧提案 mine_cell 有成案可翻〕/ 单池双列 weight_mine / 修饰位摇后过滤);差异化必破「雷安同池」冻结项、走 GDD 修订流程(用户已明示冻结约束执行侧不约束 owner,允许下破冻结即合法修订);纯权重调整零破冻结但有 9 处连带同步位(含 2 处 v0.7 漏网过期注释实证);外部无「同池不同权」中间态先例。关联条目:见本节「冒险前资源配比预设(构筑提案)」(2026-09-18 登记的玩家侧分布控制权提案——同为类型分布语义的结构修订,立项时评估合并)
|
||||
|
||||
**前置**:① 验收批读数重测与真人试玩先跑——差异化核心未知数(玩家是否利用类型分布先验绕雷/追格)只有真人数据能回答;② 拍掉调研报告第 8 章八个待决项(差异化区分的轴 / 雷·安当量分化后的行动经济条款③⑤与恒等式对账窗口 / heal 权重整数档位 / tier_min_buff 口径 / 同步流程口径扩充等)后出定稿提案
|
||||
|
||||
@@ -344,6 +352,28 @@
|
||||
|
||||
**状态**:待办(方向已拍板 2026-09-17;实施窗口 = Alpha)
|
||||
|
||||
#### 冒险前资源配比预设(构筑提案)
|
||||
|
||||
**现状**:2026-09-18 用户提案,方向评估通过,登记在案。核心想法 = 玩家在**开始冒险前**预设地图战斗资源的类型配比——预设的是**分布**(七型在格面上的权重占比),不是落位:装板摇号仍按专属随机流摇出各格类型身份,玩家定分布、摇号定落位,无固定出招剧本(与既定随机性立场相容)。两分法:① **基础资源配比**——玩家对七型格面池(attack 增伤 / defense 护甲 / heal 回血 / blast 群伤 / weaken 削弱 / pierce 穿刺 / magic 魔法)的正向行权重做配比,经覆盖值通道在开局注入,摇号按覆盖后的分布落位;② **关卡特殊资源**——不同关卡(board_biome 图主题)的地图携带配比池之外的特殊资源与差异化分布。设计红利:雷安同池 + 极性矩阵使配比自带代价轴——调高某型权重,安全格正向与雷格负向同步变多,配比 =「赌自己挖掘少失误 + 赌关卡敌人构成怕什么」的双重下注,不是免费午餐,无需另发明平衡机制。架构红利:① 的注入通道 = [元进度](systems/冒险循环/元进度.md) v1.0 刚定稿的「冒险开始参数面 + 覆盖值通道」(追加/替换集合操作已登记),零新机制;② 正是[棋盘生成](systems/排雷循环/棋盘生成.md) board_biome 上下文与[地图战斗资源](systems/战斗循环/地图战斗资源.md)`clear_<图类型>` 差异化插槽、P1 功能道具渠道等预留位的启用场景。
|
||||
|
||||
**影响面(按循环)**:
|
||||
- 排雷循环:[行动经济](systems/排雷循环/行动经济.md)——经济契约对账以资源行值为原材料,类型频次构成随配比漂移,对账窗口须按配比包络复算;[棋盘生成](systems/排雷循环/棋盘生成.md)——生成管线零改动(资源身份摇号不在其域),board_biome 词表定稿是关卡特殊资源的前置;[排雷玩法](systems/排雷循环/排雷玩法.md)——挖掘/标旗动作决定极性、承载配比的风险轴,机制零改动;[魔法道具](systems/排雷循环/魔法道具.md)——相邻:预读类道具读取身份查询面,配比改变分布先验后「资源预读与推理的边界」读感联动,不做机制耦合。
|
||||
- 战斗循环:[地图战斗资源](systems/战斗循环/地图战斗资源.md)——主战场:候选集合权重来源从纯表值扩为「表值 × 玩家覆盖」;基础配比是整体平移分布,「雷安同池」(同池同分布)语义不破,不动结构冻结;[战斗结算](systems/战斗循环/战斗结算.md)——唯一调用方:摇号入口需受理开局注入的权重覆盖,兑付编排零改动;[增益状态](systems/战斗循环/增益状态.md)——零改动(percent 行效果引用不变,配比只改触发频率不改状态语义);[敌人系统](systems/战斗循环/敌人系统.md)——间接:各关敌种构成是配比预测的对象,混编遭遇行集的走向影响配比博弈读数。
|
||||
- 冒险循环:[元进度](systems/冒险循环/元进度.md)——配比能力的家:可用类型 / 预算点数 / 预设槽位走营地柜台解锁,配比预设 = 覆盖值通道的又一生产者;[冒险结构](systems/冒险循环/冒险结构.md)——冒险开始参数面扩容,配比覆盖域的字段语义待裁;[难度曲线与Boss](systems/冒险循环/难度曲线与Boss.md)——杠杆主权转移:设计者从「定权重」改为「定预算包络、玩家在包络内分配」,通关率验收带随配比漂移,切片与验收期必须锁默认权重;[关卡节点地图](systems/冒险循环/关卡节点地图.md)——关卡特殊资源与节点奖励(功能道具渠道)的分工须一次说清:特殊资源走图内格面池差异化,功能道具走节点奖励,两渠道不混。
|
||||
- 表现与支撑:[HUD 框架](systems/表现与支撑/HUD框架.md)——新增构筑界面(冒险前的配比设置面)与配比效果的局内可读呈现;[教学引导](systems/表现与支撑/教学引导.md)——新增「读敌配比」教学口径;[数据配置](systems/表现与支撑/数据配置.md)——配比预设存档域与预算参数表建账,registry 新条目;[存档序列化](systems/表现与支撑/存档序列化.md)——预设档契约域随批登记(与元进度存档四件同批)。
|
||||
|
||||
**依赖(本提案依赖谁)**:① 冒险开始参数面 + 覆盖值通道([元进度](systems/冒险循环/元进度.md) v1.0 已定稿口径,现成);② 七型候选集合与权重语义([地图战斗资源](systems/战斗循环/地图战斗资源.md) v0.10 现行结构);③ board_biome 词表定稿([棋盘生成](systems/排雷循环/棋盘生成.md),关卡特殊资源的前置);④ 数据配置表承载与存档域(预设持久化);⑤ 元进度解锁状态(可用配比容量)。
|
||||
|
||||
**被依赖(谁会依赖本提案)**:HUD 构筑界面呈现;教学新口径;难度曲线与Boss 验收判读口径(配比包络下的通关率带复算,换算率表强条目纪律同类);行动经济对账窗口;registry 与架构概念图的结构登记(新节点落地时 archify 图须重交付)。
|
||||
|
||||
**开放问题(立项前裁决)**:① **预算机制**——自由滑条必出支配策略(全拉穿刺 + 魔法〔必中克制直伤〕大概率唯一解,构筑空间反死),候选 = 点数总预算 / 每型上限 / 配比槽位本身当解锁内容——最大设计题;② **杠杆主权切分**——切片与验收期锁默认权重(测量保护),正式期「设计者定包络、玩家分配」的参数归属;③ **与永久强化的分工**——配比容量(可用类型/点数/槽位)映射到营地三柜台哪几个;④ **基础配比的注入语义**——权重覆盖走数值覆盖还是集合操作(追加/替换),参数面字段裁决;⑤ **关卡特殊资源与功能道具渠道的边界**——图内格面池差异化与节点奖励不混池的口径。
|
||||
|
||||
**前置**:① 验收批读数重测与真人试玩先跑——配比博弈的核心未知数(玩家配比是否收敛到唯一解、分布先验怎么被利用)只有真人数据能回答(与「雷格与安全格的资源分布差异化(Alpha 批)」同前置);② 当前批序列走完:本批审批 → 验收重测 → 曲线调参 → 魔法道具内容批;③ 立项时与「雷格与安全格的资源分布差异化(Alpha 批)」合并评估——同为类型分布语义的结构修订、同一冻结面,一批做省一次修订流程。
|
||||
|
||||
**归属**:[地图战斗资源](systems/战斗循环/地图战斗资源.md)修订批(基础配比的权重覆盖语义 + GDD 修订)与[元进度](systems/冒险循环/元进度.md)(解锁容量与注入生产者)共裁;呈现面归[HUD 框架](systems/表现与支撑/HUD框架.md)与[教学引导](systems/表现与支撑/教学引导.md)随批。
|
||||
|
||||
**状态**:待办(2026-09-18 用户提案、方向评估通过;实施窗口 = Alpha,与「雷格与安全格的资源分布差异化(Alpha 批)」合并立项)
|
||||
|
||||
### 战斗表现
|
||||
|
||||
#### 敌人卡形态
|
||||
@@ -576,6 +606,22 @@
|
||||
|
||||
**状态**:待办
|
||||
|
||||
#### 意图徽标占位期符号小修
|
||||
|
||||
**现状**:切片意图徽标直接显示技能名(剧透强度);2026-09-18 用户拍板终稿方向 = 动画三档承载意图预告(常态=普攻预示 / 攻击技=发光举武器 / 重击硬化=蓄力或防御姿态,见 [美术资源依赖清单](../../art/art-assets-checklist.md) §2.3),终稿动画须样张后开工——占位期是否先把文字换成 ⚔/✦/蓄力三个符号堵住剧透,待拍板
|
||||
|
||||
**归属**:表现层升级批(占位期小修已先行落地)
|
||||
|
||||
**状态**:已解决(2026-09-18 占位符号落地:普通攻击「—」/ 伤害技 ⚔ / 增益技 ✦ / 重击类「蓄力」三档占位,技能名退出徽标;终稿三档动画仍归表现层升级批,见 [美术资源依赖清单](../../art/art-assets-checklist.md) §2.3)
|
||||
|
||||
#### 分辨率档位与棋盘格边长口径
|
||||
|
||||
**现状**:2026-09-18 用户拍板:格边长不取固定两档,按分辨率档位计算——最终呈现固定几个分辨率、窗口不可调;棋盘格子量增加则界面框架不变、格边长相应变小。[HUD框架](systems/表现与支撑/HUD框架.md)现行「两档定值 36/45px」冻结条款待按此修订;分辨率档位已定案(2026-09-18 用户拍板:**1280×800 + 1920×1080 两档**,后续调整走修订)
|
||||
|
||||
**归属**:表现层升级批(HUD框架 修订随批)
|
||||
|
||||
**状态**:待办(档位已定案,条款修订随表现层升级批)
|
||||
|
||||
### 数据配置
|
||||
|
||||
#### 变异表旧字段集是否沿用
|
||||
|
||||
@@ -119,7 +119,7 @@
|
||||
|
||||
### 进度坐标查行:跟着冒险进度成长的表带两维坐标
|
||||
|
||||
跟着冒险进度成长的表(难度、生成参数、敌人配置)每行带(关卡序号 × 节点深度)两维坐标——难度曲线的雕刻轴从第一天就留在表结构层,而不是散落各处的魔法数字。解析规则两条:其一,进度坐标就近取用,无精确行时取不超过请求坐标的最近已有行并留一条警告(警告按"哪张表、缺哪维、停在哪个键"去重,是开发期异常信号而非审计工具);其二,实体键精确匹配,那一行没有这个名字就是悬空引用,直接致命中止——进度可以就近近似,"是哪种敌人"不能近似,身份近似会静默改变遭遇构成。
|
||||
跟着冒险进度成长的表(难度、生成参数、敌人配置)每行带(关卡序号 × 节点深度)两维坐标——难度曲线的雕刻轴从第一天就留在表结构层,而不是散落各处的魔法数字。解析规则两条:其一,进度坐标向上取整(2026-09-18 用户拍板修订,原「就近向下」退役)——无精确行时取**不低于**请求坐标的最近已有行并留一条警告(警告按"哪张表、缺哪维、停在哪个键"去重,是开发期异常信号而非审计工具);取整方向的理由是**保证偏难**:宁可在内容缺口上高估难度让工具读数保守,不可静默降难掩盖断档;请求坐标低于合法域(关卡序号 <1、节点深度 <0)不属于取整,走运行期致命;请求高于最大已有行时**取最大已有行封顶**(2026-09-18 追加拍板:可取范围内向上取整,超出最大值就用最大值,封顶同样留警告)。其二,实体键精确匹配,那一行没有这个名字就是悬空引用,直接致命中止——进度可以向上近似,"是哪种敌人"不能近似,身份近似会静默改变遭遇构成。
|
||||
|
||||
三条配套边界。每关必须含深度 0 的锚行(关卡入口行),缺失即加载期致命,防止入口请求静默落到深处行造成难度突刺。请求越域(关卡序号小于 1 或深度为负)在进入解析前致命中止。没有兜底行、没有外推:超过表范围的成长外推归[难度曲线与Boss](../冒险循环/难度曲线与Boss.md)的公式职责,本系统只解析到最近已有行——解析永不发明数据。
|
||||
|
||||
@@ -187,7 +187,7 @@
|
||||
| 表路径清单 | data/tables/ 固定(调试注入根除外) | 冻结:散装路径破坏单点访问 |
|
||||
| 表结构版本常量 `SCHEMA_VERSION` | 实现期定(MVP = 1,provisional) | 全部表结构携带版本字段;高于当前支持的版本拒读,比较逻辑归[存档序列化](存档序列化.md) |
|
||||
| 随机流清单 | 封闭三流(board_gen / reward_roll / encounter) | 冻结清单;增流 = 改代码 + 评审,有意设卡 |
|
||||
| 进度坐标解析策略 | 就近取已有行 + 警告;无兜底行、无外推 | 冻结:引入静默外推会掩盖难度断档 |
|
||||
| 进度坐标解析策略 | 可取范围内向上取整 + 警告(保证偏难);超出最大行封顶取最大值 + 警告;域越界致命(2026-09-18 两段拍板,原「就近向下」退役) | 冻结:静默降难会掩盖难度断档 |
|
||||
| 入口锚行校验 | 写死开 | 非调参项;重议走文档修订流程 |
|
||||
| 调试覆盖开关 | 仅调试构建,默认关 | 正式构建结构性不存在;覆盖值永不回写表文件 |
|
||||
|
||||
@@ -198,8 +198,8 @@
|
||||
- 致命真的会死:任一致命夹具经正式通道加载,进程非 0 退出,而非仅"校验器能发现"。
|
||||
- 黄金向量:随机派生纯函数对登记向量逐个复算相等;同输入恒同输出;同流同序号重复调用恒等。
|
||||
- 计数器纪律:连续取号跨模拟关卡切换,计数器单调不重置;热重载成败都不改变主种子与计数器。
|
||||
- 就近解析:请求无精确行时返回不超过请求坐标的最近行并留一条警告,同类警告去重;精确命中零警告。
|
||||
- 越域与未播种:坐标越域在进入解析前致命中止;未设主种子就取随机数致命中止,无默认种子兜底。
|
||||
- 向上取整解析:请求无精确行时返回**不低于**请求坐标的最近行并留一条警告;请求超出最大已有行时封顶取最大行并留警告;同类警告去重;精确命中零警告。
|
||||
- 越域与未播种:坐标低于合法域(关卡序号 <1、节点深度 <0)在进入解析前致命中止(Fatal 级诊断 + 进程退出码 1,切片探针 `smoke/config_fatal_probe.gd` 验证);高于最大已有行走封顶取最大行(警告留痕,不致命);未设主种子就取随机数致命中止,无默认种子兜底。
|
||||
- 热重载门:战斗中重载被拒绝且读数不变、不发通知;门未置位时新值可读且通知恰一次;校验失败保留旧表停留就绪态。
|
||||
- 版本常量在位:表结构版本常量存在且全部表结构携带版本字段(高版本拒读判定归存档序列化)。
|
||||
- 零字面量、零第二路径:静态扫描加人工复核确认玩法代码无数值字面量、无读取口之外的表加载、无全局随机函数调用。
|
||||
@@ -217,3 +217,4 @@
|
||||
| v0.1 | 2026-09-15 | 自归档 GDD 压缩改写 |
|
||||
| v0.2 | 2026-09-15 | 雾格残留清理:关闭「待拍板」的棋盘生成参数表雾字段清理登记(fog_region_count / fog_target_ratio 两字段、雾占比绝对上限与雾域跨字段校验)——字段与校验随雾格移除同批删除,registry `board_gen_table` 条目同步修订。表清单与校验纪律不变 |
|
||||
| v0.3 | 2026-09-17 | 代币→钥石统一拍板随批措辞清偿:表清单冒险表行「代币记账」改「钥石入账」;registry adventure_table 同批改键 token_per_level→keystone_per_level。表清单与校验纪律不变 |
|
||||
| v0.4 | 2026-09-18 | **进度坐标解析口径修订(用户拍板,场景三讨论产物)**:① 取整方向「就近向下」→「**向上取整**」——无精确行取不低于请求坐标的最近行,理由 = 保证偏难(宁高估难度让工具读数保守,不静默降难掩盖断档);② 越域致命补齐——低于合法域(关卡序号 <1、节点深度 <0)走运行期致命:Fatal 级诊断 + 进程退出码 1,与装载期致命纪律并轨;**同日追加拍板**:高于最大已有行不致命,封顶取最大已有行并留警告(用户裁定「可取范围内向上取整,超过了最大值就用最大值」);③ registry enemy_table 条目「进度键 floor」随批改 ceil;切片 config_db._resolve_progress 同批落地(ceil 选择器 + _fatal 通道 + `smoke/config_fatal_probe.gd` 探针 + 冒烟 ceil 断言) |
|
||||
@@ -248,7 +248,7 @@ entities:
|
||||
type: schema_data
|
||||
owner: design/gdd/systems/战斗循环/敌人系统.md
|
||||
attributes:
|
||||
table: EnemyTable(数据配置 承载,键 (level_index, node_depth, enemy_id);敌人系统 回填 owner,2026-09-09 定稿回填——进度键 floor(数据配置 R1)+ 实体键精确匹配)
|
||||
table: EnemyTable(数据配置 承载,键 (level_index, node_depth, enemy_id);敌人系统 回填 owner,2026-09-09 定稿回填——进度键 ceil 向上取整保证偏难、超出最大行封顶取最大值(数据配置 R1,2026-09-18 用户两段拍板修订,原 floor 退役)+ 实体键精确匹配)
|
||||
fields:
|
||||
enemy_id: String(行集内主键;意图视觉映射键——视觉推测型 HUD框架×4①)
|
||||
display_name: String(本地化归 设置与本地化)
|
||||
|
||||
@@ -100,7 +100,7 @@ func request_stop() -> bool:
|
||||
# 轮内刷新(2026-09-12 方案 A 用户拍板;等待期通道 2026-09-15 用户拍板整体移除):唯一入口 =
|
||||
# Active 相位——仅扣 RAP,相位与 AP 均不动。刷新不打断轮次、不触发结算;换图编排归 战斗结算
|
||||
# (retire + install 立即执行,玩家同轮继续挖新图)。决策主体 = 玩家(经 HUD框架发起)纪律不变。
|
||||
func request_refresh_active() -> bool:
|
||||
func request_refresh() -> bool:
|
||||
if phase != PHASE_ACTIVE:
|
||||
_reject("phase")
|
||||
return false
|
||||
|
||||
@@ -51,7 +51,7 @@ var _facts_reveals: Array = []
|
||||
var _facts_flags: Array = []
|
||||
var _facts_path := ""
|
||||
var _settling := false
|
||||
var _refresh_used_this_round := 0 # 每轮刷新计数(Active 相位合计,兜底上限 = ActionEconomyTable.refresh_max_per_round)
|
||||
var _refresh_used_this_round := 0 # 每轮刷新计数(Active 相位合计,兜底上限 = ActionEconomyTable.refresh_cap_per_round)
|
||||
var _board_seq := 0 # 板序号(本战斗第几张板——快照归因用)
|
||||
var _board_from_midround_refresh := false # 装板 provenance:轮内刷新换来的图 = true(清图奖励守卫——刷新图不发清图奖励)
|
||||
var _flag_consumed := {} # 兑付资格以雷格实例为键(板级;换图重置)
|
||||
@@ -688,9 +688,9 @@ func _exit_distribution() -> void:
|
||||
|
||||
|
||||
# 呈现层查询面(HUD 刷新按钮可用性)——挖掘期唯一通道
|
||||
func can_request_refresh() -> bool:
|
||||
func can_refresh() -> bool:
|
||||
return battle_result == "" \
|
||||
and _refresh_used_this_round < int(db.action_economy.refresh_max_per_round) \
|
||||
and _refresh_used_this_round < int(db.action_economy.refresh_cap_per_round) \
|
||||
and action_economy.phase == action_economy.PHASE_ACTIVE \
|
||||
and action_economy.rap >= int(db.action_economy.rap_refresh_cost)
|
||||
|
||||
@@ -699,9 +699,9 @@ func can_request_refresh() -> bool:
|
||||
# 挖掘期唯一通道(2026-09-12 方案 A 拍板 + 2026-09-15 等待期通道整体移除):Active 相位立即换图
|
||||
# 继续挖(RAP -8;AP 保留、相位不动、不触发结算);非挖掘期请求一律拒绝——非清图轮恒同图。
|
||||
func player_request_refresh() -> bool:
|
||||
if not can_request_refresh():
|
||||
if not can_refresh():
|
||||
return false
|
||||
if not action_economy.request_refresh_active():
|
||||
if not action_economy.request_refresh():
|
||||
return false
|
||||
_refresh_used_this_round += 1
|
||||
_reward_economy.retire_mapping() # 旧图批次退役(地图战斗资源 Ready→retired;E6 新批重置前提)
|
||||
@@ -725,7 +725,7 @@ func _battle_over(result: String) -> void:
|
||||
# ---- 呈现状态面(E1 封装收口 2026-09-13):呈现层 / headless 自动玩家的唯一读取出口——
|
||||
# 协作对象(_enemy_system/_status_effects/_reward_economy)私有化后,跨层读取一律经本快照或下列命名面(diagnostic_snapshot 同款模式,
|
||||
# 禁再链式穿透 settlement.enemy_system.hero 一类路径)。载荷 schema 成文(code-conventions 2.1):
|
||||
# round / battle_result / phase / ap / rap / can_request_refresh / hero{hp,max_hp,atk,alive,armor_class} /
|
||||
# round / battle_result / phase / ap / rap / can_refresh / hero{hp,max_hp,atk,alive,armor_class} /
|
||||
# enemies[{order,display_name,hp,max_hp,enemy_id,armor_type,armor_class,pending_skill,pending_type,pending_name,effects[],ambush_layers,alive}] /
|
||||
# (敌人技能池批批 2 定稿:beat/ring_size/ring_index 拆除 → pending_* 三字段 + 敌方增益 effects 投影;池与权重不公开)
|
||||
# ambush_layers / hero_effects[](增益状态 query_active 投影)
|
||||
@@ -769,7 +769,7 @@ func presentation_snapshot() -> Dictionary:
|
||||
"battle_result": battle_result,
|
||||
"phase": String(action_economy.phase),
|
||||
"ap": int(action_economy.ap), "rap": int(action_economy.rap),
|
||||
"can_request_refresh": can_request_refresh(),
|
||||
"can_refresh": can_refresh(),
|
||||
"hero": hero,
|
||||
"enemies": enemies,
|
||||
"ambush_layers": ambush,
|
||||
|
||||
@@ -42,10 +42,21 @@ var _reload_gate := false # 数据配置 EC8——战斗结
|
||||
|
||||
func push_diag(severity: String, category: String, message: String) -> void:
|
||||
_diagnostics.append({"severity": severity, "category": category, "message": message})
|
||||
if severity == "error":
|
||||
push_error("[ConfigDB/%s] %s" % [category, message])
|
||||
elif severity == "warning":
|
||||
if severity == "warning":
|
||||
push_warning("[ConfigDB/%s] %s" % [category, message])
|
||||
else:
|
||||
push_error("[ConfigDB/%s] %s" % [category, message])
|
||||
|
||||
|
||||
# 运行期数据致命(2026-09-18 用户拍板:越域记 Fatal 级日志后立即退出——数据配置通道 fail-fast 纪律补齐到查询期)
|
||||
func _fatal(category: String, message: String) -> void:
|
||||
push_diag("fatal", category, message)
|
||||
push_error("[ConfigDB/%s] FATAL: %s —— 数据配置致命,进程退出" % [category, message])
|
||||
var main_loop := Engine.get_main_loop()
|
||||
if main_loop is SceneTree:
|
||||
main_loop.quit(1) # 帧末退出,退出码 1——调用方须立即 return,勿再消费返回值
|
||||
else:
|
||||
OS.crash("ConfigDB/%s fatal: %s" % [category, message])
|
||||
|
||||
|
||||
func reset_diagnostics() -> void:
|
||||
@@ -188,7 +199,7 @@ func validate_skill_pool_links(skill_table, enemy_table) -> Array:
|
||||
return errs
|
||||
|
||||
|
||||
# ---- R1 难度行解析(floor + warning 四元组去重;请求越域致命)----
|
||||
# ---- R1 难度行解析(2026-09-18 用户拍板修订:ceil 向上取整保证偏难;域越界与内容缺口 Fatal 退出)----
|
||||
|
||||
func resolve_board_gen(L: int, D: int) -> Dictionary:
|
||||
return _resolve_progress(board_gen.rows, L, D, "board_gen")
|
||||
@@ -213,66 +224,65 @@ func resolve_difficulty_modifiers(L: int, D: int) -> Dictionary:
|
||||
|
||||
func _resolve_progress(rows: Array, L: int, D: int, table_id: String) -> Dictionary:
|
||||
if L < 1 or D < 0:
|
||||
push_diag("error", "request_oob", "%s 请求越域 (%d,%d)" % [table_id, L, D])
|
||||
_fatal("request_oob", "%s 请求越域 (%d,%d)——进度坐标低于合法域(关卡序号≥1、节点深度≥0)" % [table_id, L, D])
|
||||
return {}
|
||||
var levels := {}
|
||||
var level_keys: Array = []
|
||||
for row in rows:
|
||||
levels[int(row.get("level_index", 0))] = true
|
||||
var level_keys := levels.keys()
|
||||
var lv := int(row.get("level_index", 0))
|
||||
if not level_keys.has(lv):
|
||||
level_keys.append(lv)
|
||||
if level_keys.is_empty():
|
||||
_fatal("structural", "%s 行集为空——锚行校验应已拦截" % table_id)
|
||||
return {}
|
||||
level_keys.sort()
|
||||
var l_star: int
|
||||
var mt_level := "exact"
|
||||
if L < level_keys[0]:
|
||||
l_star = level_keys[0]
|
||||
mt_level = "ceil"
|
||||
else:
|
||||
l_star = level_keys[0]
|
||||
for lv in level_keys:
|
||||
if lv <= L:
|
||||
l_star = lv
|
||||
if l_star < L:
|
||||
mt_level = "floor"
|
||||
var depth_keys := {}
|
||||
var l_star := _ceil_key(level_keys, L)
|
||||
var l_clamped := l_star < 0
|
||||
if l_clamped:
|
||||
l_star = int(level_keys[-1]) # 超出最大行 → 取最大行封顶(2026-09-18 追加拍板:可取范围内向上取整,超出用最大值)
|
||||
var depth_keys: Array = []
|
||||
for row in rows:
|
||||
if int(row.get("level_index", 0)) == l_star:
|
||||
depth_keys[int(row.get("node_depth", 0))] = true
|
||||
var d_keys := depth_keys.keys()
|
||||
d_keys.sort()
|
||||
var d_star: int
|
||||
var mt_depth := "exact"
|
||||
if d_keys.is_empty():
|
||||
push_diag("error", "structural", "%s level %d 无行(锚行校验应已拦截)" % [table_id, l_star])
|
||||
return {}
|
||||
if D < d_keys[0]:
|
||||
d_star = d_keys[0]
|
||||
mt_depth = "floor"
|
||||
else:
|
||||
d_star = d_keys[0]
|
||||
for dv in d_keys:
|
||||
if dv <= D:
|
||||
d_star = dv
|
||||
if d_star < D:
|
||||
mt_depth = "floor"
|
||||
var dv := int(row.get("node_depth", 0))
|
||||
if not depth_keys.has(dv):
|
||||
depth_keys.append(dv)
|
||||
depth_keys.sort()
|
||||
var d_star := _ceil_key(depth_keys, D)
|
||||
var d_clamped := d_star < 0
|
||||
if d_clamped:
|
||||
d_star = int(depth_keys[-1])
|
||||
var missing := ""
|
||||
if mt_level == "ceil":
|
||||
missing = "base_ceil"
|
||||
elif mt_level == "floor" and mt_depth == "floor":
|
||||
missing = "both"
|
||||
elif mt_level == "floor":
|
||||
missing = "level_floor"
|
||||
elif mt_depth == "floor":
|
||||
missing = "depth_floor"
|
||||
if l_clamped and d_clamped:
|
||||
missing = "both_clamp"
|
||||
elif l_clamped:
|
||||
missing = "level_clamp"
|
||||
elif d_clamped:
|
||||
missing = "depth_clamp"
|
||||
elif l_star != L and d_star != D:
|
||||
missing = "both_ceil"
|
||||
elif l_star != L:
|
||||
missing = "level_ceil"
|
||||
elif d_star != D:
|
||||
missing = "depth_ceil"
|
||||
if missing != "":
|
||||
var dedup_key := "%s|%s|%d|%d" % [table_id, missing, l_star, d_star]
|
||||
if not _warn_dedup.has(dedup_key):
|
||||
_warn_dedup[dedup_key] = true
|
||||
push_diag("warning", "resolve_" + missing, "%s 请求 (%d,%d) floor 解析 → (%d,%d) [%s]" % [table_id, L, D, l_star, d_star, missing])
|
||||
var verb := "clamp 解析(超出最大行取最大值)" if missing.contains("clamp") else "ceil 解析(向上取整保证偏难)"
|
||||
push_diag("warning", "resolve_" + missing, "%s 请求 (%d,%d) %s → (%d,%d) [%s]——2026-09-18 拍板" % [table_id, L, D, verb, l_star, d_star, missing])
|
||||
for row in rows:
|
||||
if int(row.get("level_index", 0)) == l_star and int(row.get("node_depth", 0)) == d_star:
|
||||
return row
|
||||
return {}
|
||||
|
||||
|
||||
# 取 sorted_keys 中第一个 >= request 的键;无(请求高于最大行)返回 -1 → 调用方 Fatal
|
||||
func _ceil_key(sorted_keys: Array, request: int) -> int:
|
||||
for k in sorted_keys:
|
||||
if int(k) >= request:
|
||||
return int(k)
|
||||
return -1
|
||||
|
||||
|
||||
# ---- 地形变异 variant_pool_gate:候选池门控(∅ biome_tag = 通配)----
|
||||
|
||||
func variant_pool(level_index: int, board_biomes: Array) -> Array:
|
||||
|
||||
@@ -6,12 +6,12 @@
|
||||
class_name ActionEconomyTable
|
||||
extends Resource
|
||||
|
||||
@export var ap_per_round: int = 8 # [1,32] knob
|
||||
@export var ap_per_round: int = 6 # [1,32] knob(默认值 = 现行表值基线,2026-09-16 AP 压速批 8→6 随动)
|
||||
@export var dig_ap_cost: int = 1 # [1,8] knob(域下限 1 = 零预算系统失效拒绝)
|
||||
@export var flag_place_ap_cost: int = 1 # [0,8] knob
|
||||
@export var flag_pull_ap_cost: int = 1 # [0,8] knob
|
||||
@export var rap_refresh_cost: int = 8 # [1,64] knob
|
||||
@export var refresh_max_per_round: int = 2 # [1,8] knob(2026-09-12 轮内刷新批——每轮刷新兜底上限,Active/Waiting 合计)
|
||||
@export var rap_refresh_cost: int = 6 # [1,64] knob(默认值随 AP 压速批 8→6 随动)
|
||||
@export var refresh_cap_per_round: int = 2 # [1,8] knob(2026-09-12 轮内刷新批——每轮刷新兜底上限,Active/Waiting 合计)
|
||||
@export var move_ap_cost: int = 0 # 冻结 0(P4 氛围承载)
|
||||
@export var chain_ap_cost: int = 0 # 冻结 0(v2 定稿)
|
||||
|
||||
@@ -28,8 +28,8 @@ func validate() -> Array:
|
||||
errs.append({"category": "domain", "message": "flag_pull_ap_cost 越域 [0,8]: %d" % flag_pull_ap_cost})
|
||||
if rap_refresh_cost < 1 or rap_refresh_cost > 64:
|
||||
errs.append({"category": "domain", "message": "rap_refresh_cost 越域 [1,64]: %d" % rap_refresh_cost})
|
||||
if refresh_max_per_round < 1 or refresh_max_per_round > 8:
|
||||
errs.append({"category": "domain", "message": "refresh_max_per_round 越域 [1,8]: %d" % refresh_max_per_round})
|
||||
if refresh_cap_per_round < 1 or refresh_cap_per_round > 8:
|
||||
errs.append({"category": "domain", "message": "refresh_cap_per_round 越域 [1,8]: %d" % refresh_cap_per_round})
|
||||
if move_ap_cost != 0:
|
||||
errs.append({"category": "frozen", "message": "move_ap_cost 结构冻结为 0: %d" % move_ap_cost})
|
||||
if chain_ap_cost != 0:
|
||||
|
||||
@@ -9,7 +9,7 @@ dig_ap_cost = 1
|
||||
flag_place_ap_cost = 1
|
||||
flag_pull_ap_cost = 1
|
||||
rap_refresh_cost = 6
|
||||
refresh_max_per_round = 2
|
||||
refresh_cap_per_round = 2
|
||||
move_ap_cost = 0
|
||||
chain_ap_cost = 0
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
# VERTICAL SLICE - NOT FOR PRODUCTION
|
||||
# 实现 GDD:design/ux/battle.md(五区呈现装配器)——读核心只读面(战斗结算 呈现快照 / runner)→
|
||||
# 实现 GDD:design/ux/battle.md(四区呈现装配器)——读核心只读面(战斗结算 呈现快照 / runner)→
|
||||
# 组装文案/投影 → 驱动各视图 setter。
|
||||
# 高内聚边界:"核心状态 → 呈现文案"的全部翻译集中于此;视图保持零核心依赖;
|
||||
# 静态无状态——呈现不持久化任何核心句柄。
|
||||
@@ -9,7 +9,7 @@
|
||||
# 更新触发注记(battle.md Data Requirements):旗/拔/移动成功反馈零事件外发(排雷玩法 发射面封闭)——
|
||||
# 经 ActionOutcome 返回值命令式驱动;AP/RAP 无推送信号——组合根每次调用返回后重查;
|
||||
# 增益状态 纯被动容器零信号——状态栏刷新绑 战斗结算 结算编排完成时点。
|
||||
# Date: 2026-09-12(五区改造批;基础 = 2026-09-11 HUD 装配器;2026-09-13 快照面改造)
|
||||
# Date: 2026-09-12(战斗屏改造批;基础 = 2026-09-11 HUD 装配器;2026-09-13 快照面改造)
|
||||
class_name HudPresenter
|
||||
extends RefCounted
|
||||
|
||||
@@ -68,7 +68,7 @@ static func _refresh_economy(info: HeroInfoPanelView, ap_bar: ApBarView, s: Dict
|
||||
info.set_rap(int(s.rap), int(db.action_economy.rap_refresh_cost))
|
||||
var digging := String(s.phase) == ActionEconomy.PHASE_ACTIVE
|
||||
ap_bar.set_refresh_state(refresh_remaining,
|
||||
bool(s.can_request_refresh) and digging) # Waiting 代理已随 OQ12 退役——UI 仅挖掘期受理
|
||||
bool(s.can_refresh) and digging) # Waiting 代理已随 OQ12 退役——UI 仅挖掘期受理
|
||||
ap_bar.set_stop_enabled(bool(s.hero.get("alive", false)) and digging)
|
||||
|
||||
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
# VERTICAL SLICE - NOT FOR PRODUCTION
|
||||
# Validation Question: 线性第一关(战×2→道具→战×2→恢复→Boss)能否承载"数值提升→通关期望改善"的元进度验证
|
||||
# 实现 GDD:design/ux/battle.md(战斗屏 A/B/C/D 四区 + 全屏 States + 遥测;E 区随可选类删除下线 2026-09-15)。
|
||||
# Date: 2026-09-12(battle.md 五区改造批;基础 = 2026-09-11 HUD框架-lite 组合根;code-review 修复批重构)
|
||||
# Date: 2026-09-12(battle.md 战斗屏改造批;基础 = 2026-09-11 HUD框架-lite 组合根;code-review 修复批重构)
|
||||
# 2026-09-13(封装审查修复批):核心状态读取收口至 战斗结算/runner 成文只读面(presentation_snapshot /
|
||||
# current_board / current_battle 等——禁链式穿透 settlement.enemy_system.hero 一类路径);调试模式编排抽离
|
||||
# debug_session.gd(规范 1.1 审视线 + 调试语义单一实现)。
|
||||
@@ -76,19 +76,19 @@ func _ready() -> void:
|
||||
_start_overlay.visible = true
|
||||
|
||||
|
||||
# ==================== 视图接线(battle.md 五区布局 1280×800;节点构建归 UiAssembler) ====================
|
||||
# ==================== 视图接线(battle.md 四区布局 1280×800;节点构建归 UiAssembler) ====================
|
||||
|
||||
func _build_ui() -> void:
|
||||
var root := VBoxContainer.new()
|
||||
add_child(root)
|
||||
var five: Dictionary = UiAssembler.build_five_zone(root, db)
|
||||
strip_view = five.strip_view
|
||||
stage = five.stage
|
||||
log_view = five.log_view
|
||||
info_panel = five.info_panel
|
||||
board_zone = five.board_zone
|
||||
board_view = five.board_view # 探针兼容别名(= board_zone.board_view)
|
||||
ap_bar = five.ap_bar # 探针兼容别名(= board_zone.ap_bar)
|
||||
var battle_ui: Dictionary = UiAssembler.build_battle_ui(root, db)
|
||||
strip_view = battle_ui.strip_view
|
||||
stage = battle_ui.stage
|
||||
log_view = battle_ui.log_view
|
||||
info_panel = battle_ui.info_panel
|
||||
board_zone = battle_ui.board_zone
|
||||
board_view = battle_ui.board_view # 探针兼容别名(= board_zone.board_view)
|
||||
ap_bar = battle_ui.ap_bar # 探针兼容别名(= board_zone.ap_bar)
|
||||
log_view.review_requested.connect(_open_review_from_band)
|
||||
board_zone.action_requested.connect(_on_board_action)
|
||||
board_zone.stop_pressed.connect(_on_stop_pressed)
|
||||
@@ -490,7 +490,7 @@ func _on_stop_pressed() -> void:
|
||||
|
||||
|
||||
func _on_refresh_confirmed() -> void:
|
||||
# 弃图刷新(挖掘期 Active 当场换图继续挖——D4;RAP−8 · 旧板旗作废,每轮上限 2 次)
|
||||
# 弃图刷新(挖掘期 Active 当场换图继续挖——D4;RAP 按门槛扣费 · 旧板旗作废,每轮上限读表)
|
||||
if _input_locked():
|
||||
return
|
||||
var ok: bool = false
|
||||
@@ -502,7 +502,7 @@ func _on_refresh_confirmed() -> void:
|
||||
if ok:
|
||||
_refresh_used_round += 1
|
||||
logger.log_ux("ux_refresh_attempt", {"result": "accepted", "round_refresh_index": _refresh_used_round})
|
||||
board_zone.toast.show_toast("RAP−8 · 旧板旗作废——新图已就位,AP 保留继续挖", "gold")
|
||||
board_zone.toast.show_toast("RAP−%d · 旧板旗作废——新图已就位,AP 保留继续挖" % int(db.action_economy.rap_refresh_cost), "gold")
|
||||
else:
|
||||
# 资源面/上限拒绝(EC13 合法拒绝可见;行动经济 无载荷——客户端按上下文推断)
|
||||
var rap: int = int(settlement.action_economy.rap) if settlement != null else 0
|
||||
@@ -533,7 +533,7 @@ func _handle_outcome_feedback(outcome: Dictionary) -> void:
|
||||
|
||||
func _refresh_presentations() -> void:
|
||||
# 每个核心信号/写调用返回后的全量重查装配(更新触发注记——无推送信号,命令式重查)
|
||||
var refresh_remaining: int = maxi(0, int(db.action_economy.refresh_max_per_round) - _refresh_used_round)
|
||||
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_settlement_visuals()
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
# VERTICAL SLICE - NOT FOR PRODUCTION
|
||||
# 实现 GDD:design/ux/battle.md(§Events Fired 遥测义务——ux 行族)。
|
||||
# Date: 2026-09-12(五区改造批增 ux 遥测;基础 = 2026-09-12 日志器首版)
|
||||
# Date: 2026-09-12(战斗屏改造批增 ux 遥测;基础 = 2026-09-12 日志器首版)
|
||||
# 试玩日志器(呈现层组件——订阅核心信号持久化 JSONL,供数值分析;卡死诊断转储)。
|
||||
# 职责边界:核心层只发 settlement_snapshot 信号(战斗结算)/既有信号(battle_finished/node_entered/
|
||||
# level_finished/step_row);本组件负责订阅、缓冲与写文件——核心零日志感知(零 UI 依赖不变)。
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
# VERTICAL SLICE - NOT FOR PRODUCTION
|
||||
# 实现 GDD:design/ux/battle.md(五区装配器——组合根的 UI 构建拆分载体)。
|
||||
# 实现 GDD:design/ux/battle.md(四区装配器——组合根的 UI 构建拆分载体)。
|
||||
# Date: 2026-09-12(code-review 修复批:main.gd 回涨 761 行触规范 1.1 审视线——构建拆出)
|
||||
# 高内聚边界(规范 1.1/1.3):视图构建装配器——只做 new / add_child / 布局,
|
||||
# 零信号连接、零核心写调用;返回句柄供组合根接线(ADR-0001:接线拓扑唯一归组合根)。
|
||||
@@ -9,9 +9,9 @@ extends RefCounted
|
||||
|
||||
# 战斗屏四区(A 进度条 / B 战斗画面 / C·D 两列——E 区道具面板已随可选类删除下线,2026-09-15 格面资源批)。
|
||||
# 返回句柄字典:{strip_view, stage, log_view, info_panel, board_zone, board_view, ap_bar}
|
||||
static func build_five_zone(root: Control, db) -> Dictionary:
|
||||
static func build_battle_ui(root: Control, db) -> Dictionary:
|
||||
# set_anchors_and_offsets_preset(非 set_anchors_preset):后者会把控件重置回最小内容尺寸
|
||||
# (实测 927×613——五区缩顶、棋盘 45px 格 ×10 行超出 D 区 333px 高被裁,2026-09-13 用户报告回归)
|
||||
# (实测 927×613——缩顶、棋盘 45px 格 ×10 行超出 D 区 333px 高被裁,2026-09-13 用户报告回归)
|
||||
root.set_anchors_and_offsets_preset(Control.PRESET_FULL_RECT)
|
||||
root.add_theme_constant_override("separation", 0)
|
||||
|
||||
@@ -41,6 +41,7 @@ static func build_five_zone(root: Control, db) -> Dictionary:
|
||||
|
||||
var board_zone := BoardZoneView.new()
|
||||
bottom.add_child(board_zone)
|
||||
board_zone.ap_bar.set_refresh_cost(int(db.action_economy.rap_refresh_cost)) # RAP 读数表值驱动
|
||||
|
||||
return {
|
||||
"strip_view": strip_view,
|
||||
@@ -89,7 +90,7 @@ static func build_start_overlay(host: Control, db = null) -> Dictionary:
|
||||
var title := UiKit.label("Dungeon Sweeper", 34, true)
|
||||
title.add_theme_color_override("font_color", Color8(240, 226, 200))
|
||||
box.add_child(title)
|
||||
var sub := UiKit.label("战斗屏五区改造批 —— 扫雷的因,逐行兑现的果", 16, false)
|
||||
var sub := UiKit.label("战斗屏战斗屏改造批 —— 扫雷的因,逐行兑现的果", 16, false)
|
||||
sub.add_theme_color_override("font_color", Color8(200, 188, 166))
|
||||
box.add_child(sub)
|
||||
box.add_child(HSeparator.new())
|
||||
@@ -113,7 +114,7 @@ static func build_start_overlay(host: Control, db = null) -> Dictionary:
|
||||
|
||||
# 玩法帮助文案(表值驱动——2026-09-16 AP 压速批遗留硬编码 8 随手修正;护甲等级掷点批同步"减伤"→"护甲强化")
|
||||
var help_text := "玩法:每轮 %d AP——挖开(1AP)/插旗(1AP)/移动(免费)/连锁(免费)。\n每个非封锁格都藏一种格面资源(增伤/护甲强化/回血/爆裂/削弱)。开安全格、标中雷 = 正向兑付;\n开雷格、标错安全格 = 负向兑付——全部在轮末结算逐行兑现;吃掷点的基础攻击按护甲等级判定,无 miss、最低保底 1 点。\n停手:剩余 AP 转存 RAP;弃图刷新:RAP−%d 当场换图继续挖(每轮剩 %d 次)。\n敌人全灭胜、主角倒下负。悬停可看三态光标与可挖域微光。" % [
|
||||
int(db.action_economy.ap_per_round), int(db.action_economy.rap_refresh_cost), int(db.action_economy.refresh_max_per_round)]
|
||||
int(db.action_economy.ap_per_round), int(db.action_economy.rap_refresh_cost), int(db.action_economy.refresh_cap_per_round)]
|
||||
var help := UiKit.label(help_text, 13, false)
|
||||
help.add_theme_color_override("font_color", Color8(178, 166, 146))
|
||||
box.add_child(help)
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
# VERTICAL SLICE - NOT FOR PRODUCTION
|
||||
# 实现 GDD:design/ux/battle.md(D 区 AP 条 44px——点阵+数字〔pattern 5 点阵资源显示〕、
|
||||
# 停手按钮居左、图例+弃图刷新按钮居右〔雷图右上角〕;弃图刷新确认微交互与常规确认不同位
|
||||
# 〔pattern 7 破坏性确认异位:RAP−8 · 旧板旗作废显式代价〕)。
|
||||
# 〔pattern 7 破坏性确认异位:RAP 扣费 · 旧板旗作废显式代价〕)。
|
||||
# Date: 2026-09-12
|
||||
# 高内聚边界:纯视图——意图经信号外发(stop_pressed/refresh_confirmed/legend_toggled),
|
||||
# 状态由组合根经 setter 注入;刷新可用性预判 = RAP≥8 读数(行动经济 无推送信号——每次调用返回后重查)。
|
||||
@@ -23,6 +23,8 @@ var _btn_legend: Button
|
||||
var _btn_refresh: Button
|
||||
var _refresh_sub: Label
|
||||
var _confirm_row: HBoxContainer
|
||||
var _confirm_lab: Label
|
||||
var refresh_cost: int = 0 # 表值驱动(装配经 set_refresh_cost 注入 ActionEconomyTable.rap_refresh_cost)
|
||||
var _confirm_armed := false
|
||||
var _arm_tween: Tween
|
||||
|
||||
@@ -67,9 +69,9 @@ func _init() -> void:
|
||||
_confirm_row.add_theme_constant_override("separation", 4)
|
||||
_confirm_row.visible = false
|
||||
row.add_child(_confirm_row)
|
||||
var confirm_lab := UiKit.label("RAP−8 · 旧板旗作废", 12, true)
|
||||
confirm_lab.add_theme_color_override("font_color", COL_INK)
|
||||
_confirm_row.add_child(confirm_lab)
|
||||
_confirm_lab = UiKit.label("RAP−%d · 旧板旗作废" % refresh_cost, 14, true)
|
||||
_confirm_lab.add_theme_color_override("font_color", COL_INK)
|
||||
_confirm_row.add_child(_confirm_lab)
|
||||
var confirm_btn := UiKit.button("确认弃图")
|
||||
confirm_btn.pressed.connect(_disarm_and_fire)
|
||||
_confirm_row.add_child(confirm_btn)
|
||||
@@ -87,7 +89,7 @@ func _init() -> void:
|
||||
_btn_refresh = UiKit.button("弃图刷新")
|
||||
_btn_refresh.pressed.connect(_on_refresh_pressed)
|
||||
refresh_box.add_child(_btn_refresh)
|
||||
_refresh_sub = UiKit.label("RAP−8 · 剩 0 次", 10, false)
|
||||
_refresh_sub = UiKit.label("RAP−%d · 剩 0 次" % refresh_cost, 14, false)
|
||||
_refresh_sub.horizontal_alignment = HORIZONTAL_ALIGNMENT_CENTER
|
||||
refresh_box.add_child(_refresh_sub)
|
||||
|
||||
@@ -107,8 +109,13 @@ func set_ap(ap: int, ap_max: int) -> void:
|
||||
_ap_label.text = "AP %d/%d" % [ap, ap_max]
|
||||
|
||||
|
||||
func set_refresh_cost(cost: int) -> void:
|
||||
refresh_cost = cost
|
||||
_confirm_lab.text = "RAP−%d · 旧板旗作废" % cost
|
||||
|
||||
|
||||
func set_refresh_state(remaining: int, ready: bool) -> void:
|
||||
_refresh_sub.text = "RAP−8 · 剩 %d 次" % remaining
|
||||
_refresh_sub.text = "RAP−%d · 剩 %d 次" % [refresh_cost, remaining]
|
||||
_btn_refresh.disabled = not ready
|
||||
if not ready:
|
||||
_disarm()
|
||||
|
||||
@@ -42,7 +42,7 @@ func _init(db_ref) -> void:
|
||||
_summary.clip_text = true
|
||||
_summary.text_overrun_behavior = TextServer.OVERRUN_TRIM_ELLIPSIS
|
||||
head.add_child(_summary)
|
||||
_hint = UiKit.label("结算明细 ▸ 点击展开回看", 12, false)
|
||||
_hint = UiKit.label("结算明细 ▸ 点击展开回看", 14, false)
|
||||
_hint.size_flags_horizontal = Control.SIZE_SHRINK_END
|
||||
head.add_child(_hint)
|
||||
_log = RichTextLabel.new()
|
||||
|
||||
@@ -19,6 +19,8 @@ const PENDING_STYLE := {
|
||||
"damage": ["⚔", Color8(198, 61, 34)],
|
||||
"buff": ["✦", Color8(46, 110, 142)],
|
||||
}
|
||||
# 蓄力档技能集(2026-09-18 用户拍板:重击类独立蓄力提示——伤害技 ⚔ / 增益技 ✦ / 重击类 蓄力 三档占位)
|
||||
const CHARGE_SKILL_IDS := ["heavy"]
|
||||
# 护甲类型呈现(攻击类型×护甲克制批——可读性前提:玩家须能看出该用穿刺还是魔法打它)
|
||||
const ARMOR_NAMES := {"light": "轻甲", "ward": "魔法护甲", "heavy": "重甲"}
|
||||
|
||||
@@ -82,7 +84,7 @@ func set_data(d: Dictionary) -> void:
|
||||
_set_order(int(d.get("order", 1)))
|
||||
_armor = String(d.get("armor_type", "light"))
|
||||
_armor_class = int(d.get("armor_class", 0))
|
||||
set_pending(String(d.get("pending_type", "")), String(d.get("pending_name", "")))
|
||||
set_pending(String(d.get("pending_type", "")), String(d.get("pending_skill", "")))
|
||||
# 状态行:伏击池(flat 共享池,单独通道)+ 敌方增益 percent 状态(蓄力/硬化/削弱/暴走——side-wide)
|
||||
var parts: Array = []
|
||||
var ambush: int = int(d.get("ambush_layers", 0))
|
||||
@@ -105,15 +107,17 @@ func _set_order(i: int) -> void:
|
||||
# 摇定动作渲染(敌人技能池批——presenter 不翻译,渲染映射唯一定义处归本类〔code-review 2026-09-12 先例〕):
|
||||
# pending_type = 战斗结算 快照投影(basic/damage/buff;"" = 未摇定/死亡残位)。
|
||||
# 信号/入参契约:set_data 每结算行刷新、set_pending 每轮开轮刷新(开轮摇号时点)。
|
||||
func set_pending(ptype: String, pname: String) -> void:
|
||||
func set_pending(ptype: String, pid: String) -> void:
|
||||
if _dead:
|
||||
return
|
||||
var style: Array = PENDING_STYLE.get(ptype, ["—", Color8(120, 106, 88)])
|
||||
_intent_badge.add_theme_color_override("font_color", style[1])
|
||||
if ptype == "" or ptype == "basic":
|
||||
_intent_badge.text = "意图:—" # 普通攻击零表示(不可预测——§2.4)
|
||||
elif pid in CHARGE_SKILL_IDS:
|
||||
_intent_badge.text = "意图:蓄力" # 重击类蓄力档(2026-09-18 用户三档拍板占位;终稿动画归战斗表现样张批)
|
||||
else:
|
||||
_intent_badge.text = "意图:%s %s" % [String(style[0]), pname] # 特殊技类型级占位(纯提醒,不可撤销)
|
||||
_intent_badge.text = "意图:%s" % String(style[0]) # 特殊技类型级占位——不预告技能名与数值(HUD框架;2026-09-18 剧透堵口)
|
||||
# 护甲行(环点拆除——护甲类型 + AC 恒常驻,克制对策与掷点阈值的可读前提)
|
||||
_armor_line.text = "%s · AC %d" % [_armor_tag(_armor), _armor_class]
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
# VERTICAL SLICE - NOT FOR PRODUCTION
|
||||
# 实现 GDD:design/ux/battle.md(A 区关卡进度条——全宽 × 28px 顶栏,当前节点高亮、已过节点暗金)。
|
||||
# Date: 2026-09-12(battle.md 五区改造批——对齐 28px 顶栏与高亮样式;基础 = 2026-09-11 关卡节点地图-lite 呈现)
|
||||
# Date: 2026-09-12(battle.md 战斗屏改造批——对齐 28px 顶栏与高亮样式;基础 = 2026-09-11 关卡节点地图-lite 呈现)
|
||||
# 2026-09-17 分支节点图批:图形态行集渲染 = 行进序列(已到暗金 → 当前金 → 可选下一跳亮边候选);
|
||||
# 单链形态(第一关零迁移)保持全链横条渲染。
|
||||
# 高内聚边界:只读 runner 的节点链/进度/候选做渲染,无任何写面。
|
||||
|
||||
@@ -47,7 +47,7 @@ static func perfect_action(minesweeper, settlement) -> Dictionary:
|
||||
for c in ded["safe"]:
|
||||
if not minesweeper.is_revealed(c) and not minesweeper.has_flag(c):
|
||||
return _plan_on(minesweeper, c, "dig")
|
||||
if settlement != null and bool(settlement.can_request_refresh()):
|
||||
if settlement != null and bool(settlement.can_refresh()):
|
||||
return {"kind": "refresh"}
|
||||
return {"kind": "stop"}
|
||||
|
||||
|
||||
@@ -0,0 +1,22 @@
|
||||
# VERTICAL SLICE - NOT FOR PRODUCTION
|
||||
# 验证问题:运行期数据致命通道是否成立(2026-09-18 用户拍板——进度坐标越域记 Fatal 级日志后进程退出,退出码 1)
|
||||
# 运行:Godot_console.exe --headless --path . --script res://smoke/config_fatal_probe.gd
|
||||
# 预期:进程以退出码 1 终止;打印 FAIL 行或退出码 0 即致命通道未生效。
|
||||
extends SceneTree
|
||||
|
||||
var _frames := 0
|
||||
|
||||
func _initialize() -> void:
|
||||
var db = load("res://core/config_db.gd").new()
|
||||
root.add_child(db) # 入树——autoload 同款生命周期
|
||||
db.load_tables("res://data/tables", false)
|
||||
db.resolve_enemy_rowset(0, 0) # 越域:关卡序号 <1 → Fatal,quit(1) 排队帧末退出
|
||||
print("FATAL-PROBE — Fatal 已记,等待帧末退出(退出码应为 1)")
|
||||
|
||||
func _process(_delta: float) -> bool:
|
||||
_frames += 1
|
||||
if _frames > 5:
|
||||
print("FATAL-PROBE FAIL — 5 帧内未退出,致命通道未生效")
|
||||
quit(0)
|
||||
return true
|
||||
return false
|
||||
@@ -409,6 +409,10 @@ func _smoke_board_generator() -> void:
|
||||
for L in [1, 2]:
|
||||
var row = _db.resolve_board_gen(L, 0)
|
||||
check(not row.is_empty(), "BoardGen 行解析 (%d,0)" % L)
|
||||
if L == 2:
|
||||
# R1 ceil 口径(2026-09-18 拍板):无精确行向上取整保证偏难——L2 深度 3 为恢复点无行,解析到深度 4
|
||||
var ceil_row: Dictionary = _db.resolve_board_gen(2, 3)
|
||||
check(int(ceil_row.get("node_depth", -1)) == 4, "R1 ceil 解析 (2,3)→(2,4)(向上取整偏难)")
|
||||
var b1 = board_generator.generate(L, 0, _rng.open_stream("board_gen"), _db)
|
||||
check(b1 != null, "L%d 生成产物非空" % L)
|
||||
if b1 == null:
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
# VERTICAL SLICE - NOT FOR PRODUCTION
|
||||
# 实现 GDD:design/ux/battle.md(§AC 场景级测试 + §Interaction Map——UI 行为随机化探针 v3)。
|
||||
# Date: 2026-09-12(五区改造批扩展;基础 = 2026-09-11 问题3 复现器 v2——既有断言全保留)
|
||||
# Date: 2026-09-12(战斗屏改造批扩展;基础 = 2026-09-11 问题3 复现器 v2——既有断言全保留)
|
||||
# 合成鼠标事件走真实呈现层路径(BoardView.click_cell / 按钮信号 → 组合根动作通道),
|
||||
# 随机混合玩家行为——插旗/拔旗、提前停手、弃图刷新确认链、图例模态、明细回看模态、
|
||||
# tooltip 悬停、无效点击——扫描结算停滞(缺陷②回归载体;缺陷④窗口契约随道具窗口删除退役 2026-09-15)
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
# VERTICAL SLICE - NOT FOR PRODUCTION
|
||||
# Date: 2026-09-13(五区布局诊断探针——"内容未满幅/棋盘底裁切"回归定位:打印窗口/视口/五区实际矩形
|
||||
# Date: 2026-09-13(四区布局诊断探针——"内容未满幅/棋盘底裁切"回归定位:打印窗口/视口/四区实际矩形
|
||||
# 与最小尺寸、展开旗标,对照 battle.md §Layout 1280×800 基座规格)
|
||||
# 运行:Godot_console.exe --headless --path . res://smoke/ui_layout_probe.tscn
|
||||
extends Node
|
||||
@@ -33,7 +33,7 @@ func _ready() -> void:
|
||||
print("%-16s pos=%s size=%s min=%s hflag=%d vflag=%d" % [k, ctl.position, ctl.size,
|
||||
ctl.custom_minimum_size, ctl.size_flags_horizontal, ctl.size_flags_vertical])
|
||||
var root_box: Control = main.get_child(0)
|
||||
print("five-zone root: anchors=(%s,%s)-(%s,%s) offsets=(%s,%s,%s,%s) size=%s" % [
|
||||
print("four-zone root: anchors=(%s,%s)-(%s,%s) offsets=(%s,%s,%s,%s) size=%s" % [
|
||||
root_box.anchor_left, root_box.anchor_top, root_box.anchor_right, root_box.anchor_bottom,
|
||||
root_box.offset_left, root_box.offset_top, root_box.offset_right, root_box.offset_bottom, root_box.size])
|
||||
print("board_view cell_size=%s board=%s" % [main.board_view.get("cell_size"), main.board_view.board()])
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
# VERTICAL SLICE - NOT FOR PRODUCTION
|
||||
# 实现 GDD:design/ux/battle.md(场景级 headless 探针——五区布局实例化断言;entry 17②③)。
|
||||
# Date: 2026-09-12(五区改造批扩展;基础 = 2026-09-11 首战棋盘探针——既有断言全保留)
|
||||
# 实现 GDD:design/ux/battle.md(场景级 headless 探针——四区布局实例化断言;entry 17②③)。
|
||||
# Date: 2026-09-12(战斗屏改造批扩展;基础 = 2026-09-11 首战棋盘探针——既有断言全保留)
|
||||
# 项目运行模式(autoload 在位)实例化 main.tscn,直接驱动 _start_full_level(),
|
||||
# 断言四区真实构建(棋盘/进度条/英雄卡/敌人卡/AP 点阵/明细带/数据框;E 区道具面板已删除)。
|
||||
# 运行:Godot_console.exe --headless --path . res://smoke/ui_probe.tscn
|
||||
@@ -29,7 +29,7 @@ func _ready() -> void:
|
||||
problems.append("首战未处于进行中")
|
||||
if not main.log_view.parsed_text().contains("节点 1/"):
|
||||
problems.append("节点头日志缺失")
|
||||
# ---- 五区布局断言(battle.md §Layout)----
|
||||
# ---- 四区布局断言(battle.md §Layout)----
|
||||
if not main.stage.round_label.text.contains("第 1 轮"):
|
||||
problems.append("B 区轮次·阶段指示缺失(%s)" % main.stage.round_label.text)
|
||||
if main.stage.enemy_box.get_child_count() < 1:
|
||||
|
||||
@@ -13,6 +13,11 @@ func _ready() -> void:
|
||||
add_child(main)
|
||||
await get_tree().process_frame
|
||||
var problems: Array = []
|
||||
# 基线读表(2026-09-18 随数值压缩批改表值驱动——旧字面量 6/50、12/75 已随 hero 表压缩失效)
|
||||
var base_atk := int(main.db.hero.atk)
|
||||
var base_hp := int(main.db.hero.max_hp)
|
||||
var boosted_atk := base_atk * 2 # 攻击滑条 100 → ×2
|
||||
var boosted_hp := int(round(base_hp * 1.5)) # 生命滑条 50 → +50%
|
||||
# ① 打开可见性(缺陷⑤回归:打开面板必须隐藏不透明的开始覆盖层)
|
||||
main._show_tune_panel()
|
||||
if not main.tune_panel.visible:
|
||||
@@ -21,7 +26,7 @@ func _ready() -> void:
|
||||
problems.append("开始覆盖层未隐藏——面板被遮挡(缺陷⑤复发)")
|
||||
# ② 滑条 → 生效预览联动
|
||||
main.tune_panel.set_sliders(100, 50)
|
||||
if "12" not in main.tune_panel.effect_text() or "75" not in main.tune_panel.effect_text():
|
||||
if str(boosted_atk) not in main.tune_panel.effect_text() or str(boosted_hp) not in main.tune_panel.effect_text():
|
||||
problems.append("生效预览未联动(%s)" % main.tune_panel.effect_text())
|
||||
# ③ 应用(真实信号路径:apply_requested → 组合根)——E4 后加成零表写,生效断言移至 ⑧ 战斗快照
|
||||
main.tune_panel.press_apply_for_probe()
|
||||
@@ -50,19 +55,19 @@ func _ready() -> void:
|
||||
if main.tune_panel.visible or not main._start_overlay.visible:
|
||||
problems.append("关闭后层级状态错误")
|
||||
# ⑦ hero 表运行期不可变(E4 收口回归断言:任何代码 reintroduce 表写在此被抓获——原"表值残留"断言语义升级)
|
||||
if int(main.db.hero.atk) != 6 or int(main.db.hero.max_hp) != 50:
|
||||
problems.append("hero 表被运行时改写(E4 违例:atk=%s hp=%s,期望恒基线 6/50)" % [str(main.db.hero.atk), str(main.db.hero.max_hp)])
|
||||
if int(main.db.hero.atk) != base_atk or int(main.db.hero.max_hp) != base_hp:
|
||||
problems.append("hero 表被运行时改写(E4 违例:atk=%s hp=%s,期望恒基线 %d/%d)" % [str(main.db.hero.atk), str(main.db.hero.max_hp), base_atk, base_hp])
|
||||
# ⑧ 单次加成生效回归断言:应用加成 + 启动单场战斗 → 呈现快照 hero 必须是"基线 × 单次加成"
|
||||
# (6×2=12 / 50×1.5=75)——旧缺陷(残留值被当基线再乘 → 24/112)在 encounter 参数链上同样被抓获
|
||||
# (攻击 ×2 / 生命 +50%)——旧缺陷(残留值被当基线再乘)在 encounter 参数链上同样被抓获
|
||||
main.tune_panel.set_sliders(100, 50)
|
||||
main.tune_panel.press_apply_for_probe()
|
||||
main._start_full_level() # 完整关卡路径(_start_single 按语义清零滑条 = 恒基线,不承载加成断言)
|
||||
await get_tree().process_frame
|
||||
await get_tree().process_frame
|
||||
var hero: Dictionary = main.settlement.presentation_snapshot().hero
|
||||
if int(hero.get("atk", -1)) != 12 or int(hero.get("max_hp", -1)) != 75:
|
||||
problems.append("战斗加成单次生效违例(atk=%s max_hp=%s,期望 12/75)" % [
|
||||
str(hero.get("atk", "?")), str(hero.get("max_hp", "?"))])
|
||||
if int(hero.get("atk", -1)) != boosted_atk or int(hero.get("max_hp", -1)) != boosted_hp:
|
||||
problems.append("战斗加成单次生效违例(atk=%s max_hp=%s,期望 %d/%d)" % [
|
||||
str(hero.get("atk", "?")), str(hero.get("max_hp", "?")), boosted_atk, boosted_hp])
|
||||
if problems.is_empty():
|
||||
print("[tune_probe] PASS — 打开/联动/应用/重置/模拟/关闭/基线无残留/单次加成 全链路通过(模拟 N=10 输出 %.30s…)" % out)
|
||||
get_tree().quit(0)
|
||||
|
||||
Reference in new issue
Block a user