Files
gplan-2/game/core/gain_journal.gd
T
DKChan fde14f1c1c 拆件批v1.3-B1(主角账领域拆分): hero_ledger.gd 整件退役→三新件按领域各归各账——hero_stats.gd(生命/特性/类型轴/生效公式与回血封顶单点/续玩钳制收口 clamp_hp_to_resume_cap/断点片段 hero_hp+relics 两键,构造注入 GainJournal 只读引用消费加算汇总)、gp_wallet.gd(gp 单写原语+片段 gp 键)、gain_journal.gd(获得记录三层+三通道 gain_bonus 单写原语+购买档数/钥石/真视+reset_adventure_accounts+片段六键,record_gain 转私有,_record_gain 词表不变);断点拼盘改三片段并集(BREAKPOINT_FIELDS 28 键序不变,_resume_ledger 三还原各取各键,日记缺键汇总直载/在档推导比对拒载逐字承现);消费方改址——adventure_runner(建件三引用+件出口 hero()→stats()/wallet()/journal()/deck(),start/restart 三件先日记后钱包再置满同序,_resume_params 钳制改 clamp_hp_to_resume_cap,载荷_base 随附钱包读数——停点件零钱包依赖)、level_runner(ctx hero→stats/wallet/journal 三键,私有三件同源成对自建,gp/hero_hp 属性改指三件,effective_ap_bonus→journal,hero()→stats()+journal() 出口,_bind_shop refs 换代)、shop_session(refs wallet+journal,BONUS_AXES 归 GainJournal)、battle_orchestrator(encounter "hero"→"journal" 键+_hero 类型 GainJournal)、curio_stop(构造参 stats+journal,兑付落账 split 指针,头注换代清 HeroLedger 表述)、呈现/探针/模拟六文件 12 处读面改址、测试六文件改址(hero_ledger_test 重写为三件测试——文件名与 manifest 行不变,新增 hs1 零引用源码断言)。验收:全量套件除 round_flow EV 锚 goblin 已知预期红外全绿;bp 对拍 292dumps×28 键 mismatch=0;冒烟 17 项 0 失败〔领域拆分批 V1〕
2026-10-27 08:10:08 +08:00

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