public void ProposeKeyPoint(KeyPointType type, int id, ActivePlayer player)
 {
     if (ProposedKeyPoint != null)
     {
         ReplayMaker.Generate(ProposedKeyPoint.Type, ProposedKeyPoint.Id, ProposedKeyPoint.Player, _game);
     }
     ProposedKeyPoint = new ReplayKeyPoint(null, type, id, player);
 }
 private void ProposeKeyPoint(KeyPointType type, int id, ActivePlayer player)
 {
     if (_proposedKeyPoint != null)
     {
         ReplayMaker.Generate(_proposedKeyPoint.Type, _proposedKeyPoint.Id, _proposedKeyPoint.Player);
     }
     _proposedKeyPoint = new ReplayKeyPoint(null, type, id, player);
 }
 private void GameEndKeyPoint(bool victory, int id)
 {
     if (_proposedKeyPoint != null)
     {
         ReplayMaker.Generate(_proposedKeyPoint.Type, _proposedKeyPoint.Id, _proposedKeyPoint.Player);
         _proposedKeyPoint = null;
     }
     ReplayMaker.Generate(victory ? KeyPointType.Victory : KeyPointType.Defeat, id, ActivePlayer.Player);
 }
        private void TagChange(string rawTag, int id, string rawValue, bool isRecursive = false)
        {
            if (_lastId != id)
            {
                Game.SecondToLastUsedId = _lastId;
                if (_proposedKeyPoint != null)
                {
                    ReplayMaker.Generate(_proposedKeyPoint.Type, _proposedKeyPoint.Id, _proposedKeyPoint.Player);
                    _proposedKeyPoint = null;
                }
            }
            _lastId = id;
            if (!Game.Entities.ContainsKey(id))
            {
                Game.Entities.Add(id, new Entity(id));
            }
            GAME_TAG tag;

            if (!Enum.TryParse(rawTag, out tag))
            {
                int tmp;
                if (int.TryParse(rawTag, out tmp) && Enum.IsDefined(typeof(GAME_TAG), tmp))
                {
                    tag = (GAME_TAG)tmp;
                }
            }
            var value    = ParseTagValue(tag, rawValue);
            var prevZone = Game.Entities[id].GetTag(GAME_TAG.ZONE);

            Game.Entities[id].SetTag(tag, value);

            if (tag == GAME_TAG.CONTROLLER && _waitForController != null && Game.PlayerId == -1)
            {
                if (_currentEntityHasCardId)
                {
                    Game.Entities.First(e => e.Value.GetTag(GAME_TAG.PLAYER_ID) == 1).Value.IsPlayer = value == 1;
                    Game.Entities.First(e => e.Value.GetTag(GAME_TAG.PLAYER_ID) == 2).Value.IsPlayer = value != 1;
                    Game.PlayerId   = value;
                    Game.OpponentId = value == 1 ? 2 : 1;
                }
                else
                {
                    Game.Entities.First(e => e.Value.GetTag(GAME_TAG.PLAYER_ID) == 1).Value.IsPlayer = value != 1;
                    Game.Entities.First(e => e.Value.GetTag(GAME_TAG.PLAYER_ID) == 2).Value.IsPlayer = value == 1;
                    Game.PlayerId   = value == 1 ? 2 : 1;
                    Game.OpponentId = value;
                }
            }
            var    controller = Game.Entities[id].GetTag(GAME_TAG.CONTROLLER);
            string player     = Game.Entities[id].HasTag(GAME_TAG.CONTROLLER)
                                                ? (controller == Game.PlayerId ? "FRIENDLY" : "OPPOSING")
                                                : "";
            var cardId = Game.Entities[id].CardId;

            if (tag == GAME_TAG.ZONE)
            {
                //Logger.WriteLine("--------" + player + " " + Game.Entities[id].CardId + " " + (TAG_ZONE)prevZone + " -> " +
                //                 (TAG_ZONE)value);

                if (((TAG_ZONE)value == TAG_ZONE.HAND || ((TAG_ZONE)value == TAG_ZONE.PLAY) && Game.IsMulliganDone) &&
                    _waitForController == null)
                {
                    if (!Game.IsMulliganDone)
                    {
                        prevZone = (int)TAG_ZONE.DECK;
                    }
                    if (controller == 0)
                    {
                        Game.Entities[id].SetTag(GAME_TAG.ZONE, prevZone);
                        _waitForController = new { Tag = rawTag, Id = id, Value = rawValue };
                        //Logger.WriteLine("CURRENTLY NO CONTROLLER SET FOR CARD, WAITING...");
                        return;
                    }
                }
                switch ((TAG_ZONE)prevZone)
                {
                case TAG_ZONE.DECK:
                    switch ((TAG_ZONE)value)
                    {
                    case TAG_ZONE.HAND:
                        if (controller == Game.PlayerId)
                        {
                            _gameHandler.HandlePlayerDraw(cardId, GetTurnNumber());
                            ProposeKeyPoint(KeyPointType.Draw, id, ActivePlayer.Player);
                        }
                        else if (controller == Game.OpponentId)
                        {
                            _gameHandler.HandleOpponentDraw(GetTurnNumber());
                            ProposeKeyPoint(KeyPointType.Draw, id, ActivePlayer.Opponent);
                        }
                        break;

                    case TAG_ZONE.REMOVEDFROMGAME:
                    case TAG_ZONE.GRAVEYARD:
                    case TAG_ZONE.SETASIDE:
                    case TAG_ZONE.PLAY:
                        if (controller == Game.PlayerId)
                        {
                            _gameHandler.HandlePlayerDeckDiscard(cardId, GetTurnNumber());
                            ProposeKeyPoint(KeyPointType.DeckDiscard, id, ActivePlayer.Player);
                        }
                        else if (controller == Game.OpponentId)
                        {
                            _gameHandler.HandleOpponentDeckDiscard(cardId, GetTurnNumber());
                            ProposeKeyPoint(KeyPointType.DeckDiscard, id, ActivePlayer.Opponent);
                        }
                        break;

                    case TAG_ZONE.SECRET:
                        if (controller == Game.PlayerId)
                        {
                            _gameHandler.HandlePlayerSecretPlayed(cardId, GetTurnNumber(), true);
                            ProposeKeyPoint(KeyPointType.SecretPlayed, id, ActivePlayer.Player);
                        }
                        else if (controller == Game.OpponentId)
                        {
                            _gameHandler.HandleOpponentSecretPlayed(cardId, -1, GetTurnNumber(), true, id);
                            ProposeKeyPoint(KeyPointType.SecretPlayed, id, ActivePlayer.Player);
                        }
                        break;
                    }
                    break;

                case TAG_ZONE.GRAVEYARD:
                    break;

                case TAG_ZONE.HAND:
                    switch ((TAG_ZONE)value)
                    {
                    case TAG_ZONE.PLAY:
                        if (controller == Game.PlayerId)
                        {
                            _gameHandler.HandlePlayerPlay(cardId, GetTurnNumber());
                            ProposeKeyPoint(KeyPointType.Play, id, ActivePlayer.Player);
                        }
                        else if (controller == Game.OpponentId)
                        {
                            _gameHandler.HandleOpponentPlay(cardId, Game.Entities[id].GetTag(GAME_TAG.ZONE_POSITION), GetTurnNumber());
                            ProposeKeyPoint(KeyPointType.Play, id, ActivePlayer.Opponent);
                        }
                        break;

                    case TAG_ZONE.REMOVEDFROMGAME:
                    case TAG_ZONE.GRAVEYARD:
                        if (controller == Game.PlayerId)
                        {
                            _gameHandler.HandlePlayerHandDiscard(cardId, GetTurnNumber());
                            ProposeKeyPoint(KeyPointType.HandDiscard, id, ActivePlayer.Player);
                        }
                        else if (controller == Game.OpponentId)
                        {
                            _gameHandler.HandleOpponentHandDiscard(cardId, Game.Entities[id].GetTag(GAME_TAG.ZONE_POSITION),
                                                                   GetTurnNumber());
                            ProposeKeyPoint(KeyPointType.HandDiscard, id, ActivePlayer.Opponent);
                        }
                        break;

                    case TAG_ZONE.SECRET:
                        if (controller == Game.PlayerId)
                        {
                            _gameHandler.HandlePlayerSecretPlayed(cardId, GetTurnNumber(), false);
                            ProposeKeyPoint(KeyPointType.SecretPlayed, id, ActivePlayer.Player);
                        }
                        else if (controller == Game.OpponentId)
                        {
                            _gameHandler.HandleOpponentSecretPlayed(cardId, Game.Entities[id].GetTag(GAME_TAG.ZONE_POSITION),
                                                                    GetTurnNumber(), false, id);
                            ProposeKeyPoint(KeyPointType.SecretPlayed, id, ActivePlayer.Opponent);
                        }
                        break;

                    case TAG_ZONE.DECK:
                        if (controller == Game.PlayerId)
                        {
                            _gameHandler.HandlePlayerMulligan(cardId);
                            ProposeKeyPoint(KeyPointType.Mulligan, id, ActivePlayer.Player);
                        }
                        else if (controller == Game.OpponentId)
                        {
                            _gameHandler.HandleOpponentMulligan(Game.Entities[id].GetTag(GAME_TAG.ZONE_POSITION));
                            ProposeKeyPoint(KeyPointType.Mulligan, id, ActivePlayer.Opponent);
                        }
                        break;
                    }
                    break;

                case TAG_ZONE.PLAY:
                    switch ((TAG_ZONE)value)
                    {
                    case TAG_ZONE.HAND:
                        if (controller == Game.PlayerId)
                        {
                            _gameHandler.HandlePlayerBackToHand(cardId, GetTurnNumber());
                            ProposeKeyPoint(KeyPointType.PlayToHand, id, ActivePlayer.Player);
                        }
                        else if (controller == Game.OpponentId)
                        {
                            _gameHandler.HandleOpponentPlayToHand(cardId, GetTurnNumber(), id);
                            ProposeKeyPoint(KeyPointType.PlayToHand, id, ActivePlayer.Opponent);
                        }
                        break;

                    case TAG_ZONE.DECK:
                        if (controller == Game.PlayerId)
                        {
                            _gameHandler.HandlePlayerPlayToDeck(cardId, GetTurnNumber());
                            ProposeKeyPoint(KeyPointType.PlayToDeck, id, ActivePlayer.Player);
                        }
                        else if (controller == Game.OpponentId)
                        {
                            _gameHandler.HandleOpponentPlayToDeck(cardId, GetTurnNumber());
                        }
                        ProposeKeyPoint(KeyPointType.PlayToDeck, id, ActivePlayer.Opponent);
                        break;

                    case TAG_ZONE.GRAVEYARD:
                        if (Game.Entities[id].HasTag(GAME_TAG.HEALTH))
                        {
                            if (controller == Game.PlayerId)
                            {
                                ProposeKeyPoint(KeyPointType.Death, id, ActivePlayer.Player);
                            }
                            else if (controller == Game.OpponentId)
                            {
                                ProposeKeyPoint(KeyPointType.Death, id, ActivePlayer.Opponent);
                            }
                        }
                        break;
                    }
                    break;

                case TAG_ZONE.SECRET:
                    switch ((TAG_ZONE)value)
                    {
                    case TAG_ZONE.SECRET:
                    case TAG_ZONE.GRAVEYARD:
                        if (controller == Game.PlayerId)
                        {
                            ProposeKeyPoint(KeyPointType.SecretTriggered, id, ActivePlayer.Player);
                        }
                        if (controller == Game.OpponentId)
                        {
                            _gameHandler.HandleOpponentSecretTrigger(cardId, GetTurnNumber(), id);
                            ProposeKeyPoint(KeyPointType.SecretTriggered, id, ActivePlayer.Opponent);
                        }
                        break;
                    }
                    break;

                case TAG_ZONE.SETASIDE:
                case TAG_ZONE.CREATED:
                case TAG_ZONE.INVALID:
                case TAG_ZONE.REMOVEDFROMGAME:
                    switch ((TAG_ZONE)value)
                    {
                    case TAG_ZONE.PLAY:
                        if (controller == Game.PlayerId)
                        {
                            ProposeKeyPoint(KeyPointType.Summon, id, ActivePlayer.Player);
                        }
                        if (controller == Game.OpponentId)
                        {
                            ProposeKeyPoint(KeyPointType.Summon, id, ActivePlayer.Opponent);
                        }
                        break;

                    case TAG_ZONE.HAND:
                        if (controller == Game.PlayerId)
                        {
                            _gameHandler.HandlePlayerGet(cardId, GetTurnNumber());
                            ProposeKeyPoint(KeyPointType.Obtain, id, ActivePlayer.Player);
                        }
                        else if (controller == Game.OpponentId)
                        {
                            _gameHandler.HandleOpponentGet(GetTurnNumber(), id);
                            ProposeKeyPoint(KeyPointType.Obtain, id, ActivePlayer.Opponent);
                        }
                        break;
                    }
                    break;
                }
            }
            else if (tag == GAME_TAG.PLAYSTATE && !_gameEnded)
            {
                if (Game.Entities[id].IsPlayer)
                {
                    if (value == (int)TAG_PLAYSTATE.WON)
                    {
                        GameEndKeyPoint(true, id);
                        _gameHandler.HandleGameEnd();
                        _gameHandler.HandleWin(false);
                        _gameEnded = true;
                    }
                    else if (value == (int)TAG_PLAYSTATE.LOST)
                    {
                        GameEndKeyPoint(false, id);
                        _gameHandler.HandleGameEnd();
                        _gameHandler.HandleLoss(false);
                        _gameEnded = true;
                    }
                }
                else
                {
                    if (value == (int)TAG_PLAYSTATE.WON)
                    {
                        GameEndKeyPoint(false, Game.Entities.First(x => x.Value.IsPlayer).Key);
                        _gameHandler.HandleGameEnd();
                        _gameHandler.HandleLoss(false);
                        _gameEnded = true;
                    }
                    else if (value == (int)TAG_PLAYSTATE.LOST)
                    {
                        GameEndKeyPoint(true, Game.Entities.First(x => x.Value.IsPlayer).Key);
                        _gameHandler.HandleGameEnd();
                        _gameHandler.HandleWin(false);
                        _gameEnded = true;
                    }
                }
            }
            else if (tag == GAME_TAG.CURRENT_PLAYER && value == 1)
            {
                _gameHandler.TurnStart(Game.Entities[id].IsPlayer ? ActivePlayer.Player : ActivePlayer.Opponent, GetTurnNumber());
            }
            else if (tag == GAME_TAG.NUM_ATTACKS_THIS_TURN && value > 0)
            {
                if (controller == Game.PlayerId)
                {
                    ProposeKeyPoint(KeyPointType.Attack, id, ActivePlayer.Player);
                }
                else if (controller == Game.OpponentId)
                {
                    ProposeKeyPoint(KeyPointType.Attack, id, ActivePlayer.Opponent);
                }
            }
            else if (tag == GAME_TAG.ZONE_POSITION)
            {
                var zone = Game.Entities[id].GetTag(GAME_TAG.ZONE);
                if (zone == (int)TAG_ZONE.HAND)
                {
                    if (controller == Game.PlayerId)
                    {
                        ReplayMaker.Generate(KeyPointType.HandPos, id, ActivePlayer.Player);
                    }
                    else if (controller == Game.OpponentId)
                    {
                        ReplayMaker.Generate(KeyPointType.HandPos, id, ActivePlayer.Opponent);
                    }
                }
                else if (zone == (int)TAG_ZONE.PLAY)
                {
                    if (controller == Game.PlayerId)
                    {
                        ReplayMaker.Generate(KeyPointType.BoardPos, id, ActivePlayer.Player);
                    }
                    else if (controller == Game.OpponentId)
                    {
                        ReplayMaker.Generate(KeyPointType.BoardPos, id, ActivePlayer.Opponent);
                    }
                }
            }
            else if (tag == GAME_TAG.CARD_TARGET && value > 0)
            {
                if (controller == Game.PlayerId)
                {
                    ProposeKeyPoint(KeyPointType.PlaySpell, id, ActivePlayer.Player);
                }
                else if (controller == Game.OpponentId)
                {
                    ProposeKeyPoint(KeyPointType.PlaySpell, id, ActivePlayer.Opponent);
                }
            }
            else if (tag == GAME_TAG.EQUIPPED_WEAPON && value == 0)
            {
                if (controller == Game.PlayerId)
                {
                    ProposeKeyPoint(KeyPointType.WeaponDestroyed, id, ActivePlayer.Player);
                }
                else if (controller == Game.OpponentId)
                {
                    ProposeKeyPoint(KeyPointType.WeaponDestroyed, id, ActivePlayer.Opponent);
                }
            }
            else if (tag == GAME_TAG.EXHAUSTED && value > 0)
            {
                if (Game.Entities[id].GetTag(GAME_TAG.CARDTYPE) == (int)TAG_CARDTYPE.HERO_POWER)
                {
                    if (controller == Game.PlayerId)
                    {
                        ProposeKeyPoint(KeyPointType.HeroPower, id, ActivePlayer.Player);
                    }
                    else if (controller == Game.OpponentId)
                    {
                        ProposeKeyPoint(KeyPointType.HeroPower, id, ActivePlayer.Opponent);
                    }
                }
            }
            else if (tag == GAME_TAG.CONTROLLER && Game.Entities[id].IsInZone(TAG_ZONE.SECRET))
            {
                if (value == Game.PlayerId)
                {
                    _gameHandler.HandleOpponentSecretTrigger(cardId, GetTurnNumber(), id);
                    ProposeKeyPoint(KeyPointType.SecretStolen, id, ActivePlayer.Player);
                }
                else if (value == Game.OpponentId)
                {
                    ProposeKeyPoint(KeyPointType.SecretStolen, id, ActivePlayer.Player);
                }
            }
            if (_waitForController != null)
            {
                if (!isRecursive)
                {
                    TagChange((string)_waitForController.Tag, (int)_waitForController.Id, (string)_waitForController.Value, true);
                    _waitForController = null;
                }
            }
        }