public override bool Tick(Actor self)
        {
            // We are not currently attacking a target, so scan for new targets.
            if (!IsCanceling && ChildActivity != null && ChildActivity.NextActivity == null && autoTarget != null)
            {
                // ScanForTarget already limits the scanning rate for performance so we don't need to do that here.
                var target = autoTarget.ScanForTarget(self, false, true);
                if (target.Type != TargetType.Invalid)
                {
                    // We have found a target so cancel the current move activity and queue attack activities.
                    ChildActivity.Cancel(self);
                    var attackBases = autoTarget.ActiveAttackBases;
                    foreach (var ab in attackBases)
                    {
                        QueueChild(ab.GetAttackActivity(self, AttackSource.AttackMove, target, false, false));
                    }

                    // Make sure to continue moving when the attack activities have finished.
                    QueueChild(getInner());
                }
            }

            // The last queued childactivity is guaranteed to be the inner move, so if the childactivity
            // queue is empty it means we have reached our destination and there are no more enemies on our path.
            return(TickChild(self));
        }
Beispiel #2
0
        public override bool Cancel(Actor self, bool keepQueue)
        {
            if (ChildActivity == null)
            {
                return(base.Cancel(self, keepQueue));
            }

            //Although MoveFirstHalf and MoveSecondHalf can't be interrupted,
            //We prevent them from moving forever by removing the path.
            //通过消除路径来阻止他们永远移动
            if (path != null)
            {
                path.Clear();
            }


            //Remove queued activities
            if (!keepQueue && NextInQueue != null)
            {
                NextInQueue = null;
            }

            //In current implementation,ChildActivity can be Turn,MoveFirstHalf and MoveSecondHalf.
            //Turn may be interrupted freely while they are turning.                                //转弯时可能会自由中断
            //Unlike Turn,MoveFirstHalf and MoveSecondHalf are not Interruptable,but clearing the path guarantees that they will return as soon as possible,once the actor is back in a valid position.
            //与Turn 不同,MoveFirstHalf 和 MoveSecondHalf 是不可被中断的,但清除路径可以保证一旦单位回到有效的位置,他们将尽快返回
            //This means that it is safe to unconditionally return true,which avoids breaking parent activities that rely on cancellation succeeding (but not necessarily immediately)
            //这意味着无条件返回true 是安全的,避免了依靠取消成功(但不一定立即)
            ChildActivity.Cancel(self);

            return(true);
        }
Beispiel #3
0
        public override bool Cancel(Actor self, bool keepQueue = false)
        {
            if (ChildActivity == null)
            {
                return(base.Cancel(self, keepQueue));
            }

            // Although MoveFirstHalf and MoveSecondHalf can't be interrupted,
            // we prevent them from moving forever by removing the path.
            if (path != null)
            {
                path.Clear();
            }

            // Remove queued activities
            if (!keepQueue && NextInQueue != null)
            {
                NextInQueue = null;
            }

            // In current implementation, ChildActivity can be Turn, MoveFirstHalf and MoveSecondHalf.
            // Turn may be interrupted freely while they are turning.
            // Unlike Turn, MoveFirstHalf and MoveSecondHalf are not Interruptable, but clearing the
            // path guarantees that they will return as soon as possible, once the actor is back in a
            // valid position.
            // This means that it is safe to unconditionally return true, which avoids breaking parent
            // activities that rely on cancellation succeeding (but not necessarily immediately
            ChildActivity.Cancel(self, false);

            return(true);
        }
Beispiel #4
0
 private void CheckIfReachedBestLocation(Actor self, out MiningState state)
 {
     if ((self.Location - deployDestPosition).LengthSquared <= cellRange * cellRange)
     {
         ChildActivity.Cancel(self);
         state = MiningState.TryDeploy;
     }
     else
     {
         state = MiningState.Moving;
     }
 }
Beispiel #5
0
        public override void Cancel(Actor self, bool keepQueue = false)
        {
            if (!shouldCancel)
            {
                shouldCancel = true;

                if (ChildActivity is Move || ChildActivity is Turn)
                {
                    ChildActivity.Cancel(self);
                }
                else if (ChildActivity is Drag && isDocking)
                {
                    QueueChild(new Drag(dockableActor, dockTarget, dockableActor.World.Map.CenterOfCell(dockEntry), distance / speed));
                }
            }
        }
Beispiel #6
0
        public virtual void Cancel(Actor self, bool keepQueue = false)
        {
            if (!keepQueue)
            {
                NextActivity = null;
            }

            if (!IsInterruptible)
            {
                return;
            }

            ChildActivity?.Cancel(self);

            // Directly mark activities that are queued and therefore didn't run yet as done
            State = State == ActivityState.Queued ? ActivityState.Done : ActivityState.Canceling;
        }
Beispiel #7
0
        public virtual bool Cancel(Actor self)
        {
            if (!IsInterruptible)
            {
                return(false);
            }

            if (ChildActivity != null && !ChildActivity.Cancel(self))
            {
                return(false);
            }

            State         = ActivityState.Canceled;
            NextActivity  = null;
            ChildActivity = null;

            return(true);
        }
Beispiel #8
0
        public virtual void Cancel(Actor self, bool keepQueue = false)
        {
            if (!keepQueue)
            {
                NextActivity = null;
            }

            if (!IsInterruptible)
            {
                return;
            }

            if (ChildActivity != null)
            {
                ChildActivity.Cancel(self);
            }

            State = ActivityState.Canceling;
        }
Beispiel #9
0
        public override bool Tick(Actor self)
        {
            // Refuse to take off if it would land immediately again.
            if (aircraft.ForceLanding)
            {
                Cancel(self);
            }

            if (IsCanceling)
            {
                return(true);
            }

            if (!self.World.Map.Contains(self.Location) && --endingDelay < 0)
            {
                ChildActivity.Cancel(self);
            }

            return(TickChild(self));
        }
Beispiel #10
0
        /// <summary>
        /// 活动取消
        /// </summary>
        /// <param name="self"></param>
        /// <param name="keepQueue">标识是否保持队列顺序</param>
        /// <returns></returns>
        public virtual bool Cancel(Actor self, bool keepQueue = false)
        {
            if (!IsInterruptible)
            {
                return(false);
            }

            if (ChildActivity != null && !ChildActivity.Cancel(self))
            {
                return(false);
            }

            if (!keepQueue)
            {
                NextActivity = null;
            }

            ChildActivity = null;
            State         = ActivityState.Canceled;
            return(true);
        }
Beispiel #11
0
        public override bool Tick(Actor self)
        {
            bool targetIsHiddenActor;
            var  oldTargetLocation = lastVisibleTargetLocation;

            target = target.Recalculate(self.Owner, out targetIsHiddenActor);
            if (!targetIsHiddenActor && target.Type == TargetType.Actor)
            {
                lastVisibleTarget         = Target.FromTargetPositions(target);
                lastVisibleTargetLocation = self.World.Map.CellContaining(target.CenterPosition);
            }

            // Target is equivalent to checkTarget variable in other activities
            // value is either lastVisibleTarget or target based on visibility and validity
            var targetIsValid = Target.IsValidFor(self);

            useLastVisibleTarget = targetIsHiddenActor || !targetIsValid;

            // Target is hidden or dead, and we don't have a fallback position to move towards
            var noTarget = useLastVisibleTarget && !lastVisibleTarget.IsValidFor(self);

            // Cancel the current path if the activity asks to stop, or asks to repath
            // The repath happens once the move activity stops in the next cell
            var shouldRepath = targetIsValid && ShouldRepath(self, oldTargetLocation);

            if (ChildActivity != null && (ShouldStop(self) || shouldRepath || noTarget))
            {
                ChildActivity.Cancel(self);
            }

            // Target has moved, and MoveAdjacentTo is still valid.
            if (!IsCanceling && shouldRepath)
            {
                QueueChild(Mobile.MoveTo(check => CalculatePathToTarget(self, check)));
            }

            // The last queued childactivity is guaranteed to be the inner move, so if the childactivity
            // queue is empty it means we have reached our destination.
            return(TickChild(self));
        }
Beispiel #12
0
        public override bool Tick(Actor self)
        {
            if (IsCanceling)
            {
                return(TickChild(self));
            }

            // We are currently not attacking, so scan for new targets.
            if (autoTarget != null && (ChildActivity == null || runningMoveActivity))
            {
                // Use the standard ScanForTarget rate limit while we are running the move activity to save performance.
                // Override the rate limit if our attack activity has completed so we can immediately acquire a new target instead of moving.
                target = autoTarget.ScanForTarget(self, false, true, !runningMoveActivity);

                // Cancel the current move activity and queue attack activities if we find a new target.
                if (target.Type != TargetType.Invalid)
                {
                    runningMoveActivity = false;
                    ChildActivity?.Cancel(self);

                    foreach (var ab in autoTarget.ActiveAttackBases)
                    {
                        QueueChild(ab.GetAttackActivity(self, AttackSource.AttackMove, target, false, false));
                    }
                }

                // Continue with the move activity (or queue a new one) when there are no targets.
                if (ChildActivity == null)
                {
                    runningMoveActivity = true;
                    QueueChild(getMove());
                }
            }

            // If the move activity finished, we have reached our destination and there are no more enemies on our path.
            return(TickChild(self) && runningMoveActivity);
        }
        public override Activity Tick(Actor self)
        {
            bool targetIsHiddenActor;
            var  oldTargetLocation = lastVisibleTargetLocation;

            target = target.Recalculate(self.Owner, out targetIsHiddenActor);
            if (!targetIsHiddenActor && target.Type == TargetType.Actor)
            {
                lastVisibleTarget         = Target.FromTargetPositions(target);
                lastVisibleTargetLocation = self.World.Map.CellContaining(target.CenterPosition);
            }

            // Target is equivalent to checkTarget variable in other activities
            // value is either lastVisibleTarget or target based on visibility and validity
            var targetIsValid           = Target.IsValidFor(self);
            var oldUseLastVisibleTarget = useLastVisibleTarget;

            useLastVisibleTarget = targetIsHiddenActor || !targetIsValid;

            // Update target lines if required
            if (useLastVisibleTarget != oldUseLastVisibleTarget && targetLineColor.HasValue)
            {
                self.SetTargetLine(useLastVisibleTarget ? lastVisibleTarget : target, targetLineColor.Value, false);
            }

            // Target is hidden or dead, and we don't have a fallback position to move towards
            var noTarget = useLastVisibleTarget && !lastVisibleTarget.IsValidFor(self);

            // Inner move order has completed.
            if (ChildActivity == null)
            {
                // We are done here if the order was cancelled for any
                // reason except the target moving.
                if (IsCanceling || !repath || !targetIsValid)
                {
                    return(NextActivity);
                }

                // Target has moved, and MoveAdjacentTo is still valid.
                ChildActivity = Mobile.MoveTo(() => CalculatePathToTarget(self));
                repath        = false;
            }

            // Cancel the current path if the activity asks to stop, or asks to repath
            // The repath happens once the move activity stops in the next cell
            var shouldStop   = ShouldStop(self);
            var shouldRepath = targetIsValid && !repath && ShouldRepath(self, oldTargetLocation);

            if (shouldStop || shouldRepath || noTarget)
            {
                if (ChildActivity != null)
                {
                    ChildActivity.Cancel(self);
                }

                repath = shouldRepath;
            }

            // Ticks the inner move activity to actually move the actor.
            ChildActivity = ActivityUtils.RunActivityTick(self, ChildActivity);

            return(this);
        }
Beispiel #14
0
        public override bool Tick(Actor self)
        {
            if (cargo != carryall.Carryable)
            {
                return(true);
            }

            if (IsCanceling)
            {
                if (carryall.State == Carryall.CarryallState.Reserved)
                {
                    carryall.UnreserveCarryable(self);
                }

                return(true);
            }

            if (cargo.IsDead || carryable.IsTraitDisabled || !cargo.AppearsFriendlyTo(self))
            {
                carryall.UnreserveCarryable(self);
                return(true);
            }

            // Wait until we are near the target before we try to lock it
            var distSq = (cargo.CenterPosition - self.CenterPosition).HorizontalLengthSquared;

            if (state == PickupState.Intercept && distSq <= targetLockRange.LengthSquared)
            {
                state = PickupState.LockCarryable;
            }

            if (state == PickupState.LockCarryable)
            {
                var lockResponse = carryable.LockForPickup(cargo, self);
                if (lockResponse == LockResponse.Failed)
                {
                    Cancel(self);
                }
                else if (lockResponse == LockResponse.Success)
                {
                    // Pickup position and facing are now known - swap the fly/wait activity with Land
                    ChildActivity.Cancel(self);

                    var localOffset = carryall.OffsetForCarryable(self, cargo).Rotate(carryableBody.QuantizeOrientation(self, cargo.Orientation));
                    QueueChild(new Land(self, Target.FromActor(cargo), -carryableBody.LocalToWorld(localOffset), carryableFacing.Facing));

                    // Pause briefly before attachment for visual effect
                    if (delay > 0)
                    {
                        QueueChild(new Wait(delay, false));
                    }

                    // Remove our carryable from world
                    QueueChild(new AttachUnit(self, cargo));
                    QueueChild(new TakeOff(self));

                    state = PickupState.Pickup;
                }
            }

            // Return once we are in the pickup state and the pickup activities have completed
            return(TickChild(self) && state == PickupState.Pickup);
        }
Beispiel #15
0
        public override bool Tick(Actor self)
        {
            if (!shouldCancel && (DockActor == null || DockActor.IsDead || !DockActor.IsInWorld || Dock.GetDockAction(DockableActor) == null))
            {
                shouldCancel = true;
            }

            if (ChildActivity != null)
            {
                if (shouldCancel)
                {
                    ChildActivity.Cancel(self);
                }

                if (ChildActivity != null)
                {
                    ChildActivity.Tick(self);
                }
            }

            switch (DockingState)
            {
            case DockingState.Approaching:
                if (shouldCancel)
                {
                    DockingState = DockingState.Undocked;
                    break;
                }

                // TODO does not null when target reached...?
                if (ChildActivity != null)
                {
                    break;
                }

                var distance = (DockableActor.CenterPosition - DockActor.CenterPosition).Length;

                if (distance > WDist.FromCells(Dock.Info.QueueDistance).Length)
                {
                    QueueChild(new Move(DockableActor, Target.FromActor(DockActor), WDist.FromCells(Dock.Info.QueueDistance)));
                }
                else
                {
                    DockingState = DockingState.Waiting;
                    Dock.Add(DockableActor);
                }

                break;

            case DockingState.Waiting:
                if (shouldCancel)
                {
                    DockingState = DockingState.Undocked;
                    Dock.Remove(DockableActor);
                }

                break;

            case DockingState.Docking:
                if (ChildActivity == null)
                {
                    if (shouldCancel)
                    {
                        DockingState = DockingState.Undocked;
                        Dock.Remove(DockableActor);
                    }
                    else
                    {
                        DockingState = DockingState.Docked;
                        Dock.OnDock();
                    }
                }

                break;

            case DockingState.Docked:
                if (shouldCancel)
                {
                    StartUndocking();
                }

                break;

            case DockingState.Undocking:
                if (ChildActivity == null)
                {
                    DockingState = DockingState.Undocked;
                    Dock.Remove(DockableActor);

                    if (!DockActor.IsDead && DockActor.IsInWorld)
                    {
                        var rallyPoint = DockActor.TraitOrDefault <RallyPoint>();
                        if (rallyPoint != null && rallyPoint.Path.Any())
                        {
                            DockableActor.QueueActivity(new Move(DockableActor, rallyPoint.Path.First()));
                        }
                    }
                }

                break;

            case DockingState.Undocked:
                break;
            }

            return(DockingState == DockingState.Undocked && ChildActivity == null);
        }