RiftMayhem/Assets/Scripts/NPC/NPCController.cs

252 lines
7.3 KiB
C#

using Photon.Pun;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.AI;
public class NPCController : MonoBehaviour
{
[Header("Events:")]
[SerializeField] protected GameEvent_Float experienceOnDeath;
[Header("Settings:")]
[SerializeField] protected float sightRange;
[SerializeField] protected float sightRangeMultiplierForProjectiles;
[SerializeField] protected float distanceToChangePatrolDestination;
[SerializeField] protected float patrolAgentSpeed;
[SerializeField] protected float chasingAgentSpeed;
[SerializeField] protected float timeBetweenAttacks = 1f;
[HideInInspector]
public PhotonView photonView;
[HideInInspector]
public Taggable myTag;
protected NavMeshAgent agent;
public List<Taggable> possibleTargets = new List<Taggable>();
public Taggable currentTarget;
protected SphereCollider sight;
protected PhotonView otherView;
protected Taggable possibleTarget;
protected NPCAbilityBinder abilityBinder;
protected DropTable dropTable;
protected Vector3 patrolDestination = new Vector3();
protected float counter = 0f;
protected Health health;
protected bool isDead = false;
#region Death Animation
protected float moveSpeed = 0.5f; // Speed of the downwards movement
protected float moveDistance = 3.0f; // Distance to move downwards
protected float moveDelay = 0.25f; // Delay before starting the movement
protected Vector3 startPosition;
protected Vector3 endPosition;
#endregion
protected virtual void Awake()
{
myTag = GetComponentInParent<Taggable>();
agent = GetComponentInParent<NavMeshAgent>();
photonView = GetComponentInParent<PhotonView>();
abilityBinder = GetComponent<NPCAbilityBinder>();
health = GetComponent<Health>();
dropTable = GetComponentInChildren<DropTable>();
if (!photonView.IsMine) return;
}
// Start is called before the first frame update
protected virtual void Start()
{
if (!photonView.IsMine) return;
sight = this.gameObject.AddComponent<SphereCollider>();
sight.radius = sightRange;
sight.isTrigger = true;
isDead = false;
counter = timeBetweenAttacks / 2f;
health.onDeath.AddListener(OnDeath);
}
protected virtual void OnDeath()
{
photonView.RPC(nameof(RPC_OnDeath), RpcTarget.All, dropTable.CalculateLootDrop());
}
[PunRPC]
protected virtual void RPC_OnDeath(bool lootDropped)
{
if (isDead) return;
//Debug.Log($"{this.gameObject.name} died!");
isDead = true;
agent.enabled = false;
experienceOnDeath.Raise(health.GetMaxValue() * GameConstants.GameBalancing.HealthIntoExperienceMultiplier);
dropTable.DropLoot(lootDropped);
if (!photonView.IsMine) return;
StartCoroutine(AnimateOnDeath());
}
protected virtual IEnumerator AnimateOnDeath()
{
startPosition = transform.position;
endPosition = transform.position - Vector3.up * moveDistance;
yield return new WaitForSeconds(moveDelay);
float elapsedTime = 0.0f;
while (elapsedTime < 1.0f)
{
// Increment elapsed time based on Time.deltaTime
elapsedTime += Time.deltaTime * moveSpeed;
// Move the transform towards the end position
transform.position = Vector3.Lerp(transform.position, endPosition, elapsedTime);
yield return null; // Yielding null will make the coroutine wait until the next frame
}
DestroyAfterEffect();
}
protected virtual void DestroyAfterEffect()
{
if (!photonView.IsMine) return;
PhotonNetwork.Destroy(this.gameObject);
}
protected virtual void Update()
{
if (!photonView.IsMine) return;
if (isDead) return;
if (possibleTargets.Count <= 0)
{
if (currentTarget != null)
{
currentTarget = null;
PatrolNewPosition();
}
if (agent.destination == null)
{
PatrolNewPosition();
}
else if (agent.remainingDistance < distanceToChangePatrolDestination)
{
PatrolNewPosition();
}
}
else
{
if (possibleTargets[0] == null)
{
possibleTargets.RemoveAt(0);
return;
}
currentTarget = possibleTargets[0];
agent.speed = chasingAgentSpeed;
patrolDestination = currentTarget.transform.position;
patrolDestination.y = 0f;
agent.SetDestination(patrolDestination);
counter += Time.deltaTime;
if (agent.remainingDistance <= sightRange * sightRangeMultiplierForProjectiles)
{
agent.isStopped = true;
if (counter >= timeBetweenAttacks)
{
counter = 0f;
if (!abilityBinder.ValidCoreAbility())
abilityBinder.UsePrimaryAbility();
else
{
if (Random.Range(0, 10) > 3)
abilityBinder.UsePrimaryAbility();
else
abilityBinder.UseCoreAbility(currentTarget.transform.position);
}
}
}
else
{
agent.isStopped = false;
}
}
}
protected virtual void PatrolNewPosition()
{
agent.speed = patrolAgentSpeed;
patrolDestination.x = Random.Range(-5, 5);
patrolDestination.y = 0f;
patrolDestination.z = Random.Range(-5, 5);
agent.SetDestination(this.transform.position + patrolDestination);
agent.isStopped = false;
}
protected virtual void OnTriggerEnter(Collider other)
{
if (!photonView.IsMine) return;
otherView = other.GetComponentInParent<PhotonView>();
if (otherView != null)
{
if (otherView == photonView) return;
}
possibleTarget = other.GetComponentInParent<Taggable>();
if (possibleTarget == null) return;
//if (possibleTarget.targetTag == myTag.targetTag || myTag.targetTag.AlliedTags.Contains(possibleTarget.targetTag)) return;
if (possibleTarget.HasSameTag(myTag.targetTag) || myTag.AlliedTagsContains(possibleTarget.targetTag)) return;
if (possibleTargets.Contains(possibleTarget)) return;
possibleTargets.Add(possibleTarget);
}
protected virtual void OnTriggerExit(Collider other)
{
if (!photonView.IsMine) return;
otherView = other.GetComponentInParent<PhotonView>();
if (otherView != null)
{
if (otherView == photonView) return;
}
possibleTarget = other.GetComponentInParent<Taggable>();
if (possibleTarget == null) return;
if (possibleTarget.targetTag == myTag.targetTag) return;
if (!possibleTargets.Contains(possibleTarget)) return;
possibleTargets.Remove(possibleTarget);
}
protected virtual void OnDrawGizmosSelected()
{
Gizmos.DrawWireSphere(this.transform.position, sightRange);
}
}