Merge branch 'master' into iter38
# Conflicts: # game/README.md # game/tests/验证集清单.md
This commit is contained in:
commit
416ca84aeb
85 files changed
+2939
-2054
No files matched your search
@@ -7,9 +7,9 @@ class_name AdventureRunner
|
||||
extends RefCounted
|
||||
|
||||
signal level_started(level_index: int, display_name: String) ## 每关开始(含冒险首关)——呈现层重取 runner()、刷新图条与层名行
|
||||
signal curio_choice_presented(payload: Dictionary) ## 专长三选一停点(非末关通关恰一次;通道白名单后候选恒专长+回血在载荷)——{level_index, candidates, heal_gained, hp_before, hp_after, keystone_gained, keystone_total, gp, aux_cleared}
|
||||
signal curio_choice_presented(payload: Dictionary) ## 专长三选一停点(非末关的关卡完成恰一次;通道白名单后候选恒专长+回血在载荷)——{level_index, candidates, heal_gained, hp_before, hp_after, keystone_gained, keystone_total, gp, aux_cleared}
|
||||
signal curio_resolved(result: Dictionary) ## 三选一兑付完成(pick_curio/替换受理后恰一次)——{picked, value, hp_before, hp_after, level_index}
|
||||
signal adventure_finished(summary: Dictionary) ## 冒险结算(completed/failed/abandoned)——summary 五件事:打穿没有/通关几关/止步第几关/钥石合计/主种子(+additive keystone_drops)
|
||||
signal adventure_finished(summary: Dictionary) ## 冒险结算(completed/failed/abandoned)——summary 五件事:打穿没有/完成几关/止步第几关/钥石合计/主种子(+additive keystone_drops)
|
||||
# ---- 转发族(签名与 LevelRunner 同款——呈现层对接透明;S6 经 _forward_* 方法)----
|
||||
signal node_entered(node: Dictionary, info: Dictionary)
|
||||
signal choices_presented(candidates: Array)
|
||||
@@ -266,7 +266,7 @@ func _resume_pending(bp_pending: Dictionary) -> void:
|
||||
var migrated: Array[Variant] = []
|
||||
for c in (bp_pending.get("candidates", []) as Array):
|
||||
if c is Dictionary:
|
||||
# T4——feat_id 随迁移(通关渠道候选=纯专长令牌,身份键 relic|tier|feat_id 三段全要)
|
||||
# T4——feat_id 随迁移(关卡完成渠道候选=纯专长令牌,身份键 relic|tier|feat_id 三段全要)
|
||||
var mig := {"kind": String((c as Dictionary).get("kind", "")), "tier": String((c as Dictionary).get("tier", ""))}
|
||||
if String(mig["kind"]) == "relic":
|
||||
mig["feat_id"] = String((c as Dictionary).get("feat_id", ""))
|
||||
@@ -339,7 +339,7 @@ func continue_to_next_level() -> bool:
|
||||
|
||||
# 停点空候选消化(池空=三选一环节整体跳过:候选 0 件时停点视同已处理,
|
||||
# 呈现层跳开选择面直接走后续推进。仅空候选合法;非空停点拒绝——零自动推进契约不破,正常
|
||||
# 消化仍只走 pick_curio/apply_node_curio 兑付。触发源=渠道白名单过滤后池空(关卡 Boss 通关
|
||||
# 消化仍只走 pick_curio/apply_node_curio 兑付。触发源=渠道白名单过滤后池空(关卡 Boss 击破=关卡完成
|
||||
# 渠道只出专长,专长零配置/旧档 deck 无 relic 余库即空集)。)
|
||||
func skip_empty_curio() -> bool:
|
||||
if _curio_pending.is_empty():
|
||||
@@ -390,7 +390,7 @@ func _feat_payload_keys(feat_id: String) -> Dictionary:
|
||||
|
||||
# 三选一件兑付共享体(TP0——令牌消费、摘牌单点,含 relic 分支):
|
||||
# 属性件写加算区 + 件获取计数、AP 件写第四轴、GP 件走钱包、恢复件当即回血(封顶生效上限——
|
||||
# 与账本置满/通关回血同式 effective_max_hp)、relic 件入持有集(散件单体保底——效果接线面
|
||||
# 与账本置满/关卡完成回血同式 effective_max_hp)、relic 件入持有集(散件单体保底——效果接线面
|
||||
# 按挂点消费,档位质变由 FeatsEngine 求值)。兑付即从 _curio_deck 摘除该令牌(选中踢池;
|
||||
# 未选候选从未摘牌=自动回池)。道具件不入此体——未知件返回 false 由调用方按渠道名报错。
|
||||
func _apply_curio_pick(kind: String, tier: String, value: int, feat_id: String = "") -> bool:
|
||||
@@ -483,7 +483,7 @@ func _finish_curio_pick(picked: String, value: int, hp_before: int, tier: String
|
||||
_snapshot_breakpoint()
|
||||
|
||||
|
||||
# ---- 奖励节点三选一(与通关三选一共享同池同权重同次数上限)----
|
||||
# ---- 奖励节点三选一(与关卡完成三选一共享同池同权重同次数上限)----
|
||||
|
||||
# 候选呈现(节点到达时调用——恰一 reward_pick scope 洗牌 + 道具件掷定 scope;本停点断点不载,
|
||||
# 续玩重建到选路停点后重走重抽,恢复的全局计数器保证同候选逐位复现)。
|
||||
@@ -498,7 +498,7 @@ func present_node_curio(candidates: Array) -> void:
|
||||
_node_curio_pending = {"candidates": candidates.duplicate(true)}
|
||||
|
||||
|
||||
# 点选兑付(节点域——无部分回血无钥石;令牌消费与牌库摘牌与通关三选一同库;relic 同权入持有集)
|
||||
# 点选兑付(节点域——无部分回血无钥石;令牌消费与牌库摘牌与关卡完成三选一同库;relic 同权入持有集)
|
||||
func apply_node_curio(kind: String, tier: String = "", feat_id: String = "") -> bool:
|
||||
if kind == "feat_ticket":
|
||||
return _redeem_feat_ticket() # T5 拿到即开——节点停点候选替换为专长三选一(呈现层本地重绘)
|
||||
@@ -562,7 +562,7 @@ func node_curio_pending_state() -> Dictionary:
|
||||
}
|
||||
|
||||
|
||||
# 三选一刷新(免费位 X/Y——组合根唯一调用口;无停点/无余量 false 零副作用)。通关停点重抽后重发
|
||||
# 三选一刷新(免费位 X/Y——组合根唯一调用口;无停点/无余量 false 零副作用)。关卡完成停点重抽后重发
|
||||
# curio_choice_presented(呈现层重建卡片+刷新余量);节点停点由组合根读 node_curio_pending_state 重 present。
|
||||
func refresh_curio() -> bool:
|
||||
return _refresh_curio_common(false)
|
||||
@@ -651,7 +651,7 @@ func _feat_ticket_consider(rg: RandomNumberGenerator) -> bool:
|
||||
func _redeem_feat_ticket() -> bool:
|
||||
_feat_ticket_sold += 1
|
||||
_feat_ticket_pity = 0
|
||||
var cands: Array[Variant] = _draw_curio_candidates("level_clear") # 专长池(与通关渠道同白名单)
|
||||
var cands: Array[Variant] = _draw_curio_candidates("level_clear") # 专长池(与关卡完成渠道同白名单)
|
||||
if cands.is_empty():
|
||||
push_error("[冒险结构] 专长凭证兑付失败——专长池空集")
|
||||
_feat_ticket_sold -= 1
|
||||
@@ -668,7 +668,7 @@ func _redeem_feat_ticket() -> bool:
|
||||
|
||||
# Boss 钥石逐杀掉落(掉落渠道 = Boss/精英击杀;首杀/复杀两档读 meta.tres boss_keystone;
|
||||
# 首杀判据 = 存档 boss_first_kill 标记位〔断点未注入 = 恒首杀——模拟/冒烟零扰动;标记仍在收束
|
||||
# apply_adventure_summary 逐通关关次置位〕;末关 Boss 照常入账;明细随摘要 additive 键供结算面归因)
|
||||
# apply_adventure_summary 逐关卡完成关次置位〕;末关 Boss 照常入账;明细随摘要 additive 键供结算面归因)
|
||||
func _boss_keystone_drop(li: int) -> void:
|
||||
var first := true
|
||||
if _save_manager != null:
|
||||
@@ -779,7 +779,7 @@ func _on_level_finished(payload: Dictionary) -> void:
|
||||
# Boss 钥石逐杀掉落(击杀掉落渠道,末关照常入账;首杀/复杀读 meta.tres boss_keystone)
|
||||
_boss_keystone_drop(level_index)
|
||||
if level_index < levels_total:
|
||||
# 通关兑付(非末关恰一次;三层奖励框架):部分回血先行 → 加权洗牌掷 3 → 三选一停点
|
||||
# 关卡完成兑付(非末关恰一次;三层奖励框架):部分回血先行 → 加权洗牌掷 3 → 三选一停点
|
||||
#(顺序即契约——回血按当刻账本与上限结算,选择停点零自动推进)
|
||||
var hp_before := int(ledger.get("hero_hp", 0))
|
||||
var max_eff := effective_max_hp() # 回血封顶口径含调试浮窗 pct(同战斗内上限)
|
||||
@@ -791,7 +791,7 @@ func _on_level_finished(payload: Dictionary) -> void:
|
||||
_curio_paid_refreshes = 0 # 付费刷计数随停点清零(对齐商店进店清零)
|
||||
var pick_payload: Dictionary[Variant, Variant] = {
|
||||
"level_index": level_index,
|
||||
"candidates": _draw_curio_candidates("level_clear"), # T4 渠道白名单——关底 Boss 击败=通关渠道只出专长
|
||||
"candidates": _draw_curio_candidates("level_clear"), # T4 渠道白名单——关底 Boss 击败=关卡完成渠道只出专长
|
||||
"heal_gained": heal,
|
||||
"hp_before": hp_before,
|
||||
"hp_after": int(ledger.get("hero_hp", 0)),
|
||||
@@ -805,12 +805,12 @@ func _on_level_finished(payload: Dictionary) -> void:
|
||||
curio_choice_presented.emit(pick_payload)
|
||||
_snapshot_breakpoint() # 选择停点可中断(契约 5——续玩不重抽不静默丢失)
|
||||
return
|
||||
# 末关通关:不发三选一与部分回血(没有下一战可受益)、Boss 钥石照常入账——冒险完成结算
|
||||
# 末关的关卡完成:不发三选一与部分回血(没有下一战可受益)、Boss 钥石照常入账——冒险完成结算
|
||||
_settle("completed")
|
||||
|
||||
|
||||
func _settle(result: String) -> void:
|
||||
# 冒险摘要五件事:打穿没有 / 通关几关 / 止步第几关 / 钥石入账合计 / 本局主种子
|
||||
# 冒险摘要五件事:打穿没有 / 完成几关 / 止步第几关 / 钥石入账合计 / 本局主种子
|
||||
summary = {
|
||||
"result": result,
|
||||
"cleared": result == "completed",
|
||||
|
||||
@@ -254,7 +254,7 @@ func level_gen_params_row(level_index: int) -> Dictionary:
|
||||
return level_gen_params.row_by_level_index(level_index) if level_gen_params != null else {}
|
||||
|
||||
|
||||
# 序列总关数(AdventureRunner levels_total / MetaProgression 通关累加域的取数口径)
|
||||
# 序列总关数(AdventureRunner levels_total / MetaProgression 关卡完成累加域的取数口径)
|
||||
func level_count() -> int:
|
||||
return level.rows.size() if level != null else 0
|
||||
|
||||
|
||||
@@ -40,7 +40,7 @@ func cross_validate(loaded: Dictionary, push_diag: Callable) -> void:
|
||||
if not treasure_live.has(treasure_eff):
|
||||
push_diag.call("error", "reward_dangling_treasure", "RewardTable %s aux 行引用无效道具 %s(retired/deferred/不存在): %s" % [row.get("reward_id"), treasure_eff, "双表校验"])
|
||||
# ①c F2 投放维度覆盖校验不启用:挖格不掉道具,秘宝
|
||||
# 唯一来路=三选一共享池〔节点/通关〕;共享池为「抽到道具位再动态掷定具体道具」,维度覆盖不可
|
||||
# 唯一来路=三选一共享池〔节点/关卡完成〕;共享池为「抽到道具位再动态掷定具体道具」,维度覆盖不可
|
||||
# 静态校验。
|
||||
# ② SettlementTable.effect_pool_map 悬空
|
||||
for eff in st_tab.effect_pool_map.keys():
|
||||
|
||||
@@ -561,7 +561,7 @@ func _on_battle_finished(payload: Dictionary) -> void:
|
||||
hero_hp = maxi(1, int(payload.get("hero_hp", 0))) # despawn 前捕获值(载荷自包含)
|
||||
_gain_wallet(int(payload.get("gp_dropped", 0))) # 战斗完成入账(clamp ≥0——破财可把 escrow 打负,钱包入账时钳制)
|
||||
if String(node.get("type", "")) == "boss" or result == "defeat":
|
||||
# Boss 胜利 = 关卡通关;任意战斗败北 = 关卡失败(漂移⑦清偿——每战结果上报冒险结构,
|
||||
# Boss 胜利 = 关卡完成;任意战斗败北 = 关卡失败(漂移⑦清偿——每战结果上报冒险结构,
|
||||
# 失败结算归 AdventureRunner;本类只发 level_finished)
|
||||
level_result = "victory" if result == "victory" else "defeat"
|
||||
var hp_left := hero_hp if result == "victory" else 0
|
||||
@@ -742,7 +742,7 @@ func _gain_wallet(amount: int) -> void:
|
||||
wallet_changed.emit("gain", gp, {"amount": amount})
|
||||
|
||||
|
||||
# 冒险收束清零(通关/倒下/放弃——局内货币生命周期终点,不入存档不入摘要;public——冒险模式由
|
||||
# 冒险收束清零(冒险成功/倒下/放弃——局内货币生命周期终点,不入存档不入摘要;public——冒险模式由
|
||||
# AdventureRunner._settle 在冒险收束时调用,单关模式 = 关卡收束即冒险收束)
|
||||
func close_wallet() -> void:
|
||||
gp = 0
|
||||
@@ -772,7 +772,7 @@ func _emit_wallet_event(event: String, gp_now: int, extra: Dictionary) -> void:
|
||||
wallet_changed.emit(event, gp_now, extra)
|
||||
|
||||
|
||||
# 购血(商店 max_hp 商品——当前生命 +Δ 并封顶新上限,与账本置满/通关回血同式)
|
||||
# 购血(商店 max_hp 商品——当前生命 +Δ 并封顶新上限,与账本置满/关卡完成回血同式)
|
||||
func _gain_max_hp_flat(flat: int) -> void:
|
||||
hero_hp = mini(hero_hp + flat, effective_max_hp())
|
||||
|
||||
|
||||
@@ -271,7 +271,7 @@ func forge_shop_status() -> Array:
|
||||
# (keystone_drops 副本随摘要入 recent_summaries)。
|
||||
# 钥石为 Boss 逐杀掉落——掉落金额已在冒险内逐杀入账(summary.keystone_total
|
||||
# 含全部掉落;首杀/复杀判定在 AdventureRunner._boss_keystone_drop,首杀标记在下方
|
||||
# apply_adventure_summary 逐通关关次置位)。本函数只做标记+入账+归档。
|
||||
# apply_adventure_summary 逐关卡完成关次置位)。本函数只做标记+入账+归档。
|
||||
func settle_adventure(summary: Dictionary) -> Dictionary:
|
||||
# 首次冒险布尔位置位(关卡节点图生成 v0.4——完成/失败/放弃三结局同经本收束挂点,写入只在收束)
|
||||
save.mark_first_adventure_done()
|
||||
|
||||
@@ -7,7 +7,7 @@
|
||||
class_name SaveManagerCore
|
||||
extends Node
|
||||
|
||||
const SAVE_FORMAT_VERSION := 7 # registry schema_version:v7=锻造工坊域(meta 新域 forge_routes〔六路线等级 levels+直购解锁清单 unlocked+当前武器/甲选中标记 weapon/armor;无特效域〕,旧档缺键由 _normalize 按默认补齐=初始持有态〔sword/light 在档余四锁、选中=初始路线〕,v6→v7 空迁移=缺键补齐模式);v6=生涯终身计数域(meta 两新域 adventure_total〔冒险总局数,开局即计含放弃与失败〕/adventure_cleared〔通关局数,三关全通才计 1——判定字段 summary.cleared〕,旧档缺键由 _normalize 按默认补零,收束自增唯一入账=apply_adventure_summary);v5=天赋树域(meta 三新域 tree_nodes〔node_id→已购等级〕/fork_sides〔fork_group→a|b〕/migration_note〔三体系迁移补偿注记〕);v4=同调位域(meta 三新域 boss_kill_count/attunement_equipped/attune_refresh_level——旧档缺键 = 合法空态);v3=断点附随件扩列+摘要 keystone_drops;v2=断点域出生;v1=首版;高版本拒读 owner=存档序列化
|
||||
const SAVE_FORMAT_VERSION := 7 # registry schema_version:v7=锻造工坊域(meta 新域 forge_routes〔六路线等级 levels+直购解锁清单 unlocked+当前武器/甲选中标记 weapon/armor;无特效域〕,旧档缺键由 _normalize 按默认补齐=初始持有态〔sword/light 在档余四锁、选中=初始路线〕,v6→v7 空迁移=缺键补齐模式);v6=生涯终身计数域(meta 两新域 adventure_total〔冒险总局数,开局即计含放弃与失败〕/adventure_cleared〔冒险成功局数,三关全通才计 1——判定字段 summary.cleared〕,旧档缺键由 _normalize 按默认补零,收束自增唯一入账=apply_adventure_summary);v5=天赋树域(meta 三新域 tree_nodes〔node_id→已购等级〕/fork_sides〔fork_group→a|b〕/migration_note〔三体系迁移补偿注记〕);v4=同调位域(meta 三新域 boss_kill_count/attunement_equipped/attune_refresh_level——旧档缺键 = 合法空态);v3=断点附随件扩列+摘要 keystone_drops;v2=断点域出生;v1=首版;高版本拒读 owner=存档序列化
|
||||
const SUMMARY_CAP := 10 # 最近冒险摘要保留条数(最新在前)
|
||||
|
||||
const TREE_STRUCT_VERSION := 2 # 树结构版本标记(12 节点 v0.8 结构;加载检测缺失
|
||||
@@ -154,7 +154,7 @@ func delete_slot(slot: int) -> bool:
|
||||
return true
|
||||
|
||||
|
||||
# 摘要三项按槽窥视读器(sv7/sv8,契约 5/9):钥石余额/通关局数/冒险总局数。
|
||||
# 摘要三项按槽窥视读器(sv7/sv8,契约 5/9):钥石余额/冒险成功局数/冒险总局数。
|
||||
# 只读零副作用:不激活、不写盘、不触发 _corrupt_fallback 改名(.corrupt.bak 只在正式进档路径产生)。
|
||||
# 返回 {"readable", "has_file", "keystone", "cleared", "total"}——readable=true=可读槽(空槽=零值合法态,
|
||||
# .tmp 残留按空槽——主文件不在即空);readable=false=不可读槽(损坏/高版本/缺版本字段/打开失败,
|
||||
@@ -285,7 +285,7 @@ func _default_data() -> Dictionary[String, Variant]:
|
||||
"recent_summaries": [],
|
||||
"first_adventure_done": false,
|
||||
"adventure_total": 0, # 生涯终身计数·冒险总局数(开局即计含放弃与失败,收束唯一入账)
|
||||
"adventure_cleared": 0, # 生涯终身计数·通关局数(三关全通才计 1——判定字段 summary.cleared)
|
||||
"adventure_cleared": 0, # 生涯终身计数·冒险成功局数(三关全通才计 1——判定字段 summary.cleared)
|
||||
"vision_used": 0, # 生涯终身计数·真视类工具累计使用次数(信标网络解锁行为条件;
|
||||
# 受理成功唯一计数点=battle 层经冒险层聚合、收束入账;缺键补零不升版本)
|
||||
"forge_routes": { # 锻造工坊域(六路线等级+直购解锁清单+当前选中标记;无特效域)
|
||||
@@ -417,7 +417,7 @@ func boss_first_kill_marked(level_index: int) -> bool:
|
||||
|
||||
# ---- 同调位账本域(里程碑谓词表计数源 + 装配关系 + Y 升级态)----
|
||||
|
||||
# Boss 击杀总数(含重复——底稿裁决 4 计数源;收束入账 = apply_adventure_summary 逐通关关次 +1,
|
||||
# Boss 击杀总数(含重复——底稿裁决 4 计数源;收束入账 = apply_adventure_summary 逐关卡完成关次 +1,
|
||||
# Boss 恒唯一终点故 levels_cleared 即本次冒险 Boss 击杀数)
|
||||
func boss_kill_count() -> int:
|
||||
return int(_data["meta"].get("boss_kill_count", 0))
|
||||
@@ -431,8 +431,8 @@ func adventure_total() -> int:
|
||||
return int(_data["meta"].get("adventure_total", 0))
|
||||
|
||||
|
||||
# 通关局数(口径=三关全通才计 1——判定字段 summary.cleared,adventure_runner「completed」
|
||||
# 唯一出口=末关通关)
|
||||
# 冒险成功局数(口径=三关全通才计 1——判定字段 summary.cleared,adventure_runner「completed」
|
||||
# 唯一出口=末关的关卡完成)
|
||||
func adventure_cleared() -> int:
|
||||
return int(_data["meta"].get("adventure_cleared", 0))
|
||||
|
||||
@@ -558,7 +558,7 @@ func set_attune_refresh_level(n: int) -> void:
|
||||
_data["meta"]["attune_refresh_level"] = maxi(0, n)
|
||||
|
||||
|
||||
# 同调位计数源组装(Attunement 服务取数口——clear_count = 逐关通关次数合计〔含重复关,底稿 §2.1 口径〕;
|
||||
# 同调位计数源组装(Attunement 服务取数口——clear_count = 逐关完成次数合计〔含重复关,底稿 §2.1 口径〕;
|
||||
# clear_count(level_index) 逐关访问器零改动复用)
|
||||
func recent_summaries() -> Array:
|
||||
return _data["meta"]["recent_summaries"].duplicate(true) # 值拷贝出户(本类契约「禁碰内部结构」——消费方直改不得渗入存档内存态)
|
||||
@@ -566,10 +566,10 @@ func recent_summaries() -> Array:
|
||||
|
||||
# 域更新原语(正式冒险收束唯一入账口——组合根经本函数入账,禁直改内部结构):
|
||||
# 钥石入账(summary.keystone_total——逐杀掉落已在冒险内计入,boss_drops 参数为
|
||||
# 摘要归档副本不重复入账)+ 逐通关关次 clear_count +1 与 Boss 首杀标记 + Boss 击杀总数累计
|
||||
# 摘要归档副本不重复入账)+ 逐关卡完成关次 clear_count +1 与 Boss 首杀标记 + Boss 击杀总数累计
|
||||
# (同调位里程碑计数源)+ 摘要头部插入(cap 10,最新在前,元素附
|
||||
# keystone_drops 副本——复盘可归因)+ 生涯终身计数自增(总局数开局即计:
|
||||
# 三结局同经本口恰计一次;通关局数按 summary.cleared 判定三关全通才计 1。终身计数写入
|
||||
# 三结局同经本口恰计一次;冒险成功局数按 summary.cleared 判定三关全通才计 1。终身计数写入
|
||||
# 单口=本函数,禁第二写入点)。
|
||||
func apply_adventure_summary(summary: Dictionary, boss_drops: Array = []) -> void:
|
||||
_data["meta"]["adventure_total"] = adventure_total() + 1
|
||||
|
||||
Reference in new issue
Block a user