Compare commits

..

No commits in common. "4d39596516b93f12b973f5edf8361db11e5ec07a" and "f2013efadcca3ee8d9befb7d610c12cd9efaf08e" have entirely different histories.

26 changed files with 1 additions and 779 deletions

View file

@ -1,16 +0,0 @@
extends CanvasLayer
func _unhandled_input(event: InputEvent) -> void:
if event is InputEventKey and event.pressed and not event.echo:
match event.keycode:
KEY_F1:
FlagManager.debug_print_all()
KEY_F2:
QuestManager.debug_print_all()
KEY_F3:
# Test rapide : donne 3 badges
FlagManager.set_flag(&"badges_gagnes", 3)
print("3 badges ajoutés !")
KEY_F4:
# Test rapide : force la rencontre du Prof
FlagManager.set_flag(&"prof_rencontre", true)

View file

@ -1 +0,0 @@
uid://cniwr4iowd8we

View file

@ -1,201 +0,0 @@
extends Node
## Gestionnaire global de flags de progression.
## Un flag = un fait du monde identifié par un StringName.
##
## Types supportés : bool, int, String, float, Variant (fallback).
##
## Écriture : set_flag(), set_flag_once(), increment_flag()
## Lecture : get_flag(), has_flag(), is_flag_true()
## Conditions : evaluate_condition() pour tester des conditions composées.
# Stockage : flag_name (StringName) -> valeur (Variant)
var _flags: Dictionary = {}
# Flags marqués "one-shot" (ne peuvent être modifiés qu'une fois)
var _one_shot_flags: Dictionary = {} # flag_name -> true
# --- Écriture ---
## Définit un flag à une valeur. Écrase toujours.
func set_flag(flag_name: StringName, value: Variant) -> void:
var old_value: Variant = _flags.get(flag_name, null)
if old_value == value:
return
_flags[flag_name] = value
GameEvents.flag_changed.emit(flag_name, old_value, value)
_emit_legacy_signal(flag_name, value)
## Définit un flag uniquement s'il n'a jamais été défini.
## Retourne true si le flag a effectivement été posé.
func set_flag_once(flag_name: StringName, value: Variant = true) -> bool:
if flag_name in _flags:
return false
set_flag(flag_name, value)
_one_shot_flags[flag_name] = true
return true
## Incrémente un flag numérique. Crée le flag à 0 si inexistant.
func increment_flag(flag_name: StringName, amount: int = 1) -> void:
var current: int = int(_flags.get(flag_name, 0))
set_flag(flag_name, current + amount)
## Décrémente un flag numérique (utile pour consommation de ressources).
func decrement_flag(flag_name: StringName, amount: int = 1) -> void:
increment_flag(flag_name, -amount)
## Supprime un flag (à utiliser avec prudence en dev).
func clear_flag(flag_name: StringName) -> void:
if flag_name in _flags:
var old_value: Variant = _flags[flag_name]
_flags.erase(flag_name)
GameEvents.flag_changed.emit(flag_name, old_value, null)
# --- Lecture ---
func get_flag(flag_name: StringName, default: Variant = null) -> Variant:
return _flags.get(flag_name, default)
func has_flag(flag_name: StringName) -> bool:
return flag_name in _flags
## Retourne true si le flag existe ET vaut `true` (booléen).
## Pour un int, retourne true si non-zéro.
func is_flag_true(flag_name: StringName) -> bool:
if not flag_name in _flags:
return false
var v: Variant = _flags[flag_name]
if v is bool:
return v
if v is int or v is float:
return v != 0
return v != null
func get_int(flag_name: StringName, default: int = 0) -> int:
return int(_flags.get(flag_name, default))
func get_bool(flag_name: StringName, default: bool = false) -> bool:
return bool(_flags.get(flag_name, default))
func get_string(flag_name: StringName, default: String = "") -> String:
return String(_flags.get(flag_name, default))
# --- Conditions composées ---
## Évalue un dictionnaire de conditions :
## {
## &"prof_rencontre": true, # flag == true
## &"badges_gagnes": 3, # flag >= 3 (int)
## &"starter_choisi": "pikachu", # flag == "pikachu"
## }
## Retourne true si TOUTES les conditions sont satisfaites.
func evaluate_condition(conditions: Dictionary) -> bool:
for flag_name in conditions:
var expected: Variant = conditions[flag_name]
var actual: Variant = _flags.get(flag_name, null)
# Booléen attendu : on teste la vérité (marche pour bool et int)
if expected is bool:
if is_flag_true(flag_name) != expected:
return false
# Int attendu : on teste >= (utile pour les compteurs)
elif expected is int:
if int(actual if actual != null else 0) < expected:
return false
# String / autre : égalité stricte
else:
if actual != expected:
return false
return true
## Version "au moins une condition vraie" (OR).
func evaluate_any_condition(conditions: Dictionary) -> bool:
for flag_name in conditions:
var expected: Variant = conditions[flag_name]
var actual: Variant = _flags.get(flag_name, null)
if expected is bool:
if is_flag_true(flag_name) == expected:
return true
elif expected is int:
if int(actual if actual != null else 0) >= expected:
return true
else:
if actual == expected:
return true
return false
# --- Signaux spécifiques (optionnel mais pratique) ---
## Émet des signaux dédiés pour certains flags pour simplifier les connexions.
## Exemple : GameEvents.badge_gagne.emit() si le flag "badges_gagnes" change.
func _emit_legacy_signal(flag_name: StringName, value: Variant) -> void:
# Ajoute ici tes mappings custom si tu veux des signaux dédiés.
# Ex :
# if flag_name == &"badges_gagnes":
# GameEvents.badge_count_changed.emit(int(value))
pass
# --- Connexion automatique aux événements du jeu ---
func _ready() -> void:
_connect_gameplay_events()
func _connect_gameplay_events() -> void:
GameEvents.pokemon_captured.connect(_on_pokemon_captured)
GameEvents.pokemon_defeated.connect(_on_pokemon_defeated)
GameEvents.item_collected.connect(_on_item_collected)
GameEvents.npc_talked.connect(_on_npc_talked)
GameEvents.location_reached.connect(_on_location_reached)
func _on_pokemon_captured(species_id: StringName) -> void:
increment_flag(&"nb_pokemon_captures", 1)
set_flag_once(&"premier_pokemon_capture", true)
# Flag spécifique par espèce : ex. "capture_chenipan" = true
set_flag(StringName("capture_%s" % species_id), true)
increment_flag(StringName("nb_captures_%s" % species_id), 1)
func _on_pokemon_defeated(species_id: StringName) -> void:
increment_flag(&"nb_pokemon_vaincus", 1)
increment_flag(StringName("nb_vaincus_%s" % species_id), 1)
func _on_item_collected(item_id: StringName, amount: int) -> void:
increment_flag(StringName("item_%s" % item_id), amount)
func _on_npc_talked(npc_id: StringName) -> void:
set_flag(StringName("talked_%s" % npc_id), true)
increment_flag(StringName("nb_dialogues_%s" % npc_id), 1)
func _on_location_reached(location_id: StringName) -> void:
set_flag(StringName("visited_%s" % location_id), true)
# --- Sauvegarde / Chargement ---
func get_save_data() -> Dictionary:
return {
"flags": _flags.duplicate(true),
"one_shot": _one_shot_flags.duplicate(),
}
func load_save_data(data: Dictionary) -> void:
_flags = data.get("flags", {}).duplicate(true)
_one_shot_flags = data.get("one_shot", {}).duplicate()
# --- Debug ---
func debug_print_all() -> void:
print("\n=== FLAGS ===")
if _flags.is_empty():
print("(aucun flag)")
else:
var keys: Array = _flags.keys()
keys.sort()
for flag_name in keys:
var v: Variant = _flags[flag_name]
var type_str := type_string(typeof(v))
var one_shot := " [one-shot]" if flag_name in _one_shot_flags else ""
print(" %s = %s (%s)%s" % [flag_name, str(v), type_str, one_shot])
print("=============\n")
func debug_clear_all() -> void:
_flags.clear()
_one_shot_flags.clear()
print("[FlagManager] Tous les flags ont été effacés.")

View file

@ -1 +0,0 @@
uid://ceb0ky3nlq1do

View file

@ -49,11 +49,6 @@ func _set_selected(index : int) -> void:
func save() -> void:
var config := ConfigFile.new()
config.set_value("game", "version", 1)
config.set_value("game", "timestamp", Time.get_datetime_string_from_system())
config.set_value("flags", "flags", FlagManager.get_save_data())
config.set_value("quests", "quests", QuestManager.get_save_data())
config.set_value("progress", "story_progress", story_progress)
config.set_value("team", "data", player_team.to_dict())
config.set_value("storage", "data", player_storage.to_dict())
@ -67,7 +62,3 @@ func load_data() -> void:
player_team = PokemonTeam.from_dict(team_data) if team_data is Dictionary else PokemonTeam.new()
var storage_data : Variant = config.get_value("storage", "data", {})
player_storage = PokemonStorage.from_dict(storage_data) if storage_data is Dictionary else PokemonStorage.new()
var flags_data : Variant = config.get_value("flags", "flags", {})
FlagManager.load_save_data(flags_data)
var quests_data : Variant = config.get_value("quests", "quests", {})
QuestManager.load_save_data(quests_data)

View file

@ -1,17 +0,0 @@
extends Node
# --- Quêtes (existants) ---
signal quest_started(quest_id: StringName)
signal quest_completed(quest_id: StringName)
signal quest_available(quest_id: StringName)
signal quest_objective_updated(quest_id: StringName, objective_index: int, current: int, required: int)
# --- Gameplay (existants) ---
signal pokemon_captured(species_id: StringName)
signal pokemon_defeated(species_id: StringName)
signal item_collected(item_id: StringName, amount: int)
signal npc_talked(npc_id: StringName)
signal location_reached(location_id: StringName)
# --- Flags (nouveau) ---
signal flag_changed(flag_name: StringName, old_value: Variant, new_value: Variant)

View file

@ -1 +0,0 @@
uid://ct3v0qsc3bvcn

View file

@ -1,263 +0,0 @@
extends Node
var all_quests: Dictionary = {} # quest_id -> QuestData
var active_quests: Dictionary = {} # quest_id -> QuestData
var completed_quests: Dictionary = {} # quest_id -> QuestData
var failed_quests: Dictionary = {}
const QUESTS_PATH := "res://game/quests/data/"
func _ready() -> void:
_load_all_quests()
_connect_events()
_refresh_quest_states()
GameEvents.flag_changed.connect(_on_flag_changed)
func _on_flag_changed(_flag_name: StringName, _old_value: Variant, _new_value: Variant) -> void:
_refresh_quest_states()
# --- Chargement ---
func _load_all_quests() -> void:
var dir := DirAccess.open(QUESTS_PATH)
if dir == null:
push_error("Dossier de quêtes introuvable : " + QUESTS_PATH)
return
for file in dir.get_files():
if file.ends_with(".tres"):
var quest: QuestData = load(QUESTS_PATH + file)
if quest and quest.quest_id != &"":
all_quests[quest.quest_id] = quest
# --- Calcul d'état (cœur du système de chaînes) ---
## Recalcule l'état de toutes les quêtes non-commencées :
## une quête passe de LOCKED à AVAILABLE si ses prérequis sont satisfaits.
func _refresh_quest_states() -> void:
for quest_id in all_quests:
var quest: QuestData = all_quests[quest_id]
if quest.state in [QuestData.QuestState.ACTIVE, QuestData.QuestState.COMPLETED, QuestData.QuestState.FAILED]:
continue
if _are_prerequisites_met(quest):
if quest.state == QuestData.QuestState.LOCKED:
quest.state = QuestData.QuestState.AVAILABLE
_emit_quest_available(quest_id)
else:
quest.state = QuestData.QuestState.LOCKED
func _are_prerequisites_met(quest: QuestData) -> bool:
# 1. Prérequis de quêtes
for prereq in quest.prerequisites:
if not prereq in completed_quests:
return false
# 2. Flags bloquants (si l'un est vrai → la quête ne peut PAS se débloquer)
if not quest.blocking_flags.is_empty():
if FlagManager.evaluate_condition(quest.blocking_flags):
return false
# 3. Flags requis (tous doivent être vrais)
if not quest.required_flags.is_empty():
if not FlagManager.evaluate_condition(quest.required_flags):
return false
return true
func _emit_quest_available(quest_id: StringName) -> void:
# Optionnel : signal pour notifier l'UI ou un PNJ
GameEvents.quest_available.emit(quest_id)
# --- Connexion aux événements ---
func _connect_events() -> void:
GameEvents.pokemon_captured.connect(_on_pokemon_captured)
GameEvents.pokemon_defeated.connect(_on_pokemon_defeated)
GameEvents.item_collected.connect(_on_item_collected)
GameEvents.npc_talked.connect(_on_npc_talked)
GameEvents.location_reached.connect(_on_location_reached)
# --- Démarrage de quête ---
func start_quest(quest_id: StringName, force: bool = false) -> bool:
if quest_id in active_quests or quest_id in completed_quests:
return false
if not quest_id in all_quests:
push_warning("Quête inconnue : " + str(quest_id))
return false
var quest: QuestData = all_quests[quest_id]
# Vérifie les prérequis (sauf si forcé, pour debug)
if not force and not _are_prerequisites_met(quest):
return false
# Reset les compteurs
for obj in quest.objectives:
obj.current_count = 0
quest.state = QuestData.QuestState.ACTIVE
active_quests[quest_id] = quest
GameEvents.quest_started.emit(quest_id)
return true
## Démarre automatiquement toutes les quêtes disponibles qui n'attendent
## pas de déblocage manuel. À appeler après un chargement de zone, par ex.
func auto_start_available_quests() -> void:
for quest_id in all_quests:
var quest: QuestData = all_quests[quest_id]
if quest.state == QuestData.QuestState.AVAILABLE and not quest.requires_manual_unlock:
start_quest(quest_id)
# --- Progression ---
func _progress_objective(event_type: QuestObjective.Type, target: StringName) -> void:
for quest_id in active_quests.keys():
var quest: QuestData = active_quests[quest_id]
var changed := false
for i in quest.objectives.size():
var obj: QuestObjective = quest.objectives[i]
if obj.is_complete():
continue
if obj.matches(event_type, target):
obj.current_count = min(obj.current_count + 1, obj.required_count)
changed = true
GameEvents.quest_objective_updated.emit(
quest_id, i, obj.current_count, obj.required_count
)
if changed and quest.are_all_objectives_complete():
_complete_quest(quest_id)
# --- Handlers d'événements ---
func _on_pokemon_captured(species_id: StringName) -> void:
_progress_objective(QuestObjective.Type.CAPTURE, species_id)
func _on_pokemon_defeated(species_id: StringName) -> void:
_progress_objective(QuestObjective.Type.DEFEAT, species_id)
func _on_item_collected(item_id: StringName, amount: int) -> void:
# On avance de `amount` unités
for quest_id in active_quests.keys():
var quest: QuestData = active_quests[quest_id]
for i in quest.objectives.size():
var obj: QuestObjective = quest.objectives[i]
if obj.type == QuestObjective.Type.COLLECT \
and obj.target_id == item_id \
and not obj.is_complete():
obj.current_count = min(obj.current_count + amount, obj.required_count)
GameEvents.quest_objective_updated.emit(
quest_id, i, obj.current_count, obj.required_count
)
if quest.are_all_objectives_complete():
_complete_quest(quest_id)
func _on_npc_talked(npc_id: StringName) -> void:
_progress_objective(QuestObjective.Type.TALK_TO, npc_id)
func _on_location_reached(location_id: StringName) -> void:
_progress_objective(QuestObjective.Type.REACH_LOCATION, location_id)
# --- Fin de quête ---
func _complete_quest(quest_id: StringName) -> void:
var quest: QuestData = active_quests[quest_id]
quest.state = QuestData.QuestState.COMPLETED
active_quests.erase(quest_id)
completed_quests[quest_id] = quest
_give_rewards(quest)
GameEvents.quest_completed.emit(quest_id)
# 🔑 C'est ici que la magie opère : les quêtes suivantes se débloquent !
_refresh_quest_states()
# Optionnel : auto-démarrer les quêtes suivantes qui ne demandent
# pas de déblocage manuel (ex: chaîne principale purement scriptée)
auto_start_available_quests()
func _give_rewards(quest: QuestData) -> void:
for reward in quest.rewards:
match reward.type:
QuestReward.Type.ITEM:
# À adapter à ton système d'inventaire
GameEvents.item_collected.emit(reward.target_id, reward.amount)
QuestReward.Type.MONEY:
# Inventory.add_money(reward.amount)
pass
QuestReward.Type.POKEMON:
# Team.add_pokemon(reward.target_id)
pass
QuestReward.Type.UNLOCK_QUEST:
start_quest(reward.target_id)
# --- Sauvegarde / Chargement ---
func get_save_data() -> Dictionary:
var data := {
"active": {}, # quest_id -> Array[int] (progressions)
"completed": [], # Array[StringName]
"failed": []
}
for id in active_quests:
var quest: QuestData = active_quests[id]
var counts: Array[int] = []
for obj in quest.objectives:
counts.append(obj.current_count)
data["active"][id] = counts
data["completed"] = completed_quests.keys()
data["failed"] = failed_quests.keys()
return data
func load_save_data(data: Dictionary) -> void:
active_quests.clear()
completed_quests.clear()
failed_quests.clear()
# Reset tous les états à LOCKED
for q in all_quests.values():
q.state = QuestData.QuestState.LOCKED
for obj in q.objectives:
obj.current_count = 0
# Restaure les complétées
for id in data.get("completed", []):
if id in all_quests:
all_quests[id].state = QuestData.QuestState.COMPLETED
completed_quests[id] = all_quests[id]
# Restaure les actives
for id in data.get("active", {}):
if id in all_quests:
var quest: QuestData = all_quests[id]
var counts: Array = data["active"][id]
for i in quest.objectives.size():
quest.objectives[i].current_count = counts[i] if i < counts.size() else 0
quest.state = QuestData.QuestState.ACTIVE
active_quests[id] = quest
# Recalcule les LOCKED / AVAILABLE
_refresh_quest_states()
func debug_print_all() -> void:
print("\n=== ÉTAT DES QUÊTES ===")
for quest_id in all_quests:
var q: QuestData = all_quests[quest_id]
var state_str := q.get_state_name()
var cat_str := q.get_category_name()
print("\n[%s][%s] %s — %s" % [cat_str, state_str, q.quest_id, q.title])
for i in q.objectives.size():
var obj := q.objectives[i]
var done := "✓" if obj.is_complete() else " "
var optional := " (optionnel)" if obj.is_optional else ""
print(" [%s] %s : %d/%d%s" % [
done, obj.description, obj.current_count, obj.required_count, optional
])
print("\n=======================\n")
func _input(event):
if event.is_action_pressed("debug_quests"):
QuestManager.debug_print_all()

View file

@ -1 +0,0 @@
uid://owgkeygdlsmv

View file

@ -1,25 +0,0 @@
[gd_resource type="Resource" script_class="QuestData" format=3 uid="uid://cx1rj8j6ww65u"]
[ext_resource type="Script" uid="uid://dj84i3mki0cws" path="res://game/quests/quest_objective.gd" id="1_yy5gg"]
[ext_resource type="Script" uid="uid://bpjxqwo7c5f64" path="res://game/quests/quest_reward.gd" id="2_w6uu2"]
[ext_resource type="Script" uid="uid://bldyeahkrms8n" path="res://game/quests/quest_data.gd" id="3_8rvwr"]
[sub_resource type="Resource" id="Resource_fl2hl"]
script = ExtResource("1_yy5gg")
target_id = &"prof_chen"
metadata/_custom_type_script = "uid://dj84i3mki0cws"
[sub_resource type="Resource" id="Resource_5xet1"]
script = ExtResource("2_w6uu2")
target_id = &"pokedex"
metadata/_custom_type_script = "uid://bpjxqwo7c5f64"
[resource]
script = ExtResource("3_8rvwr")
quest_id = &"main_01_prof"
title = "Prof"
category = 0
objectives = Array[ExtResource("1_yy5gg")]([SubResource("Resource_fl2hl")])
rewards = Array[ExtResource("2_w6uu2")]([SubResource("Resource_5xet1")])
requires_manual_unlock = true
metadata/_custom_type_script = "uid://bldyeahkrms8n"

View file

@ -1,14 +0,0 @@
[gd_resource type="Resource" script_class="QuestData" format=3 uid="uid://d007l7h0dy3vt"]
[ext_resource type="Script" uid="uid://dj84i3mki0cws" path="res://game/quests/quest_objective.gd" id="1_dsryk"]
[ext_resource type="Script" uid="uid://bpjxqwo7c5f64" path="res://game/quests/quest_reward.gd" id="2_0a632"]
[ext_resource type="Script" uid="uid://bldyeahkrms8n" path="res://game/quests/quest_data.gd" id="3_0ncdg"]
[resource]
script = ExtResource("3_0ncdg")
quest_id = &"main_01_start"
title = "Reçois ton premier Pokémon"
category = 0
requires_manual_unlock = true
chapter_index = 1
metadata/_custom_type_script = "uid://bldyeahkrms8n"

View file

@ -1,14 +0,0 @@
[gd_resource type="Resource" script_class="QuestData" format=3 uid="uid://b2o84nycfwg3g"]
[ext_resource type="Script" uid="uid://dj84i3mki0cws" path="res://game/quests/quest_objective.gd" id="1_pjbw5"]
[ext_resource type="Script" uid="uid://bpjxqwo7c5f64" path="res://game/quests/quest_reward.gd" id="2_eesy8"]
[ext_resource type="Script" uid="uid://bldyeahkrms8n" path="res://game/quests/quest_data.gd" id="3_wi6e2"]
[resource]
script = ExtResource("3_wi6e2")
quest_id = &"main_02_route1"
title = "Traverse la Route 1"
category = 0
prerequisites = Array[StringName]([&"main_01_start"])
chapter_index = 2
metadata/_custom_type_script = "uid://bldyeahkrms8n"

View file

@ -1,27 +0,0 @@
[gd_resource type="Resource" script_class="QuestData" format=3 uid="uid://bbdba5sej5opj"]
[ext_resource type="Script" uid="uid://dj84i3mki0cws" path="res://game/quests/quest_objective.gd" id="1_reajj"]
[ext_resource type="Script" uid="uid://bpjxqwo7c5f64" path="res://game/quests/quest_reward.gd" id="2_0q14y"]
[ext_resource type="Script" uid="uid://bldyeahkrms8n" path="res://game/quests/quest_data.gd" id="3_5inpn"]
[sub_resource type="Resource" id="Resource_1x48t"]
script = ExtResource("1_reajj")
type = 2
target_id = &"pikachu"
metadata/_custom_type_script = "uid://dj84i3mki0cws"
[sub_resource type="Resource" id="Resource_pjk6h"]
script = ExtResource("2_0q14y")
target_id = &"pokeball"
amount = 5
metadata/_custom_type_script = "uid://bpjxqwo7c5f64"
[resource]
script = ExtResource("3_5inpn")
quest_id = &"main_02_starter"
title = "Starter"
category = 0
objectives = Array[ExtResource("1_reajj")]([SubResource("Resource_1x48t")])
rewards = Array[ExtResource("2_0q14y")]([SubResource("Resource_pjk6h")])
prerequisites = Array[StringName]([&"main_01_prof"])
metadata/_custom_type_script = "uid://bldyeahkrms8n"

View file

@ -1,14 +0,0 @@
[gd_resource type="Resource" script_class="QuestData" format=3 uid="uid://djsmge1a745q2"]
[ext_resource type="Script" uid="uid://dj84i3mki0cws" path="res://game/quests/quest_objective.gd" id="1_y246s"]
[ext_resource type="Script" uid="uid://bpjxqwo7c5f64" path="res://game/quests/quest_reward.gd" id="2_ywsws"]
[ext_resource type="Script" uid="uid://bldyeahkrms8n" path="res://game/quests/quest_data.gd" id="3_bp48w"]
[resource]
script = ExtResource("3_bp48w")
quest_id = &"main_03_arène1"
title = "Bats l'Arène de Jadielle"
category = 0
prerequisites = Array[StringName]([&"main_02_route1"])
chapter_index = 3
metadata/_custom_type_script = "uid://bldyeahkrms8n"

View file

@ -1,14 +0,0 @@
[gd_resource type="Resource" script_class="QuestData" format=3 uid="uid://cywdaoplv561d"]
[ext_resource type="Script" uid="uid://dj84i3mki0cws" path="res://game/quests/quest_objective.gd" id="1_gq0xw"]
[ext_resource type="Script" uid="uid://bpjxqwo7c5f64" path="res://game/quests/quest_reward.gd" id="2_nwtdp"]
[ext_resource type="Script" uid="uid://bldyeahkrms8n" path="res://game/quests/quest_data.gd" id="3_dcxfq"]
[resource]
script = ExtResource("3_dcxfq")
quest_id = &"main_04_team_rocket"
title = "Chasse la Team Rocket"
category = 0
prerequisites = Array[StringName]([&"main_03_arène1"])
chapter_index = 4
metadata/_custom_type_script = "uid://bldyeahkrms8n"

View file

@ -1,18 +0,0 @@
[gd_resource type="Resource" script_class="QuestData" format=3 uid="uid://d7q633m7osyu"]
[ext_resource type="Script" uid="uid://dj84i3mki0cws" path="res://game/quests/quest_objective.gd" id="1_wkil8"]
[ext_resource type="Script" uid="uid://bpjxqwo7c5f64" path="res://game/quests/quest_reward.gd" id="2_eemhw"]
[ext_resource type="Script" uid="uid://bldyeahkrms8n" path="res://game/quests/quest_data.gd" id="3_r5m7j"]
[sub_resource type="Resource" id="Resource_l3iqy"]
script = ExtResource("1_wkil8")
target_id = &"champion"
metadata/_custom_type_script = "uid://dj84i3mki0cws"
[resource]
script = ExtResource("3_r5m7j")
quest_id = &"side_badges"
title = "Side Badges"
objectives = Array[ExtResource("1_wkil8")]([SubResource("Resource_l3iqy")])
requires_manual_unlock = true
metadata/_custom_type_script = "uid://bldyeahkrms8n"

View file

@ -1,33 +0,0 @@
[gd_resource type="Resource" script_class="QuestData" format=3 uid="uid://c0iff4kfhxidm"]
[ext_resource type="Script" uid="uid://dj84i3mki0cws" path="res://game/quests/quest_objective.gd" id="1_mcbuv"]
[ext_resource type="Script" uid="uid://bpjxqwo7c5f64" path="res://game/quests/quest_reward.gd" id="2_6way2"]
[ext_resource type="Script" uid="uid://bldyeahkrms8n" path="res://game/quests/quest_data.gd" id="3_fslg5"]
[sub_resource type="Resource" id="Resource_lmqnn"]
script = ExtResource("1_mcbuv")
type = 2
target_id = &"caterpie"
description = "Capturer un Chenipan"
metadata/_custom_type_script = "uid://dj84i3mki0cws"
[sub_resource type="Resource" id="Resource_1xmq8"]
script = ExtResource("1_mcbuv")
target_id = &"prof_chen"
description = "Rapporter le Chenipan au Professeur"
metadata/_custom_type_script = "uid://dj84i3mki0cws"
[sub_resource type="Resource" id="Resource_xnmnt"]
script = ExtResource("2_6way2")
target_id = &"pokeball"
metadata/_custom_type_script = "uid://bpjxqwo7c5f64"
[resource]
script = ExtResource("3_fslg5")
quest_id = &"side_chenipan"
title = "Le Chenipan du Professeur"
description = "Le Professeur Chen veut étudier un Chenipan."
objectives = Array[ExtResource("1_mcbuv")]([SubResource("Resource_lmqnn"), SubResource("Resource_1xmq8")])
rewards = Array[ExtResource("2_6way2")]([SubResource("Resource_xnmnt")])
requires_manual_unlock = true
metadata/_custom_type_script = "uid://bldyeahkrms8n"

View file

@ -1,13 +0,0 @@
[gd_resource type="Resource" script_class="QuestData" format=3 uid="uid://5xw8pcuefrfl"]
[ext_resource type="Script" uid="uid://dj84i3mki0cws" path="res://game/quests/quest_objective.gd" id="1_rk5ju"]
[ext_resource type="Script" uid="uid://bpjxqwo7c5f64" path="res://game/quests/quest_reward.gd" id="2_r8x02"]
[ext_resource type="Script" uid="uid://bldyeahkrms8n" path="res://game/quests/quest_data.gd" id="3_5wjtt"]
[resource]
script = ExtResource("3_5wjtt")
quest_id = &"side_pêcheur"
title = "Le Pêcheur Poissirène"
prerequisites = Array[StringName]([&"main_02_route1"])
requires_manual_unlock = true
metadata/_custom_type_script = "uid://bldyeahkrms8n"

View file

@ -1,41 +0,0 @@
extends Resource
class_name QuestData
enum QuestState { LOCKED, AVAILABLE, ACTIVE, COMPLETED, FAILED }
enum Category { MAIN, SIDE, HIDDEN }
@export var quest_id: StringName = &""
@export var title: String = ""
@export_multiline var description: String = ""
@export var category: Category = Category.SIDE
@export var objectives: Array[QuestObjective] = []
@export var rewards: Array[QuestReward] = []
@export var prerequisites: Array[StringName] = []
@export var requires_manual_unlock: bool = false
@export var chapter_index: int = 0
## NOUVEAU : conditions sur les flags pour que la quête soit disponible.
## Exemple :
## { &"prof_rencontre": true, &"badges_gagnes": 3 }
@export var required_flags: Dictionary = {}
## NOUVEAU : si l'un de ces flags est vrai, la quête ne se débloque PAS.
## Utile pour les choix exclusifs (ex: avoir choisi la Team Rocket).
@export var blocking_flags: Dictionary = {}
var state: QuestState = QuestState.LOCKED
func get_required_objectives() -> Array[QuestObjective]:
return objectives.filter(func(o): return not o.is_optional)
func are_all_objectives_complete() -> bool:
for obj in get_required_objectives():
if not obj.is_complete():
return false
return true
func get_state_name() -> String:
return QuestState.keys()[state]
func get_category_name() -> String:
return Category.keys()[category]

View file

@ -1 +0,0 @@
uid://bldyeahkrms8n

View file

@ -1,27 +0,0 @@
extends Resource
class_name QuestObjective
enum Type {
TALK_TO, # Parler à un PNJ
COLLECT, # Récolter/Ramasser un objet
CAPTURE, # Capturer un Pokémon
DEFEAT, # Battre un Pokémon
REACH_LOCATION, # Atteindre un lieu
CUSTOM # Pour extensions futures
}
@export var type: Type = Type.TALK_TO
@export var target_id: StringName = &"" # ex: &"chenipan", &"prof_chen"
@export var required_count: int = 1
@export var is_optional: bool = false
@export var description: String = "" # Texte affiché dans le journal
# Progression (non exportée : gérée en runtime par le QuestManager)
var current_count: int = 0
func is_complete() -> bool:
return current_count >= required_count
## Retourne true si l'événement correspond à cet objectif
func matches(event_type: Type, event_target: StringName) -> bool:
return type == event_type and target_id == event_target

View file

@ -1 +0,0 @@
uid://dj84i3mki0cws

View file

@ -1,13 +0,0 @@
extends Resource
class_name QuestReward
enum Type {
ITEM, # Donner un objet
MONEY, # Donner de l'argent
POKEMON, # Donner un Pokémon
UNLOCK_QUEST # Débloquer une nouvelle quête
}
@export var type: Type = Type.ITEM
@export var target_id: StringName = &"" # ex: &"pokeball", &"pokedex"
@export var amount: int = 1

View file

@ -1 +0,0 @@
uid://bpjxqwo7c5f64

View file

@ -2,7 +2,6 @@
[ext_resource type="Script" uid="uid://7hglx6nfu063" path="res://addons/controller_icons/objects/ControllerIconTexture.gd" id="1_4xhdt"]
[ext_resource type="Script" uid="uid://b3ddqgiawrh5c" path="res://game/ui/hud/team_hud.gd" id="2_lkjh2"]
[ext_resource type="Script" uid="uid://cniwr4iowd8we" path="res://game/core/debug_overlay.gd" id="3_euh0j"]
[sub_resource type="StyleBoxEmpty" id="StyleBoxEmpty_uyiaf"]
@ -93,6 +92,3 @@ anchor_bottom = 1.0
grow_horizontal = 2
grow_vertical = 2
script = ExtResource("2_lkjh2")
[node name="DebugOverlay" type="CanvasLayer" parent="." unique_id=1710349785]
script = ExtResource("3_euh0j")

View file

@ -24,12 +24,9 @@ buses/default_bus_layout="res://game/core/default_bus_layout.tres"
[autoload]
ControllerIcons="*uid://b7ho1rjcpht1d"
UiAudio="*uid://7e7fe2xk3aue"
GameData="*uid://d4beiel88cwc7"
GameEvents="*uid://ct3v0qsc3bvcn"
QuestManager="*uid://owgkeygdlsmv"
UiAudio="*uid://7e7fe2xk3aue"
Pokedex="*uid://dijnkrewbwgmx"
FlagManager="*uid://ceb0ky3nlq1do"
[display]
@ -166,11 +163,6 @@ player_aim_switch_target={
"events": [Object(InputEventJoypadButton,"resource_local_to_scene":false,"resource_name":"","device":-1,"button_index":0,"pressure":0.0,"pressed":true,"script":null)
]
}
debug_quests={
"deadzone": 0.2,
"events": [Object(InputEventKey,"resource_local_to_scene":false,"resource_name":"","device":-1,"window_id":0,"alt_pressed":false,"shift_pressed":false,"ctrl_pressed":false,"meta_pressed":false,"pressed":false,"keycode":0,"physical_keycode":67,"key_label":0,"unicode":99,"location":0,"echo":false,"script":null)
]
}
[physics]