迭代42-卡1-T3: battle_orchestrator装板域拆件BoardInstaller(architecture v1.24 轴丙)——六函数(生成/全局变异决议/装板受理/资源摇号/变异布置/连通片生长)迁件board_installer.gd(RefCounted零UI零await,引用束注入rng/db/minesweeper/reward_economy/encounter/fatal_cb六键assert检查+自建BoardGenerator自接线fatal);宿主薄壳_install_and_reset承载复位块(五处计数清零+板序推进+board_changed发射+秘宝叠加层退役)时序逐字;三调用点(:270 begin_battle/:683 _exit_distribution/:717 player_request_refresh)改调薄壳;_board_generator成员退役(类变量38→37只降,禁无效成员义务)——薄壳内逐调用构建installer(BoardGenerator唯一成员=fatal_handler零跨调用状态,观察等价,免去宿主新成员);board_gen/variant_place两封闭流随件流名开流时点消费序零漂移(同种子断言面钉住);static_scan S7_B1_SET/S8_FILES增行board_installer(架构S7/S8随动条在册,9→10文件)。键10归绿:文件长1035→916≤1000键消失。孤立验证:variant_placement 49/round_flow 129/seal_polarity 70三套件绿+run_smoke 15项0失败+零新增键(现值10键=16-6归绿零EXTRA)
This commit is contained in:
1 parent
c47a032dcb
commit
adff0772c5
4 files changed
+184
-134
No files matched your search
@@ -36,10 +36,10 @@ const SOURCE_EXEMPT_CLASSES := ["hero_attack", "enemy_action", "clear_reward", "
|
||||
|
||||
var db: ConfigDb
|
||||
var rng: RngServiceCore
|
||||
# E1 封装收口:协作对象 board_generator/enemy_system/status_effects/reward_economy 私有化——跨层读取一律经 presentation_snapshot()/diagnostic_snapshot() 成文出口。
|
||||
# E1 封装收口:协作对象 enemy_system/status_effects/reward_economy 私有化——跨层读取一律经 presentation_snapshot()/diagnostic_snapshot() 成文出口。
|
||||
# minesweeper/action_economy 保持公有 = 架构文档 API Boundaries 的 HUD框架消费面(意图提交 settle_batch + compute_move_path
|
||||
# 只读;ap/rap/相位读取)——非本文档登记的契约面,勿增新用途。
|
||||
var _board_generator: BoardGenerator
|
||||
# 装板域(BoardGenerator+装板六函数族)已拆 BoardInstaller——生成器实例随件自建,宿主零成员。
|
||||
var minesweeper: MinesweeperRules
|
||||
var action_economy: ActionEconomy
|
||||
var _enemy_system: UnitContainer
|
||||
@@ -230,13 +230,12 @@ var _hero_atk := 0 # 主角攻击基值快照(encounte
|
||||
func _init(db_ref: ConfigDb, rng_ref: RngServiceCore) -> void:
|
||||
db = db_ref
|
||||
rng = rng_ref
|
||||
_board_generator = BoardGenerator.new()
|
||||
action_economy = ActionEconomy.new(db)
|
||||
minesweeper = MinesweeperRules.new(db, action_economy)
|
||||
_enemy_system = UnitContainer.new(db)
|
||||
_status_effects = StatusContainer.new(db)
|
||||
_reward_economy = RewardEconomy.new(db, rng)
|
||||
_board_generator.fatal_handler = _fatal; _reward_economy.fatal_handler = _fatal # 协作件违约→本类 _fatal 封印(单点接线)
|
||||
_reward_economy.fatal_handler = _fatal # 协作件违约→本类 _fatal 封印(单点接线)
|
||||
_damage = DamageController.new(db, rng, _enemy_system, _status_effects)
|
||||
_damage.emit_row_cb = _emit_row # 行协议归属本类(9 类行协议 + 来源断言不外泄)
|
||||
_fx_host = BattleFxHost.new({"db": db, "rng": rng, "minesweeper": minesweeper, "action_economy": action_economy,
|
||||
@@ -268,7 +267,7 @@ func begin_battle(enc: Dictionary) -> bool:
|
||||
return false
|
||||
if not _begin_battle_accept(enc):
|
||||
return false
|
||||
if not _install_new_board():
|
||||
if not _install_and_reset():
|
||||
return false
|
||||
_reset_round_facts() # 首板 install 的初始展开事件不入轮 facts(resource 恒 false 的双保险)
|
||||
_begin_battle_fx_state(enc)
|
||||
@@ -411,34 +410,14 @@ func _begin_battle_preview_economy(enc: Dictionary) -> void:
|
||||
action_economy.grant_reserve_ap(voucher_rap)
|
||||
|
||||
|
||||
func _install_new_board(during_round := false) -> bool:
|
||||
var stream: RandomNumberGenerator = rng.open_stream("board_gen")
|
||||
var board: BoardData = _board_generator.generate(int(encounter.level_index), int(encounter.node_depth), stream, db)
|
||||
if board == null:
|
||||
# ---- 装板受理薄壳(BoardInstaller 拆件后的宿主承接面——begin_battle/中途刷新/轮内刷新三调用点唯一入口)----
|
||||
# 件内装板(生成→全局变异决议→装板受理→资源摇号→变异布置)成功后执行宿主态复位:五处计数清零+
|
||||
# 板序推进+board_changed 发射+秘宝叠加层退役——时序逐字;复位职责留宿主(成员单点),不随件。
|
||||
func _install_and_reset(during_round := false) -> bool:
|
||||
var installer := BoardInstaller.new({"db": db, "rng": rng, "minesweeper": minesweeper,
|
||||
"reward_economy": _reward_economy, "encounter": encounter, "fatal_cb": _fatal})
|
||||
if not installer.install(during_round):
|
||||
return false
|
||||
# 全局作用域变异决议(装板序内前置于 roll_board:图级偏斜旋钮须在资源摇号前定型——详见 _resolve_global_variant)
|
||||
_resolve_global_variant(board)
|
||||
var res: Dictionary[Variant, Variant] = minesweeper.install_board(board, during_round)
|
||||
if not res.accepted:
|
||||
_fatal("排雷玩法 install 拒绝(不变式违例): %s" % str(res))
|
||||
return false
|
||||
# 地图战斗资源 义务⑥:roll_board 恰一次(install 后、挖掘前);资格格 = 全部非封锁格(安全格 + 危险格,雷安同池)
|
||||
var r0 := {}
|
||||
for c in board.compute_r0():
|
||||
r0[c] = true
|
||||
var eligible: Array[Dictionary] = []
|
||||
for c in board.safe_cells():
|
||||
if not r0.has(c):
|
||||
eligible.append({"cell": c})
|
||||
for c in board.mines.keys():
|
||||
if not r0.has(c):
|
||||
eligible.append({"cell": c})
|
||||
if not _reward_economy.roll_board(eligible):
|
||||
_fatal("地图战斗资源 roll_board 被拒")
|
||||
return false
|
||||
# 地形变异 布置段(棋盘设置顺序第 4 步:生成棋盘 → 打开状态初始化 →
|
||||
# 战斗资源格设置 → 变异格设置)——布置在初始展开与资源格之后,变异天然不落已开区
|
||||
_place_variants(board)
|
||||
_seal_consumed.clear() # 换图新雷 = 新实例,资格自然重置(行动经济 Rule 8)
|
||||
_seal_miss_seen.clear()
|
||||
_perfect_hit_true = 0 # 整图完美计数随 install 重置
|
||||
@@ -452,103 +431,6 @@ func _install_new_board(during_round := false) -> bool:
|
||||
return true
|
||||
|
||||
|
||||
# ---- 全局作用域变异 决议(装板序内 roll_board 之前)----
|
||||
# boss/elite 图命中全局型:写整图 board_variants(恰一行)+ 注入资源面偏斜旋钮(图级投影在
|
||||
# RewardEconomy.roll_board 消费);不消费 variant_place 流(全局取用确定性——零取号合法态)。
|
||||
# 全局池空(含 L1 Boss 免疫/unlock 门控未达):字段留空、旋钮归零——_place_variants 原路走
|
||||
# region 布置 = 兜底回落合法态(防配置缺行静默裸奔——provisional)。
|
||||
func _resolve_global_variant(board: BoardData) -> void:
|
||||
board.board_variants.clear()
|
||||
_reward_economy.board_skew = 0
|
||||
var row: Dictionary[Variant, Variant] = db.combat.variation.global_variant_row(int(encounter.level_index), String(board.board_type),
|
||||
String(encounter.get("node_type", "")))
|
||||
if row.is_empty():
|
||||
return
|
||||
board.board_variants = [String(row.variant_id)]
|
||||
_reward_economy.board_skew = int(row.get("effect_value", 0))
|
||||
|
||||
|
||||
# ---- 地形变异 布置段(棋盘设置顺序第 4 步)----
|
||||
# 候选池门控(unlock_level ≤ 关卡序号 + board_types 与本地形交集,∅ 通配)经 config_db.variant_pool;
|
||||
# 池空 = 合法态,静默零布置(框架 P0 口径不变)。零特判:本段只写格子变异数据快照,不改扫雷规则本体。
|
||||
# 候选格域 = 安全格 − 初始展开区(伤害型 placement=closed_only 的结构保障——布置发生在初始展开之后,
|
||||
# 已开格天然排除);危险格不吃变异(挖雷一层惩罚 + 变异伤害双层叠罚污染逐行归因,首版排除——provisional)。
|
||||
# 每图至多一种类型(候选池内均匀选一);数量 = round(候选池格数×percent) +
|
||||
# (关卡序号−1)×per_level_bonus——基数为候选池而非总格数(percent 语义 = 占可挖格比例,
|
||||
# 关卡递增由 per_level_bonus 绝对格数承载);连通片生长(8 邻),单片 ≤ pack_max。
|
||||
# 替换制:整图 board_variants 非空 = 本图已带全局型,跳过 region 布置(详见 _resolve_global_variant)。
|
||||
func _place_variants(board: BoardData) -> void:
|
||||
if not board.board_variants.is_empty():
|
||||
return
|
||||
var pool: Array[Variant] = db.combat.variation.variant_pool(int(encounter.level_index), String(board.board_type))
|
||||
if pool.is_empty():
|
||||
return
|
||||
var r0 := {}
|
||||
for c in board.compute_r0():
|
||||
r0[c] = true
|
||||
var candidates: Array[Vector2i] = []
|
||||
for c in board.safe_cells():
|
||||
if not r0.has(c):
|
||||
candidates.append(c)
|
||||
if candidates.is_empty():
|
||||
return
|
||||
var stream: RandomNumberGenerator = rng.open_stream("variant_place") # 一板恰一 scope(换图/刷新图各取号一次)
|
||||
var vrow: Dictionary[Variant, Variant] = pool[stream.randi_range(0, pool.size() - 1)]
|
||||
var total: int = int(round(float(candidates.size()) * float(db.combat.variation.percent_of_cells) / 100.0)) \
|
||||
+ (int(encounter.level_index) - 1) * int(db.combat.variation.per_level_bonus)
|
||||
total = mini(total, candidates.size())
|
||||
_place_variants_apply(board, candidates, stream, vrow, total)
|
||||
|
||||
|
||||
# 变异片生长施加面(布置域=候选格,数量=total,vrow 单型贯穿;取号序=stream 顺序消费)
|
||||
func _place_variants_apply(board: BoardData, candidates: Array[Vector2i], stream: RandomNumberGenerator, vrow: Dictionary, total: int) -> void:
|
||||
var placed := {}
|
||||
while placed.size() < total:
|
||||
var pack_size: int = mini(total - placed.size(), stream.randi_range(2, int(db.combat.variation.pack_max)))
|
||||
var free: Array[Vector2i] = []
|
||||
for c in candidates:
|
||||
# 新片种子/生长格禁与其他已布片 8 邻贴接——否则两片粘连成一个超 pack_max 的连通分量
|
||||
# (R3 随机流下实测暴露:独立生长的相邻片合流击穿单片上限断言)
|
||||
if placed.has(c) or _adjacent_to_packs(board, placed, c):
|
||||
continue
|
||||
free.append(c)
|
||||
if free.is_empty():
|
||||
break # 生长域耗尽——该片就地收束(数量不足总目标为合法态,候选域碎片化时触发)
|
||||
var seed_c: Vector2i = free[stream.randi_range(0, free.size() - 1)]
|
||||
placed[seed_c] = true
|
||||
var pack: Array[Variant] = [seed_c]
|
||||
var pack_set := {seed_c: true}
|
||||
while pack.size() < pack_size:
|
||||
var fringe := _variants_fringe(board, pack, candidates, placed, pack_set)
|
||||
if fringe.is_empty():
|
||||
break # 生长域耗尽——该片就地收束(数量不足总目标为合法态,候选域碎片化时触发)
|
||||
var nxt: Vector2i = fringe[stream.randi_range(0, fringe.size() - 1)]
|
||||
placed[nxt] = true
|
||||
pack_set[nxt] = true
|
||||
pack.append(nxt)
|
||||
for c in placed.keys():
|
||||
board.variants[c] = [String(vrow.variant_id)]
|
||||
|
||||
|
||||
# 片生长待选格收集(本片内各生长格的 8 邻候选并集——未布置、未在途、不与他片贴接)
|
||||
func _variants_fringe(board: BoardData, pack: Array, candidates: Array[Vector2i], placed: Dictionary, pack_set: Dictionary) -> Array[Vector2i]:
|
||||
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) \
|
||||
and not _adjacent_to_packs(board, placed, n, pack_set):
|
||||
fringe.append(n)
|
||||
return fringe
|
||||
|
||||
|
||||
# 候选格是否与其他已布片(own_pack 之外的 placed 格)8 邻贴接——片间隔离保证连通分量 = 单片 ≤ pack_max
|
||||
func _adjacent_to_packs(board: BoardData, placed: Dictionary, c: Vector2i, own_pack: Dictionary = {}) -> bool:
|
||||
for m in board.neighbors8(c):
|
||||
if placed.has(m) and not own_pack.has(m):
|
||||
return true
|
||||
return false
|
||||
|
||||
|
||||
# ---- 事件缓冲(轮 facts 收集;结算触发 = Waiting 相位编排点,不依赖到达序)----
|
||||
|
||||
func _on_cell_revealed(evt: Dictionary) -> void:
|
||||
@@ -798,7 +680,7 @@ func _exit_distribution() -> void:
|
||||
if mode == "new_board":
|
||||
_reward_economy.retire_mapping()
|
||||
minesweeper.retire_board()
|
||||
if not _install_new_board():
|
||||
if not _install_and_reset():
|
||||
_fatal("换图编排失败")
|
||||
return
|
||||
# 工兵晨令续队直调拆除(内容数据驱动扩展批 T4——round_start 订阅行承载,见 begin_battle 注)
|
||||
@@ -832,7 +714,7 @@ func player_request_refresh() -> bool:
|
||||
_refresh_used_this_round += 1
|
||||
_reward_economy.retire_mapping() # 旧图批次退役(地图战斗资源 Ready→retired;E6 新批重置前提)
|
||||
minesweeper.retire_board(true) # 旧板退役(轮内通道)
|
||||
return _install_new_board(true) # 当场换图——失败即编排违例 fail-fast
|
||||
return _install_and_reset(true) # 当场换图——失败即编排违例 fail-fast
|
||||
|
||||
|
||||
func _battle_over(result: String) -> void:
|
||||
|
||||
@@ -0,0 +1,167 @@
|
||||
## 棋盘安装与变异布置域件(B1 域·BoardInstaller):生成受理、全局作用域变异决议、装板受理、
|
||||
## 资源摇号资格域组装(roll_board 恰一次——install 后、挖掘前)、region 变异决议与连通片布置。
|
||||
## 棋盘设置顺序 = 生成棋盘 → 打开状态初始化 → 战斗资源格设置 → 变异格设置(布置在初始展开与
|
||||
## 资源格之后,变异天然不落已开区)。宿主侧装板后状态复位(封印/完美计数清零、板序推进、
|
||||
## board_changed 发射、秘宝叠加层退役)留宿主薄壳——本件零复位职责。零 UI 零 await;
|
||||
## 随机只经注入 RngServiceCore 的 board_gen/variant_place 两封闭流(流名与开流时点不变,
|
||||
## 生成器只消费传入流——同种子同输入逐位复现)。
|
||||
class_name BoardInstaller
|
||||
extends RefCounted
|
||||
|
||||
var db: ConfigDb
|
||||
var rng: RngServiceCore
|
||||
var minesweeper: MinesweeperRules
|
||||
var reward_economy: RewardEconomy
|
||||
var encounter: Dictionary[String, Variant] # 宿主 encounter 同对象引用(assign 原地变异——跨战活引用)
|
||||
var fatal_cb: Callable # 协作件违约→宿主 _fatal 封印(单点接线——BoardGenerator 同款)
|
||||
var generator: BoardGenerator # 件内自建自接线(原宿主 _board_generator 成员随件迁移)
|
||||
|
||||
|
||||
func _init(bundle: Dictionary) -> void:
|
||||
for k in ["db", "rng", "minesweeper", "reward_economy", "encounter", "fatal_cb"]:
|
||||
assert(bundle.has(k), "[装板域件] 引用束缺键: %s" % k)
|
||||
db = bundle.db
|
||||
rng = bundle.rng
|
||||
minesweeper = bundle.minesweeper
|
||||
reward_economy = bundle.reward_economy
|
||||
encounter = bundle.encounter
|
||||
fatal_cb = bundle.fatal_cb
|
||||
generator = BoardGenerator.new()
|
||||
generator.fatal_handler = fatal_cb # 协作件违约→宿主 _fatal 封印(单点接线)
|
||||
|
||||
|
||||
func _fatal(msg: String) -> void:
|
||||
if fatal_cb.is_valid():
|
||||
fatal_cb.call(msg) # 组装层注入 orchestrator._fatal(封印传导,不绕第二中止通道)
|
||||
else:
|
||||
push_error(msg)
|
||||
assert(false, msg)
|
||||
|
||||
|
||||
# 装板单入口(生成 → 全局变异决议 → 装板受理 → 资源摇号 → 变异布置);
|
||||
# 宿主态复位归宿主薄壳(_install_and_reset)——本件返回即装板完成、复位未行。
|
||||
func install(during_round := false) -> bool:
|
||||
var stream: RandomNumberGenerator = rng.open_stream("board_gen")
|
||||
var board: BoardData = generator.generate(int(encounter.level_index), int(encounter.node_depth), stream, db)
|
||||
if board == null:
|
||||
return false
|
||||
# 全局作用域变异决议(装板序内前置于 roll_board:图级偏斜旋钮须在资源摇号前定型——详见 _resolve_global_variant)
|
||||
_resolve_global_variant(board)
|
||||
var res: Dictionary[Variant, Variant] = minesweeper.install_board(board, during_round)
|
||||
if not res.accepted:
|
||||
_fatal("排雷玩法 install 拒绝(不变式违例): %s" % str(res))
|
||||
return false
|
||||
# 地图战斗资源 义务⑥:roll_board 恰一次(install 后、挖掘前);资格格 = 全部非封锁格(安全格 + 危险格,雷安同池)
|
||||
var r0 := {}
|
||||
for c in board.compute_r0():
|
||||
r0[c] = true
|
||||
var eligible: Array[Dictionary] = []
|
||||
for c in board.safe_cells():
|
||||
if not r0.has(c):
|
||||
eligible.append({"cell": c})
|
||||
for c in board.mines.keys():
|
||||
if not r0.has(c):
|
||||
eligible.append({"cell": c})
|
||||
if not reward_economy.roll_board(eligible):
|
||||
_fatal("地图战斗资源 roll_board 被拒")
|
||||
return false
|
||||
# 地形变异 布置段(棋盘设置顺序第 4 步)——布置在初始展开与资源格之后,变异天然不落已开区
|
||||
_place_variants(board)
|
||||
return true
|
||||
|
||||
|
||||
# ---- 全局作用域变异 决议(装板序内 roll_board 之前)----
|
||||
# boss/elite 图命中全局型:写整图 board_variants(恰一行)+ 注入资源面偏斜旋钮(图级投影在
|
||||
# RewardEconomy.roll_board 消费);不消费 variant_place 流(全局取用确定性——零取号合法态)。
|
||||
# 全局池空(含 L1 Boss 免疫/unlock 门控未达):字段留空、旋钮归零——_place_variants 原路走
|
||||
# region 布置 = 兜底回落合法态(防配置缺行静默裸奔——provisional)。
|
||||
func _resolve_global_variant(board: BoardData) -> void:
|
||||
board.board_variants.clear()
|
||||
reward_economy.board_skew = 0
|
||||
var row: Dictionary[Variant, Variant] = db.combat.variation.global_variant_row(int(encounter.level_index), String(board.board_type),
|
||||
String(encounter.get("node_type", "")))
|
||||
if row.is_empty():
|
||||
return
|
||||
board.board_variants = [String(row.variant_id)]
|
||||
reward_economy.board_skew = int(row.get("effect_value", 0))
|
||||
|
||||
|
||||
# ---- 地形变异 布置段(棋盘设置顺序第 4 步)----
|
||||
# 候选池门控(unlock_level ≤ 关卡序号 + board_types 与本地形交集,∅ 通配)经 config_db.variant_pool;
|
||||
# 池空 = 合法态,静默零布置(框架 P0 口径不变)。零特判:本段只写格子变异数据快照,不改扫雷规则本体。
|
||||
# 候选格域 = 安全格 − 初始展开区(伤害型 placement=closed_only 的结构保障——布置发生在初始展开之后,
|
||||
# 已开格天然排除);危险格不吃变异(挖雷一层惩罚 + 变异伤害双层叠罚污染逐行归因,首版排除——provisional)。
|
||||
# 每图至多一种类型(候选池内均匀选一);数量 = round(候选池格数×percent) +
|
||||
# (关卡序号−1)×per_level_bonus——基数为候选池而非总格数(percent 语义 = 占可挖格比例,
|
||||
# 关卡递增由 per_level_bonus 绝对格数承载);连通片生长(8 邻),单片 ≤ pack_max。
|
||||
# 替换制:整图 board_variants 非空 = 本图已带全局型,跳过 region 布置(详见 _resolve_global_variant)。
|
||||
func _place_variants(board: BoardData) -> void:
|
||||
if not board.board_variants.is_empty():
|
||||
return
|
||||
var pool: Array[Variant] = db.combat.variation.variant_pool(int(encounter.level_index), String(board.board_type))
|
||||
if pool.is_empty():
|
||||
return
|
||||
var r0 := {}
|
||||
for c in board.compute_r0():
|
||||
r0[c] = true
|
||||
var candidates: Array[Vector2i] = []
|
||||
for c in board.safe_cells():
|
||||
if not r0.has(c):
|
||||
candidates.append(c)
|
||||
if candidates.is_empty():
|
||||
return
|
||||
var stream: RandomNumberGenerator = rng.open_stream("variant_place") # 一板恰一 scope(换图/刷新图各取号一次)
|
||||
var vrow: Dictionary[Variant, Variant] = pool[stream.randi_range(0, pool.size() - 1)]
|
||||
var total: int = int(round(float(candidates.size()) * float(db.combat.variation.percent_of_cells) / 100.0)) \
|
||||
+ (int(encounter.level_index) - 1) * int(db.combat.variation.per_level_bonus)
|
||||
total = mini(total, candidates.size())
|
||||
_place_variants_apply(board, candidates, stream, vrow, total)
|
||||
|
||||
|
||||
# 变异片生长施加面(布置域=候选格,数量=total,vrow 单型贯穿;取号序=stream 顺序消费)
|
||||
func _place_variants_apply(board: BoardData, candidates: Array[Vector2i], stream: RandomNumberGenerator, vrow: Dictionary, total: int) -> void:
|
||||
var placed := {}
|
||||
while placed.size() < total:
|
||||
var pack_size: int = mini(total - placed.size(), stream.randi_range(2, int(db.combat.variation.pack_max)))
|
||||
var free: Array[Vector2i] = []
|
||||
for c in candidates:
|
||||
# 新片种子/生长格禁与其他已布片 8 邻贴接——否则两片粘连成一个超 pack_max 的连通分量
|
||||
# (R3 随机流下实测暴露:独立生长的相邻片合流击穿单片上限断言)
|
||||
if placed.has(c) or _adjacent_to_packs(board, placed, c):
|
||||
continue
|
||||
free.append(c)
|
||||
if free.is_empty():
|
||||
break # 生长域耗尽——该片就地收束(数量不足总目标为合法态,候选域碎片化时触发)
|
||||
var seed_c: Vector2i = free[stream.randi_range(0, free.size() - 1)]
|
||||
placed[seed_c] = true
|
||||
var pack: Array[Variant] = [seed_c]
|
||||
var pack_set := {seed_c: true}
|
||||
while pack.size() < pack_size:
|
||||
var fringe := _variants_fringe(board, pack, candidates, placed, pack_set)
|
||||
if fringe.is_empty():
|
||||
break # 生长域耗尽——该片就地收束(数量不足总目标为合法态,候选域碎片化时触发)
|
||||
var nxt: Vector2i = fringe[stream.randi_range(0, fringe.size() - 1)]
|
||||
placed[nxt] = true
|
||||
pack_set[nxt] = true
|
||||
pack.append(nxt)
|
||||
for c in placed.keys():
|
||||
board.variants[c] = [String(vrow.variant_id)]
|
||||
|
||||
|
||||
# 片生长待选格收集(本片内各生长格的 8 邻候选并集——未布置、未在途、不与他片贴接)
|
||||
func _variants_fringe(board: BoardData, pack: Array, candidates: Array[Vector2i], placed: Dictionary, pack_set: Dictionary) -> Array[Vector2i]:
|
||||
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) \
|
||||
and not _adjacent_to_packs(board, placed, n, pack_set):
|
||||
fringe.append(n)
|
||||
return fringe
|
||||
|
||||
|
||||
# 候选格是否与其他已布片(own_pack 之外的 placed 格)8 邻贴接——片间隔离保证连通分量 = 单片 ≤ pack_max
|
||||
func _adjacent_to_packs(board: BoardData, placed: Dictionary, c: Vector2i, own_pack: Dictionary = {}) -> bool:
|
||||
for m in board.neighbors8(c):
|
||||
if placed.has(m) and not own_pack.has(m):
|
||||
return true
|
||||
return false
|
||||
@@ -0,0 +1 @@
|
||||
uid://di6u170vqf8ae
|
||||
@@ -308,13 +308,13 @@ fi
|
||||
# 可回放纯逻辑步骤流(同种子同输入逐位复现),await 会打断确定性——「模块归属」B1 行已写明
|
||||
# 「禁 await——切片 88 冒烟实证」。本闸为防回归防线(2026-10-24 人工 grep 盘面干净)。
|
||||
# 扫描面:B1 域文件集(与 architecture.md「模块归属」B1 行同口径)=battle_orchestrator.gd
|
||||
# + battle_fx_host.gd + reward_grant.gd 两拆件 + settlement/ 五段段类 + damage_controller.gd,共 9 文件,显式清单见 S8_FILES。
|
||||
# + battle_fx_host.gd + reward_grant.gd + board_installer.gd 三拆件 + settlement/ 五段段类 + damage_controller.gd,共 10 文件,显式清单见 S8_FILES。
|
||||
# 执行侧字面值豁免:脚本必须带字面值才能工作;文件集与架构文档冲突时以 B1 域文件集为准。
|
||||
# 判据:文件集内出现 await 关键字即红(词边界 \bawait\b,任何形态——await 信号/协程/
|
||||
# get_tree());排除注释行(行首 #/##)与字符串字面量(双引号包裹段内的 await 非代码),
|
||||
# 口径仿 S1/S2 的 grep 排除手法。
|
||||
# 自检:清单内文件缺位(路径写错/被改名)即判红——防扫面为空静默绿。
|
||||
S8_FILES="game/core/battle_orchestrator.gd game/core/battle_fx_host.gd game/core/reward_grant.gd game/core/settlement/aura_segment.gd game/core/settlement/combat_segment.gd game/core/settlement/decay_segment.gd game/core/settlement/grant_segment.gd game/core/settlement/verdict_segment.gd game/core/damage_controller.gd"
|
||||
S8_FILES="game/core/battle_orchestrator.gd game/core/battle_fx_host.gd game/core/reward_grant.gd game/core/board_installer.gd game/core/settlement/aura_segment.gd game/core/settlement/combat_segment.gd game/core/settlement/decay_segment.gd game/core/settlement/grant_segment.gd game/core/settlement/verdict_segment.gd game/core/damage_controller.gd"
|
||||
S8_MISS=0
|
||||
for f in $S8_FILES; do
|
||||
if [ ! -f "$f" ]; then
|
||||
@@ -356,7 +356,7 @@ fi
|
||||
# 自检:扫描面为空即判红(require_scan_face);B1 文件集与三族自家文件缺位即判红
|
||||
# (文件被改名=豁免名单失效,宁可红不可静默放行)。
|
||||
if require_scan_face "S7" "$DIR_CORE"; then
|
||||
S7_B1_SET="game/core/battle_orchestrator.gd game/core/battle_fx_host.gd game/core/reward_grant.gd game/core/settlement/aura_segment.gd game/core/settlement/combat_segment.gd game/core/settlement/decay_segment.gd game/core/settlement/grant_segment.gd game/core/settlement/verdict_segment.gd game/core/damage_controller.gd"
|
||||
S7_B1_SET="game/core/battle_orchestrator.gd game/core/battle_fx_host.gd game/core/reward_grant.gd game/core/board_installer.gd game/core/settlement/aura_segment.gd game/core/settlement/combat_segment.gd game/core/settlement/decay_segment.gd game/core/settlement/grant_segment.gd game/core/settlement/verdict_segment.gd game/core/damage_controller.gd"
|
||||
S7_MISS=0
|
||||
for f in $S7_B1_SET game/core/unit_container.gd game/core/status_container.gd game/core/reward_economy.gd; do
|
||||
if [ ! -f "$f" ]; then
|
||||
|
||||
Reference in new issue
Block a user