Files
gplan-2/game/core/status_container.gd
T

144 lines
5.5 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.
## VERTICAL SLICE - NOT FOR PRODUCTION
## 增益状态统一容器:三方效果同构实例、单一时限量纲(先兑付后衰减)、按行叠层与授予时快照抗热重载(垂直切片验证:增益减益逐行归因)。
## 零随机零信号——纯被动服务;授予唯一入口 apply_effect,满层拒绝零写入(拒收记未生效行归调用方)。
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[Variant, Variant] = db.combat.status_effects.row_by_id(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)
var snap := _grant_snapshot(row, source)
match policy:
"independent":
_instances.append(_new_instance(effect_id, 1, dur, source, snap))
return true
"accumulate":
return _apply_accumulate(effect_id, dur, snap, source)
"stack":
return _apply_stack(effect_id, dur, snap, source, max_stack)
push_warning("[增益状态] 未知 stack_policy")
return false
## 授予时快照域(抗表重载——EC9;封印溢价贯穿——迭代14② T4 percent 形态同乘快照、缺省路径零扰动)
func _grant_snapshot(row: Dictionary, source: Dictionary) -> Dictionary:
var snap_m: int = int(row.magnitude)
if source.has("magnitude_override"):
snap_m = int(source["magnitude_override"])
return {"m": snap_m, "unit": String(row.unit), "display": String(row.display_name)}
## 累加臂:命中加时长未命中追加(R += D 取本次授予生效时长——覆盖值 ≥1 按覆盖值;L 不变;快照沿首授;每次授予必有剩余次数变化)
func _apply_accumulate(effect_id: String, dur: int, snap: Dictionary, source: Dictionary) -> bool:
for inst in _instances:
if inst.effect_id == effect_id:
inst.remaining = int(inst.remaining) + dur
return true
_instances.append(_new_instance(effect_id, 1, dur, source, snap))
return true
## stack 臂:满层拒零写入·未满加层·未命中追加(stack 授予不触碰 R——spec 决议;
## 满层拒绝原子——容器零写入,拒收由战斗结算记"奖励未生效"行)
func _apply_stack(effect_id: String, dur: int, snap: Dictionary, source: Dictionary, max_stack: int) -> bool:
for inst in _instances:
if inst.effect_id == effect_id:
if int(inst.layers) >= max_stack:
return false
inst.layers = int(inst.layers) + 1
return true
_instances.append(_new_instance(effect_id, 1, dur, source, snap))
return true
func _new_instance(effect_id: String, layers: int, dur: int, source: Dictionary, snap: Dictionary) -> 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": snap["m"],
"snap_unit": snap["unit"],
"snap_display": snap["display"],
}
# 只读投影(插入序稳定枚举;六归因字段 + display_name + 授予时快照)
func query_active(side: String) -> Array:
var out: Array[Dictionary] = []
for inst in _instances:
var row: Dictionary[Variant, Variant] = db.combat.status_effects.row_by_id(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": int(inst.layers) * int(inst.snap_m), # L×m 加算(percent 越域不 clamp——收口归 战斗结算)
})
return out
# 轮末衰减:先兑付后衰减;每实例恰 −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 = int(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