Beispiel #1
0
        // WARNING: The Game must not be changing during this,
        // ie. it is not thread-safe unless the game is inactive
        public Game CloneState()
        {
            var  entities = new EntityController(Entities);
            Game game     = entities.FindGame();

            // Set references to the new player proxies (no additional cloning)
            game.Player1 = entities.FindPlayer(1);
            game.Player2 = entities.FindPlayer(2);
            if (game.CurrentPlayer != null)
            {
                game.CurrentPlayer = (CurrentPlayer.Id == game.Player1.Id ? game.Player1 : game.Player2);
            }
            // Generate zones owned by game
            for (int i = 0; i < 2; i++)
            {
                game.Players[i].Deck = new Deck(game, Players[i].Deck.HeroClass, game.Players[i]);
            }
            // Clone queue, stack and events
            game.ActionQueue = ((ActionQueue)ActionQueue.Clone());
            game.ActionQueue.Attach(game);
            // Clone triggers
            game.ActiveTriggers      = ((TriggerManager)ActiveTriggers.Clone());
            game.ActiveTriggers.Game = game;
            // Clone environment
            game.Environment = (Environment)Environment.Clone();
            // Link PowerHistory
            if (PowerHistory != null)
            {
                game.PowerHistory = new PowerHistory(game, this);
            }
#if _GAME_DEBUG
            DebugLog.WriteLine("Cloned game " + GameId + " => " + game.GameId);
#endif
            return(game);
        }
Beispiel #2
0
        internal void OnBlockEmpty(BlockStart Block)
        {
#if _GAME_DEBUG
            DebugLog.WriteLine("Game " + GameId + ": Action block " + Block.Type + " for " + Entities[Block.Source].ShortDescription + " resolved");
#endif
            PowerHistory?.Add(new BlockEnd(Block.Type));

            if (Block.Type == BlockType.TRIGGER)
            {
                ActiveTriggers.TriggerResolved();
            }

            // Post-ATTACK or Post-final TRIGGER DEATHS block
            if (Block.Type == BlockType.ATTACK || (Block.Type == BlockType.TRIGGER && ActiveTriggers.QueuedTriggersCount == 0))
            {
                RunDeathCreationStepIfNeeded();
            }
        }
Beispiel #3
0
        internal void OnQueueEmpty()
        {
#if _GAME_DEBUG
            DebugLog.WriteLine("Game " + GameId + ": Action queue resolved");
#endif
            // Don't do anything if the game state hasn't changed

            // Check if one of the other players is waiting for the other one to mulligan
            var step = Step;
            if (step == Step.BEGIN_MULLIGAN)
            {
                foreach (var p in Players)
                {
                    if (p.MulliganState == MulliganState.WAITING)
                    {
                        ActiveTriggers.Queue(TriggerType.OnMulliganWaiting, p);
                        return;
                    }
                }
            }

            // Advance game step if necessary (probably setting off new triggers)
            var nextStep = NextStep;

            // Only advance to end turn when current player chooses to
#if _GAME_DEBUG
            if (nextStep == Step.MAIN_END && ActionQueue.IsEmpty)
            {
                DebugLog.WriteLine("Game " + GameId + ": Waiting for player to select next option");
            }
#endif
            if (nextStep != step && nextStep != Step.MAIN_END)
            {
#if _GAME_DEBUG
                DebugLog.WriteLine("Game " + GameId + ": Advancing game step from " + step + " to " + nextStep);
#endif
                Step = nextStep;
            }
        }
Beispiel #4
0
        // Death checking phase
        internal void RunDeathCreationStepIfNeeded()
        {
#if _GAME_DEBUG
            DebugLog.WriteLine("Game " + GameId + ": Checking for death creation step");
#endif
            if (_deathCheckQueue.Count == 0)
            {
                return;
            }

            // We only have to check health because ToBeDestroyed cannot be reversed without the minion leaving play
            var dyingEntities =
                _deathCheckQueue.Where(
                    id => ((ICharacter)Entities[id]).MortallyWounded && Entities[id].Zone.Type == Brimstone.Zone.PLAY)
                .Select(id => (ICharacter)Entities[id]).ToList();

            if (dyingEntities.Count > 0)
            {
#if _GAME_DEBUG
                DebugLog.WriteLine("Game " + GameId + ": Running death creation step");
#endif
                PowerHistory?.Add(new BlockStart(BlockType.DEATHS, this));
            }

            // Death Creation Step
            bool gameEnd = false;
            foreach (var e in dyingEntities)
            {
#if _ACTIONS_DEBUG
                DebugLog.WriteLine("Game {0}: {1} dies", GameId, e.ShortDescription);
#endif
                // Queue deathrattles and OnDeath triggers before moving mortally wounded minion to graveyard
                // (they will be executed after the zone move)
                // TODO: Test that each queue resolves before the next one populates. If it doesn't, we can make queue populating lazy
                if (e is Minion)
                {
                    ActiveTriggers.Queue(TriggerType.OnDeath, e);
                }

                // NumMinionsPlayerKilledThisTurn seems to be the number of minions that died this turn
                // regardless of who or what killed what
                e.Controller.NumMinionsPlayerKilledThisTurn++;
                NumMinionsKilledThisTurn++;
                e.IsExhausted = false;

                // Move dead character to graveyard
                e.Zone = e.Controller.Graveyard;

                // TODO: Reset all minion tags to default
                if (e is Minion)
                {
                    var minion = ((Minion)e);
                    minion.Damage = 0;
                }

                // Hero death
                if (e is Hero)
                {
                    e.Controller.PlayState = PlayState.LOSING;
                    gameEnd = true;
                }
            }
            if (gameEnd)
            {
                GameWon();
            }

            if (dyingEntities.Count > 0)
            {
                PowerHistory?.Add(new BlockEnd(BlockType.DEATHS));
            }
            _deathCheckQueue.Clear();
        }