Skip to content

Commit 4e59179

Browse files
authored
feat: add quest guides
1 parent 0b2b2e9 commit 4e59179

23 files changed

Lines changed: 914 additions & 49 deletions

HearthWatcher/DiscoverStateWatcher.cs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -46,7 +46,8 @@ private async void Update()
4646
var curr = new DiscoverStateArgs(
4747
state?.CardId ?? "",
4848
state?.ZonePosition ?? 0,
49-
state?.ZoneSize ?? 0
49+
state?.ZoneSize ?? 0,
50+
state?.EntityId ?? 0
5051
);
5152
if(curr.Equals(_prev))
5253
continue;
Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,29 +1,37 @@
1+
using System.Collections.Generic;
2+
using System.Linq;
3+
14
namespace HearthWatcher.EventArgs;
25

36
public class DiscoverStateArgs : System.EventArgs
47
{
58
public string CardId { get; }
69
public int ZonePosition { get; }
710
public int ZoneSize { get; }
11+
public int EntityId { get; }
812

9-
public DiscoverStateArgs(string cardId, int zonePosition, int zoneSize)
13+
public DiscoverStateArgs(string cardId, int zonePosition, int zoneSize, int entityId)
1014
{
1115
CardId = cardId;
1216
ZonePosition = zonePosition;
1317
ZoneSize = zoneSize;
18+
EntityId = entityId;
1419
}
1520

1621
public override bool Equals(object? obj) => obj is DiscoverStateArgs args
1722
&& args.CardId == CardId
1823
&& args.ZonePosition == ZonePosition
19-
&& args.ZoneSize == ZoneSize;
24+
&& args.ZoneSize == ZoneSize
25+
&& args.EntityId == EntityId;
2026

2127
public override int GetHashCode()
2228
{
2329
var hashCode = -2012095321;
2430
hashCode = hashCode * -1521134295 + CardId.GetHashCode();
2531
hashCode = hashCode * -1521134295 + ZonePosition.GetHashCode();
2632
hashCode = hashCode * -1521134295 + ZoneSize.GetHashCode();
33+
hashCode = hashCode * -1521134295 + EntityId.GetHashCode();
34+
2735
return hashCode;
2836
}
2937
}

Hearthstone Deck Tracker/Controls/Overlay/Battlegrounds/Guides/GuidesTabsViewModel.cs renamed to Hearthstone Deck Tracker/Controls/Overlay/Battlegrounds/Guides/BattlegroundsGuidesTabsViewModel.cs

Lines changed: 17 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44

55
namespace Hearthstone_Deck_Tracker.Controls.Overlay.Battlegrounds.Guides;
66

7-
public class GuidesTabsViewModel : ViewModel
7+
public class BattlegroundsGuidesTabsViewModel : ViewModel
88
{
99
public ICommand ShowMinionsCommand => new Command(() =>
1010
{
@@ -32,4 +32,20 @@ public ViewModel? ActiveViewModel
3232
Core.Overlay.BattlegroundsMinionsVM.IsFiltersOpen = false;
3333
}
3434
}
35+
36+
public bool HasQuests
37+
{
38+
get => GetProp(false);
39+
private set => SetProp(value);
40+
}
41+
42+
public void Reset()
43+
{
44+
HasQuests = false;
45+
}
46+
47+
public void OnQuestSelected(bool hasQuests)
48+
{
49+
HasQuests = hasQuests;
50+
}
3551
}

Hearthstone Deck Tracker/Controls/Overlay/Battlegrounds/Guides/GuideTooltipContainer.cs

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,14 @@ private void UpdateContent()
4141
Cards = Cards
4242
};
4343
Content = trinketGuide;
44+
}
45+
else if (card.TypeEnum == CardType.BATTLEGROUND_QUEST_REWARD)
46+
{
47+
var questGuide = new Quests.QuestGuideTooltip()
48+
{
49+
Cards = Cards
50+
};
51+
Content = questGuide;
4452
}
4553
else if (card.TypeEnum == CardType.BATTLEGROUND_ANOMALY)
4654
{

Hearthstone Deck Tracker/Controls/Overlay/Battlegrounds/Guides/GuidesTabs.xaml

Lines changed: 34 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -8,10 +8,13 @@
88
xmlns:comps="clr-namespace:Hearthstone_Deck_Tracker.Controls.Overlay.Battlegrounds.Guides.Comps"
99
xmlns:extensions="clr-namespace:Hearthstone_Deck_Tracker.Utility.Extensions"
1010
xmlns:heroes="clr-namespace:Hearthstone_Deck_Tracker.Controls.Overlay.Battlegrounds.Guides.Heroes"
11+
xmlns:quests="clr-namespace:Hearthstone_Deck_Tracker.Controls.Overlay.Battlegrounds.Guides.Quests"
12+
xmlns:hearthstoneDeckTracker="clr-namespace:Hearthstone_Deck_Tracker"
1113
mc:Ignorable="d"
1214
Width="249"
13-
d:DesignHeight="249" d:DesignWidth="249">
14-
15+
d:DesignHeight="249" d:DesignWidth="249"
16+
d:DataContext="{d:DesignInstance local:BattlegroundsGuidesTabsViewModel}"
17+
>
1518
<UserControl.Resources>
1619
<Style TargetType="Button">
1720
<Setter Property="Cursor" Value="Hand" />
@@ -41,9 +44,6 @@
4144
</Setter>
4245
</Style>
4346
</UserControl.Resources>
44-
<UserControl.DataContext>
45-
<local:GuidesTabsViewModel />
46-
</UserControl.DataContext>
4747

4848
<StackPanel extensions:OverlayExtensions.IsOverlayHitTestVisible="True">
4949
<StackPanel Orientation="Horizontal" VerticalAlignment="Top" Background="#2C3135">
@@ -102,10 +102,31 @@
102102
</Button.Style>
103103
<Grid Width="83"
104104
Height="49">
105-
<Rectangle Fill="White" Height="23" Width="21">
106-
<Rectangle.OpacityMask>
107-
<VisualBrush Visual="{DynamicResource icon_hero}" />
108-
</Rectangle.OpacityMask>
105+
<Rectangle Fill="White">
106+
<Rectangle.Style>
107+
<Style TargetType="Rectangle">
108+
<Setter Property="Height" Value="27" />
109+
<Setter Property="Width" Value="24" />
110+
<Setter Property="Margin" Value="2.5,3.7,0,0" />
111+
<Setter Property="OpacityMask">
112+
<Setter.Value>
113+
<VisualBrush Visual="{DynamicResource icon_hero_and_quest}" />
114+
</Setter.Value>
115+
</Setter>
116+
<Style.Triggers>
117+
<DataTrigger Binding="{Binding HasQuests}" Value="False">
118+
<Setter Property="Height" Value="23" />
119+
<Setter Property="Width" Value="21" />
120+
<Setter Property="Margin" Value="0" />
121+
<Setter Property="OpacityMask">
122+
<Setter.Value>
123+
<VisualBrush Visual="{DynamicResource icon_hero}" />
124+
</Setter.Value>
125+
</Setter>
126+
</DataTrigger>
127+
</Style.Triggers>
128+
</Style>
129+
</Rectangle.Style>
109130
</Rectangle>
110131
</Grid>
111132
</Button>
@@ -117,7 +138,10 @@
117138
<ContentControl.Resources>
118139
<minions:BattlegroundsMinions x:Key="Minions" />
119140
<comps:CompGuideList x:Key="Comps" />
120-
<heroes:HeroGuide x:Key="Heroes" />
141+
<StackPanel x:Key="Heroes">
142+
<heroes:HeroGuide />
143+
<quests:QuestGuide DataContext="{Binding Source={x:Static hearthstoneDeckTracker:Core.Overlay}, Path=BattlegroundsQuestGuideListViewModel}" />
144+
</StackPanel>
121145

122146
<DataTemplate DataType="{x:Type minions:BattlegroundsMinionsViewModel}">
123147
<ContentControl Content="{StaticResource Minions}"/>

Hearthstone Deck Tracker/Controls/Overlay/Battlegrounds/Guides/Heroes/BattlegroundsHeroGuideListViewModel.cs

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,12 @@ public Dictionary<int, BattlegroundsHeroGuide>? HeroGuides
2020
private set => SetProp(value);
2121
}
2222

23+
public bool HasQuests
24+
{
25+
get => GetProp(false);
26+
private set => SetProp(value);
27+
}
28+
2329
private const string Url = "https://hsreplay.net/api/v1/battlegrounds/hero_guides/";
2430
private async Task<HeroGuidesApiResponse?> MakeRequest()
2531
{
@@ -68,6 +74,7 @@ public void Reset()
6874
HeroGuides = null;
6975
SelectedHero.HeroCard = null;
7076
SelectedHero.HeroGuide = null;
77+
HasQuests = false;
7178
}
7279

7380
public BattlegroundsHeroGuideViewModel SelectedHero { get; } = new ();
@@ -96,4 +103,9 @@ public void OnMulliganEnded()
96103
SelectedHero.HeroCard = heroCard;
97104
SelectedHero.HeroGuide = guide;
98105
}
106+
107+
public void OnQuestSelected(bool hasQuests)
108+
{
109+
HasQuests = hasQuests;
110+
}
99111
}

Hearthstone Deck Tracker/Controls/Overlay/Battlegrounds/Guides/Heroes/HeroGuide.xaml

Lines changed: 31 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -58,10 +58,21 @@
5858
</Style>
5959
</UserControl.Resources>
6060

61-
<Border Background="#23272A" CornerRadius="0,0,0,3" BorderBrush="#3f4346"
62-
BorderThickness="1,0,0,1"
61+
<Border Background="#23272A" BorderBrush="#3f4346"
6362
Padding="9"
6463
>
64+
<Border.Style>
65+
<Style TargetType="Border">
66+
<Setter Property="CornerRadius" Value="0,0,0,3"/>
67+
<Setter Property="BorderThickness" Value="1,0,0,1"/>
68+
<Style.Triggers>
69+
<DataTrigger Binding="{Binding HasQuests}" Value="True">
70+
<Setter Property="CornerRadius" Value="0,0,0,0"/>
71+
<Setter Property="BorderThickness" Value="1,0,0,0"/>
72+
</DataTrigger>
73+
</Style.Triggers>
74+
</Style>
75+
</Border.Style>
6576
<StackPanel DataContext="{Binding SelectedHero}">
6677
<StackPanel Margin="10,20,10,20" Visibility="{Binding IsHeroSelected, Converter={StaticResource InverseBoolToVisibility}}">
6778
<TextBlock
@@ -158,28 +169,29 @@
158169
</ItemsControl>
159170
</StackPanel>
160171
</Border>
172+
173+
<Border BorderThickness="0, 1, 0, 0" BorderBrush="#4A5256" Background="#141617">
174+
<Grid Margin="7" HorizontalAlignment="Stretch">
175+
<Grid.ColumnDefinitions>
176+
<ColumnDefinition Width="*" />
177+
<ColumnDefinition Width="Auto"/>
178+
</Grid.ColumnDefinitions>
179+
<StackPanel HorizontalAlignment="Left">
180+
<TextBlock Text="{lex:Loc Battlegrounds_CompGuide_CreatedBy}" Foreground="White" FontSize="9" Opacity="0.8"/>
181+
<TextBlock Text="JeefHS" Foreground="White" FontSize="10" FontWeight="Bold" TextAlignment="Left"/>
182+
</StackPanel>
183+
184+
<StackPanel Grid.Column="1">
185+
<TextBlock Text="{lex:Loc Battlegrounds_CompGuide_LastUpdated}" Foreground="White" HorizontalAlignment="Right" FontSize="9" Opacity="0.8"/>
186+
<TextBlock Text="{Binding LastUpdatedFormatted}" Foreground="White" FontSize="10" FontWeight="Bold" HorizontalAlignment="Right"/>
187+
</StackPanel>
188+
</Grid>
189+
</Border>
161190
</StackPanel>
162191
</StackPanel>
163192
</ScrollViewer>
164193
</Grid>
165194
</Border>
166-
<Border Grid.Row="2" BorderThickness="0, 1, 0, 0" BorderBrush="#4A5256" Background="#141617" Margin="-9,9,-9,-9" Visibility="{Binding IsGuidePublished, Converter={StaticResource BoolToVisibility}}">
167-
<Grid Margin="7" HorizontalAlignment="Stretch">
168-
<Grid.ColumnDefinitions>
169-
<ColumnDefinition Width="*" />
170-
<ColumnDefinition Width="Auto"/>
171-
</Grid.ColumnDefinitions>
172-
<StackPanel HorizontalAlignment="Left">
173-
<TextBlock Text="{lex:Loc Battlegrounds_CompGuide_CreatedBy}" Foreground="White" FontSize="9" Opacity="0.8"/>
174-
<TextBlock Text="JeefHS" Foreground="White" FontSize="10" FontWeight="Bold"/>
175-
</StackPanel>
176-
177-
<StackPanel Grid.Column="1">
178-
<TextBlock Text="{lex:Loc Battlegrounds_CompGuide_LastUpdated}" Foreground="White" HorizontalAlignment="Right" FontSize="9" Opacity="0.8"/>
179-
<TextBlock Text="{Binding LastUpdatedFormatted}" Foreground="White" FontSize="10" FontWeight="Bold" HorizontalAlignment="Right"/>
180-
</StackPanel>
181-
</Grid>
182-
</Border>
183195
</Grid>
184196
</StackPanel>
185197
</Border>
Lines changed: 90 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,90 @@
1+
using System;
2+
using System.Collections.Generic;
3+
using System.Collections.ObjectModel;
4+
using System.Linq;
5+
using System.Net;
6+
using System.Net.Http;
7+
using System.Threading.Tasks;
8+
using HearthDb.Enums;
9+
using Hearthstone_Deck_Tracker.Hearthstone;
10+
using Hearthstone_Deck_Tracker.Utility.Logging;
11+
using Hearthstone_Deck_Tracker.Utility.MVVM;
12+
using Newtonsoft.Json;
13+
14+
namespace Hearthstone_Deck_Tracker.Controls.Overlay.Battlegrounds.Guides.Quests;
15+
16+
public class BattlegroundsQuestGuideListViewModel : ViewModel
17+
{
18+
public Dictionary<int, BattlegroundsQuestGuide>? QuestGuides
19+
{
20+
get => GetProp<Dictionary<int, BattlegroundsQuestGuide>?>(null);
21+
private set => SetProp(value);
22+
}
23+
24+
public ObservableCollection<BattlegroundsQuestGuideViewModel> SelectedQuests { get; } = new();
25+
26+
public bool HasQuests => SelectedQuests.Count > 0;
27+
28+
private const string Url = "https://hsreplay.net/api/v1/battlegrounds/quest_guides/";
29+
private async Task<QuestGuidesApiResponse?> MakeRequest()
30+
{
31+
using HttpRequestMessage req = new(HttpMethod.Get, Url + $"?game_language={Helper.GetCardLanguage()}");
32+
req.Headers.UserAgent.ParseAdd(Helper.GetUserAgent());
33+
var resp = await Core.HttpClient.SendAsync(req);
34+
if(resp is { StatusCode: HttpStatusCode.OK })
35+
return JsonConvert.DeserializeObject<QuestGuidesApiResponse>(await resp.Content.ReadAsStringAsync());
36+
37+
return null;
38+
}
39+
40+
public BattlegroundsQuestGuide? GetQuestGuide(int questRewardDbfId)
41+
{
42+
if(QuestGuides == null)
43+
return null;
44+
45+
QuestGuides.TryGetValue(questRewardDbfId, out var guide);
46+
return guide;
47+
}
48+
49+
public async void Update()
50+
{
51+
if(QuestGuides != null)
52+
return;
53+
54+
try
55+
{
56+
var data = await MakeRequest();
57+
if(data == null)
58+
return;
59+
60+
QuestGuides = data.ToDictionary(h => h.Quest);
61+
}
62+
catch(Exception e)
63+
{
64+
Log.Error(e);
65+
}
66+
}
67+
68+
public void Reset()
69+
{
70+
QuestGuides = null;
71+
SelectedQuests.Clear();
72+
OnPropertyChanged(nameof(HasQuests));
73+
}
74+
75+
public void OnQuestSelected(Hearthstone.Card questRewardCard)
76+
{
77+
BattlegroundsQuestGuide? guide = null;
78+
79+
QuestGuides?.TryGetValue(questRewardCard.DbfId, out guide);
80+
81+
var questViewModel = new BattlegroundsQuestGuideViewModel
82+
{
83+
QuestCard = questRewardCard,
84+
QuestGuide = guide
85+
};
86+
87+
SelectedQuests.Add(questViewModel);
88+
OnPropertyChanged(nameof(HasQuests));
89+
}
90+
}

0 commit comments

Comments
 (0)