/// <summary> /// Executes the specified command and adds it to the command history.</summary> /// <param name="worldState"> /// The <see cref="WorldState"/> on which the specified <paramref name="command"/> is /// executed.</param> /// <param name="command"> /// The <see cref="Command"/> to execute.</param> /// <param name="queued"> /// <c>true</c> if <paramref name="command"/> was enqueued by the <see /// cref="CommandExecutor.QueueCommand"/> method; <c>false</c> if <paramref name="command"/> /// was directly supplied to the <see cref="ProcessCommand"/> method.</param> /// <exception cref="ArgumentException"> /// <paramref name="worldState"/> does not equal the <see cref="Session.WorldState"/> of the /// current <see cref="Session"/>.</exception> /// <exception cref="ArgumentNullException"> /// <paramref name="worldState"/> or <paramref name="command"/> is a null reference. /// </exception> /// <exception cref="InvalidCommandException"> /// The specified <paramref name="command"/> contains data that is invalid with respect to /// the specified <paramref name="worldState"/>.</exception> /// <remarks><para> /// <b>ExecuteCommand</b> attempts to execute the specified <paramref name="command"/> by /// calling the base class implementation of <see cref="CommandExecutor.ExecuteCommand"/>. /// </para><para> /// On success, <b>ExecuteCommand</b> shows any events that were generated and sets the <see /// cref="Session.WorldChanged"/> flag of the current <see cref="Session"/>. /// </para><para> /// If <paramref name="queued"/> is <c>true</c>, <b>ExecuteCommand</b> inserts additional /// delays before and during command execution, and scrolls the default <see /// cref="Session.MapView"/> to bring the affected sites into view. These additional actions /// are skipped if the <see cref="AbortSignal"/> is set, however.</para></remarks> protected override void ExecuteCommand( WorldState worldState, Command command, bool queued) { if (worldState == null) { ThrowHelper.ThrowArgumentNullException("worldState"); } if (command == null) { ThrowHelper.ThrowArgumentNullException("command"); } if (worldState != Session.Instance.WorldState) { ThrowHelper.ThrowArgumentExceptionWithFormat("worldState", Tektosyne.Strings.ArgumentNotEquals, "Session.Instance.WorldState"); } // get current delay for interactive replay int delay = ApplicationOptions.Instance.Game.Replay.Delay; // add delay between queued commands if (queued) { AbortSignal.WaitOne(2 * delay, false); } // validate & show command command.Validate(worldState); ShowCommand(command); PointI source = command.Source.Location; PointI target = command.Target.Location; MapView mapView = Session.MapView; if (queued && !AbortSignal.WaitOne(0, false)) { bool sourceValid = Finder.MapGrid.Contains(source); AsyncAction.Invoke(delegate { // scroll command sites into view mapView.ScrollIntoView(source, target); // highlight source site if valid if (sourceValid) { mapView.SelectedSite = source; // select first entity if specified EntityReference[] entities = command.Entities; if (entities != null && entities.Length > 0) { MainWindow.Instance.SelectedEntity = entities[0].Id; } } }); // show valid source site for a while if (sourceValid) { AbortSignal.WaitOne(delay, false); } } // execute command and add to history command.Execute(new ExecutionContext(worldState, QueueCommand, ShowCommandEvent)); worldState.History.AddCommand(command, worldState.CurrentTurn); AsyncAction.Invoke(delegate { // move to target if valid, else update source if (Finder.MapGrid.Contains(target)) { mapView.SelectedSite = target; } else { MainWindow.Instance.UpdateSelection(); } // ensure command effects are shown mapView.Redraw(); }); // world state has changed Session.Instance.SetWorldChanged(); }