/// <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; } }