nodes/stats.py¶
Part of HeartBeast Action RPG.
1"""Stats node: signal-based health tracking.
2
3Mirrors the upstream HeartBeast Stats scene: a standalone node that tracks
4current/max health and emits signals on changes. Used by Player, Enemy,
5and any other entity with HP.
6"""
7
8from __future__ import annotations
9
10from simvx.core import Node, Signal
11
12
13class Stats(Node):
14 """Signal-based health tracker, matches the upstream HeartBeast Stats scene."""
15
16 health_changed = Signal() # (new_health: int)
17 max_health_changed = Signal() # (new_max: int)
18 no_health = Signal() # emitted when health drops to 0
19
20 def __init__(self, max_health: int = 6, **kwargs):
21 super().__init__(**kwargs)
22 self._max_health = max_health
23 self._health = max_health
24 self.health_changed.emit(self._health)
25 self.max_health_changed.emit(self._max_health)
26
27 # ── Properties ───────────────────────────────────────────────────────────
28
29 @property
30 def health(self) -> int:
31 return self._health
32
33 @health.setter
34 def health(self, value: int):
35 old = self._health
36 self._health = max(0, min(value, self._max_health))
37 if self._health != old:
38 self.health_changed.emit(self._health)
39 if self._health <= 0:
40 self.no_health.emit()
41
42 @property
43 def max_health(self) -> int:
44 return self._max_health
45
46 @max_health.setter
47 def max_health(self, value: int):
48 self._max_health = max(1, value)
49 self.max_health_changed.emit(self._max_health)
50 # Clamp current health
51 if self._health > self._max_health:
52 self._health = self._max_health
53 self.health_changed.emit(self._health)