155 lines
5.2 KiB
GDScript
155 lines
5.2 KiB
GDScript
extends Control
|
|
class_name QuestJournal
|
|
|
|
enum Tab { MAIN, SIDE, COMPLETED }
|
|
|
|
const QUEST_ENTRY_SCENE := preload("res://game/quest_journal/quest_entry.tscn")
|
|
const OBJECTIVE_ROW_SCENE := preload("res://game/quest_journal/objective_row.tscn")
|
|
const REWARD_ROW_SCENE := preload("res://game/quest_journal/reward_row.tscn")
|
|
|
|
@onready var tab_bar: TabBar = $MarginContainer/HBoxContainer/LeftPanel/TabBar
|
|
@onready var quest_list: VBoxContainer = $MarginContainer/HBoxContainer/LeftPanel/ScrollContainer/QuestList
|
|
@onready var footer_label: Label = $MarginContainer/HBoxContainer/LeftPanel/FooterLabel
|
|
|
|
@onready var detail_title: Label = $MarginContainer/HBoxContainer/RightPanel/DetailScroll/DetailContent/DetailTitle
|
|
@onready var detail_category: Label = $MarginContainer/HBoxContainer/RightPanel/DetailScroll/DetailContent/DetailCategory
|
|
@onready var detail_description: RichTextLabel = $MarginContainer/HBoxContainer/RightPanel/DetailScroll/DetailContent/DetailDescription
|
|
@onready var objectives_list: VBoxContainer = $MarginContainer/HBoxContainer/RightPanel/DetailScroll/DetailContent/ObjectivesList
|
|
@onready var rewards_list: VBoxContainer = $MarginContainer/HBoxContainer/RightPanel/DetailScroll/DetailContent/RewardsList
|
|
|
|
var _current_tab: Tab = Tab.MAIN
|
|
var _selected_quest_id: StringName = &""
|
|
|
|
func _ready() -> void:
|
|
tab_bar.tab_changed.connect(_on_tab_changed)
|
|
GameEvents.quest_started.connect(_on_quest_changed)
|
|
GameEvents.quest_completed.connect(_on_quest_changed)
|
|
GameEvents.quest_objective_updated.connect(_on_objective_updated)
|
|
refresh()
|
|
|
|
func _on_tab_changed(index: int) -> void:
|
|
_current_tab = index as Tab
|
|
refresh()
|
|
|
|
func _on_quest_changed(_id: StringName) -> void:
|
|
refresh()
|
|
|
|
func _on_objective_updated(_qid: StringName, _idx: int, _cur: int, _req: int) -> void:
|
|
refresh() # simple et suffisant
|
|
|
|
# --- Rafraîchissement global ---
|
|
|
|
func refresh() -> void:
|
|
_clear_list()
|
|
var quests := _get_quests_for_tab(_current_tab)
|
|
|
|
if quests.is_empty():
|
|
_show_empty_state()
|
|
_clear_detail()
|
|
return
|
|
|
|
# Tri : principales par chapter_index, secondaires par titre
|
|
if _current_tab == Tab.MAIN:
|
|
quests.sort_custom(func(a, b): return a.chapter_index < b.chapter_index)
|
|
else:
|
|
quests.sort_custom(func(a, b): return a.title < b.title)
|
|
|
|
for quest in quests:
|
|
var entry := QUEST_ENTRY_SCENE.instantiate()
|
|
entry.setup(quest, _current_tab == Tab.COMPLETED)
|
|
entry.quest_selected.connect(_on_quest_selected)
|
|
quest_list.add_child(entry)
|
|
|
|
# Auto-sélection : garde la sélection actuelle si elle est toujours valide
|
|
var still_valid := quests.any(func(q): return q.quest_id == _selected_quest_id)
|
|
if still_valid:
|
|
_on_quest_selected(_selected_quest_id)
|
|
elif quests.size() > 0:
|
|
_on_quest_selected(quests[0].quest_id)
|
|
else:
|
|
_clear_detail()
|
|
|
|
_update_footer()
|
|
|
|
func _get_quests_for_tab(tab: Tab) -> Array[QuestData]:
|
|
var result: Array[QuestData] = []
|
|
match tab:
|
|
Tab.MAIN:
|
|
for q in QuestManager.active_quests.values():
|
|
if q.category == QuestData.Category.MAIN:
|
|
result.append(q)
|
|
Tab.SIDE:
|
|
for q in QuestManager.active_quests.values():
|
|
if q.category == QuestData.Category.SIDE:
|
|
result.append(q)
|
|
Tab.COMPLETED:
|
|
for q in QuestManager.completed_quests.values():
|
|
result.append(q)
|
|
return result
|
|
|
|
func _clear_list() -> void:
|
|
for child in quest_list.get_children():
|
|
child.queue_free()
|
|
|
|
func _show_empty_state() -> void:
|
|
var label := Label.new()
|
|
label.text = "Aucune quête dans cette catégorie."
|
|
label.add_theme_color_override("font_color", Color(0.6, 0.6, 0.6))
|
|
label.horizontal_alignment = HORIZONTAL_ALIGNMENT_CENTER
|
|
quest_list.add_child(label)
|
|
|
|
func _update_footer() -> void:
|
|
var main_count := 0
|
|
var side_count := 0
|
|
for q in QuestManager.active_quests.values():
|
|
if q.category == QuestData.Category.MAIN: main_count += 1
|
|
elif q.category == QuestData.Category.SIDE: side_count += 1
|
|
footer_label.text = "Principales : %d | Secondaires : %d | Terminées : %d" % [
|
|
main_count, side_count, QuestManager.completed_quests.size()
|
|
]
|
|
|
|
# --- Détail d'une quête ---
|
|
|
|
func _on_quest_selected(quest_id: StringName) -> void:
|
|
_selected_quest_id = quest_id
|
|
var quest: QuestData = QuestManager.all_quests.get(quest_id)
|
|
if quest == null:
|
|
_clear_detail()
|
|
return
|
|
|
|
detail_title.text = quest.title
|
|
detail_category.text = _category_label(quest.category)
|
|
detail_description.text = quest.description
|
|
|
|
# Objectifs
|
|
for child in objectives_list.get_children():
|
|
child.queue_free()
|
|
for obj in quest.objectives:
|
|
var row := OBJECTIVE_ROW_SCENE.instantiate()
|
|
row.setup(obj, _current_tab == Tab.COMPLETED)
|
|
objectives_list.add_child(row)
|
|
|
|
# Récompenses
|
|
for child in rewards_list.get_children():
|
|
child.queue_free()
|
|
for reward in quest.rewards:
|
|
var row := REWARD_ROW_SCENE.instantiate()
|
|
row.setup(reward)
|
|
rewards_list.add_child(row)
|
|
|
|
func _clear_detail() -> void:
|
|
detail_title.text = ""
|
|
detail_category.text = ""
|
|
detail_description.text = ""
|
|
for child in objectives_list.get_children():
|
|
child.queue_free()
|
|
for child in rewards_list.get_children():
|
|
child.queue_free()
|
|
|
|
func _category_label(cat: QuestData.Category) -> String:
|
|
match cat:
|
|
QuestData.Category.MAIN: return "QUÊTE PRINCIPALE"
|
|
QuestData.Category.SIDE: return "QUÊTE SECONDAIRE"
|
|
QuestData.Category.HIDDEN: return "QUÊTE SECRÈTE"
|
|
return ""
|