public static async Task<Deck> Import(string url) { try { var doc = await ImportingHelper.GetHtmlDoc(url); var deck = new Deck {Name = doc.DocumentNode.SelectSingleNode("//h1[@id='deck-title']").InnerText}; var cardList = HttpUtility.HtmlDecode(doc.DocumentNode.SelectSingleNode("//table[@id='deck-guide']").Attributes["data-deck"].Value); cardList = cardList.Replace("\"", "").Replace("[", "").Replace("]", "").Replace("\\", ""); foreach(var cardNode in cardList.Split(',').GroupBy(x => x)) { var card = Database.GetCardFromId(cardNode.Key); card.Count = cardNode.Count(); deck.Cards.Add(card); if (string.IsNullOrEmpty(deck.Class) && card.PlayerClass != "Neutral") deck.Class = card.PlayerClass; } return deck; } catch (Exception e) { Log.Error(e); return null; } }
public static async Task<Deck> Import(string url) { try { string json; using(var wc = new WebClient()) json = await wc.DownloadStringTaskAsync(url + ".json"); var wrapper = JsonConvert.DeserializeObject<IcyVeinsWrapper>(json); var deck = new Deck {Name = wrapper.deck_name}; foreach(var cardObj in wrapper.deck_cards) { var cardName = cardObj.name; if(cardName.EndsWith(" Naxx")) cardName = cardName.Replace(" Naxx", ""); if(cardName.EndsWith(" GvG")) cardName = cardName.Replace(" GvG", ""); if(cardName.EndsWith(" BrM")) cardName = cardName.Replace(" BrM", ""); var card = Database.GetCardFromName(cardName); card.Count = cardObj.quantity; deck.Cards.Add(card); if(string.IsNullOrEmpty(deck.Class) && card.PlayerClass != "Neutral") deck.Class = card.PlayerClass; } return deck; } catch(Exception e) { Log.Error(e); return null; } }
public static async Task<Deck> Import(string url) { try { var doc = await ImportingHelper.GetHtmlDoc(url); var deck = new Deck { Name = HttpUtility.HtmlDecode(doc.DocumentNode.SelectSingleNode("//*[@id='content']/div[contains(@class, 'deck')]/h1").InnerText).Trim() }; var nodes = doc.DocumentNode.SelectNodes("//a[@real_id]"); foreach(var cardNode in nodes) { var id = cardNode.Attributes["real_id"].Value; var count = int.Parse(cardNode.Attributes["nb_card"].Value); var card = Database.GetCardFromId(id); card.Count = count; deck.Cards.Add(card); if(string.IsNullOrEmpty(deck.Class) && card.PlayerClass != "Neutral") deck.Class = card.PlayerClass; } return deck; } catch(Exception e) { Log.Error(e); return null; } }
internal static void MoveGamesToOtherDeckWithoutConfirmation(Deck targetDeck, SerializableVersion targetVersion, params GameStats[] games) { if(games == null) return; foreach(var game in games) { 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); deck?.DeckStats.Games.Remove(game); } game.PlayerDeckVersion = targetVersion; game.HearthStatsDeckVersionId = targetDeck.GetVersion(targetVersion).HearthStatsDeckVersionId; game.DeckId = targetDeck.DeckId; game.DeckName = targetDeck.Name; targetDeck.DeckStats.Games.Add(game); if(HearthStatsAPI.IsLoggedIn && Config.Instance.HearthStatsAutoUploadNewGames) HearthStatsManager.MoveMatchAsync(game, targetDeck, background: true).Forget(); } DeckStatsList.Save(); DeckList.Save(); Core.MainWindow.DeckPickerList.UpdateDecks(); }
public static async Task<Deck> Import(string url) { try { var doc = await ImportingHelper.GetHtmlDoc(url); var deck = new Deck(); var deckName = HttpUtility.HtmlDecode(doc.DocumentNode.SelectSingleNode("//h1[contains(@class,'page-title')]").FirstChild.InnerText); deck.Name = deckName; var cardNameNodes = doc.DocumentNode.SelectNodes("//div[contains(@class,'name')]"); var cardCountNodes = doc.DocumentNode.SelectNodes("//div[contains(@class,'qty')]"); var cardNames = cardNameNodes.Select(cardNameNode => HttpUtility.HtmlDecode(cardNameNode.InnerText)); var cardCosts = cardCountNodes.Select(countNode => int.Parse(countNode.InnerText)); var cardInfo = cardNames.Zip(cardCosts, (n, c) => new {Name = n, Count = c}); foreach(var info in cardInfo) { var card = Database.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; } }
private async void ExportDeck(Deck deck) { var export = true; if(Config.Instance.ShowExportingDialog) { var message = string.Format( "1) create a new, empty {0}-Deck {1}.\n\n2) leave the deck creation screen open.\n\n3)do not move your mouse or type after clicking \"export\"", deck.Class, (Config.Instance.AutoClearDeck ? "(or open an existing one to be cleared automatically)" : "")); if(deck.GetSelectedDeckVersion().Cards.Any(c => c.Name == "Stalagg" || c.Name == "Feugen")) { message += "\n\nIMPORTANT: If you own golden versions of Feugen or Stalagg please make sure to configure\nOptions > Other > Exporting"; } var settings = new MessageDialogs.Settings {AffirmativeButtonText = "export"}; var result = await this.ShowMessageAsync("Export " + deck.Name + " to Hearthstone", message, MessageDialogStyle.AffirmativeAndNegative, settings); export = result == MessageDialogResult.Affirmative; } if(export) { var controller = await this.ShowProgressAsync("Creating Deck", "Please do not move your mouse or type."); Topmost = false; await Task.Delay(500); await DeckExporter.Export(deck); await controller.CloseAsync(); if(deck.MissingCards.Any()) this.ShowMissingCardsMessage(deck); } }
public static async Task<Deck> Import(string url) { try { var doc = await ImportingHelper.GetHtmlDoc(url); var titleNode = doc.DocumentNode.SelectSingleNode("//div[contains(@class,'header__title internal')]/div[contains(@class,'container')]/h1"); var cardNodes = doc.DocumentNode.SelectNodes("//ul[contains(@class,'list-unstyled cartas_list')]/li"); var deck = new Deck(); deck.Name = HttpUtility.HtmlDecode(titleNode.ChildNodes.FirstOrDefault(x => x.Name == "#text").InnerText); foreach (var node in cardNodes) { var nameNode = node.SelectSingleNode("span[contains(@class,'cartas__name')]/a"); var countNode = node.SelectSingleNode("span[contains(@class,'cartas__qtd')]"); var validChild = countNode?.ChildNodes.SingleOrDefault(c => c.Name == "#text"); var id = nameNode.Attributes.FirstOrDefault(a => a.Name == "data-hcfw-card-id").Value; var count = validChild != null ? int.Parse(countNode.InnerText) : 1; var card = Database.GetCardFromId(id); card.Count = count; deck.Cards.Add(card); if (string.IsNullOrEmpty(deck.Class) && card.PlayerClass != "Neutral") deck.Class = card.PlayerClass; } return deck; } catch (Exception e) { Log.Error(e); return null; } }
public static async Task<Deck> Import(string url) { try { var doc = await ImportingHelper.GetHtmlDoc(url); var deck = new Deck(); var deckName = HttpUtility.HtmlDecode(doc.DocumentNode.SelectSingleNode("//span[contains(@class, 'deckName')]").InnerText).Trim(); deck.Name = deckName; var cardNodes = doc.DocumentNode.SelectNodes("//table[@class='deck_card_list']/tbody/tr/td/a[@class='real_id']"); foreach(var cardNode in cardNodes) { var id = cardNode.Attributes["real_id"].Value; var count = int.Parse(cardNode.Attributes["nb_card"].Value); var card = Database.GetCardFromId(id); card.Count = 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; } }
public static async Task<Deck> Import(string url) { try { var doc = await ImportingHelper.GetHtmlDoc(url); var deck = new Deck(); var deckName = HttpUtility.HtmlDecode(doc.DocumentNode.SelectSingleNode("//h2[contains(@class, 'dname')]").InnerText); deck.Name = deckName; var cardNodes = doc.DocumentNode.SelectNodes("//ul[@class='vminionslist' or @class='vspellslist']/li"); foreach(var cardNode in cardNodes) { var count = int.Parse(cardNode.SelectSingleNode(".//span[@class='cantidad']").InnerText); var name = HttpUtility.HtmlDecode( cardNode.SelectSingleNode( ".//span[@class='nombreCarta rarity_legendary' or @class='nombreCarta rarity_epic' or @class='nombreCarta rarity_rare' or @class='nombreCarta rarity_common' or @class='nombreCarta rarity_basic']") .InnerText); var card = Database.GetCardFromName(name); card.Count = 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; } }
public static async Task<Deck> TryFindDeck(string url) { try { var doc = await ImportingHelper.GetHtmlDoc(url); var deck = new Deck(); var metaNodes = doc.DocumentNode.SelectNodes("//meta"); if(!metaNodes.Any()) return null; deck.Name = GetMetaProperty(metaNodes, "x-hearthstone:deck"); deck.Url = GetMetaProperty(metaNodes, "x-hearthstone:deck:url") ?? url; var heroId = GetMetaProperty(metaNodes, "x-hearthstone:deck:hero"); if(!string.IsNullOrEmpty(heroId)) deck.Class = Database.GetCardFromId(heroId).PlayerClass; var cardList = GetMetaProperty(metaNodes, "x-hearthstone:deck:cards").Split(','); foreach(var idGroup in cardList.GroupBy(x => x)) { var card = Database.GetCardFromId(idGroup.Key); card.Count = idGroup.Count(); deck.Cards.Add(card); if(deck.Class == null && card.IsClassCard) deck.Class = card.PlayerClass; } return deck; } catch(Exception e) { Log.Error(e); return null; } }
public static async Task<Deck> Import(string url) { try { var doc = await ImportingHelper.GetHtmlDoc(url); var deck = new Deck {IsArenaDeck = true}; var cardNodes = doc.DocumentNode.SelectSingleNode(".//ul[@class='deckList']"); var nameNodes = cardNodes.SelectNodes(".//span[@class='name']"); var countNodes = cardNodes.SelectNodes(".//span[@class='quantity']"); var numberOfCards = nameNodes.Count; for(var i = 0; i < numberOfCards; i++) { var nameRaw = nameNodes.ElementAt(i).InnerText; var name = HttpUtility.HtmlDecode(nameRaw); var card = Database.GetCardFromName(name); card.Count = int.Parse(countNodes.ElementAt(i).InnerText); deck.Cards.Add(card); if(string.IsNullOrEmpty(deck.Class) && card.PlayerClass != "Neutral") deck.Class = card.PlayerClass; } if(DeckList.Instance.AllTags.Contains("Arena")) deck.Tags.Add("Arena"); deck.Name = Helper.ParseDeckNameTemplate(Config.Instance.ArenaDeckNameTemplate, deck); return deck; } catch(Exception e) { Log.Error(e); return null; } }
public void SubtractOperator001() { Deck d1 = new Deck(); Deck d2 = new Deck(); //just in d1 d1.Cards.Add(new Card("ID_1", "", Rarity.FREE, "", "ID 1", 0, "", 0, 1, "", "", 0, 0, "", new string[] { }, 0, "", "")); //in both but diff count d1.Cards.Add(new Card("ID_2", "", Rarity.FREE, "", "ID 2", 0, "", 0, 2, "", "", 0, 0, "", new string[] { }, 0, "", "")); d2.Cards.Add(new Card("ID_2", "", Rarity.FREE, "", "ID 2", 0, "", 0, 3, "", "", 0, 0, "", new string[] { }, 0, "", "")); //just in d2 d2.Cards.Add(new Card("ID_3", "", Rarity.FREE, "", "ID 3", 0, "", 0, 2, "", "", 0, 0, "", new string[] { }, 0, "", "")); //in bth and same cont d1.Cards.Add(new Card("ID_4", "", Rarity.FREE, "", "ID 4", 0, "", 0, 5, "", "", 0, 0, "", new string[] { }, 0, "", "")); d2.Cards.Add(new Card("ID_4", "", Rarity.FREE, "", "ID 4", 0, "", 0, 5, "", "", 0, 0, "", new string[] { }, 0, "", "")); IEnumerable<Card> result = d1 - d2; Assert.IsNotNull(result); foreach (Card c in result) { Console.Out.WriteLine(c.ToString()); } Assert.AreEqual(3, result.Count()); Assert.AreEqual(1, result.Where(c => c.Id == "ID_1" && c.Count == 1).Count(), "ID 1, expected count 1"); Assert.AreEqual(1, result.Where(c => c.Id == "ID_2" && c.Count == -1).Count(), "ID 2, expected count -1"); Assert.AreEqual(1, result.Where(c => c.Id == "ID_3" && c.Count == -2).Count(), "ID 3, expected count -2"); }
public static async Task<Deck> Import(string url) { try { var doc = await ImportingHelper.GetHtmlDoc(url); var deck = new Deck(); var deckName = HttpUtility.HtmlDecode(doc.DocumentNode.SelectSingleNode("//div[contains(@class, 'deck-info')]//h1").InnerText); deck.Name = deckName; var cardNodes = doc.DocumentNode.SelectNodes("//ul[@class='listado mazo-cartas']/li"); foreach(var cardNode in cardNodes) { var count = int.Parse(cardNode.SelectSingleNode(".//span[@class='cantidad']").InnerText); var name = HttpUtility.HtmlDecode(cardNode.SelectSingleNode(".//span[@class='nombreCarta']").InnerText); var card = Database.GetCardFromName(name); card.Count = count; deck.Cards.Add(card); if(string.IsNullOrEmpty(deck.Class) && card.PlayerClass != "Neutral") deck.Class = card.PlayerClass; } return deck; } catch(Exception e) { Log.Error(e); return null; } }
private async void ExportDeck(Deck deck) { var export = true; if(Config.Instance.ShowExportingDialog) { var message = $"1) Create a new (or open an existing) {deck.Class} deck.\n\n2) Leave the deck creation screen open.\n\n3) Click 'Export' and do not move your mouse or type until done."; var settings = new MessageDialogs.Settings {AffirmativeButtonText = "Export"}; var result = await this.ShowMessageAsync("Export " + deck.Name + " to Hearthstone", message, MessageDialogStyle.AffirmativeAndNegative, settings); export = result == MessageDialogResult.Affirmative; } if(export) { var controller = await this.ShowProgressAsync("Creating Deck", "Please do not move your mouse or type."); Topmost = false; await Task.Delay(500); var success = await DeckExporter.Export(deck); await controller.CloseAsync(); if(success) { var hsDeck = HearthMirror.Reflection.GetEditedDeck(); if(hsDeck != null) { var existingHsId = DeckList.Instance.Decks.Where(x => x.DeckId != deck.DeckId).FirstOrDefault(x => x.HsId == hsDeck.Id); if(existingHsId != null) existingHsId.HsId = 0; deck.HsId = hsDeck.Id; DeckList.Save(); } } if(deck.MissingCards.Any()) this.ShowMissingCardsMessage(deck); } }
public DeckStats(Deck deck) { Name = deck.Name; Games = new List<GameStats>(); HearthStatsDeckId = deck.HearthStatsId; DeckId = deck.DeckId; }
public static async Task<Deck> Import(string url) { try { var doc = await ImportingHelper.GetHtmlDocGzip(url); var deck = new Deck { Name = HttpUtility.HtmlDecode(doc.DocumentNode.SelectSingleNode("//header[@class='panel-heading']/h1[@class='panel-title']").InnerText) .Trim() }; var nodes = doc.DocumentNode.SelectNodes("//table[@class='table table-bordered table-hover table-db']/tbody/tr"); foreach(var cardNode in nodes) { var name = HttpUtility.HtmlDecode(cardNode.SelectSingleNode(".//a").Attributes[3].Value); var temp = HttpUtility.HtmlDecode(cardNode.SelectSingleNode(".//a/small").InnerText[0].ToString()); var count = int.Parse(temp); var card = Database.GetCardFromName(name); card.Count = 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; } }
public static async Task<Deck> Import(string url) { try { var doc = await ImportingHelper.GetHtmlDoc(url); var deck = new Deck(); var deckName = HttpUtility.HtmlDecode(doc.DocumentNode.SelectSingleNode("//header[@class='entry-header']/h1[@class='entry-title']").InnerText); deck.Name = deckName; var cardNodes = doc.DocumentNode.SelectNodes("//ul[contains(@class,'deck-class')]/li"); foreach(var cardNode in cardNodes) { var name = HttpUtility.HtmlDecode(cardNode.SelectSingleNode(".//a/span[@class='card-name']").InnerText); var count = int.Parse(HttpUtility.HtmlDecode(cardNode.SelectSingleNode(".//a/span[@class='card-count']").InnerText)); var card = Database.GetCardFromName(name); card.Count = 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; } }
public AddGameDialog(Deck deck) { InitializeComponent(); _tcs = new TaskCompletionSource<GameStats>(); _editing = false; var lastGame = deck.DeckStats.Games.LastOrDefault(); if(deck.IsArenaDeck) { ComboBoxMode.SelectedItem = GameMode.Arena; ComboBoxMode.IsEnabled = false; TextBoxRank.IsEnabled = false; } else { ComboBoxMode.IsEnabled = true; TextBoxRank.IsEnabled = true; if(lastGame != null) { ComboBoxMode.SelectedItem = lastGame.GameMode; if(lastGame.GameMode == GameMode.Ranked) TextBoxRank.Text = lastGame.Rank.ToString(); } } if(lastGame != null && lastGame.Region != Region.UNKNOWN) ComboBoxRegion.SelectedItem = lastGame.Region; _deck = deck; _game = new GameStats(); BtnSave.Content = "add game"; }
public static async Task SetDeckName(Deck deck, ExportingInfo info) { if(Config.Instance.ExportSetDeckName && !deck.TagList.ToLower().Contains("brawl")) { var name = Regex.Replace(deck.Name, @"[\(\)\{\}]", ""); if(name != deck.Name) Logger.WriteLine("Removed parenthesis/braces from deck name. New name: " + name, "DeckExporter"); if(Config.Instance.ExportAddDeckVersionToName) { var version = " " + deck.SelectedVersion.ShortVersionString; if(name.Length + version.Length > MaxLengthDeckName) name = name.Substring(0, MaxLengthDeckName - version.Length); name += version; } Logger.WriteLine("Setting deck name...", "DeckExporter"); var nameDeckPos = new Point((int)Helper.GetScaledXPos(Config.Instance.ExportNameDeckX, info.HsRect.Width, info.Ratio), (int)(Config.Instance.ExportNameDeckY * info.HsRect.Height)); await ClickOnPoint(info.HsHandle, nameDeckPos); //send enter and second click to make sure the current name gets selected SendKeys.SendWait("{ENTER}"); await ClickOnPoint(info.HsHandle, nameDeckPos); if(Config.Instance.ExportPasteClipboard) { Clipboard.SetText(name); SendKeys.SendWait("^v"); } else SendKeys.SendWait(name); SendKeys.SendWait("{ENTER}"); } }
public static async Task SetDeckName(Deck deck, ExportingInfo info) { if(Config.Instance.ExportSetDeckName && !deck.TagList.ToLower().Contains("brawl")) { var name = deck.Name; if(Config.Instance.ExportAddDeckVersionToName) name += " " + deck.SelectedVersion.ShortVersionString; Logger.WriteLine("Setting deck name...", "DeckExporter"); var nameDeckPos = new Point((int)Helper.GetScaledXPos(Config.Instance.ExportNameDeckX, info.HsRect.Width, info.Ratio), (int)(Config.Instance.ExportNameDeckY * info.HsRect.Height)); await MouseActions.ClickOnPoint(info.HsHandle, nameDeckPos); //send enter and second click to make sure the current name gets selected SendKeys.SendWait("{ENTER}"); await MouseActions.ClickOnPoint(info.HsHandle, nameDeckPos); if(Config.Instance.ExportPasteClipboard) { Clipboard.SetText(name); SendKeys.SendWait("^v"); } else SendKeys.SendWait(name); SendKeys.SendWait("{ENTER}"); } }
public DeckPickerItem(Deck deck, Type deckPickerItemLayout) { InitializeComponent(); DataContext = deck; Deck = deck; _deckPickerItem = deckPickerItemLayout; SetLayout(); }
public bool BelongsToDeck(Deck deck) { if(HasHearthStatsDeckId && deck.HasHearthStatsId) return HearthStatsDeckId.Equals(deck.HearthStatsIdForUploading); //if(HasHearthStatsDeckId && deck.HasHearthStatsId && HasHearthStatsDeckVersionId && deck.HasHearthStatsDeckVersionId) // return HearthStatsDeckId.Equals(deck.HearthStatsId) && HearthStatsDeckVersionId.Equals(deck.HearthStatsDeckVersionId); return DeckId == deck.DeckId; }
public void UpdateDeckList(Deck selected) { ListViewDeck.ItemsSource = null; if(selected == null) return; ListViewDeck.ItemsSource = selected.GetSelectedDeckVersion().Cards; Helper.SortCardCollection(ListViewDeck.Items, Config.Instance.CardSortingClassFirst); }
public void SetDeck(Deck deck) { _deck = deck; ListViewDeck.Items.Clear(); foreach(var card in deck.Cards) ListViewDeck.Items.Add(card); Helper.SortCardCollection(ListViewDeck.Items, false); }
public static async Task<Deck> Import(string url) { try { var doc = await ImportingHelper.GetHtmlDoc(url); var deck = new Deck(); deck.Name = HttpUtility.HtmlDecode(doc.DocumentNode.SelectSingleNode("/html/body/div/div[4]/div/div[2]/div/div[1]/h3").InnerText.Trim()); var cards = doc.DocumentNode.SelectNodes("//div[contains(@class, 'cardname')]/span"); var deckInfo = doc.DocumentNode.SelectSingleNode("//div[@id='subinfo']").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(); if(Helper.MainWindow != null) // to avoid errors when running tests Core.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 = Database.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; } }
public void Update(Deck deck) { RectIconOg.Visibility = deck?.ContainsSet("Whispers of the Old Gods") ?? false ? Visible : Collapsed; RectIconLoe.Visibility = deck?.ContainsSet("League of Explorers") ?? false ? Visible : Collapsed; RectIconTgt.Visibility = deck?.ContainsSet("The Grand Tournament") ?? false ? Visible : Collapsed; RectIconBrm.Visibility = deck?.ContainsSet("Blackrock Mountain") ?? false ? Visible : Collapsed; RectIconGvg.Visibility = deck?.ContainsSet("Goblins vs Gnomes") ?? false ? Visible : Collapsed; RectIconNaxx.Visibility = deck?.ContainsSet("Curse of Naxxramas") ?? false ? Visible : Collapsed; }
public void SetDeck(Deck deck, bool showImportButton = true) { _deck = deck; ListViewDeck.Items.Clear(); foreach(var card in deck.Cards.ToSortedCardList()) ListViewDeck.Items.Add(card); Helper.SortCardCollection(ListViewDeck.Items, false); ButtonImport.Visibility = showImportButton ? Visibility.Visible : Visibility.Collapsed; }
public ExistingDeck(Deck deck, HearthMirror.Objects.Deck newDeck) { Deck = deck; var tmp = new Deck { Cards = new ObservableCollection<Card>(newDeck.Cards.Select(x => new Card { Id = x.Id, Count = x.Count })) }; MatchingCards = 30 - (deck - tmp).Count(x => x.Count > 0); NewVersion = MatchingCards == 30 ? new SerializableVersion(0, 0) : (MatchingCards < 26 ? SerializableVersion.IncreaseMajor(deck.Version) : SerializableVersion.IncreaseMinor(deck.Version)); }
public static async Task<bool> Export(Deck deck) { if(deck == null) return false; var currentClipboard = ""; var altScreenCapture = Config.Instance.AlternativeScreenCapture; try { Log.Info("Exporting " + deck.GetDeckInfo()); if(Config.Instance.ExportPasteClipboard && Clipboard.ContainsText()) currentClipboard = Clipboard.GetText(); var info = new ExportingInfo(); LogDebugInfo(info); var inForeground = await ExportingHelper.EnsureHearthstoneInForeground(info.HsHandle); if(!inForeground) return false; Log.Info($"Waiting for {Config.Instance.ExportStartDelay} seconds before starting the export process"); await Task.Delay(Config.Instance.ExportStartDelay * 1000); if(!altScreenCapture) Core.Overlay.ForceHide(true); await ClearDeck(info); await SetDeckName(deck, info); await ClearFilters(info); var lostFocus = await CreateDeck(deck, info); if(lostFocus) return false; await ClearSearchBox(info.HsHandle, info.SearchBoxPos); if(Config.Instance.ExportPasteClipboard) Clipboard.Clear(); Log.Info("Success exporting deck."); return true; } catch(Exception e) { Log.Error("Error exporting deck: " + e); return false; } finally { if(!altScreenCapture) Core.Overlay.ForceHide(false); try { if(Config.Instance.ExportPasteClipboard && currentClipboard != "") Clipboard.SetText(currentClipboard); } catch(Exception ex) { Log.Error("Could not restore clipboard content after export: " + ex); } } }
public Deck ToDeck(CardObject[] cards, string[] rawTags, DeckVersion[] versions, string version) { if(!klass_id.HasValue) return null; try { var url = ""; bool archived = false; if(!string.IsNullOrEmpty(notes)) { var match = Regex.Match(notes, noteUrlRegex); if(match.Success) { url = match.Groups["url"].Value; notes = Regex.Replace(notes, noteUrlRegex, ""); } if(notes.Contains(noteArchived)) { archived = true; notes = notes.Replace(noteArchived, ""); } notes = notes.Trim(); } //tags are returned all lowercase, find matching tag var tags = rawTags.Select( tag => DeckList.Instance.AllTags.FirstOrDefault(t => string.Equals(t, tag, StringComparison.InvariantCultureIgnoreCase)) ?? tag); var deck = new Deck(name ?? "", Dictionaries.HeroDict[klass_id.Value], cards == null ? new List<Card>() : cards.Where(x => x != null && x.count != null && x.id != null) .Select(x => x.ToCard()) .Where(x => x != null) .ToList(), tags, notes ?? "", url, DateTime.Now, archived, new List<Card>(), SerializableVersion.ParseOrDefault(version), new List<Deck>(), true, id.ToString(), Guid.NewGuid(), deck_version_id.ToString()); deck.LastEdited = updated_at.ToLocalTime(); if(versions.Length > 0) deck.Versions = versions.Where(v => v.version != version).Select(v => v.ToDeck(deck)).ToList(); var current = versions.FirstOrDefault(v => v.version == version); if(current != null) deck.HearthStatsDeckVersionId = current.deck_version_id.ToString(); deck.HearthStatsIdsAlreadyReset = true; return deck; } catch(Exception e) { Logger.WriteLine("error converting DeckObject: " + e, "HearthStatsAPI"); return null; } }
public async Task GetCardCounts(Deck deck) { 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()) { Log.Error("Can't find Hearthstone window."); return; } await Task.Delay(1000); Core.Overlay.ForceHidden = true; Core.Overlay.UpdatePosition(); const double xScale = 0.013; const double yScale = 0.017; const int targetHue = 53; const int hueMargin = 3; const int numVisibleCards = 21; var hsRect = User32.GetHearthstoneRect(false); var ratio = (4.0 / 3.0) / ((double)hsRect.Width / hsRect.Height); var posX = (int)Helper.GetScaledXPos(0.92, hsRect.Width, ratio); var startY = 71.0 / 768.0 * hsRect.Height; var strideY = 29.0 / 768.0 * hsRect.Height; var width = (int)Math.Round(hsRect.Width * xScale); var height = (int)Math.Round(hsRect.Height * yScale); for (var i = 0; i < Math.Min(numVisibleCards, deck.Cards.Count); i++) { var posY = (int)(startY + strideY * i); var capture = await ScreenCapture.CaptureHearthstoneAsync(new Point(posX, posY), width, height, hsHandle); if (capture == null) { continue; } var yellowPixels = 0; for (var x = 0; x < width; x++) { for (var y = 0; y < height; y++) { var pixel = capture.GetPixel(x, y); if (Math.Abs(pixel.GetHue() - targetHue) < hueMargin) { yellowPixels++; } } } //Console.WriteLine(yellowPixels + " of " + width * height + " - " + yellowPixels / (double)(width * height)); //capture.Save("arenadeckimages/" + i + ".png"); var yellowPixelRatio = yellowPixels / (double)(width * height); if (yellowPixelRatio > 0.25 && yellowPixelRatio < 50) { deck.Cards[i].Count = 2; } } if (deck.Cards.Count > numVisibleCards) { const int scrollClicksPerCard = 4; const int scrollDistance = 120; var clientPoint = new Point(posX, (int)startY); var previousPos = System.Windows.Forms.Cursor.Position; User32.ClientToScreen(hsHandle, ref clientPoint); System.Windows.Forms.Cursor.Position = new Point(clientPoint.X, clientPoint.Y); for (var j = 0; j < scrollClicksPerCard * (deck.Cards.Count - numVisibleCards); j++) { User32.mouse_event((uint)User32.MouseEventFlags.Wheel, 0, 0, -scrollDistance, UIntPtr.Zero); await Task.Delay(30); } System.Windows.Forms.Cursor.Position = previousPos; await Task.Delay(100); var remainingCards = deck.Cards.Count - numVisibleCards; startY = 76.0 / 768.0 * hsRect.Height + (numVisibleCards - remainingCards) * strideY; for (var i = 0; i < remainingCards; i++) { var posY = (int)(startY + strideY * i); var capture = await ScreenCapture.CaptureHearthstoneAsync(new Point(posX, posY), width, height, hsHandle); if (capture == null) { continue; } var yellowPixels = 0; for (var x = 0; x < width; x++) { for (var y = 0; y < height; y++) { var pixel = capture.GetPixel(x, y); if (Math.Abs(pixel.GetHue() - targetHue) < hueMargin) { yellowPixels++; } } } var yellowPixelRatio = yellowPixels / (double)(width * height); if (yellowPixelRatio > 0.25 && yellowPixelRatio < 50) { deck.Cards[numVisibleCards + i].Count = 2; } } System.Windows.Forms.Cursor.Position = new Point(clientPoint.X, clientPoint.Y); for (var j = 0; j < scrollClicksPerCard * (deck.Cards.Count - 21); j++) { User32.mouse_event((uint)User32.MouseEventFlags.Wheel, 0, 0, scrollDistance, UIntPtr.Zero); await Task.Delay(30); } System.Windows.Forms.Cursor.Position = previousPos; } Core.Overlay.ForceHidden = false; Core.Overlay.UpdatePosition(); ActivateWindow(); }
public void SelectVersion(Deck deck) { SelectVersion(deck.Version); }
private static async Task AutoSelectDeck(Deck currentDeck, string heroClass, GameMode mode, Format?currentFormat, List <IGrouping <string, Entity> > cardEntites = null) { if (mode == GameMode.Battlegrounds) { Log.Info("Switching to no-deck mode for battlegrounds"); Core.MainWindow.SelectDeck(null, true); return; } _waitingForDraws++; await Task.Delay(500); _waitingForDraws--; if (_waitingForDraws > 0) { return; } var validDecks = DeckList.Instance.Decks.Where(x => x.Class == heroClass && !x.Archived && !x.IsDungeonDeck && !x.IsDuelsDeck).ToList(); if (currentDeck != null) { validDecks.Remove(currentDeck); } validDecks = validDecks.FilterByMode(mode, currentFormat); if (cardEntites != null) { validDecks = validDecks.Where(x => cardEntites.All(ce => x.GetSelectedDeckVersion().Cards.Any(c => c.Id == ce.Key && c.Count >= ce.Count()))).ToList(); } if (_autoSelectCount > 1) { Log.Info("Too many auto selects. Showing dialog."); ShowDeckSelectionDialog(validDecks); return; } if (validDecks.Count == 0) { if (cardEntites == null || !AutoSelectDeckVersion(heroClass, mode, currentFormat, cardEntites)) { Log.Info("No matching deck found, using no-deck mode"); Core.MainWindow.SelectDeck(null, true); } return; } if (validDecks.Count == 1) { var deck = validDecks.Single(); Log.Info("Found one matching deck: " + deck); Core.MainWindow.SelectDeck(deck, true); _autoSelectCount++; return; } var lastUsed = DeckList.Instance.LastDeckClass.FirstOrDefault(x => x.Class == heroClass); if (lastUsed != null) { var deck = validDecks.FirstOrDefault(x => x.DeckId == lastUsed.Id); if (deck != null) { Log.Info($"Last used {heroClass} deck matches!"); Core.MainWindow.SelectDeck(deck, true); _autoSelectCount++; return; } } if (cardEntites == null || !AutoSelectDeckVersion(heroClass, mode, currentFormat, cardEntites)) { ShowDeckSelectionDialog(validDecks); } }
private static List <IGrouping <string, Entity> > GetMissingCards(List <IGrouping <string, Entity> > revealed, Deck deck) => revealed.Where(x => !deck.GetSelectedDeckVersion().Cards.Any(c => c.Id == x.Key && c.Count >= x.Count())).ToList();
public static List <Deck> ImportDecksTo(ICollection <Deck> targetList, IEnumerable <ImportedDeck> decks, bool brawl, bool importNew, bool updateExisting) { var importedDecks = new List <Deck>(); 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); } var existingWithId = targetList.FirstOrDefault(d => d.HsId == deck.Deck.Id); if (existingWithId != null) { existingWithId.HsId = 0; } targetList.Add(newDeck); importedDecks.Add(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.DeckStats.Games.Count == 0 || target.DeckStats.Games.All(g => g.GameMode == GameMode.Brawl))) { target.Tags.Add("Brawl"); } if (target.Archived) { target.Archived = false; Log.Info($"Unarchiving deck: {deck.Deck.Name}."); } 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})."); targetList.Remove(target); var oldDeck = (Deck)target.Clone(); oldDeck.Versions = new List <Deck>(); if (!brawl) { target.Name = deck.Deck.Name; } target.LastEdited = DateTime.Now; target.Versions.Add(oldDeck); target.Version = existing.NewVersion; target.SelectedVersion = existing.NewVersion; 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(); targetList.Add(clone); importedDecks.Add(clone); } } } return(importedDecks); }
public bool BelongsToDeckVerion(Deck deck) => PlayerDeckVersion == deck.Version || !IsAssociatedWithDeckVersion && deck.Version == new SerializableVersion(1, 0);
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>(); if (!brawl) { target.Name = deck.Deck.Name; } target.LastEdited = DateTime.Now; target.Versions.Add(oldDeck); target.Version = existing.NewVersion; target.SelectedVersion = existing.NewVersion; 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 void SetPlayerCards(Deck deck, List <Card> revealedCards) => SetPlayerCards(deck?.Cards, revealedCards);