/// --------------------------------------------- /// Ultimate Character Controller /// Copyright (c) Opsive. All Rights Reserved. /// https://www.opsive.com /// --------------------------------------------- namespace Opsive.UltimateCharacterController.Character.Abilities { using Opsive.Shared.Events; using Opsive.Shared.Game; using Opsive.UltimateCharacterController.Traits; using UnityEngine; /// /// The Revive ability will play a standing animation from laying on the ground. The OnRespawn event will be executed when the animation is complete. /// [DefaultStartType(AbilityStartType.Manual)] [DefaultState("Death")] [DefaultAbilityIndex(5)] public class Revive : Ability { [Tooltip("Should the ability start when the character dies?")] [SerializeField] protected bool m_StartOnDeath; [Tooltip("Specifies the number of seconds after the character dies that the ability should start.")] [SerializeField] protected float m_DeathStartDelay = 3; public bool StartOnDeath { get { return m_StartOnDeath; } set { m_StartOnDeath = value; } } public float DeathStartDelay { get { return m_DeathStartDelay; } set { m_DeathStartDelay = value; } } private Respawner m_Respawner; public override bool CanStayActivatedOnDeath { get { return true; } } /// /// The type of animation that the ability should play. /// private enum ReviveType { Forward, // Play a forward revive animation. Backward // Play a backward revive animation. } private int m_ReviveTypeIndex; public override int AbilityIntData { get { return m_ReviveTypeIndex; } } /// /// Initialize the default values. /// public override void Awake() { base.Awake(); m_Respawner = m_GameObject.GetCachedComponent(); if (!m_Respawner) { Debug.LogError("Error: The Revive ability requires the Respawner component to be added to the character."); return; } // If the ragdoll is starting when the character dies then the respawner will be called manually and should not reposition the character. if (m_StartOnDeath && Enabled) { m_Respawner.PositioningMode = Respawner.SpawnPositioningMode.None; m_Respawner.ScheduleRespawnOnDeath = false; m_Respawner.ScheduleRespawnOnDisable = false; } EventHandler.RegisterEvent(m_GameObject, "OnDeath", OnDeath); EventHandler.RegisterEvent(m_GameObject, "OnAnimatorReviveComplete", OnReviveComplete); } /// /// The character has died. Start the ability if requested. /// /// The position of the force. /// The amount of force which killed the character. /// The GameObject that killed the character. private void OnDeath(Vector3 position, Vector3 force, GameObject attacker) { // The ability may not need to start from the death event. if (!m_StartOnDeath) { return; } m_ReviveTypeIndex = GetReviveTypeIndex(position, force, attacker); Scheduler.ScheduleFixed(m_DeathStartDelay, StartRevive); } /// /// Returns the value that the AbilityIntData parameter should be set to. /// /// The position of the force. /// The amount of force which killed the character. /// The GameObject that killed the character. /// The value that the AbilityIntData parameter should be set to. protected virtual int GetReviveTypeIndex(Vector3 position, Vector3 force, GameObject attacker) { return (int)(m_Transform.InverseTransformPoint(position).z > 0 ? ReviveType.Forward : ReviveType.Backward); } /// /// Starts the ability. /// private void StartRevive() { StartAbility(); } /// /// The revive animation has completed. /// private void OnReviveComplete() { StopAbility(); // The respawn component will perform the necessary cleanup after the character has died. if (m_StartOnDeath) { m_Respawner.Respawn(); } } /// /// Called when the character is destroyed. /// public override void OnDestroy() { base.OnDestroy(); EventHandler.UnregisterEvent(m_GameObject, "OnDeath", OnDeath); EventHandler.UnregisterEvent(m_GameObject, "OnAnimatorReviveComplete", OnReviveComplete); } } }