Files
gplan-2/game/core/attune_loadout.gd
T

118 lines
6.1 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.
## 同调配装件:装备中的秘宝件对象集唯一所有者(每件内含充能单位与重置周期——冒险域拆分姊妹批自共享充能账字典轨迁移)。
## 同调充能单源化:物化行(treasure_inventory 内 source_class="attunement" 行)为使用面唯一事实源——
## 剩余次数由行的未用数派生(唯一读法,无影子账);字典轨与三处事后差额对账退役,改「写时种行/补行」。
## 种行/补行写时同步:冒险开始全量种行(不筛周期——battle/level 周期件开局即有行,C 区投影行数不变);
## battle/level 周期回满走 reset_cycle(已耗 handle 不回收=作废、差额补新——语义逐字承原编排器重置);
## 同调未用行跨关存活(关卡域库存提为冒险级共享、关末清空改选择性保留——单源化的行承载前提)。
## 旧档读侧以行集为源恢复使用面,attunement_charges 键读值仅作一致性校验读数(不符记日志不 fatal——键值本就派生自行)。
## Core 层零 UI;零随机(充能域无 RNG 消费);随机无关、数值只读 db。
class_name AttuneLoadout
extends RefCounted
var db: ConfigDb
var _ids: Array[Variant] = [] # 装配集(活引用注入——宿主 start/resume 时点下传)
func _init(db_ref: ConfigDb, attunement_ids: Array) -> void:
db = db_ref
set_attunement(attunement_ids)
# 装配集注入(活引用——宿主 start_adventure/resume 参数面锁定后下传)
func set_attunement(attunement_ids: Array) -> void:
_ids = attunement_ids
func item_ids() -> Array:
return _ids.duplicate()
# ---- 写时种行/补行(替代三处事后差额对账)----
# 冒险开始:全部 active_charged 件种行(**不筛周期**——承现 _seed_attune_charges 全量种账+sync 全量投行
# 语义;battle/level 周期件开局即有行,C 区投影行数不变)
func seed_for_adventure(inventory: TreasureItems) -> void:
for iid_v in _ids:
var iid := String(iid_v)
var arow: Dictionary[Variant, Variant] = db.treasure_item_row(iid)
if String(arow.get("form", "")) != "active_charged":
continue
_ensure_rows(iid, maxi(0, int(arow.get("charges_per_adventure", 0))), inventory)
# battle/level 周期回满(**按周期筛**;已耗行作废、差额补新——语义逐字承原编排器 _reseed_attune_charges;
# charges_per_adventure=0=自动兑付件不入使用面〔试炼镐——不走骑库存面〕)
func reset_cycle(cycle: String, inventory: TreasureItems) -> void:
for iid_v in _ids:
var iid := String(iid_v)
var arow: Dictionary[Variant, Variant] = db.treasure_item_row(iid)
if String(arow.get("form", "")) != "active_charged":
continue
if String(arow.get("charge_reset", "adventure")) != cycle:
continue
var want := int(arow.get("charges_per_adventure", 0))
if want < 1:
continue # charges=0=自动兑付件(不走骑库存面,兑付=积点段自动 grant_ap)
_ensure_rows(iid, want, inventory)
# 差额补行单点(未用行数不足 want 即补——「差额注入防续玩双份」现役语义逐字)
func _ensure_rows(iid: String, want: int, inventory: TreasureItems) -> void:
var existing := 0
for r in inventory.snapshot_inventory():
if String(r.item_id) == iid and String(r.source_class) == "attunement" and not bool(r.used):
existing += 1
for i in range(maxi(0, want - existing)):
inventory.add_item(iid, "attunement", Vector2i(-1, -1), 0)
# ---- 使用面(战斗路径改指)----
# 充能消耗(承原 attune_charge_consume「扣账 -1」语义——单源化后=行标 used 幂等承载:
# 使用管线 consume 句柄已标行 used,本口兜底标未用行〔双入口同点防御——行 used 不可逆幂等〕)
func consume_charge(item_id: String, inventory: TreasureItems) -> void:
for r in inventory.snapshot_inventory():
if String(r.item_id) == item_id and String(r.source_class) == "attunement" and not bool(r.used):
inventory.consume(int(r.handle)) # 行标 used(与使用管线 consume 同口——幂等兜底)
return
# ---- 读面(行派生——唯一读法)----
# 剩余次数(未用行数派生——原字典轨读数逐位等价)
func charges_left(item_id: String, inventory: TreasureItems) -> int:
var n := 0
for r in inventory.snapshot_inventory():
if String(r.item_id) == item_id and String(r.source_class) == "attunement" and not bool(r.used):
n += 1
return n
# ---- 断点自交片段(应用层拼盘口收件——键名与策略不变)----
# attunement_charges 键(值形状=原字典轨 {item_id:剩余}——由行派生,键名/策略不变)
func breakpoint_fragment(inventory: TreasureItems) -> Dictionary[Variant, Variant]:
var charges: Dictionary[Variant, Variant] = {}
for iid_v in _ids:
var iid := String(iid_v)
var arow: Dictionary[Variant, Variant] = db.treasure_item_row(iid)
if String(arow.get("form", "")) == "active_charged":
charges[iid] = charges_left(iid, inventory)
return {"attunement_charges": charges}
# 旧档读侧(以行集为源恢复使用面——键值仅校验读数:不符记日志不 fatal;缺键保持种子态=原语义)。
# 调用时点=行集已随 aux_items 回填(恢复链序:库存回填先于本口)。
func restore_fragment(frag: Dictionary, inventory: TreasureItems) -> void:
var stored: Variant = frag.get("attunement_charges", null)
if not (stored is Dictionary) or (stored as Dictionary).is_empty():
return # 缺键 = 旧档/无断点,保持种子态(原语义)
for iid in (stored as Dictionary).keys():
var derived := charges_left(String(iid), inventory)
var recorded := int((stored as Dictionary)[iid])
if derived != recorded:
# 跨版续玩兜底:改前档关卡完成停点的同调行已被关末清空(键在行缺)——按键值差额补行,
# 使用面与改前字典轨续玩逐位等价;新档行集为源时差额=0 零操作(行集仍为读数唯一来源)
push_warning("[同调配装] 充能校验读数与行派生不一致(%s 档=%d 行派生=%d——按键值差额补行)"
% [String(iid), recorded, derived])
_ensure_rows(String(iid), recorded, inventory)