private async void DeleteDeck(Deck deck) { if (deck == null) { return; } var deckStats = DeckStatsList.Instance.DeckStats.FirstOrDefault(ds => ds.BelongsToDeck(deck)); if (deckStats != null) { if (deckStats.Games.Any()) { if (Config.Instance.KeepStatsWhenDeletingDeck) { DefaultDeckStats.Instance.GetDeckStats(deck.Class).Games.AddRange(deckStats.Games); DefaultDeckStats.Save(); Logger.WriteLine(string.Format("Moved deckstats for deck {0} to default stats", deck.Name), "Edit"); } else { try { foreach (var game in deckStats.Games) { game.DeleteGameFile(); } Logger.WriteLine("Deleted games from deck: " + deck.Name, "Edit"); } catch (Exception) { Logger.WriteLine("Error deleting games", "Edit"); } } } DeckStatsList.Instance.DeckStats.Remove(deckStats); DeckStatsList.Save(); Logger.WriteLine("Removed deckstats from deck: " + deck.Name, "Edit"); } if (HearthStatsAPI.IsLoggedIn && deck.HasHearthStatsId && await CheckHearthStatsDeckDeletion()) { HearthStatsManager.DeleteDeckAsync(deck, false, true); } DeckList.Instance.Decks.Remove(deck); DeckList.Save(); ; //DeckPickerList.RemoveDeck(deck); DeckPickerList.UpdateDecks(); ListViewDeck.ItemsSource = null; Logger.WriteLine("Deleted deck: " + deck.Name, "Edit"); }
private static async Task <Deck> ImportHearthPwn(string url) { try { var doc = await GetHtmlDoc(url); var deck = new Deck(); var deckName = HttpUtility.HtmlDecode(doc.DocumentNode.SelectSingleNode("//header/h2[contains(@class,'t-deck-title')]").InnerText); deck.Name = deckName; var cardNameNodes = doc.DocumentNode.SelectNodes("//td[contains(@class,'col-name')]//a[contains(@href,'/cards/') and contains(@class,'rarity')]"); var cardCountNodes = doc.DocumentNode.SelectNodes("//td[contains(@class,'col-name')]"); //<span class="t-deck-type-label">Midrange</span> var decktype = doc.DocumentNode.SelectSingleNode("//span[contains(@class,'t-deck-type-label')]").InnerText; if (decktype != "None" && Config.Instance.TagDecksOnImport) { if (!DeckList.Instance.AllTags.Contains(decktype)) { DeckList.Instance.AllTags.Add(decktype); DeckList.Save(); Helper.MainWindow.SortFilterDecksFlyout.LoadTags(DeckList.Instance.AllTags); Helper.MainWindow.TagControlEdit.LoadTags(DeckList.Instance.AllTags.Where(t => t != "All").ToList()); } deck.Tags.Add(decktype); } var cardNames = cardNameNodes.Select(cardNameNode => HttpUtility.HtmlDecode(cardNameNode.InnerText)); var cardCosts = cardCountNodes.Select(countNode => int.Parse(Regex.Match(countNode.LastChild.InnerText, @"\d+").Value)); var cardInfo = cardNames.Zip(cardCosts, (n, c) => new { Name = n, Count = c }); foreach (var info in cardInfo) { var card = Game.GetCardFromName(info.Name); card.Count = info.Count; deck.Cards.Add(card); if (string.IsNullOrEmpty(deck.Class) && card.PlayerClass != "Neutral") { deck.Class = card.PlayerClass; } } return(deck); } catch (Exception e) { Logger.WriteLine(e.ToString(), "DeckImporter"); return(null); } }
internal void BtnUnarchiveDeck_Click(object sender, RoutedEventArgs e) { foreach (var deck in DeckPickerList.SelectedDecks) { ArchiveDeck(deck, false, false); } DeckList.Save(); DeckPickerList.UpdateDecks(); DeckPickerList.SelectDeckAndAppropriateView(DeckPickerList.SelectedDecks.FirstOrDefault()); UpdateMenuItemVisibility(); DeckPickerList.UpdateArchivedClassVisibility(); }
public static void SaveDeck(Deck deck, bool invokeApi = true) { deck.Edited(); DeckList.Instance.Decks.Add(deck); DeckList.Save(); Core.MainWindow.DeckPickerList.SelectDeckAndAppropriateView(deck); Core.MainWindow.DeckPickerList.UpdateDecks(forceUpdate: new[] { deck }); Core.MainWindow.SelectDeck(deck, true); if (invokeApi) { DeckManagerEvents.OnDeckCreated.Execute(deck); } }
public void ArchiveDeck(Deck deck, bool archive, bool saveAndUpdate = true) { if (deck == null) { return; } var oldArchived = deck.Archived; if (oldArchived == archive) { return; } deck.Archived = archive; deck.Edited(); try { if (saveAndUpdate) { DeckList.Save(); DeckPickerList.UpdateDecks(); if (archive) { SelectDeck(null, true); } else { DeckPickerList.SelectDeckAndAppropriateView(deck); UpdateMenuItemVisibility(); } DeckPickerList.UpdateArchivedClassVisibility(); } var archivedLog = archive ? "archived" : "unarchived"; Logger.WriteLine(String.Format("Successfully {0} deck: {1}", archivedLog, deck.Name), "ArchiveDeck"); if (Config.Instance.HearthStatsAutoUploadNewDecks && HearthStatsAPI.IsLoggedIn) { Logger.WriteLine(String.Format("auto uploading {0} deck", archivedLog), "ArchiveDeck"); HearthStatsManager.UpdateDeckAsync(deck, background: true); } } catch (Exception) { Logger.WriteLine(String.Format("Error {0} deck", archive ? "archiving" : "unarchiving", deck.Name), "ArchiveDeck"); } }
internal async void BtnCloneDeck_Click(object sender, RoutedEventArgs e) { var cloneStats = (await this.ShowMessageAsync("Clone game history?", "(Cloned games do not count towards class or overall stats.)", MessageDialogStyle.AffirmativeAndNegative, new MetroDialogSettings { AffirmativeButtonText = "clone history", NegativeButtonText = "do not clone history" })) == MessageDialogResult.Affirmative; var deck = DeckPickerList.SelectedDecks.FirstOrDefault(); var clone = (Deck)deck.CloneWithNewId(false); var originalStats = deck.DeckStats; clone.ResetHearthstatsIds(); clone.Versions.ForEach(v => v.ResetHearthstatsIds()); clone.Archived = false; DeckList.Instance.Decks.Add(clone); DeckList.Save(); var newStatsEntry = DeckStatsList.Instance.DeckStats.FirstOrDefault(ds => ds.BelongsToDeck(clone)); if (newStatsEntry == null) { newStatsEntry = new DeckStats(clone); DeckStatsList.Instance.DeckStats.Add(newStatsEntry); } if (cloneStats) { foreach (var game in originalStats.Games) { newStatsEntry.AddGameResult(game.CloneWithNewId()); } Logger.WriteLine("cloned gamestats", "Edit"); } DeckStatsList.Save(); DeckPickerList.SelectDeckAndAppropriateView(clone); if (Config.Instance.HearthStatsAutoUploadNewDecks && HearthStatsAPI.IsLoggedIn) { HearthStatsManager.UploadDeckAsync(clone); } }
private void DeleteTag(string tag) { if (DeckList.Instance.AllTags.Contains(tag)) { DeckList.Instance.AllTags.Remove(tag); foreach (var deck in DeckList.Instance.Decks.Where(deck => deck.Tags.Contains(tag))) { deck.Tags.Remove(tag); } DeckList.Save(); Core.MainWindow.ReloadTags(); Core.MainWindow.DeckPickerList.UpdateDecks(); } }
private static Deck CreateDungeonDeck(string playerClass) { Log.Info($"Creating new {playerClass} dungeon run deck"); var deck = DungeonRun.GetDefaultDeck(playerClass); if (deck == null) { Log.Info($"Could not find default deck for {playerClass}"); return(null); } DeckList.Instance.Decks.Add(deck); DeckList.Save(); Core.MainWindow.DeckPickerList.UpdateDecks(); Core.MainWindow.SelectDeck(deck, true); return(deck); }
public void SaveDeck() { if (!_noteChanged || _currentDeck == null) { return; } DeckList.Save(); if (Config.Instance.HearthStatsAutoUploadNewDecks && HearthStatsAPI.IsLoggedIn) { Log.Info($"auto updating {_currentDeck} deck"); HearthStatsManager.UpdateDeckAsync(_currentDeck, background: true).Forget(); } _noteChanged = false; BtnSave.IsEnabled = false; Core.MainWindow.DeckPickerList.UpdateDecks(); }
public void SaveDeck() { if (!_noteChanged || _currentDeck == null) { return; } DeckList.Save(); if (Config.Instance.HearthStatsAutoUploadNewDecks && HearthStatsAPI.IsLoggedIn) { Logger.WriteLine(string.Format("auto updating {0} deck", _currentDeck), "NoteDialog"); HearthStatsManager.UpdateDeckAsync(_currentDeck, background: true); } _noteChanged = false; BtnSave.IsEnabled = false; Helper.MainWindow.DeckPickerList.UpdateDecks(); }
public static void ImportDecks(IEnumerable <ImportedDeck> decks, bool brawl, bool importNew = true, bool updateExisting = true, bool select = true) { var imported = ImportDecksTo(DeckList.Instance.Decks, decks, brawl, importNew, updateExisting); if (!imported.Any()) { return; } DeckList.Save(); Core.MainWindow.DeckPickerList.UpdateDecks(); Core.MainWindow.UpdateIntroLabelVisibility(); if (select) { Core.MainWindow.SelectDeck(imported.First(), true); } Core.UpdatePlayerCards(true); }
private static Deck CreateDungeonDeck(string playerClass, CardSet set) { var shrine = Core.Game.Player.Board.FirstOrDefault(x => x.HasTag(GameTag.SHRINE))?.CardId; Log.Info($"Creating new {playerClass} dungeon run deck (CardSet={set}, Shrine={shrine})"); var deck = DungeonRun.GetDefaultDeck(playerClass, set, shrine); if (deck == null) { Log.Info($"Could not find default deck for {playerClass} in card set {set} with Shrine={shrine}"); return(null); } DeckList.Instance.Decks.Add(deck); DeckList.Save(); Core.MainWindow.DeckPickerList.UpdateDecks(); Core.MainWindow.SelectDeck(deck, true); return(deck); }
private void FixTagOrder() { var changed = false; if (DeckList.Instance.AllTags.IndexOf("All") != 0) { MoveTag("All", DeckList.Instance.AllTags.IndexOf("All"), 0); changed = true; } if (DeckList.Instance.AllTags.IndexOf("None") != 1) { MoveTag("None", DeckList.Instance.AllTags.IndexOf("None"), 1); changed = true; } if (changed) { DeckList.Save(); } }
private void TagControlOnDeleteTag(SortFilterDecks sender, string tag) { if (DeckList.Instance.AllTags.Contains(tag)) { DeckList.Instance.AllTags.Remove(tag); foreach (var deck in DeckList.Instance.Decks.Where(deck => deck.Tags.Contains(tag))) { deck.Tags.Remove(tag); } //if(Helper.MainWindow.NewDeck.Tags.Contains(tag)) // Helper.MainWindow.NewDeck.Tags.Remove(tag); DeckList.Save(); Helper.MainWindow.SortFilterDecksFlyout.LoadTags(DeckList.Instance.AllTags); Helper.MainWindow.TagControlEdit.LoadTags(DeckList.Instance.AllTags.Where(t => t != "All" && t != "None").ToList()); //Helper.MainWindow.DeckPickerList.UpdateList(); Helper.MainWindow.DeckPickerList.UpdateDecks(); } }
private void SortFilterDecksFlyoutOnSelectedTagsChanged() { //only set tags if tags were changed in "My Decks" if (Name == "SortFilterDecksFlyout") { var tags = Tags.Where(tag => tag.Selected).Select(tag => tag.Name).ToList(); //Helper.MainWindow.DeckPickerList.SetSelectedTags(tags); Config.Instance.SelectedTags = tags; Config.Save(); Helper.MainWindow.DeckPickerList.UpdateDecks(); Helper.MainWindow.StatsWindow.StatsControl.LoadOverallStats(); Helper.MainWindow.DeckStatsFlyout.LoadOverallStats(); } else if (Name == "TagControlEdit") { var tags = Tags.Where(tag => tag.Selected).Select(tag => tag.Name).ToList(); DeckList.Instance.ActiveDeck.Tags = new List <string>(tags); Helper.MainWindow.DeckPickerList.UpdateDecks(); DeckList.Save(); ; Helper.MainWindow.UpdateQuickFilterItemSource(); } }
private void SortFilterDecksFlyoutOnSelectedTagsChanged() { //only set tags if tags were changed in "My Decks" if (Name == nameof(Core.MainWindow.SortFilterDecksFlyout)) { var tags = Tags.Where(tag => tag.Selected == true).Select(tag => tag.Name).ToList(); Config.Instance.SelectedTags = tags; Config.Save(); Core.MainWindow.DeckPickerList.UpdateDecks(); } else if (Name == nameof(Core.MainWindow.TagControlEdit)) { var tags = Tags.Where(tag => tag.Selected == true).Select(tag => tag.Name).ToList(); var ignore = Tags.Where(tag => tag.Selected == null).Select(tag => tag.Name).ToList(); foreach (var deck in Core.MainWindow.DeckPickerList.SelectedDecks) { var keep = deck.Tags.Intersect(ignore); deck.Tags = new List <string>(tags.Concat(keep)); deck.Edited(); } Core.MainWindow.DeckPickerList.UpdateDecks(false); DeckList.Save(); } }
internal async void BtnName_Click(object sender, RoutedEventArgs e) { var deck = DeckList.Instance.ActiveDeck; if (deck == null) { return; } var settings = new MetroDialogSettings { AffirmativeButtonText = "set", NegativeButtonText = "cancel", DefaultText = deck.Name }; var newName = await this.ShowInputAsync("Set deck name", "", settings); if (!string.IsNullOrEmpty(newName) && deck.Name != newName) { deck.Name = newName; DeckList.Save(); DeckPickerList.UpdateDecks(); if (Config.Instance.HearthStatsAutoUploadNewDecks && HearthStatsAPI.IsLoggedIn) { HearthStatsManager.UpdateDeckAsync(deck, true, true); } } }
private static Deck CreateDungeonDeck(string playerClass, CardSet set, bool isPVPDR, List <int> selectedDeck = null, Card loadout = null) { var shrine = Core.Game.Player.Board.FirstOrDefault(x => x.HasTag(GameTag.SHRINE))?.CardId; Log.Info($"Creating new {playerClass} dungeon run deck (CardSet={set}, Shrine={shrine}, SelectedDeck={selectedDeck != null})"); var deck = selectedDeck == null ? DungeonRun.GetDefaultDeck(playerClass, set, shrine) : DungeonRun.GetDeckFromDbfIds(playerClass, set, isPVPDR, selectedDeck); if (deck == null) { Log.Info($"Could not find default deck for {playerClass} in card set {set} with Shrine={shrine}"); return(null); } if (loadout != null && selectedDeck != null && !selectedDeck.Contains(loadout.DbfIf)) { deck.Cards.Add(loadout); } DeckList.Instance.Decks.Add(deck); DeckList.Save(); Core.MainWindow.DeckPickerList.UpdateDecks(); Core.MainWindow.SelectDeck(deck, true); return(deck); }
private void MoveGameToOtherDeck(List <GameStats> selectedGames) { if (selectedGames == null) { return; } var heroes = new Dictionary <string, int>(); foreach (var game in selectedGames) { if (!heroes.ContainsKey(game.PlayerHero)) { heroes.Add(game.PlayerHero, 0); } heroes[game.PlayerHero]++; } var heroPlayed = heroes.Any() ? heroes.OrderByDescending(x => x.Value).First().Key : "Any"; var possibleTargets = DeckList.Instance.Decks.Where(d => d.Class == heroPlayed || heroPlayed == "Any"); var dialog = new MoveGameDialog(possibleTargets); if (Config.Instance.StatsInWindow) { dialog.Owner = Core.Windows.StatsWindow; } else { dialog.Owner = Helper.MainWindow; } dialog.ShowDialog(); var selectedDeck = dialog.SelectedDeck; if (selectedDeck == null) { return; } foreach (var game in selectedGames) { var defaultDeck = DefaultDeckStats.Instance.DeckStats.FirstOrDefault(ds => ds.Games.Contains(game)); if (defaultDeck != null) { defaultDeck.Games.Remove(game); DefaultDeckStats.Save(); } else { var deck = DeckList.Instance.Decks.FirstOrDefault(d => game.DeckId == d.DeckId); if (deck != null) { deck.DeckStats.Games.Remove(game); } } game.PlayerDeckVersion = dialog.SelectedVersion; game.HearthStatsDeckVersionId = selectedDeck.GetVersion(dialog.SelectedVersion).HearthStatsDeckVersionId; game.DeckId = selectedDeck.DeckId; game.DeckName = selectedDeck.Name; selectedDeck.DeckStats.Games.Add(game); if (HearthStatsAPI.IsLoggedIn && Config.Instance.HearthStatsAutoUploadNewGames) { HearthStatsManager.MoveMatchAsync(game, selectedDeck, background: true); } } DeckStatsList.Save(); DeckList.Save(); Refresh(); Core.MainWindow.DeckPickerList.UpdateDecks(); }
internal async void BtnCloneSelectedVersion_Click(object sender, RoutedEventArgs e) { var deck = DeckPickerList.SelectedDecks.FirstOrDefault(); if (deck == null) { return; } var cloneStats = (await this.ShowMessageAsync("Clone game history?", "(Cloned games do not count towards class or overall stats.)", MessageDialogStyle.AffirmativeAndNegative, new MetroDialogSettings { AffirmativeButtonText = "clone history", NegativeButtonText = "do not clone history" })) == MessageDialogResult.Affirmative; var clone = (Deck)deck.CloneWithNewId(false); // bug #1316 - ResetVersions needs the current version as an argument clone.ResetVersions(); clone.ResetHearthstatsIds(); clone.Archived = false; var originalStatsEntry = clone.DeckStats; /*while(DeckList.DecksList.Any(d => d.Name == clone.Name)) * { * var settings = new MetroDialogSettings {AffirmativeButtonText = "Set", DefaultText = clone.Name}; * var name = * await * this.ShowInputAsync("Name already exists", "You already have a deck with that name, please select a different one.", settings); * * if(string.IsNullOrEmpty(name)) * return; * * clone.Name = name; * }*/ DeckList.Instance.Decks.Add(clone); DeckPickerList.UpdateDecks(); DeckList.Save(); var newStatsEntry = DeckStatsList.Instance.DeckStats.FirstOrDefault(ds => ds.BelongsToDeck(clone)); if (newStatsEntry == null) { newStatsEntry = new DeckStats(clone); DeckStatsList.Instance.DeckStats.Add(newStatsEntry); } //clone game stats if (cloneStats) { foreach (var game in originalStatsEntry.Games) { newStatsEntry.AddGameResult(game.CloneWithNewId()); } Logger.WriteLine("cloned gamestats (version)", "Edit"); } DeckStatsList.Save(); //DeckPickerList.UpdateList(); DeckPickerList.SelectDeckAndAppropriateView(clone); if (Config.Instance.HearthStatsAutoUploadNewDecks && HearthStatsAPI.IsLoggedIn) { HearthStatsManager.UploadDeckAsync(clone); } }
private void MoveGameToOtherDeck(GameStats selectedGame) { if (selectedGame == null) { return; } var heroes = new Dictionary <string, int>(); foreach (var turn in selectedGame.TurnStats) { foreach (var play in turn.Plays) { if (!play.Type.ToString().Contains("Player")) { continue; } var hero = Game.GetCardFromId(play.CardId).PlayerClass; if (hero == null) { continue; } if (!heroes.ContainsKey(hero)) { heroes.Add(hero, 0); } heroes[hero]++; } } var heroPlayed = heroes.Any() ? heroes.OrderByDescending(x => x.Value).First().Key : "Any"; var possibleTargets = DeckList.Instance.Decks.Where(d => d.Class == heroPlayed || heroPlayed == "Any"); var dialog = new MoveGameDialog(possibleTargets); if (Config.Instance.StatsInWindow) { dialog.Owner = Helper.MainWindow.StatsWindow; } else { dialog.Owner = Helper.MainWindow; } dialog.ShowDialog(); var selectedDeck = dialog.SelectedDeck; if (selectedDeck == null) { return; } var defaultDeck = DefaultDeckStats.Instance.DeckStats.FirstOrDefault(ds => ds.Games.Contains(selectedGame)); if (defaultDeck != null) { defaultDeck.Games.Remove(selectedGame); DefaultDeckStats.Save(); } else { _deck.DeckStats.Games.Remove(selectedGame); } selectedGame.PlayerDeckVersion = selectedDeck.Version; //move to latest version selectedGame.HearthStatsDeckVersionId = selectedDeck.HearthStatsDeckVersionId; selectedDeck.DeckStats.Games.Add(selectedGame); DeckStatsList.Save(); DeckList.Save(); ; Refresh(); Helper.MainWindow.DeckPickerList.UpdateDecks(); if (HearthStatsAPI.IsLoggedIn && Config.Instance.HearthStatsAutoUploadNewGames) { HearthStatsManager.MoveMatchAsync(selectedGame, selectedDeck, background: true); } }
public static void UpdateDungeonRunDeck(DungeonInfo info) { if (!Config.Instance.DungeonAutoImport) { return; } Log.Info($"Found dungeon run deck Set={((CardSet)info.CardSet).ToString()}"); var baseDeck = info.SelectedDeck ?? new List <int>(); var allCards = info.DbfIds?.ToList() ?? new List <int>(); if (baseDeck.All(x => allCards.Contains(x))) { if (info.PlayerChosenLoot > 0) { var loot = new[] { info.LootA, info.LootB, info.LootC }; var chosen = loot[info.PlayerChosenLoot - 1]; for (var i = 1; i < chosen.Count; i++) { allCards.Add(chosen[i]); } } if (info.PlayerChosenTreasure > 0) { allCards.Add(info.Treasure[info.PlayerChosenTreasure - 1]); } } else { allCards = baseDeck; } var cards = allCards.GroupBy(x => x).Select(x => { var card = Database.GetCardFromDbfId(x.Key, false); if (card == null) { return(null); } card.Count = x.Count(); return(card); }).Where(x => x != null).ToList(); var loadoutCardId = info.LoadoutCardId; var loadout = loadoutCardId != null?Database.GetCardFromId(loadoutCardId) : null; if (loadout != null && !allCards.Contains(loadout.DbfIf)) { cards.Add(loadout); } if (!Config.Instance.DungeonRunIncludePassiveCards) { cards.RemoveAll(c => !c.Collectible && c.HideStats); } var cardSet = (CardSet)info.CardSet; string playerClass = null; if (cardSet == CardSet.ULDUM && loadout != null) { playerClass = DungeonRun.GetUldumHeroPlayerClass(loadout.PlayerClass); } else { if (allCards.Count == 10) { playerClass = allCards.Select(x => Database.GetCardFromDbfId(x).PlayerClass).FirstOrDefault(x => x != null)?.ToUpperInvariant(); } if (playerClass == null) { playerClass = ((CardClass)info.HeroCardClass).ToString().ToUpperInvariant(); } } var deck = DeckList.Instance.Decks.FirstOrDefault(x => x.IsDungeonDeck && x.Class.ToUpperInvariant() == playerClass.ToUpperInvariant() && !(x.IsDungeonRunCompleted ?? false) && x.Cards.All(e => cards.Any(c => c.Id == e.Id && c.Count >= e.Count))); if (deck == null && (deck = CreateDungeonDeck(playerClass, cardSet, info.SelectedDeck, loadout)) == null) { Log.Info($"No existing deck - can't find default deck for {playerClass}"); return; } if (!info.RunActive && (cardSet == CardSet.ULDUM || cardSet == CardSet.DALARAN)) { Log.Info($"Inactive run for Set={cardSet.ToString()} - this is a new run"); return; } if (cards.All(c => deck.Cards.Any(e => c.Id == e.Id && c.Count == e.Count))) { Log.Info("No new cards"); return; } deck.Cards.Clear(); Helper.SortCardCollection(cards, false); foreach (var card in cards) { deck.Cards.Add(card); } deck.LastEdited = DateTime.Now; DeckList.Save(); Core.UpdatePlayerCards(true); Log.Info("Updated dungeon run deck"); }
public static async Task Export(Deck deck) { if (deck == null) { return; } string Current_Clipboard = ""; try { if (Config.Instance.ExportPasteClipboard && Clipboard.ContainsText()) { Current_Clipboard = Clipboard.GetText(); } Logger.WriteLine(string.Format("Exporting " + deck.GetDeckInfo()), "DeckExporter"); var hsHandle = User32.GetHearthstoneWindow(); if (!User32.IsHearthstoneInForeground()) { //restore window and bring to foreground User32.ShowWindow(hsHandle, User32.SwRestore); User32.SetForegroundWindow(hsHandle); //wait it to actually be in foreground, else the rect might be wrong await Task.Delay(500); } if (!User32.IsHearthstoneInForeground()) { MessageBox.Show("Can't find Heartstone window."); Logger.WriteLine("Can't find Hearthstone window.", "DeckExporter"); return; } Logger.WriteLine("Waiting for " + Config.Instance.ExportStartDelay + " seconds before starting the export process", "DeckExporter"); await Task.Delay(Config.Instance.ExportStartDelay * 1000); var hsRect = User32.GetHearthstoneRect(false); var ratio = (4.0 / 3.0) / ((double)hsRect.Width / hsRect.Height); var searchBoxPos = new Point((int)(GetXPos(Config.Instance.ExportSearchBoxX, hsRect.Width, ratio)), (int)(Config.Instance.ExportSearchBoxY * hsRect.Height)); var cardPosX = GetXPos(Config.Instance.ExportCard1X, hsRect.Width, ratio); var card2PosX = GetXPos(Config.Instance.ExportCard2X, hsRect.Width, ratio); var cardPosY = Config.Instance.ExportCardsY * hsRect.Height; Helper.MainWindow.Overlay.ForceHidden = true; Helper.MainWindow.Overlay.UpdatePosition(); if (Config.Instance.AutoClearDeck) { await ClearDeck(hsRect.Width, hsRect.Height, hsHandle, ratio); } if (Config.Instance.ExportSetDeckName) { await SetDeckName(deck.Name, ratio, hsRect.Width, hsRect.Height, hsHandle); } await ClickAllCrystal(ratio, hsRect.Width, hsRect.Height, hsHandle); Logger.WriteLine("Creating deck...", "DeckExporter"); deck.MissingCards.Clear(); foreach (var card in deck.Cards) { var missingCardsCount = await AddCardToDeck(card, searchBoxPos, cardPosX, card2PosX, cardPosY, hsRect.Height, hsRect.Width, hsHandle); if (missingCardsCount < 0) { return; } if (missingCardsCount > 0) { var missingCard = (Card)card.Clone(); missingCard.Count = missingCardsCount; deck.MissingCards.Add(missingCard); } } if (deck.MissingCards.Any()) { DeckList.Save(); } // Clear search field now all cards have been entered await ClickOnPoint(hsHandle, searchBoxPos); SendKeys.SendWait("{DELETE}"); SendKeys.SendWait("{ENTER}"); if (Config.Instance.ExportPasteClipboard) { Clipboard.Clear(); } Logger.WriteLine("Done creating deck.", "DeckExporter"); } catch (Exception e) { Logger.WriteLine("Error exporting deck: " + e, "DeckExporter"); } finally { Helper.MainWindow.Overlay.ForceHidden = false; Helper.MainWindow.Overlay.UpdatePosition(); if (Config.Instance.ExportPasteClipboard && Current_Clipboard != "") { Clipboard.SetText(Current_Clipboard); } } }
public static void ImportDecks(IEnumerable <ImportedDeck> decks, bool brawl, bool importNew = true, bool updateExisting = true, bool select = true) { Deck toSelect = null; foreach (var deck in decks) { if (deck.SelectedImportOption is NewDeck) { if (!importNew) { continue; } Log.Info($"Saving {deck.Deck.Name} as new deck."); var newDeck = new Deck { Class = deck.Class, Name = deck.Deck.Name, HsId = deck.Deck.Id, Cards = new ObservableCollection <Card>(deck.Deck.Cards.Select(x => { var card = Database.GetCardFromId(x.Id); card.Count = x.Count; return(card); })), LastEdited = DateTime.Now, IsArenaDeck = false }; if (brawl) { newDeck.Tags.Add("Brawl"); newDeck.Name = Helper.ParseDeckNameTemplate(Config.Instance.BrawlDeckNameTemplate, newDeck); } DeckList.Instance.Decks.Add(newDeck); toSelect = newDeck; } else { if (!updateExisting) { continue; } var existing = deck.SelectedImportOption as ExistingDeck; if (existing == null) { continue; } var target = existing.Deck; target.HsId = deck.Deck.Id; if (brawl && !target.Tags.Any(x => x.ToUpper().Contains("BRAWL"))) { target.Tags.Add("Brawl"); } if (existing.NewVersion.Major == 0) { Log.Info($"Assinging id to existing deck: {deck.Deck.Name}."); } else { Log.Info($"Saving {deck.Deck.Name} as {existing.NewVersion.ShortVersionString} (prev={target.Version.ShortVersionString})."); DeckList.Instance.Decks.Remove(target); var oldDeck = (Deck)target.Clone(); oldDeck.Versions = new List <Deck>(); target.Name = deck.Deck.Name; target.LastEdited = DateTime.Now; target.Versions.Add(oldDeck); target.Version = existing.NewVersion; target.SelectedVersion = existing.NewVersion; target.HearthStatsDeckVersionId = ""; target.Cards.Clear(); var cards = deck.Deck.Cards.Select(x => { var card = Database.GetCardFromId(x.Id); card.Count = x.Count; return(card); }); foreach (var card in cards) { target.Cards.Add(card); } var clone = (Deck)target.Clone(); DeckList.Instance.Decks.Add(clone); toSelect = clone; } } } DeckList.Save(); Core.MainWindow.DeckPickerList.UpdateDecks(); Core.MainWindow.UpdateIntroLabelVisibility(); if (select && toSelect != null) { Core.MainWindow.SelectDeck(toSelect, true); } Core.UpdatePlayerCards(true); }
public static void UpdateDungeonRunDeck(DungeonInfo info, bool isPVPDR) { if (!Config.Instance.DungeonAutoImport) { return; } var isNewPVPDR = isPVPDR && !info.RunActive && info.SelectedLoadoutTreasureDbId > 0; Log.Info($"Found dungeon run deck Set={(CardSet)info.CardSet}, PVPDR={isPVPDR} (new={isNewPVPDR})"); var allCards = info.DbfIds?.ToList() ?? new List <int>(); // New PVPDR runs have all non-loadout cards in the DbfIds. We still add the picked loadout below. // So we don't want to replace allCards with baseDeck, as backDeck is empty, and we don't want to add // any loot or treasure, as these will be the ones from a previous run, if they exist. if (!isNewPVPDR) { var baseDeck = info.SelectedDeck ?? new List <int>(); if (baseDeck.All(x => allCards.Contains(x))) { if (info.PlayerChosenLoot > 0) { var loot = new[] { info.LootA, info.LootB, info.LootC }; var chosen = loot[info.PlayerChosenLoot - 1]; for (var i = 1; i < chosen.Count; i++) { allCards.Add(chosen[i]); } } if (info.PlayerChosenTreasure > 0) { allCards.Add(info.Treasure[info.PlayerChosenTreasure - 1]); } } else { allCards = baseDeck; } } var cards = allCards.GroupBy(x => x).Select(x => { var card = Database.GetCardFromDbfId(x.Key, false); if (card == null) { return(null); } card.Count = x.Count(); return(card); }).Where(x => x != null).ToList(); var loadoutCardId = info.LoadoutCardId; var loadout = loadoutCardId != null?Database.GetCardFromId(loadoutCardId) : null; if (loadout != null && !allCards.Contains(loadout.DbfIf)) { cards.Add(loadout); } if (!Config.Instance.DungeonRunIncludePassiveCards) { cards.RemoveAll(c => !c.Collectible && c.HideStats); } var cardSet = (CardSet)info.CardSet; string playerClass = null; if (cardSet == CardSet.ULDUM && loadout != null) { playerClass = DungeonRun.GetUldumHeroPlayerClass(loadout.PlayerClass); } else if (isPVPDR) { playerClass = HearthDbConverter.ConvertClass((CardClass)(info.HeroClass != 0 ? info.HeroClass : info.HeroCardClass)); } else { if (allCards.Count == 10) { playerClass = allCards.Select(x => Database.GetCardFromDbfId(x).PlayerClass).FirstOrDefault(x => x != null)?.ToUpperInvariant(); } if (playerClass == null) { playerClass = ((CardClass)info.HeroCardClass).ToString().ToUpperInvariant(); } } var deck = DeckList.Instance.Decks.FirstOrDefault(x => (!isPVPDR && x.IsDungeonDeck || isPVPDR && x.IsDuelsDeck) && x.Class.ToUpperInvariant() == playerClass.ToUpperInvariant() && x.Cards.All(e => cards.Any(c => c.Id == e.Id && c.Count >= e.Count)) && !(x.IsDungeonRunCompleted ?? false) && !(x.IsDuelsRunCompleted ?? false)); var baseDbfids = isPVPDR ? info.DbfIds : info.SelectedDeck; if (deck == null && (deck = CreateDungeonDeck(playerClass, cardSet, isPVPDR, baseDbfids, loadout)) == null) { Log.Info($"No existing deck - can't find default deck for {playerClass}"); return; } if (!info.RunActive && (cardSet == CardSet.ULDUM || cardSet == CardSet.DALARAN)) { Log.Info($"Inactive run for Set={cardSet.ToString()} - this is a new run"); return; } if (cards.All(c => deck.Cards.Any(e => c.Id == e.Id && c.Count == e.Count))) { Log.Info("No new cards"); return; } deck.Cards.Clear(); Helper.SortCardCollection(cards, false); foreach (var card in cards) { deck.Cards.Add(card); } deck.LastEdited = DateTime.Now; DeckList.Save(); Core.UpdatePlayerCards(true); Log.Info("Updated dungeon run deck"); }
private async void SaveDeck(bool overwrite, SerializableVersion newVersion) { var deckName = TextBoxDeckName.Text; if (string.IsNullOrEmpty(deckName)) { var settings = new MetroDialogSettings { AffirmativeButtonText = "Set", DefaultText = deckName }; var name = await this.ShowInputAsync("No name set", "Please set a name for the deck", settings); if (String.IsNullOrEmpty(name)) { return; } deckName = name; TextBoxDeckName.Text = name; } /*while(DeckList.DecksList.Any(d => d.Name == deckName) && (!EditingDeck || !overwrite)) * { * var settings = new MetroDialogSettings {AffirmativeButtonText = "Set", DefaultText = deckName}; * var name = * await * this.ShowInputAsync("Name already exists", "You already have a deck with that name, please select a different one.", settings); * * if(String.IsNullOrEmpty(name)) * return; * * deckName = name; * TextBoxDeckName.Text = name; * }*/ if (_newDeck.Cards.Sum(c => c.Count) != 30) { var settings = new MetroDialogSettings { AffirmativeButtonText = "Yes", NegativeButtonText = "No" }; var result = await this.ShowMessageAsync("Not 30 cards", string.Format("Deck contains {0} cards. Is this what you want to save anyway?", _newDeck.Cards.Sum(c => c.Count)), MessageDialogStyle.AffirmativeAndNegative, settings); if (result != MessageDialogResult.Affirmative) { return; } } var previousVersion = _newDeck.Version; if (overwrite && (_newDeck.Version != newVersion)) { AddDeckHistory(); _newDeck.Version = newVersion; _newDeck.SelectedVersion = newVersion; _newDeck.HearthStatsDeckVersionId = ""; //UpdateDeckHistoryPanel(_newDeck, false); } if (EditingDeck && overwrite) { DeckList.Instance.Decks.Remove(_newDeck); //DeckPickerList.RemoveDeck(_newDeck); } var oldDeckName = _newDeck.Name; _newDeck.Name = deckName; var newDeckClone = (Deck)_newDeck.Clone(); newDeckClone.Archived = false; DeckList.Instance.Decks.Add(newDeckClone); newDeckClone.LastEdited = DateTime.Now; DeckList.Save(); Logger.WriteLine("Saved Decks", "SaveDeck"); if (EditingDeck) { TagControlEdit.SetSelectedTags(new List <string>()); if (deckName != oldDeckName) { var statsEntry = DeckStatsList.Instance.DeckStats.FirstOrDefault(ds => ds.BelongsToDeck(_newDeck)); if (statsEntry != null) { if (overwrite) { statsEntry.Name = deckName; Logger.WriteLine("Deck has new name, updated deckstats", "SaveDeck"); } else { var newStatsEntry = DeckStatsList.Instance.DeckStats.FirstOrDefault(ds => ds.BelongsToDeck(_newDeck)); if (newStatsEntry == null) { newStatsEntry = new DeckStats(_newDeck); DeckStatsList.Instance.DeckStats.Add(newStatsEntry); } foreach (var game in statsEntry.Games) { newStatsEntry.AddGameResult(game.CloneWithNewId()); } Logger.WriteLine("cloned gamestats for \"Set as new\"", "SaveDeck"); } DeckStatsList.Save(); } } } if (Config.Instance.HearthStatsAutoUploadNewDecks && HearthStatsAPI.IsLoggedIn) { Logger.WriteLine("auto uploading new/edited deck", "SaveDeck"); if (EditingDeck) { if (previousVersion != newVersion) { HearthStatsManager.UploadVersionAsync(newDeckClone, _originalDeck.HearthStatsIdForUploading, background: true); } else { HearthStatsManager.UpdateDeckAsync(newDeckClone, background: true); } } else { HearthStatsManager.UploadDeckAsync(newDeckClone, background: true); } } //after cloning the stats, otherwise new stats will be generated //DeckPickerList.AddAndSelectDeck(newDeckClone); EditingDeck = false; foreach (var tag in _newDeck.Tags) { SortFilterDecksFlyout.AddSelectedTag(tag); } DeckPickerList.SelectDeckAndAppropriateView(newDeckClone); CloseNewDeck(); ClearNewDeckSection(); }
private static async Task <Deck> ImportHsTopdeck(string url) { try { var doc = await GetHtmlDoc(url); //<div id="leftbar"><div class="headbar"><div style="float:left">ViaGame House Cup #3</div> var tournament = HttpUtility.HtmlDecode(doc.DocumentNode.SelectSingleNode("//div[@id='leftbar']/div[contains(@class, 'headbar')]/div").InnerText); // <div class="headbar"><div style="float:left">#5 - Hunter Face -<a href="search.php?q=ThijsNL&filter=current">ThijsNL</a> var deckName = HttpUtility.HtmlDecode(doc.DocumentNode.SelectSingleNode("//div[@id='center']/div[@class='headbar']/div").InnerText.Trim()); var deck = new Deck(); deck.Name = tournament + " - " + deckName; //<div class="cardname" ... <span class="basic">2 Abusive Sergeant</span> var cards = doc.DocumentNode.SelectNodes("//div[contains(@class, 'cardname')]/span"); //<span class="midlarge"><span class="hunter">Hunter</span>-<span class="aggro">Aggro</span></span> var deckInfo = doc.DocumentNode.SelectSingleNode("//div[@id='contentfr']/div[@id='infos']").SelectNodes("//span[contains(@class, 'midlarge')]/span"); if (deckInfo.Count == 2) { deck.Class = HttpUtility.HtmlDecode(deckInfo[0].InnerText).Trim(); var decktype = HttpUtility.HtmlDecode(deckInfo[1].InnerText).Trim(); if (!String.IsNullOrEmpty(decktype) && decktype != "None" && Config.Instance.TagDecksOnImport) { if (!DeckList.Instance.AllTags.Contains(decktype)) { DeckList.Instance.AllTags.Add(decktype); DeckList.Save(); Helper.MainWindow.ReloadTags(); } deck.Tags.Add(decktype); } } foreach (var cardNode in cards) { var nameString = HttpUtility.HtmlDecode(cardNode.InnerText); var match = Regex.Match(nameString, @"^\s*(\d+)\s+(.*)\s*$"); if (match.Success) { var count = match.Groups[1].Value; var name = match.Groups[2].Value; var card = Game.GetCardFromName(name); card.Count = count.Equals("2") ? 2 : 1; deck.Cards.Add(card); if (string.IsNullOrEmpty(deck.Class) && card.PlayerClass != "Neutral") { deck.Class = card.PlayerClass; } } } return(deck); } catch (Exception e) { Logger.WriteLine(e.ToString(), "DeckImporter"); return(null); } }