主卡T2(拆件批wr2/wr3): CurioStop建件+CurioDeck纯池化——curio_stop.gd新件(停点三态/刷新三源账/兑付族/凭证出箱voucher_outbox/信号面自带/rebind_level_runner每关注入GP回调防调死对象/open_level_clear收编关卡完成停点段);adventure_runner停点面迁出(停点方法族留组合根薄委托——T5 C类收口;stop()件出口;信号中继法转发——T3直连前承转;_resume_pending迁stop.restore_pending含token_migration;resume已兑付分支stop.restore_resolved;_bp_parts停点键改stop片段取数);CurioDeck纯池化(bind_handlers/consume_pool_purchase反向回调退役——商店消费链ShopSession→注入Callable→stop.consume_pool_purchase兑付单点);测试挂死级改址随批(直读写已迁字段30+处→stop()件测试构造面,语义=原直写——G2b清单停点域全部);cs1/cs2/cs3现役断言承继尾缀落点(拆件批 V2/V3)。验收:bp1对拍292dumps×27键逐位零漂移(改前/after_T1/after_T2三时点同种子逐位一致)+九套件零红+csf集成绿+冒烟17项0失败〔拆件批 V2〕〔拆件批 V3〕

This commit is contained in:
DKChan committed 2026-10-27 03:04:22 +08:00
1 parent 8d7b12e063
commit 4a9e4300ad
31 files changed
+189353 -709

No files matched your search

+45 -66
View File
@@ -2,7 +2,7 @@
## 关卡域生命周期编排者:节点图行进、HP 跨战斗携带、恢复点兑付、关卡末收束(垂直切片验证:一关内数值提升可感知);商店族归 ShopSession 件。
## Core 层零 UI 依赖(headless 可跑完整关卡);零自动推进——兑付确认后经 choices_presented,推进只走 pick_next_node。
## 种子域:单关模式 start_level 自播种;冒险模式 start_level_external 不重播种(主种子恰一次归 AdventureRunner)。
## hero_atk_pct/hero_hp_pct 为测试专用覆盖——经 encounter 显式传入战斗,零表写,db.hero 运行期只读。
## 调试浮窗百分比通道单点归主角账(set_hero_override 转调——公式消费面同源)。
## 信号顺序契约:呈现层须在 level_started 回调重取 runner 实例,choices_presented 才不会被空防御丢弃。
class_name LevelRunner
extends RefCounted
@@ -22,18 +22,20 @@ var node_index := -1
# ---- 账本载体(冒险结构实现批——漂移②清偿)----
# 冒险模式 = AdventureRunner 共享字典(Dictionary 引用共享——hero_hp/gp 属性读写直接落冒险账本);
# 单关模式 = 本实例私有账本(start_level 重建,既有单关语义逐位保留)。
var _ledger: Dictionary[Variant, Variant] = {"hero_hp": 0, "gp": 0}
var level_counters: Dictionary[Variant, Variant] = {} # 关卡桶(lvl_ 前缀计数器;每关随 LevelRunner new 天然空=按关清零,替代旧硬编码清除名单)
var _rest_handler: Callable # 治疗封顶回报执行体(默认内置 rest_heal_amount;冒险模式 = AdventureRunner.apply_rest——接口③)
var _external := false # 冒险模式标记(钱包收束时机与播种语义分叉点)
# hero_hp / gp 属性化(既有读写点零改动——值类型经属性落 _ledger)
# 主角账引用(拆件批 T1 过渡面:冒险模式经 set_hero 注入共享实体账、单关模式 _init 自建私有账;
# 构造注入收口归 T3 ctx 面——后置 setter 随构造注入一并退役)
var _hero: HeroLedger = HeroLedger.new(null, {}) # 直构缺省私有账(db 随 _init 补)
var _adv_bucket: Dictionary[Variant, Variant] = {} # 冒险桶(效果引擎 adv_ 计数器宿主字典——冒险模式随 hero 注入;单关=本实例自有)
# hero_hp / gp 属性化(既有读写点零改动——值类型经属性落主角账)
var hero_hp: int:
get: return int(_ledger["hero_hp"])
set(v): _ledger["hero_hp"] = v
get: return _hero.hero_hp
set(v): _hero.hero_hp = v
var gp: int: # GP 冒险钱包(局内货币——冒险开始 = 0、收束清零;不入存档不入摘要)
get: return int(_ledger["gp"])
set(v): _ledger["gp"] = v
var base_override := {"atk": 0, "max_hp": 0, "armor_class": 0} # 永久强化 flat 注入(元进度实现批——冒险模式 = AdventureRunner 共享字典经 start_level_external 注入;单关测试模式 = 私有全零)
get: return _hero.gp
set(v): _hero.gp = v
var _shop: ShopSession = null # 商店件(_init 建;双模式货架/定价/购买/刷新唯一宿主)
# 协作对象私有(E1/E3 封装收口):settlement 读取经 current_battle() 成文出口
var _settlement: BattleOrchestrator = null # 当前战斗编排器(关卡结束置 null)
@@ -61,12 +63,7 @@ var _shop_visit_buys: int:
get: return _shop.visit_buys
var _shop_paid_refreshes: int:
get: return _shop.paid_refreshes
var _shop_purchased: Dictionary[Variant, Variant]: # product_id → 已购档数(现价重算输入;冒险开始清零)
get: return _shop.purchased
set(v): _shop.purchased = v
var hero_atk_pct := 0 # 测试面板覆盖值(切片专用)
var hero_hp_pct := 0
# ---- 关卡相位轴(显式 Phase enum:内部 enum + 守卫换算,对齐 行动经济 Phase 先例;
# level_result:String 与 awaiting_choice() 是 AdventureRunner/呈现层消费的外部契约面)----
enum Phase { IDLE, RUNNING, AWAITING_CHOICE, ENDED }
@@ -80,6 +77,7 @@ var _generator # 参数化长图生成器(惰性建——NodeMapGenerator
func _init(db_ref: ConfigDb, rng_ref: RngServiceCore) -> void:
db = db_ref
rng = rng_ref
_hero.db = db # 直构私有账补表引用(构造参形态 T3 收口)
_shop = ShopSession.new(db, rng)
_bind_shop()
@@ -92,49 +90,31 @@ func _is_running() -> bool:
# ---- 测试面板覆盖(模拟天赋树属性提升——仅测试用,正式侧归 元进度;经 encounter 传入战斗)----
func set_hero_override(atk_pct: int, hp_pct: int) -> void:
hero_atk_pct = atk_pct
hero_hp_pct = hp_pct
_hero.set_debug_override(atk_pct, hp_pct)
# 叠加次序(钉死):表值 → 永久强化 flat(base_override)→ 加算区 flat(bonus)先加
# → 调试浮窗百分比后乘(调试数值工具恒乘最后)
# 生效公式单点归主角账(拆件批 T1——本类删公式本体,读面转调;叠加次序注释随公式迁主角账)
func effective_atk() -> int:
var base: int = int(db.hero.atk) + int(base_override.get("atk", 0)) + int(run_ledger.bonus.get("atk", 0))
return maxi(1, int(round(float(base) * (100.0 + float(hero_atk_pct)) / 100.0)))
return _hero.effective_atk()
func effective_max_hp() -> int:
var base: int = int(db.hero.max_hp) + int(base_override.get("max_hp", 0)) + int(run_ledger.bonus.get("max_hp", 0))
return maxi(1, int(round(float(base) * (100.0 + float(hero_hp_pct)) / 100.0)))
return _hero.effective_max_hp()
# 护甲等级生效值(入战 AC 三层可加:甲型基础 AC〔forge.tres 选中甲路线 base_ac〕+
# 甲路线等级加值〔base_override.armor_class——hero_override 锻造分量〕+ 加算区 armor_class 轴;
# 无调试浮窗百分比通道,纯 flat)
func effective_ac() -> int:
return maxi(0, _armor_base_ac() + int(base_override.get("armor_class", 0)) + int(run_ledger.bonus.get("armor_class", 0)))
# 甲型基础 AC(三层之第一层——选中甲路线行 base_ac;未注入/缺行=锻造配置默认值路线=轻甲 10,
# 与 hero.tres 两轴删除前 armor_class=10 行为连续)
func _armor_base_ac() -> int:
var at: String = _hero_armor_type if _hero_armor_type != "" else db.forge_default_armor_type()
var row: Dictionary[Variant, Variant] = db.forge_armor_route_by_type(at)
if row.is_empty():
return int(db.hero.armor_class) # 表缺失防御兜底(现役基准)
return int(row.get("base_ac", 0))
return _hero.effective_ac()
# 行动点加成生效值(统一冒险加算区第四轴 ap;经战斗开始入参 hero_ap_bonus
# 传入战斗域,兑现 = 每场战斗开始首轮行动点基线 +加成值〔行动经济 GDD 跨冒险行动点加成轴节〕)
func effective_ap_bonus() -> int:
return maxi(0, int(run_ledger.bonus.get("ap", 0)))
return maxi(0, _hero.bonus_total("ap"))
# 覆盖复位(关卡结束归零——表值不可变,仅清百分比;调用方兼容保留)
func restore_hero_base() -> void:
hero_atk_pct = 0
hero_hp_pct = 0
_hero.set_debug_override(0, 0)
# ---- 关卡生命周期 ----
@@ -148,7 +128,6 @@ func start_level(level_index: int, seed_val: int, base_override_in: Dictionary =
# 注入面只服务数值验证工具,非玩家可达路径)
_external = false
_rest_handler = rest_heal_amount
_ledger = {"hero_hp": 0, "gp": 0}
var row := _find_level_row(level_index)
if row.is_empty():
push_error("[关卡节点地图] level_index %d 在 LevelTable 无行" % level_index)
@@ -158,14 +137,8 @@ func start_level(level_index: int, seed_val: int, base_override_in: Dictionary =
_phase = Phase.IDLE
_candidates = []
visited = []
gp = 0 # 冒险钱包清零开局(局内货币生命周期起点)
run_ledger.bonus = {"atk": 0, "max_hp": 0, "armor_class": 0} # 加算区冒险开始全 0(单关入口零元进度——注入面见上)
base_override = {"atk": 0, "max_hp": 0, "armor_class": 0} # 永久强化 flat:缺省全零白板(单关入口零元进度——注入面见上)
_shop_purchased = {} # 已购档数清零(跨冒险不延续——递增定价按冒险内累计)
_bind_shop() # 钱包引用换代重绑(_ledger 已重建)
for k in base_override.keys():
base_override[k] = maxi(0, int(base_override_in.get(k, 0))) # 注入规范化(契约同冒险开始参数面)
hero_hp = effective_max_hp()
_hero.rebase_override(base_override_in) # 永久强化 flat 重注(规范化归主角账——契约同冒险开始参数面)
_hero.reset_for_single_level() # 账面值重置(钱包/加算区/已购档/钥石/日记清零+生命置满——实例不重建,shop 绑定不换代)
rng.new_adventure(seed_val) # 关卡起点 = 冒险起点(切片口径;跨关接续归 冒险结构)
if not _assign_generated_graph(row, seed_val):
_phase = Phase.ENDED
@@ -179,30 +152,24 @@ func start_level(level_index: int, seed_val: int, base_override_in: Dictionary =
return _enter_node(entries[0])
# 冒险结构接口①:开始关卡(载荷 = 关卡序号 + 当前生命 + 生效上限——生命经共享账本交接;
# 种子域归冒险结构:本路径不重播种;账本归冒险结构:本路径不重置 gp/bonus/_shop_purchased,
# 也不重置 hero_hp——账本当前值即开局生命,AdventureRunner 已在 ledger 写好)。
# base_override = 永久强化 flat 共享引用(缺省 {} 全零白板,与 B1 空参数路径同值)。
# 冒险结构接口①:开始关卡(载荷 = 关卡序号 + 当前生命 + 生效上限——生命经主角账共享交接;
# 种子域归冒险结构:本路径不重播种;账本归冒险结构:本路径不重置 gp/加算区/已购档,
# 也不重置 hero_hp——账本当前值即开局生命,AdventureRunner 已在主角账写好)。
# 流程与 start_level 同款(_find_level_row → 生成图装配 → 状态初始化 → _enter_node(入口)),
# 差异仅在账本/加算区/已购档/恢复执行体的注入与零重置。
# 差异仅在恢复执行体的注入与零重置(主角账/冒险桶经 set_hero 注入——T1 过渡面,T3 收构造)。
# defer_entry 尾参(缺省 false = 直接进节点)——true 时不自动
# _enter_node(entry),改置选路态(awaiting_choice + 单候选 = 入口节点),由 AdventureRunner 在
# level_started 之后调 present_entry_choice() 呈现、玩家 pick_next_node 显式进首战。拆两步的
# 信号顺序契约:呈现层须先经 level_started 重取 runner 实例,choices_presented 才不会被
# _on_choices_presented 的 runner 空防御静默丢弃。入口呈现零 RNG 消耗、pick 走同一个
# _enter_node(entry)——测量面零漂移红线。
func start_level_external(level_index: int, ledger: Dictionary,
purchased_ref: Dictionary, rest_handler: Callable, base_override_ref: Dictionary = {},
func start_level_external(level_index: int, rest_handler: Callable,
defer_entry: bool = false, resume_state: Dictionary = {}) -> bool:
var row := _find_level_row(level_index)
if row.is_empty():
push_error("[关卡节点地图] level_index %d 在 LevelTable 无行" % level_index)
return false
_external = true
_ledger = ledger
base_override = base_override_ref
_shop_purchased = purchased_ref
_bind_shop() # 钱包共享引用换代重绑(_ledger = 冒险账本)
_rest_handler = rest_handler
if not _assign_generated_graph(row, rng.master_seed):
return false
@@ -516,7 +483,9 @@ func _start_battle(node: Dictionary) -> bool:
"hero_armor_class": effective_ac(), "hero_ap_bonus": effective_ap_bonus(),
"attack_type": _hero_attack_type, "armor_type": _hero_armor_type, # 两根类型轴(spawn 英雄快照;空串=锻造配置默认值回退)
"attunement": _attunement,
"ledger": run_ledger, # 共享四账单类下传(单引用键)
"ledger": run_ledger, # 充能账瘦壳下传(单引用键——bonus/真视/桶已迁主角账与冒险桶)
"hero": _hero, # 主角实体账下传(战末 bonus 汇入/真视计数单写原语消费面)
"adv_bucket": _adv_bucket, # 冒险桶下传(效果引擎 adv_ 计数器宿主字典——跨战持久同一引用)
"level_counters": level_counters, # 关卡桶下传(同关跨战共享引用、随本类 new 天然空)
"feats": _feats,
"tree_rules": _tree_rules,
@@ -677,15 +646,26 @@ func set_hero_axes(attack_type: String, armor_type: String) -> void:
_hero_armor_type = armor_type
# 共享四本账注入(RunLedger 单类下传,含 bonus/attune_charges/
# vision_counter/adventure_counters 四账;战斗侧只走账类原语,战末 export/开局 seed
# 时点语义不变)
# 共享充能账瘦壳注入(RunLedger 瘦身后只承载 attune_charges;战斗侧只走账类原语)
var run_ledger: RunLedger = RunLedger.new()
# 主角账只读出口(加算区生产读面承接—— AdventureRunner.hero() 同款组件交出)
func hero() -> HeroLedger:
return _hero
# 主角实体账注入(冒险模式共享 AdventureRunner 建件——生命/钱包/加算区/类型轴/特性集单点;
# 随行注入冒险桶引用。T1 过渡 setter——T3 构造注入收口后本组 setter 退役)
func set_hero(h: HeroLedger, adv_bucket: Dictionary) -> void:
_hero = h
_adv_bucket = adv_bucket
_bind_shop() # 账面换代重绑(钱包/购买加算落点面)
func set_run_ledger(l: RunLedger) -> void:
run_ledger = l
_bind_shop() # 账类换代重绑(加算区 flat 落点面)
_bind_shop() # 账类换代重绑(充能账读数面)
# 凭证件三账注入(储备金袋 RAP/时沙 首轮 AP/完美保险 标错豁免;节点级一次性,
@@ -753,11 +733,10 @@ func close_wallet() -> void:
# 实装归 ShopSession 件(双模式货架/定价/购买/刷新唯一宿主);本类保留同签名委托与件注入/
# 白盒入口——外部调用面与断点取数面零变化。
# 件注入(建件与宿主引用换代时调用——钱包/账类/图行/装配集为共享引用,出账直接落同一引用)
# 件注入(建件与宿主引用换代时调用——钱包/主角账/图行/装配集为共享引用,出账直接落同一引用)
func _bind_shop() -> void:
_shop.bind({
"wallet": _ledger,
"run_ledger": run_ledger,
"hero": _hero,
"level_row": level_row,
"tree_rules": _tree_rules,
"attunement": _attunement,