Beispiel #1
0
        /// <summary>
        /// Tell the threat to mark itself as being behind the given cover.
        /// </summary>
        public void OnEnterCover(Cover cover)
        {
            if (_cover != null)
            {
                _cover.UnregisterUser(this);
            }

            _cover = cover;
            _cover.RegisterUser(this, transform.position);
        }
Beispiel #2
0
        private void updateRegistration()
        {
            if (_registeredCover != _targetCover)
            {
                if (_registeredCover != null)
                {
                    _registeredCover.UnregisterUser(_actor);
                }

                _registeredCover = _targetCover;
            }

            if (_registeredCover != null)
            {
                if (_actor.Cover == _registeredCover)
                {
                    _registeredCover.RegisterUser(_actor, _actor.transform.position);
                }
                else
                {
                    _registeredCover.RegisterUser(_actor, _targetPosition);
                }
            }
        }
        private void Update()
        {
            if (_situation.IsAlerted)
            {
                if (!_hasAddedToAlertedControllers)
                {
                    _hasAddedToAlertedControllers = true;
                    _alertedControllers.Add(this);
                }
            }
            else if (_hasAddedToAlertedControllers)
            {
                _alertedControllers.Remove(this);
            }

            _stateTime += Time.deltaTime;

            _agent.updatePosition = false;
            _agent.updateRotation = false;
            _agent.updateUpAxis   = false;
            _agent.autoRepath     = true;
            _agent.autoBraking    = false;

            if (!_motor.IsAlive)
            {
                _situation.TargetCover = null;
            }

            if (_lastTargetCover != _situation.TargetCover)
            {
                if (_lastTargetCover != null)
                {
                    _lastTargetCover.UnregisterUser(_actor);
                }

                _lastTargetCover = _situation.TargetCover;

                if (_lastTargetCover != null)
                {
                    _lastTargetCover.RegisterUser(_actor);
                }
            }

            if (_isWaitingForPath && !_agent.pathPending)
            {
                _pathLength       = _agent.path.GetCornersNonAlloc(_path);
                _currentPathIndex = 0;
                _isWaitingForPath = false;
            }

            if (!_motor.IsAlive)
            {
                _state         = AIState.none;
                _agent.enabled = false;
                return;
            }
            else
            {
                _agent.enabled = true;
            }

            if (_motor.PotentialCover != null)
            {
                _motor.InputTakeCover();
            }

            if (_situation.IsAlerted)
            {
                if (!_motor.IsInCover)
                {
                    _motor.InputAim();
                }

                // Make the AI pick up a weapon.
                if (Fighting.WeaponToUse <= 0)
                {
                    _motor.InputWeapon(0);
                }
                else if (Fighting.WeaponToUse - 1 < _motor.Weapons.Length)
                {
                    _motor.InputWeapon(Fighting.WeaponToUse);
                }
                else
                {
                    _motor.InputWeapon(_motor.Weapons.Length);
                }

                _situation.IsAllowedToBeAggressive = true;

                ///
                /// POTENTIALLY FORGET ABOUT THE ENEMY. CHECK IF CAN BE AGGRESSIVE.
                ///
                if (_situation.Threat != null)
                {
                    if (_situation.Threat.IsAlive)
                    {
                        if (!_situation.CanSeeTheThreat && _situation.NoThreatTimer > View.EnemySustainTime)
                        {
                            _situation.RemoveEnemyState();
                        }
                        else
                        {
                            if (_registeredGroup != null)
                            {
                                _registeredGroup.MarkAsPotentialAggressive(this);
                                _situation.IsAllowedToBeAggressive = _registeredGroup.IsAggressive(this);
                            }
                        }
                    }
                    else
                    {
                        _situation.RemoveEnemyState();
                    }
                }

                ///
                /// AIM AND FIRE
                ///
                if (_situation.Threat != null && (_situation.CanSeeTheThreat || _situation.NoThreatTimer < View.SightSustainTime))
                {
                    // Process grenade throwing
                    if (_situation.ThrownGrenadeCount < Grenades.GrenadeCount)
                    {
                        var doThrow = false;

                        if (_situation.IsAllowedToBeAggressive)
                        {
                            if (_hasThrowFirstGrenade)
                            {
                                if (_grenadeTimer < Grenades.Interval)
                                {
                                    _grenadeTimer += Time.deltaTime;
                                }
                                else
                                {
                                    doThrow = true;
                                }
                            }
                            else
                            {
                                if (_grenadeTimer < Grenades.FirstGrenadeDelay)
                                {
                                    _grenadeTimer += Time.deltaTime;
                                }
                                else
                                {
                                    doThrow = true;
                                }
                            }
                        }

                        if (doThrow && _motor.PotentialGrenade != null)
                        {
                            if (_grenadeCheckTimer <= float.Epsilon)
                            {
                                GrenadeDescription desc;
                                desc.Gravity    = _motor.Grenade.Gravity;
                                desc.Duration   = _motor.PotentialGrenade.Timer;
                                desc.Bounciness = _motor.PotentialGrenade.Bounciness;

                                var length = GrenadePath.Calculate(GrenadePath.Origin(_motor, Util.AngleOfVector(_situation.ThreatGroundPosition - transform.position)),
                                                                   _situation.ThreatGroundPosition,
                                                                   _motor.Grenade.MaxVelocity,
                                                                   desc,
                                                                   _grenadePath,
                                                                   _motor.Grenade.Step);

                                if (Vector3.Distance(_grenadePath[length - 1], _situation.ThreatGroundPosition) > Grenades.MaxRadius ||
                                    Vector3.Distance(_grenadePath[length - 1], _situation.CurrentPosition) < Grenades.AvoidDistance)
                                {
                                    _grenadeCheckTimer = Grenades.CheckInterval;
                                }
                                else
                                {
                                    _motor.InputThrowGrenade(_grenadePath, length, _motor.Grenade.Step);
                                    _situation.ThrownGrenadeCount++;

                                    _grenadeTimer         = 0;
                                    _hasThrowFirstGrenade = true;
                                }
                            }
                            else
                            {
                                _grenadeCheckTimer -= Time.deltaTime;
                            }
                        }
                        else
                        {
                            _grenadeCheckTimer = 0;
                        }
                    }

                    // Position in world space that is best fit to aim at.
                    var perfectTarget = _situation.ThreatGroundPosition + (_situation.ThreatTopPosition - _situation.ThreatGroundPosition) * 0.7f;

                    if (_situation.IsThreatInCover)
                    {
                        var dot = Vector3.Dot(_situation.ThreatCoverForward, (_situation.ThreatGroundPosition - transform.position).normalized);

                        if (dot < -0.1f)
                        {
                            perfectTarget = _situation.ThreatStandingTopPosition;
                        }
                    }

                    // Make the AI look at the target.
                    {
                        var vector = perfectTarget - _motor.transform.position;
                        vector.y = 0;

                        if (vector.magnitude < 2)
                        {
                            _motor.SetLookTarget(perfectTarget + vector * 2);
                        }
                        else
                        {
                            _motor.SetLookTarget(perfectTarget);
                        }

                        _motor.SetBodyLookTarget(perfectTarget);
                    }

                    // Aim the gun at the inprecise target.
                    var targetRadius = Fighting.TargetRadius.Get(Vector3.Distance(_situation.ThreatGroundPosition, transform.position));
                    _motor.SetFireTarget(perfectTarget + new Vector3(UnityEngine.Random.Range(-1, 1) * targetRadius,
                                                                     UnityEngine.Random.Range(-1, 1) * targetRadius,
                                                                     UnityEngine.Random.Range(-1, 1) * targetRadius));

                    // We want AI too look at the corner when standing near it.
                    if (_motor.IsInTallCover)
                    {
                        if (_situation.TargetDirection < 0)
                        {
                            _motor.InputStandLeft();
                        }
                        else if (_situation.TargetDirection > 0)
                        {
                            _motor.InputStandRight();
                        }
                    }

                    // Fire
                    {
                        var isAllowedToFire = _situation.IsAllowedToBeAggressive;

                        if (Behaviour.OnlyFireWhenSeen || !_situation.IsAllowedToBeAggressive)
                        {
                            var up   = Camera.main.WorldToViewportPoint(transform.position);
                            var down = Camera.main.WorldToViewportPoint(transform.position + Vector3.up * 2);

                            if ((up.x < 0 ||
                                 up.y < 0 ||
                                 up.x > 1 ||
                                 up.y > 1 ||
                                 up.z < 0) &&
                                (down.x < 0 ||
                                 down.y < 0 ||
                                 down.x > 1 ||
                                 down.y > 1 ||
                                 down.z < 0))
                            {
                                isAllowedToFire = false;
                            }
                            else
                            {
                                isAllowedToFire = true;
                            }
                        }

                        if (isAllowedToFire)
                        {
                            var burst  = Behaviour.IsFightingUsingCovers ? CoveredFightingBursts : CoveredApproachBursts;
                            var isDumb = _state == AIState.fireInCover &&
                                         (_stateTime <= burst.IntroDuration || _stateTime >= burst.IntroDuration + burst.Duration);

                            var isWalking = _state != AIState.takeCover && _state != AIState.approach && _state != AIState.retreat;

                            // Check if can fire right now.
                            if (Behaviour.CanFire &&
                                (!isWalking || _walkingBurstWait < WalkingBursts.Duration) &&
                                (!_situation.IsTargetCoverGood ||
                                 (_state != AIState.hideInCover &&
                                  (_state != AIState.takeCover || _motor.Cover == null))))
                            {
                                var aimPoint = transform.position;

                                if (_motor.IsInTallCover && _situation.IsTargetCoverGood)
                                {
                                    if (_situation.TargetDirection < 0)
                                    {
                                        aimPoint = _motor.Cover.LeftCorner(transform.position.y, _motor.CoverSettings.CornerOffset.x);
                                    }
                                    else
                                    {
                                        aimPoint = _motor.Cover.RightCorner(transform.position.y, _motor.CoverSettings.CornerOffset.x);
                                    }
                                }

                                // See if the motor can hit the standing enemy after potentially peeking.
                                if (AIUtil.IsInSight(this, aimPoint, _situation.ThreatStandingTopPosition))
                                {
                                    if (_state == AIState.fireInCover)
                                    {
                                        _motor.InputAim();
                                    }

                                    if (!isDumb)
                                    {
                                        _motor.InputFire();
                                    }
                                }
                            }
                        }

                        _lookPointTimer = 0;
                    }
                }
                else
                {
                    _motor.SetFireTarget(_situation.ThreatGroundPosition);
                    _motor.SetLookTarget(_situation.ThreatGroundPosition);
                    _motor.SetBodyLookTarget(_situation.ThreatGroundPosition);
                    lookAround(_situation.ThreatGroundPosition - _motor.transform.position);
                }
            }
            else
            {
                _motor.InputWeapon(0);

                if (_state == AIState.patrol || _state == AIState.patrolPause)
                {
                    Vector3 forward;

                    if (Waypoints.Length > 1)
                    {
                        var next = Waypoints[_situation.PatrolPoint];

                        forward = next.Position - transform.position;

                        if (forward.magnitude < 0.5f)
                        {
                            var previous = _situation.PatrolPoint == 0 ? Waypoints[Waypoints.Length - 1] : Waypoints[_situation.PatrolPoint - 1];
                            var line     = next.Position - previous.Position;

                            if (Vector2.Dot(line, forward) > 0)
                            {
                                forward = line;
                            }
                        }
                    }
                    else
                    {
                        forward = transform.forward;
                    }

                    lookAround(forward);
                }
                else
                {
                    _lookPointTimer = 0;
                }
            }

            var positionToMoveTo = transform.position;

            ///
            /// STATE MANAGEMENT
            ///
            {
                var updateSituationInDetail = false;

                {
                    // Update the update delay timer.
                    _updateTimer -= Time.deltaTime;

                    if (_updateTimer < 0)
                    {
                        _updateTimer            = Fighting.ReactionTime;
                        updateSituationInDetail = true;
                    }
                }

                // Update standing burst timer.
                {
                    _walkingBurstWait += Time.deltaTime;

                    if (_walkingBurstWait > WalkingBursts.Duration + WalkingBursts.Wait)
                    {
                        _walkingBurstWait = 0;
                    }
                }

                {
                    _situation.Update(this, _previousSituation, updateSituationInDetail);

                    if (!isStateStillValid(_state, _stateTime, _situation, _situation))
                    {
                        updateSituation(calcState(_situation, _state, _stateTime));
                    }
                }
            }

            ///
            /// WALK
            ///
            if (!_motor.IsInCornerAimState)
            {
                if (_state == AIState.takeCover ||
                    _state == AIState.approach ||
                    _state == AIState.investigate ||
                    _state == AIState.retreat ||
                    _state == AIState.patrol ||
                    _state == AIState.avoidGrenade)
                {
                    var toTarget = _situation.TargetPosition - transform.position;

                    // If patrolling, set the body to rotate towards the target.
                    if (_state == AIState.patrol)
                    {
                        if (toTarget.magnitude > 0.1f)
                        {
                            var normalized = toTarget.normalized;
                            var position   = transform.position + normalized * 4;
                            var dot        = Vector3.Dot(toTarget.normalized, _motor.transform.forward);

                            if (Waypoints[_situation.PatrolPoint].Run)
                            {
                                _motor.SetBodyLookTarget(position, 8);
                            }
                            else
                            {
                                if (dot > 0)
                                {
                                    _motor.SetBodyLookTarget(position, 1.6f);
                                }
                                else if (dot > -0.5f)
                                {
                                    _motor.SetBodyLookTarget(position, 2.5f);
                                }
                                else
                                {
                                    _motor.SetBodyLookTarget(position, 4f);
                                }
                            }
                        }
                    }

                    // Move the last meter without using the agent.
                    if (toTarget.magnitude > 1.0f)
                    {
                        var vectorToAgent   = _agent.nextPosition - transform.position;
                        var distanceToAgent = vectorToAgent.magnitude;

                        if (distanceToAgent > float.Epsilon)
                        {
                            vectorToAgent /= distanceToAgent;
                        }

                        // If agent moved too far, reset it.
                        if (distanceToAgent > 1f)
                        {
                            updateAgent(_situation.TargetPosition);
                        }

                        float walkSpeed;

                        if (_state == AIState.patrol && !Patrol.IsAlwaysRunning && (Waypoints.Length == 0 || !Waypoints[_situation.PatrolPoint].Run))
                        {
                            walkSpeed = 0.5f;
                        }
                        else
                        {
                            walkSpeed = 1.0f;
                        }

                        var point = _currentPathIndex + 1 < _pathLength ? _path[_currentPathIndex + 1] : _situation.TargetPosition;

                        var vectorToPoint   = point - transform.position;
                        var distanceToPoint = vectorToPoint.magnitude;

                        if (distanceToPoint > float.Epsilon)
                        {
                            vectorToPoint /= distanceToPoint;
                        }

                        if (distanceToPoint < 0.1f && _currentPathIndex + 1 < _pathLength)
                        {
                            _currentPathIndex++;
                        }

                        _agent.speed = 0.1f;
                        _motor.InputMovement(new CharacterMovement(vectorToPoint, walkSpeed));
                    }
                    else
                    {
                        if (_state == AIState.takeCover)
                        {
                            _motor.InputImmediateCoverSearch();
                            _motor.InputTakeCover();
                        }

                        if (toTarget.magnitude > 0.05f)
                        {
                            _motor.InputMovement(new CharacterMovement(toTarget.normalized, 0.5f));
                        }
                        else
                        {
                            _motor.transform.position = _situation.TargetPosition;
                        }
                    }
                }
            }
        }