class_name QuestSprite extends Control @onready var damage_banner_template = preload("res://templates/damage_banner.tscn") @onready var lifebar : TextureProgressBar = $LifeBar @export var life : int = 1 @export var max_life : int = 1 @export var energy : int = 1 @export var max_energy : int = 1 var level : int = 1 @export var exp : int = 0 var reset_position : Vector2 var melee_range : float = 100 var highlight_color : Color = Color(1,1,1,0) var knockback_tween : Tween @export var stats : StatBlock var gold : int = 0 @onready var anim_player : AnimationPlayer = $AnimationPlayer @onready var sprite_material : ShaderMaterial = $Sprite.material @onready var banner_offset : Node2D = $BannerOffset signal hitting() signal died(killer :QuestSprite) signal action_complete(requeue : bool) signal busy() signal arrived() func _ready() -> void: lifebar.value = life lifebar.max_value = max_life lifebar.visible = false func _process(delta: float) -> void: sprite_material.set_shader_parameter("highlight", highlight_color) func position_reset() -> void: var tween = create_tween() #TODO: Vary movement animations? tween.tween_callback(anim_player.play.bind("running")) tween.tween_property(self, "position", reset_position,.5) if reset_position.x < position.x: $Sprite.flip_h = true tween.tween_property($Sprite, "flip_h", false, 0) tween.tween_callback(anim_player.play.bind("idle")) tween.tween_callback(arrived.emit) func approach(target, offset) -> void: var tween = create_tween() if target.position.x > position.x: #TODO: Switch facing direction offset = -offset #TODO: Vary movement animations? tween.tween_callback(anim_player.play.bind("running")) var target_position = target.position + Vector2(offset, 0) tween.tween_property(self, "position", target_position,.5) if target_position.x < position.x: $Sprite.flip_h = true tween.tween_property($Sprite, "flip_h", false, 0) tween.tween_callback(anim_player.play.bind("idle")) tween.tween_callback(arrived.emit) func take_damage(source : QuestSprite, amount : int) -> void: busy.emit() var damage_banner = damage_banner_template.instantiate() damage_banner.position = Vector2.ZERO banner_offset.add_child(damage_banner) damage_banner.set_label(str(-amount)) if amount > 0: anim_player.play("hurt") life = clampi(life - amount, 0, max_life) lifebar.value = life lifebar.max_value = max_life if life == 0: print("%s killed %s!" % [source.name, name]) die(source) else: print("%s hit %s for %d damage!" % [source.name, name, amount]) action_complete.emit(false) func die(killer : QuestSprite) -> void: died.emit(killer) queue_free() func trigger_hit() -> void: hitting.emit() func complete_action(requeue : bool, reset_animation : String) -> void: anim_player.play(reset_animation) action_complete.emit(requeue) func show_lifebar(showing : bool) -> void: lifebar.visible = showing func flip_h() -> void: $Sprite.flip_h = true func knockback(time : float) -> void: knockback_tween = create_tween() var offset : Vector2 = Vector2(-20, 0) if $Sprite.flip_h: offset.x *= -1 var knockback_pos = reset_position + offset knockback_tween.tween_property(self, "position", knockback_pos, lerp(0.0, time, (knockback_pos.x - position.x) / offset.x )) knockback_tween.tween_property(self, "position", reset_position, time)