151 lines
7.1 KiB
GDScript
151 lines
7.1 KiB
GDScript
## 加算日记件:统一冒险加算区与获得记录唯一所有者。获得记录三层结构=获得记录列表
|
||
## (_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
|