/// <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()
        {
            var count = AIUtil.FindActorsIncludingDead(_targetPosition, Radius);

            for (int i = 0; i < count; i++)
            {
                PlayEffect(AIUtil.Actors[i], AIUtil.Actors[i].transform.position);
                Perform(AIUtil.Actors[i]);
            }

            return(true);
        }
Beispiel #2
0
        private void Update()
        {
            if (!_actor.IsAlive)
            {
                return;
            }

            _wait -= Time.deltaTime;

            if (_wait > float.Epsilon)
            {
                _oldVisible.Clear();
                _oldVisibleHash.Clear();

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

                    if (actor != null)
                    {
                        _oldVisible.Add(actor);
                        _oldVisibleHash.Add(actor);
                    }
                }

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

                    if (!actor.IsAlive)
                    {
                        _visible.Remove(actor);
                        _visibleHash.Remove(actor);

                        if (!_seenDeadHash.Contains(actor))
                        {
                            _seenDeadHash.Add(actor);
                            Message("OnSeeDeath", actor);
                        }
                    }
                }

                return;
            }

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

            _oldVisible.Clear();
            _oldVisibleHash.Clear();

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

                if (actor != null)
                {
                    _oldVisible.Add(actor);
                    _oldVisibleHash.Add(actor);
                }
            }

            _visible.Clear();
            _visibleHash.Clear();

            var count = AIUtil.FindActorsIncludingDead(_actor.TopPosition, Distance, _actor);

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

                if (CheckVisibility(actor))
                {
                    if (actor.IsAlive)
                    {
                        _visible.Add(actor);
                        _visibleHash.Add(actor);
                    }
                    else
                    {
                        if (!_seenDeadHash.Contains(actor))
                        {
                            _seenDeadHash.Add(actor);
                            Message("OnSeeDeath", actor);
                        }
                        // A hack, should fix in some other way
                        else if (_brain != null && _brain.Threat == actor)
                        {
                            _brain.OnSeeDeath(actor);
                        }
                    }
                }
            }

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

                if (!_visibleHash.Contains(actor))
                {
                    Message("OnUnseeActor", actor);
                }
            }

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

                if (!_oldVisibleHash.Contains(actor))
                {
                    Message("OnSeeActor", actor);
                }
            }
        }
Beispiel #3
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;
                }
            }
        }