Exemple #1
0
        public static void RunSolverStressTest()
        {
            int numIterations = 1000 * 1000;

            Logger.WriteLine("Solver testing start, numIterations:" + numIterations);

            Stopwatch timer = new Stopwatch();

            timer.Start();

            TriadDeck testDeck   = new TriadDeck(new int[] { 10, 20, 30, 40, 50 });
            TriadNpc  testNpc    = TriadNpcDB.Get().Find("Garima");
            Random    randStream = new Random();

            TriadGameSession solver = new TriadGameSession();

            solver.modifiers.AddRange(testNpc.Rules);
            solver.UpdateSpecialRules();

            for (int Idx = 0; Idx < numIterations; Idx++)
            {
                TriadGameData testData    = solver.StartGame(testDeck, testNpc.Deck, ETriadGameState.InProgressBlue);
                Random        sessionRand = new Random(randStream.Next());
                solver.SolverPlayRandomGame(testData, sessionRand);
            }

            timer.Stop();
            Logger.WriteLine("Solver testing finished, time taken:" + timer.ElapsedMilliseconds + "ms");

            if (Debugger.IsAttached)
            {
                Debugger.Break();
            }
        }
        public void Initialize(TriadNpc npc, TriadGameModifier[] regionMods, List <TriadCard> lockedCards)
        {
            this.npc         = npc;
            numPossibleDecks = 1;
            numTestedDecks   = 0;
            numMsElapsed     = 0;

            PlayerSettingsDB playerDB = PlayerSettingsDB.Get();

            currentSolver = new TriadGameSession();
            currentSolver.modifiers.AddRange(npc.Rules);
            currentSolver.modifiers.AddRange(regionMods);
            currentSolver.UpdateSpecialRules();

            isOrderImportant = false;
            foreach (TriadGameModifier mod in currentSolver.modifiers)
            {
                isOrderImportant = isOrderImportant || mod.IsDeckOrderImportant();
            }

            bool foundCards = FindCardPool(playerDB.ownedCards, currentSolver.modifiers, lockedCards);

            if (foundCards)
            {
                UpdatePossibleDeckCount();
            }
        }
Exemple #3
0
        public void UpdatePlayerDeckForNpc(TriadNpc npc, TriadDeck deck)
        {
            if (npc != null && deck != null && deck.knownCards.Count == 5)
            {
                bool bIsStarterDeck = true;
                for (int Idx = 0; Idx < starterCards.Length; Idx++)
                {
                    bIsStarterDeck = bIsStarterDeck && (starterCards[Idx] == deck.knownCards[Idx]);
                }

                if (!bIsStarterDeck)
                {
                    bool bChanged = true;
                    if (lastDeck.ContainsKey(npc))
                    {
                        if (lastDeck[npc].Equals(deck))
                        {
                            bChanged = false;
                        }
                        else
                        {
                            lastDeck.Remove(npc);
                        }
                    }

                    if (bChanged)
                    {
                        TriadCard[] deckCardsCopy = deck.knownCards.ToArray();
                        lastDeck.Add(npc, new TriadDeck(deckCardsCopy));
                        MarkDirty();
                    }
                }
            }
        }
Exemple #4
0
        public void PrepareStats(TriadNpc npc, TriadGameModifier[] regionMods, List <TriadCard> lockedCards, out string numOwnedStr, out string numPossibleStr)
        {
            bool bIsOrderImportant = false;

            foreach (TriadGameModifier mod in npc.Rules)
            {
                bIsOrderImportant = bIsOrderImportant || mod.IsDeckOrderImportant();
            }
            foreach (TriadGameModifier mod in regionMods)
            {
                bIsOrderImportant = bIsOrderImportant || mod.IsDeckOrderImportant();
            }

            //TriadCardDB playerDB = TriadCardDB.Get();
            PlayerSettingsDB playerDB = PlayerSettingsDB.Get();

            int numOwned = playerDB.ownedCards.Count;

            numOwnedStr = numOwned.ToString();

            if (bUseScoredBuilder)
            {
                UpdatePossibleDeckCount(numRareToBuild, numCommonToBuild, lockedCards, bIsOrderImportant);
            }
            else
            {
                UpdatePossibleDeckCount(numOwned, bIsOrderImportant);
            }

            numPossibleStr = numPossibleDecks.ToString("N0");
        }
Exemple #5
0
        public void SetNpc(TriadNpc inNpc)
        {
            npc = inNpc;

            UpdateStatusDescription();
            labelNpc.Text   = "NPC: " + ((npc != null) ? npc.ToString() : "unknown");
            labelRules.Text = "Rules: npc changed, waiting for scan...";
        }
        public Task Process(TriadNpc npc, TriadGameModifier[] regionMods, List <TriadCard> lockedCards)
        {
            this.npc       = npc;
            numTestedDecks = 0;
            numMsElapsed   = 0;
            bAbort         = false;

            return(Task.Run(() => { FindDecksScored(regionMods, lockedCards); }));
        }
Exemple #7
0
 public TriadGameScreenMemory()
 {
     gameSession        = new TriadGameSession();
     gameState          = new TriadGameData();
     deckBlue           = new TriadDeckInstanceScreen();
     deckRed            = new TriadDeckInstanceScreen();
     blueDeckHistory    = new List <TriadCard[]>();
     bHasSwapRule       = false;
     swappedBlueCardIdx = -1;
     lastScanNpc        = null;
 }
Exemple #8
0
        public void Update(TriadGameSession currentGame, TriadNpc npc)
        {
            bool isDirty = true;

            if (session != null && session.modifiers.Count == currentGame.modifiers.Count)
            {
                int numMatching = 0;
                for (int Idx = 0; Idx < currentGame.modifiers.Count; Idx++)
                {
                    TriadGameModifier currentMod = session.modifiers[Idx];
                    TriadGameModifier reqMod     = currentGame.modifiers[Idx];

                    if (currentMod.GetType() == reqMod.GetType())
                    {
                        numMatching++;
                    }
                }

                isDirty = (numMatching != session.modifiers.Count);
            }

            if (npc != this.npc)
            {
                this.npc = npc;
                isDirty  = true;
            }

            if (isDirty)
            {
                session            = new TriadGameSession();
                session.solverName = "Fav #" + (contextId + 1);

                foreach (TriadGameModifier mod in currentGame.modifiers)
                {
                    TriadGameModifier modCopy = (TriadGameModifier)Activator.CreateInstance(mod.GetType());
                    modCopy.OnMatchInit();

                    session.modifiers.Add(modCopy);
                }

                session.UpdateSpecialRules();
                CalcWinChance();
            }
        }
Exemple #9
0
        public static void RunSolverStressTest()
        {
#if DEBUG
            int numIterations = 1000 * 100;
            Logger.WriteLine("Solver testing start, numIterations:" + numIterations);
            perfStats = new SolverPerfStats();

            Stopwatch timer = new Stopwatch();
            timer.Start();

            TriadDeck testDeck   = new TriadDeck(new int[] { 10, 20, 30, 40, 50 });
            TriadNpc  testNpc    = TriadNpcDB.Get().Find("Garima");
            Random    randStream = new Random();

            TriadGameSession solver = new TriadGameSession();
            solver.modifiers.AddRange(testNpc.Rules);
            solver.UpdateSpecialRules();

            for (int Idx = 0; Idx < numIterations; Idx++)
            {
                TriadGameData testData    = solver.StartGame(testDeck, testNpc.Deck, ETriadGameState.InProgressBlue);
                Random        sessionRand = new Random(randStream.Next());
                solver.SolverPlayRandomGame(testData, sessionRand);
            }

            timer.Stop();
            Logger.WriteLine("Solver testing finished, time taken:" + timer.ElapsedMilliseconds + "ms");

            float TicksToMs = 1000.0f / Stopwatch.Frequency;
            Logger.WriteLine(">> PlayRandomTurn.SelectSpot: " + (perfStats.PlayRandomTurnSelectSpot * TicksToMs) + "ms");
            Logger.WriteLine(">> PlayRandomTurn.SelectCard: " + (perfStats.PlayRandomTurnSelectCard * TicksToMs) + "ms");
            Logger.WriteLine(">> PlayRandomTurn.PlaceCard: " + (perfStats.PlayRandomTurnPlaceCard * TicksToMs) + "ms");
            Logger.WriteLine("  >> PlaceCard.OnPlaced: " + (perfStats.PlaceCardOnPlaced * TicksToMs) + "ms");
            Logger.WriteLine("  >> PlaceCard.OnPlacedMods: " + (perfStats.PlaceCardOnPlacedMods * TicksToMs) + "ms");
            Logger.WriteLine("  >> PlaceCard.Captures: " + (perfStats.PlaceCardCaptures * TicksToMs) + "ms");
            Logger.WriteLine("  >> PlaceCard.CapturesCombo: " + (perfStats.PlaceCardCapturesCombo * TicksToMs) + "ms");
            Logger.WriteLine("  >> PlaceCard.PostCaptures: " + (perfStats.PlaceCardPostCaptures * TicksToMs) + "ms");
            Logger.WriteLine("  >> PlaceCard.AllPlaced: " + (perfStats.PlaceCardAllPlaced * TicksToMs) + "ms");
#endif // DEBUG
        }
Exemple #10
0
        private bool UpdateNpcs(GameDataLists gameDataLists, Dictionary <string, TriadGameModifier> mapRuleNames)
        {
            Logger.WriteLine("Updating npc list...");

            TriadCardDB cardDB       = TriadCardDB.Get();
            TriadNpcDB  npcDB        = TriadNpcDB.Get();
            var         validDeckIds = new List <string>();

            foreach (var npcData in gameDataLists.npcs)
            {
                if (npcData.LinkedNpcId == null)
                {
                    continue;
                }

                if (npcData.LinkedNpcId.LinkedName == null || npcData.LinkedNpcId.LinkedLocation == null)
                {
                    continue;
                }

                TriadDeck npcDataDeck = new TriadDeck();
                foreach (var cardData in npcData.LinkedCardsFixed)
                {
                    npcDataDeck.knownCards.Add(cardDB.cards[cardData.Id]);
                }
                foreach (var cardData in npcData.LinkedCardsVariable)
                {
                    npcDataDeck.unknownCardPool.Add(cardDB.cards[cardData.Id]);
                }
                npcDataDeck.UpdateDeckId();
                validDeckIds.Add(npcDataDeck.deckId);

                // mistakes were made...
                TriadNpc npcOb = npcDB.FindByDeckId(npcDataDeck.deckId);
                int      npcId = (npcOb == null) ? npcDB.npcs.Count : npcOb.Id;

                if (npcOb != null)
                {
                    // ensure decks are the same
                    if (!npcOb.Deck.Equals(npcDataDeck))
                    {
                        Logger.WriteLine("FAILED npc update, id:{0} name:{1} is not matching cards!", npcId, npcData.LinkedNpcId.LinkedName.Name.GetCodeName());
                        return(false);
                    }
                }
                else
                {
                    while (npcDB.npcs.Count <= npcId)
                    {
                        npcDB.npcs.Add(null);
                    }

                    var listMods = new List <TriadGameModifier>();
                    foreach (var ruleData in npcData.LinkedRules)
                    {
                        listMods.Add(mapRuleNames[ruleData.Name.GetCodeName()]);
                    }

                    var listRewards = new List <TriadCard>();
                    foreach (var rewardData in npcData.LinkedRewards)
                    {
                        listRewards.Add(cardDB.cards[rewardData.LinkedCard.Id]);
                    }

                    npcOb = new TriadNpc(npcId, listMods, listRewards, npcDataDeck);

                    Logger.WriteLine(">> adding new npc: " + npcOb.ToString());
                    npcDB.npcs[npcId] = npcOb;
                }

                var linkedLoc = npcData.LinkedNpcId.LinkedLocation;
                linkedLoc.LinkedMap.GetCoords(linkedLoc.ScaledPosX, linkedLoc.ScaledPosZ, out npcOb.LocationX, out npcOb.LocationY);

                npcOb.Name.Text        = npcData.LinkedNpcId.LinkedName.Name.Text;
                npcOb.LocationMap.Text = npcData.LinkedNpcId.LinkedLocation.LinkedMap.LinkedPlace.Name.Text;
            }

            for (int idx = 0; idx < npcDB.npcs.Count; idx++)
            {
                TriadNpc npcOb = npcDB.npcs[idx];
                if (npcOb != null)
                {
                    if (!validDeckIds.Contains(npcOb.Deck.deckId))
                    {
                        Logger.WriteLine(">> removing npc: " + npcOb.ToString() + ", deck:" + npcOb.Deck.ToString());
                        npcDB.npcs[idx] = null;
                        continue;
                    }

                    if (npcOb.Id != idx)
                    {
                        Logger.WriteLine("FAILED npc update, index mismatch for npc[{0}].Id:{1}, Name:{2}", idx, npcOb.Id, npcOb.Name.GetCodeName());
                        return(false);
                    }
                }
            }

            return(true);
        }
Exemple #11
0
        public bool LoadFromJson(string jsonStr)
        {
            TriadCardDB cardDB = TriadCardDB.Get();
            TriadNpcDB  npcDB  = TriadNpcDB.Get();

            ownedCards.Clear();
            completedNpcs.Clear();
            lastDeck.Clear();
            favDecks.Clear();

            try
            {
                JsonParser.ObjectValue jsonOb = JsonParser.ParseJson(jsonStr);

                JsonParser.ObjectValue uiOb = (JsonParser.ObjectValue)jsonOb["ui", null];
                if (uiOb != null)
                {
                    JsonParser.Value BoolTrue  = new JsonParser.BoolValue(true);
                    JsonParser.Value BoolFalse = new JsonParser.BoolValue(false);

                    useXInput      = (JsonParser.BoolValue)uiOb["xInput", BoolTrue];
                    alwaysOnTop    = (JsonParser.BoolValue)uiOb["onTop", BoolFalse];
                    forcedLanguage = (JsonParser.StringValue)uiOb["lang", null];

                    TryGettingFloatValue(uiOb, "fontSize", ref fontSize);
                    TryGettingFloatValue(uiOb, "markerCard", ref markerDurationCard);
                    TryGettingFloatValue(uiOb, "markerSwap", ref markerDurationSwap);
                    TryGettingFloatValue(uiOb, "markerCactpot", ref markerDurationCactpot);

                    TryGettingIntValue(uiOb, "lastNpcId", ref lastNpcId);
                    TryGettingFloatValue(uiOb, "lastWidth", ref lastWidth);
                    TryGettingFloatValue(uiOb, "lastHeight", ref lastHeight);

                    fontSize = Math.Min(Math.Max(fontSize, 10), 40);
                }

                JsonParser.ObjectValue cloudOb = (JsonParser.ObjectValue)jsonOb["cloud", null];
                if (cloudOb != null)
                {
                    useCloudStorage = (JsonParser.BoolValue)cloudOb["use", JsonParser.BoolValue.Empty];
                    cloudToken      = (JsonParser.StringValue)cloudOb["token", null];
                }

                JsonParser.ArrayValue cardsArr = (JsonParser.ArrayValue)jsonOb["cards", JsonParser.ArrayValue.Empty];
                foreach (JsonParser.Value value in cardsArr.entries)
                {
                    int cardId = (JsonParser.IntValue)value;
                    ownedCards.Add(cardDB.cards[cardId]);
                }

                JsonParser.ArrayValue npcsArr = (JsonParser.ArrayValue)jsonOb["npcs", JsonParser.ArrayValue.Empty];
                foreach (JsonParser.Value value in npcsArr.entries)
                {
                    int npcId = (JsonParser.IntValue)value;
                    completedNpcs.Add(npcDB.npcs[npcId]);
                }

                JsonParser.ArrayValue decksArr = (JsonParser.ArrayValue)jsonOb["decks", JsonParser.ArrayValue.Empty];
                foreach (JsonParser.Value value in decksArr.entries)
                {
                    JsonParser.ObjectValue deckOb = (JsonParser.ObjectValue)value;
                    int npcId = (JsonParser.IntValue)deckOb["id"];

                    TriadNpc npc = TriadNpcDB.Get().npcs[npcId];
                    if (npc != null)
                    {
                        TriadDeck deckCards = new TriadDeck();

                        cardsArr = (JsonParser.ArrayValue)deckOb["cards", JsonParser.ArrayValue.Empty];
                        foreach (JsonParser.Value cardValue in cardsArr.entries)
                        {
                            int cardId = (JsonParser.IntValue)cardValue;
                            deckCards.knownCards.Add(cardDB.cards[cardId]);
                        }

                        lastDeck.Add(npc, deckCards);
                    }
                }

                JsonParser.ArrayValue favDecksArr = (JsonParser.ArrayValue)jsonOb["favDecks", JsonParser.ArrayValue.Empty];
                foreach (JsonParser.Value value in favDecksArr.entries)
                {
                    JsonParser.ObjectValue deckOb    = (JsonParser.ObjectValue)value;
                    TriadDeckNamed         deckCards = new TriadDeckNamed();

                    cardsArr = (JsonParser.ArrayValue)deckOb["cards", JsonParser.ArrayValue.Empty];
                    foreach (JsonParser.Value cardValue in cardsArr.entries)
                    {
                        int cardId = (JsonParser.IntValue)cardValue;
                        deckCards.knownCards.Add(cardDB.cards[cardId]);
                    }

                    if (deckCards.knownCards.Count > 0)
                    {
                        deckCards.Name = deckOb["name", JsonParser.StringValue.Empty];
                        favDecks.Add(deckCards);
                    }
                }

                JsonParser.ObjectValue imageHashesOb = (JsonParser.ObjectValue)jsonOb["images", null];
                if (imageHashesOb != null)
                {
                    customHashes = ImageHashDB.Get().LoadImageHashes(imageHashesOb);
                    ImageHashDB.Get().hashes.AddRange(customHashes);
                }
            }
            catch (Exception ex)
            {
                Logger.WriteLine("Loading failed! Exception:" + ex);
            }

            Logger.WriteLine("Loaded player cards: " + ownedCards.Count + ", npcs: " + completedNpcs.Count + ", hashes: " + customHashes.Count);
            return(ownedCards.Count > 0);
        }
Exemple #12
0
        public bool LoadFromXmlStream(Stream stream)
        {
            TriadCardDB cardDB = TriadCardDB.Get();
            TriadNpcDB  npcDB  = TriadNpcDB.Get();

            try
            {
                XmlDocument xdoc = new XmlDocument();
                xdoc.Load(stream);

                foreach (XmlNode testNode in xdoc.DocumentElement.ChildNodes)
                {
                    try
                    {
                        XmlElement testElem = (XmlElement)testNode;
                        if (testElem != null && testElem.Name == "ui")
                        {
                            int autoScanNum = int.Parse(testElem.GetAttribute("autoScan"));
                            useAutoScan = (autoScanNum == 1);
                        }
                        else if (testElem != null && testElem.Name == "cloud")
                        {
                            int useNum = int.Parse(testElem.GetAttribute("use"));
                            useCloudStorage = (useNum == 1);
                            cloudToken      = testElem.HasAttribute("token") ? testElem.GetAttribute("token") : null;
                        }
                        else if (testElem != null && testElem.Name == "card")
                        {
                            int cardId = int.Parse(testElem.GetAttribute("id"));
                            ownedCards.Add(cardDB.cards[cardId]);
                        }
                        else if (testElem != null && testElem.Name == "npc")
                        {
                            int npcId = int.Parse(testElem.GetAttribute("id"));
                            completedNpcs.Add(npcDB.npcs[npcId]);
                        }
                        else if (testElem != null && testElem.Name == "deck")
                        {
                            int      npcId = int.Parse(testElem.GetAttribute("id"));
                            TriadNpc npc   = TriadNpcDB.Get().npcs[npcId];
                            if (npc != null)
                            {
                                TriadDeck deckCards = new TriadDeck();
                                foreach (XmlAttribute attr in testElem.Attributes)
                                {
                                    if (attr.Name.StartsWith("card"))
                                    {
                                        string cardNumStr = attr.Name.Substring(4);
                                        int    cardNum    = int.Parse(cardNumStr);
                                        while (deckCards.knownCards.Count < (cardNum + 1))
                                        {
                                            deckCards.knownCards.Add(null);
                                        }

                                        int cardId = int.Parse(attr.Value);
                                        deckCards.knownCards[cardNum] = TriadCardDB.Get().cards[cardId];
                                    }
                                }

                                lastDeck.Add(npc, deckCards);
                            }
                        }
                        else
                        {
                            ImageHashData customHash = ImageHashDB.Get().LoadHashEntry(testElem);
                            if (customHash != null)
                            {
                                customHashes.Add(customHash);
                            }
                            else
                            {
                                ImagePatternDigit customDigit = ImageHashDB.Get().LoadDigitEntry(testElem);
                                if (customDigit.Value > 0)
                                {
                                    customDigits.Add(customDigit);
                                }
                            }
                        }
                    }
                    catch (Exception ex)
                    {
                        Logger.WriteLine("Loading failed! Exception:" + ex);
                    }
                }
            }
            catch (Exception ex)
            {
                Logger.WriteLine("Loading failed! Exception:" + ex);
            }

            return(ownedCards.Count > 0);
        }
Exemple #13
0
        public bool LoadFromJson(string jsonStr)
        {
            TriadCardDB cardDB = TriadCardDB.Get();
            TriadNpcDB  npcDB  = TriadNpcDB.Get();

            try
            {
                JsonParser.ObjectValue jsonOb = JsonParser.ParseJson(jsonStr);

                JsonParser.ObjectValue uiOb = (JsonParser.ObjectValue)jsonOb["ui", null];
                if (uiOb != null)
                {
                    useAutoScan = (JsonParser.BoolValue)uiOb["autoScan", JsonParser.BoolValue.Empty];
                }

                JsonParser.ObjectValue cloudOb = (JsonParser.ObjectValue)jsonOb["cloud", null];
                if (cloudOb != null)
                {
                    useCloudStorage = (JsonParser.BoolValue)cloudOb["use", JsonParser.BoolValue.Empty];
                    cloudToken      = (JsonParser.StringValue)cloudOb["token", null];
                }

                JsonParser.ArrayValue cardsArr = (JsonParser.ArrayValue)jsonOb["cards", JsonParser.ArrayValue.Empty];
                foreach (JsonParser.Value value in cardsArr.entries)
                {
                    int cardId = (JsonParser.IntValue)value;
                    ownedCards.Add(cardDB.cards[cardId]);
                }

                JsonParser.ArrayValue npcsArr = (JsonParser.ArrayValue)jsonOb["npcs", JsonParser.ArrayValue.Empty];
                foreach (JsonParser.Value value in npcsArr.entries)
                {
                    int npcId = (JsonParser.IntValue)value;
                    completedNpcs.Add(npcDB.npcs[npcId]);
                }

                JsonParser.ArrayValue decksArr = (JsonParser.ArrayValue)jsonOb["decks", JsonParser.ArrayValue.Empty];
                foreach (JsonParser.Value value in decksArr.entries)
                {
                    JsonParser.ObjectValue deckOb = (JsonParser.ObjectValue)value;
                    int npcId = (JsonParser.IntValue)deckOb["id"];

                    TriadNpc npc = TriadNpcDB.Get().npcs[npcId];
                    if (npc != null)
                    {
                        TriadDeck deckCards = new TriadDeck();

                        cardsArr = (JsonParser.ArrayValue)deckOb["cards", JsonParser.ArrayValue.Empty];
                        foreach (JsonParser.Value cardValue in cardsArr.entries)
                        {
                            int cardId = (JsonParser.IntValue)cardValue;
                            deckCards.knownCards.Add(cardDB.cards[cardId]);
                        }

                        lastDeck.Add(npc, deckCards);
                    }
                }

                JsonParser.ArrayValue favDecksArr = (JsonParser.ArrayValue)jsonOb["favDecks", JsonParser.ArrayValue.Empty];
                foreach (JsonParser.Value value in favDecksArr.entries)
                {
                    JsonParser.ObjectValue deckOb    = (JsonParser.ObjectValue)value;
                    TriadDeckNamed         deckCards = new TriadDeckNamed();

                    cardsArr = (JsonParser.ArrayValue)deckOb["cards", JsonParser.ArrayValue.Empty];
                    foreach (JsonParser.Value cardValue in cardsArr.entries)
                    {
                        int cardId = (JsonParser.IntValue)cardValue;
                        deckCards.knownCards.Add(cardDB.cards[cardId]);
                    }

                    if (deckCards.knownCards.Count > 0)
                    {
                        deckCards.Name = deckOb["name", JsonParser.StringValue.Empty];
                        favDecks.Add(deckCards);
                    }
                }

                JsonParser.ObjectValue imageHashesOb = (JsonParser.ObjectValue)jsonOb["images", null];
                if (imageHashesOb != null)
                {
                    customHashes = ImageHashDB.Get().LoadImageHashes(imageHashesOb);
                }

                JsonParser.ArrayValue digitHashesArr = (JsonParser.ArrayValue)jsonOb["digits", null];
                if (digitHashesArr != null)
                {
                    customDigits = ImageHashDB.Get().LoadDigitHashes(digitHashesArr);
                }
            }
            catch (Exception ex)
            {
                Logger.WriteLine("Loading failed! Exception:" + ex);
            }

            return(ownedCards.Count > 0);
        }
        public static void RunTest(string configPath, bool debugMode)
        {
            string testName = System.IO.Path.GetFileNameWithoutExtension(configPath);

            string configText = System.IO.File.ReadAllText(configPath);

            JsonParser.ObjectValue rootOb = JsonParser.ParseJson(configText);
            if (rootOb["type"] != "Screen")
            {
                return;
            }

            ScannerTriad.VerifyConfig configData = new ScannerTriad.VerifyConfig();
            configData.Load(rootOb);

            // setup npc & modifiers
            TriadNpc testNpc = TriadNpcDB.Get().Find(configData.npc);

            if (testNpc == null)
            {
                string exceptionMsg = string.Format("Test {0} failed! Can't find npc: {1}", testName, configData.npc);
                throw new Exception(exceptionMsg);
            }

            ScannerTriad.GameState screenGame = new ScannerTriad.GameState();
            if (mapValidationRules == null)
            {
                mapValidationRules = new Dictionary <string, TriadGameModifier>();
                foreach (TriadGameModifier mod in ImageHashDB.Get().modObjects)
                {
                    mapValidationRules.Add(mod.GetCodeName(), mod);
                }
            }

            foreach (string modName in configData.rules)
            {
                screenGame.mods.Add(mapValidationRules[modName]);
            }

            Func <ScannerTriad.VerifyCard, TriadCard> ConvertToTriadCard = configCard =>
            {
                if (configCard.state == ScannerTriad.ECardState.None)
                {
                    return(null);
                }
                if (configCard.state == ScannerTriad.ECardState.Hidden)
                {
                    return(TriadCardDB.Get().hiddenCard);
                }

                TriadCard matchingCard = !string.IsNullOrEmpty(configCard.name) ?
                                         TriadCardDB.Get().Find(configCard.name) :
                                         TriadCardDB.Get().Find(configCard.sides[0], configCard.sides[1], configCard.sides[2], configCard.sides[3]);

                if (matchingCard == null)
                {
                    string exceptionMsg = string.Format("Test {0} failed! Can't match validation card: '{1}' [{2},{3},{4},{5}]", testName,
                                                        configCard.name, configCard.sides[0], configCard.sides[1], configCard.sides[2], configCard.sides[3]);
                    throw new Exception(exceptionMsg);
                }

                return(matchingCard);
            };

            bool needsLockedBlue = false;

            for (int idx = 0; idx < 5; idx++)
            {
                screenGame.blueDeck[idx] = ConvertToTriadCard(configData.deckBlue[idx]);
                screenGame.redDeck[idx]  = ConvertToTriadCard(configData.deckRed[idx]);

                if (configData.deckBlue[idx].state == ScannerTriad.ECardState.Locked)
                {
                    needsLockedBlue = true;
                }
            }

            if (needsLockedBlue)
            {
                for (int idx = 0; idx < 5; idx++)
                {
                    if (configData.deckBlue[idx].state == ScannerTriad.ECardState.Visible)
                    {
                        screenGame.forcedBlueCard = screenGame.blueDeck[idx];
                        break;
                    }
                }
            }

            for (int idx = 0; idx < 9; idx++)
            {
                screenGame.board[idx]      = ConvertToTriadCard(configData.board[idx]);
                screenGame.boardOwner[idx] =
                    configData.board[idx].state == ScannerTriad.ECardState.PlacedBlue ? ETriadCardOwner.Blue :
                    configData.board[idx].state == ScannerTriad.ECardState.PlacedRed ? ETriadCardOwner.Red :
                    ETriadCardOwner.Unknown;
            }

            TriadGameScreenMemory screenMemory = new TriadGameScreenMemory {
                logScan = false
            };

            screenMemory.OnNewScan(screenGame, testNpc);
            screenMemory.gameSession.SolverFindBestMove(screenMemory.gameState, out int solverBoardPos, out TriadCard solverTriadCard, out TriadGameResultChance bestChance);

            if (bestChance.expectedResult == ETriadGameState.BlueLost && bestChance.winChance <= 0.0f && bestChance.drawChance <= 0.0f)
            {
                string exceptionMsg = string.Format("Test {0} failed! Can't find move!", testName);
                throw new Exception(exceptionMsg);
            }
        }
Exemple #15
0
        public bool Load()
        {
            List <TriadNpc> loadedNpcs  = new List <TriadNpc>();
            int             maxLoadedId = 0;

            List <TriadGameModifier> modObjects = new List <TriadGameModifier>();

            foreach (Type type in Assembly.GetAssembly(typeof(TriadGameModifier)).GetTypes())
            {
                if (type.IsSubclassOf(typeof(TriadGameModifier)))
                {
                    modObjects.Add((TriadGameModifier)Activator.CreateInstance(type));
                }
            }

            try
            {
                XmlDocument xdoc = new XmlDocument();
                xdoc.Load(AssetManager.Get().GetAsset(DBPath));

                foreach (XmlNode npcNode in xdoc.DocumentElement.ChildNodes)
                {
                    XmlElement npcElem = (XmlElement)npcNode;
                    if (npcElem != null && npcElem.Name == "npc")
                    {
                        try
                        {
                            List <TriadGameModifier> rules   = new List <TriadGameModifier>();
                            List <TriadCard>         rewards = new List <TriadCard>();
                            int[] deckA = new int[5];
                            int[] deckV = new int[5];

                            foreach (XmlNode innerNode in npcElem.ChildNodes)
                            {
                                XmlElement testElem = (XmlElement)innerNode;
                                if (testElem != null)
                                {
                                    if (testElem.Name == "rule")
                                    {
                                        rules.Add(ParseRule(testElem.GetAttribute("name"), modObjects));
                                    }
                                    else if (testElem.Name == "reward")
                                    {
                                        int cardId = int.Parse(testElem.GetAttribute("id"));
                                        rewards.Add(TriadCardDB.Get().cards[cardId]);
                                    }
                                    else if (testElem.Name == "deckA")
                                    {
                                        deckA[0] = int.Parse(testElem.GetAttribute("id0"));
                                        deckA[1] = int.Parse(testElem.GetAttribute("id1"));
                                        deckA[2] = int.Parse(testElem.GetAttribute("id2"));
                                        deckA[3] = int.Parse(testElem.GetAttribute("id3"));
                                        deckA[4] = int.Parse(testElem.GetAttribute("id4"));
                                    }
                                    else if (testElem.Name == "deckV")
                                    {
                                        deckV[0] = int.Parse(testElem.GetAttribute("id0"));
                                        deckV[1] = int.Parse(testElem.GetAttribute("id1"));
                                        deckV[2] = int.Parse(testElem.GetAttribute("id2"));
                                        deckV[3] = int.Parse(testElem.GetAttribute("id3"));
                                        deckV[4] = int.Parse(testElem.GetAttribute("id4"));
                                    }
                                }
                            }

                            TriadNpc newNpc = new TriadNpc(
                                int.Parse(npcElem.GetAttribute("id")),
                                WebUtility.HtmlDecode(npcElem.GetAttribute("name")),
                                WebUtility.HtmlDecode(npcElem.GetAttribute("location")),
                                rules,
                                rewards,
                                deckA,
                                deckV);

                            loadedNpcs.Add(newNpc);
                            maxLoadedId = Math.Max(maxLoadedId, newNpc.Id);
                        }
                        catch (Exception ex)
                        {
                            Logger.WriteLine("Loading failed! Exception:" + ex);
                        }
                    }
                }
            }
            catch (Exception ex)
            {
                Logger.WriteLine("Loading failed! Exception:" + ex);
            }

            if (loadedNpcs.Count > 0)
            {
                while (npcs.Count < (maxLoadedId + 1))
                {
                    npcs.Add(null);
                }

                foreach (TriadNpc npc in loadedNpcs)
                {
                    npcs[npc.Id] = npc;
                }
            }

            Logger.WriteLine("Loaded npcs: " + npcs.Count);
            return(loadedNpcs.Count > 0);
        }
Exemple #16
0
        private Dictionary <int, TriadNpc> ParseNpcs(string folderPath, Dictionary <int, TriadCard> cardMap)
        {
            int DataFormat = 2;

            Dictionary <int, TriadGameModifier> ruleMap    = ParseGameRules(folderPath);
            Dictionary <int, string>            npcNameMap = ParseNpcNames(folderPath);
            Dictionary <int, int>    npcTriadIdMap         = ParseNpcTriadIds(folderPath);
            Dictionary <int, int>    npcBaseIdMap          = ParseNpcTriadNpcIds(folderPath, npcTriadIdMap);
            Dictionary <int, string> npcLocationMap        = ParseNpcLocations(folderPath, npcBaseIdMap.Values.ToList());

            Dictionary <int, int>                  rewardMap   = (DataFormat == 1) ? ParseRewardItems(folderPath, cardMap) : null;
            Dictionary <string, TriadCard>         cardNameMap = (DataFormat == 2) ? BuildCardNameMap(cardMap) : null;
            Dictionary <string, TriadGameModifier> ruleNameMap = (DataFormat == 2) ? BuildRuleNameMap() : null;

            Dictionary <int, TriadNpc> loadedNpcs = new Dictionary <int, TriadNpc>();
            List <string[]>            npcData    = ParseCSVFile(folderPath + "TripleTriad.csv");

            if (npcData.Count > 0 && npcData[0].Length == 31)
            {
                for (int Idx = 0; Idx < npcData.Count; Idx++)
                {
                    int npcKey = int.Parse(npcData[Idx][0]);
                    if (npcKey <= 0 || !npcBaseIdMap.ContainsKey(npcKey))
                    {
                        continue;
                    }

                    int npcBaseId = npcBaseIdMap[npcKey];
                    int npcId     = npcTriadIdMap[npcKey];

                    List <int> cardsFixed = new List <int>();
                    List <int> cardsVar   = new List <int>();

                    if (DataFormat == 1)
                    {
                        cardsFixed.Add(int.Parse(npcData[Idx][1]));
                        cardsFixed.Add(int.Parse(npcData[Idx][2]));
                        cardsFixed.Add(int.Parse(npcData[Idx][3]));
                        cardsFixed.Add(int.Parse(npcData[Idx][4]));
                        cardsFixed.Add(int.Parse(npcData[Idx][5]));
                        for (int cardIdx = cardsFixed.Count - 1; cardIdx >= 0; cardIdx--)
                        {
                            if (cardsFixed[cardIdx] == 0)
                            {
                                cardsFixed.RemoveAt(cardIdx);
                            }
                            else
                            {
                                cardsFixed[cardIdx] = cardMap[cardsFixed[cardIdx]].Id;
                            }
                        }

                        cardsVar.Add(int.Parse(npcData[Idx][6]));
                        cardsVar.Add(int.Parse(npcData[Idx][7]));
                        cardsVar.Add(int.Parse(npcData[Idx][8]));
                        cardsVar.Add(int.Parse(npcData[Idx][9]));
                        cardsVar.Add(int.Parse(npcData[Idx][10]));
                        for (int cardIdx = cardsVar.Count - 1; cardIdx >= 0; cardIdx--)
                        {
                            if (cardsVar[cardIdx] == 0)
                            {
                                cardsVar.RemoveAt(cardIdx);
                            }
                            else
                            {
                                cardsVar[cardIdx] = cardMap[cardsVar[cardIdx]].Id;
                            }
                        }
                    }
                    else
                    {
                        for (int InnerIdx = 1; InnerIdx <= 5; InnerIdx++)
                        {
                            if (npcData[Idx][InnerIdx].Length > 0 && npcData[Idx][InnerIdx] != "0")
                            {
                                TriadCard matchingCard = cardNameMap[npcData[Idx][InnerIdx]];
                                cardsFixed.Add(matchingCard.Id);
                            }
                        }

                        for (int InnerIdx = 6; InnerIdx <= 10; InnerIdx++)
                        {
                            if (npcData[Idx][InnerIdx].Length > 0 && npcData[Idx][InnerIdx] != "0")
                            {
                                TriadCard matchingCard = cardNameMap[npcData[Idx][InnerIdx]];
                                cardsVar.Add(matchingCard.Id);
                            }
                        }
                    }

                    if (cardsFixed.Count == 0 && cardsVar.Count == 0)
                    {
                        continue;
                    }

                    List <TriadGameModifier> rules = new List <TriadGameModifier>();
                    if (DataFormat == 1)
                    {
                        int rule1 = int.Parse(npcData[Idx][11]);
                        if (rule1 != 0)
                        {
                            rules.Add(ruleMap[rule1]);
                        }
                        int rule2 = int.Parse(npcData[Idx][12]);
                        if (rule2 != 0)
                        {
                            rules.Add(ruleMap[rule2]);
                        }
                    }
                    else
                    {
                        if (npcData[Idx][11].Length > 0)
                        {
                            rules.Add(ruleNameMap[npcData[Idx][11]]);
                        }
                        if (npcData[Idx][12].Length > 0)
                        {
                            rules.Add(ruleNameMap[npcData[Idx][12]]);
                        }
                    }

                    List <TriadCard> rewardCards = new List <TriadCard>();
                    if (DataFormat == 1)
                    {
                        int[] rewardItems = new int[4] {
                            int.Parse(npcData[Idx][27]), int.Parse(npcData[Idx][28]), int.Parse(npcData[Idx][29]), int.Parse(npcData[Idx][30])
                        };
                        foreach (int itemId in rewardItems)
                        {
                            if (itemId > 0)
                            {
                                int       cardId = rewardMap[itemId];
                                TriadCard cardOb = cardMap[cardId];
                                rewardCards.Add(cardOb);
                            }
                        }
                    }
                    else
                    {
                        for (int InnerIdx = 27; InnerIdx <= 30; InnerIdx++)
                        {
                            if (npcData[Idx][InnerIdx].Length > 0 && npcData[Idx][InnerIdx] != "0")
                            {
                                string cardName = npcData[Idx][InnerIdx];
                                if (cardName.EndsWith(" Card"))
                                {
                                    cardName = cardName.Remove(cardName.Length - 5);
                                }

                                TriadCard matchingCard = cardNameMap[cardName];
                                rewardCards.Add(matchingCard);
                            }
                        }
                    }

                    string npcDesc      = npcNameMap[npcBaseId];
                    string locationDesc = npcLocationMap[npcBaseId];

                    TriadNpc npcOb = new TriadNpc(0, npcDesc, locationDesc, rules, rewardCards, cardsFixed.ToArray(), cardsVar.ToArray());
                    loadedNpcs.Add(npcId, npcOb);
                }
            }
            else
            {
                throw new Exception("Unable to parse npcs from csv!");
            }

            return(loadedNpcs);
        }
Exemple #17
0
        private bool UpdateNpcs(Dictionary <int, TriadNpc> npcMap)
        {
            TriadNpcDB npcDB      = TriadNpcDB.Get();
            int        newNpcId   = npcDB.npcs[npcDB.npcs.Count - 1].Id + 1;
            bool       hasChanges = false;

            foreach (KeyValuePair <int, TriadNpc> kvp in npcMap)
            {
                if (kvp.Key >= newNpcId)
                {
                    kvp.Value.Id = newNpcId;
                    newNpcId++;

                    while (npcDB.npcs.Count < newNpcId)
                    {
                        npcDB.npcs.Add(null);
                    }
                    npcDB.npcs[kvp.Value.Id] = kvp.Value;

                    Logger.WriteLine("Newly added npc: " + kvp.Value.ToString());
                    hasChanges = true;
                    continue;
                }

                TriadNpc npcMatch = npcDB.Find(kvp.Value.Name);
                if (npcMatch == null)
                {
                    foreach (TriadNpc testNpc in npcDB.npcs)
                    {
                        if (testNpc != null &&
                            HasMatchingRewards(testNpc.Rewards, kvp.Value.Rewards) &&
                            HasMatchingRules(testNpc.Rules, kvp.Value.Rules) &&
                            testNpc.Deck.Equals(kvp.Value.Deck))
                        {
                            Logger.WriteLine("Npc name remap: " + testNpc.ToString() + " => " + kvp.Value.Name);
                            npcMatch   = testNpc;
                            hasChanges = true;
                            break;
                        }
                    }
                }

                if (npcMatch != null)
                {
                    kvp.Value.Id             = npcMatch.Id;
                    npcDB.npcs[kvp.Value.Id] = kvp.Value;
                }
                else
                {
                    Logger.WriteLine("Newly added npc: " + kvp.Value.ToString());

                    kvp.Value.Id = newNpcId;
                    newNpcId++;
                    hasChanges = true;

                    while (npcDB.npcs.Count < newNpcId)
                    {
                        npcDB.npcs.Add(null);
                    }
                    npcDB.npcs[kvp.Value.Id] = kvp.Value;
                }
            }

            if (hasChanges)
            {
                npcDB.Save();
            }

            return(hasChanges);
        }
Exemple #18
0
        public EUpdateFlags OnNewScan(ScreenshotAnalyzer.GameStateTriad screenGame, TriadNpc selectedNpc)
        {
            EUpdateFlags updateFlags = EUpdateFlags.None;

            // check if game from screenshot can be continuation of cached one
            // is current state a continuation of last one?
            // ideally each blue turn is a capture until game resets = any card disappears from board
            // guess work for adding sense of persistence to screen decks
            bool bContinuesPrevState = (deckRed.deck == selectedNpc.Deck) && (lastScanNpc == selectedNpc);

            if (bContinuesPrevState)
            {
                for (int Idx = 0; Idx < gameState.board.Length; Idx++)
                {
                    bool bWasNull = gameState.board[Idx] == null;
                    bool bIsNull  = screenGame.board[Idx] == null;

                    if (!bWasNull && bIsNull)
                    {
                        bContinuesPrevState = false;
                        Logger.WriteLine("Can't continue previous state: board[" + Idx + "] disappeared ");
                    }
                }
            }
            else
            {
                Logger.WriteLine("Can't continue previous state: npc changed");
            }

            bool bModsChanged = (gameSession.modifiers.Count != screenGame.mods.Count) || !gameSession.modifiers.All(screenGame.mods.Contains);

            if (bModsChanged)
            {
                bHasSwapRule    = false;
                bHasRestartRule = false;
                bHasOpenRule    = false;
                gameSession.modifiers.Clear();
                gameSession.modifiers.AddRange(screenGame.mods);
                gameSession.specialRules = ETriadGameSpecialMod.None;
                gameSession.modFeatures  = TriadGameModifier.EFeature.None;
                foreach (TriadGameModifier mod in gameSession.modifiers)
                {
                    gameSession.modFeatures |= mod.GetFeatures();

                    // swap rule is bad for screenshot based analysis, no good way of telling what is out of place
                    if (mod is TriadGameModifierSwap)
                    {
                        bHasSwapRule = true;
                    }
                    else if (mod is TriadGameModifierSuddenDeath)
                    {
                        bHasRestartRule = true;
                    }
                    else if (mod is TriadGameModifierAllOpen)
                    {
                        bHasOpenRule = true;
                    }
                }

                updateFlags        |= EUpdateFlags.Modifiers;
                bContinuesPrevState = false;
                Logger.WriteLine("Can't continue previous state: modifiers changed");

                deckRed.SetSwappedCard(null, -1);
            }

            // wipe blue deck history when playing with new npc (or region modifiers have changed)
            bool bRemoveBlueHistory = bModsChanged || (lastScanNpc != selectedNpc);

            if (bRemoveBlueHistory)
            {
                blueDeckHistory.Clear();
                if (bHasSwapRule)
                {
                    Logger.WriteLine("Blue deck history cleared");
                }
            }

            bool bRedDeckChanged = (lastScanNpc != selectedNpc) || !IsDeckMatching(deckRed, screenGame.redDeck) || (deckRed.deck != selectedNpc.Deck);

            if (bRedDeckChanged)
            {
                updateFlags |= EUpdateFlags.RedDeck;
                deckRed.deck = selectedNpc.Deck;
                lastScanNpc  = selectedNpc;

                // needs to happen before any changed to board (gameState)
                UpdateAvailableRedCards(deckRed, screenGame.redDeck, screenGame.blueDeck,
                                        screenGame.board, deckBlue.cards, gameState.board, bContinuesPrevState);
            }

            bool bBlueDeckChanged = !IsDeckMatching(deckBlue, screenGame.blueDeck);

            if (bBlueDeckChanged)
            {
                updateFlags |= EUpdateFlags.BlueDeck;
                deckBlue.UpdateAvailableCards(screenGame.blueDeck);
            }

            gameSession.forcedBlueCard = screenGame.forcedBlueCard;
            gameState.state            = ETriadGameState.InProgressBlue;
            gameState.deckBlue         = deckBlue;
            gameState.deckRed          = deckRed;
            gameState.numCardsPlaced   = 0;

            bool bBoardChanged = false;

            for (int Idx = 0; Idx < gameState.board.Length; Idx++)
            {
                bool bWasNull = gameState.board[Idx] == null;
                bool bIsNull  = screenGame.board[Idx] == null;

                if (bWasNull && !bIsNull)
                {
                    bBoardChanged        = true;
                    gameState.board[Idx] = new TriadCardInstance(screenGame.board[Idx], screenGame.boardOwner[Idx]);
                    Logger.WriteLine("  board update: [" + Idx + "] " + gameState.board[Idx].owner + ": " + gameState.board[Idx].card.Name);
                }
                else if (!bWasNull && bIsNull)
                {
                    bBoardChanged        = true;
                    gameState.board[Idx] = null;
                }
                else if (!bWasNull && !bIsNull)
                {
                    if (gameState.board[Idx].owner != screenGame.boardOwner[Idx] ||
                        gameState.board[Idx].card != screenGame.board[Idx])
                    {
                        bBoardChanged        = true;
                        gameState.board[Idx] = new TriadCardInstance(screenGame.board[Idx], screenGame.boardOwner[Idx]);
                    }
                }

                gameState.numCardsPlaced += (gameState.board[Idx] != null) ? 1 : 0;
            }

            if (bBoardChanged)
            {
                updateFlags |= EUpdateFlags.Board;

                foreach (TriadGameModifier mod in gameSession.modifiers)
                {
                    mod.OnScreenUpdate(gameState);
                }
            }

            // start of game, do additional checks when swap rule is active
            if (bHasSwapRule && gameState.numCardsPlaced <= 1)
            {
                updateFlags |= DetectSwapOnGameStart();
            }

            Logger.WriteLine("OnNewScan> board:" + (bBoardChanged ? "changed" : "same") +
                             ", blue:" + (bBlueDeckChanged ? "changed" : "same") +
                             ", red:" + (bRedDeckChanged ? "changed" : "same") +
                             ", mods:" + (bModsChanged ? "changed" : "same") +
                             ", continuePrev:" + bContinuesPrevState +
                             " => " + ((updateFlags != EUpdateFlags.None) ? ("UPDATE[" + updateFlags + "]") : "skip"));

            return(updateFlags);
        }
Exemple #19
0
        public bool Load()
        {
            try
            {
                XmlDocument xdoc = new XmlDocument();
                xdoc.Load(AssetManager.Get().GetAsset(DBPath));

                foreach (XmlNode npcNode in xdoc.DocumentElement.ChildNodes)
                {
                    XmlElement npcElem = (XmlElement)npcNode;
                    if (npcElem != null && npcElem.Name == "npc")
                    {
                        try
                        {
                            List <TriadGameModifier> rules   = new List <TriadGameModifier>();
                            List <TriadCard>         rewards = new List <TriadCard>();
                            int[] deckA = new int[5];
                            int[] deckV = new int[5];

                            foreach (XmlNode innerNode in npcElem.ChildNodes)
                            {
                                XmlElement testElem = (XmlElement)innerNode;
                                if (testElem != null)
                                {
                                    if (testElem.Name == "rule")
                                    {
                                        int ruleId = int.Parse(testElem.GetAttribute("id"));
                                        rules.Add(TriadGameModifierDB.Get().mods[ruleId].Clone());
                                    }
                                    else if (testElem.Name == "reward")
                                    {
                                        int cardId = int.Parse(testElem.GetAttribute("id"));
                                        rewards.Add(TriadCardDB.Get().cards[cardId]);
                                    }
                                    else if (testElem.Name == "deckA")
                                    {
                                        deckA[0] = int.Parse(testElem.GetAttribute("id0"));
                                        deckA[1] = int.Parse(testElem.GetAttribute("id1"));
                                        deckA[2] = int.Parse(testElem.GetAttribute("id2"));
                                        deckA[3] = int.Parse(testElem.GetAttribute("id3"));
                                        deckA[4] = int.Parse(testElem.GetAttribute("id4"));
                                    }
                                    else if (testElem.Name == "deckV")
                                    {
                                        deckV[0] = int.Parse(testElem.GetAttribute("id0"));
                                        deckV[1] = int.Parse(testElem.GetAttribute("id1"));
                                        deckV[2] = int.Parse(testElem.GetAttribute("id2"));
                                        deckV[3] = int.Parse(testElem.GetAttribute("id3"));
                                        deckV[4] = int.Parse(testElem.GetAttribute("id4"));
                                    }
                                }
                            }

                            TriadNpc newNpc = new TriadNpc(
                                int.Parse(npcElem.GetAttribute("id")),
                                rules,
                                rewards,
                                deckA,
                                deckV);
                            newNpc.LocationX = int.Parse(npcElem.GetAttribute("mx"));
                            newNpc.LocationY = int.Parse(npcElem.GetAttribute("my"));

                            while (npcs.Count <= newNpc.Id)
                            {
                                npcs.Add(null);
                            }

                            npcs[newNpc.Id] = newNpc;
                        }
                        catch (Exception ex)
                        {
                            Logger.WriteLine("Loading failed! Exception:" + ex);
                        }
                    }
                }
            }
            catch (Exception ex)
            {
                Logger.WriteLine("Loading failed! Exception:" + ex);
            }

            Logger.WriteLine("Loaded npcs: " + npcs.Count);
            return(npcs.Count > 0);
        }