Пример #1
0
        public void Regroup()
        {
            _friends.Clear();
            _takenPositions.Clear();

            var count = Physics.OverlapSphereNonAlloc(_actor.transform.position, CallDistance, _colliders, 0x1, QueryTriggerInteraction.Ignore);
            var limit = Limit;

            for (int i = 0; i < count; i++)
            {
                var friend = Actors.Get(_colliders[i].gameObject);

                if (friend != null && friend != _actor && friend.IsAlive && friend.Side == _actor.Side)
                {
                    var distance = Vector3.Distance(_actor.transform.position, friend.transform.position);

                    if (distance < CallDistance)
                    {
                        if (limit <= 0)
                        {
                            break;
                        }
                        else
                        {
                            limit--;
                        }

                        friend.SendMessage("ToLeaveCover");
                        _friends.Add(friend);
                    }
                }
            }

            foreach (var friend in _friends)
            {
                friend.SendMessage("ToRegroupAround", this);
            }
        }
Пример #2
0
        /// <summary>
        /// Catches the animator event during the execution and may perform the action. Returns true if that is the case.
        /// </summary>
        public override bool OnFinishAction()
        {
            for (int i = 0; i < Actors.Count; i++)
            {
                var actor = Actors.Get(i);

                var isAlly = actor.Side == _actor.Side;
                var isSelf = actor == _actor;

                if (isSelf && !CanTargetSelf)
                {
                    continue;
                }

                if (actor.isActiveAndEnabled && ((CanTargetAlly && isAlly) || (CanTargetEnemy && !isAlly) || (CanTargetSelf && isSelf)))
                {
                    PlayEffect(actor, actor.transform.position);
                    Perform(actor);
                }
            }

            return(true);
        }
Пример #3
0
        private void Update()
        {
            if (!_actor.IsAlive)
            {
                return;
            }

            _wait -= Time.deltaTime;

            if (DebugFriends)
            {
                foreach (var friend in _friends)
                {
                    if (friend != null)
                    {
                        Debug.DrawLine(friend.transform.position, transform.position, Color.yellow);
                    }
                }
            }

            if (_wait > float.Epsilon)
            {
                return;
            }

            _wait = Random.Range(UpdateDelay * 0.8f, UpdateDelay * 1.2f);

            _oldFriends.Clear();

            foreach (var friend in _friends)
            {
                if (friend != null)
                {
                    _oldFriends.Add(friend);
                }
            }

            _friends.Clear();

            foreach (var friend in _oldFriends)
            {
                var distance = Vector3.Distance(_actor.transform.position, friend.transform.position);

                if (distance < Distance && friend.IsAlive)
                {
                    _friends.Add(friend);
                }
                else
                {
                    Message("OnLostFriend", friend);

                    var comm = get(friend);

                    if (comm != null)
                    {
                        if (comm._friends.Contains(_actor))
                        {
                            comm._friends.Remove(_actor);
                            comm.Message("OnLostFriend", _actor);
                        }
                    }
                }
            }

            var count = Physics.OverlapSphereNonAlloc(_actor.transform.position, Distance, Util.Colliders, Layers.Character, QueryTriggerInteraction.Ignore);

            for (int i = 0; i < count; i++)
            {
                var friend = Actors.Get(Util.Colliders[i].gameObject);

                if (friend != null && friend != _actor && friend.IsAlive && friend.Side == _actor.Side && !_oldFriends.Contains(friend))
                {
                    var distance = Vector3.Distance(_actor.transform.position, friend.transform.position);

                    if (distance < Distance)
                    {
                        var comm = get(friend);

                        if (comm != null)
                        {
                            Message("OnFoundFriend", friend);
                            _friends.Add(friend);

                            comm._stayFriends.Add(_actor);

                            if (!comm._friends.Contains(_actor))
                            {
                                comm._friends.Add(_actor);
                                comm.Message("OnFoundFriend", _actor);
                            }
                        }
                    }
                }
            }

            _stayFriends.Clear();
        }
Пример #4
0
 private void OnDestroy()
 {
     Actors.Unregister(this);
 }
Пример #5
0
 private void OnDisable()
 {
     Actors.Unregister(this);
 }
Пример #6
0
 private void OnEnable()
 {
     Actors.Register(this);
 }
Пример #7
0
 /// <summary>
 /// Notified by components that the actor is no longer alive.
 /// </summary>
 public void OnDead()
 {
     _isAlive = false;
     Actors.Unregister(this);
 }
Пример #8
0
        private void Update()
        {
            if (_autoWait > float.Epsilon)
            {
                _autoWait -= Time.deltaTime;
            }
            if (_checkWait > float.Epsilon)
            {
                _checkWait -= Time.deltaTime;
            }
            if (_coverTimer > float.Epsilon)
            {
                _coverTimer -= Time.deltaTime;
            }

            if (_active != null && (!_active.Update() || (!_active.HasNoTimeout && (Time.timeSinceLevelLoad - _actionStart) > Timeout)))
            {
                end();
            }

            if (_actor.Cover == null)
            {
                _isInCover  = false;
                _coverTimer = 0;
            }
            else if (!_isInCover)
            {
                _coverTimer = CoverDelay;
                _isInCover  = true;
            }

            if (_active == null &&
                _autoWait <= float.Epsilon &&
                _checkWait <= float.Epsilon &&
                _brain.enabled &&
                _brain.State != FighterState.process &&
                _actor.IsAlive &&
                _coverTimer <= float.Epsilon &&
                (!WaitForCoverActions || !_isTakingCover))
            {
                _checkWait = 0.5f;
                _nearbyActors.Clear();

                {
                    var count = AIUtil.FindActorsIncludingDead(transform.position, AutoDistance);
                    for (int i = 0; i < count; i++)
                    {
                        _nearbyActors.Add(AIUtil.Actors[i]);
                    }
                }

                var canUseAttackAction = !AutoAttackOnlyFromCover || _actor.Cover != null;

                AIAction bestSingleAction       = null;
                Actor    bestSingleActionTarget = null;

                ///////////////////////////////////////////////////////
                //
                // CONSIDER MULTIPLE TARGET ACTIONS
                //
                ///////////////////////////////////////////////////////

                AIAction bestMultipleAction            = null;
                int      bestMultipleActionTargetCount = 0;

                for (int i = 0; i < Actions.Length; i++)
                {
                    var action = Actions[i];
                    if (action.Wait > float.Epsilon || !action.Auto || action.NeedsSingleTargetActor || action.NeedsTargetLocation || action.NeedsOnlySelf)
                    {
                        continue;
                    }

                    int count = 0;

                    for (int j = 0; j < Actors.Count; j++)
                    {
                        var actor = Actors.Get(j);

                        if (!actor.IsAlive && action.ShouldIgnoreDead)
                        {
                            continue;
                        }

                        if (actor.Side == _actor.Side)
                        {
                            if (((actor == _actor && action.CanTargetSelf) || action.CanTargetAlly) && action.IsNeededFor(actor))
                            {
                                count++;
                            }
                        }
                        else if (canUseAttackAction && action.CanTargetEnemy && action.IsNeededFor(actor) && (!AutoAttackOnlyFromCover || !action.WillMoveForActor(actor)))
                        {
                            count++;
                        }
                    }

                    if (count > bestMultipleActionTargetCount)
                    {
                        bestMultipleAction            = action;
                        bestMultipleActionTargetCount = count;
                    }
                }

                if (bestMultipleAction != null)
                {
                    _autoWait = AutoCooldown;
                    Execute(bestMultipleAction);
                    return;
                }

                ///////////////////////////////////////////////////////
                //
                // CONSIDER SELF ACTIONS
                //
                ///////////////////////////////////////////////////////

                for (int i = 0; i < Actions.Length; i++)
                {
                    var action = Actions[i];
                    if (action.Wait > float.Epsilon || !action.Auto || !action.NeedsOnlySelf)
                    {
                        continue;
                    }

                    if (action.CanTargetSelf && action.IsNeededFor(_actor))
                    {
                        if (_actor == Priority)
                        {
                            _autoWait = AutoCooldown;
                            Execute(action, _actor);
                            return;
                        }

                        bestSingleAction       = action;
                        bestSingleActionTarget = _actor;
                        break;
                    }
                }

                ///////////////////////////////////////////////////////
                //
                // CONSIDER SINGLE TARGET ACTIONS
                //
                ///////////////////////////////////////////////////////

                for (int i = 0; i < Actions.Length; i++)
                {
                    var action = Actions[i];
                    if (action.Wait > float.Epsilon || !action.Auto || !action.NeedsSingleTargetActor)
                    {
                        continue;
                    }

                    Actor best         = null;
                    var   bestDistance = 0f;
                    var   isBestSelf   = false;

                    for (int j = 0; j < _nearbyActors.Count; j++)
                    {
                        var actor = _nearbyActors[j];

                        if (!actor.IsAlive && action.ShouldIgnoreDead)
                        {
                            continue;
                        }

                        if (actor == _actor)
                        {
                            if (action.CanTargetSelf && action.IsNeededFor(actor))
                            {
                                if (actor == Priority)
                                {
                                    _autoWait = AutoCooldown;
                                    Execute(action, actor);
                                    return;
                                }

                                if (best == null)
                                {
                                    best         = actor;
                                    bestDistance = 0;
                                    isBestSelf   = true;
                                }
                            }
                        }
                        else if (actor.Side == _actor.Side)
                        {
                            if (action.CanTargetAlly && action.IsNeededFor(actor))
                            {
                                if (actor == Priority)
                                {
                                    _autoWait = AutoCooldown;
                                    Execute(action, actor);
                                    return;
                                }

                                var distance = Vector3.Distance(transform.position, actor.transform.position);

                                if (best == null || isBestSelf || distance < bestDistance)
                                {
                                    best         = actor;
                                    bestDistance = distance;
                                    isBestSelf   = false;
                                }
                            }
                        }
                        else if (canUseAttackAction && action.CanTargetEnemy && action.IsNeededFor(actor) && (!AutoAttackOnlyFromCover || !action.WillMoveForActor(actor)))
                        {
                            if (actor == Priority)
                            {
                                _autoWait = AutoCooldown;
                                Execute(action, actor);
                                return;
                            }

                            var distance = Vector3.Distance(transform.position, actor.transform.position);

                            if (best == null || isBestSelf || distance < bestDistance)
                            {
                                best         = actor;
                                bestDistance = distance;
                                isBestSelf   = false;
                            }
                        }
                    }

                    if (best != null)
                    {
                        bestSingleAction       = action;
                        bestSingleActionTarget = best;
                        break;
                    }
                }

                ///////////////////////////////////////////////////////
                //
                // CONSIDER AREA ACTIONS
                //
                ///////////////////////////////////////////////////////

                for (int i = 0; i < Actions.Length; i++)
                {
                    var action = Actions[i];
                    if (action.Wait > float.Epsilon || !action.Auto || !action.NeedsTargetLocation)
                    {
                        continue;
                    }

                    _possibleActionTargets.Clear();

                    for (int j = 0; j < _nearbyActors.Count; j++)
                    {
                        var actor = _nearbyActors[j];

                        if (!actor.IsAlive && action.ShouldIgnoreDead)
                        {
                            continue;
                        }

                        if (actor == _actor)
                        {
                            if (action.CanTargetSelf && action.IsNeededFor(actor))
                            {
                                _possibleActionTargets.Add(actor);
                            }
                        }
                        else if (actor.Side == _actor.Side)
                        {
                            if (action.CanTargetAlly && action.IsNeededFor(actor))
                            {
                                _possibleActionTargets.Add(actor);
                            }
                        }
                        else if (canUseAttackAction && action.CanTargetEnemy && action.IsNeededFor(actor))
                        {
                            _possibleActionTargets.Add(actor);
                        }
                    }

                    if (_possibleActionTargets.Count == 0 || (_possibleActionTargets.Count == 1 && bestSingleAction != null))
                    {
                        continue;
                    }

                    if (action.UIRadius > float.Epsilon)
                    {
                        var radius = action.UIRadius;
                        var steps  = (int)(2 * AutoDistance / radius);

                        var hasBest         = false;
                        var bestPosition    = Vector3.zero;
                        var bestDistance    = 0f;
                        var bestActorCount  = 0;
                        var bestHasPriority = false;

                        for (int x = -steps / 2; x < steps / 2; x++)
                        {
                            for (int y = -steps / 2; y < steps / 2; y++)
                            {
                                var position = transform.position + new Vector3(x * action.UIRadius, 0, y * radius);
                                var distance = Vector3.Distance(position, transform.position);

                                if (distance > AutoDistance)
                                {
                                    continue;
                                }

                                if (AutoAttackOnlyFromCover && action.CanTargetEnemy && action.WillMoveForPosition(position))
                                {
                                    continue;
                                }

                                var actorCount  = 0;
                                var hasPriority = false;

                                for (int j = 0; j < _possibleActionTargets.Count; j++)
                                {
                                    var a = _possibleActionTargets[j];

                                    if (Vector3.Distance(position, a.transform.position) < radius)
                                    {
                                        actorCount++;

                                        if (a == Priority)
                                        {
                                            hasPriority = true;
                                        }
                                    }
                                }

                                if (actorCount > 0)
                                {
                                    var isBetter = false;

                                    if (!hasBest)
                                    {
                                        isBetter = true;
                                    }
                                    else if (hasPriority && !bestHasPriority)
                                    {
                                        isBetter = false;
                                    }
                                    else if (!bestHasPriority)
                                    {
                                        if (actorCount > bestActorCount)
                                        {
                                            isBetter = true;
                                        }
                                        else if (actorCount == bestActorCount)
                                        {
                                            isBetter = distance < bestDistance;
                                        }
                                    }

                                    if (isBetter)
                                    {
                                        hasBest         = true;
                                        bestPosition    = position;
                                        bestDistance    = distance;
                                        bestHasPriority = hasPriority;
                                        bestActorCount  = actorCount;
                                    }
                                }
                            }
                        }

                        if (hasBest &&
                            (bestSingleAction == null || bestActorCount > 1))
                        {
                            _autoWait = AutoCooldown;
                            Execute(action, bestPosition);
                            return;
                        }
                    }
                }

                ///////////////////////////////////////////////////////
                //
                // EXECUTE BEST SINGLE IF NO AREA POSSIBLE
                //
                ///////////////////////////////////////////////////////

                if (bestSingleAction != null)
                {
                    _autoWait = AutoCooldown;
                    Execute(bestSingleAction, bestSingleActionTarget);
                }

                ///////////////////////////////////////////////////////
                //
                // CONSIDER NON-TARGET ACTIONS
                //
                ///////////////////////////////////////////////////////

                for (int i = 0; i < Actions.Length; i++)
                {
                    var action = Actions[i];
                    if (action.Wait > float.Epsilon || !action.Auto || action.CanTargetAny || action.CanTargetGround || action.UIRadius > float.Epsilon || action.CanTargetMultiple || action.NeedsOnlySelf)
                    {
                        continue;
                    }

                    _autoWait = AutoCooldown;
                    Execute(action);
                    return;
                }
            }
        }
Пример #9
0
 /// <summary>
 /// Broadcasts an alert.
 /// </summary>
 public void OnHit(Hit hit)
 {
     Alerts.Broadcast(hit.Position, Range, true, Actors.Get(hit.Attacker), false);
 }
Пример #10
0
        private void Update()
        {
            if (!_actor.IsAlive || !_canCall)
            {
                return;
            }

            if (_firstTriggerWait < FirstCheckDelay)
            {
                _firstTriggerWait += Time.deltaTime;
                return;
            }

            if (_triggerSpacing >= float.Epsilon)
            {
                _triggerSpacing -= Time.deltaTime;
                return;
            }

            var count = _nearbyFriends.Count;

            foreach (var friend in _visibleFriends)
            {
                if (!_nearbyFriends.Contains(friend))
                {
                    count++;
                }
            }

            if (count <= FriendCount)
            {
                var levelCount = 0;

                for (int i = 0; i < Actors.Count; i++)
                {
                    var actor = Actors.Get(i);

                    if (actor.IsAlive && actor.Side == _actor.Side && actor.IsAggressive)
                    {
                        levelCount++;
                    }
                }

                if (levelCount < MaxLevelCount)
                {
                    if (_triggerWait >= CheckDuration)
                    {
                        if (!OnlyCallInCover || _motor.IsInCover)
                        {
                            _triggerWait      = 0;
                            _triggerSpacing   = CheckSpacing;
                            _isWaitingForCall = true;
                            Message("ToMakeCall");
                        }
                    }
                    else
                    {
                        _triggerWait += Time.deltaTime;
                    }
                }
                else
                {
                    _triggerWait = 0;
                }
            }
            else
            {
                _triggerWait = 0;
            }
        }
Пример #11
0
        private void Update()
        {
            if (!_actor.IsAlive)
            {
                return;
            }

            _wait -= Time.deltaTime;

            if (_wait > float.Epsilon)
            {
                return;
            }

            _wait = Random.Range(UpdateDelay * 0.8f, UpdateDelay * 1.2f);

            _oldVisible.Clear();

            foreach (var actor in _visible)
            {
                _oldVisible.Add(actor);
            }

            _visible.Clear();

            foreach (var actor in _oldVisible)
            {
                if (actor != null && actor.IsAlive && AIUtil.IsInSight(_actor, actor.TopPosition, actor.GetViewDistance(Distance, _isAlerted), FieldOfView))
                {
                    _visible.Add(actor);
                }
                else
                {
                    Message("OnUnseeActor", actor);

                    if (!actor.IsAlive)
                    {
                        _knownAlive.Remove(actor);
                        Message("OnSeeDeath", actor);
                    }
                }
            }

            var count = Physics.OverlapSphereNonAlloc(_actor.TopPosition, Distance, _colliders, 0x1, QueryTriggerInteraction.Ignore);

            for (int i = 0; i < count; i++)
            {
                var actor = Actors.Get(_colliders[i].gameObject);

                if (actor != null && actor != _actor && actor.IsAlive && !_oldVisible.Contains(actor))
                {
                    if (AIUtil.IsInSight(_actor, actor.TopPosition, actor.GetViewDistance(Distance, _isAlerted), FieldOfView))
                    {
                        _visible.Add(actor);
                        Message("OnSeeActor", actor);
                    }
                }
            }

            _oldKnownAlive.Clear();

            foreach (var known in _knownAlive)
            {
                _oldKnownAlive.Add(known);
            }

            _knownAlive.Clear();

            foreach (var actor in _oldKnownAlive)
            {
                if (_visible.Contains(actor))
                {
                    _knownAlive.Add(actor);
                }
                else if (AIUtil.IsInSight(_actor, actor.TopPosition, actor.GetViewDistance(Distance, _isAlerted), FieldOfView))
                {
                    Message("OnSeeDeath", actor);
                }
                else
                {
                    _knownAlive.Add(actor);
                }
            }
        }
Пример #12
0
        /// <summary>
        /// Finds an object and a hit position a bullet would hit if fired. Checks if it is a friend.
        /// </summary>
        public RaycastHit Raycast(Vector3 origin, Vector3 direction, out bool isFriend, bool friendCheck)
        {
            RaycastHit closestHit      = new RaycastHit();
            float      closestDistance = Distance * 10;

            var minDistance = 0f;

            if (_isUsingCustomRaycast)
            {
                minDistance = Vector3.Distance(Origin, RaycastOrigin);
            }

            if (minDistance > 0.5f)
            {
                minDistance -= 0.5f;
            }

            isFriend = false;
            var count = Physics.RaycastNonAlloc(origin, direction, _hits, Distance);

            for (int i = 0; i < count; i++)
            {
                var hit = _hits[i];

                if (Character != null && Util.InHiearchyOf(hit.collider.gameObject, Character.gameObject))
                {
                    continue;
                }

                if (hit.distance < closestDistance && hit.distance > minDistance)
                {
                    var isOk     = true;
                    var isShield = false;

                    if (hit.collider.isTrigger)
                    {
                        if (BodyPartHealth.Contains(hit.collider.gameObject))
                        {
                            isOk = true;
                        }
                        else
                        {
                            var shield = BulletShield.Get(hit.collider.gameObject);

                            if (shield != null)
                            {
                                if (Vector3.Dot(shield.transform.forward, hit.normal) >= -0.2f)
                                {
                                    isOk     = true;
                                    isShield = true;
                                }
                                else
                                {
                                    isOk = false;
                                }
                            }
                            else
                            {
                                isOk = false;
                            }
                        }
                    }
                    else
                    {
                        var health = CharacterHealth.Get(hit.collider.gameObject);

                        if (health != null)
                        {
                            isOk = health.IsRegisteringHits;
                        }
                    }

                    if (isOk)
                    {
                        if (!isShield && (_isIgnoringSelf || _hasFireCondition) && friendCheck)
                        {
                            var root = getHealthTarget(hit.collider.gameObject);

                            if (root != null)
                            {
                                if (_isIgnoringSelf && Character != null && root == Character.gameObject)
                                {
                                    isFriend = true;
                                }
                                else if (_hasFireCondition)
                                {
                                    var actor = Actors.Get(root);

                                    if (actor != null)
                                    {
                                        isFriend = actor.Side == _fireConditionSide;
                                    }
                                    else
                                    {
                                        isFriend = false;
                                    }
                                }
                                else
                                {
                                    isFriend = false;
                                }
                            }
                            else
                            {
                                isFriend = false;
                            }
                        }

                        closestHit      = hit;
                        closestDistance = hit.distance;
                    }
                }
            }

            return(closestHit);
        }