using UnityEngine;
using UnityEngine.Events;
/// <summary>
/// GAME 1303 Tier 5 — "Carry the food from A to B. Monsters try to steal it."
/// Last Delivery's core loop.
///
/// SETUP
/// 1. Player (the delivery robot): TopDownMover or GridMover + Health + this script.
/// 2. Carried Visual: a child sprite of the food/package. It's shown while carrying and
/// hidden when stolen.
/// 3. Starting Cargo: how many items you set off with (1 for a single package;
/// 3 for "deliver as many as you can").
/// 4. Losing cargo: wire the monster's damage to LoseCargo — either
/// Health.OnDamaged -> DeliveryObjective.LoseOne (a hit costs you food)
/// or from an enemy's DamageOnContact set to 0 damage plus a UnityEvent, if you want
/// the monsters to steal food WITHOUT hurting the robot (closer to Chris's pitch).
/// 5. Delivery point: a DeliveryPoint trigger at B (see the other script).
/// 6. OnAllCargoLost fires when you arrive empty-handed or run out — wire to
/// GameManager.GameOver or a "you failed the delivery" line.
///
/// Design note worth raising with Chris: losing the food (not health) as the fail state
/// makes the monsters scary without needing combat, which fits a delivery robot better
/// than a health bar does.
/// </summary>
public class DeliveryObjective : MonoBehaviour
{
[Header("Cargo")]
public int startingCargo = 1;
public GameObject carriedVisual;
[Tooltip("Prefab dropped in the world when cargo is stolen — the player can pick it back up.")]
public GameObject droppedCargoPrefab;
public float dropForce = 3f;
[Tooltip("Seconds of immunity after losing cargo so one monster can't take everything at once.")]
public float lossCooldown = 1f;
[Header("Feedback")]
public string loseSfx = "cargo_lost";
public string pickupSfx = "collect";
public string deliverSfx = "delivered";
[Header("Events")]
public UnityEvent<int> OnCargoChanged;
public UnityEvent OnCargoLost;
public UnityEvent OnCargoRecovered;
public UnityEvent OnAllCargoLost;
public UnityEvent<int> OnDelivered; // how many were delivered
public int Cargo { get; private set; }
public bool HasCargo => Cargo > 0;
private float cooldown;
void Start()
{
Cargo = startingCargo;
Refresh();
}
void Update() { cooldown -= Time.deltaTime; }
/// <summary>Wire an enemy hit here. Drops one item into the world.</summary>
public void LoseOne()
{
if (Cargo <= 0 || cooldown > 0f) return;
cooldown = lossCooldown;
Cargo--;
if (droppedCargoPrefab != null)
{
var drop = Instantiate(droppedCargoPrefab, transform.position, Quaternion.identity);
var rb = drop.GetComponent<Rigidbody2D>();
if (rb != null)
rb.AddForce(Random.insideUnitCircle.normalized * dropForce, ForceMode2D.Impulse);
}
if (!string.IsNullOrEmpty(loseSfx)) AudioManager.Instance?.PlaySFX(loseSfx);
Refresh();
OnCargoLost?.Invoke();
if (Cargo <= 0) OnAllCargoLost?.Invoke();
}
/// <summary>Wire a DroppedCargo pickup here (or call from Collectible.OnCollected).</summary>
public void PickUpOne()
{
Cargo++;
if (!string.IsNullOrEmpty(pickupSfx)) AudioManager.Instance?.PlaySFX(pickupSfx);
Refresh();
OnCargoRecovered?.Invoke();
}
/// <summary>Called by DeliveryPoint. Returns how many were handed over.</summary>
public int DeliverAll()
{
int delivered = Cargo;
Cargo = 0;
Refresh();
if (delivered > 0 && !string.IsNullOrEmpty(deliverSfx)) AudioManager.Instance?.PlaySFX(deliverSfx);
OnDelivered?.Invoke(delivered);
return delivered;
}
void Refresh()
{
if (carriedVisual != null) carriedVisual.SetActive(Cargo > 0);
OnCargoChanged?.Invoke(Cargo);
}
}