迭代11第①批:魔法道具同调实施批 T0-T10 全落(重闸 645/0 + MC off 逐位 PASS)
- T1 表与schema:attunement_growth.tres 谓词表(m1/m2/m3+Σgrant≤slot_cap 校验+slots() 求值口径)+道具表扩列(form/charges/slot_cost/unlock_requires/effective_rounds/charge_n+effect_kinds 九kind+KEY_WHITELIST 零裸flat护栏)+七同调行 - T2 save v4(boss_kill_count 收束入账+attunement_equipped+attune_refresh_level+断点 attunement_charges+迁移链 v3→v4) - T3 Attunement 求值服务(纯函数零 await 零 RNG) - T4 营地装配覆盖层(工坊扩容程序占位+Y 升级行 attune_refresh_upgrade 行族) - T5 被动六件接线+装配注入链+刷新 X/Y 双源(BonusPickOverlay 刷新钮,autoplay 默认不刷) - T6 掘进蓄能全链+摆钟能力面(骑库存面差额注入+断点充能键);炸格 P5 甲影响评估破面大→用户裁拆后批,blast_kit deferred 留位 - T7 退役面五件(BONUS_IDS 除名 aux_item+transitional_sync_slots 过渡键退役=迭代10欠账③清偿+授予路/四容量闸拆除+nest_pendulum 换装 active_charged) - T8 冒烟六新断言(645/0)+MC attune 开关+贪心画像分层 off/on 各 N=60 双策略(on 画像功率显著带平移归调参批;off 新锚=对拍正主留盘主区 sim-data,81000 降批入口基准) - T9 连带修订九件(魔法道具定位重写/元进度v1.6/地图战斗资源v0.16/行动经济v0.7/05不做v1.3/关卡节点地图v1.4/node-reward v2.2/registry 三处/06 收口+炸格拆后批新条) - T10 重闸全绿:冒烟 645/0+熵增 PASS+doc 三闸零新增+MC off 复跑同种子逐位一致 PASS;出口人闸后移迭代 12(用户 2026-10-03 令)
This commit is contained in:
1 parent
02cb92a972
commit
a6a2bf885e
37 files changed
+1075
-173
No files matched your search
+105
-33
@@ -72,6 +72,10 @@ var _base_override := {"atk": 0, "max_hp": 0, "armor_class": 0}
|
||||
var _first_script := false # 首次脚本模式(关卡节点图生成 v0.4——true = 全关零抽签取池内模板 0;测量夹具恒 false) # 永久强化 flat 注入(元进度实现批——冒险开始参数面 params.hero_override 存入,共享给 LevelRunner;全零 = 白板)
|
||||
var _last_aux_cleared := 0 # additive(迭代 7 T4——最近一次关卡末清空计数,summary 取数面)
|
||||
var _aux_unlocked := {} # aux 解锁门控集(迭代 7 T5——params.aux_unlocked 接收面)
|
||||
var _attunement: Array = [] # 同调装配集(迭代 11 第①批 T5——params.attunement 接收面,start_level 外下传 LevelRunner)
|
||||
var _attune_refresh_x := 0 # 刷新件余量(迭代 11 第①批 T5b P1 甲——每碰三选一重置=X 表值;优先消耗、不结转)
|
||||
var _attune_refresh_y := 0 # Y 冒险周期池(开局参数面注入,用完即无——营地升级行表值)
|
||||
var attune_charges := {} # 同调主动件冒险充能账本(迭代 11 第①批 T6——跨关卡共享 dict;settlement use_aux 扣减直改同引用;断点随 attunement_charges 键入档)
|
||||
var _save_manager = null # 断点承载注入(迭代 8 卡①——null = 不写断点;模拟/冒烟缺省)
|
||||
var _resume_bp := {} # 续玩快照暂存(resume_adventure → _start_current_level 单跳传递)
|
||||
# ---- 三选一停点态(迭代 10 奖励重构批)----
|
||||
@@ -112,7 +116,13 @@ func start_adventure(seed_val: int, params: Dictionary = {}) -> bool:
|
||||
_pending_next_level = false
|
||||
_base_override = _normalize_override(params.get("hero_override", {}))
|
||||
_first_script = bool(params.get("first_script", false)) # 缺省 = 非首次(抽签路径;真实侧由呈现层读存档布尔位传入)
|
||||
_aux_unlocked = params.get("aux_unlocked", {}) if params.get("aux_unlocked", {}) is Dictionary else {} # additive(迭代 7 T5)
|
||||
_aux_unlocked = params.get("aux_unlocked", {}) if params.get("aux_unlocked", {}) is Dictionary else {}
|
||||
_attunement = params.get("attunement", []) if params.get("attunement", []) is Array else [] # additive(迭代 11 第①批 T5)
|
||||
_attune_refresh_y = maxi(0, int(params.get("attune_refresh_y", 0))) # additive(迭代 11 第①批 T5b——Y 冒险周期池)
|
||||
_seed_attune_charges() # 迭代 11 第①批 T6——冒险开始充能账本按装备主动件重置(每冒险充能语义) # additive(迭代 7 T5)
|
||||
_attunement = params.get("attunement", []) if params.get("attunement", []) is Array else [] # additive(迭代 11 第①批 T5)
|
||||
_attune_refresh_y = maxi(0, int(params.get("attune_refresh_y", 0))) # additive(迭代 11 第①批 T5b——Y 冒险周期池)
|
||||
_seed_attune_charges() # 迭代 11 第①批 T6——冒险开始充能账本按装备主动件重置(每冒险充能语义)
|
||||
ledger["hero_hp"] = effective_max_hp() # 生命账本置满(生效上限口径——T17 修复:含 TunePanel pct,与战斗内同源)
|
||||
state = "running"
|
||||
return _start_current_level()
|
||||
@@ -168,6 +178,9 @@ func resume_adventure(bp: Dictionary, params: Dictionary = {}) -> bool:
|
||||
int(round(float(int(db.hero.max_hp) + int(_base_override.get("max_hp", 0))) * (100.0 + float(_override[1])) / 100.0))))
|
||||
_first_script = false # 续玩模板已随快照强制(已抽模板零重抽)——脚本模式不重放
|
||||
_aux_unlocked = params.get("aux_unlocked", {}) if params.get("aux_unlocked", {}) is Dictionary else {}
|
||||
_attunement = params.get("attunement", []) if params.get("attunement", []) is Array else [] # additive(迭代 11 第①批 T5)
|
||||
_attune_refresh_y = maxi(0, int(params.get("attune_refresh_y", 0))) # additive(迭代 11 第①批 T5b——Y 冒险周期池)
|
||||
_seed_attune_charges() # 迭代 11 第①批 T6——冒险开始充能账本按装备主动件重置(每冒险充能语义)
|
||||
# 三选一停点续玩分支(迭代 10——选择态/已兑付态不重跑关卡;奖励选择态不重抽、已兑付不重付)
|
||||
var bp_pending: Dictionary = bp.get("bonus_pending", {}) as Dictionary
|
||||
var bp_result: Dictionary = bp.get("bonus_result", {}) as Dictionary
|
||||
@@ -197,6 +210,10 @@ func resume_adventure(bp: Dictionary, params: Dictionary = {}) -> bool:
|
||||
bonus_resolved.emit(_bonus_result.duplicate(true))
|
||||
return true
|
||||
_resume_bp = bp.duplicate(true)
|
||||
# 迭代 11 第①批 T6——充能账本随断点回局(缺键 = 旧档/无断点,保持 _seed_attune_charges 种子态)
|
||||
var bp_charges = bp.get("attunement_charges", null)
|
||||
if bp_charges is Dictionary:
|
||||
attune_charges = (bp_charges as Dictionary).duplicate(true)
|
||||
state = "running"
|
||||
return _start_current_level()
|
||||
|
||||
@@ -315,15 +332,11 @@ func _pick_aux_item(count: int) -> bool:
|
||||
push_error("[冒险结构] pick_bonus(aux_item) 拒绝——解锁道具池空集(白板/门控态不入牌库的防御兜底)")
|
||||
return false
|
||||
var hp_before := int(ledger.get("hero_hp", 0))
|
||||
if AuxItems.can_accept(picked.size(), _bonus_aux_carry.size(), db): # 同调位守卫单点(2026-10-02)
|
||||
for iid in picked:
|
||||
_bonus_aux_carry.append(String(iid))
|
||||
_finish_bonus_pick("aux_item", picked.size(), hp_before)
|
||||
return true
|
||||
# 满位替换子交互:现有持有件 + 新件 N+1 选 N(丢旧收新 / 放弃新件两路,终态恒 ≤ 同调位)
|
||||
_bonus_pending["chosen"] = "aux_item"
|
||||
_bonus_pending["incoming"] = picked.duplicate()
|
||||
aux_replace_presented.emit(_carry_records(), {"index": -1, "item_id": String(picked[0]), "count": picked.size()})
|
||||
# 迭代 11 第①批 T7——同调位守卫随过渡键退役拆除(aux 卡出池后本路径不可达;能力件容量闸
|
||||
# 正主 = 营地装配面 Attunement.slots 满位禁选)
|
||||
for iid in picked:
|
||||
_bonus_aux_carry.append(String(iid))
|
||||
_finish_bonus_pick("aux_item", picked.size(), hp_before)
|
||||
return true
|
||||
|
||||
|
||||
@@ -372,6 +385,7 @@ func node_bonus_candidates() -> Dictionary:
|
||||
|
||||
|
||||
func present_node_bonus(candidates: Array, aux_detail: Array = []) -> void:
|
||||
_reset_refresh_x() # 迭代 11 第①批 T5b——碰三选一重置 X 余量(不结转)
|
||||
_node_bonus_pending = {"candidates": candidates.duplicate(true), "aux_detail": aux_detail.duplicate(true)}
|
||||
|
||||
|
||||
@@ -405,18 +419,14 @@ func _apply_node_aux(count: int) -> bool:
|
||||
var records: Array = []
|
||||
if _runner != null and _runner.aux_inventory != null:
|
||||
records = _runner.aux_inventory.holding_records()
|
||||
var holding := records.size() + _bonus_aux_carry.size()
|
||||
if AuxItems.can_accept(picked.size(), holding, db): # 同调位守卫单点(2026-10-02)
|
||||
if _runner != null:
|
||||
for iid in picked:
|
||||
var rec: Dictionary = _runner.grant_aux_item(String(iid), "reward_node")
|
||||
if rec.is_empty():
|
||||
push_warning("[冒险结构] 奖励节点道具授予被拒(防御兜底留痕): %s" % String(iid))
|
||||
_finish_node_bonus("aux_item", picked.size())
|
||||
return true
|
||||
_node_bonus_pending["chosen"] = "aux_item"
|
||||
_node_bonus_pending["incoming"] = picked.duplicate()
|
||||
aux_replace_presented.emit(records, {"handle": -1, "item_id": String(picked[0]), "count": picked.size()})
|
||||
# 迭代 11 第①批 T7——守卫随过渡键退役拆除(BONUS_IDS 已除名 aux_item,本分支不可达;
|
||||
# 替换子交互路由随容量闸一并退役——能力件容量闸正主 = 营地装配面满位禁选)
|
||||
if _runner != null:
|
||||
for iid in picked:
|
||||
var rec: Dictionary = _runner.grant_aux_item(String(iid), "reward_node")
|
||||
if rec.is_empty():
|
||||
push_warning("[冒险结构] 奖励节点道具授予被拒(防御兜底留痕): %s" % String(iid))
|
||||
_finish_node_bonus("aux_item", picked.size())
|
||||
return true
|
||||
|
||||
|
||||
@@ -436,6 +446,71 @@ func _resolve_node_replace(discard_handle: int) -> bool:
|
||||
return true
|
||||
|
||||
|
||||
# 冒险开始充能账本重置(T6——装备 active_charged 件各回 charges_per_adventure;被动件不入账)
|
||||
func _seed_attune_charges() -> void:
|
||||
attune_charges = {}
|
||||
for iid in _attunement:
|
||||
var arow: Dictionary = db.aux_item_row(String(iid))
|
||||
if String(arow.get("form", "")) == "active_charged":
|
||||
attune_charges[String(iid)] = maxi(0, int(arow.get("charges_per_adventure", 0)))
|
||||
|
||||
|
||||
# ---- 三选一刷新(迭代 11 第①批 T5b——P1 甲 X/Y 双源:X=刷新件每碰三选一重给〔优先消耗、不结转〕、
|
||||
# Y=营地升级行冒险周期池〔用完即无〕;重抽消费 reward_pick 既有洗牌流,池规则全保留——不放回/
|
||||
# 达上限剔牌/掷定前置直显;停点可中断)----
|
||||
|
||||
func _attune_refresh_x_total() -> int:
|
||||
return int(db.aux_item_row("pick_refresh").get("magnitude", 0)) if _attunement.has("pick_refresh") else 0
|
||||
|
||||
|
||||
func _reset_refresh_x() -> void:
|
||||
_attune_refresh_x = _attune_refresh_x_total()
|
||||
|
||||
|
||||
# 当前可刷新次数(X 优先 + Y 池——呈现层余量读数口)
|
||||
func attune_refresh_left() -> int:
|
||||
return _attune_refresh_x + _attune_refresh_y
|
||||
|
||||
|
||||
# 节点停点在途态读回(组合根重 present 用——candidates/aux_detail 值拷贝)
|
||||
func node_bonus_pending_state() -> Dictionary:
|
||||
return {
|
||||
"candidates": (_node_bonus_pending.get("candidates", []) as Array).duplicate(true),
|
||||
"aux_detail": (_node_bonus_pending.get("aux_detail", []) as Array).duplicate(true),
|
||||
}
|
||||
|
||||
|
||||
# 三选一刷新(组合根唯一调用口;无停点/无余量 false 零副作用)。通关停点重抽后重发
|
||||
# bonus_choice_presented(呈现层重建卡片+刷新余量);节点停点由组合根读 node_bonus_pending_state 重 present。
|
||||
func refresh_bonus() -> bool:
|
||||
if _attune_refresh_x <= 0 and _attune_refresh_y <= 0:
|
||||
return false
|
||||
if not _bonus_pending.is_empty():
|
||||
if _attune_refresh_x > 0:
|
||||
_attune_refresh_x -= 1
|
||||
else:
|
||||
_attune_refresh_y -= 1
|
||||
var cands: Array = _draw_bonus_candidates()
|
||||
_bonus_pending["candidates"] = cands.duplicate(true)
|
||||
_bonus_pending["aux_detail"] = _last_draw_aux.duplicate()
|
||||
var payload: Dictionary = (_bonus_pending.get("payload", {}) as Dictionary).duplicate(true)
|
||||
payload["candidates"] = cands
|
||||
payload["aux_detail"] = _last_draw_aux.duplicate()
|
||||
bonus_choice_presented.emit(payload) # 同信号重 present(零自动推进契约不破——停点仍在途)
|
||||
_snapshot_breakpoint()
|
||||
return true
|
||||
if not _node_bonus_pending.is_empty():
|
||||
if _attune_refresh_x > 0:
|
||||
_attune_refresh_x -= 1
|
||||
else:
|
||||
_attune_refresh_y -= 1
|
||||
var cands2: Array = _draw_bonus_candidates()
|
||||
_node_bonus_pending["candidates"] = cands2.duplicate(true)
|
||||
_node_bonus_pending["aux_detail"] = _last_draw_aux.duplicate()
|
||||
return true
|
||||
return false
|
||||
|
||||
|
||||
# 替换在途守卫(2026-10-02 修复批——双渠道替换受理的共用前置谓词:停点态非空且 chosen=aux_item)
|
||||
func _replace_in_transit(pending: Dictionary) -> bool:
|
||||
return not pending.is_empty() and String(pending.get("chosen", "")) == "aux_item"
|
||||
@@ -501,12 +576,8 @@ func _draw_bonus_candidates() -> Array:
|
||||
keyed.sort_custom(func(a, b): return float(a["key"]) > float(b["key"]))
|
||||
var out: Array = []
|
||||
for i in mini(int(db.adventure.bonus_candidate_count), keyed.size()): # 候选数读表(2026-10-02 魔法数结构化——默认 3 = 现行行为)
|
||||
var cid := String(keyed[i]["id"])
|
||||
out.append(cid)
|
||||
if cid == "aux_item":
|
||||
var roll_rg: RandomNumberGenerator = rng.open_stream("reward_pick")
|
||||
for j in maxi(1, int(db.adventure.bonus_aux_item_count)):
|
||||
_last_draw_aux.append(_roll_from(roll_rg))
|
||||
out.append(String(keyed[i]["id"]))
|
||||
# 迭代 11 第①批 T7——aux_item 掷定前置分支随池种退役拆除(BONUS_IDS 已除名,候选恒无 aux 卡)
|
||||
return out
|
||||
|
||||
|
||||
@@ -592,11 +663,10 @@ func _start_current_level() -> bool:
|
||||
var ok: bool = _runner.start_level_external(level_index, ledger, bonus, purchased,
|
||||
Callable(self, "apply_rest"), _base_override, true, template_pick, resume_state)
|
||||
if ok:
|
||||
# 三选一道具件跨关携带注入(迭代 10——上关兑付的道具件进本关库存〔奖励只朝下一战生效〕;
|
||||
# 注入即移交——carry 清空,本关末随关卡域库存清空)
|
||||
for iid in _bonus_aux_carry:
|
||||
_runner.grant_aux_item(iid, "bonus_pick")
|
||||
_bonus_aux_carry = []
|
||||
_runner.set_attunement(_attunement) # 迭代 11 第①批 T5——同调装配下传(enc 携带进战斗结算)
|
||||
_runner.set_attune_charges(attune_charges) # 迭代 11 第①批 T6——充能账本下传(能力件骑库存面注入)
|
||||
# 三选一道具件跨关携带注入(迭代 10)——迭代 11 第①批 T7 退役:aux 卡出池后 carry 恒空集,
|
||||
# 注入面随停点渠道退役拆除(容器字段保留=替换子交互机械惰性承载,零投放零行为)
|
||||
level_started.emit(level_index, String(_runner.level_row.get("display_name", "")))
|
||||
# 入口停点断点(node_id=-1)与 defer_entry 同态(node_index=-1+单候选)——走入口呈现;
|
||||
# 中途停点(node_id>=0)走停点呈现(restore_aux_items 先于呈现=C 区库存就位)。
|
||||
@@ -635,6 +705,7 @@ func _on_level_finished(payload: Dictionary) -> void:
|
||||
ledger["hero_hp"] = hp_before + heal
|
||||
# 置位先于 emit(信号同步派发——处理器内立即确认时 _pending_next_level 必须已就位)
|
||||
_pending_next_level = true
|
||||
_reset_refresh_x() # 迭代 11 第①批 T5b——碰三选一重置 X 余量(不结转)
|
||||
var pick_payload: Dictionary = {
|
||||
"level_index": level_index,
|
||||
"candidates": _draw_bonus_candidates(),
|
||||
@@ -724,6 +795,7 @@ func _snapshot_breakpoint() -> void:
|
||||
},
|
||||
"gp": int(ledger.get("gp", 0)),
|
||||
"shop_purchased": purchased.duplicate(true),
|
||||
"attunement_charges": attune_charges.duplicate(true), # 迭代 11 第①批 T6——同调主动件充能余量随断点(save v4 域)
|
||||
"template_pick": _runner.active_template_index if _runner != null else -1,
|
||||
"master_seed": master_seed,
|
||||
"rng_counter": rng.counter(),
|
||||
|
||||
Reference in new issue
Block a user