156 lines
4.9 KiB
C#
156 lines
4.9 KiB
C#
using System;
|
|
using SepCore.Event;
|
|
using SepCore.Definition;
|
|
using UnityEngine;
|
|
|
|
namespace SepCore.Components
|
|
{
|
|
public class HealthComponent : MonoBehaviour
|
|
{
|
|
private int _maxHealthBase;
|
|
private int _currentHealth;
|
|
private bool _isDead => _currentHealth <= 0;
|
|
|
|
private StatComponent _statComponent;
|
|
|
|
private Action<StatType, float> _onStatChangedAction;
|
|
private float _lastLifeStealTime = -1f;
|
|
public const float LifeStealIcd = 0.1f;
|
|
|
|
private bool _isPlayer => _statComponent != null;
|
|
|
|
public float HealthRatio => MaxHealth > 0 ? (float)CurrentHealth / MaxHealth : 0f;
|
|
|
|
public int MaxHealth => _statComponent != null
|
|
? Mathf.CeilToInt(_statComponent.GetStatValue(StatType.MaxHp))
|
|
: _maxHealthBase;
|
|
|
|
public int CurrentHealth
|
|
{
|
|
get => _currentHealth;
|
|
set => _currentHealth = value;
|
|
}
|
|
|
|
#region FSM
|
|
|
|
public void OnInit(int maxHealth, StatComponent statComponent = null)
|
|
{
|
|
_maxHealthBase = maxHealth;
|
|
_currentHealth = maxHealth;
|
|
_statComponent = statComponent;
|
|
if (_statComponent != null)
|
|
{
|
|
_statComponent.Pipeline.SetBaseValue(StatType.MaxHp, maxHealth);
|
|
_onStatChangedAction = OnStatChanged;
|
|
_statComponent.Pipeline.OnStatChanged += _onStatChangedAction;
|
|
}
|
|
}
|
|
|
|
public void OnReset()
|
|
{
|
|
if (_statComponent != null && _onStatChangedAction != null)
|
|
{
|
|
_statComponent.Pipeline.OnStatChanged -= _onStatChangedAction;
|
|
_onStatChangedAction = null;
|
|
}
|
|
|
|
_statComponent = null;
|
|
_lastLifeStealTime = -1f;
|
|
}
|
|
|
|
private void OnStatChanged(StatType statType, float newValue)
|
|
{
|
|
if (statType == StatType.MaxHp)
|
|
{
|
|
if (_currentHealth > MaxHealth)
|
|
{
|
|
_currentHealth = MaxHealth;
|
|
}
|
|
|
|
if (GameEntry.Event != null)
|
|
{
|
|
GameEntry.Event.Fire(this, PlayerHealthChangeEventArgs.Create(0, CurrentHealth, MaxHealth));
|
|
}
|
|
}
|
|
}
|
|
|
|
#endregion
|
|
|
|
|
|
public void TakeDamage(int damage, bool isCrit = false, bool isDodge = false, Vector3? hitPosition = null)
|
|
{
|
|
if (_isDead) return;
|
|
|
|
if (isDodge)
|
|
{
|
|
float yOffset = GameEntry.Luban != null && GameEntry.Luban.IsReady
|
|
? GameEntry.Luban.Global.DamageTextYOffset / 1000f
|
|
: 1f;
|
|
Vector3 pos = hitPosition ?? (transform.position + Vector3.up * yOffset);
|
|
if (GameEntry.DamageText != null)
|
|
{
|
|
GameEntry.DamageText.ShowDamage(pos, 0, false, true);
|
|
}
|
|
return;
|
|
}
|
|
|
|
if (damage <= 0) return;
|
|
|
|
_currentHealth = Mathf.Max(0, _currentHealth - damage);
|
|
CauseDamage(damage, isCrit, hitPosition);
|
|
|
|
if (_isPlayer && GameEntry.Event != null)
|
|
{
|
|
GameEntry.Event.Fire(this, PlayerHealthChangeEventArgs.Create(damage, CurrentHealth, MaxHealth));
|
|
}
|
|
}
|
|
|
|
public void TakeDamage(int damage)
|
|
{
|
|
TakeDamage(damage, false, false, null);
|
|
}
|
|
|
|
public void Heal(int healAmount)
|
|
{
|
|
if (_isDead || healAmount <= 0) return;
|
|
|
|
int oldHealth = _currentHealth;
|
|
_currentHealth = Mathf.Min(_currentHealth + healAmount, MaxHealth);
|
|
int healed = _currentHealth - oldHealth;
|
|
|
|
if (healed > 0 && _isPlayer && GameEntry.Event != null)
|
|
{
|
|
GameEntry.Event.Fire(this, PlayerHealthChangeEventArgs.Create(-healed, CurrentHealth, MaxHealth));
|
|
}
|
|
}
|
|
|
|
public bool TryTriggerLifeSteal(int healAmount, float? customTime = null)
|
|
{
|
|
if (_isDead || healAmount <= 0) return false;
|
|
float currentTime = customTime ?? Time.time;
|
|
if (_lastLifeStealTime >= 0f && currentTime - _lastLifeStealTime < LifeStealIcd)
|
|
{
|
|
return false;
|
|
}
|
|
|
|
_lastLifeStealTime = currentTime;
|
|
Heal(healAmount);
|
|
return true;
|
|
}
|
|
|
|
private void CauseDamage(int damage, bool isCrit = false, Vector3? hitPosition = null)
|
|
{
|
|
if (damage <= 0) return;
|
|
float yOffset = GameEntry.Luban != null && GameEntry.Luban.IsReady
|
|
? GameEntry.Luban.Global.DamageTextYOffset / 1000f
|
|
: 1f;
|
|
Vector3 pos = hitPosition ?? (transform.position + Vector3.up * yOffset);
|
|
if (GameEntry.DamageText != null)
|
|
{
|
|
GameEntry.DamageText.ShowDamage(pos, damage, isCrit, false);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|