81 lines
4.2 KiB
GDScript
81 lines
4.2 KiB
GDScript
## 关卡节点图参数档 schema(节点图生成器核心批 卡① T1):五旋钮+战斗保底+岔口去路数的行式数据表。
|
||
## 键 = level_index(关卡行集单点),消费面经 ConfigDB.level_gen_params_row() 读取;生成器只吃参数档、不认关卡号(契约 6)。
|
||
## 数值全 provisional(定值批落终值);域校验沿关卡节点图生成.md v1.1 调参表已锁条款——层深 L1≥6 递增增幅变大、
|
||
## 配比四类合计 1、出口 L1 恒 1/L2-L3 1-3、岔口去路数恒 2/3、战斗保底≥0。
|
||
class_name LevelGenParams
|
||
extends Resource
|
||
|
||
const RATIO_KEYS := ["battle_ratio", "reward_ratio", "rest_ratio", "shop_ratio"]
|
||
const ROW_KEYS := ["level_index", "layers", "branch_density", "entry_count", "exit_count",
|
||
"battle_floor", "fork_ways_min", "fork_ways_max"] + RATIO_KEYS
|
||
|
||
@export var rows: Array[Dictionary] = [] # 每行 = ROW_KEYS 键集(level_index 唯一正整数)
|
||
|
||
|
||
func validate() -> Array:
|
||
var errs: Array[Dictionary] = []
|
||
var seen := {}
|
||
var layers_by_level := {}
|
||
for row in rows:
|
||
var L: int = int(row.get("level_index", 0))
|
||
var key := "level %d" % L
|
||
if seen.has(L):
|
||
errs.append({"category": "dup_key", "message": "LevelGenParams 键重复: %d" % L})
|
||
seen[L] = true
|
||
if L < 1:
|
||
errs.append({"category": "domain", "message": "%s 关卡序号越域(≥1)" % key})
|
||
var ks := (row as Dictionary).keys()
|
||
ks.sort()
|
||
var expect := ROW_KEYS.duplicate()
|
||
expect.sort()
|
||
if ks != expect:
|
||
errs.append({"category": "structural", "message": "%s 字段键集非 ROW_KEYS 闭集" % key})
|
||
continue
|
||
var layers: int = int(row.get("layers", 0))
|
||
if layers < 6:
|
||
errs.append({"category": "domain", "message": "%s 层深 %d 低于下限 6(层深 L1≥6 已锁)" % [key, layers]})
|
||
layers_by_level[L] = layers
|
||
var bd: float = float(row.get("branch_density", -1.0))
|
||
if bd < 0.0 or bd > 1.0:
|
||
errs.append({"category": "domain", "message": "%s 分支密度 %f 越域 [0,1]" % [key, bd]})
|
||
var ratio_sum := 0.0
|
||
for rk in RATIO_KEYS:
|
||
var v: float = float(row.get(rk, -1.0))
|
||
if v < 0.0 or v > 1.0:
|
||
errs.append({"category": "domain", "message": "%s %s=%f 越域 [0,1]" % [key, rk, v]})
|
||
ratio_sum += v
|
||
if not is_equal_approx(ratio_sum, 1.0):
|
||
errs.append({"category": "domain", "message": "%s 配比四类合计 %f ≠ 1(已锁)" % [key, ratio_sum]})
|
||
var entry_count: int = int(row.get("entry_count", 0))
|
||
if entry_count < 1:
|
||
errs.append({"category": "domain", "message": "%s 入口个数 %d 越域(≥1)" % [key, entry_count]})
|
||
var exit_count: int = int(row.get("exit_count", 0))
|
||
if exit_count < 1 or exit_count > 3:
|
||
errs.append({"category": "domain", "message": "%s 出口个数 %d 越域 [1,3](已锁范围)" % [key, exit_count]})
|
||
if L == 1 and exit_count != 1:
|
||
errs.append({"category": "domain", "message": "%s 出口个数 %d ≠ 1(L1 出口恒 1 已锁)" % [key, exit_count]})
|
||
var bf: int = int(row.get("battle_floor", -1))
|
||
if bf < 0:
|
||
errs.append({"category": "domain", "message": "%s 战斗保底 %d 越域(≥0)" % [key, bf]})
|
||
var fmin: int = int(row.get("fork_ways_min", 0))
|
||
var fmax: int = int(row.get("fork_ways_max", 0))
|
||
if fmin != 2 or fmax != 3:
|
||
errs.append({"category": "domain", "message": "%s 岔口去路数 (%d,%d) ≠ (2,3)(已锁)" % [key, fmin, fmax]})
|
||
if layers_by_level.has(1) and layers_by_level.has(2) and layers_by_level.has(3):
|
||
var d12: int = int(layers_by_level[2]) - int(layers_by_level[1])
|
||
var d23: int = int(layers_by_level[3]) - int(layers_by_level[2])
|
||
if not (int(layers_by_level[1]) < int(layers_by_level[2]) and int(layers_by_level[2]) < int(layers_by_level[3])):
|
||
errs.append({"category": "domain", "message": "层深逐关递增不成立(L1/L2/L3 = %d/%d/%d)" % [
|
||
layers_by_level[1], layers_by_level[2], layers_by_level[3]]})
|
||
elif d23 <= d12:
|
||
errs.append({"category": "domain", "message": "层深增幅未变大(Δ(L1→L2)=%d、Δ(L2→L3)=%d)" % [d12, d23]})
|
||
return errs
|
||
|
||
|
||
# 参数档单点读取(键 = level_index,缺行返回空字典——沿 level_row() 体例)
|
||
func row_by_level_index(level_index: int) -> Dictionary:
|
||
for row in rows:
|
||
if int(row.get("level_index", 0)) == level_index:
|
||
return row
|
||
return {}
|