diff --git a/HearthWatcher/DungeonRunWatcher.cs b/HearthWatcher/DungeonRunWatcher.cs index c9977d9451..c42718422e 100644 --- a/HearthWatcher/DungeonRunWatcher.cs +++ b/HearthWatcher/DungeonRunWatcher.cs @@ -48,15 +48,15 @@ public void Run() private async void Watch() { Running = true; - _prevCards = new List[] { null, null, null }; - _prevLootChoice = new[] { 0, 0, 0 }; - _prevTreasureChoice = new[] { 0, 0, 0 }; + _prevCards = new List[] { null, null, null, null, null }; + _prevLootChoice = new[] { 0, 0, 0, 0, 0 }; + _prevTreasureChoice = new[] { 0, 0, 0, 0, 0 }; while(_watch) { await Task.Delay(_delay); if(!_watch) break; - if(Update()) + if(await Update()) break; } Running = false; @@ -73,46 +73,25 @@ private async void Watch() CardIds.NonCollectible.Druid.RottoothHeroic, }; - public bool Update() + public async Task Update() { if(_dataProvider.InAdventureScreen) { - var dungeonInfo = Reflection.GetDungeonInfo(); - if(dungeonInfo != null) - { - for(var i = 0; i < dungeonInfo.Length; i++) - { - if(dungeonInfo[i]?.RunActive ?? false) - { - if(_prevCards[i] == null || !dungeonInfo[i].DbfIds.SequenceEqual(_prevCards[i]) - || _prevLootChoice[i] != dungeonInfo[i].PlayerChosenLoot - || _prevTreasureChoice[i] != dungeonInfo[i].PlayerChosenTreasure) - { - _prevCards[i] = dungeonInfo[i].DbfIds.ToList(); - _prevLootChoice[i] = dungeonInfo[i].PlayerChosenLoot; - _prevTreasureChoice[i] = dungeonInfo[i].PlayerChosenTreasure; - DungeonInfoChanged?.Invoke(dungeonInfo[i]); - } - } - else - _prevCards[i] = null; - } - - if(_prevLootChoice.All(x => x > 0) && _prevTreasureChoice.All(x => x > 0)) - return true; - } - else - { - _prevCards = new List[] { null, null, null }; - } - + var shouldBreak = UpdateDungeonInfo(); + if(shouldBreak) + return true; } else if(_dataProvider.InAiMatch && !string.IsNullOrEmpty(_dataProvider.OpponentHeroId)) { if(Cards.All.TryGetValue(_dataProvider.OpponentHeroId, out var card)) { - if(new [] {CardSet.LOOTAPALOOZA, CardSet.GILNEAS}.Contains(card.Set) && card.Id.Contains("BOSS") || card.Set == CardSet.TROLL && card.Id.EndsWith("h")) + if(new [] {CardSet.LOOTAPALOOZA, CardSet.GILNEAS, CardSet.DALARAN}.Contains(card.Set) && card.Id.Contains("BOSS") || card.Set == CardSet.TROLL && card.Id.EndsWith("h")) { + if(card.Set == CardSet.DALARAN) + { + UpdateDungeonInfo(); + await Task.Delay(500); + } var newRun = _initialOpponents.Contains(_dataProvider.OpponentHeroId) || _dataProvider.OpponentHeroHealth == 10; DungeonRunMatchStarted?.Invoke(newRun); @@ -122,5 +101,38 @@ public bool Update() } return false; } + + public bool UpdateDungeonInfo() + { + var dungeonInfo = Reflection.GetDungeonInfo(); + if(dungeonInfo != null) + { + for(var i = 0; i < dungeonInfo.Length; i++) + { + if(dungeonInfo[i] != null && (dungeonInfo[i].RunActive || dungeonInfo[i].SelectedDeckId != 0)) + { + if(_prevCards[i] == null || !(dungeonInfo[i].DbfIds?.SequenceEqual(_prevCards[i]) ?? false) + || _prevLootChoice[i] != dungeonInfo[i].PlayerChosenLoot + || _prevTreasureChoice[i] != dungeonInfo[i].PlayerChosenTreasure) + { + _prevCards[i] = dungeonInfo[i].DbfIds?.ToList(); + _prevLootChoice[i] = dungeonInfo[i].PlayerChosenLoot; + _prevTreasureChoice[i] = dungeonInfo[i].PlayerChosenTreasure; + DungeonInfoChanged?.Invoke(dungeonInfo[i]); + } + } + else + _prevCards[i] = null; + } + + if(_prevLootChoice.All(x => x > 0) && _prevTreasureChoice.All(x => x > 0)) + return true; + } + else + { + _prevCards = new List[] { null, null, null, null, null }; + } + return false; + } } } diff --git a/Hearthstone Deck Tracker/Config.cs b/Hearthstone Deck Tracker/Config.cs index 2a283d29a9..4e5d532411 100644 --- a/Hearthstone Deck Tracker/Config.cs +++ b/Hearthstone Deck Tracker/Config.cs @@ -152,6 +152,9 @@ public class Config [DefaultValue("Rumble Run {Date dd-MM HH:mm}")] public string RumbleRunDeckNameTemplate = "Rumble Run {Date dd-MM HH:mm}"; + [DefaultValue("Dalaran Heist {Date dd-MM HH:mm}")] + public string DalaranHeistDeckNameTemplate = "Dalaran Heist {Date dd-MM HH:mm}"; + [DefaultValue(HsActionType.Flash)] public HsActionType TurnStartAction = HsActionType.Flash; diff --git a/Hearthstone Deck Tracker/DeckManager.cs b/Hearthstone Deck Tracker/DeckManager.cs index 7b175621e3..a50350c775 100644 --- a/Hearthstone Deck Tracker/DeckManager.cs +++ b/Hearthstone Deck Tracker/DeckManager.cs @@ -425,11 +425,11 @@ public static void SaveDeck(Deck baseDeck, Deck newVersion, bool overwriteCurren DeckManagerEvents.OnDeckUpdated.Execute(newVersion); } - public static void DungeonRunMatchStarted(bool newRun) + public static void DungeonRunMatchStarted(bool newRun, bool recursive = false) { if(!Config.Instance.DungeonAutoImport) return; - Log.Info($"Dungeon run detected! New={newRun}"); + Log.Info($"Dungeon run detected! New={newRun}, Recursive={recursive}"); var playerClass = Core.Game.Player.Board.FirstOrDefault(x => x.IsHero)?.Card.PlayerClass; if(playerClass == null) return; @@ -445,8 +445,18 @@ public static void DungeonRunMatchStarted(bool newRun) if(newRun) { var hero = Core.Game.Opponent.PlayerEntities.FirstOrDefault(x => x.IsHero)?.CardId; - var set = Database.GetCardFromId(hero)?.CardSet; - CreateDungeonDeck(playerClass, set ?? CardSet.INVALID); + var set = Database.GetCardFromId(hero)?.CardSet ?? CardSet.INVALID; + if (set == CardSet.DALARAN) + { + Watchers.DungeonRunWatcher.UpdateDungeonInfo(); + if(!recursive) + { + DungeonRunMatchStarted(newRun, true); + return; + } + } + else + CreateDungeonDeck(playerClass, set); } else { @@ -470,29 +480,43 @@ public static void UpdateDungeonRunDeck(DungeonInfo info) if(!Config.Instance.DungeonAutoImport) return; Log.Info("Found dungeon run deck!"); - var allCards = info.DbfIds.ToList(); - if(info.PlayerChosenLoot > 0) + var baseDeck = info.SelectedDeck ?? new List(); + var allCards = info.DbfIds?.ToList() ?? new List(); + if (baseDeck.All(x => allCards.Contains(x))) { - 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.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]); } - 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; - }).ToList(); + }).Where(x => x != null).ToList(); if(!Config.Instance.DungeonRunIncludePassiveCards) cards.RemoveAll(c => !c.Collectible && c.HideStats); - var playerClass = ((CardClass)info.HeroCardClass).ToString().ToUpperInvariant(); + + string playerClass = null; + 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 && !(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.CardSet)) == null) + if(deck == null && (deck = CreateDungeonDeck(playerClass, (CardSet)info.CardSet, info.SelectedDeck)) == null) { Log.Info($"No existing deck - can't find default deck for {playerClass}"); return; @@ -512,11 +536,13 @@ public static void UpdateDungeonRunDeck(DungeonInfo info) Log.Info("Updated dungeon run deck"); } - private static Deck CreateDungeonDeck(string playerClass, CardSet set) + private static Deck CreateDungeonDeck(string playerClass, CardSet set, List selectedDeck = 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})"); - var deck = DungeonRun.GetDefaultDeck(playerClass, set, shrine); + 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, selectedDeck); if(deck == null) { Log.Info($"Could not find default deck for {playerClass} in card set {set} with Shrine={shrine}"); diff --git a/Hearthstone Deck Tracker/Hearthstone/DungeonRun.cs b/Hearthstone Deck Tracker/Hearthstone/DungeonRun.cs index a7ec99b808..f96aaab974 100644 --- a/Hearthstone Deck Tracker/Hearthstone/DungeonRun.cs +++ b/Hearthstone Deck Tracker/Hearthstone/DungeonRun.cs @@ -15,9 +15,19 @@ public static Deck GetDefaultDeck(string playerClass, CardSet set, string shrine var cards = GetCards(playerClass, set, shrineCardId); if(cards == null) return null; + return GetDeck(playerClass, set, cards.Select(Database.GetCardFromId)); + } + + public static Deck GetDeckFromDbfIds(string playerClass, CardSet set, IEnumerable dbfIds) + { + return GetDeck(playerClass, set, dbfIds.Select(dbfId => Database.GetCardFromDbfId(dbfId))); + } + + public static Deck GetDeck(string playerClass, CardSet set, IEnumerable cards) + { var deck = new Deck { - Cards = new ObservableCollection(cards.Select(Database.GetCardFromId)), + Cards = new ObservableCollection(cards), Class = CultureInfo.InvariantCulture.TextInfo.ToTitleCase(playerClass.ToLowerInvariant()), IsDungeonDeck = true, LastEdited = DateTime.Now @@ -39,6 +49,8 @@ private static string GetDeckTemplate(CardSet set) return Config.Instance.MonsterHuntDeckNameTemplate; case CardSet.TROLL: return Config.Instance.RumbleRunDeckNameTemplate; + case CardSet.DALARAN: + return Config.Instance.DalaranHeistDeckNameTemplate; default: return null; } diff --git a/Hearthstone Deck Tracker/Hearthstone/Watchers.cs b/Hearthstone Deck Tracker/Hearthstone/Watchers.cs index 636318dbd6..cbc288fa9c 100644 --- a/Hearthstone Deck Tracker/Hearthstone/Watchers.cs +++ b/Hearthstone Deck Tracker/Hearthstone/Watchers.cs @@ -18,8 +18,8 @@ static Watchers() { ArenaWatcher.OnCompleteDeck += (sender, args) => DeckManager.AutoImportArena(Config.Instance.SelectedArenaImportingBehaviour ?? ArenaImportingBehaviour.AutoImportSave, args.Info); PackWatcher.NewPackEventHandler += (sender, args) => PackUploader.UploadPack(args.PackId, args.Cards); - DungeonRunWatcher.DungeonRunMatchStarted += DeckManager.DungeonRunMatchStarted; - DungeonRunWatcher.DungeonInfoChanged += DeckManager.UpdateDungeonRunDeck; + DungeonRunWatcher.DungeonRunMatchStarted += newRun => DeckManager.DungeonRunMatchStarted(newRun); + DungeonRunWatcher.DungeonInfoChanged += dungeonInfo => DeckManager.UpdateDungeonRunDeck(dungeonInfo); FriendlyChallengeWatcher.OnFriendlyChallenge += OnFriendlyChallenge; }