Esempio n. 1
0
        private void UpdateState()
        {
            //forced death check
            if (CurrentAiState != ActorAiState.Dead)
            {
                if (Health <= 0)
                {
                    EnterState(ActorAiState.Dead);
                }
            }

            //hack to retrieve swizzled target after a load
            GetSwizzledTarget();

            switch (CurrentAiState)
            {
            case ActorAiState.Idle:
                if (Aggressive)
                {
                    //search for targets, select target
                    SelectTarget();
                    if (Target != null)
                    {
                        EnterState(ActorAiState.Chasing);
                    }
                }
                break;

            case ActorAiState.Wandering:
                //TODO aggression
                if (MovementComponent.DistToTarget <= WanderThreshold || TimeInState >= WanderTimeout)
                {
                    Vector2 newpos = VectorUtils.GetRandomVector2(InitialPosition.GetFlatVector(), WanderRadius);
                    MovementComponent.SetDestination(newpos.GetSpaceVector());
                    TimeInState = 0;
                }
                if (Aggressive)
                {
                    //search for targets, select target
                    SelectTarget();
                    if (Target != null)
                    {
                        EnterState(ActorAiState.Chasing);
                    }
                }
                break;

            case ActorAiState.Chasing:
                if (!RpgWorldUtils.TargetIsAlive(Target))
                {
                    EnterState(BaseAiState);
                    break;
                }

                if ((MetaState.Instance.SessionFlags.Contains("NoTarget") || GameState.Instance.PlayerFlags.Contains(PlayerFlags.NoTarget)) && Target.GetComponent <PlayerController>())
                {
                    EnterState(BaseAiState);
                    break;
                }

                if (AttackComponent != null && AttackComponent.ReadyToAttack && AttackComponent.TargetInRange)
                {
                    EnterState(ActorAiState.Attacking);
                    return;
                }
                else
                {
                    //set target
                    var d = Target.position;
                    MovementComponent.SetDestination(d);
                }
                if (!Relentless)
                {
                    //break off if we are too far away or too badly hurt
                    if (Health <= (MaxHealth * 0.2f))
                    {
                        EnterState(ActorAiState.Fleeing);
                    }
                    else if ((Target.position - transform.position).magnitude > SearchRadius)
                    {
                        EnterState(BaseAiState);
                        Target = null;
                    }
                }
                break;

            case ActorAiState.ScriptedMoveTo:
                if (MovementComponent.AtTarget)     //we made it!
                {
                    EnterState(ActorAiState.Idle);  //don't wander off if you were sent there!
                }
                break;

            case ActorAiState.Attacking:
                //wait...
                if (!AttackComponent.DidAttack && AttackComponent.WarmupIsDone)
                {
                    AttackComponent.DoAttack();     //waaaaay too complicated to cram here
                }
                if (AttackComponent.AttackIsDone)
                {
                    //just return
                    if (!RpgWorldUtils.TargetIsAlive(Target))
                    {
                        EnterState(BaseAiState);
                    }
                    else
                    {
                        EnterState(ActorAiState.Chasing);
                    }
                }
                break;

            case ActorAiState.Hurting:
                if (TimeInState >= PainWaitTime)
                {
                    if (BeenHit && Target != null)
                    {
                        EnterState(ActorAiState.Chasing);
                    }
                    else
                    {
                        EnterState(LastAiState);
                    }
                }
                break;

            case ActorAiState.Fleeing:
                //stop running if far enough away, or target is gone
                if (!RpgWorldUtils.TargetIsAlive(Target) || (Target.position - transform.position).magnitude > SearchRadius)
                {
                    EnterState(BaseAiState);
                    Target = null;
                    break;
                }
                {
                    //set target
                    var d = transform.position + ((Target.position - transform.position).normalized * -1);
                    MovementComponent.SetDestination(d);
                }
                break;
            }
        }
Esempio n. 2
0
        private void SelectTarget()
        {
            var gameplayConfig = ConfigState.Instance.GetGameplayConfig();

            if (TotalTickCount % SearchInterval * (1f / gameplayConfig.Difficulty.ActorAggression) != 0)
            {
                return;
            }

            var detectionDifficultyFactor = 1f / gameplayConfig.Difficulty.ActorPerception;

            //check player first since it's (relatively) cheap
            if (FactionModel.GetRelation(Faction, "Player") == FactionRelationStatus.Hostile && !MetaState.Instance.SessionFlags.Contains("NoTarget") && !GameState.Instance.PlayerFlags.Contains(PlayerFlags.NoTarget))
            {
                var playerObj = WorldUtils.GetPlayerObject();
                if (playerObj != null && RpgWorldUtils.TargetIsAlive(playerObj.transform))
                {
                    PlayerController pc = playerObj.GetComponent <PlayerController>();

                    if ((playerObj.transform.position - transform.position).magnitude <= SearchRadius &&
                        UnityEngine.Random.Range(0f, 1f * detectionDifficultyFactor) <= RpgValues.DetectionChance(GameState.Instance.PlayerRpgState, pc.MovementComponent.IsCrouching, pc.MovementComponent.IsRunning))
                    {
                        if (UseLineOfSight)
                        {
                            //additional check
                            RaycastHit hitinfo;
                            if (Physics.Raycast(transform.position + new Vector3(0, 1.0f, 0), (playerObj.transform.position - transform.position), out hitinfo))
                            {
                                if (hitinfo.collider.gameObject == playerObj)
                                {
                                    Target = playerObj.transform;
                                    return;
                                }
                            }
                        }
                        else
                        {
                            //otherwise, close enough
                            Target = playerObj.transform;
                            return;
                        }
                    }
                }
            }

            //if(TargetNpc)
            {
                //var sw = System.Diagnostics.Stopwatch.StartNew();

                //new code should be faster if n is large but it may not bear out in practice, and it probably allocs more dedotated wam

                var colliders = Physics.OverlapSphere(transform.position, SearchRadius, LayerMask.GetMask("Default", "ActorHitbox"));
                HashSet <ActorController> potentialTargets = new HashSet <ActorController>();

                foreach (var collider in colliders)
                {
                    var actorController = collider.GetComponent <ActorController>();
                    if (actorController != null)
                    {
                        potentialTargets.Add(actorController);
                        break;
                    }

                    var hitboxComponent = collider.GetComponent <IHitboxComponent>();
                    if (hitboxComponent != null && hitboxComponent.ParentController is ActorController hitboxAC)
                    {
                        potentialTargets.Add(hitboxAC);
                        break;
                    }
                }


                //old stupid code: should work well enough as long as n is small and your computer is fast enough
                //IEnumerable<ActorController> potentialTargets = transform.root.GetComponentsInChildren<ActorController>();

                foreach (var potentialTarget in potentialTargets)
                {
                    if (RpgWorldUtils.TargetIsAlive(potentialTarget.transform) &&
                        (potentialTarget.transform.position - transform.position).magnitude <= SearchRadius &&
                        FactionModel.GetRelation(Faction, potentialTarget.Faction) == FactionRelationStatus.Hostile &&
                        !(potentialTarget == this))
                    {
                        //roll some dice
                        if (potentialTarget.Detectability < 1 && UnityEngine.Random.Range(0f, 1f * detectionDifficultyFactor) > potentialTarget.Detectability) //probably correct
                        {
                            continue;
                        }

                        if (UseLineOfSight)
                        {
                            //additional check
                            RaycastHit hitinfo;
                            if (Physics.Raycast(transform.position + new Vector3(0, 1.0f, 0), (potentialTarget.transform.position - transform.position), out hitinfo))
                            {
                                if (hitinfo.collider.gameObject == potentialTarget.gameObject)
                                {
                                    Target = potentialTarget.transform;
                                    break;
                                }
                            }
                        }
                        else
                        {
                            //otherwise, close enough
                            Target = potentialTarget.transform;
                            break;
                        }
                    }
                }

                //sw.Stop();
                //Debug.Log($"Target lookup: {sw.Elapsed.TotalMilliseconds:F4} ms");
            }

            if (!RpgWorldUtils.TargetIsAlive(Target))
            {
                Target = null;
            }
        }
Esempio n. 3
0
        private void SelectTarget()
        {
            var gameplayConfig = ConfigState.Instance.GetGameplayConfig();

            if (TotalTickCount % SearchInterval * (1f / gameplayConfig.Difficulty.ActorAggression) != 0)
            {
                return;
            }

            if (TargetPicker != null)
            {
                Target = TargetPicker();
                return;
            }

            var detectionDifficultyFactor = 1f / gameplayConfig.Difficulty.ActorPerception;

            //check player first since it's (relatively) cheap
            if (GameState.Instance.FactionState.GetRelation(Faction, "Player") == FactionRelationStatus.Hostile && !MetaState.Instance.SessionFlags.Contains("NoTarget") && !GameState.Instance.PlayerFlags.Contains(PlayerFlags.NoTarget))
            {
                var playerObj = WorldUtils.GetPlayerObject();
                if (playerObj != null && RpgWorldUtils.TargetIsAlive(playerObj.transform))
                {
                    PlayerController pc = playerObj.GetComponent <PlayerController>();

                    if ((playerObj.transform.position - transform.position).magnitude <= SearchRadius &&
                        UnityEngine.Random.Range(0f, 1f * detectionDifficultyFactor) <= ((IAmTargetable)pc).Detectability)
                    {
                        if (UseLineOfSight)
                        {
                            if (CheckLineOfSight(pc))
                            {
                                Target = playerObj.transform;
                                return;
                            }
                        }
                        else
                        {
                            //otherwise, close enough
                            Target = playerObj.transform;
                            return;
                        }
                    }
                }
            }

            //if(TargetNpc)
            {
                //var sw = System.Diagnostics.Stopwatch.StartNew();

                //new code should be faster if n is large but it may not bear out in practice, and it probably allocs more dedotated wam

                var colliders = Physics.OverlapSphere(transform.position, SearchRadius, WorldUtils.GetAttackLayerMask());
                HashSet <IAmTargetable> potentialTargets = new HashSet <IAmTargetable>();

                foreach (var collider in colliders)
                {
                    var baseController = collider.GetComponent <BaseController>();
                    if (baseController != null)
                    {
                        if (baseController is IAmTargetable iat && iat.ValidTarget)
                        {
                            potentialTargets.Add(iat);
                        }
                        continue; //continue anyway since we've found a base controller and it's either targetable or it's not
                    }

                    var hitboxComponent = collider.GetComponent <IHitboxComponent>();
                    if (hitboxComponent != null && hitboxComponent.ParentController is IAmTargetable iat2 && iat2.ValidTarget)
                    {
                        potentialTargets.Add(iat2);
                        continue;
                    }
                }


                //old stupid code: should work well enough as long as n is small and your computer is fast enough
                //IEnumerable<ActorController> potentialTargets = transform.root.GetComponentsInChildren<ActorController>();

                foreach (var potentialTarget in potentialTargets)
                {
                    BaseController targetController = potentialTarget as BaseController;
                    if (targetController == null)
                    {
                        continue;
                    }

                    if (RpgWorldUtils.TargetIsAlive(targetController.transform) &&
                        (targetController.transform.position - transform.position).magnitude <= SearchRadius &&
                        GameState.Instance.FactionState.GetRelation(Faction, potentialTarget.Faction) == FactionRelationStatus.Hostile &&
                        !(potentialTarget == this))
                    {
                        //roll some dice
                        if (potentialTarget.Detectability < 1 && UnityEngine.Random.Range(0f, 1f * detectionDifficultyFactor) > potentialTarget.Detectability) //probably correct
                        {
                            continue;
                        }

                        if (UseLineOfSight)
                        {
                            if (CheckLineOfSight(targetController))
                            {
                                Target = targetController.transform;
                                break;
                            }
                        }
                        else
                        {
                            //otherwise, close enough
                            Target = targetController.transform;
                            break;
                        }
                    }
                }

                //sw.Stop();
                //Debug.Log($"Target lookup: {sw.Elapsed.TotalMilliseconds:F4} ms");
            }

            if (!RpgWorldUtils.TargetIsAlive(Target))
            {
                Target = null;
            }
        }