// Assets/_Project/Scripts/Gameplay/EnemyHealth.cs
using Unity.Netcode;
using UnityEngine;
using TD.Core;
namespace TD.Gameplay
{
///
/// Per-enemy HP component. Holds replicated HP and is the single point
/// through which all damage flows, so resistance lookups (Phase 1.5+) can
/// be added in one place without touching every damage source.
///
///
/// Lives on the enemy prefab root alongside and the
/// future EnemyMovement component (Phase 1.5/1.6). HP is server-written
/// and replicated to all clients so health bars can render on any peer.
///
/// Death flow (server-only):
/// TakeDamage clamps HP to 0, fires , then calls
/// NetworkObject.Despawn. Subscribers must not touch the NetworkObject
/// after OnDied returns.
///
[RequireComponent(typeof(NetworkObject))]
public class EnemyHealth : NetworkBehaviour
{
[SerializeField] private float maxHp = 100f;
private readonly NetworkVariable hp = new NetworkVariable(
0f,
NetworkVariableReadPermission.Everyone,
NetworkVariableWritePermission.Server);
// ----- Public state -----------------------------------------------
public float CurrentHp => hp.Value;
public float MaxHp => maxHp;
public bool IsDead => hp.Value <= 0f;
// Stub: set by EnemyMovement or spawner in Phase 1.5/1.6.
// TowerCombat reads this to honour the GroundedOnly tower flag.
public bool IsFlying => false;
// ----- Events -----------------------------------------------------
///
/// Fired on the server immediately before the enemy NetworkObject is despawned.
/// subscribes to clear its target reference.
/// Do not access the NetworkObject after this event returns.
///
public event System.Action OnDied;
// ----- NGO lifecycle ----------------------------------------------
public override void OnNetworkSpawn()
{
if (IsServer)
hp.Value = maxHp;
}
// ----- Server API -------------------------------------------------
///
/// Applies to this enemy. Server-only; no-op on clients.
/// is recorded for future resistance/weakness lookups —
/// all damage is full-value until the resistance table is implemented (Phase 1.5+).
///
public void TakeDamage(float damage, DamageType type)
{
if (!IsServer) return;
if (IsDead) return;
// STUB — resistance table slot:
// float modified = ResistanceTable.Apply(damage, type, this);
float modified = damage;
hp.Value = Mathf.Max(0f, hp.Value - modified);
if (hp.Value <= 0f)
HandleDeath();
}
// ----- Private ----------------------------------------------------
private void HandleDeath()
{
OnDied?.Invoke(this);
NetworkObject.Despawn();
}
}
}