diff --git a/game/core/action_economy.gd b/game/core/action_economy.gd index a80b0455..816e76be 100644 --- a/game/core/action_economy.gd +++ b/game/core/action_economy.gd @@ -13,19 +13,23 @@ const PHASE_IDLE := "Idle" const PHASE_ACTIVE := "Active" const PHASE_WAITING := "Waiting" -var db +# 相位轴(P6 状态机——code-review 2026-09-29 P2-2):内部 enum + match,外部 phase getter 保持 +# String 面(presentation_snapshot 与冒烟链的 "Idle"/"Active"/"Waiting" 对照契约零变化)。 +enum Phase { IDLE, ACTIVE, WAITING } + +var db: ConfigDb # 相位与账本只读出口(E5 封装收口 2026-09-13):外部读取经 getter-only 属性(架构文档 # "ap/rap/phase 只读" 的机制化),写入只经 notify_* / request_* 方法通道。 -var _phase: String = PHASE_IDLE +var _phase: int = Phase.IDLE var phase: String: - get: return _phase + get: return _phase_text(_phase) var _ap := 0 var ap: int: get: return _ap var _rap := 0 var rap: int: get: return _rap -var _last_round_end: Dictionary = {} # {path_tag, continuation_hint}——排雷玩法 组包 round_end 的合法数据源 +var _last_round_end: Dictionary[String, String] = {} # {path_tag, continuation_hint}——排雷玩法 组包 round_end 的合法数据源 var last_round_end: Dictionary: get: return _last_round_end var _settlement_consumed := false # AC-14 门:notify_settlement_done 消费后才受理 round_start @@ -33,10 +37,19 @@ var _next_round_mode := "" # 调试观测量(同板续轮 / var _pending_ap_delta := 0 # 下轮行动点修正排队(格面资源八型批 2026-09-20——action 型 ±1 排队,轮开始兑现后清零) -func _init(db_ref) -> void: +func _init(db_ref: ConfigDb) -> void: db = db_ref +func _phase_text(p: int) -> String: + match p: + Phase.ACTIVE: + return PHASE_ACTIVE + Phase.WAITING: + return PHASE_WAITING + return PHASE_IDLE + + func _cost(kind: String) -> int: var ae = db.action_economy match kind: @@ -54,7 +67,7 @@ func _cost(kind: String) -> int: # 通用扣减(排雷玩法 用于旗动作;挖握走 request_dig——cleared 仲裁需要 clears_map 参数) func try_spend(action_kind: String) -> bool: - if phase != PHASE_ACTIVE: + if _phase != Phase.ACTIVE: _reject("phase") return false return _spend_and_arbitrate(action_kind, false) @@ -62,7 +75,7 @@ func try_spend(action_kind: String) -> bool: # 排雷玩法 挖掘专用:chain_size = 连锁附加格数(不含首格);clears_map = 本次动作后全图安全格开完 func request_dig(chain_size: int, clears_map: bool) -> bool: - if phase != PHASE_ACTIVE: + if _phase != Phase.ACTIVE: _reject("phase") return false return _spend_and_arbitrate("dig", clears_map) @@ -86,7 +99,7 @@ func _spend_and_arbitrate(action_kind: String, clears_map: bool) -> bool: # 停手:剩余 AP 1:1 转存 RAP;行动经济 直发 stopped 路径 round_end(双发射源) func request_stop() -> bool: - if phase != PHASE_ACTIVE: + if _phase != Phase.ACTIVE: _reject("phase") return false _rap += _ap @@ -100,7 +113,7 @@ func request_stop() -> bool: # Active 相位——仅扣 RAP,相位与 AP 均不动。刷新不打断轮次、不触发结算;换图编排归 战斗结算 # (retire + install 立即执行,玩家同轮继续挖新图)。决策主体 = 玩家(经 HUD框架发起)纪律不变。 func request_refresh() -> bool: - if phase != PHASE_ACTIVE: + if _phase != Phase.ACTIVE: _reject("phase") return false if _rap < db.action_economy.rap_refresh_cost: @@ -111,7 +124,7 @@ func request_refresh() -> bool: # 战斗结算 回发:结算完成(仅记录编排意图;phase 停留 Waiting——AC-14 门不被绕过) func notify_settlement_done(next_round_mode: String) -> bool: - if phase != PHASE_WAITING: + if _phase != Phase.WAITING: _reject("phase") return false _settlement_consumed = true @@ -130,25 +143,25 @@ func pending_ap_delta() -> int: func notify_round_start() -> bool: - if phase == PHASE_IDLE: + if _phase == Phase.IDLE: pass # 战斗首轮唯一出口 - elif phase == PHASE_WAITING and _settlement_consumed: + elif _phase == Phase.WAITING and _settlement_consumed: pass else: _reject("phase") return false _ap = maxi(0, db.action_economy.ap_per_round + _pending_ap_delta) # 每轮基线 + 排队修正(下限 0) _pending_ap_delta = 0 - _phase = PHASE_ACTIVE + _phase = Phase.ACTIVE _settlement_consumed = false return true func notify_combat_end() -> bool: - if phase != PHASE_WAITING: + if _phase != Phase.WAITING: _reject("phase") return false - _phase = PHASE_IDLE + _phase = Phase.IDLE _rap = 0 # RAP 战斗域清零(用户拍板;HUD框架可见反馈义务) _ap = 0 return true @@ -160,7 +173,7 @@ func _finish_round(path_tag: String, continuation_hint: String) -> void: assert(path_tag != "ap_exhausted" or _ap == 0, "耗尽轮剩余行动点恒为 0(实现层断言兜底)") assert(path_tag != "cleared" or _ap == 0, "清图轮剩余行动点当场清零(不进储备池)") _last_round_end = {"path_tag": path_tag, "continuation_hint": continuation_hint} - _phase = PHASE_WAITING + _phase = Phase.WAITING func _reject(source: String) -> void: diff --git a/game/core/adventure_runner.gd b/game/core/adventure_runner.gd index 2f267235..7d8a3bf4 100644 --- a/game/core/adventure_runner.gd +++ b/game/core/adventure_runner.gd @@ -66,7 +66,7 @@ var _base_override := {"atk": 0, "max_hp": 0, "armor_class": 0} var _first_script := false # 首次脚本模式(关卡节点图生成 v0.4——true = 全关零抽签取池内模板 0;测量夹具恒 false) # 永久强化 flat 注入(元进度实现批——冒险开始参数面 params.hero_override 存入,共享给 LevelRunner;全零 = 白板) -func _init(db_ref, rng_ref) -> void: +func _init(db_ref: ConfigDb, rng_ref: RngServiceCore) -> void: db = db_ref rng = rng_ref diff --git a/game/core/battle_orchestrator.gd b/game/core/battle_orchestrator.gd index f6d1de1a..d9b6fe99 100644 --- a/game/core/battle_orchestrator.gd +++ b/game/core/battle_orchestrator.gd @@ -38,8 +38,8 @@ const SOURCE_EXEMPT_TYPES := ["decay", "verdict"] # 行来源断言豁免集合(来源类别层)——事实来源是单位 / 清图而非棋盘格 const SOURCE_EXEMPT_CLASSES := ["hero_attack", "enemy_action", "clear_reward"] -var db -var rng +var db: ConfigDb +var rng: RngServiceCore # E1 封装收口(2026-09-13):协作对象 board_generator/enemy_system/status_effects/reward_economy 私有化——跨层读取一律经 presentation_snapshot()/ # diagnostic_snapshot() 成文出口(呈现层链式穿透 settlement._enemy_system.hero_unit() 的根因收口)。 # minesweeper/action_economy 保持公有 = 架构文档 API Boundaries 的 HUD框架消费面(意图提交 settle_batch + compute_move_path @@ -52,13 +52,13 @@ var _status_effects: StatusContainer var _reward_economy: RewardEconomy var _damage: DamageController # 伤害控制器(伤害管线单据化批 2026-09-24——单据唯一兑付管线) -var encounter: Dictionary = {} +var encounter: Dictionary[String, Variant] = {} var round_index := 0 var battle_result := "" # "" / "victory" / "defeat" / "fatal_error" var escrow := 0 # 战斗内 GP 缓冲(战斗域中间态——begin_battle 清零;gp_gain/gp_loss 兑付累记;随 gp_dropped 上抛即弃,不入钱包) -var _facts_reveals: Array = [] -var _facts_flags: Array = [] +var _facts_reveals: Array[Dictionary] = [] +var _facts_flags: Array[Dictionary] = [] var _facts_path := "" var _settling := false var _refresh_used_this_round := 0 # 每轮刷新计数(Active 相位合计,兜底上限 = ActionEconomyTable.refresh_cap_per_round) @@ -71,7 +71,7 @@ var _perfect_hit_false := 0 var _hero_atk := 0 # 主角攻击基值快照(encounter.hero_atk;E4 收口——表值运行期不可变) -func _init(db_ref, rng_ref) -> void: +func _init(db_ref: ConfigDb, rng_ref: RngServiceCore) -> void: db = db_ref rng = rng_ref _board_generator = BoardGenerator.new() @@ -94,7 +94,7 @@ func begin_battle(enc: Dictionary) -> bool: if round_index != 0: push_warning("[战斗结算] begin_battle 重复受理") return false - encounter = enc + encounter.assign(enc) escrow = 0 # 战斗域零 GP 持久(GP+商店房实施批——每场战斗缓冲从零起算) _damage.set_hero_ac_override(int(enc.get("hero_armor_class", -1))) # 主角护甲合流入参(伤害控制器 defender_ac 消费——口径同原 _defender_ac) db.set_reload_gate(true) @@ -150,7 +150,7 @@ func _install_new_board(during_round := false) -> bool: var r0 := {} for c in board.compute_r0(): r0[c] = true - var eligible: Array = [] + var eligible: Array[Dictionary] = [] for c in board.safe_cells(): if not r0.has(c): eligible.append({"cell": c}) @@ -189,7 +189,7 @@ func _place_variants(board: BoardData) -> void: var r0 := {} for c in board.compute_r0(): r0[c] = true - var candidates: Array = [] + var candidates: Array[Vector2i] = [] for c in board.safe_cells(): if not r0.has(c): candidates.append(c) @@ -203,7 +203,7 @@ func _place_variants(board: BoardData) -> void: var placed := {} while placed.size() < total: var pack_size: int = mini(total - placed.size(), stream.randi_range(2, int(db.variation.pack_max))) - var free: Array = [] + var free: Array[Vector2i] = [] for c in candidates: # 新片种子/生长格禁与其他已布片 8 邻贴接——否则两片粘连成一个超 pack_max 的连通分量 # (R3 随机流下实测暴露:独立生长的相邻片合流击穿单片上限断言) @@ -217,7 +217,7 @@ func _place_variants(board: BoardData) -> void: var pack: Array = [seed_c] var pack_set := {seed_c: true} while pack.size() < pack_size: - var fringe: Array = [] + var fringe: Array[Vector2i] = [] for c in pack: for n in board.neighbors8(c): if candidates.has(n) and not placed.has(n) and not fringe.has(n) \ @@ -628,10 +628,10 @@ func _emit_composition_effects(side: String, ri: int) -> void: # ---- 结算快照(playtest 数值分析数据面——每次结算全量状态;运行时零决策读取)---- func _emit_settlement_snapshot(verdict: String) -> void: - var enemies: Array = [] + var enemies: Array[Dictionary] = [] for u in _enemy_system.query_alive("enemy"): enemies.append({"id": String(u.enemy_id), "hp": int(u.hp), "max_hp": int(u.max_hp), "atk": int(u.atk), "pending_skill": _enemy_system.pending_action(u), "armor": String(u.get("armor_type", "light")), "armor_class": int(u.get("armor_class", 0))}) - var buffs: Array = [] + var buffs: Array[Dictionary] = [] for eff in _status_effects.query_active("hero"): buffs.append({"id": eff.effect_id, "side": "hero", "layers": eff.layers, "left": eff.remaining_settlements}) for eff in _status_effects.query_active("enemy"): @@ -746,10 +746,10 @@ func _roll_gp_drop() -> int: # (敌人技能池批批 2 定稿:beat/ring_size/ring_index 拆除 → pending_* 三字段 + 敌方增益 effects 投影;池与权重不公开; # 八型批 2026-09-20:ambush_layers 拆除——伏击退役,警觉并入 effects 投影)hero_effects[](增益状态 query_active 投影) func presentation_snapshot() -> Dictionary: - var enemies: Array = [] + var enemies: Array[Dictionary] = [] var all: Array = _enemy_system.all_enemies() # 敌方增益投影(side-wide 状态——蓄力/硬化/削弱/暴走 percent 行 + 警觉 ac 行,八型批 2026-09-20) - var enemy_effects: Array = [] + var enemy_effects: Array[Dictionary] = [] for eff in _status_effects.query_active("enemy"): var erow: Dictionary = db.status_effect_row(eff.effect_id) if not erow.is_empty() and String(erow.unit) in ["percent", "ac"]: diff --git a/game/core/board_data.gd b/game/core/board_data.gd index d5cdcdea..354919de 100644 --- a/game/core/board_data.gd +++ b/game/core/board_data.gd @@ -49,7 +49,7 @@ func has_variant(c: Vector2i, vid: String) -> bool: func neighbors8(c: Vector2i) -> Array: - var out: Array = [] + var out: Array[Vector2i] = [] for dy in range(-1, 2): for dx in range(-1, 2): if dx == 0 and dy == 0: @@ -61,7 +61,7 @@ func neighbors8(c: Vector2i) -> Array: func spawn_cells() -> Array: - var out: Array = [] + var out: Array[Vector2i] = [] for dy in range(-1, 2): for dx in range(-1, 2): var c := Vector2i(spawn_center.x + dx, spawn_center.y + dy) @@ -71,7 +71,7 @@ func spawn_cells() -> Array: func all_cells() -> Array: - var out: Array = [] + var out: Array[Vector2i] = [] for y in height: for x in width: out.append(Vector2i(x, y)) @@ -79,7 +79,7 @@ func all_cells() -> Array: func safe_cells() -> Array: - var out: Array = [] + var out: Array[Vector2i] = [] for c in all_cells(): if is_safe(c): out.append(c) diff --git a/game/core/board_generator.gd b/game/core/board_generator.gd index b946942c..b8e9e676 100644 --- a/game/core/board_generator.gd +++ b/game/core/board_generator.gd @@ -83,7 +83,7 @@ func _attempt(params: Dictionary, rng_stream: RandomNumberGenerator, db) -> Boar var spawn := {} for c in b.spawn_cells(): spawn[c] = true - var domain: Array = [] + var domain: Array[Vector2i] = [] for c in b.all_cells(): if not spawn.has(c): domain.append(c) @@ -198,7 +198,7 @@ func measure_inferability(b: BoardData) -> Dictionary: func _build_constraints(b: BoardData, r: Dictionary, known_mines: Dictionary, safe_set: Dictionary) -> Array: - var out: Array = [] + var out: Array[Dictionary] = [] for c in r.keys(): if not safe_set.has(c): continue # 只对已开安全格的数字建约束 @@ -273,7 +273,7 @@ func legality(b: BoardData, params: Dictionary, db) -> bool: func _legality_faults(b: BoardData, params: Dictionary) -> Array: - var faults: Array = [] + var faults: Array[String] = [] # ① 出生区无雷 ② 出生区∪R₀ 无变异 ③ 数字恒真 ④ R₀ ≠ S(排雷玩法 修订义务) for c in b.spawn_cells(): if b.is_mine(c): diff --git a/game/core/config_db.gd b/game/core/config_db.gd index d5dc1c81..9a32cd5b 100644 --- a/game/core/config_db.gd +++ b/game/core/config_db.gd @@ -4,6 +4,7 @@ # ConfigDB autoload(数据配置)——数值表单点访问入口(Rule 2)+ 校验双通道(Rule 6)+ R1 行解析。 # 实现 GDD:design/archive/gdd-2026-09-14/d2-data-config.md(系统 ID D2·数据配置——registry 追溯锚,命名规范见 CLAUDE.md) # 切片注:headless --script 模式下由冒烟脚本显式实例化(数据配置 AC 前言);玩法代码禁止绕过本单点自建 load()。 +class_name ConfigDb extends Node const SCHEMA_VERSION := 1 @@ -36,16 +37,16 @@ var reward: RewardTable var settlement: SettlementTable var level: LevelTable var difficulty: DifficultyTable -# GP+商店房实施批(2026-09-21):ShopTable 暂持无类型注记——schema class_name 落籍归并行数据面, -# 落籍后可收紧为 `var shop: ShopTable`(消费面一律走下方 shop_* 访问器,禁直读行集) -var shop = null +# GP+商店房实施批(2026-09-21):ShopTable 类型化持用(schema class_name 已落籍——code-review 2026-09-29 P2-4 收口; +# 消费面一律走下方 shop_* 访问器,禁直读行集) +var shop: ShopTable = null # 元进度实现批(2026-09-21):MetaTable 类型化持用(schema 与表同批落籍,无 shop 先例的落籍间隙问题) var meta: MetaTable var adventure: AdventureTable var is_ready := false -var _diagnostics: Array = [] # {severity, category, message} -var _warn_dedup: Dictionary = {} # R1 四元组去重注册表 +var _diagnostics: Array[Dictionary] = [] # {severity, category, message} +var _warn_dedup: Dictionary[String, bool] = {} # R1 四元组去重注册表 var _reload_gate := false # 数据配置 EC8——战斗结算 唯一调用方 @@ -170,7 +171,7 @@ func _cross_validate(loaded: Dictionary) -> void: for lrow in lv.rows: var li: int = int(lrow.level_index) # 模板池感知(关卡节点图生成 v0.4——池内全模板跨表校验,不只 row.nodes) - var node_lists: Array = [] + var node_lists: Array[Array] = [] var tpls: Array = lrow.get("templates", []) if tpls.is_empty(): node_lists.append(lrow.get("nodes", [])) @@ -199,8 +200,8 @@ func _cross_validate(loaded: Dictionary) -> void: # proposal-status-vocabulary §1.2)+ 施放类 side 守卫(增益引用 enemy 侧 / 妨害引用 hero 侧状态行)。 # status_table 显式入参:装载序上本校验先于成员赋值执行(self.status_effects 尚为 Nil)——装载通道传 loaded 表, # 冒烟直验传 _db.status_effects;传 null 时 side 守卫跳过(其他校验不受影响)。 -func validate_skill_pool_links(skill_table, enemy_table, status_table = null) -> Array: - var errs: Array = [] +func validate_skill_pool_links(skill_table: SkillTable, enemy_table: EnemyTable, status_table: StatusEffectTable = null) -> Array: + var errs: Array[Dictionary] = [] var skill_types := {} for row in skill_table.rows: skill_types[String(row.get("skill_id", ""))] = String(row.get("type", "")) @@ -267,7 +268,7 @@ func _resolve_progress(rows: Array, L: int, D: int, table_id: String) -> Diction if L < 1 or D < 0: _fatal("request_oob", "%s 请求越域 (%d,%d)——进度坐标低于合法域(关卡序号≥1、节点深度≥0)" % [table_id, L, D]) return {} - var level_keys: Array = [] + var level_keys: Array[int] = [] for row in rows: var lv := int(row.get("level_index", 0)) if not level_keys.has(lv): @@ -280,7 +281,7 @@ func _resolve_progress(rows: Array, L: int, D: int, table_id: String) -> Diction var l_clamped := l_star < 0 if l_clamped: l_star = int(level_keys[-1]) # 超出最大行 → 取最大行封顶(2026-09-18 追加拍板:可取范围内向上取整,超出用最大值) - var depth_keys: Array = [] + var depth_keys: Array[int] = [] for row in rows: if int(row.get("level_index", 0)) == l_star: var dv := int(row.get("node_depth", 0)) @@ -328,7 +329,7 @@ func _ceil_key(sorted_keys: Array, request: int) -> int: # board_type 词表——biome_tags 系旧观念残留退役)---- func variant_pool(level_index: int, board_type: String) -> Array: - var pool: Array = [] + var pool: Array[Dictionary] = [] for row in variation.rows: if int(row.get("unlock_level", 999)) > level_index: continue diff --git a/game/core/damage_controller.gd b/game/core/damage_controller.gd index eff81ef2..7899f7ba 100644 --- a/game/core/damage_controller.gd +++ b/game/core/damage_controller.gd @@ -48,14 +48,14 @@ const TARGET_FRONT_ALIVE := "front_alive_enemy" const TARGET_HERO := "hero" const TARGET_ALL_ALIVE := "all_alive_enemies" -var db +var db: ConfigDb var rng var units # UnitContainer——目标解析/伤害交付/存活查询(句柄即 Dictionary 引用) var effects # StatusContainer——池值/AC 型效果读取(增益状态 只读消费面) var emit_row_cb: Callable # 行协议注入口:func(type, source_class, origin_cell, ri, display, value, extra, highlight) var policy := POLICY_SEGMENT # 结账时机开关(2026-09-24 用户拍板第二步拨 B=攒批段界统一结;回切 A 改回 POLICY_IMMEDIATE 即还原迁移前行为) -var _queue: Array = [] # 未结单据(B 模式攒批;A 模式恒空) +var _queue: Array[Dictionary] = [] # 未结单据(B 模式攒批;A 模式恒空) var _outcomes := {} # ticket_id → "redeemed"/"zero"/"voided"(结账后可查——清图高光份数消费) var _seq := 0 # 流水号 var _halted := false # 主角倒下终止旗(死亡事件置位——flush 余单作废) diff --git a/game/core/level_runner.gd b/game/core/level_runner.gd index 5bad590a..e5a762de 100644 --- a/game/core/level_runner.gd +++ b/game/core/level_runner.gd @@ -40,9 +40,9 @@ signal board_changed() signal level_finished(payload: Dictionary) # {result, hp, node_index, node_id, node_type} signal wallet_changed(event: String, gp: int, extra: Dictionary) # GP 钱包事件投影:gain{amount}/buy{product,price}/clear——试玩日志与商店覆盖层刷新源(GP+商店房实施批) -var db -var rng -var level_row: Dictionary = {} +var db: ConfigDb +var rng: RngServiceCore +var level_row: Dictionary[String, Variant] = {} var node_index := -1 # ---- 账本载体(冒险结构实现批——漂移②清偿)---- # 冒险模式 = AdventureRunner 共享字典(Dictionary 引用共享——hero_hp/gp 属性读写直接落冒险账本); @@ -68,12 +68,12 @@ var hero_hp_pct := 0 var _running := false var level_result := "" # "" / "victory" / "defeat" var _awaiting_choice := false # 选路态(兑付确认后、pick 前为零自动推进的可见停点) -var _candidates: Array = [] # 当前选路候选(节点引用数组) -var visited: Array = [] # 已兑付/到达节点序列(呈现层图条数据源;含当前节点) +var _candidates: Array[Dictionary] = [] # 当前选路候选(节点引用数组) +var visited: Array[Dictionary] = [] # 已兑付/到达节点序列(呈现层图条数据源;含当前节点) var _graph_mode := false # 图形态缓存(行集任一节点带 next;单链 = false) -func _init(db_ref, rng_ref) -> void: +func _init(db_ref: ConfigDb, rng_ref: RngServiceCore) -> void: db = db_ref rng = rng_ref @@ -142,7 +142,7 @@ func start_level(level_index: int, seed_val: int, base_override_in: Dictionary = break hero_hp = effective_max_hp() rng.new_adventure(seed_val) # 关卡起点 = 冒险起点(切片口径;跨关接续归 冒险结构) - level_row = _resolve_template_row(row, template_pick) # 池解析在播种后(node_map 抽签须已播种——EC7) + level_row.assign(_resolve_template_row(row, template_pick)) # 池解析在播种后(node_map 抽签须已播种——EC7) _running = true var entry := _entry_node() if entry.is_empty(): @@ -177,7 +177,7 @@ func start_level_external(level_index: int, ledger: Dictionary, bonus_ref: Dicti base_override = base_override_ref _shop_purchased = purchased_ref _rest_handler = rest_handler - level_row = _resolve_template_row(row, template_pick) + level_row.assign(_resolve_template_row(row, template_pick)) node_index = -1 level_result = "" _awaiting_choice = false @@ -286,11 +286,11 @@ func _out_ids(node: Dictionary) -> Array: # 出边候选(节点引用数组——选路口/呈现层共用读面) -func _out_nodes(node: Dictionary) -> Array: +func _out_nodes(node: Dictionary) -> Array[Dictionary]: var ids := {} for n in nodes(): ids[_node_id(n)] = n - var out: Array = [] + var out: Array[Dictionary] = [] for tid in _out_ids(node): if ids.has(tid): out.append(ids[tid]) @@ -304,7 +304,7 @@ func next_candidates() -> Array: # 当前选路候选编号表(pick_next_node 的合法入参域——编号空间解析单一出口) func next_candidate_ids() -> Array: - var out: Array = [] + var out: Array[int] = [] for c in _candidates: out.append(_node_id(c)) return out @@ -326,7 +326,7 @@ func node_out_ids(node: Dictionary) -> Array: # 已到节点编号序列(只读投影——编号空间解析单一出口) func visited_ids() -> Array: - var out: Array = [] + var out: Array[int] = [] for v in visited: out.append(_node_id(v)) return out @@ -493,7 +493,7 @@ func close_wallet() -> void: # 商店覆盖层数据源(只读投影——现价/已购档数在此现算,呈现层禁复算定价公式) func shop_products() -> Array: - var out: Array = [] + var out: Array[Dictionary] = [] for prow in db.shop_products(): out.append({ "product_id": String(prow.get("product_id", "")), diff --git a/game/core/meta_progression.gd b/game/core/meta_progression.gd index 3f8ae992..a94e6083 100644 --- a/game/core/meta_progression.gd +++ b/game/core/meta_progression.gd @@ -16,11 +16,11 @@ class_name MetaProgression extends RefCounted -var db -var save +var db: ConfigDb +var save: SaveManager -func _init(db_ref, save_ref) -> void: +func _init(db_ref: ConfigDb, save_ref: SaveManager) -> void: db = db_ref save = save_ref @@ -83,7 +83,7 @@ func _workshop_progress(channel: String) -> int: # 工坊六行只读投影(呈现层数据源):{item_id, display_name, threshold, unlocked, progress} func workshop_status() -> Array: - var out: Array = [] + var out: Array[Dictionary] = [] for row in db.meta_workshop_items(): var iid := String(row.get("item_id", "")) out.append({ @@ -98,7 +98,7 @@ func workshop_status() -> Array: # 达标未解锁 → unlock_item + 写盘;返回新解锁 item_id 列(冒险收束后与营地打开时各调一次) func refresh_workshop_unlocks() -> Array: - var new_unlocks: Array = [] + var new_unlocks: Array[String] = [] for row in db.meta_workshop_items(): var iid := String(row.get("item_id", "")) if save.item_unlocked(iid): @@ -118,7 +118,7 @@ func refresh_workshop_unlocks() -> Array: func settle_adventure(summary: Dictionary) -> Dictionary: # 首次冒险布尔位置位(关卡节点图生成 v0.4——完成/失败/放弃三结局同经本收束挂点,写入只在收束) save.mark_first_adventure_done() - var drops: Array = [] + var drops: Array[Dictionary] = [] for li in range(1, int(summary.get("levels_cleared", 0)) + 1): var first: bool = not save.boss_first_kill_marked(li) var row: Dictionary = db.meta_boss_keystone_row(li) diff --git a/game/core/minesweeper_rules.gd b/game/core/minesweeper_rules.gd index acd3ab1c..757111d5 100644 --- a/game/core/minesweeper_rules.gd +++ b/game/core/minesweeper_rules.gd @@ -15,18 +15,18 @@ signal round_end_board(payload: Dictionary) # 双发射源之棋盘路径( const SUB_REASONS := ["not_adjacent", "target_revealed", "target_concealed", "flag_present", "no_path", "out_of_catalog"] # flag_absent 随 flag_pull 退役(2026-09-19) -var db -var action_economy +var db: ConfigDb +var action_economy: ActionEconomy # 棋盘状态私有(E2 封装收口 2026-09-13):对外只暴露 current_board()/reveal_record() 等查询面, # 禁止跨模块直读/直写原始字典——先例教训 = board_view 绕过查询面直读 revealed。 var _board: BoardData = null var _revealed := {} # Vector2i → {"kind": "safe"/"mine", "digit": int} var _flags := {} # Vector2i → true(棋盘单态;跨轮保留随图存续) var _hero := Vector2i.ZERO -var _spawn: Dictionary = {} +var _spawn: Dictionary[Vector2i, bool] = {} -func _init(db_ref, action_economy_ref) -> void: +func _init(db_ref: ConfigDb, action_economy_ref: ActionEconomy) -> void: db = db_ref action_economy = action_economy_ref @@ -125,7 +125,7 @@ func retire_board(during_round := false) -> Dictionary: # 四不变式(诊断类别封闭枚举):inv1 出生区雷 / inv2a 出生区变异 / inv2b R₀ 变异 / inv3 数字恒真 / inv4 R₀=S func _install_invariant_faults(b: BoardData) -> Array: - var faults: Array = [] + var faults: Array[String] = [] var r0 := {} for c in b.compute_r0(): r0[c] = true @@ -171,7 +171,7 @@ func _initial_expansion_order(b: BoardData) -> Array: # ---- 批次结算(唯一提交入口;单意图批 = 平凡形 ≡ 便捷 API)---- func settle_batch(intents: Array) -> Array: - var outcomes: Array = [] + var outcomes: Array[Dictionary] = [] if intents.is_empty(): return outcomes if action_economy.phase != action_economy.PHASE_ACTIVE or _board == null: @@ -179,7 +179,7 @@ func settle_batch(intents: Array) -> Array: outcomes.append(_outcome(false, "rejected", "phase", "")) return outcomes # F4 语义序仲裁:C_dig(真模拟清图)→ C_stop → C_other;类内稳定序 = 到达序 - var indexed: Array = [] + var indexed: Array[Dictionary] = [] for i in intents.size(): indexed.append({"i": i, "intent": intents[i], "cls": _classify(intents[i])}) indexed.sort_custom(func(a, b): @@ -395,7 +395,7 @@ func compute_move_path(target: Vector2i) -> Array: queue.append(n) if not prev.has(target): return [] - var path: Array = [] + var path: Array[Vector2i] = [] var cur := target while cur != _hero: path.push_front(cur) diff --git a/game/core/reward_economy.gd b/game/core/reward_economy.gd index 990b2b92..69b8963d 100644 --- a/game/core/reward_economy.gd +++ b/game/core/reward_economy.gd @@ -12,10 +12,10 @@ class_name RewardEconomy extends RefCounted -var db -var rng +var db: ConfigDb +var rng: RngServiceCore var _phase := "unrolled" # unrolled → ready → retired -var _eligible: Array = [] # [{cell}] 行主序规范序 +var _eligible: Array[Dictionary] = [] # [{cell}] 行主序规范序 var _mapping := {} # Vector2i → reward_id(正向行身份——格面资源类型由 cell_type 承载) var _power_roll := {} # Vector2i → 区间行 roll 值(身份批内追加取号) var _clear_power := -1 # 清图槽区间行 roll 值(-1 = 定值行) @@ -25,7 +25,7 @@ var _clear_granted := false var _clear_snapshot := {} -func _init(db_ref, rng_ref) -> void: +func _init(db_ref: ConfigDb, rng_ref: RngServiceCore) -> void: db = db_ref rng = rng_ref @@ -43,7 +43,7 @@ func roll_board(eligible: Array) -> bool: return false # 行主序规范化 + 去重(排序责任不外推给 战斗结算) var seen := {} - var list: Array = [] + var list: Array[Dictionary] = [] for e in eligible: var c: Vector2i = e.cell if seen.has(c): @@ -175,7 +175,7 @@ func polarity_row(cell_type: String, polarity: String) -> Dictionary: # ---- F6 当量供给(行动经济 条款①对照实物输入——全活行投影 + tier_min_buff)---- func equivalence_supply() -> Dictionary: - var live: Array = [] + var live: Array[Dictionary] = [] var tier_min_buff := 99 for row in db.reward.rows: if int(row.weight) <= 0: @@ -206,7 +206,7 @@ func weighted_pick(rows: Array, r: int) -> String: func _rollable_rows() -> Array: # 摇号池 = cell 池正向行 weight>0(负向行纯字典不消费权重;封锁格不在本函数职责域——清单由调用方裁剪) - var out: Array = [] + var out: Array[Dictionary] = [] for row in db.reward.rows: if String(row.get("pool_tag", "")) == "cell" and String(row.get("polarity", "")) == "positive" and int(row.weight) > 0: out.append(row) @@ -214,7 +214,7 @@ func _rollable_rows() -> Array: func _pool_rows(pool_tag: String) -> Array: - var out: Array = [] + var out: Array[Dictionary] = [] for row in db.reward.rows: if row.pool_tag == pool_tag and int(row.weight) > 0: out.append(row) diff --git a/game/core/rng_service.gd b/game/core/rng_service.gd index 57da3383..7415dc9f 100644 --- a/game/core/rng_service.gd +++ b/game/core/rng_service.gd @@ -11,6 +11,7 @@ # splitmix64 finalizer 变体终末混淆,见 _mix64 注记;并流前分盐黄金向量随批作废,新向量按单盐重登记(scope 0-3 与 # 旧 board_gen 向量逐位连续——单盐沿用原 board_gen 盐)。 # 取号语义:全新冒险首个 open_stream = 全局 scope 0;事件日志逐次落盘 user://logs/rng_log_.jsonl。 +class_name RngServiceCore extends Node # 用途标签封闭词表(并流前七流名全保留;新增用途走扩签通道 = 改代码 + 评审——清单封闭语义由「流」改「标签」) diff --git a/game/core/save_manager.gd b/game/core/save_manager.gd index 92f31493..0ba4a064 100644 --- a/game/core/save_manager.gd +++ b/game/core/save_manager.gd @@ -33,8 +33,8 @@ const FORGE_ATTRS := ["max_hp", "atk", "armor_class"] # 属性锻造三档合 var _path: String # 存档文件路径(默认 user://save.json;冒烟注入隔离路径) var _read_only := false # 高版本拒读置位——write_to_disk 一律拒绝(契约 4 禁写) -var _data: Dictionary = {} # 内存数据模型(_init 即内置默认;load 后为档案内容) -var _migrations: Dictionary = {} # from_version → Callable(data)->data(升一版;生产链现为空——骨架先行) +var _data: Dictionary[String, Variant] = {} # 内存数据模型(_init 即内置默认;load 后为档案内容) +var _migrations: Dictionary[int, Callable] = {} # from_version → Callable(data)->data(升一版;生产链现为空——骨架先行) func _init(path: String = "user://save.json") -> void: @@ -44,7 +44,7 @@ func _init(path: String = "user://save.json") -> void: # ---- 默认数据模型(新档合法态——全零;白板存档 = 完整可玩〔元进度 单局循环零依赖〕)---- -func _default_data() -> Dictionary: +func _default_data() -> Dictionary[String, Variant]: return { "version": SAVE_FORMAT_VERSION, "meta": { @@ -222,7 +222,7 @@ func _corrupt_fallback(reason: String) -> bool: # 迁移后/低版本档字段补齐(改版不弃档:缺新域按默认补齐,既有值保留) -func _normalize(data: Dictionary) -> Dictionary: +func _normalize(data: Dictionary) -> Dictionary[String, Variant]: var merged := _default_data() for key in data: merged[key] = data[key] diff --git a/game/core/status_container.gd b/game/core/status_container.gd index eb4c210c..718d54a7 100644 --- a/game/core/status_container.gd +++ b/game/core/status_container.gd @@ -8,12 +8,12 @@ class_name StatusContainer extends RefCounted -var db +var db: ConfigDb var _open := false -var _instances: Array = [] # 插入序;元素 = {effect_id, layers, remaining, source_class, origin_cell, round_index, snap_m, snap_unit, snap_display} +var _instances: Array[Dictionary] = [] # 插入序;元素 = {effect_id, layers, remaining, source_class, origin_cell, round_index, snap_m, snap_unit, snap_display} -func _init(db_ref) -> void: +func _init(db_ref: ConfigDb) -> void: db = db_ref @@ -84,7 +84,7 @@ func _new_instance(effect_id: String, layers: int, dur: int, source: Dictionary, # 只读投影(插入序稳定枚举;六归因字段 + display_name + 授予时快照) func query_active(side: String) -> Array: - var out: Array = [] + var out: Array[Dictionary] = [] for inst in _instances: var row: Dictionary = db.status_effect_row(inst.effect_id) if row.is_empty(): @@ -119,7 +119,7 @@ func decay_round() -> int: if not _open: return 0 # EC13 域闭兜底读法——容器恒空,无独立分支不诊断 var k := 0 - var survivors: Array = [] + var survivors: Array[Dictionary] = [] for inst in _instances: inst.remaining -= 1 if inst.remaining <= 0: diff --git a/game/core/unit_container.gd b/game/core/unit_container.gd index 1ad625c0..6173892c 100644 --- a/game/core/unit_container.gd +++ b/game/core/unit_container.gd @@ -20,18 +20,18 @@ extends RefCounted # 消费方 = 伤害控制器(怪死 → 其未结单据作废〔死亡即不动手〕;主角死 → 兑付终止旗)。 signal unit_died(u: Dictionary) -var db +var db: ConfigDb # 单位容器私有(E3 封装收口 2026-09-13):hero/enemies 原始数组不再外露——读取经 hero_unit()/ # all_enemies() 投影面(死亡残位查询包含在内),写入只经 apply_damage/heal/set_pending_action/commit_action/ # tick_cooldowns/spawn/despawn。 # 句柄语义不变:投影返回的 Dictionary 引用即单位句柄(同 query_alive 先例)。 -var _hero: Dictionary = {} # {hp, max_hp, atk, is_hero: true} -var _enemies: Array = [] # 行主序生成序;元素 = 单位 Dictionary +var _hero: Dictionary[String, Variant] = {} # {hp, max_hp, atk, is_hero: true} +var _enemies: Array[Dictionary] = [] # 行主序生成序;元素 = 单位 Dictionary var _spawned := false var _despawned := false -func _init(db_ref) -> void: +func _init(db_ref: ConfigDb) -> void: db = db_ref @@ -69,7 +69,7 @@ func spawn(level_index: int, node_depth: int, hero_hp: int, unit_count_override: for i in range(count): var eff_row_atk: int = enemy_atk_override if enemy_atk_override >= 0 else int(row.atk) # 实例池快照(proposal §2.2:开战把模板快照一份,冷却全零——与"生成拿到当时的表值快照"同一条快照纪律) - var pool_snap: Array = [] + var pool_snap: Array[Dictionary] = [] for entry in row.get("pool", []): pool_snap.append({ "skill_id": String(entry.get("skill_id", "")), @@ -103,7 +103,7 @@ func query_alive(side: String) -> Array: return [] if side == "hero": return [] if (_hero.is_empty() or not _hero.alive) else [_hero] - var out: Array = [] + var out: Array[Dictionary] = [] for u in _enemies: if u.alive: out.append(u) @@ -118,7 +118,7 @@ func rollable_skills(u: Dictionary) -> Array: if u.is_empty() or _despawned or u.get("is_hero", false): _diag("rollable_skills 失效句柄") return [] - var out: Array = [] + var out: Array[Dictionary] = [] for e in u.pool: if int(e.cooldown_left) <= 0: out.append({"skill_id": String(e.skill_id), "weight": int(e.weight)}) @@ -130,7 +130,7 @@ func special_skills(u: Dictionary) -> Array: if u.is_empty() or _despawned or u.get("is_hero", false): _diag("special_skills 失效句柄") return [] - var out: Array = [] + var out: Array[Dictionary] = [] for e in u.pool: var srow: Dictionary = db.skill_row(String(e.skill_id)) if not srow.is_empty() and String(srow.type) != "basic": diff --git a/game/data/schemas/action_economy_table.gd b/game/data/schemas/action_economy_table.gd index 21d1d431..6c1c8003 100644 --- a/game/data/schemas/action_economy_table.gd +++ b/game/data/schemas/action_economy_table.gd @@ -16,7 +16,7 @@ extends Resource func validate() -> Array: - var errs: Array = [] + var errs: Array[Dictionary] = [] if ap_per_round < 1 or ap_per_round > 32: errs.append({"category": "domain", "message": "ap_per_round 越域 [1,32]: %d" % ap_per_round}) if dig_ap_cost < 1 or dig_ap_cost > 8: diff --git a/game/data/schemas/adventure_table.gd b/game/data/schemas/adventure_table.gd index 7d71b3b5..a2a7db95 100644 --- a/game/data/schemas/adventure_table.gd +++ b/game/data/schemas/adventure_table.gd @@ -15,7 +15,7 @@ extends Resource func validate() -> Array: - var errs: Array = [] + var errs: Array[Dictionary] = [] if level_clear_hp_bonus < 0 or level_clear_hp_bonus > 999: errs.append({"category": "domain", "message": "level_clear_hp_bonus 越域 [0,999]: %d" % level_clear_hp_bonus}) if keystone_per_level < 0 or keystone_per_level > 999: diff --git a/game/data/schemas/board_gen_table.gd b/game/data/schemas/board_gen_table.gd index 52d66824..ad5f4b40 100644 --- a/game/data/schemas/board_gen_table.gd +++ b/game/data/schemas/board_gen_table.gd @@ -6,7 +6,7 @@ class_name BoardGenTable extends Resource -@export var rows: Array = [] # Array[Dictionary] +@export var rows: Array[Dictionary] = [] # Array[Dictionary] const SOLVER_RULES := ["single", "single_subset"] const COST_BUDGET := 16384 # F2c provisional 量级护栏(禁墙钟逃生) const TARGET_ABS_FLOOR := 0.85 # 战斗结算 修订——target 域下限(P1 绝对锚) @@ -14,7 +14,7 @@ const BOARD_TYPE_VOCABULARY := ["dungeon", "underdark", "deep_underdark"] # func validate() -> Array: - var errs: Array = [] + var errs: Array[Dictionary] = [] if rows.is_empty(): errs.append({"category": "empty_table", "message": "BoardGenTable 为空"}) return errs diff --git a/game/data/schemas/difficulty_table.gd b/game/data/schemas/difficulty_table.gd index 8e26cb25..d7055443 100644 --- a/game/data/schemas/difficulty_table.gd +++ b/game/data/schemas/difficulty_table.gd @@ -6,14 +6,14 @@ class_name DifficultyTable extends Resource -@export var rows: Array = [] # Array[Dictionary]:{level_index, node_depth, hp_mult, atk_mult} +@export var rows: Array[Dictionary] = [] # Array[Dictionary]:{level_index, node_depth, hp_mult, atk_mult} const MULT_MIN := 0.1 const MULT_MAX := 10.0 func validate() -> Array: - var errs: Array = [] + var errs: Array[Dictionary] = [] var seen := {} for row in rows: var L: int = int(row.get("level_index", 0)) diff --git a/game/data/schemas/enemy_table.gd b/game/data/schemas/enemy_table.gd index be9b2ba9..781493fc 100644 --- a/game/data/schemas/enemy_table.gd +++ b/game/data/schemas/enemy_table.gd @@ -9,7 +9,7 @@ class_name EnemyTable extends Resource -@export var rows: Array = [] # Array[Dictionary] +@export var rows: Array[Dictionary] = [] # Array[Dictionary] # 护甲类型封闭枚举(攻击类型 × 护甲克制批——克制矩阵本体在 SettlementTable; # 2026-09-15 命名统一批:位置键 {none, a, b} → 语义键 {light, ward, heavy} = 轻甲 / 魔法护甲 / 重甲) @@ -17,7 +17,7 @@ const ARMOR_TYPES := ["light", "ward", "heavy"] func validate() -> Array: - var errs: Array = [] + var errs: Array[Dictionary] = [] if rows.is_empty(): errs.append({"category": "empty_table", "message": "EnemyTable 为空"}) return errs @@ -108,14 +108,14 @@ func validate() -> Array: # R1:进度键 floor + 行集恰一敌种(实体键无歧义,悬空致命由调用方处理) func resolve_rowset(L: int, D: int) -> Dictionary: - var best: Dictionary = {} + var best: Dictionary[String, Variant] = {} var best_l := -1 var best_d := -1 for row in rows: var rl: int = int(row.get("level_index", 0)) var rd: int = int(row.get("node_depth", 0)) if rl <= L and rd <= D and (rl > best_l or (rl == best_l and rd > best_d)): - best = row + best.assign(row) best_l = rl best_d = rd return best diff --git a/game/data/schemas/hero_table.gd b/game/data/schemas/hero_table.gd index e462485b..0c953498 100644 --- a/game/data/schemas/hero_table.gd +++ b/game/data/schemas/hero_table.gd @@ -14,7 +14,7 @@ extends Resource func validate() -> Array: - var errs: Array = [] + var errs: Array[Dictionary] = [] if max_hp < 1 or max_hp > 999: errs.append({"category": "domain", "message": "max_hp 越域 [1,999]: %d" % max_hp}) if atk < 1 or atk > 999: diff --git a/game/data/schemas/level_table.gd b/game/data/schemas/level_table.gd index 5ac5a397..64619156 100644 --- a/game/data/schemas/level_table.gd +++ b/game/data/schemas/level_table.gd @@ -15,13 +15,13 @@ class_name LevelTable extends Resource -@export var rows: Array = [] # Array[Dictionary] +@export var rows: Array[Dictionary] = [] # Array[Dictionary] const NODE_TYPES := ["battle", "reward", "rest", "boss", "shop"] # 商店房批 2026-09-21 四→五类(关卡节点地图 v1.1) func validate() -> Array: - var errs: Array = [] + var errs: Array[Dictionary] = [] if rows.is_empty(): errs.append({"category": "empty_table", "message": "LevelTable 为空"}) return errs @@ -40,7 +40,7 @@ func validate() -> Array: errs.append({"category": "domain", "message": "level %d rest_heal_pct 越域 [0,100]" % L}) # 模板池(关卡节点图生成 v0.4——M-3 迭代 5 T5):row.templates 非空 = 池形态,池内全模板加载期校验 # (违规致命——不只抽中的那张);空 = 旧单图形态(row.nodes 直读,向后兼容零迁移)。 - var node_lists: Array = [] # [ [上下文标签, nodes 数组], ... ] + var node_lists: Array[Array] = [] # [ [上下文标签, nodes 数组], ... ] var templates: Array = row.get("templates", []) if templates.is_empty(): node_lists.append(["", row.get("nodes", [])]) @@ -59,7 +59,7 @@ func validate() -> Array: # 单节点链校验体(validate 抽出——row.nodes 与池内每张模板同跑一套;ctx = 消息上下文标签) func _validate_level_nodes(L: int, ctx: String, nodes: Array) -> Array: - var errs: Array = [] + var errs: Array[Dictionary] = [] var tag: String = "" if ctx.is_empty() else "〔%s〕" % ctx if nodes.is_empty(): errs.append({"category": "domain", "message": "level %d%s 节点链为空" % [L, tag]}) @@ -102,9 +102,9 @@ func _validate_level_nodes(L: int, ctx: String, nodes: Array) -> Array: # 图合法性核心(返回错误列表):id 解析(图=node_depth / 单链=数组下标)→ 出边表 → # 唯一性/前进方向/入口唯一/Boss 终点/双向可达六检。参考 关卡节点地图 v1.0 分支节点图规则。 func _validate_graph(L: int, nodes: Array, is_graph: bool, tag: String = "") -> Array: - var errs: Array = [] - var ids: Array = [] # 每节点 id(下标对齐) - var nexts: Array = [] # 每节点出边 id 数组 + var errs: Array[Dictionary] = [] + var ids: Array[int] = [] # 每节点 id(下标对齐) + var nexts: Array[Array] = [] # 每节点出边 id 数组 var id_to_idx := {} for i in nodes.size(): var node: Dictionary = nodes[i] @@ -116,7 +116,7 @@ func _validate_graph(L: int, nodes: Array, is_graph: bool, tag: String = "") -> if id_to_idx.has(nid): errs.append({"category": "dup_key", "message": "level %d%s 节点编号重复: %d(关卡内唯一定位地址)" % [L, tag, nid]}) id_to_idx[nid] = i - var nx: Array = [] + var nx: Array[int] = [] if node.has("next"): for v in node.get("next", []): nx.append(int(v)) @@ -135,7 +135,7 @@ func _validate_graph(L: int, nodes: Array, is_graph: bool, tag: String = "") -> for i in nodes.size(): for tid in nexts[i]: has_inbound[tid] = true - var entries: Array = [] + var entries: Array[int] = [] for i in nodes.size(): if not has_inbound.has(ids[i]): entries.append(i) diff --git a/game/data/schemas/meta_table.gd b/game/data/schemas/meta_table.gd index 5afd4483..4c32566a 100644 --- a/game/data/schemas/meta_table.gd +++ b/game/data/schemas/meta_table.gd @@ -16,10 +16,10 @@ class_name MetaTable extends Resource -@export var forge_products: Array = [] # Array[Dictionary] 键 attr -@export var boss_keystone: Array = [] # Array[Dictionary] 键 level_index -@export var workshop_items: Array = [] # Array[Dictionary] 键 item_id -@export var conversion: Array = [] # Array[Dictionary] 键 attr +@export var forge_products: Array[Dictionary] = [] # Array[Dictionary] 键 attr +@export var boss_keystone: Array[Dictionary] = [] # Array[Dictionary] 键 level_index +@export var workshop_items: Array[Dictionary] = [] # Array[Dictionary] 键 item_id +@export var conversion: Array[Dictionary] = [] # Array[Dictionary] 键 attr const FORGE_ATTRS := ["max_hp", "atk", "armor_class"] const WORKSHOP_ITEM_IDS := ["probe_dust", "sapper_order", "loot_compass", "nest_pendulum", "catacomb_scroll", "blast_kit"] @@ -30,7 +30,7 @@ const WORKSHOP_CHANNELS := ["total_clears"] func validate() -> Array: - var errs: Array = [] + var errs: Array[Dictionary] = [] # 行族空护栏(四族皆为 ConfigDB 消费面——缺族即致命) for family in ["forge_products", "boss_keystone", "workshop_items", "conversion"]: if get(family).is_empty(): diff --git a/game/data/schemas/reward_table.gd b/game/data/schemas/reward_table.gd index 6c887495..8ba29941 100644 --- a/game/data/schemas/reward_table.gd +++ b/game/data/schemas/reward_table.gd @@ -10,7 +10,7 @@ class_name RewardTable extends Resource -@export var rows: Array = [] # Array[Dictionary] +@export var rows: Array[Dictionary] = [] # Array[Dictionary] const CELL_TYPES := ["attack", "defense", "heal", "blast", "weaken", "pierce", "magic", "action", "gp"] # 九型封闭(格面资源九型批 2026-09-20 八→九,词表 v1.1)——清单外加载拒绝 const POLARITIES := ["positive", "negative"] @@ -19,7 +19,7 @@ const CELL_TYPE_KEYS := ["attack", "defense", "heal", "blast", "weaken", "pierce func validate() -> Array: - var errs: Array = [] + var errs: Array[Dictionary] = [] if rows.is_empty(): errs.append({"category": "empty_table", "message": "RewardTable 为空"}) return errs @@ -106,7 +106,7 @@ func validate() -> Array: func rows_by_pool(pool_tag: String) -> Array: - var out: Array = [] + var out: Array[Dictionary] = [] for row in rows: if row.get("pool_tag", "") == pool_tag: out.append(row) diff --git a/game/data/schemas/settlement_table.gd b/game/data/schemas/settlement_table.gd index b597056f..aa02e936 100644 --- a/game/data/schemas/settlement_table.gd +++ b/game/data/schemas/settlement_table.gd @@ -9,8 +9,8 @@ extends Resource @export var equivalence_ref_damage: int = 12 # [1,999] knob——当量参考敞口 D_ref @export var p_perfect: int = 200 # {100,200} percent——完美排雷第二份兑付触发(载体域) @export var segment_order: PackedStringArray = [] # 结构冻结——恒等拍板段序校验违例致命 -@export var source_label_map: Dictionary = {} # 结构冻结——source_class→文案键 -@export var effect_pool_map: Dictionary = {} # 结构冻结——effect_id→pool(悬空加载致命) +@export var source_label_map: Dictionary[String, Variant] = {} # 结构冻结——source_class→文案键 +@export var effect_pool_map: Dictionary[String, Variant] = {} # 结构冻结——effect_id→pool(悬空加载致命) @export var pool_clamp_lo: int = -100 # 结构冻结 @export var pool_clamp_hi: int = 100 # 结构冻结 @export var round_direction: String = "floor" # 结构冻结——单一取整规则 @@ -19,7 +19,7 @@ extends Resource # 【两条抽象分离,勿焊死】攻击类型 = 伤害的属性轴,只决定查 armor_effectiveness 哪一行,定义里不含任何棋盘来源; # 充能 = 按攻击类型分桶的附加伤害储备,"谁往桶里放东西"属**奖励的定义**(开格/标雷只是奖励触发源,奖励内容可改)。 # 原 damage_a_per_cell / damage_a_cap / damage_b_per_flag 与 charge_grants 充能奖励定义均退役(2026-09-19 充能退役批——攻击模型回归单分量)。 -@export var armor_effectiveness: Dictionary = {} # 克制修正矩阵(加法点数 delta):{攻击类型 {normal|pierce|magic}: {护甲 {light|ward|heavy}: 点数 [-3,+3]}} +@export var armor_effectiveness: Dictionary[String, Variant] = {} # 克制修正矩阵(加法点数 delta):{攻击类型 {normal|pierce|magic}: {护甲 {light|ward|heavy}: 点数 [-3,+3]}} # ---- 护甲等级掷点批(2026-09-16 用户拍板,数字即规范——registry settlement_table.ac_roll/ac_discount_tiers 同批定稿)---- # 判定式:掷 1d20,掷点 ≥ 防守方 AC + 攻击加成 → 全额;低掷按缺口(AC−掷点)查档打折,无 miss、无零收益档; # nat 最大面(crit_roll)= 暴击:该次基础攻击分量 ×2 且恒全额;任何伤害落地全局下限 damage_floor(≥1)—— @@ -28,8 +28,8 @@ extends Resource # 微调旋钮 = 档位边界(roll_tier_bounds)与档位值(roll_tier_discounts),不动 AC 值(armor_class 归单位表)。 @export var roll_faces: int = 20 # [2,1000] knob——掷点骰面(d20) @export var attack_bonus: int = 0 # [0,999] 结构位——攻击者掷点加成,切片恒 0(元进度/武器附魔未来投值) -@export var roll_tier_bounds: Array = [] # 缺口档边界升序:缺口 ≥ bounds[i] 落入第 i 档([3,7] = 缺口1-3/4-7/8+ 三档) -@export var roll_tier_discounts: Array = [] # 档位值 percent 降序(与 bounds 同长;[75,50,25] = ×0.75/×0.5/×0.25) +@export var roll_tier_bounds: Array[int] = [] # 缺口档边界升序:缺口 ≥ bounds[i] 落入第 i 档([3,7] = 缺口1-3/4-7/8+ 三档) +@export var roll_tier_discounts: Array[int] = [] # 档位值 percent 降序(与 bounds 同长;[75,50,25] = ×0.75/×0.5/×0.25) @export var crit_roll: int = 20 # [1,roll_faces] knob——nat 最大面 = 暴击触发掷点(恒全额) @export var crit_multiplier: int = 200 # [100,999] percent knob——暴击倍率(200 = ×2,只乘该次基础攻击分量) @export var damage_floor: int = 1 # [1,999] knob——任何伤害落地全局下限·全来源("被减伤归零 v=0"行语义随批退役) @@ -43,7 +43,7 @@ const P_PERFECT_DOMAIN := [100, 200] func validate() -> Array: - var errs: Array = [] + var errs: Array[Dictionary] = [] if equivalence_ref_damage < 1 or equivalence_ref_damage > 999: errs.append({"category": "domain", "message": "equivalence_ref_damage 越域 [1,999]: %d" % equivalence_ref_damage}) if not P_PERFECT_DOMAIN.has(p_perfect): diff --git a/game/data/schemas/shop_table.gd b/game/data/schemas/shop_table.gd index 43483bbf..b76afe85 100644 --- a/game/data/schemas/shop_table.gd +++ b/game/data/schemas/shop_table.gd @@ -13,17 +13,17 @@ class_name ShopTable extends Resource -@export var gp_drops: Array = [] # Array[Dictionary] 键 tier -@export var level_gp_bonus: Array = [] # Array[Dictionary] 键 level_index -@export var products: Array = [] # Array[Dictionary] 键 product_id -@export var price_level_bonus: Array = [] # Array[Dictionary] 键 level_index +@export var gp_drops: Array[Dictionary] = [] # Array[Dictionary] 键 tier +@export var level_gp_bonus: Array[Dictionary] = [] # Array[Dictionary] 键 level_index +@export var products: Array[Dictionary] = [] # Array[Dictionary] 键 product_id +@export var price_level_bonus: Array[Dictionary] = [] # Array[Dictionary] 键 level_index const GP_TIERS := ["normal", "elite", "boss"] const PRODUCT_ATTRS := ["atk", "max_hp", "armor_class"] func validate() -> Array: - var errs: Array = [] + var errs: Array[Dictionary] = [] # 行族空护栏(四轴皆为 ConfigDB 消费面——缺族即致命) for family in ["gp_drops", "level_gp_bonus", "products", "price_level_bonus"]: if get(family).is_empty(): diff --git a/game/data/schemas/skill_table.gd b/game/data/schemas/skill_table.gd index e654f2f3..42663ee8 100644 --- a/game/data/schemas/skill_table.gd +++ b/game/data/schemas/skill_table.gd @@ -8,7 +8,7 @@ class_name SkillTable extends Resource -@export var rows: Array = [] # Array[Dictionary] +@export var rows: Array[Dictionary] = [] # Array[Dictionary] # 保底 M(provisional 归 难度曲线与Boss):连续 M 拍执行的都是普通攻击 → 下拍必出特殊技 # (特殊技内按权重、不受冷却限制——proposal §2.1 两道闸之二)。全局单旋钮(不分敌种)。 @export var pity_threshold: int = 4 @@ -20,7 +20,7 @@ const RIDER_MULT_MAX := 1.0 # rider_mult 域 (0, 1]( func validate() -> Array: - var errs: Array = [] + var errs: Array[Dictionary] = [] if rows.is_empty(): errs.append({"category": "empty_table", "message": "SkillTable 为空"}) return errs diff --git a/game/data/schemas/status_effect_table.gd b/game/data/schemas/status_effect_table.gd index 2a964102..e939afea 100644 --- a/game/data/schemas/status_effect_table.gd +++ b/game/data/schemas/status_effect_table.gd @@ -6,7 +6,7 @@ class_name StatusEffectTable extends Resource -@export var rows: Array = [] # Array[Dictionary] +@export var rows: Array[Dictionary] = [] # Array[Dictionary] const TARGET_SIDES := ["hero", "enemy"] const UNITS := ["percent", "flat", "ac"] # 2026-09-16 护甲等级掷点批增 ac——AC 阈值轴效果(ac_up),非池百分比非定点值 @@ -14,7 +14,7 @@ const STACK_POLICIES := ["stack", "refresh", "independent"] func validate() -> Array: - var errs: Array = [] + var errs: Array[Dictionary] = [] if rows.is_empty(): errs.append({"category": "empty_table", "message": "StatusEffectTable 为空"}) return errs diff --git a/game/data/schemas/variation_table.gd b/game/data/schemas/variation_table.gd index 4a8cb5b5..ce5199a3 100644 --- a/game/data/schemas/variation_table.gd +++ b/game/data/schemas/variation_table.gd @@ -11,7 +11,7 @@ class_name VariationTable extends Resource -@export var rows: Array = [] # Array[Dictionary] +@export var rows: Array[Dictionary] = [] # Array[Dictionary] # 布置参数(表头字段;数量公式 = round(候选池格数 × percent_of_cells / 100) + (关卡序号 − 1) × per_level_bonus, # 连通片生长、单片 ≤ pack_max——2026-09-19 用户拍板:图规模百分比 × 关卡递增,全连通、单片不超 4; # 2026-09-21 用户拍板基数修正:百分比基数 = 候选池(安全格 − 初始展开区,即实际可挖格)而非总格数) @@ -27,7 +27,7 @@ const PLACEMENTS := ["closed_only", "any"] # 布置约束 func validate() -> Array: # 空清单是合法状态(地形变异 P0)——零行即零变体格,配置加载零错误、零警告 - var errs: Array = [] + var errs: Array[Dictionary] = [] var seen := {} for row in rows: var vid: String = row.get("variant_id", "") diff --git a/game/presentation/battle_narrator.gd b/game/presentation/battle_narrator.gd index 7ad51825..b29d9945 100644 --- a/game/presentation/battle_narrator.gd +++ b/game/presentation/battle_narrator.gd @@ -28,7 +28,7 @@ static func shop_line(gp: int) -> String: # 选路口行(零自动推进停点——战斗胜利/兑付确认后出现) static func route_line(candidates: Array, runner) -> String: - var names: Array = [] + var names: Array[String] = [] for cand in candidates: names.append("节点 %d" % runner.node_id_of(cand)) return "[color=#e0b860]── 岔路口:可选下一跳 %s ──[/color]" % " / ".join(names) @@ -105,7 +105,7 @@ static func keystone_settle_text(detail: Dictionary, name_lookup: Dictionary = { var line := "钥石入账:" + " · ".join(parts) var unlocks: Array = detail.get("new_unlocks", []) if not unlocks.is_empty(): - var names: Array = [] + var names: Array[String] = [] for iid in unlocks: names.append(String(name_lookup.get(String(iid), String(iid)))) line += "\n工坊新解锁:" + "、".join(names) diff --git a/game/presentation/debug_session.gd b/game/presentation/debug_session.gd index 35cf12c8..d1c34fbf 100644 --- a/game/presentation/debug_session.gd +++ b/game/presentation/debug_session.gd @@ -20,7 +20,7 @@ var _hero_override: Callable # 组合根生效值供给(→ {atk, m var _seed_value: Callable # 组合根种子读取(LineEdit) var _level_mode := false -var _level_battles: Array = [] +var _level_battles: Array[int] = [] var _level_idx := 0 var _carry_hp := 0 var settlement = null # 当前战斗编排器(组合根在 battle_created 接线、battle_ready 接手) diff --git a/game/presentation/hud_presenter.gd b/game/presentation/hud_presenter.gd index 09088550..0b67bd93 100644 --- a/game/presentation/hud_presenter.gd +++ b/game/presentation/hud_presenter.gd @@ -41,7 +41,7 @@ static func _refresh_hero(stage: BattleStageView, info: HeroInfoPanelView, s: Di var atk: int = int(hero.atk) # 修正 = attack_up 池有效值(hero_offense);来源角标 = 效果 display_name(快照 hero_effects 投影) var mod_total := 0 - var sources: Array = [] + var sources: Array[String] = [] for eff in s.hero_effects: if String(eff.effect_id) == "attack_up": mod_total += int(eff.effective_value) @@ -111,7 +111,7 @@ static func outcome_text(outcome: Dictionary) -> String: # ---- 调整板批量模拟报告装配(文案归 presenter——视图只 set_text;code-review 2026-09-12 批) ---- static func tune_sim_report(n: int, atk_pct: int, hp_pct: int, wins: int, dmg_all: Array, hp_left_win: Array, hp_boss: Array, rounds_all: Array, death_nodes: Dictionary, base_hp: int) -> String: - var lines: Array = [] + var lines: Array[String] = [] lines.append("[b]模拟 N=%d(atk+%d%% / hp+%d%%)[/b]" % [n, atk_pct, hp_pct]) lines.append("通关率 [color=#80d080]%.0f%%[/color](%d/%d)" % [100.0 * float(wins) / float(maxi(1, n)), wins, n]) lines.append("整关承伤:均 %.1f · p90 %.0f(基础 HP %d)" % [_mean(dmg_all), _p90(dmg_all), base_hp]) @@ -121,7 +121,7 @@ static func tune_sim_report(n: int, atk_pct: int, hp_pct: int, wins: int, dmg_al if death_nodes.is_empty(): lines.append("败北节点:—") else: - var parts: Array = [] + var parts: Array[String] = [] for k in death_nodes.keys(): parts.append("%s×%d" % [k, death_nodes[k]]) lines.append("败北节点:%s(0-3=战斗序,4=Boss)" % " ".join(parts)) diff --git a/game/presentation/main.gd b/game/presentation/main.gd index 32392a7a..74445ebb 100644 --- a/game/presentation/main.gd +++ b/game/presentation/main.gd @@ -321,9 +321,9 @@ func _on_adventure_finished(summary: Dictionary) -> void: stage.settle_hero_idle() # 主角态回 idle(迭代 6 T3 三态收尾) # 存档入账(元进度实现批):settle = Boss 两档入账 + 工坊解锁 + 摘要入档 + 写盘(唯一写档点不变—— # 调试两层不经过本处理器,天然不写档不污染生涯数据)。 - var detail: Dictionary = {} + var detail: Dictionary[String, Variant] = {} if meta != null: - detail = meta.settle_adventure(summary) + detail.assign(meta.settle_adventure(summary)) var text := Narrator.adventure_summary_text(summary) if not detail.is_empty(): text += "\n" + Narrator.keystone_settle_text(detail, _item_name_lookup()) @@ -671,7 +671,7 @@ func _on_camp_closed() -> void: # 营地快照投影(纯读——锻造三行/工坊六行/余额/最近冒险;拼句归 CampOverlay,账面归 MetaProgression) func _camp_data() -> Dictionary: - var forge_rows: Array = [] + var forge_rows: Array[Dictionary] = [] if meta != null: for attr in MetaTable.FORGE_ATTRS: var row: Dictionary = db.meta_forge_row(attr) diff --git a/game/presentation/modal_stack.gd b/game/presentation/modal_stack.gd index 4dbdb370..8d54fe06 100644 --- a/game/presentation/modal_stack.gd +++ b/game/presentation/modal_stack.gd @@ -6,7 +6,7 @@ # 纯逻辑零节点构建——组合根持有本类并喂入 Control;不持久化核心状态。 extends RefCounted -var _list: Array = [] # 登记序 = z 遮挡序(低 → 高) +var _list: Array[Control] = [] # 登记序 = z 遮挡序(低 → 高) var _occluded := {} # modal → 被其隐藏的上方层(关闭恢复) @@ -15,7 +15,7 @@ func register(m: Control) -> void: func open(m: Control) -> void: - var hidden: Array = [] + var hidden: Array[Control] = [] var idx := _list.find(m) for i in range(idx + 1, _list.size()): var higher: Control = _list[i] diff --git a/game/presentation/playtest_logger.gd b/game/presentation/playtest_logger.gd index 85d0ae94..9e312642 100644 --- a/game/presentation/playtest_logger.gd +++ b/game/presentation/playtest_logger.gd @@ -17,8 +17,8 @@ const RING_SIZE := 200 var _file: FileAccess = null var _path := "" var _seed := 0 -var _recent_steps: Array = [] # 环形缓冲:最近结算行 -var _recent_actions: Array = [] # 环形缓冲:最近玩家动作 +var _recent_steps: Array[Dictionary] = [] # 环形缓冲:最近结算行 +var _recent_actions: Array[Dictionary] = [] # 环形缓冲:最近玩家动作 var _snap_count := 0 var ap_per_round := 8 # 组合根注入(AP 消耗口径分母——行动经济 无推送信号) var _ux_inputs := 0 # 本结算轮原始输入动作数(log_action 计数,快照后归零) diff --git a/game/presentation/tune_sim_controller.gd b/game/presentation/tune_sim_controller.gd index 4206109f..83267881 100644 --- a/game/presentation/tune_sim_controller.gd +++ b/game/presentation/tune_sim_controller.gd @@ -30,10 +30,10 @@ func run(n: int) -> void: panel.set_sim_running(true) panel.set_sim_progress("模拟中:0/%d …" % n) var wins := 0 - var dmg_all: Array = [] - var hp_left_win: Array = [] - var hp_boss: Array = [] - var rounds_all: Array = [] + var dmg_all: Array[float] = [] + var hp_left_win: Array[float] = [] + var hp_boss: Array[float] = [] + var rounds_all: Array[int] = [] var death_nodes := {} for i in range(n): var st = LevelAutoplay.run_level(db, SEED_BASE + i, 1, panel.atk_pct(), panel.hp_pct(), false, logger) diff --git a/game/presentation/views/battle_end_overlay.gd b/game/presentation/views/battle_end_overlay.gd index 3f81fe26..884c6b58 100644 --- a/game/presentation/views/battle_end_overlay.gd +++ b/game/presentation/views/battle_end_overlay.gd @@ -137,7 +137,7 @@ func _play_flag_recall(count: int) -> void: # ---- 演出密度终稿(样张 v2 冻结批 T3——程序化 tween,确定性散布,零新帧资产) ---- -var _crest_bricks: Array = [] # 纹章碎砖驻留面(close 时回收) +var _crest_bricks: Array[ColorRect] = [] # 纹章碎砖驻留面(close 时回收) var _fx_crest_shards := 0 var _fx_dust_motes := 0 var _fx_flag_dots := 0 diff --git a/game/presentation/views/battle_log_view.gd b/game/presentation/views/battle_log_view.gd index 5da01675..f83f5e09 100644 --- a/game/presentation/views/battle_log_view.gd +++ b/game/presentation/views/battle_log_view.gd @@ -27,7 +27,7 @@ var _log: RichTextLabel var _summary: Label var _hint: Label var _mode := "dig" # dig = 收起摘要 / settle = 实时流(模式归组合根驱动) -var _round_rows: Array = [] # 本结算轮行缓冲(上轮摘要构建源) +var _round_rows: Array[Dictionary] = [] # 本结算轮行缓冲(上轮摘要构建源) var _pending_agg := {} # 聚合计数行 pending(type+batch_key → {row, count}) @@ -85,9 +85,9 @@ func finish_settlement_round() -> void: _flush_pending_agg() if _round_rows.is_empty(): return - var parts: Array = [] + var parts: Array[String] = [] for bb in _round_rows: - parts.append(_strip_bb(String(bb))) + parts.append(_strip_bb(str(bb))) var text := "上轮: " + " | ".join(parts) if text.length() > 190: text = text.substr(0, 190) + "…" diff --git a/game/presentation/views/battle_stage_view.gd b/game/presentation/views/battle_stage_view.gd index 839df109..e1108690 100644 --- a/game/presentation/views/battle_stage_view.gd +++ b/game/presentation/views/battle_stage_view.gd @@ -31,7 +31,7 @@ var round_label: Label var stage_center: Label var enemy_box: Control # 站桩壳层伴随件容器(T3 语义改写:HBoxContainer → Control) var log_view: BattleLogView -var _cards: Array = [] # StandeeBody(世界本体,敌) +var _cards: Array[Node2D] = [] # StandeeBody(世界本体,敌) var _row: HBoxContainer # 文本半区行(stage_center 载体 + 世界布局基准) var _companion_layer: Control # 壳层伴随件层(主角 slot_row 宿主;敌伴随件宿主 = enemy_box) var _svp_container: SubViewportContainer diff --git a/game/presentation/views/board_cell_unit.gd b/game/presentation/views/board_cell_unit.gd index 73b94543..7ff34e51 100644 --- a/game/presentation/views/board_cell_unit.gd +++ b/game/presentation/views/board_cell_unit.gd @@ -17,11 +17,11 @@ var edge := 46.0: # 格边长(BoardView.set_cell_area 单点 var bg_sb: StyleBoxFlat = null # 格底 StyleBox(BoardView 每次 paint 重建;呼吸微光就地改边框) # ── 接触带微光绘制面(2026-09-26 批:可挖域微光自"墙格整框"改"英雄格周界空间侧"——art-bible §3.2 v2.8; # 仅英雄格单元承载,BoardView.refresh 按可挖域写边/角码、_process 逐拍更新呼吸色)── -var contact_bands: Array = [] # 正交接触边码 0=N/1=S/2=W/3=E(该侧整条边) -var contact_corners: Array = [] # 斜向共享角码 0=NW/1=NE/2=SW/3=SE(角点+两侧各半条边) +var contact_bands: Array[int] = [] # 正交接触边码 0=N/1=S/2=W/3=E(该侧整条边) +var contact_corners: Array[int] = [] # 斜向共享角码 0=NW/1=NE/2=SW/3=SE(角点+两侧各半条边) var contact_col := Color(0, 0, 0, 0) # 当前呼吸色(alpha 0 = 不画) var plate := false # 数字色牌开关(BoardView paint 按已开格 glyph 写入——原则二) -var outline_sides: Array = [] # 墙格地面朝向描边码 0=N/1=S/2=W/3=E(轮廓加强批——程序侧结构件) +var outline_sides: Array[int] = [] # 墙格地面朝向描边码 0=N/1=S/2=W/3=E(轮廓加强批——程序侧结构件) # ── 高墙感 D 投影档(2026-09-28 挑档落码——研究件四变体用户裁 D=C+地面投影,ITB 同款高度线索)── # 南立面 = 墙格南缘内侧「口沿高光线 + 双段暗带」(邻地面格才画,墙群内聚);地面投影 = 北邻墙格 # 在本已开格北缘投渐隐暗带。参数按研究件 64px 拼版实测比例换算(立面双段 0.16/0.25 格边、投影带 diff --git a/game/presentation/views/board_fx_view.gd b/game/presentation/views/board_fx_view.gd index f7a899b0..c852c5b5 100644 --- a/game/presentation/views/board_fx_view.gd +++ b/game/presentation/views/board_fx_view.gd @@ -127,7 +127,7 @@ const SHOVEL_FRAME_PX := 32.0 # 铲帧画布边长(缩放比与英雄帧 const SHOVEL_FRAME_S := 0.08 # ~80ms/帧(f0→f1→f2 共 ~240ms 即收) const SHOVEL_GRIP := Vector2(18, 12) # 握把锚点(素材侧锁定的画布坐标——英雄持握手位对齐点) -var _shovel_texs: Array = [] # 惰性装载缓存(素材缺位 = 空表静默回退——素材不入 git) +var _shovel_texs: Array[Texture2D] = [] # 惰性装载缓存(素材缺位 = 空表静默回退——素材不入 git) # 挖掘挥铲:hand = 英雄持握手位(BoardView.hero_hand_point 出口,fx 与棋盘同层同系)—— diff --git a/game/presentation/views/board_view.gd b/game/presentation/views/board_view.gd index 976b5b52..f69ad555 100644 --- a/game/presentation/views/board_view.gd +++ b/game/presentation/views/board_view.gd @@ -102,7 +102,7 @@ var _diggable := {} # 可挖域(8 向相邻未开格)——呼吸微 var _breath_t := 0.0 var _contact_unit: Node2D = null # 接触带承载单元(=英雄格 CellUnit;rebuild 随清场复位) var _install_tw: Tween # 入场淡入 tween(rebuild 重入先杀) -var _ripple_tws: Array = [] # R0 涟漪逐格 tween(rebuild 重入全杀) +var _ripple_tws: Array[Tween] = [] # R0 涟漪逐格 tween(rebuild 重入全杀) var _dig_glow := false # 挖掘期才允许唯一在动元素(art-bible §2.1) var _hover := Vector2i(-9, -9) var _last_click := {"cell": Vector2i(-9, -9), "ms": -100000} @@ -768,8 +768,8 @@ func _apply_contact_bands() -> void: if hu == null: return _contact_unit = hu - var bands: Array = [] - var corners: Array = [] + var bands: Array[int] = [] + var corners: Array[int] = [] for d in [Vector2i(0, -1), Vector2i(0, 1), Vector2i(-1, 0), Vector2i(1, 0)]: if _diggable.has(_minesweeper.hero_pos() + d): bands.append(0 if d.y < 0 else (1 if d.y > 0 else (2 if d.x < 0 else 3))) diff --git a/game/presentation/views/camp_overlay_view.gd b/game/presentation/views/camp_overlay_view.gd index 0d1ecef2..eb2a7ec9 100644 --- a/game/presentation/views/camp_overlay_view.gd +++ b/game/presentation/views/camp_overlay_view.gd @@ -21,8 +21,8 @@ const ATTR_LABELS := {"atk": "攻击", "max_hp": "生命上限", "armor_class": var _balance_label: Label var _forge_holder: VBoxContainer var _workshop_holder: VBoxContainer -var _forge_rows: Array = [] # [{attr, level_l, price_l, btn}]——refresh_camp 就地重刷(零重建回流) -var _workshop_rows: Array = [] # [{item_id, progress_l, status_l}] +var _forge_rows: Array[Dictionary] = [] # [{attr, level_l, price_l, btn}]——refresh_camp 就地重刷(零重建回流) +var _workshop_rows: Array[Dictionary] = [] # [{item_id, progress_l, status_l}] var _recent_list: Label # 最近冒险(逐行拼接 label——只读账面,随 open_camp 重建) @@ -198,7 +198,7 @@ func _rebuild_workshop(data: Dictionary) -> void: func _rebuild_recent(data: Dictionary) -> void: - var lines: Array = [] + var lines: Array[String] = [] var recent: Array = data.get("recent", []) if recent.is_empty(): lines.append(" (暂无冒险记录——完成或结束一次冒险后入账)") diff --git a/game/presentation/views/level_map_screen.gd b/game/presentation/views/level_map_screen.gd index 82901172..0028fac7 100644 --- a/game/presentation/views/level_map_screen.gd +++ b/game/presentation/views/level_map_screen.gd @@ -52,7 +52,7 @@ var _hp_bar: Control var _attr_value: Label var _bonus_row: HBoxContainer var _bonus_value: Label -var _cand_ids: Array = [] # 本停点候选 id 集(图上命中合法集) +var _cand_ids: Array[int] = [] # 本停点候选 id 集(图上命中合法集) var _content_size := Vector2(620, 240) # 图内容包络(open_choices 按图拟合——画布 min 尺寸随它) var _hover_id := -1 # 悬停预承诺候选(-1 = 无) var abandon_btn: Button # 放弃入口(可见性归组合根 set_abandon_available——只在冒险模式开) @@ -230,7 +230,7 @@ func open_choices(cands: Array, runner) -> void: _runner = runner _hover_id = -1 _reset_abandon_confirm() - var visited: Array = [] + var visited: Array[int] = [] if runner != null: visited = runner.visited_ids() if cands.size() > 1: @@ -308,7 +308,7 @@ func _refresh_status() -> void: ac_txt += " +%d" % ac_bonus _attr_value.text = "攻击 %s · 护甲 AC %s" % [atk_txt, ac_txt] var hp_bonus := int(_runner.bonus.get("max_hp", 0)) - var parts: Array = [] + var parts: Array[String] = [] if atk_bonus > 0: parts.append("攻 +%d" % atk_bonus) if hp_bonus > 0: @@ -458,7 +458,7 @@ func _layout(nodes: Array, canvas: Control) -> Dictionary: func _assign_layers(nodes: Array, layer: Dictionary, slot: Dictionary) -> void: var layer_counts := {} var entry := _entry(nodes) - var queue: Array = [] + var queue: Array[Dictionary] = [] if not entry.is_empty(): queue.append(entry) layer[entry] = 0 diff --git a/game/presentation/views/shop_overlay_view.gd b/game/presentation/views/shop_overlay_view.gd index 47457560..7a515259 100644 --- a/game/presentation/views/shop_overlay_view.gd +++ b/game/presentation/views/shop_overlay_view.gd @@ -15,7 +15,7 @@ const ATTR_LABELS := {"atk": "攻击", "max_hp": "生命上限", "armor_class": var _gp_label: Label var _cards_box: VBoxContainer -var _card_rows: Array = [] # [{product_id, price, bought, btn}]——refresh_state 就地重刷(零重建回流) +var _card_rows: Array[Dictionary] = [] # [{product_id, price, bought, btn}]——refresh_state 就地重刷(零重建回流) func _init() -> void: diff --git a/game/smoke/smoke_all.gd b/game/smoke/smoke_all.gd index 1bb5d022..2e2652a4 100644 --- a/game/smoke/smoke_all.gd +++ b/game/smoke/smoke_all.gd @@ -152,8 +152,8 @@ func _smoke_node_map_templates() -> void: "抽签确定性:同种子逐位同图(实测 %s)" % String(names[0])) # ⑤ N=1 池与现行固定图等价:单模板行过图校验(抽签取模 1 恒 0 = 回滚档) var lt = load("res://data/schemas/level_table.gd").new() - lt.rows = [{"level_index": 9, "display_name": "t", "rest_heal_pct": 30, - "templates": [tpl0]}] + lt.rows.assign([{"level_index": 9, "display_name": "t", "rest_heal_pct": 30, + "templates": [tpl0]}]) check(lt.validate().is_empty(), "N=1 池表通过图校验(回滚档形态合法)") # ⑥ 首次脚本分支:first_script=true 全关模板 0;false = 抽签(scope 恰一差异) var rngF = load("res://core/rng_service.gd").new() @@ -949,13 +949,13 @@ func _smoke_variation_framework() -> void: check(_db.variation.row_by_id("nonexistent").is_empty(), "清单外 variant_id 返回空(读取通道在位)") # 跨字段互锁负样本(加载期致命——枚举语义一致性闸) var vt = load("res://data/schemas/variation_table.gd").new() - vt.rows = [{"variant_id": "bad1", "display_name": "坏行甲", "unlock_level": 1, "scope": "region", + vt.rows.assign([{"variant_id": "bad1", "display_name": "坏行甲", "unlock_level": 1, "scope": "region", "effect": "flat_damage", "effect_value": 1, "trigger": "on_open", "placement": "any", - "board_types": [], "counter_items": []}] + "board_types": [], "counter_items": []}]) check(_errs_has_cross_field(vt.validate()), "跨字段互锁负样本①:flat_damage + placement=any 被拒(只出现在未打开的格子)") - vt.rows = [{"variant_id": "bad2", "display_name": "坏行乙", "unlock_level": 1, "scope": "region", + vt.rows.assign([{"variant_id": "bad2", "display_name": "坏行乙", "unlock_level": 1, "scope": "region", "effect": "hide_number", "effect_value": 0, "trigger": "on_open", "placement": "any", - "board_types": [], "counter_items": []}] + "board_types": [], "counter_items": []}]) check(_errs_has_cross_field(vt.validate()), "跨字段互锁负样本②:hide_number + trigger≠on_number_shown 被拒") @@ -2529,47 +2529,47 @@ func _smoke_skill_pool_death_void() -> void: func _smoke_skill_pool_validation_reject() -> void: var skill_table = load("res://data/schemas/skill_table.gd").new() var enemy_table = load("res://data/schemas/enemy_table.gd").new() - enemy_table.rows = [{"enemy_id": "x", "display_name": "x", "pool": [{"skill_id": "ghost", "weight": 1}]}] + enemy_table.rows.assign([{"enemy_id": "x", "display_name": "x", "pool": [{"skill_id": "ghost", "weight": 1}]}]) check(_has_err_category(_db.validate_skill_pool_links(skill_table, enemy_table), "dangling_skill"), "加载校验拒绝:池条目 skill_id 悬空致命") - skill_table.rows = [{"skill_id": "a", "display_name": "a", "type": "damage", "damage_mult": 1.5, "cooldown_beats": 2}] + skill_table.rows.assign([{"skill_id": "a", "display_name": "a", "type": "damage", "damage_mult": 1.5, "cooldown_beats": 2}]) check(_has_err_category(_db.validate_skill_pool_links(skill_table, enemy_table), "pool_composition"), "加载校验拒绝:池普攻行数 ≠ 1(空池不可能前提)") - skill_table.rows = [ + skill_table.rows.assign([ {"skill_id": "b1", "display_name": "b1", "type": "buff", "buff_ref": "empower", "buff_duration": 2, "cooldown_beats": 3}, - {"skill_id": "b2", "display_name": "b2", "type": "buff", "buff_ref": "fortify", "buff_duration": 2, "cooldown_beats": 4}] - enemy_table.rows = [{"enemy_id": "x", "display_name": "x", "pool": [{"skill_id": "b1", "weight": 1}, {"skill_id": "b2", "weight": 1}]}] + {"skill_id": "b2", "display_name": "b2", "type": "buff", "buff_ref": "fortify", "buff_duration": 2, "cooldown_beats": 4}]) + enemy_table.rows.assign([{"enemy_id": "x", "display_name": "x", "pool": [{"skill_id": "b1", "weight": 1}, {"skill_id": "b2", "weight": 1}]}]) check(_has_err_category(_db.validate_skill_pool_links(skill_table, enemy_table), "pool_composition"), "加载校验拒绝:池增益技 > 1(每池增益 ≤1 纪律)") - skill_table.rows = [{"skill_id": "atk", "display_name": "a", "type": "basic", "damage_mult": 2.0, "cooldown_beats": 0}] + skill_table.rows.assign([{"skill_id": "atk", "display_name": "a", "type": "basic", "damage_mult": 2.0, "cooldown_beats": 0}]) check(not skill_table.validate().is_empty(), "加载校验拒绝:普攻配倍率 ≠ 1(域校验锁死)") - skill_table.rows = [{"skill_id": "atk", "display_name": "a", "type": "basic", "cooldown_beats": 2}] + skill_table.rows.assign([{"skill_id": "atk", "display_name": "a", "type": "basic", "cooldown_beats": 2}]) check(not skill_table.validate().is_empty(), "加载校验拒绝:普攻配冷却 ≠ 0(域校验锁死)") - skill_table.rows = [{"skill_id": "d", "display_name": "d", "type": "damage", "damage_mult": 30.0, "cooldown_beats": 1}] + skill_table.rows.assign([{"skill_id": "d", "display_name": "d", "type": "damage", "damage_mult": 30.0, "cooldown_beats": 1}]) check(not skill_table.validate().is_empty(), "加载校验拒绝:damage_mult 越域 [1.1,16]") var et2 = load("res://data/schemas/enemy_table.gd").new() - et2.rows = [{"enemy_id": "x", "display_name": "x", "pool": [{"skill_id": "a", "weight": 0}]}] + et2.rows.assign([{"enemy_id": "x", "display_name": "x", "pool": [{"skill_id": "a", "weight": 0}]}]) check(not et2.validate().is_empty(), "加载校验拒绝:池权重 ≤ 0") - et2.rows = [{"enemy_id": "x", "display_name": "x", "pool": []}] + et2.rows.assign([{"enemy_id": "x", "display_name": "x", "pool": []}]) check(not et2.validate().is_empty(), "加载校验拒绝:空池(禁)") # 新效应词汇批(2026-09-19):妨害 / 必中附加分量校验组 - skill_table.rows = [ + skill_table.rows.assign([ {"skill_id": "w1", "display_name": "w1", "type": "debuff", "buff_ref": "off_guard", "buff_duration": 2, "cooldown_beats": 4}, - {"skill_id": "w2", "display_name": "w2", "type": "debuff", "buff_ref": "off_guard", "buff_duration": 2, "cooldown_beats": 4}] - enemy_table.rows = [{"enemy_id": "x", "display_name": "x", "pool": [{"skill_id": "w1", "weight": 1}, {"skill_id": "w2", "weight": 1}]}] + {"skill_id": "w2", "display_name": "w2", "type": "debuff", "buff_ref": "off_guard", "buff_duration": 2, "cooldown_beats": 4}]) + enemy_table.rows.assign([{"enemy_id": "x", "display_name": "x", "pool": [{"skill_id": "w1", "weight": 1}, {"skill_id": "w2", "weight": 1}]}]) check(_has_err_category(_db.validate_skill_pool_links(skill_table, enemy_table), "pool_composition"), "加载校验拒绝:池妨害技 > 1(每池妨害 ≤1 纪律)") - skill_table.rows = [{"skill_id": "w1", "display_name": "w1", "type": "debuff", "cooldown_beats": 4}] + skill_table.rows.assign([{"skill_id": "w1", "display_name": "w1", "type": "debuff", "cooldown_beats": 4}]) check(not skill_table.validate().is_empty(), "加载校验拒绝:妨害技缺 buff_ref(效果引用)") - skill_table.rows = [{"skill_id": "d", "display_name": "d", "type": "damage", "damage_mult": 1.5, "rider_mult": 1.5, "cooldown_beats": 1}] + skill_table.rows.assign([{"skill_id": "d", "display_name": "d", "type": "damage", "damage_mult": 1.5, "rider_mult": 1.5, "cooldown_beats": 1}]) check(not skill_table.validate().is_empty(), "加载校验拒绝:rider_mult 越域 (0,1]") - skill_table.rows = [{"skill_id": "b", "display_name": "b", "type": "buff", "buff_ref": "empower", "buff_duration": 2, "rider_mult": 0.5, "cooldown_beats": 1}] + skill_table.rows.assign([{"skill_id": "b", "display_name": "b", "type": "buff", "buff_ref": "empower", "buff_duration": 2, "rider_mult": 0.5, "cooldown_beats": 1}]) check(not skill_table.validate().is_empty(), "加载校验拒绝:非伤害技带必中附加分量") # 施放类 side 守卫:妨害技引用敌方侧状态 → 拒绝(增益技引用主角侧同罪,本组以妨害反例覆盖) - skill_table.rows = [ + skill_table.rows.assign([ {"skill_id": "atk", "display_name": "a", "type": "basic", "cooldown_beats": 0}, - {"skill_id": "w1", "display_name": "w1", "type": "debuff", "buff_ref": "empower", "buff_duration": 2, "cooldown_beats": 4}] - enemy_table.rows = [{"enemy_id": "x", "display_name": "x", "pool": [{"skill_id": "atk", "weight": 1}, {"skill_id": "w1", "weight": 1}]}] + {"skill_id": "w1", "display_name": "w1", "type": "debuff", "buff_ref": "empower", "buff_duration": 2, "cooldown_beats": 4}]) + enemy_table.rows.assign([{"enemy_id": "x", "display_name": "x", "pool": [{"skill_id": "atk", "weight": 1}, {"skill_id": "w1", "weight": 1}]}]) check(_has_err_category(_db.validate_skill_pool_links(skill_table, enemy_table, _db.status_effects), "cast_side"), "加载校验拒绝:妨害技引用敌方侧状态(施放类 side 守卫)") @@ -2676,34 +2676,34 @@ func _smoke_level_graph() -> void: var lt = load("res://data/schemas/level_table.gd").new() var good := [{"node_depth": 0, "type": "battle", "next": [1, 2]}, {"node_depth": 1, "type": "battle", "next": [2]}, {"node_depth": 2, "type": "boss"}] - lt.rows = [{"level_index": 9, "display_name": "t", "rest_heal_pct": 30, "nodes": good}] + lt.rows.assign([{"level_index": 9, "display_name": "t", "rest_heal_pct": 30, "nodes": good}]) check(lt.validate().is_empty(), "图校验正例:两岔合流小图零错误") var dup = JSON.parse_string(JSON.stringify(good)) dup[1].node_depth = 0 - lt.rows = [{"level_index": 9, "display_name": "t", "rest_heal_pct": 30, "nodes": dup}] + lt.rows.assign([{"level_index": 9, "display_name": "t", "rest_heal_pct": 30, "nodes": dup}]) check(_has_err_category(lt.validate(), "dup_key"), "图校验拒绝:节点编号重复(关卡内唯一定位地址)") var dual = JSON.parse_string(JSON.stringify(good)) dual.append({"node_depth": 9, "type": "battle", "next": [2]}) - lt.rows = [{"level_index": 9, "display_name": "t", "rest_heal_pct": 30, "nodes": dual}] + lt.rows.assign([{"level_index": 9, "display_name": "t", "rest_heal_pct": 30, "nodes": dual}]) check(_has_err_category(lt.validate(), "structural"), "图校验拒绝:第二无入边节点(入口唯一违例——入口节点数 = 3)") var boss_out = JSON.parse_string(JSON.stringify(good)) boss_out[2].next = [1] - lt.rows = [{"level_index": 9, "display_name": "t", "rest_heal_pct": 30, "nodes": boss_out}] + lt.rows.assign([{"level_index": 9, "display_name": "t", "rest_heal_pct": 30, "nodes": boss_out}]) check(_has_err_category(lt.validate(), "structural"), "图校验拒绝:Boss 带出边(终点不可外出)") var cyc = JSON.parse_string(JSON.stringify(good)) cyc[1].next = [0] - lt.rows = [{"level_index": 9, "display_name": "t", "rest_heal_pct": 30, "nodes": cyc}] + lt.rows.assign([{"level_index": 9, "display_name": "t", "rest_heal_pct": 30, "nodes": cyc}]) check(_has_err_category(lt.validate(), "structural"), "图校验拒绝:回边 1→0(连线只朝前进方向 ⇒ 无环)") var dang = JSON.parse_string(JSON.stringify(good)) dang[0].next = [1, 7] - lt.rows = [{"level_index": 9, "display_name": "t", "rest_heal_pct": 30, "nodes": dang}] + lt.rows.assign([{"level_index": 9, "display_name": "t", "rest_heal_pct": 30, "nodes": dang}]) check(_has_err_category(lt.validate(), "dangling_next"), "图校验拒绝:出边指向不存在编号(悬空致命)") var orphan = JSON.parse_string(JSON.stringify(good)) orphan[0].next = [1] orphan[1].next = [2] orphan.append({"node_depth": 5, "type": "battle", "next": [2]}) - lt.rows = [{"level_index": 9, "display_name": "t", "rest_heal_pct": 30, "nodes": orphan}] + lt.rows.assign([{"level_index": 9, "display_name": "t", "rest_heal_pct": 30, "nodes": orphan}]) var orphan_errs: Array = lt.validate() check(_has_err_category(orphan_errs, "structural"), "图校验拒绝:孤儿节点(从入口不可达 / 双入口同体违例)") # ④ L2 选路推进:min / max 双路径全通(确定性路径轴——零随机流自开)