Files
2026-07-06 22:59:47 -07:00

88 lines
2.2 KiB
GDScript

class_name HealthComponent
extends Node
signal health_changed(current: int, maximum: int)
signal depleted
@export var maximum := 100
@export var current := 100
@export var hitstun_seconds := 0.4
var _hitstun_time_left := 0.0
func _ready() -> void:
_emit_changed()
func _process(delta: float) -> void:
if _hitstun_time_left <= 0.0:
return
_hitstun_time_left = maxf(0.0, _hitstun_time_left - delta)
if _hitstun_time_left <= 0.0 and current > 0:
var state_machine := _state_machine_or_null()
if state_machine != null and state_machine.has_method("set_life_state"):
state_machine.call("set_life_state", &"Alive")
func set_values(next_current: int, next_maximum: int) -> void:
maximum = max(1, next_maximum)
current = clampi(next_current, 0, maximum)
if current > 0:
_hitstun_time_left = 0.0
_emit_changed()
func apply_damage(amount: int) -> void:
if amount <= 0:
return
current = clampi(current - amount, 0, maximum)
_emit_changed()
if current == 0:
depleted.emit()
func receive_hit(result: Dictionary) -> void:
var amount := int(result.get("damage", result.get("amount", 0)))
apply_damage(amount)
var state_machine := _state_machine_or_null()
if state_machine == null or not state_machine.has_method("set_life_state"):
return
if current <= 0:
_hitstun_time_left = 0.0
state_machine.call("set_life_state", &"Dead")
elif amount > 0 and bool(result.get("interrupts", true)):
_hitstun_time_left = maxf(0.0, hitstun_seconds)
state_machine.call("set_life_state", &"Hitstun")
func heal(amount: int) -> void:
if amount <= 0:
return
current = clampi(current + amount, 0, maximum)
_emit_changed()
func _emit_changed() -> void:
health_changed.emit(current, maximum)
var bus := _event_bus_or_null()
if bus != null and _is_player_health_component():
bus.emit_signal("player_health_changed", current, maximum)
func _is_player_health_component() -> bool:
var actor := get_parent()
return actor != null and actor.name == "Player"
func _event_bus_or_null() -> Node:
if not is_inside_tree():
return null
return get_tree().root.get_node_or_null("EventBus")
func _state_machine_or_null() -> Node:
if not is_inside_tree():
return null
return get_node_or_null("../StateMachine")