using Kryz.CharacterStats.Examples; using Photon.Pun; using System.Collections; using System.Collections.Generic; using UnityEngine; using UnityEngine.Events; public class Health : Resource { protected CharacterStats character; protected AbsorbEffectInstance absorbEffectInstance; protected DamageIncomeModifierEffectInstance damageIncomeModifierEffectInstance; public UnityEvent onMaxHealthChanged = new UnityEvent(); public UnityEvent onDeath = new UnityEvent(); [HideInInspector] public PhotonView photonView; protected bool invulnerable = false; public bool Invulnerable => invulnerable; float incomingValue; private bool isDead; public UnityEvent OnInvulnerabilityStateChanged = new UnityEvent(); public void SetIsDeadState(bool isDead) { this.isDead = isDead; canRegen = !isDead; } protected virtual void Awake() { character = GetComponent(); photonView = GetComponent(); absorbEffectInstance = GetComponent(); damageIncomeModifierEffectInstance = GetComponent(); baseMaxValue = maxValue; baseFlatRegen = flatRegen; character.onUpdateStatValues.AddListener(CalculateMaxValueBasedOnStat); } protected override void Start() { if (!photonView.IsMine) return; base.Start(); } public void SetInvulnerabilityState(bool isInvulnerable) { if (!photonView.IsMine) return; photonView.RPC(nameof(RPC_SetInvulnerabilityState), RpcTarget.All, isInvulnerable); } [PunRPC] public void RPC_SetInvulnerabilityState(bool isInvulnerable) { invulnerable = isInvulnerable; OnInvulnerabilityStateChanged.Invoke(invulnerable); } protected void HandleDamageIncomeModifierEffects() { if (incomingValue < 0) { if (damageIncomeModifierEffectInstance.IsActive) { //Debug.Log("Incoming damage b4 mitigation: " + incomingValue); incomingValue = damageIncomeModifierEffectInstance.ModifyDamageIncome(incomingValue); if (incomingValue > 0) //avoid damage ultra mitigated turning into healing incomingValue = 0; } //Debug.Log("Incoming damage after mitigation: " + incomingValue); } } protected void HandleAbsorbEffects() { if (incomingValue < 0) { if (absorbEffectInstance.IsActive) { //Debug.Log("Incoming damage b4 absorbs: " + incomingValue); incomingValue = absorbEffectInstance.AbsorbDamage(incomingValue); if (incomingValue > 0) //avoid complete absorbs turning into healing incomingValue = 0; } //Debug.Log("Incoming damage after absorbs: " + incomingValue); } } public override void ChangeValue(float value) { if (!photonView.IsMine) return; //Debug.Log("Value to change: " + value); if (isDead) return; incomingValue = value; if (invulnerable && incomingValue < 0) return; HandleDamageIncomeModifierEffects(); HandleAbsorbEffects(); currentValue += incomingValue; currentValue = Mathf.Clamp(currentValue, 0, maxValue); if (currentValue == 0) { //dead; onDeath.Invoke(); } //Debug.Log("CurrentHealth: " + currentValue); onResourceChanged.Invoke(currentValue); } public bool EnoughHealth(float cost) { if (invulnerable) return true; return cost <= currentValue; } [PunRPC] public void RPC_ChangeValueHealth(float value) { if (!photonView.IsMine) return; //Debug.Log("Received ChangeValue from RPC from someone"); ChangeValue(value); } public override float GetMaxValue() { return base.GetMaxValue(); } public virtual void CalculateMaxValueBasedOnStat() { maxValue = baseMaxValue + character.Vitality.Value * GameConstants.CharacterBalancing.VitalityToHealthRate; CalculateRegenValueBasedOnStat(); onMaxHealthChanged.Invoke(maxValue); } public void CalculateRegenValueBasedOnStat() { flatRegen = baseFlatRegen + (character.Strength.Value - character.Strength.BaseValue) * GameConstants.CharacterBalancing.BonusStrengthToFlatRegenRate; //percentRegen = (character.Vitality.Value - character.Vitality.BaseValue) * GameConstants.CharacterBalancing.BonusVitalityToPercentRegenRate; //Debug.Log(this.gameObject.name + " regens health " + flatRegen + " " + percentRegen + " = " + flatRegen + (maxValue * percentRegen / 100f)); } public override void SetMaxValue(float value) { base.SetMaxValue(value); onMaxHealthChanged.Invoke(maxValue); } }