using System; using System.Collections; using System.Collections.Generic; using System.Linq; using UnityEngine; using UnityEngine.AI; public class Virus : MonoBehaviour { private Item item; private NavMeshAgent nav; void Awake() { item = GetComponentInChildren<Item>(); nav = GetComponentInChildren<NavMeshAgent>(); nav.isStopped = true; repathTimer = new SimpleTimer(); attackTween = new SimpleTween(); attackTimer = new SimpleTimer(); } public GameObject MeshRoot; // Start is called before the first frame update void Start() { } void StartLocal() { PathToPlayer(); } private float pathTime; private Player targetPlayer; private SimpleTimer repathTimer; private SimpleTween attackTween; private SimpleTimer attackTimer; private void PathToPlayer() { List<Player> players = new List<Player>(); List<float> weights = new List<float>(); foreach (Player p in FindObjectsOfType<Player>()) { players.Add(p); float dist = (p.transform.position - transform.position).magnitude; weights.Add(30 - dist); } if (players.Count == 0) { repathTimer.Start(3, PathToPlayer); } float total = weights.Sum(); targetPlayer = null; float rand = UnityEngine.Random.Range(0, total); float sum = 0; for (int i = 0; i < players.Count; i++) { sum += weights[i]; if (rand < sum || i == players.Count - 1) { targetPlayer = players[i]; break; } } if (targetPlayer != null) { nav.stoppingDistance = AttackMaxDist * 0.8f; pathTime = Time.realtimeSinceStartup; nav.isStopped = false; nav.destination = TargetBasePos; } } public void StopPathing() { nav.isStopped = true; } public bool IsPathFinished() { if (!nav.pathPending) { if (nav.remainingDistance <= nav.stoppingDistance) { if (!nav.hasPath || nav.velocity.sqrMagnitude == 0f) { return true; } } } return false; } public Vector3 TargetBasePos { get { if (targetPlayer == null) return new Vector3(); return targetPlayer.transform.position + Vector3.down * targetPlayer.BottomOffset; } } public float DistToTarget { get { if (targetPlayer == null) return 99999; return (TargetBasePos - transform.position).magnitude; } } public float AttackMaxDist = 1.3f; public float RepathTime = 1.3f; // Update is called once per frame void Update() { if (item != null && item.IsLocal && !nav.isStopped) { if (IsPathFinished()) { if (DistToTarget > AttackMaxDist) { nav.destination = TargetBasePos; } else { StopPathing(); AttackTarget(); } } else if (targetPlayer == null) { StopPathing(); targetPlayer = null; PathToPlayer(); } else if (Time.realtimeSinceStartup > pathTime + RepathTime && DistToTarget > 2) { nav.destination = TargetBasePos; } } } void TakeDamage(object detailsObj) { Dictionary<string, object> details = detailsObj as Dictionary<string, object>; if (details != null && details.ContainsKey("damage")) { item.DestroyItem(); } } void OnDestroy() { attacking = false; damaged.Clear(); attackTween.Stop(); repathTimer.Stop(); attackTimer.Stop(); } public float AttackTime = 0.2f; public float AttackDistMult = 1.3f; public float Damage = 0.4f; private void AttackTarget() { Vector3 startPos = transform.position; Vector3 delta = TargetBasePos - startPos; delta *= AttackDistMult; if (delta.magnitude < AttackMaxDist * 0.4f) { delta = delta.normalized * AttackMaxDist * 0.4f; } attacking = true; damaged.Clear(); attackTween.Init( v => { transform.position = startPos + delta * v; MeshRoot.transform.localScale = new Vector3(1, 1, 1) * (v * 0.3f + 1.0f); }, SimpleTween.QuadEaseOut, 0, 1, AttackTime); attackTween.OnFinish = FinishedAttack; //attackTimer.Start(AttackTime / AttackDistMult, DamageTarget); } public float AttackWait = 0.8f; private bool attacking = false; private List<Player> damaged = new List<Player>(); private void FinishedAttack() { attacking = false; MeshRoot.transform.localScale = new Vector3(1, 1, 1); if (damagedAny) { item.DestroyItem(); } if (UnityEngine.Random.Range(0, 1) < 0.4f) { attackTimer.Start(0.3f, PathToPlayer); targetPlayer = null; return; } if (targetPlayer != null && DistToTarget <= AttackMaxDist) { attackTimer.Start(AttackWait, CheckAttackTarget); } else { targetPlayer = null; PathToPlayer(); } } private void CheckAttackTarget() { if (targetPlayer != null && DistToTarget <= AttackMaxDist) { AttackTarget(); } else { targetPlayer = null; PathToPlayer(); } } private bool damagedAny = false; void OnTriggerEnter(Collider other) { Player p = other.GetComponentInParent<Player>(); if (p != null && !damaged.Contains(p) && attacking) { DamagePlayer(p); } } public float MinDamageDist = 0.6f; private void DamagePlayer(Player p) { //if (targetPlayer != null && DistToTarget < MinDamageDist) //{ damaged.Add(p); Item playerItem = p.GetComponentInChildren<Item>(); if (playerItem != null && item != null && item.GetNetHost() != null) { item.GetNetHost().SendItemCommand(playerItem.Key, "TakeDamage", new Dictionary<string, object> { { "damage", Damage } }); damagedAny = true; } //} } }