Example #1
0
        /// <summary>
        /// Check if the given cover is fitting.
        /// </summary>
        private bool doesCoverFit(Cover cover)
        {
            if (cover == null || cover.Top < _position.y + 0.5f)
            {
                return(false);
            }

            var position = _position + cover.Forward * _radius;
            var distance = Vector3.Distance(position, cover.ClosestPointTo(position, 0, 0));

            float radius;

            if (cover == _current.Main)
            {
                radius = cover.IsTall(_position.y, _settings.TallThreshold) ? _settings.TallSideLeaveRadius : _settings.LowSideLeaveRadius;
            }
            else
            {
                radius = cover.IsTall(_position.y, _settings.TallThreshold) ? _settings.TallSideEnterRadius : _settings.LowSideEnterRadius;
            }

            var isInFront = cover.IsInFront(_position, cover == _current.Main) &&
                            (cover.IsInFront(_position + cover.Right * radius, cover == _current.Main) || cover.RightAdjacent != null) &&
                            (cover.IsInFront(_position + cover.Left * radius, cover == _current.Main) || cover.LeftAdjacent != null);

            var isOld = isInFront && distance <= _settings.LeaveDistance && cover == _current.Main;

            if (isOld)
            {
                return(true);
            }

            var isNew = isInFront && distance <= _settings.EnterDistance && cover != _current.Main;

            if (isNew)
            {
                return(true);
            }

            return(false);
        }
        /// <summary>
        /// Returns an updated situation struct.
        /// </summary>
        public void Update(AIController controller, AISituation previous, bool updateInDetail)
        {
            if (!IsAlerted)
            {
                HasInvestigatedTheLatestAlert = false;
            }
            else if (Threat == null & Vector3.Distance(CurrentPosition, ThreatGroundPosition) < controller.Distances.ThreatInvestigation)
            {
                MarkInvestigated();
            }

            if (HasAnInvestigatedAlert)
            {
                InvestigatedAlertAge += Time.deltaTime;
            }

            // Check grenades
            {
                IsNearGrenade = false;
                float minDist = 1000;

                foreach (var grenade in GrenadeList.All)
                {
                    var vec  = grenade.transform.position - controller.transform.position;
                    var dist = vec.magnitude;

                    if (dist < grenade.ExplosionRadius)
                    {
                        if (!IsNearGrenade || dist < minDist)
                        {
                            minDist                = dist;
                            IsNearGrenade          = true;
                            NearestGrenadePosition = grenade.transform.position;

                            if (Threat == null)
                            {
                                HasInvestigatedTheLatestAlert = false;
                                HasAnInvestigatedAlert        = false;
                                ThreatGroundPosition          = grenade.transform.position;
                            }
                        }
                    }
                }
            }

            // Check friends and enemies.
            if (Threat == null || (!IsAlerted && !IsGettingAlerted))
            {
                var minEnemyInfoTimer = controller.View.EnemySustainTime;

                foreach (var actor in Actors.All)
                {
                    if (actor != controller.Actor)
                    {
                        if (actor.Side != controller.Actor.Side)
                        {
                            if (AIUtil.IsInSight(controller, actor.TopPosition))
                            {
                                IsAlerted = true;
                                ReadEnemyState(actor);
                                break;
                            }
                        }
                        else if (actor.AI != null && actor.AI.IsAlerted)
                        {
                            var vector = actor.transform.position - controller.transform.position;

                            if (vector.magnitude < controller.View.CommunicationDistance)
                            {
                                IsAlerted = true;

                                if (actor.AI.Situation.NoThreatTimer < actor.AI.View.EnemySustainTime &&
                                    minEnemyInfoTimer > actor.AI.Situation.NoThreatTimer)
                                {
                                    TakeEnemyState(actor.AI);
                                }
                            }
                        }
                    }
                }
            }

            // Check friends if they had investigated the same position
            if (IsAlerted && Threat == null && !HasInvestigatedTheLatestAlert)
            {
                foreach (var friend in Actors.All)
                {
                    if (friend != controller.Actor &&
                        friend.Side == controller.Actor.Side &&
                        friend.AI.IsAlerted &&
                        friend.AI.Situation.HasAnInvestigatedAlert &&
                        friend.AI.Situation.InvestigatedAlertAge < 10 &&
                        Vector3.Distance(friend.transform.position, controller.transform.position) < controller.View.CommunicationDistance &&
                        Vector3.Distance(friend.AI.Situation.InvestigatedThreatPosition, ThreatGroundPosition) < controller.Distances.ThreatInvestigation)
                    {
                        MarkInvestigated();
                        break;
                    }
                }
            }


            // Check threats
            if (Threat == null)
            {
                var minDist = 100000f;

                foreach (var alert in Alerts.All)
                {
                    var dist = Vector3.Distance(controller.transform.position, alert.Position);

                    if (dist < alert.Range)
                    {
                        if (dist < minDist)
                        {
                            minDist                       = dist;
                            IsAlerted                     = true;
                            ThreatGroundPosition          = alert.Position;
                            HasAnInvestigatedAlert        = false;
                            HasInvestigatedTheLatestAlert = false;
                        }
                    }
                }
            }

            // React to grenades
            if (IsNoticingGrenade)
            {
                if (GrenadeReaction < float.Epsilon)
                {
                    IsNoticingGrenade = false;
                }
                else
                {
                    GrenadeReaction -= Time.deltaTime;
                    IsNearGrenade    = false;
                }
            }
            else if (IsNearGrenade && !previous.IsNearGrenade)
            {
                GrenadeReaction   = controller.Fighting.GrenadeReactionTime;
                IsNoticingGrenade = true;
                IsNearGrenade     = false;
            }

            if (IsNearGrenade)
            {
                IsAlerted = true;
            }

            // React to being alerted.
            if (IsGettingAlerted)
            {
                if (AlertReaction < float.Epsilon)
                {
                    IsGettingAlerted = false;
                    IsAlerted        = true;
                }
                else
                {
                    AlertReaction -= Time.deltaTime;
                    IsAlerted      = false;
                }
            }
            else if (IsAlerted && !previous.IsAlerted)
            {
                AlertReaction    = controller.Fighting.ReactionTime;
                IsGettingAlerted = true;
                IsAlerted        = false;
            }

            if (previous.TargetCover != null &&
                (controller.Motor.LeftCover == previous.TargetCover || controller.Motor.RightCover == previous.TargetCover || controller.Motor.Cover == previous.TargetCover))
            {
                CurrentCover = previous.TargetCover;
            }
            else
            {
                CurrentCover = controller.Motor.Cover;
            }

            CurrentPosition = controller.transform.position;
            IsGunReady      = controller.Motor.IsGunReady && controller.Motor.Gun.Clip >= controller.Motor.Gun.ClipSize * controller.Fighting.ReloadFraction;

            if (controller.Health != null && Threat != null && Threat.IsAttacking)
            {
                IsRetreating = IsAlerted && controller.Health.Health <= controller.Fighting.MinHealth;
            }
            else
            {
                IsRetreating = false;
            }

            if (IsAlerted)
            {
                var couldSeeTheEnemy = CanSeeTheThreat;
                CanSeeTheThreat = false;

                if (Threat != null)
                {
                    if (couldSeeTheEnemy || updateInDetail)
                    {
                        CanSeeTheThreat = AIUtil.IsInSight(controller, Threat.TopPosition);
                    }

                    if (CanSeeTheThreat)
                    {
                        ReadEnemyState(Threat);
                    }
                    else
                    {
                        NoThreatTimer += Time.deltaTime;

                        if (updateInDetail)
                        {
                            // Check friends and enemies.
                            foreach (var friend in Actors.All)
                            {
                                if (friend != controller.Actor &&
                                    friend.Side == controller.Actor.Side &&
                                    friend.AI != null &&
                                    friend.AI.IsAlerted &&
                                    friend.AI.Situation.CanSeeTheThreat &&
                                    friend.AI.Situation.Threat == Threat)
                                {
                                    var vector = friend.transform.position - controller.transform.position;

                                    if (vector.magnitude < controller.View.CommunicationDistance)
                                    {
                                        TakeEnemyState(friend.AI);
                                    }
                                }
                            }
                        }
                    }
                }

                if (TargetCover != null && updateInDetail)
                {
                    var distanceToThreat = Vector3.Distance(TargetPosition, ThreatGroundPosition);

                    IsTargetCoverGood = distanceToThreat >= controller.Distances.MinEnemy &&
                                        distanceToThreat >= controller.Cover.MinCoverToEnemyDistance &&
                                        AIUtil.IsGoodAngle(controller,
                                                           TargetCover,
                                                           TargetPosition,
                                                           ThreatGroundPosition,
                                                           TargetCover.IsTall(controller.Motor.CoverSettings.TallThreshold)) &&
                                        !AIUtil.IsCoverPositionTooCloseToFriends(TargetCover, controller, TargetPosition);
                }

                if (updateInDetail)
                {
                    if (TargetCover != null && TargetCover.IsTall(controller.Motor.CoverSettings.TallThreshold))
                    {
                        Vector3 aimPoint;

                        if (TargetDirection < 0)
                        {
                            aimPoint = TargetCover.LeftCorner(0, controller.Motor.CoverSettings.CornerOffset.x);
                        }
                        else
                        {
                            aimPoint = TargetCover.RightCorner(0, controller.Motor.CoverSettings.CornerOffset.x);
                        }

                        CanSeeFromTargetPosition = AIUtil.IsInSight(controller, aimPoint, ThreatStandingTopPosition);
                    }
                    else
                    {
                        CanSeeFromTargetPosition = AIUtil.IsInSight(controller, TargetPosition, ThreatStandingTopPosition);
                    }
                }
            }
            else
            {
                if (TargetCover != null && updateInDetail)
                {
                    IsTargetCoverGood = !AIUtil.IsCoverPositionTooCloseToFriends(TargetCover, controller, TargetPosition);
                }

                CanSeeFromTargetPosition = true;
            }
        }