111 lines
3.2 KiB
C#
111 lines
3.2 KiB
C#
using System;
|
|
using UnityEngine;
|
|
using UnityEngine.Events;
|
|
|
|
namespace MegaKoop.Game.Combat
|
|
{
|
|
[DisallowMultipleComponent]
|
|
public class Health : MonoBehaviour, IDamageable
|
|
{
|
|
[SerializeField] private float maxHealth = 100f;
|
|
[SerializeField] private Team team = Team.Neutral;
|
|
[SerializeField] private bool ignoreFriendlyFire = true;
|
|
[SerializeField] private bool destroyOnDeath = false;
|
|
[SerializeField] private UnityEvent<float> onHealthChanged;
|
|
[SerializeField] private UnityEvent onDeath;
|
|
|
|
public float MaxHealth => maxHealth;
|
|
public float CurrentHealth { get; private set; }
|
|
public Team Team => team;
|
|
public bool IsAlive => CurrentHealth > 0f;
|
|
|
|
public event Action<float> NormalizedHealthChanged;
|
|
|
|
private void Awake()
|
|
{
|
|
maxHealth = Mathf.Max(1f, maxHealth);
|
|
CurrentHealth = maxHealth;
|
|
onHealthChanged?.Invoke(CurrentHealth / MaxHealth);
|
|
NormalizedHealthChanged?.Invoke(CurrentHealth / MaxHealth);
|
|
}
|
|
|
|
public void ApplyDamage(DamagePayload payload)
|
|
{
|
|
if (!IsAlive || payload.Amount <= 0f)
|
|
{
|
|
return;
|
|
}
|
|
|
|
if (ignoreFriendlyFire && team != Team.Neutral && payload.SourceTeam == team)
|
|
{
|
|
return;
|
|
}
|
|
|
|
CurrentHealth = Mathf.Max(0f, CurrentHealth - payload.Amount);
|
|
float normalized = CurrentHealth / MaxHealth;
|
|
onHealthChanged?.Invoke(normalized);
|
|
NormalizedHealthChanged?.Invoke(normalized);
|
|
|
|
if (CurrentHealth <= 0f)
|
|
{
|
|
HandleDeath();
|
|
}
|
|
}
|
|
|
|
public void Heal(float amount)
|
|
{
|
|
if (amount <= 0f || !IsAlive)
|
|
{
|
|
return;
|
|
}
|
|
|
|
CurrentHealth = Mathf.Min(MaxHealth, CurrentHealth + amount);
|
|
float normalized = CurrentHealth / MaxHealth;
|
|
onHealthChanged?.Invoke(normalized);
|
|
NormalizedHealthChanged?.Invoke(normalized);
|
|
}
|
|
|
|
public void Revive(float overrideMaxHealth = -1f)
|
|
{
|
|
if (overrideMaxHealth > 0f)
|
|
{
|
|
maxHealth = Mathf.Max(1f, overrideMaxHealth);
|
|
}
|
|
|
|
CurrentHealth = maxHealth;
|
|
float normalized = CurrentHealth / MaxHealth;
|
|
onHealthChanged?.Invoke(normalized);
|
|
NormalizedHealthChanged?.Invoke(normalized);
|
|
}
|
|
|
|
private void HandleDeath()
|
|
{
|
|
onDeath?.Invoke();
|
|
|
|
if (destroyOnDeath)
|
|
{
|
|
Destroy(gameObject);
|
|
}
|
|
}
|
|
|
|
private void OnValidate()
|
|
{
|
|
maxHealth = Mathf.Max(1f, maxHealth);
|
|
}
|
|
|
|
public void ForceSetNormalizedHealth(float normalized)
|
|
{
|
|
normalized = Mathf.Clamp01(normalized);
|
|
bool wasAlive = IsAlive;
|
|
CurrentHealth = normalized * MaxHealth;
|
|
onHealthChanged?.Invoke(normalized);
|
|
NormalizedHealthChanged?.Invoke(normalized);
|
|
|
|
if (CurrentHealth <= 0f && wasAlive)
|
|
{
|
|
HandleDeath();
|
|
}
|
|
}
|
|
}
|
|
}
|