Newer
Older
BlackoutClient / Assets / Gameplay / Virus.cs
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();
    }
        
    // 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 OnDestroy()
    {
        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;

        attackTween.Init(v => transform.position = startPos + delta * v, SimpleTween.QuadEaseOut, 0, 1, AttackTime);
        attackTween.OnFinish = FinishedAttack;

        attackTimer.Start(AttackTime / AttackDistMult, DamageTarget);
        
    }

    public float AttackWait = 0.8f;

    private void FinishedAttack()
    {
        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 void DamageTarget()
    {
        if (targetPlayer != null)
        {
            Item playerItem = targetPlayer.GetComponentInChildren<Item>();
            if (playerItem != null && item != null && item.GetNetHost() != null)
            {
                item.GetNetHost().SendItemCommand(playerItem.Key, "TakeDamage", new Dictionary<string, object> { { "damage", Damage } });
            }
        }
    }
}