112 lines
3.4 KiB
GDScript
112 lines
3.4 KiB
GDScript
class_name VillagerFieldNoteHud
|
|
extends Control
|
|
|
|
const ENTER_OFFSET := 9.0
|
|
const EXIT_OFFSET := 4.0
|
|
|
|
@export var player: Node
|
|
@export var simulation_manager: Node
|
|
|
|
@onready var accent: ColorRect = $Accent
|
|
@onready var copy: VBoxContainer = $Copy
|
|
@onready var name_label: Label = $Copy/Name
|
|
@onready var activity_label: Label = $Copy/Activity
|
|
@onready var target_label: Label = $Copy/Target
|
|
@onready var carrying_label: Label = $Copy/Carrying
|
|
@onready var reason_label: Label = $Copy/Reason
|
|
|
|
var copy_resting_position: Vector2
|
|
var current_context_key := ""
|
|
var motion_tween: Tween
|
|
var motion_version := 0
|
|
var is_hiding := false
|
|
|
|
|
|
func _ready() -> void:
|
|
copy_resting_position = copy.position
|
|
visible = false
|
|
modulate.a = 0.0
|
|
if simulation_manager != null and simulation_manager.has_signal("state_restored"):
|
|
simulation_manager.state_restored.connect(_on_state_restored)
|
|
call_deferred("refresh_note", true)
|
|
|
|
|
|
func _process(_delta: float) -> void:
|
|
refresh_note()
|
|
|
|
|
|
func refresh_note(force: bool = false) -> void:
|
|
if player == null or not player.has_method("get_nearby_villager_inspection"):
|
|
current_context_key = ""
|
|
_hide_note()
|
|
return
|
|
var context: VillagerInspectionResult = player.get_nearby_villager_inspection()
|
|
if context == null:
|
|
if force or not current_context_key.is_empty():
|
|
current_context_key = ""
|
|
_hide_note()
|
|
return
|
|
var next_key := context.cache_key()
|
|
if not force and next_key == current_context_key:
|
|
return
|
|
current_context_key = next_key
|
|
_present(context, true)
|
|
|
|
|
|
func _present(context: VillagerInspectionResult, animate: bool) -> void:
|
|
motion_version += 1
|
|
if motion_tween != null and motion_tween.is_valid():
|
|
motion_tween.kill()
|
|
motion_tween = null
|
|
is_hiding = false
|
|
name_label.text = context.npc_name
|
|
activity_label.text = context.activity_text()
|
|
target_label.text = "Target · %s" % context.target_name
|
|
carrying_label.text = "Carrying · %s" % context.carrying_text()
|
|
reason_label.text = "Why · %s" % context.decision_reason
|
|
visible = true
|
|
accent.pivot_offset = accent.size * 0.5
|
|
if not animate:
|
|
copy.position = copy_resting_position
|
|
modulate.a = 1.0
|
|
accent.scale.y = 1.0
|
|
return
|
|
copy.position = copy_resting_position + Vector2(-ENTER_OFFSET, 0.0)
|
|
modulate.a = 0.0
|
|
accent.scale.y = 0.18
|
|
motion_tween = create_tween().set_parallel(true)
|
|
motion_tween.set_trans(Tween.TRANS_QUAD).set_ease(Tween.EASE_OUT)
|
|
motion_tween.tween_property(copy, "position", copy_resting_position, 0.2)
|
|
motion_tween.tween_property(self, "modulate:a", 1.0, 0.16)
|
|
motion_tween.tween_property(accent, "scale:y", 1.0, 0.26)
|
|
|
|
|
|
func _hide_note() -> void:
|
|
if not visible or is_hiding:
|
|
return
|
|
is_hiding = true
|
|
motion_version += 1
|
|
var hide_version := motion_version
|
|
if motion_tween != null and motion_tween.is_valid():
|
|
motion_tween.kill()
|
|
motion_tween = null
|
|
motion_tween = create_tween().set_parallel(true)
|
|
motion_tween.set_trans(Tween.TRANS_SINE).set_ease(Tween.EASE_IN)
|
|
motion_tween.tween_property(self, "modulate:a", 0.0, 0.14)
|
|
motion_tween.tween_property(copy, "position:x", copy_resting_position.x - EXIT_OFFSET, 0.14)
|
|
motion_tween.finished.connect(_on_hide_finished.bind(hide_version), CONNECT_ONE_SHOT)
|
|
|
|
|
|
func _on_hide_finished(hide_version: int) -> void:
|
|
if motion_version != hide_version:
|
|
return
|
|
motion_tween = null
|
|
is_hiding = false
|
|
if current_context_key.is_empty():
|
|
visible = false
|
|
|
|
|
|
func _on_state_restored() -> void:
|
|
current_context_key = ""
|
|
call_deferred("refresh_note", true)
|