using Photon.Pun; using System.Collections; using System.Collections.Generic; using UnityEngine; using UnityEngine.Events; public class NetworkedAreaOfEffect : MonoBehaviour, IPunObservable { [Header("Visuals:")] [SerializeField] protected GameObject telegraph; [SerializeField] protected GameObject effectVisual; [Header("Physics:")] [SerializeField] protected LayerMask abilityHitLayer; [Header("Hit VFX:")] [SerializeField] protected GameObject impactHitVFX; [Header("Optional:")] [SerializeField] protected bool shouldDisableVisualsOnDelayedDestroyEntered = true; [Header("Set by Code")] public PhotonView photonView; public PhotonView owner; public Taggable ownerTag; public AreaOfEffectAbility ability; public float radius; public bool shouldResizeVisuals; public float telegraphDelay; public float lifeSpan; public bool canHitSelf; protected PhotonView possibleTarget; protected Taggable target; protected List targets = new List(); protected Vector3 resizedByAbility = new Vector3(); protected Collider[] hits; protected bool waitingForDestroy = false; protected List hitSpawnedVFXs = new List(); protected GameObject hitSpawnedVFX; protected Vector3 hitPositionCorrected; public UnityEvent onTargetHit = new UnityEvent(); protected virtual void Awake() { photonView = GetComponent(); onTargetHit.AddListener(SpawnHitParticleVFX); } public virtual void Init() { waitingForDestroy = false; if (photonView.IsMine) { if (shouldResizeVisuals) { resizedByAbility.x = radius * 2; resizedByAbility.z = radius * 2; telegraph.transform.localScale = resizedByAbility; effectVisual.transform.localScale = resizedByAbility; } photonView.RPC(nameof(RPC_RemoteInit), RpcTarget.Others, AbilityIndexer.Instance.Abilities.IndexOf(ability)); StartCoroutine(ApplyTelegraphDelay(telegraphDelay)); } } [PunRPC] protected virtual void RPC_RemoteInit(int abilityIndex) { ability = (AreaOfEffectAbility)AbilityIndexer.Instance.Abilities[abilityIndex]; } protected virtual IEnumerator ApplyTelegraphDelay(float delay) { ShowTelegraph(); yield return new WaitForSeconds(delay); ApplyArea(); } protected virtual void ApplyArea() { ShowEffectVisual(); CheckSurroundings(); //StartCoroutine(SelfDestruct()); } [PunRPC] protected virtual void RPC_CheckSurroundings() { hits = Physics.OverlapSphere(this.transform.position, radius, abilityHitLayer); targets.Clear(); foreach (Collider collider in hits) { possibleTarget = collider.GetComponentInParent(); if (possibleTarget != null) if (possibleTarget == owner && !canHitSelf) continue; target = collider.GetComponentInParent(); if (target == null) continue; if (!target.IsValidTarget(ability.targettingTags)) continue; //Debug.Log("hit collider, added target: " + target.name); targets.Add(target); } for (int i = 0; i < targets.Count; i++) { hitPositionCorrected = targets[i].transform.position; hitPositionCorrected.y = 0.5f; onTargetHit.Invoke(hitPositionCorrected); } } protected void SpawnHitParticleVFX(Vector3 position) { if (impactHitVFX == null) return; hitSpawnedVFX = Instantiate(impactHitVFX, position, this.transform.rotation); hitSpawnedVFXs.Add(hitSpawnedVFX); } protected virtual void CheckSurroundings() { if (waitingForDestroy) return; hits = Physics.OverlapSphere(this.transform.position, radius, abilityHitLayer); targets.Clear(); foreach (Collider collider in hits) { possibleTarget = collider.GetComponentInParent(); if (possibleTarget != null) if (possibleTarget == owner && !canHitSelf) continue; target = collider.GetComponentInParent(); if (target == null) continue; if (!target.IsValidTarget(ability.targettingTags)) continue; //Debug.Log("hit collider, added target: " + target.name); targets.Add(target); } photonView.RPC(nameof(RPC_CheckSurroundings), RpcTarget.Others); if (!photonView.IsMine) return; for (int i = 0; i < targets.Count; i++) { hitPositionCorrected = targets[i].transform.position; hitPositionCorrected.y = 0.5f; onTargetHit.Invoke(hitPositionCorrected); } foreach (BaseEffect effect in ability.abilityEffects) { effect.ApplyEffect(ownerTag, targets); } waitingForDestroy = true; StartCoroutine(DelayedDestroy()); } protected virtual void OnDrawGizmos() { Gizmos.color = Color.red; Gizmos.DrawWireSphere(this.transform.position, radius); } protected virtual IEnumerator SelfDestruct() { yield return new WaitForSeconds(lifeSpan); waitingForDestroy = true; StartCoroutine(DelayedDestroy()); } protected virtual IEnumerator DelayedDestroy() { if (shouldDisableVisualsOnDelayedDestroyEntered) effectVisual.SetActive(false); yield return new WaitForSeconds(1.5f); for (int i = hitSpawnedVFXs.Count - 1; i >= 0; i--) { if (hitSpawnedVFXs[i] != null) { Destroy(hitSpawnedVFXs[i]); } } yield return new WaitForSeconds(1f); PhotonNetwork.Destroy(photonView); } protected void ShowTelegraph() { telegraph.SetActive(true); effectVisual.SetActive(false); } protected void ShowEffectVisual() { telegraph.SetActive(false); effectVisual.SetActive(true); } public void OnPhotonSerializeView(PhotonStream stream, PhotonMessageInfo info) { if (stream.IsWriting) { //stream.SendNext(telegraph.activeSelf); stream.SendNext(effectVisual.activeSelf); } if (stream.IsReading) { //telegraph.SetActive((bool)stream.ReceiveNext()); effectVisual.SetActive((bool)stream.ReceiveNext()); } } }