class_name Stat extends RefCounted ## Individual stat instance belonging to a combatant. ## Has a base value and optional temporary mods from effects. ## GetValue returns base + sum(mods), clamped to [min, max]. var _def: StatDef var _base: int var _mods: Dictionary func _init(def: StatDef) -> void: _def = def _base = 0 _mods = {} func get_def() -> StatDef: return _def func get_base() -> int: return _base func set_base(value: int) -> void: var combatant: Combatant = _def.get_context()._get_combatant_with_stat(self) if combatant: var evt: StatBaseEvent = StatBaseEvent.new(combatant.get_id(), _def.get_id(), value) _def.get_context()._emit_event(evt) value = evt.value _base = _clamp(value) func add_base(value: int) -> void: set_base(_base + value) func sub_base(value: int) -> void: set_base(_base - value) func get_value() -> int: var value: int = _base for source_id in _mods: value += _mods[source_id] return _clamp(value) func reset() -> void: _mods.clear() func set_mod(source: Variant, value: int) -> void: var source_id: int = _resolve_source_id(source) var combatant: Combatant = _def.get_context()._get_combatant_with_stat(self) if combatant: var evt: StatModEvent = StatModEvent.new(combatant.get_id(), _def.get_id(), source_id, value) _def.get_context()._emit_event(evt) value = evt.mod_value if value == 0: _mods.erase(source_id) else: _mods[source_id] = value func _resolve_source_id(source: Variant) -> int: if source == null: return 0 if source is NBattleObject: return source.get_id() if source is int: return source push_error("NBattle: Invalid source type for set_mod") return 0 func _clamp(value: int) -> int: return clampi(value, _def.get_min(), _def.get_max())