## 加算日记件:统一冒险加算区与获得记录唯一所有者。获得记录三层结构=获得记录列表 ## (_record_gain 追加、返回记录 id)→ 属性增益明细(带来源指回)→ 四轴汇总(由明细同步维护; ## summary 与断点读汇总,日记为现行事实源)。三写通道统一走 gain_bonus 单写原语:三选一属性件 ## (source_class="curio_pick")/商店属性商品("shop_product"、kind=product_id)/战末导出 ## ("battle_export"、kind=轴名)。本局钥石增量与逐杀明细、真视使用记录、商店已购档数记账同域。 ## 生命与钱包各归 HeroStats/GpWallet——主角账三件各交各的断点片段,拼盘落盘归冒险应用层。 ## Core 层零 UI;随机零消费。 class_name GainJournal extends RefCounted # 加算区四轴(键序即断点 bonus 键序——与拆件前共享账置账形态逐位同形) const BONUS_AXES: Array[String] = ["atk", "max_hp", "armor_class", "ap"] var _gain_log: Array[Variant] = [] # 获得记录列表(三选一件/商店购买/战末奖励各一条) var _bonus_detail: Array[Variant] = [] # 属性增益明细(带来源指回 gain_id) var _bonus_total: Dictionary[Variant, Variant] = {"atk": 0, "max_hp": 0, "armor_class": 0, "ap": 0} var _keystone := 0 # 钥石入账累计(摘要第三件事的账面) var _keystone_drops: Array[Variant] = [] # Boss 逐杀掉落明细(additive 摘要键 keystone_drops) var _vision_used := 0 # 真视使用记录(本局计数——冒险收束聚合入档) var _purchased: Dictionary[Variant, Variant] = {} # product_id → 已购档数(递增定价输入;冒险开始清零) # ---- 获得记录三层 ---- # 获得记录列表追加(三通道各一条——source_class 词表:curio_pick/shop_product/battle_export; # 返回记录 id 供明细来源指回) func _record_gain(source_class: String, kind: String, detail: Dictionary) -> int: var rec_id := _gain_log.size() + 1 # 记录 id = 列表序派生(1 起——恢复面按 max(id) 校正) var rec: Dictionary[Variant, Variant] = {"id": rec_id, "source_class": source_class, "kind": kind} rec.merge(detail.duplicate(true)) _gain_log.append(rec) return rec_id # 统一冒险加算区单写原语(三通道统一入口。明细+汇总同步维护——写时同拍,无事后对账) func gain_bonus(axis: String, value: int, source_class: String, kind: String) -> void: var gain_id := _record_gain(source_class, kind, {"axis": axis, "value": value}) _bonus_detail.append({"gain_id": gain_id, "axis": axis, "value": value, "source_class": source_class, "kind": kind}) _bonus_total[axis] = int(_bonus_total.get(axis, 0)) + value # 汇总读面(生效公式/断点/摘要唯一取数口) func bonus_total(axis: String) -> int: return int(_bonus_total.get(axis, 0)) func bonus_snapshot() -> Dictionary[Variant, Variant]: return _bonus_total.duplicate(true) # 商店已购档数记账(购买条目——递增定价输入;定价读数走 purchase_tier) func record_purchase(product_id: String) -> void: _purchased[product_id] = purchase_tier(product_id) + 1 func purchase_tier(product_id: String) -> int: return int(_purchased.get(product_id, 0)) # 本局钥石增量(Boss 逐杀掉落渠道——首杀/复杀金额由调用方按存档标记判读后入行) func record_keystone_drop(drop: Dictionary) -> void: _keystone_drops.append(drop.duplicate(true)) _keystone += int(drop.get("amount", 0)) func keystone_gained() -> int: return _keystone func keystone_drop_log() -> Array: return _keystone_drops.duplicate(true) # 真视使用记录(真视类工具受理成功恰计一次;冒险收束聚合入档) func record_vision_use() -> void: _vision_used += 1 func vision_used() -> int: return _vision_used # 日记域账面重置(冒险开始/单关重开共用值面——宿主须先调本件再调 HeroStats 置满,生命口径 # 才不含加算区) func reset_adventure_accounts() -> void: _bonus_total = {"atk": 0, "max_hp": 0, "armor_class": 0, "ap": 0} _gain_log = [] _bonus_detail = [] _purchased = {} _keystone = 0 _keystone_drops = [] _vision_used = 0 # ---- 断点自交片段(应用层拼盘口收件——本件只交自己的账)---- # 片段键:bonus(汇总快照)/shop_purchased/keystone/keystone_drops/vision_counter_used # +获得日记键(唯一声明的断点扩列;旧档缺日记→汇总直载 clamp、在档→明细推导比对不符 # push_error 拒载) func breakpoint_fragment() -> Dictionary[Variant, Variant]: return { "bonus": bonus_snapshot(), "shop_purchased": _purchased.duplicate(true), "keystone": _keystone, "keystone_drops": keystone_drop_log(), "vision_counter_used": _vision_used, "gain_journal": {"records": _gain_log.duplicate(true), "details": _bonus_detail.duplicate(true)}, } # 片段回填(日记缺键 = 旧档——汇总直载跳过比对;日记在档 = 由明细推导汇总、与留存汇总不符 # 即报错中止——日记为现行事实源,汇总仅作一致性校验读数) func restore_fragment(frag: Dictionary, _params: Dictionary) -> void: _purchased = (frag.get("shop_purchased", {}) as Dictionary).duplicate(true) _keystone = int(frag.get("keystone", 0)) _keystone_drops = (frag.get("keystone_drops", []) as Array).duplicate(true) _vision_used = maxi(0, int(frag.get("vision_counter_used", 0))) # clamp 类(现役读侧策略同款) var journal: Variant = frag.get("gain_journal", null) if journal is Dictionary and not (journal as Dictionary).is_empty(): _restore_from_journal(journal as Dictionary, frag) return # 旧档回退:汇总键直载(clamp 类——四轴子键夹 ≥0) _bonus_total = {} var bp_bonus: Dictionary[Variant, Variant] = frag.get("bonus", {}) as Dictionary for axis in BONUS_AXES: _bonus_total[axis] = maxi(0, int(bp_bonus.get(axis, 0))) # 日记回填(记录列表与明细全量还原;汇总由明细推导——与留存汇总逐轴比对,不符即致命中止) func _restore_from_journal(journal: Dictionary, frag: Dictionary) -> void: _gain_log = (journal.get("records", []) as Array).duplicate(true) _bonus_detail = (journal.get("details", []) as Array).duplicate(true) var derived: Dictionary[Variant, Variant] = {"atk": 0, "max_hp": 0, "armor_class": 0, "ap": 0} for d in _bonus_detail: var axis := String((d as Dictionary).get("axis", "")) if not derived.has(axis): push_error("[加算日记] 断点日记明细含未知加算轴: %s(拒绝载入)" % axis) derived.clear() break derived[axis] = int(derived[axis]) + int((d as Dictionary).get("value", 0)) if derived.is_empty(): return # 已报错中止(fail-fast——明细非法整面拒绝) var stored: Dictionary[Variant, Variant] = frag.get("bonus", {}) as Dictionary for axis in derived.keys(): if int(stored.get(axis, -1)) != int(derived[axis]): push_error("[加算日记] 断点汇总与日记推导不一致(axis=%s 汇总=%d 推导=%d)——拒绝载入" % [axis, int(stored.get(axis, -1)), int(derived[axis])]) return _bonus_total = derived