using System.Collections.Generic; using Pathfinding; using Pathfinding.RVO; using UnityEngine; using UnityEngine.Events; [RequireComponent(typeof(TaggedObject))] public class Hp : MonoBehaviour { public float maxHp; public bool getsKnockedOutInsteadOfDying; private float hp; private TaggedObject taggedObject; [Tooltip("The hight where enemies aim at and where hit indicators are spawned")] public float hitFeedbackHeight; [Tooltip("This child object is enabled when this unit is alive.")] public GameObject aliveVisuals; [Tooltip("This child object is enabled when this unit is knocked out.")] public GameObject knockedOutVisuals; public GameObject fxToSpawnOnDeath; public Vector3 deathFxSpawnOffset; public Transform deathFxSpawnWithPosAndRotOf; [HideInInspector] public UnityEvent OnHpChange = new UnityEvent(); [HideInInspector] public UnityEvent OnRevive = new UnityEvent(); [HideInInspector] public UnityEvent OnHeal = new UnityEvent(); [HideInInspector] public UnityEvent OnReceiveDamage = new UnityEvent(); [HideInInspector] public UnityEvent OnKillOrKnockout = new UnityEvent(); private AutoAttack[] autoAttacks; private ManualAttack[] manualAttacks; private PathfindMovement pathfindMovement; private RVOController rvoController; private PlayerMovement playerMovement; private NavmeshCut[] navmeshCut; private PlayerInteraction playerInteraction; public GameObject coin; public float coinSpawnOffset; public int coinCount; [SerializeField] private Weapon spwanAttackOnDeath; private float damageMultiplyer = 1f; private float healingMultiplyer = 1f; public bool invulnerable; public float HpValue => hp; public float HpPercentage => hp / maxHp; public bool KnockedOut => hp <= 0f; public TaggedObject TaggedObj => taggedObject; public PathfindMovement PathfindMovement => pathfindMovement; public Weapon SpwanAttackOnDeath { get { return spwanAttackOnDeath; } set { spwanAttackOnDeath = value; } } public float DamageMultiplyer { get { return damageMultiplyer; } set { damageMultiplyer = value; } } public void ScaleHp(float _multiply) { hp *= _multiply; maxHp *= _multiply; } private void Start() { playerInteraction = GetComponent(); taggedObject = GetComponent(); autoAttacks = GetComponents(); manualAttacks = GetComponents(); pathfindMovement = GetComponent(); rvoController = GetComponent(); playerMovement = GetComponent(); navmeshCut = GetComponentsInChildren(); taggedObject.AddTag(TagManager.ETag.AUTO_Alive); Revive(callReviveEvent: false); ActivateAndDeactivateChildrenAndCompements(_alive: true); if (PerkManager.instance.HealingSpiritsActive && (bool)taggedObject && taggedObject.Tags.Contains(TagManager.ETag.PlayerOwned)) { healingMultiplyer *= PerkManager.instance.healingSpirits_healMulti; } } private void ActivateAndDeactivateChildrenAndCompements(bool _alive) { if ((bool)aliveVisuals) { aliveVisuals.SetActive(_alive); } if ((bool)knockedOutVisuals) { knockedOutVisuals.SetActive(!_alive); } if (autoAttacks.Length != 0) { AutoAttack[] array = autoAttacks; for (int i = 0; i < array.Length; i++) { array[i].enabled = _alive; } } if (manualAttacks.Length != 0) { ManualAttack[] array2 = manualAttacks; for (int i = 0; i < array2.Length; i++) { array2[i].enabled = _alive; } } if ((bool)pathfindMovement) { pathfindMovement.enabled = _alive; if (!_alive) { pathfindMovement.ClearCurrentPath(); } } if ((bool)rvoController) { rvoController.enabled = _alive; } if ((bool)playerMovement) { playerMovement.enabled = _alive; } NavmeshCut[] array3 = navmeshCut; for (int i = 0; i < array3.Length; i++) { array3[i].enabled = _alive; } if ((bool)playerInteraction) { playerInteraction.enabled = _alive; } } public void Revive(bool callReviveEvent = true, float healthPercentage = 1f) { if (hp <= 0f) { if (callReviveEvent) { OnRevive.Invoke(); } taggedObject.RemoveTag(TagManager.ETag.AUTO_KnockedOutAndHealOnDawn); taggedObject.AddTag(TagManager.ETag.AUTO_Alive); ActivateAndDeactivateChildrenAndCompements(_alive: true); hp = 0f; } else if (hp < maxHp) { OnHeal.Invoke(); } hp += maxHp * healthPercentage; if (hp > maxHp) { hp = maxHp; } OnHpChange.Invoke(); } public bool TakeDamage(float _amount, TaggedObject _damageComingFrom = null, bool causedByPlayer = false, bool invokeFeedbackEvents = true) { if (hp <= 0f) { return false; } if (invulnerable) { return false; } if (_amount <= 0f) { Heal(0f - _amount); return false; } if ((bool)pathfindMovement) { pathfindMovement.GetAgroFromObject(_damageComingFrom); } hp -= _amount; OnHpChange.Invoke(); if (invokeFeedbackEvents) { OnReceiveDamage.Invoke(causedByPlayer); } if (hp <= 0f) { OnKillOrKnockout.Invoke(); if ((bool)fxToSpawnOnDeath) { if ((bool)deathFxSpawnWithPosAndRotOf) { Object.Instantiate(fxToSpawnOnDeath, deathFxSpawnWithPosAndRotOf.position + deathFxSpawnOffset, deathFxSpawnWithPosAndRotOf.rotation, null); } else { Object.Instantiate(fxToSpawnOnDeath, base.transform.position + deathFxSpawnOffset, fxToSpawnOnDeath.transform.rotation, null); } } if (getsKnockedOutInsteadOfDying) { taggedObject.RemoveTag(TagManager.ETag.AUTO_Alive); taggedObject.AddTag(TagManager.ETag.AUTO_KnockedOutAndHealOnDawn); ActivateAndDeactivateChildrenAndCompements(_alive: false); } else { Object.Destroy(base.gameObject); if ((bool)coin) { for (int i = 0; i < coinCount; i++) { if (i > 1) { Object.Instantiate(coin, base.transform.position + Vector3.up * coinSpawnOffset + Quaternion.Euler(0f, 45f * (float)i, 0f) * Vector3.forward * 2f, Quaternion.identity); } else { Object.Instantiate(coin, base.transform.position + Vector3.up * coinSpawnOffset, Quaternion.identity); } } } } if ((bool)spwanAttackOnDeath) { spwanAttackOnDeath.Attack(base.transform.position, null, Vector3.zero, taggedObject, damageMultiplyer); } return true; } return false; } public void Heal(float _amount) { if (!(hp <= 0f) && !(_amount <= 0f)) { hp += _amount * healingMultiplyer; if (hp > maxHp) { hp = maxHp; } OnHpChange.Invoke(); } } public static void ReviveAllUnitsWithTag(List _mustHaveTags, List _mayNotHaveTags, float _healthPercentage = 1f) { List list = new List(); TagManager.instance.FindAllTaggedObjectsWithTags(list, _mustHaveTags, _mayNotHaveTags); for (int i = 0; i < list.Count; i++) { list[i].Hp.Revive(callReviveEvent: true, _healthPercentage); } } public static void MarkDestroyedBuildingsAsDontRevive(List _mustHaveTags, List _mayNotHaveTags, float _healthPercentage = 1f) { List list = new List(); TagManager.instance.FindAllTaggedObjectsWithTags(list, _mustHaveTags, _mayNotHaveTags); for (int i = 0; i < list.Count; i++) { if (list[i].Tags.Contains(TagManager.ETag.AUTO_KnockedOutAndHealOnDawn)) { list[i].GetComponentInParent().Interactor.OnKnockOut(); if (!list[i].Tags.Contains(TagManager.ETag.AUTO_NoReviveNextMorning)) { list[i].Tags.Add(TagManager.ETag.AUTO_NoReviveNextMorning); } else { list[i].Tags.Remove(TagManager.ETag.AUTO_NoReviveNextMorning); } } } } public static void KillAllUnitsWithTag(List _mustHaveTags, List _mayNotHaveTags) { List list = new List(); TagManager.instance.FindAllTaggedObjectsWithTags(list, _mustHaveTags, _mayNotHaveTags); for (int i = 0; i < list.Count; i++) { list[i].Hp.TakeDamage(float.MaxValue); } } public static void ReviveAllKnockedOutPlayerUnitsAndBuildings() { if (!PerkManager.instance.DestructionGodActive) { List list = new List(); List list2 = new List(); list.Add(TagManager.ETag.PlayerOwned); list2.Add(TagManager.ETag.AUTO_NoReviveNextMorning); ReviveAllUnitsWithTag(list, list2); return; } List list3 = new List(); List mayNotHaveTags = new List(); list3.Add(TagManager.ETag.PlayerOwned); list3.Add(TagManager.ETag.Building); MarkDestroyedBuildingsAsDontRevive(list3, mayNotHaveTags); List list4 = new List(); mayNotHaveTags = new List(); list4.Add(TagManager.ETag.PlayerOwned); mayNotHaveTags.Add(TagManager.ETag.Building); mayNotHaveTags.Add(TagManager.ETag.AUTO_NoReviveNextMorning); ReviveAllUnitsWithTag(list4, mayNotHaveTags); mayNotHaveTags.Clear(); mayNotHaveTags.Add(TagManager.ETag.AUTO_NoReviveNextMorning); list4.Add(TagManager.ETag.Building); ReviveAllUnitsWithTag(list4, mayNotHaveTags, 0.33f); } public static void KillAllEnemyUnits() { List list = new List(); List mayNotHaveTags = new List(); list.Add(TagManager.ETag.EnemyOwned); KillAllUnitsWithTag(list, mayNotHaveTags); } }