public void Callback(object custom) { var now = SystemClock.Now; locker.Lock(c => assignmentTroops.Select(troop => troop.Stub).ToArray <ILockable>(), new object[] {}, Tribe) .Do(() => { lock (assignmentLock) { // Possible for reschedule to be called before we grab the assignmentLock if (IsScheduled) { scheduler.Remove(this); } var troopToDispatch = assignmentTroops.FirstOrDefault(x => !x.Dispatched && x.DepartureTime <= now); if (troopToDispatch != null) { // Make sure troop time is still valid. If not we need to put it back on the scheduler. // The time may change if the user has finished upgrading a tech/unit that improves speed since adding // it to the assignment. var departureTime = DepartureTime(troopToDispatch.Stub); if (departureTime > now) { troopToDispatch.DepartureTime = departureTime; } // If a troop dispatches, then we set the troop to dispatched. else if (Dispatch(troopToDispatch.Stub)) { troopToDispatch.Dispatched = true; } // Otherwise, if dispatch fails, then we remove it. else { RemoveStubWithoutRescheduling(troopToDispatch.Stub); } } // Take the quickest stub or the final target time. Time = assignmentTroops.Any(s => !s.Dispatched) ? assignmentTroops.Where(s => !s.Dispatched).Min(x => x.DepartureTime) : TargetTime; // If there are stubs that have not been dispatched or we haven't reached the time that the assignment should be over then we just reschedule it. if (assignmentTroops.Any(x => !x.Dispatched) || TargetTime.CompareTo(SystemClock.Now) > 0) { scheduler.Put(this); dbManager.Save(this); } else { // Remove all stubs from the assignment before removing it completely var stubs = assignmentTroops.Select(x => x.Stub).ToList(); foreach (var stub in stubs) { RemoveStubWithoutRescheduling(stub); } AssignmentComplete(this); // Delete the assignment if (DbPersisted) { dbManager.Delete(this); } } } }); }
/// <summary> /// Calculates the departure time for a given troop stub /// </summary> /// <param name="stub"></param> /// <returns></returns> private DateTime DepartureTime(ITroopStub stub) { int distance = tileLocator.TileDistance(stub.City.PrimaryPosition, 1, new Position(X, Y), 1); return(TargetTime.Subtract(TimeSpan.FromSeconds(formula.MoveTimeTotal(stub, distance, IsAttack)))); }