using System.Collections.Generic;
using UnityEngine;
using UnityEngine.Events;
/// <summary>
/// GAME 1303 Tier 7 — "Changing the nature of the pet." Watches how the player has cared
/// for it over time and settles on a personality. Cozy Critters.
///
/// HOW IT WORKS
/// Every CareAction adds 1 to a counter named after its Personality Trait
/// ("well_fed", "playful", "cuddled", "groomed"). This script periodically compares the
/// counters and picks whichever Personality's trait has the highest share — but only once
/// there's enough evidence (Minimum Actions) and only if it clearly leads (Dominance
/// Threshold), so the pet doesn't flip personality every few minutes.
///
/// SETUP
/// 1. Add to the pet. Needs Tier 4's ChoiceFlagManager in the scene (it stores the counters).
/// 2. Add a Personality per outcome: an id, a display name, the trait it grows from, and
/// optionally a sprite/animator to swap in and a tint.
/// 3. Leave one personality with an empty trait as the default ("ordinary").
/// 4. OnPersonalityChanged fires when it settles somewhere new — good for a little
/// "your critter seems more playful lately" message.
/// 5. Happiness Stat (optional): a pet whose happiness has been low for a long time can
/// drift toward a Sad Personality id instead. Set Sad Personality Id and the threshold.
///
/// The point is that this is descriptive, not a score. There's no wrong personality —
/// which is what keeps it cozy.
/// </summary>
public class PersonalityTracker : MonoBehaviour
{
[System.Serializable]
public class Personality
{
public string id = "playful";
public string displayName = "Playful";
[TextArea(1, 3)] public string description = "";
[Tooltip("Counter name grown by CareActions (leave empty for the default personality).")]
public string trait = "playful";
[Header("Look (optional)")]
public RuntimeAnimatorController animatorController;
public Sprite portrait;
public Color tint = Color.white;
}
public List<Personality> personalities = new List<Personality>();
[Tooltip("How often to re-evaluate, in seconds.")]
public float evaluateEvery = 15f;
[Tooltip("Total care actions needed before a personality can form.")]
public int minimumActions = 10;
[Tooltip("A trait must hold at least this share of all actions to win (0.4 = 40%).")]
[Range(0.2f, 1f)] public float dominanceThreshold = 0.4f;
[Header("Sad drift (optional)")]
public NeedStat happiness;
public string sadPersonalityId = "";
[Range(0f, 1f)] public float sadBelow = 0.25f;
public float sadMinutesRequired = 5f;
[Header("Events")]
public UnityEvent<string> OnPersonalityChanged; // id
public Personality Current { get; private set; }
private Animator anim;
private SpriteRenderer sr;
private float timer;
private float sadMinutes;
void Awake()
{
anim = GetComponent<Animator>();
sr = GetComponentInChildren<SpriteRenderer>();
}
void Start()
{
Evaluate();
}
void Update()
{
if (happiness != null && happiness.Normalized < sadBelow)
sadMinutes += Time.deltaTime / 60f;
else
sadMinutes = Mathf.Max(0f, sadMinutes - Time.deltaTime / 60f);
timer -= Time.deltaTime;
if (timer <= 0f) { timer = evaluateEvery; Evaluate(); }
}
public void Evaluate()
{
if (personalities.Count == 0) return;
var flags = ChoiceFlagManager.Instance;
// Sad drift wins if it's been going on long enough
if (!string.IsNullOrEmpty(sadPersonalityId) && sadMinutes >= sadMinutesRequired)
{
var sad = personalities.Find(p => p.id == sadPersonalityId);
if (sad != null) { Apply(sad); return; }
}
int total = 0;
Personality best = null;
int bestCount = 0;
foreach (var p in personalities)
{
if (string.IsNullOrEmpty(p.trait)) continue;
int c = flags != null ? flags.GetCount(p.trait) : 0;
total += c;
if (c > bestCount) { bestCount = c; best = p; }
}
Personality result = Default();
if (total >= minimumActions && best != null && (float)bestCount / total >= dominanceThreshold)
result = best;
Apply(result);
}
Personality Default()
{
var d = personalities.Find(p => string.IsNullOrEmpty(p.trait));
return d ?? personalities[0];
}
void Apply(Personality p)
{
if (p == null || p == Current) return;
Current = p;
if (anim != null && p.animatorController != null) anim.runtimeAnimatorController = p.animatorController;
if (sr != null) sr.color = p.tint;
ChoiceFlagManager.Instance?.SetFlag("personality_" + p.id);
OnPersonalityChanged?.Invoke(p.id);
}
}