using System.Collections.Generic;
using UnityEngine;
using UnityEngine.Events;
/// <summary>
/// GAME 1303 Tier 4 — A bag of named true/false facts about the playthrough:
/// "met_the_ghost", "generator_powered", "boss_defeated", "took_the_left_path".
/// Doors, switches, dialogue and endings all read from here.
///
/// (This lands in Tier 4 because Door needs it. Tier 6's narrative scripts —
/// DialogueRunner, EndingSelector, WorldStateSwapper — use the same component.)
///
/// SETUP
/// - One empty GameObject "FlagManager" with this script. Tick Persist Across Scenes
/// for any game where progress spans levels.
/// - Set a flag from any UnityEvent: pick ChoiceFlagManager -> SetFlag (string).
/// e.g. BossController.OnBossDefeated -> SetFlag("boss1_defeated")
/// - Counters are for "how many times" questions: AddCount("ingredients_burned", 1).
///
/// From code:
/// ChoiceFlagManager.Instance.SetFlag("door_opened");
/// if (ChoiceFlagManager.Instance.HasFlag("has_key")) ...
/// int n = ChoiceFlagManager.Instance.GetCount("ghosts_freed");
/// </summary>
public class ChoiceFlagManager : MonoBehaviour
{
public static ChoiceFlagManager Instance { get; private set; }
public bool persistAcrossScenes = true;
[Tooltip("Flags that start set (useful for testing a later part of the game).")]
public List<string> startingFlags = new List<string>();
[Header("Events")]
public UnityEvent<string> OnFlagSet;
public UnityEvent<string> OnFlagCleared;
public UnityEvent<string, int> OnCountChanged;
private readonly HashSet<string> flags = new HashSet<string>();
private readonly Dictionary<string, int> counters = new Dictionary<string, int>();
void Awake()
{
if (Instance != null && Instance != this) { Destroy(gameObject); return; }
Instance = this;
if (persistAcrossScenes) DontDestroyOnLoad(gameObject);
foreach (var f in startingFlags) flags.Add(f);
}
// ---- Flags ----
public void SetFlag(string flag)
{
if (string.IsNullOrEmpty(flag) || !flags.Add(flag)) return;
OnFlagSet?.Invoke(flag);
}
public void ClearFlag(string flag)
{
if (!flags.Remove(flag)) return;
OnFlagCleared?.Invoke(flag);
}
public bool HasFlag(string flag) => !string.IsNullOrEmpty(flag) && flags.Contains(flag);
/// <summary>True only if every name in the comma-separated list is set. Prefix a name
/// with ! to require it NOT be set: "has_key, !alarm_tripped".</summary>
public bool HasAll(string commaSeparated)
{
if (string.IsNullOrWhiteSpace(commaSeparated)) return true;
foreach (var raw in commaSeparated.Split(','))
{
string s = raw.Trim();
if (s.Length == 0) continue;
bool negate = s[0] == '!';
if (negate) s = s.Substring(1).Trim();
if (HasFlag(s) == negate) return false;
}
return true;
}
// ---- Counters ----
public void AddCount(string key, int amount = 1)
{
counters.TryGetValue(key, out int c);
counters[key] = c + amount;
OnCountChanged?.Invoke(key, counters[key]);
}
public int GetCount(string key) => counters.TryGetValue(key, out int c) ? c : 0;
// ---- Bookkeeping ----
public void ResetAll()
{
flags.Clear();
counters.Clear();
foreach (var f in startingFlags) flags.Add(f);
}
/// <summary>All set flags, for a Tier 7 SaveSystem.</summary>
public List<string> GetAllFlags() => new List<string>(flags);
public void LoadFlags(IEnumerable<string> saved)
{
flags.Clear();
foreach (var f in saved) flags.Add(f);
}
}