修复(迭代 41 测试债批): 9 套件归绿+静态扫描 S9/S10/S11 清零+删死常量 SCHEMA_VERSION——两个产品回归随批修(standee 补间目标改子对象 st/tune_sim 运行态收尾归还 run),测试面按 iter41 拆件改址(slots/meta_state/crossrun/_forge/_side);S9 类型闸 24 处(node_map 三处给 Array[int] 真类型,其余动态边界 type-hint: ignore 逐处注记)+S10 头注日期 4 处+S11 退役词 1 处;config_db 头注「--script 无 autoload」订正为实测事实(autoload 并存、共享 .tres resolver 归最后装载者)
This commit is contained in:
1 parent
6dea23729b
commit
215da31591
23 files changed
+87
-63
No files matched your search
@@ -1,14 +1,13 @@
|
|||||||
## VERTICAL SLICE - NOT FOR PRODUCTION
|
## VERTICAL SLICE - NOT FOR PRODUCTION
|
||||||
## 数值表单点访问入口:全部 .tres 表的加载、校验诊断与门面(垂直切片验证:改表即改玩法,数值零硬编码)。
|
## 数值表单点访问入口:全部 .tres 表的加载、校验诊断与门面(垂直切片验证:改表即改玩法,数值零硬编码)。
|
||||||
## 玩法代码禁止绕过本单点自建 load();行查询归各表类(表管自己的行——2026-10-27 全清设计定稿),
|
## 玩法代码禁止绕过本单点自建 load();行查询归各表类(表管自己的行),
|
||||||
## 表持有按域收进三容器(combat 战斗编排域/run 冒险 runner 域/crossrun 跨局元进度域),
|
## 表持有按域收进三容器(combat 战斗编排域/run 冒险 runner 域/crossrun 跨局元进度域),
|
||||||
## 消费面经 db.<容器>.<表> 直连。「经 ConfigDB 单点读取」=经其持有的容器与表对象(架构 :88)。
|
## 消费面经 db.<容器>.<表> 直连。「经 ConfigDB 单点读取」=经其持有的容器与表对象(架构 :88)。
|
||||||
## headless --script 模式无 autoload——冒烟脚本显式实例化本类;加载失败 is_ready=false 加 fatal 封印,调用方须查。
|
## 冒烟脚本可显式实例化本类(headless --script 亦会加载 autoload——共享 .tres 上的 resolver 归最后装载的实例);
|
||||||
|
## 加载失败 is_ready=false 加 fatal 封印,调用方须查。
|
||||||
class_name ConfigDb
|
class_name ConfigDb
|
||||||
extends Node
|
extends Node
|
||||||
|
|
||||||
const SCHEMA_VERSION := 1
|
|
||||||
|
|
||||||
const TABLE_MANIFEST := {
|
const TABLE_MANIFEST := {
|
||||||
"action_economy": "action_economy.tres",
|
"action_economy": "action_economy.tres",
|
||||||
"variation": "variation.tres",
|
"variation": "variation.tres",
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
## 战斗域容器(D2 域容器——config_db 表持有按域收敛,2026-10-27 全清设计定稿):战斗编排域七表类型化持有。
|
## 战斗域容器(D2 域容器——config_db 表持有按域收敛):战斗编排域七表类型化持有。
|
||||||
## 零方法零行为——纯持有结构;「经 ConfigDB 单点读取」=经其持有的容器与表对象(架构 :88 定稿注记)。
|
## 零方法零行为——纯持有结构;「经 ConfigDB 单点读取」=经其持有的容器与表对象(架构 :88 定稿注记)。
|
||||||
class_name ConfigDomainCombat
|
class_name ConfigDomainCombat
|
||||||
extends Resource
|
extends Resource
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
## 跨局域容器(D2 域容器——config_db 表持有按域收敛,2026-10-27 全清设计定稿):跨局元进度域五表类型化持有
|
## 跨局域容器(D2 域容器——config_db 表持有按域收敛):跨局元进度域五表类型化持有
|
||||||
## (跨局循环=单局之外的长线进度域)。零方法零行为——纯持有结构;
|
## (跨局循环=单局之外的长线进度域)。零方法零行为——纯持有结构;
|
||||||
## 「经 ConfigDB 单点读取」=经其持有的容器与表对象(架构 :88 定稿注记)。
|
## 「经 ConfigDB 单点读取」=经其持有的容器与表对象(架构 :88 定稿注记)。
|
||||||
class_name ConfigDomainCrossrun
|
class_name ConfigDomainCrossrun
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
## 冒险域容器(D2 域容器——config_db 表持有按域收敛,2026-10-27 全清设计定稿):冒险 runner 域七表类型化持有。
|
## 冒险域容器(D2 域容器——config_db 表持有按域收敛):冒险 runner 域七表类型化持有。
|
||||||
## 零方法零行为——纯持有结构;「经 ConfigDB 单点读取」=经其持有的容器与表对象(架构 :88 定稿注记)。
|
## 零方法零行为——纯持有结构;「经 ConfigDB 单点读取」=经其持有的容器与表对象(架构 :88 定稿注记)。
|
||||||
class_name ConfigDomainRun
|
class_name ConfigDomainRun
|
||||||
extends Resource
|
extends Resource
|
||||||
|
|||||||
@@ -187,8 +187,8 @@ func _vo_edges(nodes: Array, by_id: Dictionary, indeg: Dictionary, errs: Array)
|
|||||||
|
|
||||||
## 阶段三·流事实域:入口集(入度 0)/终点集(无出边)与 Boss 终点判据、去路数形态
|
## 阶段三·流事实域:入口集(入度 0)/终点集(无出边)与 Boss 终点判据、去路数形态
|
||||||
func _vo_flow_facts(nodes: Array, indeg: Dictionary, errs: Array) -> Dictionary:
|
func _vo_flow_facts(nodes: Array, indeg: Dictionary, errs: Array) -> Dictionary:
|
||||||
var entries := []
|
var entries: Array[int] = []
|
||||||
var terminals := []
|
var terminals: Array[int] = []
|
||||||
for n in nodes:
|
for n in nodes:
|
||||||
var id0: int = int(n["id"])
|
var id0: int = int(n["id"])
|
||||||
var outs = n["next"]
|
var outs = n["next"]
|
||||||
@@ -277,8 +277,8 @@ func _vo_width_rules(nodes: Array, errs: Array) -> void:
|
|||||||
|
|
||||||
## 计数规则③·参数档对照:战斗保底/入口数/终点数/层高(params 为空时跳过)
|
## 计数规则③·参数档对照:战斗保底/入口数/终点数/层高(params 为空时跳过)
|
||||||
func _vo_params_check(params: Dictionary, nodes: Array, by_id: Dictionary, flow_ends: Array, errs: Array) -> void:
|
func _vo_params_check(params: Dictionary, nodes: Array, by_id: Dictionary, flow_ends: Array, errs: Array) -> void:
|
||||||
var entries: Array = flow_ends[0]
|
var entries: Array[int] = flow_ends[0]
|
||||||
var terminals: Array = flow_ends[1]
|
var terminals: Array[int] = flow_ends[1]
|
||||||
var battles := 0
|
var battles := 0
|
||||||
for n in nodes:
|
for n in nodes:
|
||||||
if String(n["type"]) == "battle":
|
if String(n["type"]) == "battle":
|
||||||
@@ -309,7 +309,7 @@ func _build(rg: RandomNumberGenerator) -> Dictionary:
|
|||||||
var entries: Array[int] = []
|
var entries: Array[int] = []
|
||||||
for i in range(en):
|
for i in range(en):
|
||||||
entries.append(_mk("battle", 0))
|
entries.append(_mk("battle", 0))
|
||||||
var prevs: Array = _build_trunk(t, entries.duplicate())
|
var prevs: Array[int] = _build_trunk(t, entries.duplicate())
|
||||||
|
|
||||||
var terminals: Array[int] = []
|
var terminals: Array[int] = []
|
||||||
for r in range(e):
|
for r in range(e):
|
||||||
@@ -326,7 +326,7 @@ func _build(rg: RandomNumberGenerator) -> Dictionary:
|
|||||||
|
|
||||||
|
|
||||||
## 主链段(深度 1..t 逐层单链,主链段零 RNG):返回链末节点集(e>1 时收束为一处即归属大岔口)
|
## 主链段(深度 1..t 逐层单链,主链段零 RNG):返回链末节点集(e>1 时收束为一处即归属大岔口)
|
||||||
func _build_trunk(t: int, prevs: Array) -> Array:
|
func _build_trunk(t: int, prevs: Array[int]) -> Array[int]:
|
||||||
for d in range(1, t + 1):
|
for d in range(1, t + 1):
|
||||||
var nid := _mk("battle", d)
|
var nid := _mk("battle", d)
|
||||||
for p in prevs:
|
for p in prevs:
|
||||||
|
|||||||
@@ -52,7 +52,7 @@ const TIER_QUOTAS := {"common": 70, "excellent": 25, "rare": 7, "legendary": 0}
|
|||||||
@export var cap_segment: AdventureCapSegment = AdventureCapSegment.new() # 已拿上限段(curio_cap_* 9)
|
@export var cap_segment: AdventureCapSegment = AdventureCapSegment.new() # 已拿上限段(curio_cap_* 9)
|
||||||
|
|
||||||
# —— 专长获取专长凭证(非 Boss 渠道的专长入口形态,奇物.md v2.7 渠道轴定位;
|
# —— 专长获取专长凭证(非 Boss 渠道的专长入口形态,奇物.md v2.7 渠道轴定位;
|
||||||
# 四口径契约④:拿到即开不可囤积/罕见只在概率不在价格/一局限购一次/计步保底连续 5 展示未出
|
# 四口径契约④:拿到即开不可囤积/稀有只在概率不在价格/一局限购一次/计步保底连续 5 展示未出
|
||||||
# 第 6 必出(计数=展示次数、刷新重展计入、节点与商店共享、触发清零、限购满不再触发)。
|
# 第 6 必出(计数=展示次数、刷新重展计入、节点与商店共享、触发清零、限购满不再触发)。
|
||||||
# 四参数全部 provisional 归曲线调参;limit/pity_step 系口径定死值,调参可复议)——
|
# 四参数全部 provisional 归曲线调参;limit/pity_step 系口径定死值,调参可复议)——
|
||||||
@export var feat_ticket_chance: int = 20 # [0,100] knob(provisional)——每次非 Boss 渠道展示专长凭证出现概率 %
|
@export var feat_ticket_chance: int = 20 # [0,100] knob(provisional)——每次非 Boss 渠道展示专长凭证出现概率 %
|
||||||
|
|||||||
@@ -7,9 +7,9 @@ extends RefCounted
|
|||||||
## 三束按域收拢(u21——同 u20 形;views=视图句柄/getters=查询 Callable 活引用/flow=编排 Callable):
|
## 三束按域收拢(u21——同 u20 形;views=视图句柄/getters=查询 Callable 活引用/flow=编排 Callable):
|
||||||
## 原 12 参长签名收 4 参——字段即原构造参数逐一同名迁移,键面=消费方改址合同。
|
## 原 12 参长签名收 4 参——字段即原构造参数逐一同名迁移,键面=消费方改址合同。
|
||||||
var db
|
var db
|
||||||
var views: Dictionary = {} # {camp_overlay, shop_overlay, toast, start_overlay, logger}
|
var views: Dictionary = {} # {camp_overlay, shop_overlay, toast, start_overlay, logger} # type-hint: ignore(三束异构混载——视图句柄/查询 Callable/编排 Callable)
|
||||||
var getters: Dictionary = {} # {meta_get, save_get, runner_get}
|
var getters: Dictionary = {} # {meta_get, save_get, runner_get} # type-hint: ignore(同上——Callable 束)
|
||||||
var flow: Dictionary = {} # {open_modal, close_modal, refresh_presentations}
|
var flow: Dictionary = {} # {open_modal, close_modal, refresh_presentations} # type-hint: ignore(同上——Callable 束)
|
||||||
|
|
||||||
|
|
||||||
func _init(db_ref, views_bundle: Dictionary, getters_bundle: Dictionary, flow_bundle: Dictionary) -> void:
|
func _init(db_ref, views_bundle: Dictionary, getters_bundle: Dictionary, flow_bundle: Dictionary) -> void:
|
||||||
|
|||||||
@@ -7,9 +7,9 @@ extends RefCounted
|
|||||||
## 三束按域收拢(u20——views=视图句柄/getters=查询 Callable 活引用〔禁快照〕/flow=编排 Callable):
|
## 三束按域收拢(u20——views=视图句柄/getters=查询 Callable 活引用〔禁快照〕/flow=编排 Callable):
|
||||||
## 原 16 参长签名收 4 参——字段即原构造参数逐一同名迁移,键面=消费方改址合同。
|
## 原 16 参长签名收 4 参——字段即原构造参数逐一同名迁移,键面=消费方改址合同。
|
||||||
var db
|
var db
|
||||||
var views: Dictionary = {} # {curio_overlay, end_overlay, board_view, toast}
|
var views: Dictionary = {} # {curio_overlay, end_overlay, board_view, toast} # type-hint: ignore(三束异构混载——视图句柄/查询 Callable/编排 Callable)
|
||||||
var getters: Dictionary = {} # {meta_get, save_get, adventure_get, runner_get, adventure_mode_get}
|
var getters: Dictionary = {} # {meta_get, save_get, adventure_get, runner_get, adventure_mode_get} # type-hint: ignore(同上——Callable 束)
|
||||||
var flow: Dictionary = {} # {open_modal, open_modal_after_playback, close_modal, refresh_presentations, fatal_screen, gp_summary}
|
var flow: Dictionary = {} # {open_modal, open_modal_after_playback, close_modal, refresh_presentations, fatal_screen, gp_summary} # type-hint: ignore(同上——Callable 束)
|
||||||
|
|
||||||
|
|
||||||
func _init(db_ref, views_bundle: Dictionary, getters_bundle: Dictionary, flow_bundle: Dictionary) -> void:
|
func _init(db_ref, views_bundle: Dictionary, getters_bundle: Dictionary, flow_bundle: Dictionary) -> void:
|
||||||
|
|||||||
@@ -196,11 +196,11 @@ static func outcome_text(outcome: Dictionary) -> String:
|
|||||||
## 统计束收拢(u19——stats 六键 {wins, dmg_all, hp_left_win, hp_boss, rounds_all, death_nodes})
|
## 统计束收拢(u19——stats 六键 {wins, dmg_all, hp_left_win, hp_boss, rounds_all, death_nodes})
|
||||||
static func tune_sim_report(n: int, atk_pct: int, hp_pct: int, stats: Dictionary, base_hp: int) -> String:
|
static func tune_sim_report(n: int, atk_pct: int, hp_pct: int, stats: Dictionary, base_hp: int) -> String:
|
||||||
var wins: int = stats.get("wins", 0)
|
var wins: int = stats.get("wins", 0)
|
||||||
var dmg_all: Array = stats.get("dmg_all", [])
|
var dmg_all: Array = stats.get("dmg_all", []) # type-hint: ignore(stats 束 Variant 出值——元素类型归模拟域写入面,未参数化)
|
||||||
var hp_left_win: Array = stats.get("hp_left_win", [])
|
var hp_left_win: Array = stats.get("hp_left_win", []) # type-hint: ignore(同上)
|
||||||
var hp_boss: Array = stats.get("hp_boss", [])
|
var hp_boss: Array = stats.get("hp_boss", []) # type-hint: ignore(同上)
|
||||||
var rounds_all: Array = stats.get("rounds_all", [])
|
var rounds_all: Array = stats.get("rounds_all", []) # type-hint: ignore(同上)
|
||||||
var death_nodes: Dictionary = stats.get("death_nodes", {})
|
var death_nodes: Dictionary = stats.get("death_nodes", {}) # type-hint: ignore(同上——键为败北节点标签)
|
||||||
var lines: Array[String] = []
|
var lines: Array[String] = []
|
||||||
lines.append("[b]模拟 N=%d(atk+%d%% / hp+%d%%)[/b]" % [n, atk_pct, hp_pct])
|
lines.append("[b]模拟 N=%d(atk+%d%% / hp+%d%%)[/b]" % [n, atk_pct, hp_pct])
|
||||||
lines.append("关卡完成率 [color=#%s]%.0f%%[/color](%d/%d)" % [UiKit.HEX_LOG_WIN, 100.0 * float(wins) / float(maxi(1, n)), wins, n])
|
lines.append("关卡完成率 [color=#%s]%.0f%%[/color](%d/%d)" % [UiKit.HEX_LOG_WIN, 100.0 * float(wins) / float(maxi(1, n)), wins, n])
|
||||||
|
|||||||
@@ -50,10 +50,12 @@ func run(n: int) -> void:
|
|||||||
await panel.get_tree().process_frame
|
await panel.get_tree().process_frame
|
||||||
logger.close_session()
|
logger.close_session()
|
||||||
panel.set_sim_report(HudPresenter.tune_sim_report(n, panel.atk_pct(), panel.hp_pct(), stats, _base_hp))
|
panel.set_sim_report(HudPresenter.tune_sim_report(n, panel.atk_pct(), panel.hp_pct(), stats, _base_hp))
|
||||||
|
panel.set_sim_running(false)
|
||||||
|
_running = false
|
||||||
|
|
||||||
|
|
||||||
## 单局模拟域(循环体提函数——结果四桶记账;u19 stats 六键同构承载)
|
## 单局模拟域(循环体提函数——结果四桶记账;u19 stats 六键同构承载)
|
||||||
func _run_one_level(autoplay, stats: Dictionary, i: int, panel, logger) -> void:
|
func _run_one_level(autoplay, stats: Dictionary, i: int, panel, logger) -> void: # type-hint: ignore(驱动/面板/日志件鸭子型注入——同 run 构造缝)
|
||||||
var st = autoplay.run_level(db, SEED_BASE + i, 1, panel.atk_pct(), panel.hp_pct(), false, logger)
|
var st = autoplay.run_level(db, SEED_BASE + i, 1, panel.atk_pct(), panel.hp_pct(), false, logger)
|
||||||
(stats["dmg_all"] as Array).append(st.hero_dmg)
|
(stats["dmg_all"] as Array).append(st.hero_dmg)
|
||||||
(stats["rounds_all"] as Array).append(st.rounds)
|
(stats["rounds_all"] as Array).append(st.rounds)
|
||||||
@@ -64,5 +66,3 @@ func _run_one_level(autoplay, stats: Dictionary, i: int, panel, logger) -> void:
|
|||||||
elif st.result == "defeat":
|
elif st.result == "defeat":
|
||||||
var key := "%d.%s" % [st.defeat_node_index, st.defeat_node_type]
|
var key := "%d.%s" % [st.defeat_node_index, st.defeat_node_type]
|
||||||
stats["death_nodes"][key] = int(stats["death_nodes"].get(key, 0)) + 1
|
stats["death_nodes"][key] = int(stats["death_nodes"].get(key, 0)) + 1
|
||||||
panel.set_sim_running(false)
|
|
||||||
_running = false
|
|
||||||
@@ -75,7 +75,7 @@ func _build_world_stage() -> void:
|
|||||||
|
|
||||||
|
|
||||||
## Control 文本半区域(round_label / stage_center / log_view 原样保留——C1 永久 Control)
|
## Control 文本半区域(round_label / stage_center / log_view 原样保留——C1 永久 Control)
|
||||||
func _build_text_half(db_ref) -> void:
|
func _build_text_half(db_ref) -> void: # type-hint: ignore(db 鸭子型注入——单测以最小 stub 构造)
|
||||||
var vb := VBoxContainer.new()
|
var vb := VBoxContainer.new()
|
||||||
vb.add_theme_constant_override("separation", 4)
|
vb.add_theme_constant_override("separation", 4)
|
||||||
vb.set_anchors_preset(Control.PRESET_FULL_RECT)
|
vb.set_anchors_preset(Control.PRESET_FULL_RECT)
|
||||||
@@ -124,7 +124,7 @@ func _build_center_row(vb: VBoxContainer) -> void:
|
|||||||
|
|
||||||
|
|
||||||
## 壳层伴随件层域(最顶——世界站桩之上的 Control 触达面)+主角站桩注册(世界)+ 状态行伴随件(壳层)
|
## 壳层伴随件层域(最顶——世界站桩之上的 Control 触达面)+主角站桩注册(世界)+ 状态行伴随件(壳层)
|
||||||
func _build_companion_layer(db_ref) -> void:
|
func _build_companion_layer(db_ref) -> void: # type-hint: ignore(db 鸭子型注入——单测以最小 stub 构造)
|
||||||
_companion_layer = Control.new()
|
_companion_layer = Control.new()
|
||||||
_companion_layer.set_anchors_preset(Control.PRESET_FULL_RECT)
|
_companion_layer.set_anchors_preset(Control.PRESET_FULL_RECT)
|
||||||
_companion_layer.mouse_filter = Control.MOUSE_FILTER_IGNORE
|
_companion_layer.mouse_filter = Control.MOUSE_FILTER_IGNORE
|
||||||
|
|||||||
@@ -478,9 +478,9 @@ func _room_color(node: Dictionary, ctx: Dictionary) -> Color:
|
|||||||
## 选路停点(候选非空)非候选通道降透明——金岔路从结构网分离(干线共线重叠缺陷的
|
## 选路停点(候选非空)非候选通道降透明——金岔路从结构网分离(干线共线重叠缺陷的
|
||||||
## 视觉主因:不同源通道共用同一垂直干线,金边与石色边焊接成「整列可走」假象)
|
## 视觉主因:不同源通道共用同一垂直干线,金边与石色边焊接成「整列可走」假象)
|
||||||
func _draw_passage_layer(canvas: Control, ctx: Dictionary) -> void:
|
func _draw_passage_layer(canvas: Control, ctx: Dictionary) -> void:
|
||||||
var nodes: Array = ctx["nodes"]
|
var nodes: Array = ctx["nodes"] # type-hint: ignore(ctx 束 Variant 出值——布局缓存数组未参数化)
|
||||||
var pos: Dictionary = ctx["pos"]
|
var pos: Dictionary = ctx["pos"] # type-hint: ignore(同上——节点 id → 坐标)
|
||||||
var cand_ids: Array = ctx["cand_ids"]
|
var cand_ids: Array = ctx["cand_ids"] # type-hint: ignore(同上——候选 id 集)
|
||||||
var dim_passages: bool = not cand_ids.is_empty()
|
var dim_passages: bool = not cand_ids.is_empty()
|
||||||
for node in nodes:
|
for node in nodes:
|
||||||
var from: Vector2 = pos[node]
|
var from: Vector2 = pos[node]
|
||||||
@@ -496,7 +496,7 @@ func _draw_passage_layer(canvas: Control, ctx: Dictionary) -> void:
|
|||||||
|
|
||||||
## 房间方块域:底色随行进态+Boss/候选描边+图标/字形+编号+类型文字标签
|
## 房间方块域:底色随行进态+Boss/候选描边+图标/字形+编号+类型文字标签
|
||||||
func _draw_room(canvas: Control, node: Dictionary, ctx: Dictionary) -> void:
|
func _draw_room(canvas: Control, node: Dictionary, ctx: Dictionary) -> void:
|
||||||
var pos: Dictionary = ctx["pos"]
|
var pos: Dictionary = ctx["pos"] # type-hint: ignore(ctx 束 Variant 出值——节点 id → 坐标)
|
||||||
var p: Vector2 = pos[node]
|
var p: Vector2 = pos[node]
|
||||||
var t := String(node.get("type", ""))
|
var t := String(node.get("type", ""))
|
||||||
var nid := _id_of(node)
|
var nid := _id_of(node)
|
||||||
|
|||||||
@@ -134,7 +134,7 @@ func _set_hp(hp: int) -> void:
|
|||||||
if st._hp_tween != null and st._hp_tween.is_valid():
|
if st._hp_tween != null and st._hp_tween.is_valid():
|
||||||
st._hp_tween.kill()
|
st._hp_tween.kill()
|
||||||
st._hp_tween = create_tween()
|
st._hp_tween = create_tween()
|
||||||
st._hp_tween.tween_property(self, "st.hp_value", target, UiKit.motion(0.15))
|
st._hp_tween.tween_property(st, "hp_value", target, UiKit.motion(0.15))
|
||||||
|
|
||||||
|
|
||||||
# 主角/敌方共用——状态效果唯一展示面(壳层伴随件转发;空态 = 图标行隐藏不占位)
|
# 主角/敌方共用——状态效果唯一展示面(壳层伴随件转发;空态 = 图标行隐藏不占位)
|
||||||
@@ -205,17 +205,17 @@ func set_pending(ptype: String, pid: String) -> void:
|
|||||||
# 三档运动签名互异,灰度/剪影层可辨)。摇定时一次性短动画,随后静帧保持。
|
# 三档运动签名互异,灰度/剪影层可辨)。摇定时一次性短动画,随后静帧保持。
|
||||||
func _play_intent_motion() -> void:
|
func _play_intent_motion() -> void:
|
||||||
var tw := create_tween()
|
var tw := create_tween()
|
||||||
tw.tween_property(self, "st._intent_scale", 1.6, UiKit.motion(0.10))
|
tw.tween_property(st, "_intent_scale", 1.6, UiKit.motion(0.10))
|
||||||
tw.tween_property(self, "st._intent_scale", 1.0, UiKit.motion(0.16))
|
tw.tween_property(st, "_intent_scale", 1.0, UiKit.motion(0.16))
|
||||||
tw.parallel().tween_property(self, "st._glyph_rot", 4.0, UiKit.motion(0.10))
|
tw.parallel().tween_property(st, "_glyph_rot", 4.0, UiKit.motion(0.10))
|
||||||
tw.tween_property(self, "st._glyph_rot", 0.0, UiKit.motion(0.14))
|
tw.tween_property(st, "_glyph_rot", 0.0, UiKit.motion(0.14))
|
||||||
if _intent_charge:
|
if _intent_charge:
|
||||||
tw.tween_property(self, "st._intent_scale", 1.22, UiKit.motion(0.28)).set_trans(Tween.TRANS_SINE) # ③蓄力缓推
|
tw.tween_property(st, "_intent_scale", 1.22, UiKit.motion(0.28)).set_trans(Tween.TRANS_SINE) # ③蓄力缓推
|
||||||
tw.tween_interval(UiKit.motion(0.40)) # 定格微顿
|
tw.tween_interval(UiKit.motion(0.40)) # 定格微顿
|
||||||
tw.tween_property(self, "st._intent_scale", 1.0, UiKit.motion(0.18))
|
tw.tween_property(st, "_intent_scale", 1.0, UiKit.motion(0.18))
|
||||||
else:
|
else:
|
||||||
tw.tween_property(self, "st._intent_scale", 1.26, UiKit.motion(0.11)) # ②二次弹跳(高举)
|
tw.tween_property(st, "_intent_scale", 1.26, UiKit.motion(0.11)) # ②二次弹跳(高举)
|
||||||
tw.tween_property(self, "st._intent_scale", 1.0, UiKit.motion(0.13))
|
tw.tween_property(st, "_intent_scale", 1.0, UiKit.motion(0.13))
|
||||||
|
|
||||||
|
|
||||||
# 资产挂点:tex 落位后字形隐退、纹理立绘顶位——零代码换装契约;tex=null 回退字形。
|
# 资产挂点:tex 落位后字形隐退、纹理立绘顶位——零代码换装契约;tex=null 回退字形。
|
||||||
|
|||||||
@@ -466,7 +466,7 @@ const PANEL_DEFAULT := true # modal_shell 面板哨兵(非 StyleBox 实例
|
|||||||
# 面板哨兵解析(六参收拢五参——三态:null=无面板〔原 with_panel=false〕/PANEL_DEFAULT=默认样式盒面板
|
# 面板哨兵解析(六参收拢五参——三态:null=无面板〔原 with_panel=false〕/PANEL_DEFAULT=默认样式盒面板
|
||||||
# 〔原 with_panel=true+panel_sb=null〕/StyleBox 实例=自定义样式盒面板〔原双参形态〕;
|
# 〔原 with_panel=true+panel_sb=null〕/StyleBox 实例=自定义样式盒面板〔原双参形态〕;
|
||||||
# 判别用 is StyleBox——StyleBox 与布尔哨兵直接 != 属异类操作数违例)
|
# 判别用 is StyleBox——StyleBox 与布尔哨兵直接 != 属异类操作数违例)
|
||||||
static func _resolve_shell_panel(panel_sb) -> PanelContainer:
|
static func _resolve_shell_panel(panel_sb) -> PanelContainer: # type-hint: ignore(三态哨兵 bool/null/StyleBox 异构形参)
|
||||||
if panel_sb == null:
|
if panel_sb == null:
|
||||||
return null
|
return null
|
||||||
var panel := PanelContainer.new()
|
var panel := PanelContainer.new()
|
||||||
|
|||||||
@@ -478,7 +478,7 @@ func _smoke_save_slots() -> void:
|
|||||||
fsrc.store_string(JSON.stringify({"version": 7, "meta": {"keystone_balance": 1234}}))
|
fsrc.store_string(JSON.stringify({"version": 7, "meta": {"keystone_balance": 1234}}))
|
||||||
fsrc.close()
|
fsrc.close()
|
||||||
DirAccess.remove_absolute(slot_tpl % 1)
|
DirAccess.remove_absolute(slot_tpl % 1)
|
||||||
ml._migrate_legacy_save(legacy_src, slot_tpl % 1, legacy_src + ".migrated.bak")
|
ml.slots._migrate_legacy_save(legacy_src, slot_tpl % 1, legacy_src + ".migrated.bak")
|
||||||
var migrated: Dictionary = JSON.parse_string(FileAccess.get_file_as_string(slot_tpl % 1))
|
var migrated: Dictionary = JSON.parse_string(FileAccess.get_file_as_string(slot_tpl % 1))
|
||||||
Kit.check("sv12 旧档字节迁入槽 1(逐域相等——余额 1234)〔卡① sv12〕",
|
Kit.check("sv12 旧档字节迁入槽 1(逐域相等——余额 1234)〔卡① sv12〕",
|
||||||
int((migrated.get("meta", {}) as Dictionary).get("keystone_balance", -1)) == 1234)
|
int((migrated.get("meta", {}) as Dictionary).get("keystone_balance", -1)) == 1234)
|
||||||
@@ -489,7 +489,7 @@ func _smoke_save_slots() -> void:
|
|||||||
var fsrc2 := FileAccess.open(legacy_src, FileAccess.WRITE)
|
var fsrc2 := FileAccess.open(legacy_src, FileAccess.WRITE)
|
||||||
fsrc2.store_string(JSON.stringify({"version": 7, "meta": {"keystone_balance": 777}}))
|
fsrc2.store_string(JSON.stringify({"version": 7, "meta": {"keystone_balance": 777}}))
|
||||||
fsrc2.close()
|
fsrc2.close()
|
||||||
ml._migrate_legacy_save(legacy_src, slot_tpl % 1, legacy_src + ".migrated.bak")
|
ml.slots._migrate_legacy_save(legacy_src, slot_tpl % 1, legacy_src + ".migrated.bak")
|
||||||
var slot1_now: Dictionary = JSON.parse_string(FileAccess.get_file_as_string(slot_tpl % 1))
|
var slot1_now: Dictionary = JSON.parse_string(FileAccess.get_file_as_string(slot_tpl % 1))
|
||||||
Kit.check("sv12 幂等:槽 1 已存在不重迁(预置 777 零覆盖、源保留)〔卡① sv12〕",
|
Kit.check("sv12 幂等:槽 1 已存在不重迁(预置 777 零覆盖、源保留)〔卡① sv12〕",
|
||||||
int((slot1_now.get("meta", {}) as Dictionary).get("keystone_balance", -1)) == 1234
|
int((slot1_now.get("meta", {}) as Dictionary).get("keystone_balance", -1)) == 1234
|
||||||
|
|||||||
@@ -17,10 +17,14 @@ class StubTable:
|
|||||||
return []
|
return []
|
||||||
|
|
||||||
|
|
||||||
class StubDB:
|
class StubCrossrun:
|
||||||
var treasure_items: StubTable
|
var treasure_items: StubTable
|
||||||
|
|
||||||
|
|
||||||
|
class StubDB:
|
||||||
|
var crossrun := StubCrossrun.new()
|
||||||
|
|
||||||
|
|
||||||
func _stub_db() -> StubDB:
|
func _stub_db() -> StubDB:
|
||||||
var t := StubTable.new()
|
var t := StubTable.new()
|
||||||
t.rows = {
|
t.rows = {
|
||||||
|
|||||||
@@ -52,7 +52,7 @@ func _init() -> void:
|
|||||||
var sv = load("res://core/save_manager.gd").new("user://r1_mech_test_save.json")
|
var sv = load("res://core/save_manager.gd").new("user://r1_mech_test_save.json")
|
||||||
var mp = load("res://core/meta_progression.gd").new(db, sv)
|
var mp = load("res://core/meta_progression.gd").new(db, sv)
|
||||||
mt.rows = [base_pre.duplicate(true), base_dep.duplicate(true)]
|
mt.rows = [base_pre.duplicate(true), base_dep.duplicate(true)]
|
||||||
db.set("meta_tree", mt)
|
db.crossrun.meta_tree = mt
|
||||||
sv.meta_state.set_tree_level("gate_pre", 1)
|
sv.meta_state.set_tree_level("gate_pre", 1)
|
||||||
if mp.tree_can_buy("gate_dep"):
|
if mp.tree_can_buy("gate_dep"):
|
||||||
failures += 1
|
failures += 1
|
||||||
|
|||||||
@@ -23,6 +23,9 @@ func _init() -> void:
|
|||||||
|
|
||||||
|
|
||||||
func _trigger_oob() -> void:
|
func _trigger_oob() -> void:
|
||||||
|
# 共享 .tres 上的 resolver 归最后装载的实例——autoload ConfigDB 的 _ready 在测试 _init 之后
|
||||||
|
# 二次注入覆盖私有实例,故触发前把解析通道归还被测实例(诊断落 _db,退出码判据才成立)
|
||||||
|
_db.combat.board_gen._resolver = _db._resolver
|
||||||
# 越域请求(关卡序号 0 < 合法域 ≥1)——_fatal 内部 push fatal 诊断并 quit(1)(帧末退出)
|
# 越域请求(关卡序号 0 < 合法域 ≥1)——_fatal 内部 push fatal 诊断并 quit(1)(帧末退出)
|
||||||
var got: Dictionary = _db.combat.board_gen.resolve_row(0, 0)
|
var got: Dictionary = _db.combat.board_gen.resolve_row(0, 0)
|
||||||
if _db.diagnostics_count("fatal") >= 1:
|
if _db.diagnostics_count("fatal") >= 1:
|
||||||
|
|||||||
@@ -164,11 +164,11 @@ func _test_meta_accessors(db) -> void:
|
|||||||
if not conv_rows.is_empty():
|
if not conv_rows.is_empty():
|
||||||
var cattr: String = String(conv_rows[0].attr)
|
var cattr: String = String(conv_rows[0].attr)
|
||||||
var conv_hit := {}
|
var conv_hit := {}
|
||||||
for r in db.crossrun.meta.conversion:
|
for r in db.crossrun.meta.conversion:
|
||||||
if String(r.get("attr", "")) == cattr:
|
if String(r.get("attr", "")) == cattr:
|
||||||
conv_hit = r
|
conv_hit = r
|
||||||
break
|
break
|
||||||
Kit.check("meta.conversion 行集按 attr 命中(访问器退役改直扫同判据)", conv_hit == conv_rows[0])
|
Kit.check("meta.conversion 行集按 attr 命中(访问器退役改直扫同判据)", conv_hit == conv_rows[0])
|
||||||
|
|
||||||
|
|
||||||
# ---- TABLE_MANIFEST ↔ data/tables 目录同步(各系统→D2 单点契约的登记面)----
|
# ---- TABLE_MANIFEST ↔ data/tables 目录同步(各系统→D2 单点契约的登记面)----
|
||||||
|
|||||||
@@ -515,10 +515,15 @@ func _smoke_meta() -> void:
|
|||||||
Kit.check("boss_keystone L1–L3 行连续可达且 first_kill ≥ repeat_kill 全行(首杀全量/重复小额)", boss_ok)
|
Kit.check("boss_keystone L1–L3 行连续可达且 first_kill ≥ repeat_kill 全行(首杀全量/重复小额)", boss_ok)
|
||||||
|
|
||||||
|
|
||||||
|
class _MetaStateMock:
|
||||||
|
# 最小元进度件形态——attunement.slots 经 meta_state.tree_state() 读已购等级
|
||||||
|
func tree_state() -> Dictionary:
|
||||||
|
return {"nodes": {"att_socket1": 1}, "fork_sides": {}}
|
||||||
|
|
||||||
|
|
||||||
class _TreeSaveMock:
|
class _TreeSaveMock:
|
||||||
# 核代码增补:最小 save 形态——attunement.slots 只读 tree_level("att_socketN")
|
# 最小 save 形态——attunement.slots 只读 save.meta_state.tree_state().nodes["att_socketN"]
|
||||||
func tree_level(n: String) -> int:
|
var meta_state := _MetaStateMock.new()
|
||||||
return 1 if n == "att_socket1" else 0
|
|
||||||
|
|
||||||
|
|
||||||
func _conversion_row_of(rows: Array, attr: String) -> Dictionary:
|
func _conversion_row_of(rows: Array, attr: String) -> Dictionary:
|
||||||
|
|||||||
@@ -15,7 +15,7 @@ func _initialize() -> void:
|
|||||||
|
|
||||||
func _row_by_id(ov) -> Dictionary:
|
func _row_by_id(ov) -> Dictionary:
|
||||||
var out := {}
|
var out := {}
|
||||||
for r in ov._forge_rows:
|
for r in ov._forge._forge_rows:
|
||||||
out[String(r.route_id)] = r
|
out[String(r.route_id)] = r
|
||||||
return out
|
return out
|
||||||
|
|
||||||
@@ -42,16 +42,16 @@ func _run() -> void:
|
|||||||
# ① 锁定态:树钥匙未点亮 → 工作间不可见、两区零行板(无任何可交互购买路径)
|
# ① 锁定态:树钥匙未点亮 → 工作间不可见、两区零行板(无任何可交互购买路径)
|
||||||
ov.open_camp({"balance": 999, "forge": mp.forge_shop_status(), "tree": []})
|
ov.open_camp({"balance": 999, "forge": mp.forge_shop_status(), "tree": []})
|
||||||
Kit.check("锁定态:工作间不可见(forge_workshop 钥匙未点亮)〔锻造工坊批 V13〕",
|
Kit.check("锁定态:工作间不可见(forge_workshop 钥匙未点亮)〔锻造工坊批 V13〕",
|
||||||
not ov._forge_workbench.visible and ov._forge_lock_l.visible)
|
not ov._forge._forge_workbench.visible and ov._forge._forge_lock_l.visible)
|
||||||
Kit.check("锁定态:两区零行板(占位纪律——零购买路径)〔锻造工坊批 V13〕",
|
Kit.check("锁定态:两区零行板(占位纪律——零购买路径)〔锻造工坊批 V13〕",
|
||||||
ov._forge_zone_weapon.get_child_count() == 0 and ov._forge_zone_armor.get_child_count() == 0)
|
ov._forge._forge_zone_weapon.get_child_count() == 0 and ov._forge._forge_zone_armor.get_child_count() == 0)
|
||||||
|
|
||||||
# ② 解锁态:钥匙点亮 → 两区各三路线
|
# ② 解锁态:钥匙点亮 → 两区各三路线
|
||||||
ov.open_camp({"balance": 500, "forge": mp.forge_shop_status(),
|
ov.open_camp({"balance": 500, "forge": mp.forge_shop_status(),
|
||||||
"tree": [{"node_id": "forge_workshop", "level": 1}]})
|
"tree": [{"node_id": "forge_workshop", "level": 1}]})
|
||||||
Kit.check("解锁态:工作间可见(钥匙点亮展开)〔锻造工坊批 V13〕", ov._forge_workbench.visible)
|
Kit.check("解锁态:工作间可见(钥匙点亮展开)〔锻造工坊批 V13〕", ov._forge._forge_workbench.visible)
|
||||||
Kit.check("两区各三路线(武器锻造区 3 + 护甲锻造区 3)〔锻造工坊批 V13〕",
|
Kit.check("两区各三路线(武器锻造区 3 + 护甲锻造区 3)〔锻造工坊批 V13〕",
|
||||||
ov._forge_zone_weapon.get_child_count() == 3 and ov._forge_zone_armor.get_child_count() == 3)
|
ov._forge._forge_zone_weapon.get_child_count() == 3 and ov._forge._forge_zone_armor.get_child_count() == 3)
|
||||||
var rows: Dictionary = _row_by_id(ov)
|
var rows: Dictionary = _row_by_id(ov)
|
||||||
Kit.check("六路线行册恰全(sword/spear/staff/light/heavy/ward)〔锻造工坊批 V13〕",
|
Kit.check("六路线行册恰全(sword/spear/staff/light/heavy/ward)〔锻造工坊批 V13〕",
|
||||||
rows.has("sword") and rows.has("spear") and rows.has("staff")
|
rows.has("sword") and rows.has("spear") and rows.has("staff")
|
||||||
|
|||||||
@@ -55,6 +55,19 @@ class FakeDriver extends RefCounted:
|
|||||||
"defeat_node_index": 3, "defeat_node_type": "battle", "hp_left": 0.0, "hp_at_boss": 0.0}
|
"defeat_node_index": 3, "defeat_node_type": "battle", "hp_left": 0.0, "hp_at_boss": 0.0}
|
||||||
|
|
||||||
|
|
||||||
|
# 假配置库(TuneSimController 只读 db.run.action_economy.ap_per_round——最小域对象图)
|
||||||
|
class FakeActionEconomy:
|
||||||
|
var ap_per_round := 2
|
||||||
|
|
||||||
|
|
||||||
|
class FakeRun:
|
||||||
|
var action_economy := FakeActionEconomy.new()
|
||||||
|
|
||||||
|
|
||||||
|
class FakeDB:
|
||||||
|
var run := FakeRun.new()
|
||||||
|
|
||||||
|
|
||||||
func _init() -> void:
|
func _init() -> void:
|
||||||
UiKit.motion_scale = 1.0
|
UiKit.motion_scale = 1.0
|
||||||
|
|
||||||
@@ -126,7 +139,7 @@ func _init() -> void:
|
|||||||
var panel := FakePanel.new()
|
var panel := FakePanel.new()
|
||||||
root.add_child(panel)
|
root.add_child(panel)
|
||||||
var drv := FakeDriver.new()
|
var drv := FakeDriver.new()
|
||||||
var ctrl = TuneSimScript.new({"action_economy": {"ap_per_round": 2}}, panel, 100, drv)
|
var ctrl = TuneSimScript.new(FakeDB.new(), panel, 100, drv)
|
||||||
drv.ctrl = ctrl
|
drv.ctrl = ctrl
|
||||||
await ctrl.run(2) # 假 driver 回调内读 is_running()(两局各一读)
|
await ctrl.run(2) # 假 driver 回调内读 is_running()(两局各一读)
|
||||||
Kit.check("控制器运行中 is_running()=true(驱动回调内读数)〔wd8〕", drv.seen == [true, true])
|
Kit.check("控制器运行中 is_running()=true(驱动回调内读数)〔wd8〕", drv.seen == [true, true])
|
||||||
|
|||||||
@@ -802,7 +802,7 @@ func _camp_recent_projection() -> void:
|
|||||||
var camp = load("res://presentation/views/camp_overlay_view.gd").new()
|
var camp = load("res://presentation/views/camp_overlay_view.gd").new()
|
||||||
camp.open_camp({"balance": 0, "recent": [
|
camp.open_camp({"balance": 0, "recent": [
|
||||||
{"result": "completed", "levels_cleared": 2, "keystone_total": 5, "master_seed": 42}]})
|
{"result": "completed", "levels_cleared": 2, "keystone_total": 5, "master_seed": 42}]})
|
||||||
var recent_text: String = String(camp._recent_list.text)
|
var recent_text: String = String(camp._side._recent_list.text)
|
||||||
Kit.check("营地最近冒险行完成关数措辞(实际「%s」)〔口径换代 V6〕" % recent_text,
|
Kit.check("营地最近冒险行完成关数措辞(实际「%s」)〔口径换代 V6〕" % recent_text,
|
||||||
recent_text.contains("完成 2 关") and not recent_text.contains("通关"))
|
recent_text.contains("完成 2 关") and not recent_text.contains("通关"))
|
||||||
camp.visible = false
|
camp.visible = false
|
||||||
|
|||||||
Reference in new issue
Block a user