feat: surface player standing and quest journal in the village HUD

This commit is contained in:
2026-08-08 17:48:13 +02:00
parent 9e6a6afcf5
commit 089fef9968
6 changed files with 419 additions and 1 deletions
+143
View File
@@ -0,0 +1,143 @@
class_name QuestJournalHud
extends Control
const ENTER_OFFSET := 8.0
const THANKS_SECONDS := 3.4
@export var simulation_manager: Node
@onready var accent: ColorRect = $Accent
@onready var copy: VBoxContainer = $Copy
@onready var standing_label: Label = $Copy/Standing
@onready var quest_label: Label = $Copy/Quest
@onready var quest_kicker: Label = $Copy/QuestKicker
@onready var thanks_label: Label = $Copy/Thanks
var resting_position: Vector2
var feedback_version := 0
var feedback_tween: Tween
var journal_tween: Tween
func _ready() -> void:
resting_position = position
visible = false
modulate.a = 0.0
if simulation_manager == null:
push_error("QuestJournalHud: simulation_manager missing")
return
if simulation_manager.has_signal("player_quest_opened"):
simulation_manager.player_quest_opened.connect(_on_quest_opened)
if simulation_manager.has_signal("player_quest_completed"):
simulation_manager.player_quest_completed.connect(_on_quest_completed)
if simulation_manager.has_signal("player_quest_expired"):
simulation_manager.player_quest_expired.connect(_on_quest_expired)
if simulation_manager.has_signal("player_standing_changed"):
simulation_manager.player_standing_changed.connect(_on_standing_changed)
if simulation_manager.has_signal("opportunity_resolved"):
simulation_manager.opportunity_resolved.connect(_on_opportunity_resolved)
if simulation_manager.has_signal("state_restored"):
simulation_manager.state_restored.connect(_on_state_restored)
_refresh()
func _on_quest_opened(_quest: PlayerQuestRecord) -> void:
_refresh()
func _on_quest_expired(_quest: PlayerQuestRecord) -> void:
_refresh()
func _on_standing_changed(_standing: PlayerStandingRecord) -> void:
_refresh()
func _on_opportunity_resolved(
_opportunity: OpportunityStateRecord, _cause_event: EconomicEventRecord
) -> void:
_refresh()
func _on_state_restored() -> void:
_refresh()
func _refresh() -> void:
if simulation_manager == null:
return
var standing: PlayerStandingRecord = simulation_manager.get_player_standing()
if standing == null:
return
var standing_text := (
"Standing · %s · %.0f/100" % [standing.get_tier_name(), standing.get_standing()]
)
standing_label.text = standing_text
var quest: PlayerQuestRecord = simulation_manager.get_active_player_quest()
if quest == null:
quest_kicker.text = ""
quest_label.text = ""
else:
var requester_name := _get_npc_name(quest.get_requester_npc_id())
quest_kicker.text = "ACTIVE QUEST"
quest_label.text = (
"%s · bring %.0f %s to the %s"
% [
requester_name,
quest.get_target_amount(),
String(quest.get_resource_id()).replace("_", " "),
String(quest.get_target_id()).replace("_", " "),
]
)
var has_content := not quest_kicker.text.is_empty() or not standing_text.is_empty()
if not has_content:
return
if not visible:
visible = true
modulate.a = 0.0
position = resting_position + Vector2(0.0, ENTER_OFFSET)
if journal_tween != null and journal_tween.is_valid():
journal_tween.kill()
journal_tween = create_tween().set_parallel(true)
journal_tween.set_trans(Tween.TRANS_QUAD).set_ease(Tween.EASE_OUT)
journal_tween.tween_property(self, "position", resting_position, 0.3)
journal_tween.tween_property(self, "modulate:a", 1.0, 0.22)
func _on_quest_completed(quest: PlayerQuestRecord) -> void:
_refresh()
var requester_name := _get_npc_name(quest.get_requester_npc_id())
_show_thanks(
"Gratitude",
(
"%s thanks you for your help. +%.0f Standing"
% [requester_name, quest.get_standing_reward()]
)
)
func _show_thanks(heading: String, message: String) -> void:
feedback_version += 1
var version := feedback_version
if feedback_tween != null and feedback_tween.is_valid():
feedback_tween.kill()
thanks_label.text = "%s\n%s" % [heading, message]
thanks_label.visible = true
thanks_label.modulate.a = 0.0
feedback_tween = create_tween().set_parallel(true)
feedback_tween.set_trans(Tween.TRANS_QUAD).set_ease(Tween.EASE_OUT)
feedback_tween.tween_property(thanks_label, "modulate:a", 1.0, 0.3)
feedback_tween.chain().tween_interval(THANKS_SECONDS)
feedback_tween.chain().tween_property(thanks_label, "modulate:a", 0.0, 0.5)
feedback_tween.chain().tween_callback(
func() -> void:
if version == feedback_version:
thanks_label.visible = false
)
func _get_npc_name(npc_id: int) -> String:
for npc in simulation_manager.npcs:
if npc.id == npc_id:
return npc.npc_name
return "Someone"