using UnityEngine;
using UnityEngine.Events;
/// <summary>
/// GAME 1303 Tier 6 — A ghost that hates the flashlight. Flees, freezes, fades, or burns
/// while lit. Detective Liz ("uses her flashlight to fight ghosts"); a Commission Witch
/// variant works too.
///
/// SETUP
/// 1. Ghost: FloatingEnemy and/or EnemyChase (Tier 2) + Health + this script.
/// Add a Hurtbox child (Team = Enemy) so the flashlight's Hitbox can damage it.
/// 2. Drag the player's Flashlight2D in, or leave it empty and it finds the Player tag.
/// 3. Reaction while lit:
/// Flee – runs away from the player (EnemyChase is disabled while lit)
/// Freeze – stops dead, vulnerable
/// Weaken – keeps moving but takes damage (via the beam's Hitbox) and fades
/// Banish – takes Damage Per Second directly from this script; no Hitbox needed
/// 4. Fade While Lit makes it visibly weaker — good feedback even without damage numbers.
/// 5. Requires Line Of Sight stops the beam working through walls.
///
/// The reason this is a separate script rather than just "the beam is a Hitbox": the
/// interesting part isn't damage, it's that the ghost BEHAVES differently in light. That's
/// what makes the flashlight feel like a tool rather than a gun.
/// </summary>
public class LightSensitiveEnemy : MonoBehaviour
{
public enum Reaction { Flee, Freeze, Weaken, Banish }
public Reaction reaction = Reaction.Flee;
public Flashlight2D flashlight;
[Tooltip("Beam cone half-angle and range used for the check. Match your Light 2D.")]
public float coneAngle = 35f;
public float range = 8f;
public bool requiresLineOfSight = true;
public LayerMask wallLayers;
[Header("Behaviour while lit")]
public float fleeSpeed = 4f;
public bool fadeWhileLit = true;
[Range(0f, 1f)] public float litAlpha = 0.35f;
[Tooltip("Banish mode: health lost per second in the beam.")]
public float damagePerSecond = 2f;
[Tooltip("Seconds still lit before the reaction starts (a moment of resistance).")]
public float resistTime = 0.2f;
[Header("Events")]
public UnityEvent OnEnteredLight;
public UnityEvent OnLeftLight;
public UnityEvent OnBanished;
public bool IsLit { get; private set; }
private EnemyChase chase;
private FloatingEnemy floater;
private Rigidbody2D rb;
private Health health;
private SpriteRenderer sr;
private Transform player;
private float litTimer;
private float damageAccumulator;
private Color baseColour = Color.white;
void Awake()
{
chase = GetComponent<EnemyChase>();
floater = GetComponent<FloatingEnemy>();
rb = GetComponent<Rigidbody2D>();
health = GetComponent<Health>();
sr = GetComponentInChildren<SpriteRenderer>();
if (sr != null) baseColour = sr.color;
}
void Start()
{
var p = GameObject.FindGameObjectWithTag("Player");
if (p != null)
{
player = p.transform;
if (flashlight == null) flashlight = p.GetComponent<Flashlight2D>();
}
}
void FixedUpdate()
{
bool lit = CheckLit();
if (lit != IsLit)
{
IsLit = lit;
litTimer = 0f;
if (lit) OnEnteredLight?.Invoke(); else OnLeftLight?.Invoke();
ApplyVisual();
if (!lit) RestoreBehaviour();
}
if (!IsLit) return;
litTimer += Time.fixedDeltaTime;
if (litTimer < resistTime) return;
switch (reaction)
{
case Reaction.Flee:
if (chase != null) chase.enabled = false;
if (floater != null) floater.enabled = false;
if (rb != null && player != null)
{
Vector2 away = ((Vector2)transform.position - (Vector2)player.position).normalized;
rb.linearVelocity = away * fleeSpeed;
}
break;
case Reaction.Freeze:
if (chase != null) chase.enabled = false;
if (floater != null) floater.enabled = false;
if (rb != null) rb.linearVelocity = Vector2.zero;
break;
case Reaction.Weaken:
// Keeps moving; the beam's Hitbox does the damage.
break;
case Reaction.Banish:
damageAccumulator += damagePerSecond * Time.fixedDeltaTime;
if (damageAccumulator >= 1f && health != null)
{
int whole = Mathf.FloorToInt(damageAccumulator);
damageAccumulator -= whole;
health.ClearInvulnerability();
health.TakeDamage(whole);
if (health.IsDead) OnBanished?.Invoke();
}
break;
}
}
bool CheckLit()
{
if (flashlight == null || !flashlight.IsOn) return false;
if (!flashlight.IsLit(transform.position, coneAngle, range)) return false;
if (requiresLineOfSight && player != null)
{
Vector2 dir = (Vector2)transform.position - (Vector2)player.position;
if (Physics2D.Raycast(player.position, dir.normalized, dir.magnitude, wallLayers)) return false;
}
return true;
}
void ApplyVisual()
{
if (sr == null || !fadeWhileLit) return;
Color c = baseColour;
c.a = IsLit ? litAlpha : baseColour.a;
sr.color = c;
}
void RestoreBehaviour()
{
if (chase != null) chase.enabled = true;
if (floater != null) floater.enabled = true;
damageAccumulator = 0f;
}
}