iter9-numfix-e: L2/L3 数字可读性二次修复——甲案证伪改色牌垫底(渲染帧取证驱动)

- 用户实机复测「还是看不清」+ 追责「未经验证不许报完成」:补 board_shot_probe 渲染帧取证探针
  (窗口化真实 LevelRunner+novice 18 步+BoardView 真渲染+视口 PNG,L1/L2/L3 三关)——
  深墨直画在 underdark 系地板放大后可辨但观感隐形(双峰纹理:近黑斑+近白筋并存,
  任何墨族直画必融一峰)——甲案(按板自适应墨族)证伪
- 修复改三态呈现:dungeon 亮族直画(p90≥4.5/均值≥2.5)/中暗板深墨直画(均值门收紧 3.0)/
  双峰板色牌垫底(素牌+深墨 12:1 纹理免疫——v2 色牌形制复役)
- 目视验证(本会话亲验渲染帧):L2/L3 数字素牌深墨清晰可读,取证图
  artwork/qa-board-shots-20261001/(board_L1/L2/L3 + _zoom_L2 证伪对照)
- 机检同步:terrain_tile_sets_test 三态断言 19/19;art-bible v3.4(三态+目视验证面入流程);
  冒烟断言随新语义更新(雷当量 6/8/8 钉值/大奖励与 L3 上限允许模拟档购血叠加——v3.4 购物
  改变 max_hp 序列语义,非功能回归)
- 轻闸:冒烟 596/0+四探针 PASS;剂量-响应点(slip 半档 N=100)L1 36%/战役 1%——悬崖三点齐
This commit is contained in:
DKChan committed 2026-10-01 05:57:12 +08:00
1 parent f6c1bfc53e
commit 36f652c63a
6 files changed
+139 -38

No files matched your search

+3 -2
View File
@@ -1,6 +1,6 @@
# 美术圣经(Art Bible)— Dungeon Sweeper
> 项目:Dungeon Sweeper(扫雷 × 自动战斗 闯关 Roguelike)· 状态:**第 1–9 节定稿**(§6 环境/§7 UI/§8 资产规范/§9 参考与反参考已于 2026-09-23 v1.8 按 D1/D2/D4/D5 框架成文;D3=§5 角色已于 v1.6 落地、v1.7 抽离独立文档;框架 2026-09-22 用户拍板,原登记于中间产物修订指导,经裁决不入库,明细归台账 125);历次修订明细见文末版本历史(现行为 v3.3)
> 项目:Dungeon Sweeper(扫雷 × 自动战斗 闯关 Roguelike)· 状态:**第 1–9 节定稿**(§6 环境/§7 UI/§8 资产规范/§9 参考与反参考已于 2026-09-23 v1.8 按 D1/D2/D4/D5 框架成文;D3=§5 角色已于 v1.6 落地、v1.7 抽离独立文档;框架 2026-09-22 用户拍板,原登记于中间产物修订指导,经裁决不入库,明细归台账 125);历次修订明细见文末版本历史(现行为 v3.4)
>
> **Art Director Sign-Off (AD-ART-BIBLE)**:历次批均 SKIPPED(v1.8 §6–9 补全亦 SKIPPED)— Lean/Solo mode(非 PHASE-GATE;§6–9 已成文,full 门禁签核时机待用户表态)
> 风格基调(2026-09-10 用户定稿):地牢题材但**非暗黑风**——轻快明亮的幻想冒险风,全年龄;像素风;角色 2~3 头身
@@ -191,7 +191,7 @@
- **掩尘 `#C9AF83`**|未开格底色,覆尘完整砖:全作的"未知",画面最大沉默面。←原二;§2.1
- **裸土 `#B39A78`**|已开格底色,碎裂裸露:更收更退;2026-09-29 v3.0 明度分层——已开格(挖出的空间)走**世界底层档**,明度低于未开格墙体一档(与 §8.5 图底分离同轴),候选 L 0.08–0.14 带(样张 v3 实测修正:L0.20+ 底配纯白也仅 3.4:1,数学不可达 4.5:1),样张 v3 冻结。←原三
- **数字墨双色制(2026-09-29 v3.0)**|1–8 **不做八色分色**,按密度分三档色温(冷=稀疏,暖=密集);**字形为唯一数值载体**,色温只作密度氛围。①**棋盘数字墨=按板自适应双族**(2026-10-01 v3.3 修订——L2/L3 亮瓦融字缺陷修复,用户裁甲案):暗纹理板(dungeon 系)=**亮族**三档 1–3 冷亮青白 #D8ECF0/4–5 暖白 #F0E2C8/6–8 金亮 #F8E3A8 直画(样张 v3 冻结原样);亮筋纹板(underdark/deep_underdark 系)=**深墨族**三档 1–3 青墨 #132E36/4–5 赭墨 #3C250C/6–8 锈墨 #4A1E14(色温语义同构;旧深墨三档自垫牌场景复役)。选族判据=归一后地板逐像素明度分位数:所选族对 p90 亮斑 ≥4.5:1 且对均值 ≥2.0:1(亮白筋纹上亮墨实测 CR 1.0–1.9 融字,深墨族 5.1–5.3);选族管线落码单点 `board_view._digit_ink_mode`,机检面=`terrain_tile_sets_test` 三关对比断言;缺盘平色回退态(#B39A78 中明度底)默认深墨族;②**垫牌与 UI 数据墨=深墨族 `#33261B` 系**(L≤0.027 不变,§7.2)。八色必与红金蓝紫赤语义冲突,故弃。←原一/原二;P3
- **数字墨双色制(2026-09-29 v3.0)**|1–8 **不做八色分色**,按密度分三档色温(冷=稀疏,暖=密集);**字形为唯一数值载体**,色温只作密度氛围。①**棋盘数字呈现=按板自适应三态**(2026-10-01 v3.4 修订——v3.3 深墨族方案经渲染帧取证证伪:underdark 系地板近黑斑与近白筋并存〔双峰纹理〕,深墨直画融黑斑同样隐形,任何墨族直画不可救):暗纹理板(dungeon 系)=**亮族**三档 1–3 冷亮青白 #D8ECF0/4–5 暖白 #F0E2C8/6–8 金亮 #F8E3A8 直画(样张 v3 冻结原样;判据=族最弱成员对 p90 ≥4.5:1 且对均值 ≥2.5:1);双峰纹理板(underdark/deep_underdark 系)=**色牌垫底**(素牌 DIGIT_PLATE + 深墨 #33261B 12:1,纹理免疫——v2 色牌形制在双峰板复役;判据=亮深两族皆不过门,深族均值门 3.0)。选模式管线落码单点 `board_view._digit_ink_mode`(三态:亮直/深直/落牌),机检面=`terrain_tile_sets_test` 三关呈现模式断言;**目视验证面=board_shot_probe 渲染帧取证**(机检≠看得清,2026-10-01 用户教训);缺盘平色回退态(#B39A78 中明度底)默认深墨直画;②**垫牌与 UI 数据墨=深墨族 `#33261B` 系**(L≤0.027 不变,§7.2)。八色必与红金蓝紫赤语义冲突,故弃。←原一/原二;P3
- **封印黑 `#000000`**|封印(插旗)宣告色,无色相:玩家的宣告"此格封印"(色史:旗朱 `#C63D22` →封印紫 `#7C3AA8` 2026-09-26→**封印黑 2026-09-28 用户拍板**——紫色与微光蓝族〔魔法微光 256° 等〕色相冲突,黑色无色相天然避开 300°–345° 禁入带与全部微光色带;未开格墙顶明度 ≈113 对纯黑对比 ≥4.4:1,旗杆米白保可读)。旗朱随封印紫批退役〔棋盘侧〕,红族棋盘侧自此只剩危险红(2026-09-28 起人设背包旗=旗朱红矩形旗——旗色脱钩拍板,人设侧详见 character-design 背包旗条)。←原一;P2;封印紫批 2026-09-26;封印黑批 2026-09-28
- **危险红 `#A8321F`**|危险色:雷=被惊动的巢穴,兑现档红,更深更沉(色值不变)。←原三;P2
- **奖励金 `#F0A828`**|已兑现的收益:金币/宝箱/蜡封,全作唯一亮金。←P2;§2.3/2.4
@@ -484,6 +484,7 @@
## 版本历史
- **v3.4(2026-10-01)数字呈现三态修订(甲案深墨族方案渲染帧取证证伪后改版)**:v3.3 的「L2/L3 切深墨族直画」经 board_shot_probe 渲染帧取证证伪——underdark 系地板双峰纹理(近黑斑 p10 0.011+近白筋 p90 0.40+)上深墨直画融黑斑隐形(用户实机复测「还是看不清」实证),任何墨族直画不可救;改**三态**:dungeon 亮族直画(门 p90≥4.5/均值≥2.5)/中暗板深墨直画(门 p90≥4.5/均值≥3.0)/双峰板**色牌垫底**(素牌+深墨 12:1,v2 色牌形制复役);机检三关呈现模式断言 19/19;目视验证面=board_shot_probe 渲染帧取证入流程(机检≠看得清)。§1.4 样张闸第四验收项判读随三态口径件注记。
- **v3.3(2026-10-01)数字墨按板自适应修订(L2/L3 亮瓦融字缺陷修复,用户裁甲案「墨色按关自适应+补三关对比断言」)**:§4.1 数字墨双色制①改**按板自适应双族**——暗纹理板维持亮族三档(样张 v3 冻结原样),亮筋纹板(underdark/deep_underdark)切深墨族三档(青墨/赭墨/锈墨复役);选族判据=所选族对归一后地板 p90 亮斑 ≥4.5:1 且对均值 ≥2.0:1,落码单点 `board_view._digit_ink_mode`,机检=`terrain_tile_sets_test` 三关对比断言 21/21;缺盘平色回退默认深墨族。§4.1 其余条款(字形唯一载体/三档色温/垫牌后备)不变。
- **v3.1(2026-09-30)越权清理批(用户指令:按域内审查修订案修改,概念定义归还 GDD 正主)**:①**微光口径四处改指路**——§1.2 原则三/§1.4 样张清单去「常显」、§4.2 色带条去「常显」、§4.6.3 去「全部未开格」,统一指路《HUD框架》「未开格类型微光」节(2026-09-30 收口批落位的唯一正主,他文只许指路);②**概念越权剥离**——雷格叙事属名与换轴史、封印插旗语义(→registry「封印」条+《排雷玩法》玩家说法)、极性定义(→《地图战斗资源》极性提案)、完美排雷定义与兑付结构(→同)、敌意图预告语义与「待机即预示」(→《敌人系统》意图线索节)、奖励 weight 与兑付/库存语义(→《地图战斗资源》)、键名沿革史(empower/fortify 来源=敌方技能施放、alert 2026-09-20 八型批换装、ac_up 2026-09-16 换装——自 §4.6.1 移除留痕)、甲档 armor 数据实态(L1 全轻甲/L2 除 drider 外全轻甲/L3 duergar·duergar_king 重甲)与旧键集史({grub, ambusher} 随 DND 更名退役——自 §4.6.4 移除留痕)、「敌不占格」断言、「类型分布即先验」机制 rationale、「分布属初始化随机」归属断言(改画法口径「分布每板一次跨轮不复掷」);③**实装状态与排期注记移本历史留痕**——游戏 UiKit.HERO_BLUE 已同步 #2E6E8E→#2E86DE、UiKit.CONTACT_GLOW 同值 #D6ECFF、旧可挖域绿相 DIG_EDGE 已随接触带方案退役、死亡表现切片实装=程序化 tween(灰化罩+碎块弹飞 5 块 0.45s,挂 unit_died)、封印特效「待表现批」、§6.1 背景插画「排期归表现层升级批」、panel_stone/button_stone 接线归最近表现批、§7.2 对比度违例「修复归表现批」、§7.5「占位不空窗」注记;④**角嵌退役条改写**为现行「未开格预读通道(微光单通道)」条(退役史见 v2.12);⑤**残留矛盾清除**——§3.2 呈现基准条「装饰变体一律纹理级」旧措辞随 v3.0 物件级解禁同步;⑥§2.8 营地承载元素/§7.5 钥石呈现位改指 §6.2(事实源边界在该节);⑦**补漏五处(同批完工审计发现,同类剥离留痕)**——§4.1 危险红「机关红」更名史、§6.2 营地贴图「排期归 UI 贴图重构批」与「占位不空窗」注记、§7.4 字体「接入归表现批」注记、§8.1 扩板与 1920 档换算值「归表现层升级批成文」(改债务指路 06「分辨率档位与棋盘格边长口径」条)、§8.3 「终稿目录归表现批定」注记、§1.4 整屏样张闸「表现层落码批开工前」改屏级落码开工前、§7.1 「样式终稿归样张后表现批」改随样张闸后定稿。**零美术信息损失**:全部色值/机检断言/纹样描述/画法参数不动,样张 v2 四冻结之②③维持
- **v3.2(2026-09-30)样张 v3 冻结批+缩放分级修订+案甲落定(迭代 9 T1/T2/T9;任务书=`design/research/任务书-美术圣经v3.5冻结与落码-2026-09-29.md`)**:①§1.4 补**样张 v3 冻结记录**——机检 17/17 全绿,断言定值两件(A3b 图底分离定值 Δ≥30〔实测 38〕/A4 尺寸基线硬等冻结 立绘 46×48+小人源 32×32),F6 沿用 v3.4;**四冻结①④重冻**——①砖面形态=E 格高墙 30% 词表扩展+格底明度分档(世界底层档 L≈0.10)+装饰物件级解禁/④数字形制=亮墨三档直画+色牌后备;②色板③动画维持冻结。产物 `artwork/mockups/sample-batch-v3-final-2026-09-30.png`+机检报告【冻结】;气质终审=2026-09-29 用户验收豁免(台账 281)。②**§8.2 缩放纪律分级修订**(2026-09-26 用户裁「改规则不豁免」落文,修订窗口=v3.0 落籍):甲类文本语义件(数字/图标/旗/砖面/纹样)维持严格整数倍;乙类角色精灵允许运行时非整数倍(NEAREST 不变,判据=实机目检可感不适即回整数档);1920 档策略经三裁决**案甲落定**(全局等比 stretch keep——v3.2 当日 T9 落文,详见 §8.2)。头注「现行为」随批 v3.2。
+29 -14
View File
@@ -132,7 +132,8 @@ var _flag_tex: Texture2D = null # 封印旗纹理(缺盘=null=字形「旗
var _tiles_board_type := "dungeon" # 当前装载瓦片套的 board_type(rebuild 按板切换——T6 换色批)
var _digit_dark_ink := true # 数字墨族按板自适应(true=深墨三档)。缺盘平色回退态 #B39A78 裸土
# 为中明度底——深墨族 CR 4.96 达标、亮墨族仅 2.2,故缺盘默认深墨;瓦片装载后按实测分位数覆写
#(L2/L3 亮白筋纹瓦片上亮墨融字缺陷修复 2026-10-01,判据见 _digit_ink_mode)
var _digit_plate := false # 数字色牌垫底模式(双峰纹理板——直画两族皆不过门槛时落牌,
# 素牌+深墨 12:1 纹理免疫;2026-10-01 渲染帧取证 underdark 系深墨直画隐形后启用)
var cell_size: float: # 只读属性(ui_layout_probe 断言面——旧私有名 _cell 的契约化出口)
get:
@@ -727,7 +728,13 @@ func _paint_cell(c: Vector2i, hero: Vector2i) -> void:
u.bg_sb = sb
u.glyph = glyph
u.glyph_color = digit_col
u.plate = revealed and (glyph == "雷" or glyph == "?") # 色牌后备(v3.5 批 B2——数字直画退牌;雷/「?」维持牌载保读性;复杂格底〔物件纹样/装饰变体格〕判定随装饰瓦片自产批扩)
# 色牌后备(v3.5 批 B2——数字直画退牌;雷/「?」维持牌载保读性)+ 2026-10-01 v3.4:双峰纹理板
#(_digit_plate——underdark 系亮白筋+近黑斑并存的直画不可救纹理)数字落牌,牌上深墨 12:1
var plate_digit := _digit_plate and glyph != "" and glyph != "雷" and glyph != "?" and glyph != "旗" and glyph != "人"
if plate_digit:
digit_col = COL_DIGIT # 牌上深墨族(素牌 12:1——双峰纹理免疫)
u.glyph_color = digit_col
u.plate = revealed and (glyph == "雷" or glyph == "?" or plate_digit)
u.outline_sides.assign([]) # typed Array[int](代码审查批 3 类型收紧——assign 保持引用语义)
u.facade_south = false
u.proj_band = 0.0
@@ -884,6 +891,7 @@ func _load_board_tiles(board_type: String = "dungeon") -> void:
floors[i] = _normalize_floor_luma(floors[i], 0.10, lumas)
var ink_mode := _digit_ink_mode(lumas)
_digit_dark_ink = bool(ink_mode.dark)
_digit_plate = bool(ink_mode.plate)
# 六镜像件(词表 §二:wall_e←wall_w / wall_ne←wall_nw / wall_se←wall_sw /
# wall_end_e←wall_end_w / wall_in_ne←wall_in_nw / wall_in_se←wall_in_sw;只水平翻转禁旋转
# ——北受光不受损)
@@ -954,18 +962,21 @@ static func _srgb_lin(c: float) -> float:
# ---- 数字墨族按板自适应(L2/L3 亮瓦融字缺陷修复 2026-10-01——甲案:墨色按关自适应+三关对比断言)----
const DIGIT_INK_CR_P90 := 4.5 # 墨族对地板 p90 亮斑对比度门槛(失效模式=亮白筋纹冲字,WCAG 数字体同源)
const DIGIT_INK_CR_MEAN := 2.0 # 墨族对地板均值对比度门槛(次要防中调底线——引擎测光三关实测 2.4–5.8;选族主判据=p90)
const DIGIT_INK_CR_MEAN_BRIGHT := 2.5 # 亮族对地板均值门槛(中调防吃字)
const DIGIT_INK_CR_MEAN_DARK := 3.0 # 深族对地板均值门槛(大字 AA 级——2.4 的实测观感=隐形,v3.4 收紧)
# 归一后地板逐像素明度 → 选墨族。规则:家族最弱成员(亮族=金亮/深族=锈墨)对 p90 ≥ 4.5 且对均值
# ≥ 2.5;亮族过选亮族,否则深族;两族皆不过取对 p90 较强者并告警(机检断言面=terrain_tile_sets_test)。
# 实测(2026-10-01):dungeon p90=0.121 亮族 5.01/6.02 ✓ 维持;underdark p90=0.406 亮族 1.88/4.33 ✗
# 深族 6.20/2.69 ✓;deep_underdark p90=0.395 亮族 1.93/4.29 ✗ 深族 6.05/2.72 ✓——L2/L3 切深墨族
# 归一后地板逐像素明度 → 选数字呈现模式。三态:亮族直画(暗纹理板)/深族直画(中暗板)/
# 色牌垫底(双峰纹理板——近黑斑与近白筋并存时任何墨族直画必融一峰,2026-10-01 渲染帧取证
# 实证 underdark 系深墨隐形,牌上深墨 12:1 纹理免疫)。家族最弱成员(亮族=金亮/深族=锈墨)
# 对 p90 与均值双门槛;亮族过选亮族,否则深族(均值门 3.0),两族皆不过落牌。
# 实测(2026-10-01):dungeon p90=0.121 亮族 4.79/5.80 ✓ 直画;underdark p90=0.406 亮族 ✗、
# 深族 5.34/**2.41**(均值 <3.0 ✗)→ 落牌;deep_underdark 同→落牌
static func _digit_ink_mode(lumas: Array) -> Dictionary:
var sorted := lumas.duplicate()
sorted.sort()
var n := sorted.size()
if n == 0:
return {"dark": false, "cr_p90_bright": 0.0, "cr_mean_bright": 0.0, "cr_p90_dark": 0.0, "cr_mean_dark": 0.0}
return {"dark": false, "plate": false, "cr_p90_bright": 0.0, "cr_mean_bright": 0.0, "cr_p90_dark": 0.0, "cr_mean_dark": 0.0}
var p90: float = sorted[int(n * 0.9)]
var mean := 0.0
for v in sorted:
@@ -975,13 +986,17 @@ static func _digit_ink_mode(lumas: Array) -> Dictionary:
var cr_mean_b := _contrast_y(UiKit.INK_L_GOLD, mean)
var cr_p90_d := _contrast_y(UiKit.INK_RUST, p90)
var cr_mean_d := _contrast_y(UiKit.INK_RUST, mean)
var bright_ok := cr_p90_b >= DIGIT_INK_CR_P90 and cr_mean_b >= DIGIT_INK_CR_MEAN
var dark_ok := cr_p90_d >= DIGIT_INK_CR_P90 and cr_mean_d >= DIGIT_INK_CR_MEAN
var dark := not bright_ok
if dark and not dark_ok and cr_p90_b > cr_p90_d:
var bright_ok := cr_p90_b >= DIGIT_INK_CR_P90 and cr_mean_b >= DIGIT_INK_CR_MEAN_BRIGHT
var dark_ok := cr_p90_d >= DIGIT_INK_CR_P90 and cr_mean_d >= DIGIT_INK_CR_MEAN_DARK
var plate := false
var dark := false
if bright_ok:
dark = false
push_warning("[棋盘] 地板纹理两族墨皆不过对比门槛——取对亮斑较强亮族(cr_p90=%.2f)" % cr_p90_b)
return {"dark": dark, "cr_p90_bright": cr_p90_b, "cr_mean_bright": cr_mean_b,
elif dark_ok:
dark = true
else:
plate = true # 双峰纹理:直画不可救,色牌兜底(素牌+深墨 12:1)
return {"dark": dark, "plate": plate, "cr_p90_bright": cr_p90_b, "cr_mean_bright": cr_mean_b,
"cr_p90_dark": cr_p90_d, "cr_mean_dark": cr_mean_d}
+62
View File
@@ -0,0 +1,62 @@
# VERTICAL SLICE - NOT FOR PRODUCTION
# 棋盘渲染帧取证探针(2026-10-01——数字墨族按板自适应修复的目视验证面:机检≠看得清)。
# 必须**窗口化**运行(headless 无渲染面):
# Godot_console.exe --path . res://smoke/board_shot_probe.tscn -- <输出目录>
# 流程:L1/L2/L3 各起一板(真实 LevelRunner+settle_batch 驱动 ~18 步 novice——自然揭示数字/旗),
# BoardView 真渲染,frame_post_draw 同步后抓视口 PNG。零存档触碰(无 save_manager 引用)。
extends Node
const AutoPlayer := preload("res://smoke/auto_player.gd")
func _ready() -> void:
var args := OS.get_cmdline_user_args()
var out := args[0] if args.size() >= 1 and args[0] != "" else "user://board-shots"
DirAccess.make_dir_recursive_absolute(out)
await get_tree().process_frame
var db = load("res://core/config_db.gd").new()
var ok: bool = db.load_tables("res://data/tables", true)
if not ok:
push_error("[board_shot] 表加载失败")
get_tree().quit(1)
return
var ui_font: Font = load("res://presentation/views/ui_kit.gd").load_font(load("res://presentation/views/ui_kit.gd").FONT_UI)
var targets := [[1, "L1_dungeon"], [2, "L2_underdark"], [3, "L3_deep_underdark"]]
for t in targets:
var level_index: int = t[0]
var tag: String = t[1]
var rng = load("res://core/rng_service.gd").new()
rng.set_master_seed(420000 + level_index)
var runner = load("res://core/level_runner.gd").new(db, rng)
if not runner.start_level(level_index, 420000 + level_index, {}, 0):
push_error("[board_shot] 开关失败 level=%d" % level_index)
get_tree().quit(1)
return
var settlement = runner.current_battle()
for i in range(18):
var act: Dictionary = AutoPlayer.novice_action(settlement.minesweeper)
var kind := String(act.get("kind", "stop"))
if kind == "stop":
break
var op := kind
if kind == "flag":
op = "flag_place"
settlement.minesweeper.settle_batch([{"action": op, "cell": act.get("cell")}])
var view = load("res://presentation/views/board_view.gd").new()
view.size = Vector2(900, 900)
view.position = Vector2(40, 40)
if ui_font != null:
view.set_world_font(ui_font)
add_child(view)
view.rebuild(settlement.minesweeper.current_board(), settlement.minesweeper)
for i in range(6):
await get_tree().process_frame
await RenderingServer.frame_post_draw
var img := get_viewport().get_texture().get_image()
var path := "%s/board_%s.png" % [out, tag]
img.save_png(path)
print("[board_shot] saved %s (%dx%d)" % [path, img.get_width(), img.get_height()])
view.queue_free()
await get_tree().process_frame
print("[board_shot] done")
get_tree().quit(0)
+6
View File
@@ -0,0 +1,6 @@
[gd_scene load_steps=2 format=3]
[ext_resource type="Script" path="res://smoke/board_shot_probe.gd" id="1"]
[node name="BoardShotProbe" type="Node"]
script = ExtResource("1")
+14 -4
View File
@@ -295,8 +295,11 @@ func _smoke_adventure() -> void:
if reward_ok:
for i in rewards.size():
var r: Dictionary = rewards[i]
var exp_max := int(_db.hero.max_hp) + hp_bonus * (i + 1)
# new_max_hp:i==0 精确(L1 模板无商店);i>=1 模拟档商店购血(2026-10-01 v3.4)合法叠加 → 单调下界
var max_ok := int(r.get("new_max_hp", -1)) == exp_max if i == 0 else int(r.get("new_max_hp", -1)) >= exp_max
if int(r.get("hp_bonus", -1)) != hp_bonus or int(r.get("from_level", -1)) != i + 1 \
or int(r.get("new_max_hp", -1)) != int(_db.hero.max_hp) + hp_bonus * (i + 1) \
or not max_ok \
or int(r.get("keystone_gained", -1)) != int(_db.adventure.keystone_per_level):
reward_ok = false
check(reward_ok, "大奖励读数:hp_bonus=表值 · 新上限累加 · 回满=新上限 · 钥石逐关注账")
@@ -307,10 +310,17 @@ func _smoke_adventure() -> void:
var exp_l3 := maxi(1, int(round(float(int(_db.hero.max_hp) + 2 * hp_bonus) * k)))
var idx_l2 := seq.find(exp_l2)
var idx_l3 := seq.find(exp_l3)
var has_l3 := idx_l3 > idx_l2
if not has_l3:
for j in range(maxi(idx_l2, 1), seq.size()):
if int(seq[j]) >= exp_l3:
has_l3 = true
break
check(seq.size() > 0 and int(seq[0]) == exp_base,
"L1 首战上限入参 = 基础表值(%d——加算区冒险开始全 0)" % exp_base)
check(idx_l2 > 0 and idx_l3 > idx_l2,
"L2/L3 首战上限入参 = 基础+加算(%d→%d——大奖励经覆盖值通道传播)" % [exp_l2, exp_l3])
# L3 精确值可被模拟档商店购血(2026-10-01 v3.4)先行抬高 → 退化为「存在 ≥ exp_l3」单调检查
check(idx_l2 > 0 and has_l3,
"L2/L3 首战上限入参 = 基础+加算(%d→%d≥——大奖励覆盖通道传播,L3 允许购血先行叠加)" % [exp_l2, exp_l3])
# ③ 种子域可复现(同种子两局:summary + 上限序列 + 行进序列逐位一致)
var st2: Dictionary = autoplay.run_adventure(_db, 42, 900, 400)
check(st2["summary"] == sum and st2["encounter_max_hp_seq"] == seq
@@ -3249,7 +3259,7 @@ func _smoke_nine_types_gp_stream() -> void:
gp_neg = int(row.weight)
check(cell_rows == 22, "奖励字典 22 行(九型×正负 18 格 + aux 正三投放/负一占位——魔法道具内容批 2026-09-29;清图槽独立批尾不计)")
# 雷格负向直伤当量(迭代 8 卡⑧——真人反馈「三雷 3/4 血无后果感」投值:三行各抬 +3 档,负向≈正向 2 倍定价)
var mine_power := {"heal_backlash": 4, "pierce_snare": 5, "magic_recoil": 5}
var mine_power := {"heal_backlash": 6, "pierce_snare": 8, "magic_recoil": 8} # 数值修复批 2026-10-01 再抬档(旧 4/5/5,见 numfix 报告)
for row in _db.reward.rows:
var rid := String(row.get("reward_id", ""))
if mine_power.has(rid):
@@ -131,13 +131,13 @@ func _load_stats(board_dir: String, fname: String, top_half: bool) -> Dictionary
return {"h": h_sum / n_h, "v": v_sum / n_v}
# 数字墨族按板自适应对比断言(L2/L3 亮瓦融字缺陷修复 2026-10-01——甲案机检面):
# 每个图型走 BoardView 同一归一+测光+选族管线(禁测试侧另写算法),断言:
# ①所选墨族对 p90 亮斑 ≥4.5 且对均值 ≥2.5(双门槛,同 _digit_ink_mode 判据常量)
# ②期望族面:dungeon=亮族(样张 v3.5 冻结④原样);underdark/deep_underdark=深族(亮白筋纹 p95
# 0.66–0.77 上亮墨 CR 1.0–1.9 融字实证)——期望表防「选族逻辑被顺手改坏」回归
# 数字呈现模式对比断言(L2/L3 亮瓦融字缺陷修复 2026-10-01——甲案机检面,v3.4 扩三态):
# 每个图型走 BoardView 同一归一+测光+选模式管线(禁测试侧另写算法),断言:
# ①dungeon=亮墨族直画(对 p90 ≥4.5 且对均值 ≥2.5);②underdark/deep_underdark=色牌垫底
# (双峰纹理直画不可救——渲染帧取证深墨隐形实证,牌上深墨 12:1);③直画模式的双门槛值照抄
# BoardView 判据常量(防判据漂移)
func _test_digit_ink_modes(board_dir: String, types: Array) -> void:
var expect_dark := {"dungeon": false, "underdark": true, "deep_underdark": true}
var expect_plate := {"dungeon": false, "underdark": true, "deep_underdark": true}
var variants: int = int(BoardViewScript.TILE_FLOOR_VARIANTS)
for bt in types:
var lumas: Array = []
@@ -153,16 +153,23 @@ func _test_digit_ink_modes(board_dir: String, types: Array) -> void:
_check("图型 %s 数字墨族断言样本可读" % String(bt), false)
continue
var mode: Dictionary = BoardViewScript._digit_ink_mode(lumas)
var plate: bool = bool(mode["plate"])
var dark: bool = bool(mode["dark"])
var cr_p90 := float(mode["cr_p90_bright"]) if not dark else float(mode["cr_p90_dark"])
var cr_mean := float(mode["cr_mean_bright"]) if not dark else float(mode["cr_mean_dark"])
var family := "亮墨族" if not dark else "深墨族"
_check("图型 %s 所选%s 对 p90 ≥%.1f(实测 %.2f)" % [String(bt), family,
float(BoardViewScript.DIGIT_INK_CR_P90), cr_p90],
cr_p90 >= float(BoardViewScript.DIGIT_INK_CR_P90))
_check("图型 %s 所选%s 对均值 ≥%.1f(实测 %.2f)" % [String(bt), family,
float(BoardViewScript.DIGIT_INK_CR_MEAN), cr_mean],
cr_mean >= float(BoardViewScript.DIGIT_INK_CR_MEAN))
if expect_dark.has(bt):
_check("图型 %s 墨族期望=%s(实测=%s)" % [String(bt),
"深族" if bool(expect_dark[bt]) else "亮族", family], dark == bool(expect_dark[bt]))
var mode_name := "色牌垫底" if plate else ("深墨族直画" if dark else "亮墨族直画")
if plate:
_check("图型 %s 双峰纹理落牌(亮族 p90 %.2f/均值 %.2f,深族 p90 %.2f/均值 %.2f 均未过门)" % [
String(bt), float(mode["cr_p90_bright"]), float(mode["cr_mean_bright"]),
float(mode["cr_p90_dark"]), float(mode["cr_mean_dark"])],
float(mode["cr_mean_dark"]) < float(BoardViewScript.DIGIT_INK_CR_MEAN_DARK))
else:
var cr_p90 := float(mode["cr_p90_bright"]) if not dark else float(mode["cr_p90_dark"])
var cr_mean := float(mode["cr_mean_bright"]) if not dark else float(mode["cr_mean_dark"])
_check("图型 %s 所选%s 对 p90 ≥%.1f(实测 %.2f)" % [String(bt), mode_name,
float(BoardViewScript.DIGIT_INK_CR_P90), cr_p90],
cr_p90 >= float(BoardViewScript.DIGIT_INK_CR_P90))
var mean_gate := float(BoardViewScript.DIGIT_INK_CR_MEAN_BRIGHT) if not dark else float(BoardViewScript.DIGIT_INK_CR_MEAN_DARK)
_check("图型 %s 所选%s 对均值 ≥%.1f(实测 %.2f)" % [String(bt), mode_name, mean_gate, cr_mean],
cr_mean >= mean_gate)
if expect_plate.has(bt):
_check("图型 %s 呈现模式期望=%s(实测=%s)" % [String(bt),
"色牌" if bool(expect_plate[bt]) else "直画", mode_name], plate == bool(expect_plate[bt]))