# VERTICAL SLICE - NOT FOR PRODUCTION # Validation Question: 玩家能否无指导在一场完整战斗中经历「开战→挖掘规划→轮末结算逐行兑现→胜/负」并逐行归因(P2) # Date: 2026-09-10 # 增益状态·统一状态容器:三向效果同构实例 · 单一时限量纲 remaining_settlements(先兑付后衰减)· # 按行叠层(stack 授予不触碰 R)· 授予时数值快照抗热重载 · 零随机零信号。 # 注:MVP 单敌假设经 敌人系统 回验不成立(定多敌)——enemy 侧 side-wide 语义按 registry 改写执行。 # 实现 GDD:design/archive/gdd-2026-09-14/b3-status-effect.md(系统 ID B3·增益状态——registry 追溯锚,命名规范见 CLAUDE.md) class_name StatusContainer extends RefCounted var db: ConfigDb var _open := false var _instances: Array[Dictionary] = [] # 插入序;元素 = {effect_id, layers, remaining, source_class, origin_cell, round_index, snap_m, snap_unit, snap_display} func _init(db_ref: ConfigDb) -> void: db = db_ref func notify_battle_start() -> bool: if _open: push_warning("[增益状态] Active 下重复 notify_battle_start(EC11)") return false _open = true _instances.clear() return true # 唯一授予入口(挖掘期零直写——战斗结算 结算编排期统一调用)。 # duration_override(敌人技能池批——增益技施放):技能行 buff_duration 覆盖状态行时长(-1 = 状态表值)。 # 施放是持续量的 owner(proposal §2.2 字段词汇表"buff_duration 增益持续回合数");其他授予路径传缺省。 func apply_effect(effect_id: String, source: Dictionary, duration_override: int = -1) -> bool: if not _open: push_warning("[增益状态] 域闭授予(EC1)") return false var row: Dictionary = db.status_effect_row(effect_id) if row.is_empty(): push_warning("[增益状态] 未知 effect_id(EC2): %s" % effect_id) return false var policy: String = row.stack_policy var dur: int = int(row.duration_settlements) if duration_override < 1 else duration_override var max_stack: int = int(row.max_stack) # 授予时快照(抗表重载——EC9) var snap_m: int = int(row.magnitude) var snap_unit: String = String(row.unit) var snap_display: String = String(row.display_name) match policy: "independent": _instances.append(_new_instance(effect_id, 1, dur, source, snap_m, snap_unit, snap_display)) return true "refresh": for inst in _instances: if inst.effect_id == effect_id: inst.remaining = dur # R ← D(取实例快照 D——同表值);L 不变;空刷新恒 true return true _instances.append(_new_instance(effect_id, 1, dur, source, snap_m, snap_unit, snap_display)) return true "stack": for inst in _instances: if inst.effect_id == effect_id: if inst.layers >= max_stack: return false # 满层拒绝原子——容器零写入(拒收由战斗结算记"奖励未生效"行) inst.layers += 1 # stack 授予不触碰 R(spec 决议) return true _instances.append(_new_instance(effect_id, 1, dur, source, snap_m, snap_unit, snap_display)) return true push_warning("[增益状态] 未知 stack_policy") return false func _new_instance(effect_id: String, layers: int, dur: int, source: Dictionary, m: int, unit: String, display: String) -> Dictionary: return { "effect_id": effect_id, "layers": layers, "remaining": dur, "source_class": String(source.get("source_class", "")), "origin_cell": source.get("origin_cell", Vector2i(-1, -1)), "round_index": int(source.get("round_index", 0)), "snap_m": m, "snap_unit": unit, "snap_display": display, } # 只读投影(插入序稳定枚举;六归因字段 + display_name + 授予时快照) func query_active(side: String) -> Array: var out: Array[Dictionary] = [] for inst in _instances: var row: Dictionary = db.status_effect_row(inst.effect_id) if row.is_empty(): continue if String(row.target_side) != side: continue out.append({ "effect_id": inst.effect_id, "layers": inst.layers, "remaining_settlements": inst.remaining, "source_class": inst.source_class, "origin_cell": inst.origin_cell, "round_index": inst.round_index, "display_name": inst.snap_display, "snap_magnitude": inst.snap_m, "snap_unit": inst.snap_unit, "effective_value": inst.layers * inst.snap_m, # L×m 加算(percent 越域不 clamp——收口归 战斗结算) }) return out # 池层数读值(战斗结算·战斗段伏击池 L 的消费面) func pool_layers(effect_id: String) -> int: for inst in _instances: if inst.effect_id == effect_id: return inst.layers return 0 # 轮末衰减:先兑付后衰减;每实例恰 −1;归 0 移除;返回移除数 k(恰一次执行由 战斗结算 编排信任承载) func decay_round() -> int: if not _open: return 0 # EC13 域闭兜底读法——容器恒空,无独立分支不诊断 var k := 0 var survivors: Array[Dictionary] = [] for inst in _instances: inst.remaining -= 1 if inst.remaining <= 0: k += 1 else: survivors.append(inst) _instances = survivors return k func notify_battle_end() -> bool: if not _open: push_warning("[增益状态] BattleClosed 下重复 notify_battle_end(EC11)") return false _open = false _instances.clear() # 全清不跨战斗 return true