示例#1
0
        /// <overloads>
        /// Starts an interactive replay.</overloads>
        /// <summary>
        /// Replays all commands present in the specified <see cref="WorldState"/> but missing from
        /// the current <see cref="WorldState"/>.</summary>
        /// <param name="worldState">
        /// The <see cref="WorldState"/> containing the new commands to show in an interactive
        /// replay.</param>
        /// <param name="isComputer">
        /// The new value for the <see cref="IsComputerTurn"/> property while the replay is active.
        /// </param>
        /// <exception cref="ArgumentException">
        /// One of the conditions described in <see cref="History.AddCommands"/>.</exception>
        /// <exception cref="ArgumentNullException">
        /// <paramref name="worldState"/> is a null reference.</exception>
        /// <exception cref="PropertyValueException">
        /// The current session <see cref="Session.State"/> is neither <see
        /// cref="SessionState.Closed"/>, <see cref="SessionState.Computer"/>, nor <see
        /// cref="SessionState.Human"/>.</exception>
        /// <remarks><para>
        /// <b>Start</b> sets the session <see cref="Session.State"/> to <see
        /// cref="SessionState.Replay"/> and <see cref="CurrentState"/> to <see
        /// cref="ReplayState.Play"/>, and begins an interactive replay of all history commands
        /// stored in the specified <paramref name="worldState"/> that are not present in the <see
        /// cref="WorldState.History"/> of the current session's <see cref="Session.WorldState"/>.
        /// </para><para>
        /// When the replay ends or is aborted, the current session's <see
        /// cref="Session.WorldState"/> will be set to the specified <paramref name="worldState"/>,
        /// and its previous value will be discarded. The session's original <see
        /// cref="Graphics.MapView.SelectedSite"/> is likewise discarded and replaced with <see
        /// cref="Site.InvalidLocation"/>.
        /// </para><para>
        /// The specified <paramref name="worldState"/> may contain the same number of commands as
        /// that of the current <see cref="Session"/>. In this case, <b>Start</b> briefly highlights
        /// the home site of the active faction but does nothing else.</para></remarks>

        public void Start(WorldState worldState, bool isComputer)
        {
            CheckStartState();

            // store computer turn flag
            IsComputerTurn = isComputer;

            // store current history command count
            History history = Session.Instance.WorldState.History;
            int     index   = history.Commands.Count;

            // append new history commands, if any
            history.AddCommands(worldState.History);

            // set restore point to new world state
            this._originalWorldState = worldState;

            // save current session state
            this._originalState = Session.State;

            // ignore current site selection
            this._originalSelected = Site.InvalidLocation;

            // start replay with first new command
            Debug.Assert(index <= history.Commands.Count);
            this._commandIndex = index;

            // switch session to Replay state
            Session.State = SessionState.Replay;
            MainWindow.Instance.StatusMessage.Push(Global.Strings.StatusReplay);

            // show active faction's home site
            ShowFaction(Session.Instance.WorldState.ActiveFaction);

            // enter Play state
            CurrentState = ReplayState.Play;
            AsyncAction.Run(PlayCommands);
        }
示例#2
0
        /// <summary>
        /// Replays commands starting at the specified full turn and active faction indices.
        /// </summary>
        /// <param name="turn">
        /// The index of the full turn at which to start interactive replay.</param>
        /// <param name="faction">
        /// The index of the faction whose activation during the specified <paramref name="turn"/>
        /// should start interactive replay.</param>
        /// <exception cref="ArgumentOutOfRangeException"><para>
        /// <paramref name="turn"/> is greater than the <see cref="WorldState.CurrentTurn"/> of the
        /// current <see cref="Session.WorldState"/>.
        /// </para><para>-or-</para><para>
        /// <paramref name="faction"/> is less than zero.</para></exception>
        /// <exception cref="PropertyValueException">
        /// The current session <see cref="Session.State"/> is neither <see
        /// cref="SessionState.Closed"/>, <see cref="SessionState.Computer"/>, nor <see
        /// cref="SessionState.Human"/>.</exception>
        /// <remarks><para>
        /// <b>Start</b> sets the session <see cref="Session.State"/> to <see
        /// cref="SessionState.Replay"/> and <see cref="CurrentState"/> to <see
        /// cref="ReplayState.Play"/>, skips ahead to the specified <paramref name="turn"/> and
        /// <paramref name="faction"/> indices, and then begins an interactive replay of all
        /// remaining commands stored in the session's <see cref="WorldState.History"/>.
        /// </para><para>
        /// <b>Start</b> shows an informational message and returns immediately if there are no
        /// commands to replay.
        /// </para><para>
        /// If the specified <paramref name="turn"/> is negative, <b>Start</b> shows a <see
        /// cref="Dialog.ChangeTurn"/> dialog, allowing the user to enter the turn at which to start
        /// interactive replay.
        /// </para><para>
        /// If the specified <paramref name="faction"/> is greater than the number of surviving
        /// factions at any point while skipping ahead, interactive replay will begin with the first
        /// active faction during the specified <paramref name="turn"/>.</para></remarks>

        public void Start(int turn, int faction)
        {
            CheckStartState();
            Session    session = Session.Instance;
            WorldState world   = session.WorldState;

            if (turn > world.CurrentTurn)
            {
                ThrowHelper.ThrowArgumentOutOfRangeExceptionWithFormat(
                    "turn", turn, Tektosyne.Strings.ArgumentGreaterValue, "CurrentTurn");
            }

            if (faction < 0)
            {
                ThrowHelper.ThrowArgumentOutOfRangeException(
                    "faction", faction, Tektosyne.Strings.ArgumentNegative);
            }

            // show message and quit if no commands to replay
            if (world.History.Commands.Count == 0)
            {
                MessageBox.Show(MainWindow.Instance,
                                Global.Strings.DialogReplayNone, Global.Strings.TitleReplay,
                                MessageBoxButton.OK, MessageBoxImage.Information);
                return;
            }

            if (turn < 0)
            {
                // ask user to specify starting turn
                var dialog = new Dialog.ChangeTurn(
                    world.CurrentTurn, Global.Strings.TitleReplayFromTurn);
                dialog.Owner = MainWindow.Instance;
                if (dialog.ShowDialog() != true)
                {
                    return;
                }

                // get turn entered by user
                turn = dialog.Turn;
                Debug.Assert(turn >= 0);
                Debug.Assert(turn <= world.CurrentTurn);
            }

            // save current session data
            this._originalWorldState = session.WorldState;
            this._originalSelected   = Session.MapView.SelectedSite;
            this._originalState      = Session.State;

            // switch session to Replay state
            Session.State = SessionState.Replay;

            // show replay control message...
            MainWindow.Instance.StatusMessage.Push(Global.Strings.StatusReplay);

            // ...but wait for new world state
            MainWindow.Instance.BeginWait(Global.Strings.StatusReplayCommands);
            MainWindow.Instance.StatusMessage.Push();

            TaskEvents events = new TaskEvents(Application.Current.Dispatcher);

            events.TaskMessage += ((sender, args) =>
                                   MainWindow.Instance.StatusMessage.Text = args.Value);

            try {
                // create world state from scenario
                WorldState worldState = new WorldState();
                worldState.Initialize(events);

                // copy original turn count
                worldState.History.CopyFullTurns(this._originalWorldState.History);
                session.WorldState = worldState;
            }
            finally {
                MainWindow.Instance.StatusMessage.Pop();
                MainWindow.Instance.EndWait();
            }

            AsyncAction.Run(delegate {
                // skip to specified turn & faction
                this._commandIndex = 0;
                if (turn > 0 || faction > 0)
                {
                    Skip(turn, faction);
                }

                // set default map view to new world state
                AsyncAction.Invoke(() => Session.MapView.WorldState = session.WorldState);

                // show active faction's home if not skipped
                if (this._commandIndex == 0)
                {
                    ShowFaction(session.WorldState.ActiveFaction);
                }

                // enter Play state
                CurrentState = ReplayState.Play;
                PlayCommands();
            });
        }
示例#3
0
        /// <summary>
        /// Allows units of the <see cref="WorldState.ActiveFaction"/>, which must be controlled by
        /// a local human player, to perform an attack from or on the selected <see cref="Site"/>.
        /// </summary>
        /// <exception cref="PropertyValueException">
        /// The current session <see cref="Session.State"/> is not <see cref="SessionState.Human"/>.
        /// </exception>
        /// <remarks><para>
        /// <b>Attack</b> shows the <see cref="Dialog.AttackFromSite"/> dialog if the selected site
        /// contains any units owned by the <see cref="WorldState.ActiveFaction"/> that report
        /// possible attack targets. If no owned units are present, the <see
        /// cref="Dialog.AttackSite"/> dialog is shown instead.
        /// </para><para>
        /// In either case, <b>Attack</b> issues an <see cref="AttackCommand"/> with the entered
        /// data for the <see cref="WorldState.ActiveFaction"/>.</para></remarks>

        public static void Attack()
        {
            CheckSessionState();

            Session    session = Session.Instance;
            WorldState world   = session.WorldState;
            Faction    faction = world.ActiveFaction;

            // retrieve selected source site
            Site source = world.GetSite(Session.MapView.SelectedSite);

            if (source == null)
            {
                return;
            }

            // retrieve owned units in source site
            List <Entity> present = new List <Entity>();

            foreach (Entity unit in source.Units)
            {
                if (unit.Owner == faction)
                {
                    present.Add(unit);
                }
            }

            // variables used by both "if" branches
            var            eligible = new EntityList();
            PointI         target   = Site.InvalidLocation;
            IList <PointI> targets  = null;
            EntityList     units    = null;

            // prepare single-unit collection
            var singleUnit = new List <Entity>(1)
            {
                null
            };

            // check if source site contains owned units
            if (present.Count > 0)
            {
                // determine units eligible for attack
                foreach (Unit unit in present)
                {
                    singleUnit[0] = unit;
                    targets       = Finder.FindAttackTargets(world, singleUnit);
                    if (targets.Count > 0)
                    {
                        eligible.Add(unit);
                    }
                }

                // check if any present units may attack
                if (eligible.Count == 0)
                {
                    MessageBox.Show(MainWindow.Instance,
                                    Global.Strings.DialogAttackSourceNone,
                                    Global.Strings.TitleAttackSite + faction.Name,
                                    MessageBoxButton.OK, MessageBoxImage.Information);
                    return;
                }

                // show "Attack From Site" dialog for active faction
                using (var dialog = new Dialog.AttackFromSite(source, eligible)) {
                    dialog.Owner = MainWindow.Instance;
                    if (dialog.ShowDialog() != true)
                    {
                        return;
                    }

                    // retrieve user selections
                    target = dialog.Target;
                    units  = dialog.Units;
                }
            }
            else
            {
                // retrieve placed units of active faction
                var placed = faction.GetEntities(EntityCategory.Unit, true);

                // check if faction owns any placed units
                if (placed.Count == 0)
                {
                    MessageBox.Show(MainWindow.Instance,
                                    Global.Strings.DialogAttackPlacedNone,
                                    Global.Strings.TitleAttackSite + faction.Name,
                                    MessageBoxButton.OK, MessageBoxImage.Information);
                    return;
                }

                // target selected site
                target = source;

                // determine units eligible for attack
                foreach (Unit unit in placed)
                {
                    singleUnit[0] = unit;
                    targets       = Finder.FindAttackTargets(world, singleUnit);
                    if (targets.Contains(target))
                    {
                        eligible.Add(unit);
                    }
                }

                // check if any units may attack
                if (eligible.Count == 0)
                {
                    MessageBox.Show(MainWindow.Instance,
                                    Global.Strings.DialogAttackTargetNone,
                                    Global.Strings.TitleAttackSite + faction.Name,
                                    MessageBoxButton.OK, MessageBoxImage.Information);
                    return;
                }

                // show "Attack Site" dialog for active faction
                using (var dialog = new Dialog.AttackSite(target, eligible)) {
                    dialog.Owner = MainWindow.Instance;
                    if (dialog.ShowDialog() != true)
                    {
                        return;
                    }

                    // retrieve user selection
                    units = dialog.Units;
                }
            }

            // issue Attack command for valid selections
            if (target != Site.InvalidLocation && units != null && units.Count > 0)
            {
                AsyncAction.Run(() => session.Executor.ExecuteAttack(world, units, target));
            }
        }
示例#4
0
        /// <summary>
        /// Allows selected units of the <see cref="WorldState.ActiveFaction"/>, which must be
        /// controlled by a local human player, to move to another <see cref="Site"/>.</summary>
        /// <exception cref="PropertyValueException">
        /// The current session <see cref="Session.State"/> is not <see cref="SessionState.Human"/>.
        /// </exception>
        /// <remarks>
        /// <b>Move</b> shows the <see cref="Dialog.MoveUnits"/> dialog if the selected site
        /// contains any units owned by the <see cref="WorldState.ActiveFaction"/> that report any
        /// possible movement targets, and issues a <b>Move</b> command for the <see
        /// cref="WorldState.ActiveFaction"/> with the entered data.</remarks>

        public static void Move()
        {
            CheckSessionState();

            Session    session = Session.Instance;
            WorldState world   = session.WorldState;
            Faction    faction = world.ActiveFaction;

            // retrieve selected source site
            Site source = world.GetSite(Session.MapView.SelectedSite);

            if (source == null)
            {
                return;
            }

            // retrieve owned units in source site
            var present = new EntityList();

            foreach (Entity unit in source.Units)
            {
                if (unit.Owner == faction)
                {
                    present.Add(unit);
                }
            }

            // check if source site contains owned units
            if (present.Count == 0)
            {
                MessageBox.Show(MainWindow.Instance,
                                Global.Strings.DialogMoveSourceEmpty,
                                Global.Strings.TitleMoveUnits + faction.Name,
                                MessageBoxButton.OK, MessageBoxImage.Information);
                return;
            }

            var            eligible = new EntityList();
            IList <PointI> targets  = null;

            // prepare single-unit collection
            var singleUnit = new List <Entity>(1)
            {
                null
            };

            // determine units eligible for movement
            foreach (Unit unit in present)
            {
                singleUnit[0] = unit;
                targets       = Finder.FindMoveTargets(world, singleUnit);
                if (targets.Count > 0)
                {
                    eligible.Add(unit);
                }
            }

            // check if any present units may move
            if (eligible.Count == 0)
            {
                MessageBox.Show(MainWindow.Instance,
                                Global.Strings.DialogMoveSourceNone,
                                Global.Strings.TitleMoveUnits + faction.Name,
                                MessageBoxButton.OK, MessageBoxImage.Information);
                return;
            }

            PointI     target = Site.InvalidLocation;
            EntityList units  = null;

            // show "Move Units" dialog for active faction
            using (var dialog = new Dialog.MoveUnits(source, eligible)) {
                dialog.Owner = MainWindow.Instance;
                if (dialog.ShowDialog() != true)
                {
                    return;
                }

                // retrieve user selections
                target = dialog.Target;
                units  = dialog.Units;
            }

            // issue Move command for valid selections
            if (target != Site.InvalidLocation && units != null && units.Count > 0)
            {
                AsyncAction.Run(() => session.Executor.ExecuteMove(world, units, target));
            }
        }