RiftMayhem/Assets/Scripts/Player/PlayerDeathManager.cs

321 lines
9.3 KiB
C#

using Photon.Pun;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;
public class PlayerDeathManager : MonoBehaviour, IPunObservable
{
[SerializeField] private GameEvent onLocalPlayerCheatedDeath;
[SerializeField] private GameEvent onLocalPlayerFainted;
[SerializeField] private GameEvent onLocalPlayerPermaDeath;
[SerializeField] private GameEvent onLocalPlayerRevived;
[Space]
[SerializeField] private GameObject reviveProgressGO;
[SerializeField] private GameObject bleedOutProgressGO;
[SerializeField] private Image reviveProgressFill;
[SerializeField] private Image bleedOutProgressFill;
private bool hasUsedCheatDeath = false;
public bool HasUsedCheatDeath => hasUsedCheatDeath;
private bool isFainted = false;
public bool IsFainted => isFainted;
private float bleedOutTimer = 0f;
public float BleedOutTimer => bleedOutTimer;
private float reviveProgress = 0f;
public float ReviveProgress => reviveProgress;
PhotonView owner;
RiftPlayer ownerPlayer;
Health health;
SphereCollider reviveTrigger;
CharacterAnimatorController anim;
RiftPlayer possibleReviver;
public List<RiftPlayer> playersInsideReviveTrigger = new List<RiftPlayer>();
PlayerDeathManager potentialReferenceAddition;
NetworkManager networkManager;
private void Awake()
{
owner = GetComponentInParent<PhotonView>();
ownerPlayer = GetComponentInParent<RiftPlayer>();
health = GetComponentInParent<Health>();
anim = ownerPlayer.GetComponentInChildren<CharacterAnimatorController>();
reviveTrigger = GetComponentInChildren<SphereCollider>();
reviveTrigger.transform.localScale = Vector3.one * GameConstants.CharacterBalancing.ReviveTriggerRadius * 2;
reviveTrigger.isTrigger = true;
reviveTrigger.gameObject.SetActive(false);
reviveProgressGO.SetActive(false);
bleedOutProgressGO.SetActive(false);
networkManager = FindObjectOfType<NetworkManager>();
}
private void Start()
{
if (!owner.IsMine) return;
health.onDeath.AddListener(OnDeath);
}
private void OnDeath()
{
if (PhotonNetwork.CurrentRoom.PlayerCount <= 1)
{
HandleSoloDeath();
}
else
{
HandleGroupDeath();
}
}
private void HandleSoloDeath()
{
if (!hasUsedCheatDeath)
{
CheatDeath();
}
else
{
Die();
}
}
private void HandleGroupDeath()
{
EnterFaintedState();
}
private void CheatDeath()
{
hasUsedCheatDeath = true;
health.SetCurrentValue(health.GetMaxValue() * GameConstants.CharacterBalancing.SoloCheatDeathHealthPercent);
StartCoroutine(SoloInvulnerability());
if (!owner.IsMine) return;
onLocalPlayerCheatedDeath.Raise();
}
private IEnumerator SoloInvulnerability()
{
// Implement invulnerability logic
health.SetInvulnerabilityState(true);
yield return new WaitForSeconds(GameConstants.CharacterBalancing.SoloCheatDeathInvulnerabilityDuration);
// Remove invulnerability
health.SetInvulnerabilityState(false);
}
private void EnterFaintedState()
{
isFainted = true;
reviveTrigger.gameObject.SetActive(true);
// Disable player movement and abilities
// Change player visuals to "fainted" state
health.SetIsDeadState(true);
StartCoroutine(BleedOutTimerCoroutine());
if (!owner.IsMine) return;
if(AreAllPlayersFaintedOrDead())
{
if (PhotonNetwork.IsMasterClient)
{
StartCoroutine(Return());
}
}
reviveProgressGO.SetActive(true);
bleedOutProgressGO.SetActive(true);
anim.OnDeath();
onLocalPlayerFainted.Raise();
}
private IEnumerator BleedOutTimerCoroutine()
{
bleedOutTimer = GameConstants.CharacterBalancing.GroupBleedOutDuration;
bleedOutProgressFill.fillAmount = bleedOutTimer / GameConstants.CharacterBalancing.GroupBleedOutDuration;
while (bleedOutTimer > 0 && isFainted)
{
bleedOutTimer -= Time.deltaTime;
bleedOutProgressFill.fillAmount = bleedOutTimer / GameConstants.CharacterBalancing.GroupBleedOutDuration;
yield return null;
}
if (isFainted)
{
Die();
}
}
private void OnTriggerEnter(Collider other)
{
if (!isFainted) return;
possibleReviver = other.GetComponentInParent<RiftPlayer>();
if (possibleReviver == null) return;
if (possibleReviver == ownerPlayer) return;
if (playersInsideReviveTrigger.Contains(possibleReviver)) return;
Debug.Log($"R: added {possibleReviver.name} as a reviver");
playersInsideReviveTrigger.Add(possibleReviver);
}
private void Update()
{
if (!owner.IsMine)
{
reviveProgressFill.fillAmount = reviveProgress / GameConstants.CharacterBalancing.ReviveTime;
bleedOutProgressFill.fillAmount = bleedOutTimer / GameConstants.CharacterBalancing.GroupBleedOutDuration;
return;
}
if (!isFainted) return;
if (playersInsideReviveTrigger.Count > 0)
{
for (int i = playersInsideReviveTrigger.Count - 1; i >= 0; i--)
{
if (playersInsideReviveTrigger[i].health.GetCurrentValue() <= 0)
playersInsideReviveTrigger.RemoveAt(i);
}
reviveProgress += GameConstants.CharacterBalancing.ReviveSpeed * playersInsideReviveTrigger.Count * Time.deltaTime;
reviveProgressFill.fillAmount = reviveProgress / GameConstants.CharacterBalancing.ReviveTime;
if (reviveProgress >= GameConstants.CharacterBalancing.ReviveTime)
{
Revive();
}
}
}
private void OnTriggerExit(Collider other)
{
if (!isFainted) return;
possibleReviver = other.GetComponentInParent<RiftPlayer>();
if (possibleReviver == null) return;
if (possibleReviver == ownerPlayer) return;
if (!playersInsideReviveTrigger.Contains(possibleReviver)) return;
Debug.Log($"R: removed {possibleReviver.name} from revivers pool");
playersInsideReviveTrigger.Remove(possibleReviver);
}
private void Revive()
{
isFainted = false;
reviveTrigger.gameObject.SetActive(false);
reviveProgress = 0;
health.SetIsDeadState(false);
health.SetCurrentValue(health.GetMaxValue() * GameConstants.CharacterBalancing.ReviveHealthPercent);
// Re-enable player movement and abilities
// Restore normal player visuals
playersInsideReviveTrigger.Clear();
if (!owner.IsMine) return;
reviveProgressGO.SetActive(false);
bleedOutProgressGO.SetActive(false);
anim.OnRevived();
onLocalPlayerRevived.Raise();
}
private void Die()
{
health.SetIsDeadState(true);
// Implement full death logic (respawn, etc.)
if (PhotonNetwork.CurrentRoom.PlayerCount <= 1)
{
//Player perma death on the job, wait X to show info, then PhotonNetwork.LoadLevel(RiftHuntersInn)
StartCoroutine(Return());
}
else
{
//if players alive > 0
//wait motherfucker
//else
//all dead, host load level
if(AreAllPlayersFaintedOrDead())
{
if(PhotonNetwork.IsMasterClient)
{
StartCoroutine(Return());
}
}
}
if (!owner.IsMine) return;
if(!isFainted)
anim.OnDeath();
reviveProgressGO.SetActive(false);
bleedOutProgressGO.SetActive(false);
onLocalPlayerPermaDeath.Raise();
}
private bool AreAllPlayersFaintedOrDead()
{
for (int i = 0; i < networkManager.party.Count; i++)
{
potentialReferenceAddition = ((RiftPlayer)networkManager.party[i].TagObject).GetComponentInChildren<PlayerDeathManager>();
if (potentialReferenceAddition.IsFainted) continue;
else return false;
}
return true;
}
IEnumerator Return()
{
yield return new WaitForSeconds(GameConstants.GameBalancing.PermaDeathInfoTime);
if (PhotonNetwork.IsMasterClient) PhotonNetwork.LoadLevel("4-RiftHuntersInn");
}
public void OnPhotonSerializeView(PhotonStream stream, PhotonMessageInfo info)
{
if (stream.IsWriting)
{
stream.SendNext(isFainted);
stream.SendNext(reviveTrigger.gameObject.activeSelf);
stream.SendNext(reviveProgress);
stream.SendNext(bleedOutTimer);
}
else if (stream.IsReading)
{
isFainted = (bool)stream.ReceiveNext();
reviveTrigger.gameObject.SetActive((bool)stream.ReceiveNext());
reviveProgress = (float)stream.ReceiveNext();
bleedOutTimer = (float)stream.ReceiveNext();
reviveProgressGO.SetActive(reviveTrigger.gameObject.activeSelf);
bleedOutProgressGO.SetActive(reviveTrigger.gameObject.activeSelf);
}
}
}