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.")