extends Node3D @export var player_spawn_position := Vector3(0.0, 0.0, 0.0) @export var day_length := 120.0 @export var start_light_angle := -90.0 @onready var _player: RigidBody3D = get_node_or_null("Player") as RigidBody3D @onready var _sun: DirectionalLight3D = $DirectionalLight3D @onready var _quest_text: RichTextLabel = get_node_or_null("PhoneUI/Control/PhoneFrame/QuestText") as RichTextLabel var _time := 0.0 func _ready() -> void: _move_player_to_spawn() _setup_quest_ui() func _process(delta: float) -> void: _update_day_night(delta) func _move_player_to_spawn() -> void: if _player == null: return var spawn_marker := _consume_spawn_marker() if spawn_marker != null: _player.call("teleport_to_spawn", spawn_marker.global_transform) else: _player.global_position = player_spawn_position _player.linear_velocity = Vector3.ZERO _player.angular_velocity = Vector3.ZERO func _consume_spawn_marker() -> Node3D: if TeleportState == null: return null var spawn_name: StringName = TeleportState.consume_spawn_name() if spawn_name == StringName(): return null return find_child(String(spawn_name), true, false) as Node3D func _update_day_night(delta: float) -> void: if _sun == null or day_length <= 0.0: return _time = fmod(_time + delta, day_length) var t: float = _time / day_length var angle: float = lerp(start_light_angle, start_light_angle + 360.0, t) _sun.rotation_degrees.x = angle var energy_curve: float = -sin((t * TAU) + (start_light_angle * PI / 180.0)) _sun.light_energy = clamp((energy_curve * 1.0) + 0.2, 0.0, 1.2) func _setup_quest_ui() -> void: if QuestManager == null: return if not QuestManager.is_connected("quest_state_changed", Callable(self, "_refresh_quest_ui")): QuestManager.quest_state_changed.connect(_refresh_quest_ui) _refresh_quest_ui() func _refresh_quest_ui() -> void: if _quest_text == null or QuestManager == null: return var state: Dictionary = QuestManager.get_active_quest_state() if not bool(state.get("active", false)): _quest_text.text = "No active quest." return var title := String(state.get("title", "Quest")) if bool(state.get("completed", false)): _quest_text.text = "[b]%s[/b]\nComplete." % title return var step_index: int = int(state.get("current_step_index", 0)) var total_steps: int = int(state.get("total_steps", 0)) var step_text := String(state.get("current_step_text", "")) _quest_text.text = "[b]%s[/b]\nStep %d/%d\n%s" % [title, step_index + 1, total_steps, step_text]