using UnityEngine;
using UnityEngine.Events;
/// <summary>
/// GAME 1303 Tier 6 — "Press E." A thing in the world the player can examine, talk to,
/// pick up, or operate. Anabasis, Detective Liz (clues), Commission Witch (order board),
/// Cozy Critters, Store Simulator.
///
/// SETUP
/// 1. Object + Collider2D (Is Trigger) sized to how close the player must stand + this script.
/// 2. Prompt Text: what the little floating label says ("Examine", "Talk", "Pick up").
/// 3. Wire OnInteract to whatever should happen: DialogueRunner.StartDialogue,
/// Door.Open, ChoiceFlagManager.SetFlag, an animation, a sound.
/// 4. One Shot: can only be used once (a note you read, an item you take).
/// 5. Require Flag / Blocked By Flag: gate an interaction on story state, e.g. a locked
/// desk that only works once you have "found_key".
/// 6. The player needs an InteractionPrompt component (see the other script) — one on the
/// player object handles every interactable in the game.
///
/// This is the single most reusable script in the narrative tier: almost every "something
/// happens when the player does a thing here" moment is an Interactable plus a UnityEvent.
/// </summary>
[RequireComponent(typeof(Collider2D))]
public class Interactable : MonoBehaviour
{
[Header("Prompt")]
public string promptText = "Examine";
[Tooltip("Where the floating prompt appears. Leave empty for just above this object.")]
public Transform promptAnchor;
public Vector2 promptOffset = new Vector2(0f, 1f);
[Header("Rules")]
public bool oneShot = false;
[Tooltip("Flags required (comma separated; prefix ! to require NOT set).")]
public string requireFlags = "";
[Tooltip("Set this flag when interacted with. Leave blank for none.")]
public string setFlagOnInteract = "";
public bool startEnabled = true;
[Header("Feedback")]
public string sfxName = "";
public Sprite usedSprite;
[Header("Events")]
public UnityEvent OnInteract;
public UnityEvent OnBecameAvailable;
public UnityEvent OnPlayerEntered;
public UnityEvent OnPlayerExited;
public bool Used { get; private set; }
public bool IsAvailable => startEnabled && enabled && !(oneShot && Used) && FlagsOk();
public Vector3 PromptPosition =>
(promptAnchor != null ? promptAnchor.position : transform.position) + (Vector3)promptOffset;
void Reset() { GetComponent<Collider2D>().isTrigger = true; }
bool FlagsOk()
{
if (string.IsNullOrWhiteSpace(requireFlags)) return true;
return ChoiceFlagManager.Instance == null || ChoiceFlagManager.Instance.HasAll(requireFlags);
}
void OnTriggerEnter2D(Collider2D other)
{
if (!other.CompareTag("Player")) return;
InteractionPrompt.Register(this);
OnPlayerEntered?.Invoke();
}
void OnTriggerExit2D(Collider2D other)
{
if (!other.CompareTag("Player")) return;
InteractionPrompt.Unregister(this);
OnPlayerExited?.Invoke();
}
void OnDisable() => InteractionPrompt.Unregister(this);
/// <summary>Called by InteractionPrompt when the player presses the interact button.</summary>
public void Interact()
{
if (!IsAvailable) return;
Used = true;
if (!string.IsNullOrEmpty(sfxName)) AudioManager.Instance?.PlaySFX(sfxName);
if (!string.IsNullOrEmpty(setFlagOnInteract)) ChoiceFlagManager.Instance?.SetFlag(setFlagOnInteract);
if (usedSprite != null)
{
var sr = GetComponentInChildren<SpriteRenderer>();
if (sr != null) sr.sprite = usedSprite;
}
OnInteract?.Invoke();
if (oneShot) InteractionPrompt.Unregister(this);
}
/// <summary>Turn an interactable on later in the story.</summary>
public void SetAvailable(bool available)
{
startEnabled = available;
if (available) OnBecameAvailable?.Invoke();
}
void OnDrawGizmosSelected()
{
Gizmos.color = Color.yellow;
Gizmos.DrawWireSphere(PromptPosition, 0.15f);
}
}