UnityGameProjectsCode / RelianceGame / AI Control / Enemy Scripts / EnemyAttackState.cs
EnemyAttackState.cs
Raw
using EnemyAIMachineTools;
using System.Collections;
using UnityEngine;

public class EnemyAttackState : EnemyState
{
    private static EnemyAttackState _instance; //only declared once

    private EnemyAttackState() //set instance to itself
    {
        if (_instance != null)
        {
            return;
        }

        _instance = this;
    }

    public static EnemyAttackState instance //creates the instance of the first state if it does not exist
    {
        get
        {
            if (_instance == null)
            {
                new EnemyAttackState();
            }

            return _instance;
        }
    }

    public override IEnumerator InState(EnemyAIMachine owner)
    {
        float timeWaitingToShoot = 0;
        float timeSinceFiring = 0;
        bool shotFired = false;
        bool movingCloserToEnemy = false;

        while (owner.botMachine.currentState == EnemyAttackState.instance)
        {
            if (!owner.disabled)
            {
                if (owner.enemyObject == null)
                {
                    owner.canSeeEnemy = false;
                    owner.health = null;

                    owner.laserLine.enabled = false;
                    owner.barrelLight.enabled = false;

                    if (!owner.insideTurret)
                        owner.botMachine.ChangeState(EnemyChaseState.instance);
                    else
                        owner.botMachine.ChangeState(EnemyTurretSearchState.instance);
                    yield break;
                }
                else
                {
                    if (shotFired == true)
                    {
                        timeSinceFiring += Time.deltaTime;

                        if (!owner.animator.GetCurrentAnimatorStateInfo(0).IsName("BarrelLightFade") && !owner.turretBot)
                        {
                            owner.laserLine.enabled = false;
                            owner.barrelLight.enabled = false;
                        }

                        if (!owner.animator.GetCurrentAnimatorStateInfo(0).IsName("TurretBarrelLightFade") && owner.turretBot)
                        {
                            owner.laserLine.enabled = false;
                            owner.barrelLight.enabled = false;
                        }

                        if (timeSinceFiring >= owner.fireRate && shotFired == true)
                        {
                            timeSinceFiring = 0.0f;
                            shotFired = false;
                        }
                    }

                    if (owner.turretBot == false && movingCloserToEnemy == false)
                        owner.thisAgent.SetDestination(owner.transform.position);

                    //before firing check if there are too many enemies and if the bot should change to the retreat state
                    if (owner.additionalEnemies.Count >= 2 && owner.friendlyBots.Count <= 1 && !owner.turretBot)
                    {
                        for (int i = 0; i < owner.movingBotsOnly.Count; i++) //for all moving bots, check if any of them are close enough to retreat to
                        {
                            if (Vector3.Distance(owner.movingBotsOnly[i].transform.position, owner.transform.position) <= owner.retreatRadius && Vector3.Distance(owner.movingBotsOnly[i].transform.position, owner.transform.position) >= 50)
                            {
                                owner.laserLine.enabled = false;
                                owner.barrelLight.enabled = false;

                                owner.botMachine.ChangeState(EnemyRetreatState.instance);
                                yield break;
                            }
                        }
                    }

                    int numberOfBotsCalled = 0;

                    for (int i = 0; i < owner.movingBotsOnly.Count; i++) //if there are any friendly bots within the reinforcementRadius, give them this bots target
                    {
                        if (Vector3.Distance(owner.transform.position, owner.movingBotsOnly[i].transform.position) <= owner.reinforcementRadius)
                        {
                            EnemyAIMachine target = owner.movingBotsOnly[i].GetComponent<EnemyAIMachine>();

                            if (target.enemyObject == null) //if the current bot doesnt already have a target, set it
                            {
                                target.enemyObject = owner.enemyObject;
                                target.canSeeEnemy = true;

                                numberOfBotsCalled++;
                            }
                        }
                    }

                    if (numberOfBotsCalled != 0)
                    {
                        owner.logD.RecieveLog(owner.displayName + " called " + numberOfBotsCalled + " bot(s) for help!");
                        numberOfBotsCalled = 0;
                    }


                    if (Vector3.Distance(owner.transform.position, owner.enemyObject.transform.position) <= owner.attackDistance && owner.canSeeEnemy)
                    {
                        MoveTurret(owner);

                        if (!owner.turretBot)
                        {
                            timeWaitingToShoot += Time.deltaTime;

                            if (timeWaitingToShoot >= 5f)
                            {
                                owner.thisAgent.SetDestination(owner.enemyObject.transform.position);
                                movingCloserToEnemy = true;

                                if (Vector3.Distance(owner.transform.position, owner.enemyObject.transform.position) <= 20 || owner.onTarget)
                                {
                                    owner.thisAgent.SetDestination(owner.transform.position);
                                    movingCloserToEnemy = false;
                                }
                            }
                        }

                        //after calling the MoveTurret method, wait for the onTarget bool to be true
                        if (owner.onTarget == true)
                        {
                            timeWaitingToShoot = 0;

                            if (!shotFired)
                            {
                                timeSinceFiring = 0.0f;
                                shotFired = true;
                                Shoot(owner);
                            }

                            bool removing = false;

                            for (int i = 0; i < owner.friendlyBots.Count; i++) //if any of the bots are already removing an enemy, dont do anything
                            {
                                if (owner.friendlyBots[i].GetComponent<EnemyAIMachine>().removingEnemy == true)
                                {
                                    removing = true;
                                    break;
                                }
                            }

                            if (removing == false)
                            {
                                if (owner.enemyObject != null)
                                {
                                    if (owner.health.health <= 0)
                                    {
                                        owner.removingEnemy = true;
                                        OnEnemyDeath(owner);
                                    }
                                }
                            }
                        }

                    }
                    else
                    {
                        owner.laserLine.enabled = false;
                        owner.barrelLight.enabled = false;

                        if (!owner.insideTurret)
                            owner.botMachine.ChangeState(EnemyChaseState.instance);
                        else
                            owner.botMachine.ChangeState(EnemyTurretSearchState.instance);
                        yield break;
                    }
                }
            }
            else
            {
                owner.thisAgent.SetDestination(owner.transform.position);
            }
            yield return null;
        }
    }

    private void Shoot(EnemyAIMachine _owner)
    {
        _owner.soundMgr.StartMusicCouroutine();

        int randomHitChance = Random.Range(0, 100);

        float pitchVariance = Random.Range(0.80f, 1.20f);
        _owner.audioS.pitch = pitchVariance;
        _owner.audioS.PlayOneShot(_owner.GetComponent<MultipleAudioClips>().clips[1]);

        int randomLaserMat = Random.Range(0, 5);
        _owner.laserLine.material = _owner.lasers[randomLaserMat];
        _owner.laserLine.SetPosition(0, _owner.barrelEnd.position);
        _owner.laserLine.SetPosition(1, _owner.contactPoint);
        _owner.laserLine.enabled = true;
        _owner.barrelLight.enabled = true;

        if (!_owner.turretBot)
        {
            _owner.animator.Play("BarrelLightFade", 0);
            _owner.animator.Play("LaserFade", 1);
            _owner.animator.Play("BarrelMove", 2);
        }
        else
        {
            _owner.animator.Play("TurretBarrelLightFade", 0);
            _owner.animator.Play("TurretLaserFade", 1);
        }

        _owner.laserParticles.Play();

        if (!_owner.enemyObject.GetComponent<StructureInfo>())
        {
            int modifiedHitChance = 0;

            if (!_owner.enemyObject.GetComponent<AIAllyMachine>())
                modifiedHitChance = _owner.enemyObject.GetComponent<BotStats>().ModifyEnemyHitChance(_owner.hitChance); //call to the enemys bot stats script to change the hit chance based on thier lucky stat
            else
                modifiedHitChance = _owner.hitChance;

            if (randomHitChance <= modifiedHitChance && _owner.enemyObject != null)
            {
                int randomCritChance = Random.Range(0, 100);

                _owner.CreateImpactParticles();

                _owner.audioS.PlayOneShot(_owner.enemyObject.GetComponent<MultipleAudioClips>().clips[0]);

                if (randomCritChance <= _owner.critChance)
                {
                    _owner.health.HealthReduce(2); //reduces health of target, health script grabbed in update of EnemyAIMachine
                }
                else
                {
                    _owner.health.HealthReduce();
                }

                if (_owner.enemyObject.GetComponent<AIMachine>() != null) //if the enemy is an player controlled AI
                {

                    if (_owner.enemyObject.GetComponent<AIMachine>().enemyObject == null) //if the enemy doesnt already have a target, set it to this bot
                    {
                        _owner.enemyObject.GetComponent<AIMachine>().enemyObject = _owner.gameObject;
                        _owner.enemyObject.GetComponent<AIMachine>().canSeeEnemy = true;
                    }
                }
                else if (_owner.enemyObject.GetComponent<AIAllyMachine>()) //if the enemy is an Ally AI
                {

                    if (_owner.enemyObject.GetComponent<AIAllyMachine>().enemyObject == null) //if the enemy doesnt already have a target, set it to this bot
                    {
                        _owner.enemyObject.GetComponent<AIAllyMachine>().enemyObject = _owner.gameObject;
                        _owner.enemyObject.GetComponent<AIAllyMachine>().canSeeEnemy = true;
                    }
                }
            }
            else
            {
                _owner.logD.RecieveLog(_owner.displayName + " missed their shot.");
            }
        }
        else
        {
            if (randomHitChance <= _owner.hitChance && _owner.enemyObject != null)
            {
                _owner.audioS.PlayOneShot(_owner.enemyObject.GetComponent<MultipleAudioClips>().clips[0]);

                int randomCritChance = Random.Range(0, 100);

                if (randomCritChance <= _owner.critChance)
                {
                    _owner.health.HealthReduce(2);
                }
                else
                {
                    _owner.health.HealthReduce();
                }
            }
        }

    }

    private void OnEnemyDeath(EnemyAIMachine _owner)
    {
        var tempEnemyHolder = _owner.enemyObject;

        _owner.enemyObject.SetActive(false);
        _owner.enemyObject = null;
        _owner.health = null;
        _owner.canSeeEnemy = false;

        if (tempEnemyHolder.GetComponent<StructureInfo>()) //check what type of enemy was killed and put out the correct logs
        {
            _owner.logD.RecieveLog(tempEnemyHolder.GetComponent<StructureInfo>().displayName + " has died", Color.red);
            _owner.gameMgr.OnStructureDestroy(tempEnemyHolder);
        }
        else
        {
            if (tempEnemyHolder.GetComponent<Health>().HP == null) //if the enemy target has no text variable, it is an ally (protect mode unit)
            {
                _owner.logD.RecieveLog(tempEnemyHolder.GetComponent<AIAllyMachine>().displayName + " has died", Color.red);
                _owner.gameMgr.EnemyOnKill(tempEnemyHolder);
            }
            else
            {
                tempEnemyHolder.GetComponent<Health>().HP.text = "Dead";
                _owner.gameMgr.EnemyOnKill(tempEnemyHolder);

                if (tempEnemyHolder.GetComponent<AIMachine>() != null)
                    _owner.logD.RecieveLog(tempEnemyHolder.GetComponent<AIMachine>().displayName + " has died", Color.red);
                else
                    _owner.logD.RecieveLog(_owner.displayName + ": lead bot has died", Color.red);
            }
        }

        for (int i = 0; i < _owner.friendlyBots.Count; i++) //after the enemy is dead, check other friendly bots for the same target, remove it, then send them to an appropriate state
        {
            EnemyAIMachine targetBot = null;

            targetBot = _owner.friendlyBots[i].GetComponent<EnemyAIMachine>();

            if (targetBot.enemyObject == tempEnemyHolder && targetBot.gameObject.activeSelf == true)
            {
                targetBot.enemyObject = null;
                targetBot.health = null;
                targetBot.canSeeEnemy = false;
                targetBot.laserLine.enabled = false;
                targetBot.barrelLight.enabled = false;

                var currentState = targetBot.botMachine.currentState;

                if (currentState == EnemyAttackState.instance && !_owner.turretBot)
                    targetBot.botMachine.ChangeState(EnemyChaseState.instance);
                else if (currentState == EnemyAttackState.instance && _owner.turretBot)
                    targetBot.botMachine.ChangeState(EnemyTurretSearchState.instance);

            }
        }

        _owner.removingEnemy = false;
    }

    private void MoveTurret(EnemyAIMachine _owner) //called to move the bots turret so that it faces the target
    {
        //declare variables that will be used to determine how to move the turret
        Vector3 hitPos = _owner.enemyObject.GetComponentInChildren<HighlightObject>().transform.position;
        Quaternion turretRot = Quaternion.LookRotation(hitPos - _owner.turretPos.transform.position);

        if (Vector3.Angle(_owner.turretPos.transform.forward, _owner.enemyObject.transform.position - _owner.turretPos.transform.position) > 5) //rotate the turret until it is facing within 5 degrees of the enemy
        {
            //rotate the turret over time to the enemy
            _owner.turretPos.transform.rotation = Quaternion.RotateTowards(_owner.turretPos.transform.rotation, turretRot, Time.deltaTime * _owner.turretRotateSpeed);

            //set the turrets y euler angle so that it only moves on that transform
            _owner.turretPos.transform.localEulerAngles = new Vector3(0, _owner.turretPos.transform.localEulerAngles.y, 0);
        }

        //rotate the barrel over time to the enemy
        _owner.barrelPos.transform.rotation = Quaternion.RotateTowards(_owner.barrelPos.transform.rotation, turretRot, Time.deltaTime * _owner.barrelMoveSpeed);

        //set the barrels y euler angle so that it only moves on that transform
        if (_owner.turretBot)
            _owner.barrelPos.transform.localEulerAngles = new Vector3(_owner.barrelPos.transform.localEulerAngles.x, 0, 0);
        else
            _owner.barrelPos.transform.localEulerAngles = new Vector3(0, _owner.barrelPos.transform.localEulerAngles.y, 0);
    }
}