88 lines
2.2 KiB
GDScript
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")
|