예제 #1
0
        void MoveToNext(ref CardList <CardInPlay>[] current, CardList <CardInPlay> next, double timestamp, bool isInitialDraw, bool isLocalPlayer)
        {
            CardList <CardInPlay> stationaryResult = new CardList <CardInPlay>();
            CardList <CardInPlay> movedResult      = new CardList <CardInPlay>();

            // For each card in 'next', look for a card in 'current' that's in the same zone
            // If found, remove from both and add to stationaryCards set
            for (int i = 0; i < NumZones; i++)
            {
                stationaryResult.AddRange(CardList <CardInPlay> .Extract(ref next, ref current[i], (x, y) =>
                {
                    // Skip values in next that are incorrect zone
                    if ((int)x.CurrentZone != i)
                    {
                        return(-1);
                    }
                    int z = x.TheCard.Cost - y.TheCard.Cost;
                    if (z == 0)
                    {
                        z = x.TheCard.Name.CompareTo(y.TheCard.Name);
                    }
                    return(z);
                }, (x, y) =>
                {
                    y.BoundingBox           = x.BoundingBox;
                    y.NormalizedBoundingBox = x.NormalizedBoundingBox;
                    y.NormalizedCenter      = x.NormalizedCenter;
                    return(y);
                }));
            }

            // For each card in next, look for a card in 'current' Ether zone that may have returned to the same zone
            movedResult.AddRange(CardList <CardInPlay> .Extract(ref next, ref current[(int)PlayZone.Ether], (x, y) =>
            {
                // Skip values in next that are incorrect zone
                if (y.CurrentZone != PlayZone.Ether)
                {
                    return(-1);
                }
                int z = x.TheCard.Cost - y.TheCard.Cost;
                if (z == 0)
                {
                    z = x.TheCard.Name.CompareTo(y.TheCard.Name);
                }
                // Skip values in current that are incorrect zone
                if (z == 0 && x.CurrentZone != y.LastNonEtherZone)
                {
                    z = 1;
                }
                return(z);
            }, (x, y) =>
            {
                y.BoundingBox           = x.BoundingBox;
                y.NormalizedBoundingBox = x.NormalizedBoundingBox;
                y.NormalizedCenter      = x.NormalizedCenter;
                y.MoveToZone(x.CurrentZone, timestamp);
                return(y);
            }));

            // For each card in next, look for a card in 'current' Ether zone that may has an approved transition
            movedResult.AddRange(CardList <CardInPlay> .Extract(ref next, ref current[(int)PlayZone.Ether], (x, y) =>
            {
                // Skip values in next that are incorrect zone
                if (y.CurrentZone != PlayZone.Ether)
                {
                    return(-1);
                }
                int z = x.TheCard.Cost - y.TheCard.Cost;
                if (z == 0)
                {
                    z = x.TheCard.Name.CompareTo(y.TheCard.Name);
                }
                // Skip values in current that are incorrect zone
                if (z == 0 && GameBoard.TransitionResult.Proceed != GameBoard.TransitionAllowed(y.LastNonEtherZone, PlayZone.Unknown, x.CurrentZone, isInitialDraw, isLocalPlayer))
                {
                    z = -1;
                }
                return(z);
            }, (x, y) =>
            {
                x.LastNonEtherZone = y.LastNonEtherZone;
                x.LastZone         = PlayZone.Ether;
                x.IsFromDeck       = y.IsFromDeck;
                x.ChampionCode     = y.ChampionCode;
                return(x);
            }));

            // For each card in next, look for approved transitions, skipping current in deck
            for (int i = 0; i < NumZones; i++)
            {
                if (i == (int)PlayZone.Deck)
                {
                    continue;
                }

                movedResult.AddRange(CardList <CardInPlay> .Extract(ref next, ref current[i], (x, y) =>
                {
                    // Skip values in next that are incorrect zone
                    int z = x.TheCard.Cost - y.TheCard.Cost;
                    if (z == 0)
                    {
                        z = x.TheCard.Name.CompareTo(y.TheCard.Name);
                    }
                    if (z == 0 && GameBoard.TransitionResult.Proceed != GameBoard.TransitionAllowed(y.CurrentZone, y.LastNonEtherZone, x.CurrentZone, isInitialDraw, isLocalPlayer))
                    {
                        z = -1;
                    }
                    return(z);
                }, (x, y) =>
                {
                    x.SetLastZone(y.CurrentZone);
                    x.IsFromDeck   = y.IsFromDeck;
                    x.ChampionCode = y.ChampionCode;
                    return(x);
                }));
            }

            // For each card in next, look for declined transitions
            for (int i = 0; i < NumZones; i++)
            {
                stationaryResult.AddRange(CardList <CardInPlay> .Extract(ref next, ref current[i], (x, y) =>
                {
                    // Skip values in next that are incorrect zone
                    int z = x.TheCard.Cost - y.TheCard.Cost;
                    if (z == 0)
                    {
                        z = x.TheCard.Name.CompareTo(y.TheCard.Name);
                    }
                    if (z == 0 && GameBoard.TransitionResult.Stay != GameBoard.TransitionAllowed(y.CurrentZone, y.LastNonEtherZone, x.CurrentZone, isInitialDraw, isLocalPlayer))
                    {
                        z = -1;
                    }
                    return(z);
                }, (x, y) =>
                {
                    y.BoundingBox           = x.BoundingBox;
                    y.NormalizedBoundingBox = x.NormalizedBoundingBox;
                    y.NormalizedCenter      = x.NormalizedCenter;
                    return(y);
                }));
            }

            // For each card in 'hand', look for champion transformations
            stationaryResult.AddRange(CardList <CardInPlay> .Extract(ref next, ref current[(int)PlayZone.Hand], (x, y) =>
            {
                // Skip values in next that are incorrect zone
                if ((int)x.CurrentZone != (int)PlayZone.Hand)
                {
                    return(-1);
                }
                if (y.ChampionCode.Length == 0)
                {
                    return(-1);
                }
                if (y.TheCard.SuperType == "Champion")
                {
                    var spellCode = y.TheCard.AssociatedCardCodes.Last();
                    var spellCard = CardLibrary.GetCard(spellCode);
                    if (spellCard.FlavorText == x.TheCard.FlavorText)
                    {
                        return(0);
                    }
                }
                else if (x.TheCard.SuperType == "Champion")
                {
                    if (x.CardCode == y.ChampionCode)
                    {
                        return(0);
                    }
                }
                return(-1);
            }, (x, y) =>
            {
                x.LastZone     = y.CurrentZone;
                x.IsFromDeck   = y.IsFromDeck;
                x.ChampionCode = y.ChampionCode;
                return(x);
            }));


            // For each card in next, look for approved transitions from deck
            movedResult.AddRange(CardList <CardInPlay> .Extract(ref next, ref current[(int)PlayZone.Deck], (x, y) =>
            {
                // Skip values in next that are incorrect zone
                int z = x.TheCard.Cost - y.TheCard.Cost;
                if (z == 0)
                {
                    z = x.TheCard.Name.CompareTo(y.TheCard.Name);
                }
                if (z == 0 && GameBoard.TransitionResult.Proceed != GameBoard.TransitionAllowed(y.CurrentZone, y.LastNonEtherZone, x.CurrentZone, isInitialDraw, isLocalPlayer))
                {
                    z = -1;
                }
                return(z);
            }, (x, y) =>
            {
                x.SetLastZone(y.CurrentZone);
                x.IsFromDeck   = y.IsFromDeck;
                x.ChampionCode = y.ChampionCode;
                return(x);
            }));

            // Move not in deck to ether
            for (int i = 0; i < NumZones; i++)
            {
                PlayZone newZone = PlayZone.Ether;
                if (i == (int)PlayZone.Deck || i == (int)PlayZone.Graveyard || i == (int)PlayZone.Ether)
                {
                    continue;
                }
                if (i == (int)PlayZone.Stage && isInitialDraw)
                {
                    newZone = PlayZone.Deck;
                }

                for (int j = 0; j < current[i].Count; j++)
                {
                    current[i][j].MoveToZone(newZone, timestamp);
                }
                movedResult.AddRange(current[i]);
                current[i].Clear();
            }

            // Remove cards in next that are in a zone that does not accept from Unknown
            next = next.GetSubset(x => GameBoard.TransitionResult.Proceed == GameBoard.TransitionAllowed(x.LastNonEtherZone, PlayZone.Unknown, x.CurrentZone, isInitialDraw, isLocalPlayer));

            // Add remaining cards to the moved set
            movedResult.AddRange(next);

            // Log all moves
            foreach (var card in movedResult)
            {
                LogMove(card, card.CurrentZone != PlayZone.Ether);
            }

            // Re-add all the cars to the zones
            for (int i = 0; i < NumZones; i++)
            {
                current[i].AddRange(stationaryResult.GetSubset(x => (int)x.CurrentZone == i));
                current[i].AddRange(movedResult.GetSubset(x => (int)x.CurrentZone == i));
            }
        }
예제 #2
0
        /// <summary>
        /// Process next rectangle layout
        /// </summary>
        /// <param name="overlay"></param>
        /// <param name="timestamp"></param>
        public void ProcessNext(Dictionary <string, JsonElement> overlay, double timestamp)
        {
            TimeCounter++;

            if (!TestMode && PlayerCards[(int)PlayZone.Deck].Count == 0 && PlayerCards[(int)PlayZone.Graveyard].Count == 0)
            {
                // Have not received the deck yet
                return;
            }
            CardList <CardInPlay> cardsInPlay = new CardList <CardInPlay>();

            bool isChampionUpgrading = false;

            if (overlay != null)
            {
                var screen = overlay["Screen"].ToObject <Dictionary <string, JsonElement> >();
                ScreenWidth  = screen["ScreenWidth"].GetInt32();
                ScreenHeight = screen["ScreenHeight"].GetInt32();

                // We normalize elements' bounding box based on screen height. However, if screen ratio becomes
                // too high, screen expands height-wise. To make sure we have same behavior as before,
                // We adjust the height accordingly.
                int normalizedScreenHeight = (int)(0.5 + GameBoard.ComputeNormalizedScreenHeight(ScreenWidth, ScreenHeight));

                Point correctionOffset = new Point(0, 0);
                var   rectangles       = overlay["Rectangles"].ToObject <Dictionary <string, JsonElement>[]>();
                foreach (var dict in rectangles)
                {
                    string cardCode = dict["CardCode"].GetString();
                    if (cardCode == "face")
                    {
                        if (dict["LocalPlayer"].GetBoolean())
                        {
                            int x = dict["TopLeftX"].GetInt32();
                            int y = dict["TopLeftY"].GetInt32();
                            if (IsInitialDraw)
                            {
                                LocalPlayerFace = new Point(x, y);
                            }
                            else
                            {
                                correctionOffset.X = LocalPlayerFace.X - x;
                                correctionOffset.Y = LocalPlayerFace.Y - y;
                            }
                        }

                        // We don't process face
                        continue;
                    }
                    Card card = CardLibrary.GetCard(cardCode);

                    // Also ignore abilities
                    if (card.Type != "Ability")
                    {
                        CardInPlay c = new CardInPlay(dict, ScreenWidth, ScreenHeight, correctionOffset, normalizedScreenHeight);
                        cardsInPlay.Add(card.Cost, card.Name, c);
                        if (c.CurrentZone == PlayZone.Hand && c.NormalizedCenter.Y > 1.3f)
                        {
                            // Champion is upgrading
                            isChampionUpgrading = true;
                        }
                    }
                }
            }

            // Split next elements between owners. Also, disregard cards with unknown zone
            CardList <CardInPlay> nextPlayerCards   = new CardList <CardInPlay>();
            CardList <CardInPlay> nextOpponentCards = new CardList <CardInPlay>();

            cardsInPlay.Split(ref nextPlayerCards, ref nextOpponentCards, x => x.Owner == PlayerType.LocalPlayer && x.CurrentZone != PlayZone.Unknown);
            Callback.OnElementsUpdate(nextPlayerCards, nextOpponentCards, ScreenWidth, ScreenHeight);
            if (isChampionUpgrading)
            {
                // Bail, champion is upgrading
                return;
            }

            if (nextPlayerCards.FindIndex(x => x.CurrentZone == PlayZone.Stage) >= 0)
            {
                CardsAreOnStage = true;
            }
            else if (CardsAreOnStage)
            {
                // Transition, reset ether timers
                for (int i = 0; i < PlayerCards[(int)PlayZone.Ether].Count; i++)
                {
                    PlayerCards[(int)PlayZone.Ether][i].EtherStartTime = timestamp;
                }
                CardsAreOnStage = false;
            }

            // Mark all opponent cards as "from deck" for now
            // This is because we cannot reliably know which ones are not from deck yet
            for (int i = 0; i < nextOpponentCards.Count; i++)
            {
                nextOpponentCards[i].IsFromDeck = nextOpponentCards[i].TheCard.IsCollectible;
            }

            MoveToNext(ref PlayerCards, nextPlayerCards, timestamp, IsInitialDraw, true);
            if (IsInitialDraw)
            {
                // Initial draw until we add some cards to hand
                IsInitialDraw = (PlayerCards[(int)PlayZone.Hand].Count() == 0);
            }


            MoveToNext(ref OpponentCards, nextOpponentCards, timestamp, false, false);

            // Purge Ether of spells that have been cast
            bool thoroughCleanUp = false;
            int  handCardIndex   = PlayerCards[(int)PlayZone.Hand].FindIndex(x => x.CurrentZone == PlayZone.Hand);

            if (PlayerCards[(int)PlayZone.Hand].Count() > 0 && PlayerCards[(int)PlayZone.Hand][0].NormalizedBoundingBox.Height < 0.235f)
            {
                thoroughCleanUp = true;
            }

            // Clean up ether -- generally move expired cards to graveyard, but also send cast champion spells back to deck
            if (!CardsAreOnStage)
            {
                // Find all the expiring
                CardList <CardInPlay> cardsGoingToGraveyard = CleanUpEther(ref PlayerCards[(int)PlayZone.Ether], timestamp, thoroughCleanUp);
                for (int i = 0; i < cardsGoingToGraveyard.Count; i++)
                {
                    if (cardsGoingToGraveyard[i].ChampionCode.Length > 0 && cardsGoingToGraveyard[i].TheCard.Type == "Spell")
                    {
                        var championCard       = CardLibrary.GetCard(cardsGoingToGraveyard[i].ChampionCode);
                        var championCardInPlay = new CardInPlay(championCard);
                        championCardInPlay.LastZone         = PlayZone.Ether;
                        championCardInPlay.LastNonEtherZone = cardsGoingToGraveyard[i].LastNonEtherZone;
                        championCardInPlay.CurrentZone      = PlayZone.Deck;
                        PlayerCards[(int)PlayZone.Deck].Add(championCard.Cost, championCard.Name, championCardInPlay);
                        cardsGoingToGraveyard[i].IsFromDeck = false;
                        Log.WriteLine(LogType.Player, "[{0}{1}] Shuffled back: {2}", championCardInPlay.LastNonEtherZone.ToString()[0],
                                      championCardInPlay.CurrentZone.ToString()[0], championCard.Name);
                    }
                }

                PlayerCards[(int)PlayZone.Graveyard].AddRange(cardsGoingToGraveyard);
            }
            OpponentCards[(int)PlayZone.Graveyard].AddRange(CleanUpEther(ref OpponentCards[(int)PlayZone.Ether], timestamp, true));

            NotifyCardSetUpdates();

            // Update attacking player
            int numPlayerAttackers   = PlayerCards[(int)PlayZone.Battle].Count + PlayerCards[(int)PlayZone.Windup].Count + PlayerCards[(int)PlayZone.Attack].Count;
            int numOpponentAttackers = OpponentCards[(int)PlayZone.Battle].Count + OpponentCards[(int)PlayZone.Windup].Count + OpponentCards[(int)PlayZone.Attack].Count;

            if (AttackingPlayer == PlayerType.None)
            {
                if (numPlayerAttackers != numOpponentAttackers)
                {
                    AttackingPlayer = numPlayerAttackers > numOpponentAttackers ? PlayerType.LocalPlayer : PlayerType.Opponent;
                }
            }
            else if (numPlayerAttackers == 0 && numOpponentAttackers == 0)
            {
                AttackingPlayer = PlayerType.None;
            }

            // Here we try to identify opponent's cards that did not start in deck
            // If a card appears in hand and we can see it, it was likely generated
            // Also, if a card appears in the field without going through stage first
            // it was likely generated by spell or another unit
            // Mark these cards as not from deck
            // Unfortunately, we have no way of tracking nabbed cards, so those will show up
            // as from deck
            for (int i = 0; i < OpponentCards[(int)PlayZone.Field].Count; i++)
            {
                if (OpponentCards[(int)PlayZone.Field][i].LastNonEtherZone == PlayZone.Unknown)
                {
                    OpponentCards[(int)PlayZone.Field][i].IsFromDeck = false;
                }
            }
            for (int i = 0; i < OpponentCards[(int)PlayZone.Hand].Count; i++)
            {
                if (OpponentCards[(int)PlayZone.Hand][i].LastNonEtherZone == PlayZone.Unknown)
                {
                    OpponentCards[(int)PlayZone.Hand][i].IsFromDeck = false;
                }
            }
        }