Files
gplan-2/game/data/schemas/level_gen_params.gd
T

106 lines
5.3 KiB
GDScript
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
## 关卡节点图参数档 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 head := _validate_row_head(row, seen)
errs.append_array(head["errs"])
if not head["ok"]:
continue
errs.append_array(_validate_row_shape(row, head["L"], head["key"], layers_by_level))
errs.append_array(_validate_row_counts(row, head["L"], head["key"]))
# 层深递进尾段(L1<L2<L3 且增幅变大——层深 L1≥6 递增增幅变大已锁)
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 查重/关卡序号越域/字段键集闭集(ok=跳过行剩余判据)
func _validate_row_head(row: Dictionary, seen: Dictionary) -> Dictionary:
var errs: Array[Dictionary] = []
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})
return {"errs": errs, "L": L, "key": key, "ok": false}
return {"errs": errs, "L": L, "key": key, "ok": true}
## 行形态域:层深下限(layers_by_level 引用登记——层深递进尾段取数)/分支密度/配比四类合计 1
func _validate_row_shape(row: Dictionary, L: int, key: String, layers_by_level: Dictionary) -> Array[Dictionary]:
var errs: Array[Dictionary] = []
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]})
return errs
## 行计数域:入口/出口(L1 恒 1)/战斗保底/岔口去路数锁值
func _validate_row_counts(row: Dictionary, L: int, key: String) -> Array[Dictionary]:
var errs: Array[Dictionary] = []
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]})
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 {}