fix(review-batch3): 类型收紧生产清零137处(P1-2三步+延伸)+autoload class_name(ConfigDb/RngServiceCore)与_init标注(P2-1)+validate_skill_pool_links/ShopTable标注(P2-4)+相位enum外String面(P2-2)+typed-rows探针实证.tres装载转换;smoke缝合20处rows.assign+str(bb)同语义;审计生产双归零(240→103/83→59全测试链),单测7套绿,冒烟576/0同基线
This commit is contained in:
1 parent
f5edb65d25
commit
104cea6461
46 files changed
+233
-218
No files matched your search
@@ -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:
|
||||
|
||||
@@ -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:
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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))
|
||||
|
||||
@@ -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
|
||||
@@ -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:
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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():
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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):
|
||||
|
||||
@@ -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():
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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", "")
|
||||
|
||||
Reference in new issue
Block a user