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