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;
}
//}
}
}