using Photon.Pun; using System.Collections; using System.Collections.Generic; using UnityEngine; public class BossController : NPCController { [Header("Boss Related:")] [SerializeField] protected GameEvent onBossDead; [SerializeField] protected float bossRangedAttacksRange; [SerializeField] protected float bossMeleeAttacksRange; protected BossAbilityBinder bossAbilityBinder; protected bool lockedInPhase = false; protected float targetDistance = float.MaxValue; protected float distance; protected Taggable resultTarget; protected float endSearchTime; protected Collider[] hits; protected override void Awake() { base.Awake(); bossAbilityBinder = GetComponent(); } [PunRPC] protected override void RPC_OnDeath(bool lootDropped) { if (isDead) return; onBossDead.Raise(); base.RPC_OnDeath(lootDropped); } protected override void Start() { base.Start(); if (!photonView.IsMine) return; CheckSurroundings(); LockInTarget(CheckClosestTarget()); } protected override void Update() { if (!photonView.IsMine) return; if (isDead) return; if (PrimaryMovementBehaviourCheck()) { PerformPrimaryMovementBehaviour(); } else if (agent.remainingDistance <= agent.stoppingDistance) agent.isStopped = true; counter += Time.deltaTime; if (counter >= timeBetweenAttacks) { if (HighestPriorityCheck()) { PerformHighestPriorityAction(); } else if (SecondHighestPriorityCheck()) { PerformSecondHighestPriorityAction(); } else if (ThirdHighestPriorityCheck()) { PerformThirdHighestPriorityAction(); } else { agent.isStopped = false; } } else { agent.isStopped = false; } } protected virtual bool PrimaryMovementBehaviourCheck() { return Vector3.Distance(agent.transform.position, currentTarget.transform.position) > (bossRangedAttacksRange * 0.8f); } protected virtual bool HighestPriorityCheck() { return bossAbilityBinder.CanCastUltimate(); } protected virtual bool SecondHighestPriorityCheck() { return (bossAbilityBinder.CanCastCoreAbility() && agent.remainingDistance <= bossRangedAttacksRange); } protected virtual bool ThirdHighestPriorityCheck() { return agent.remainingDistance <= bossMeleeAttacksRange; } protected virtual void PerformPrimaryMovementBehaviour() { patrolDestination = currentTarget.transform.position; patrolDestination.y = 0f; agent.SetDestination(patrolDestination); agent.isStopped = false; } protected virtual void PerformHighestPriorityAction() { PerformUltimate(); } protected virtual void PerformSecondHighestPriorityAction() { PerformCoreAbility(); } protected virtual void PerformThirdHighestPriorityAction() { PerformMeleeAbility(); } protected virtual void PerformUltimate() { Debug.Log("INSIDE CAN CAST ULTIMATE: " + bossAbilityBinder.CanCastUltimate()); ResetValuesOnAbilityPerformed(); bossAbilityBinder.UseUltimateAbility(currentTarget.transform); } protected virtual void PerformCoreAbility() { ResetValuesOnAbilityPerformed(); bossAbilityBinder.UseCoreAbility(currentTarget.transform.position); } protected virtual void PerformMeleeAbility() { ResetValuesOnAbilityPerformed(); bossAbilityBinder.UseMeleeAbility(); } protected virtual void ResetValuesOnAbilityPerformed() { agent.isStopped = true; counter = 0f; } protected virtual Taggable CheckClosestTarget() { targetDistance = float.MaxValue; Debug.Log("CLOSEST COUNT: " + possibleTargets.Count); for (int i = 0; i < possibleTargets.Count; i++) { distance = Vector3.Distance(possibleTargets[i].transform.position, agent.transform.position); if (distance < targetDistance) { targetDistance = distance; resultTarget = possibleTargets[i]; } } return resultTarget; } protected virtual Taggable CheckFurthestAwayTarget() { targetDistance = 0f; for (int i = 0; i < possibleTargets.Count; i++) { distance = Vector3.Distance(possibleTargets[i].transform.position, agent.transform.position); if (distance > targetDistance) { targetDistance = distance; resultTarget = possibleTargets[i]; } } return resultTarget; } protected virtual IEnumerator TargetLockedInPhaseDurationCoroutine() { yield return new WaitForSeconds(GameConstants.GameBalancing.BossTargetLockInPhaseDuration); SearchForNewTargetToLockIn(); } protected virtual IEnumerator SearchForNewTargetToLockInCoroutine() { endSearchTime = Time.time + GameConstants.GameBalancing.BossSearchForNewTargetLockInDuration; while (Time.time < endSearchTime) { UpdateCurrentTarget(possibleTargets[Random.Range(0, possibleTargets.Count)]); yield return new WaitForSeconds(GameConstants.GameBalancing.BossSearchForNewTargetLockInDuration / 3); } LockInTarget(CheckClosestTarget()); } protected virtual void LockInTarget(Taggable target) { lockedInPhase = true; UpdateCurrentTarget(target); Debug.Log("Target Locked In: " + target.name); StartCoroutine(TargetLockedInPhaseDurationCoroutine()); } protected virtual void SearchForNewTargetToLockIn() { lockedInPhase = false; Debug.Log("Searching for new lockin: "); StartCoroutine(SearchForNewTargetToLockInCoroutine()); } protected virtual void UpdateCurrentTarget(Taggable target) { currentTarget = target; SetupAgentStats(); } protected virtual void SetupAgentStats() { agent.speed = chasingAgentSpeed; patrolDestination = currentTarget.transform.position; patrolDestination.y = 0f; agent.SetDestination(patrolDestination); } protected virtual void CheckSurroundings() { if (!photonView.IsMine) return; hits = Physics.OverlapSphere(this.transform.position, sightRange); Debug.Log("CHECK SURROUNDINGS COUNT: " + hits.Length); foreach (Collider collider in hits) { Debug.Log("CHECKING COLLIDER: " + collider.name); otherView = collider.GetComponentInParent(); if (otherView != null) { if (otherView == photonView) continue; } possibleTarget = collider.GetComponentInParent(); if (possibleTarget == null) continue; //if (possibleTarget.targetTag == myTag.targetTag || myTag.targetTag.AlliedTags.Contains(possibleTarget.targetTag)) continue; if (possibleTarget.HasSameTag(myTag.targetTag) || myTag.AlliedTagsContains(possibleTarget.targetTag)) continue; if (possibleTargets.Contains(possibleTarget)) continue; Debug.Log("ADDING TARGET " + possibleTarget.name); possibleTargets.Add(possibleTarget); } } }