コード例 #1
0
    protected void FixedUpdate()
    {
        HandleAnimation();

        if (!Alive() || !GameManager.Instance.GameStarted || !navMeshAgent.isOnNavMesh)
        {
            return;
        }


        if (InArea && InArea.Visible() && MovementAudio && !MovementAudio.isPlaying)
        {
            MovementAudio.Play();
        }
        else if (InArea && !InArea.Visible() && MovementAudio && MovementAudio.isPlaying)
        {
            MovementAudio.Stop();
        }

        if (SPE.GetStatMax() < 1)
        {
            Debug.LogWarning("Speed is 0");
        }

        navMeshAgent.speed = Walking ? Mathf.Min(WalkingSpeed, SPE.GetStatMax()) / 2f : SPE.GetStatMax() / 2f;

        DesiredVelocity = navMeshAgent.desiredVelocity.sqrMagnitude;
        AgentVelocity   = navMeshAgent.velocity.sqrMagnitude;
        HasPath         = navMeshAgent.hasPath;
        PathStale       = navMeshAgent.isPathStale;
        IsOnNavMesh     = navMeshAgent.isOnNavMesh;

        //if (IncoherentNavAgentSpeed() && agentStuckRoutine == null)
        //    agentStuckRoutine = StartCoroutine(CheckForNavAgentStuck(0.25f));

        //TODO: merge together with move's switch statement
        if (Attacking() && AttackTarget && AttackTarget.Alive() && InAttackRange()
            ) //has live enemy target and in attackrange
        {
            navMeshAgent.isStopped = true;

            if (_attackRoutine == null)
            {
                _attackRoutine = StartCoroutine(AttackRoutine());
            }
        }
        else
        {
            navMeshAgent.isStopped = false;
            SelectAction();
        }
    }
コード例 #2
0
    private IEnumerator AttackRoutine()
    {
        //Debug.Log(gameObject.name + " is Attacking " + AttackTarget.gameObject.name);

        State = CharacterState.Attacking;
        while (Attacking() && InAttackRange() && AttackTarget.Alive())
        {
            (this as Goblin)?.Speak(SoundBank.GoblinSound.Attacking);

            //HIT TARGET
            var damage = Random.Range(1, DMG.GetStatMax()) * OutgoingDmgPct;
            if (AttackTarget.Surprised())
            {
                damage = (int)(damage * AmbushModifier);
            }
            var target = AttackTarget;
            if (!(target.Team && GameManager.Instance.InvincibleMode))
            {
                target.Health -= (int)Mathf.Round(damage * target.IncomingDmgPct);
            }

            if (target.Health <= 0)
            {
                //Debug.Log(name + " killed " + target.name);

                if (this as Goblin)
                {
                    ((Goblin)this).Xp += GameManager.XpKill();
                    if (Team)
                    {
                        Team.OnTeamKill.Invoke();
                    }
                    (this as Goblin)?.Speak(SoundBank.GoblinSound.Laugh);
                }

                break;
            }

            //Debug.Log(gameObject.name + " hit " + AttackTarget.gameObject.name +" for " + Damage + " damage");

            //should be tied to animation maybe?
            yield return(new WaitForSeconds(AttackTime));
        }

        _attackRoutine = null;
    }
コード例 #3
0
    private bool InAttackRange()
    {
        if (!AttackTarget || !AttackTarget.Alive())
        {
            return(false);
        }

        var targetCol = AttackTarget.GetComponent <CapsuleCollider>();

        if (!targetCol)
        {
            Debug.LogWarning(name + "'s target does not have a capsule collider");
            return(false);
        }

        var boxCol = GetComponent <CapsuleCollider>();

        return((boxCol.transform.position - (targetCol.transform.position)).magnitude
               <= boxCol.radius * boxCol.transform.lossyScale.x
               + targetCol.radius * targetCol.transform.lossyScale.x + AttackRange);
    }
コード例 #4
0
    private void SelectAction()
    {
        switch (State)
        {
        case CharacterState.Idling:
            //reset morale
            Morale = COU.GetStatMax() * 2;

            if (actionInProgress)
            {
                if (navMeshAgent.remainingDistance < 0.02f)
                {
                    actionInProgress = false;
                }
            }
            else if (IrritationMeter >= IrritaionTolerance)
            {
                ChangeState(CharacterState.Attacking);
            }
            else if (Random.value < 0.015f)     //selecting idle action
            {
                (this as Goblin)?.Speak(PlayerController.GetDynamicReactions(PlayerController.DynamicState.Idle));

                actionInProgress = true;

                Vector3 dest;

                if (InArea)
                {
                    if (GetClosestEnemy() &&
                        (        //ANY friends fighting
                            InArea.PresentCharacters.Any(c => c.tag == tag && c.Alive() && c.Attacking())
                            // I am aggressive wanderer
                            || (StickToRoad && InArea.PresentCharacters.Any(c => c.tag == "Player" & !c.Hiding()))
                        ))
                    {
                        //Debug.Log(name + ": Joining attack without beeing attacked");

                        ChangeState(CharacterState.Attacking, true);
                        Morale -= 5;
                        Target  = GetClosestEnemy().transform.position;
                        dest    = Target;
                    }
                    else if ((this as Goblin) && Team && Team.Leader.InArea != InArea && Team.Leader.Idling())
                    {
                        dest = Team.Leader.InArea.GetRandomPosInArea();
                    }
                    else if ((this as Goblin) && tag == "Player" && GetClosestEnemy() && (GetClosestEnemy().transform.position - transform.position).magnitude < provokeDistance)
                    {
                        ChangeState(CharacterState.Provoking, true);
                        var ctx = GetClosestEnemy();
                        (this as Goblin).ProvokeTarget = ctx;
                        (this as Goblin)?.Speak(PlayerController.GetDynamicReactions(PlayerController.DynamicState.Mocking));
                        dest = ctx.transform.position;
                    }
                    else if (StickToRoad)
                    {
                        var goingTo = InArea.GetClosestNeighbour(transform.position, true);

                        dest = goingTo.PointOfInterest ? goingTo.GetRandomPosInArea(): goingTo.transform.position;

                        //Debug.Log(name + ": Wandering to "+ goingTo);
                        Target = dest;

                        goingTo.PresentCharacters.ForEach(c => StartCoroutine(c.SpotArrivalCheck(this)));

                        ChangeState(CharacterState.Travelling, true);
                    }
                    else
                    {
                        dest = InArea.GetRandomPosInArea();
                    }
                }
                else
                {
                    dest   = transform.position + Random.insideUnitSphere * idleDistance;
                    dest.y = 0;
                }

                navMeshAgent.SetDestination(dest);    //new Vector3(Random.Range(-idleDistance, idleDistance), 0,Random.Range(-idleDistance, idleDistance)));
            }
            //TODO: use a different method for activity selection than else if
            else if (Random.value < 0.0025f && this as Goblin && Team &&
                     !(Team.Leader == this) && (this as Goblin).ClassType > Goblin.Class.Slave
                     & !Team.Challenger && (Team.Leader as Goblin).CurrentLevel < ((Goblin)this).CurrentLevel)
            {
                //TODO: make it only appear after a while

                Debug.Log("Chief Fight!!");
                Team.ChallengeForLeadership(this as Goblin);
            }
            //TODO: define better which characters should search stuff
            else if (Random.value < 0.001f * SMA.GetStatMax() && Team && this as Goblin && !InArea.AnyEnemies() && InArea.Lootables.Any(l => !l.Searched))
            {
                var loots = InArea.Lootables.Where(l => !l.Searched).ToArray();

                var loot = loots[Random.Range(0, loots.Count())];

                (this as Goblin).Search(loot);
            }
            break;

        case CharacterState.Attacking:
            if (AttackTarget && AttackTarget.Alive() && AttackTarget.InArea == InArea)
            {
                if (AttackTarget.Fleeing())
                {
                    var c = GetClosestEnemy();
                    if (c)
                    {
                        AttackTarget = c;
                    }
                }

                navMeshAgent.SetDestination(AttackTarget.transform.position);

                //TODO: add random factor
            }
            else
            {
                TargetGone();
            }
            break;

        case CharacterState.Travelling:
            navMeshAgent.SetDestination(Target);
            //check for arrival and stop travelling
            if (Vector3.Distance(transform.position, Target) < 3f)
            {
                //Debug.Log(name +" arrived at target");
                State = CharacterState.Idling;

                actionInProgress = false;

                break;
            }

            break;

        case CharacterState.Fleeing:
            (this as Goblin)?.Speak(SoundBank.GoblinSound.PanicScream);

            //if (actionInProgress &! navMeshAgent.hasPath)
            //{
            //    //TODO: move into next if statement, if correct
            //    Debug.Log("stuck fleeing resolved");
            //    actionInProgress = false;
            //    ChangeState(CharacterState.Idling, true);
            //}
            if (fleeingToArea == InArea && navMeshAgent.remainingDistance < 0.1f)
            {
                actionInProgress = false;
                ChangeState(CharacterState.Idling, true);
            }
            else if (!actionInProgress)
            {
                fleeingToArea = InArea.GetClosestNeighbour(transform.position, StickToRoad);
                navMeshAgent.SetDestination(fleeingToArea.GetRandomPosInArea());

                actionInProgress = true;
            }
            break;

        case CharacterState.Dead:
            break;

        case CharacterState.Hiding:
            if (!Hidingplace)
            {
                State = CharacterState.Idling;
            }
            //already set the destination
            if ((navMeshAgent.destination - hiding.HideLocation.transform.position).sqrMagnitude < 1f)
            {
                if (InArea.AnyEnemies() && navMeshAgent.remainingDistance > 0.2f)
                {
                    ChangeState(CharacterState.Idling);
                }
            }
            else
            {
                navMeshAgent.SetDestination(hiding.HideLocation.transform.position);
            }
            break;

        //Only to be used for chief fights. TODO: rename
        case CharacterState.Watching:
            if (!Team || !Team.Challenger)
            {
                //cheer
                (this as Goblin)?.Speak(SoundBank.GoblinSound.Laugh);
                ChangeState(CharacterState.Idling, true);
            }
            else
            {
                if (Vector3.Distance(transform.position, Team.Challenger.transform.position) < 3f && Team.Challenger != this && Team.Leader != this)
                {
                    //cheer
                    (this as Goblin)?.Speak(PlayerController.GetDynamicReactions(PlayerController.DynamicState.ChiefBattleCheer));

                    navMeshAgent.ResetPath();
                }
                else if (!actionInProgress)
                {
                    navMeshAgent.SetDestination(Team.Challenger.transform.position);
                    actionInProgress = true;
                }
            }

            break;

        case CharacterState.Searching:
            //check for arrival and stop travelling
            if (Vector3.Distance(transform.position, LootTarget.transform.position) < 2f)
            {
                if (LootTarget.ContainsLoot)
                {
                    (this as Goblin)?.Speak(SoundBank.GoblinSound.Laugh);
                    PopUpText.ShowText(name + " found " + LootTarget.Loot);
                    Team.OnTreasureFound.Invoke(1);
                }
                if (LootTarget.ContainsFood)
                {
                    (this as Goblin)?.Speak(SoundBank.GoblinSound.Laugh);
                    PopUpText.ShowText(name + " found " + LootTarget.Food);
                    Team.OnFoodFound.Invoke(5);
                }
                if (this as Goblin)
                {
                    foreach (var equipment in LootTarget.EquipmentLoot)
                    {
                        //TODO: create player choice for selecting goblin
                        (this as Goblin)?.Speak(SoundBank.GoblinSound.Laugh);
                        PopUpText.ShowText(name + " found " + equipment.name);
                        if (Team && Team.Members.Count > 1)
                        {
                            Team.OnEquipmentFound.Invoke(equipment, this as Goblin);
                        }
                        else
                        {
                            Equip(equipment);
                        }
                    }
                }

                LootTarget.EquipmentLoot.Clear();

                LootTarget.ContainsFood = false;
                LootTarget.ContainsLoot = false;
                LootTarget.Searched     = true;

                State = CharacterState.Idling;
                break;
            }
            break;

        case CharacterState.Provoking:
            var g = this as Goblin;

            if (!g)
            {
                Debug.LogWarning("Non-goblin is being provocative");
                break;
            }

            if (!g.ProvokeTarget || g.ProvokeTarget.InArea != InArea)
            {
                (this as Goblin)?.Speak(SoundBank.GoblinSound.Laugh);
                g.ProvokeTarget = GetClosestEnemy();
            }

            if (!g.ProvokeTarget)
            {
                ChangeState(CharacterState.Idling, true);
                break;
            }

            if (g.ProvokeTarget.Attacking())
            {
                ChangeState(CharacterState.Attacking);
                break;
            }

            if (!actionInProgress && navMeshAgent.remainingDistance < 0.5f)
            {
                actionInProgress = true;
                navMeshAgent.SetDestination(g.ProvokeTarget.transform.position);
                ProvokeStartTime = Time.time;
                break;
            }

            if (ProvokeTime + ProvokeStartTime > Time.time)
            {
                //run away
                actionInProgress = false;
                var dest = InArea.GetRandomPosInArea();
                navMeshAgent.SetDestination(dest);
                g.ProvokeTarget.IrritationMeter++;
                break;
            }
            if ((g.ProvokeTarget.transform.position - transform.position).magnitude < 4)     //Provoke
            {
                navMeshAgent.isStopped = true;
                if (Random.value < 0.2f)
                {
                    (this as Goblin)?.Speak(
                        PlayerController.GetDynamicReactions(PlayerController.DynamicState.Mocking));
                }
            }
            break;

        case CharacterState.Surprised:
            navMeshAgent.isStopped = true;

            if (SurprisedTime + SurprisedStartTime <= Time.time)
            {
                ChangeState(CharacterState.Attacking);
            }
            break;

        case CharacterState.Resting:


            if (!Team || !Team.Campfire)
            {
                ChangeState(CharacterState.Idling, true);
            }
            else
            {
                if (Vector3.Distance(transform.position, Team.Campfire.transform.position) < 4f)
                {
                    (this as Goblin)?.Speak(SoundBank.GoblinSound.Eat);

                    navMeshAgent.ResetPath();
                }
                else if (!actionInProgress)
                {
                    navMeshAgent.SetDestination(Team.Campfire.transform.position);
                    actionInProgress = true;
                }
            }

            break;

        default:
            break;
        }
    }