diff --git a/hsVoiceCommands.sln b/hsVoiceCommands.sln
new file mode 100644
index 0000000..052d82d
--- /dev/null
+++ b/hsVoiceCommands.sln
@@ -0,0 +1,22 @@
+
+Microsoft Visual Studio Solution File, Format Version 12.00
+# Visual Studio 14
+VisualStudioVersion = 14.0.23107.0
+MinimumVisualStudioVersion = 10.0.40219.1
+Project("{F184B08F-C81C-45F6-A57F-5ABD9991F28F}") = "HDT-Voice", "hsVoiceCommands\HDT-Voice.vbproj", "{1D71665E-6ABB-4765-AD4B-EB9AC9F01A17}"
+EndProject
+Global
+ GlobalSection(SolutionConfigurationPlatforms) = preSolution
+ Debug|Any CPU = Debug|Any CPU
+ Release|Any CPU = Release|Any CPU
+ EndGlobalSection
+ GlobalSection(ProjectConfigurationPlatforms) = postSolution
+ {1D71665E-6ABB-4765-AD4B-EB9AC9F01A17}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {1D71665E-6ABB-4765-AD4B-EB9AC9F01A17}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {1D71665E-6ABB-4765-AD4B-EB9AC9F01A17}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {1D71665E-6ABB-4765-AD4B-EB9AC9F01A17}.Release|Any CPU.Build.0 = Release|Any CPU
+ EndGlobalSection
+ GlobalSection(SolutionProperties) = preSolution
+ HideSolutionNode = FALSE
+ EndGlobalSection
+EndGlobal
diff --git a/hsVoiceCommands/HDT-Voice.vb b/hsVoiceCommands/HDT-Voice.vb
new file mode 100644
index 0000000..2536bbf
--- /dev/null
+++ b/hsVoiceCommands/HDT-Voice.vb
@@ -0,0 +1,62 @@
+Imports System
+Imports System.Windows.Controls
+
+Imports Hearthstone_Deck_Tracker.Plugins
+Public Class HDTVoice
+ Implements IPlugin
+ Public ReadOnly Property Author As String Implements IPlugin.Author
+ Get
+ Return "Chris Sheridan"
+ End Get
+ End Property
+
+ Public ReadOnly Property ButtonText As String Implements IPlugin.ButtonText
+ Get
+ Return "Settings"
+ End Get
+ End Property
+
+ Public ReadOnly Property Description As String Implements IPlugin.Description
+ Get
+ Return "Control Hearthstone using simple voice commands"
+ End Get
+ End Property
+
+ Public ReadOnly Property MenuItem As MenuItem Implements IPlugin.MenuItem
+ Get
+ Return Nothing
+ End Get
+ End Property
+
+ Public ReadOnly Property Name As String Implements IPlugin.Name
+ Get
+ Return "HDT-Voice"
+ End Get
+ End Property
+
+ Public ReadOnly Property Version As Version Implements IPlugin.Version
+ Get
+ Return New Version(0, 2, 1)
+ End Get
+ End Property
+
+ Public Sub OnButtonPress() Implements IPlugin.OnButtonPress
+ Dim fc As New formConfig
+ fc.ShowDialog()
+
+ Return
+ End Sub
+
+ Public Sub OnLoad() Implements IPlugin.OnLoad
+ Dim voicePlugin As New hsVoicePlugin
+ voicePlugin.Load()
+ End Sub
+
+ Public Sub OnUnload() Implements IPlugin.OnUnload
+ Return
+ End Sub
+
+ Public Sub OnUpdate() Implements IPlugin.OnUpdate
+ Return
+ End Sub
+End Class
diff --git a/hsVoiceCommands/HDT-Voice.vbproj b/hsVoiceCommands/HDT-Voice.vbproj
new file mode 100644
index 0000000..e0ff0ef
--- /dev/null
+++ b/hsVoiceCommands/HDT-Voice.vbproj
@@ -0,0 +1,133 @@
+
+
+
+
+ Debug
+ AnyCPU
+ {1D71665E-6ABB-4765-AD4B-EB9AC9F01A17}
+ Library
+ HDTVoice
+ HDT-Voice
+ 512
+ Windows
+ v4.5.2
+
+
+ true
+ full
+ true
+ true
+ bin\Debug\
+ HDT-Voice.xml
+ 42016,41999,42017,42018,42019,42032,42036,42020,42021,42022
+
+
+ pdbonly
+ false
+ true
+ true
+ bin\Release\
+ HDT-Voice.xml
+ 42016,41999,42017,42018,42019,42032,42036,42020,42021,42022
+
+
+ On
+
+
+ Binary
+
+
+ Off
+
+
+ On
+
+
+
+ ..\..\..\..\..\Games\Hearthstone\Hearthstone Deck Tracker\Hearthstone Deck Tracker.exe
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ formConfig.vb
+
+
+ Form
+
+
+
+
+
+ True
+ Application.myapp
+
+
+ True
+ True
+ Resources.resx
+
+
+ True
+ Settings.settings
+ True
+
+
+
+
+ formConfig.vb
+
+
+ VbMyResourcesResXFileCodeGenerator
+ Resources.Designer.vb
+ My.Resources
+ Designer
+
+
+
+
+
+ MyApplicationCodeGenerator
+ Application.Designer.vb
+
+
+ SettingsSingleFileGenerator
+ My
+ Settings.Designer.vb
+
+
+
+
+ copy /Y "$(TargetPath)" "D:\Games\Hearthstone\Hearthstone Deck Tracker\plugins"
+
+
+
\ No newline at end of file
diff --git a/hsVoiceCommands/My Project/Application.Designer.vb b/hsVoiceCommands/My Project/Application.Designer.vb
new file mode 100644
index 0000000..88dd01c
--- /dev/null
+++ b/hsVoiceCommands/My Project/Application.Designer.vb
@@ -0,0 +1,13 @@
+'------------------------------------------------------------------------------
+'
+' This code was generated by a tool.
+' Runtime Version:4.0.30319.42000
+'
+' Changes to this file may cause incorrect behavior and will be lost if
+' the code is regenerated.
+'
+'------------------------------------------------------------------------------
+
+Option Strict On
+Option Explicit On
+
diff --git a/hsVoiceCommands/My Project/Application.myapp b/hsVoiceCommands/My Project/Application.myapp
new file mode 100644
index 0000000..758895d
--- /dev/null
+++ b/hsVoiceCommands/My Project/Application.myapp
@@ -0,0 +1,10 @@
+
+
+ false
+ false
+ 0
+ true
+ 0
+ 1
+ true
+
diff --git a/hsVoiceCommands/My Project/AssemblyInfo.vb b/hsVoiceCommands/My Project/AssemblyInfo.vb
new file mode 100644
index 0000000..eeea7fc
--- /dev/null
+++ b/hsVoiceCommands/My Project/AssemblyInfo.vb
@@ -0,0 +1,35 @@
+Imports System
+Imports System.Reflection
+Imports System.Runtime.InteropServices
+
+' General Information about an assembly is controlled through the following
+' set of attributes. Change these attribute values to modify the information
+' associated with an assembly.
+
+' Review the values of the assembly attributes
+
+
+
+
+
+
+
+
+
+
+'The following GUID is for the ID of the typelib if this project is exposed to COM
+
+
+' Version information for an assembly consists of the following four values:
+'
+' Major Version
+' Minor Version
+' Build Number
+' Revision
+'
+' You can specify all the values or you can default the Build and Revision Numbers
+' by using the '*' as shown below:
+'
+
+
+
diff --git a/hsVoiceCommands/My Project/Resources.Designer.vb b/hsVoiceCommands/My Project/Resources.Designer.vb
new file mode 100644
index 0000000..d1a78a1
--- /dev/null
+++ b/hsVoiceCommands/My Project/Resources.Designer.vb
@@ -0,0 +1,63 @@
+'------------------------------------------------------------------------------
+'
+' This code was generated by a tool.
+' Runtime Version:4.0.30319.42000
+'
+' Changes to this file may cause incorrect behavior and will be lost if
+' the code is regenerated.
+'
+'------------------------------------------------------------------------------
+
+Option Strict On
+Option Explicit On
+
+Imports System
+
+Namespace My.Resources
+
+ 'This class was auto-generated by the StronglyTypedResourceBuilder
+ 'class via a tool like ResGen or Visual Studio.
+ 'To add or remove a member, edit your .ResX file then rerun ResGen
+ 'with the /str option, or rebuild your VS project.
+ '''
+ ''' A strongly-typed resource class, for looking up localized strings, etc.
+ '''
+ _
+ Friend Module Resources
+
+ Private resourceMan As Global.System.Resources.ResourceManager
+
+ Private resourceCulture As Global.System.Globalization.CultureInfo
+
+ '''
+ ''' Returns the cached ResourceManager instance used by this class.
+ '''
+ _
+ Friend ReadOnly Property ResourceManager() As Global.System.Resources.ResourceManager
+ Get
+ If Object.ReferenceEquals(resourceMan, Nothing) Then
+ Dim temp As Global.System.Resources.ResourceManager = New Global.System.Resources.ResourceManager("HDTVoice.Resources", GetType(Resources).Assembly)
+ resourceMan = temp
+ End If
+ Return resourceMan
+ End Get
+ End Property
+
+ '''
+ ''' Overrides the current thread's CurrentUICulture property for all
+ ''' resource lookups using this strongly typed resource class.
+ '''
+ _
+ Friend Property Culture() As Global.System.Globalization.CultureInfo
+ Get
+ Return resourceCulture
+ End Get
+ Set
+ resourceCulture = value
+ End Set
+ End Property
+ End Module
+End Namespace
diff --git a/hsVoiceCommands/My Project/Resources.resx b/hsVoiceCommands/My Project/Resources.resx
new file mode 100644
index 0000000..af7dbeb
--- /dev/null
+++ b/hsVoiceCommands/My Project/Resources.resx
@@ -0,0 +1,117 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ text/microsoft-resx
+
+
+ 2.0
+
+
+ System.Resources.ResXResourceReader, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
+
+
+ System.Resources.ResXResourceWriter, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
+
+
\ No newline at end of file
diff --git a/hsVoiceCommands/My Project/Settings.Designer.vb b/hsVoiceCommands/My Project/Settings.Designer.vb
new file mode 100644
index 0000000..e18a02b
--- /dev/null
+++ b/hsVoiceCommands/My Project/Settings.Designer.vb
@@ -0,0 +1,97 @@
+'------------------------------------------------------------------------------
+'
+' This code was generated by a tool.
+' Runtime Version:4.0.30319.42000
+'
+' Changes to this file may cause incorrect behavior and will be lost if
+' the code is regenerated.
+'
+'------------------------------------------------------------------------------
+
+Option Strict On
+Option Explicit On
+
+
+Namespace My
+
+ _
+ Partial Friend NotInheritable Class MySettings
+ Inherits Global.System.Configuration.ApplicationSettingsBase
+
+ Private Shared defaultInstance As MySettings = CType(Global.System.Configuration.ApplicationSettingsBase.Synchronized(New MySettings()),MySettings)
+
+#Region "My.Settings Auto-Save Functionality"
+#If _MyType = "WindowsForms" Then
+ Private Shared addedHandler As Boolean
+
+ Private Shared addedHandlerLockObject As New Object
+
+ _
+ Private Shared Sub AutoSaveSettings(ByVal sender As Global.System.Object, ByVal e As Global.System.EventArgs)
+ If My.Application.SaveMySettingsOnExit Then
+ My.Settings.Save()
+ End If
+ End Sub
+#End If
+#End Region
+
+ Public Shared ReadOnly Property [Default]() As MySettings
+ Get
+
+#If _MyType = "WindowsForms" Then
+ If Not addedHandler Then
+ SyncLock addedHandlerLockObject
+ If Not addedHandler Then
+ AddHandler My.Application.Shutdown, AddressOf AutoSaveSettings
+ addedHandler = True
+ End If
+ End SyncLock
+ End If
+#End If
+ Return defaultInstance
+ End Get
+ End Property
+
+ _
+ Public Property Threshold() As Integer
+ Get
+ Return CType(Me("Threshold"),Integer)
+ End Get
+ Set
+ Me("Threshold") = value
+ End Set
+ End Property
+
+ _
+ Public Property showLast() As Boolean
+ Get
+ Return CType(Me("showLast"),Boolean)
+ End Get
+ Set
+ Me("showLast") = value
+ End Set
+ End Property
+ End Class
+End Namespace
+
+Namespace My
+
+ _
+ Friend Module MySettingsProperty
+
+ _
+ Friend ReadOnly Property Settings() As Global.HDTVoice.My.MySettings
+ Get
+ Return Global.HDTVoice.My.MySettings.Default
+ End Get
+ End Property
+ End Module
+End Namespace
diff --git a/hsVoiceCommands/My Project/Settings.settings b/hsVoiceCommands/My Project/Settings.settings
new file mode 100644
index 0000000..fb41ebc
--- /dev/null
+++ b/hsVoiceCommands/My Project/Settings.settings
@@ -0,0 +1,12 @@
+
+
+
+
+
+ 90
+
+
+ False
+
+
+
\ No newline at end of file
diff --git a/hsVoiceCommands/app.config b/hsVoiceCommands/app.config
new file mode 100644
index 0000000..1be76fd
--- /dev/null
+++ b/hsVoiceCommands/app.config
@@ -0,0 +1,40 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 90
+
+
+ False
+
+
+
+
diff --git a/hsVoiceCommands/formConfig.Designer.vb b/hsVoiceCommands/formConfig.Designer.vb
new file mode 100644
index 0000000..66caf2d
--- /dev/null
+++ b/hsVoiceCommands/formConfig.Designer.vb
@@ -0,0 +1,151 @@
+ _
+Partial Class formConfig
+ Inherits System.Windows.Forms.Form
+
+ 'Form overrides dispose to clean up the component list.
+ _
+ Protected Overrides Sub Dispose(ByVal disposing As Boolean)
+ Try
+ If disposing AndAlso components IsNot Nothing Then
+ components.Dispose()
+ End If
+ Finally
+ MyBase.Dispose(disposing)
+ End Try
+ End Sub
+
+ 'Required by the Windows Form Designer
+ Private components As System.ComponentModel.IContainer
+
+ 'NOTE: The following procedure is required by the Windows Form Designer
+ 'It can be modified using the Windows Form Designer.
+ 'Do not modify it using the code editor.
+ _
+ Private Sub InitializeComponent()
+ Me.checkDefaultAudio = New System.Windows.Forms.CheckBox()
+ Me.comboAudioDevice = New System.Windows.Forms.ComboBox()
+ Me.groupInput = New System.Windows.Forms.GroupBox()
+ Me.groupRecog = New System.Windows.Forms.GroupBox()
+ Me.numThreshold = New System.Windows.Forms.NumericUpDown()
+ Me.Label1 = New System.Windows.Forms.Label()
+ Me.buttonSave = New System.Windows.Forms.Button()
+ Me.checkLast = New System.Windows.Forms.CheckBox()
+ Me.groupInput.SuspendLayout()
+ Me.groupRecog.SuspendLayout()
+ CType(Me.numThreshold, System.ComponentModel.ISupportInitialize).BeginInit()
+ Me.SuspendLayout()
+ '
+ 'checkDefaultAudio
+ '
+ Me.checkDefaultAudio.AutoSize = True
+ Me.checkDefaultAudio.Checked = True
+ Me.checkDefaultAudio.CheckState = System.Windows.Forms.CheckState.Checked
+ Me.checkDefaultAudio.Enabled = False
+ Me.checkDefaultAudio.Location = New System.Drawing.Point(6, 46)
+ Me.checkDefaultAudio.Name = "checkDefaultAudio"
+ Me.checkDefaultAudio.Size = New System.Drawing.Size(115, 17)
+ Me.checkDefaultAudio.TabIndex = 0
+ Me.checkDefaultAudio.Text = "Use system default"
+ Me.checkDefaultAudio.UseVisualStyleBackColor = True
+ '
+ 'comboAudioDevice
+ '
+ Me.comboAudioDevice.Enabled = False
+ Me.comboAudioDevice.FormattingEnabled = True
+ Me.comboAudioDevice.Location = New System.Drawing.Point(6, 19)
+ Me.comboAudioDevice.Name = "comboAudioDevice"
+ Me.comboAudioDevice.Size = New System.Drawing.Size(247, 21)
+ Me.comboAudioDevice.TabIndex = 1
+ '
+ 'groupInput
+ '
+ Me.groupInput.Controls.Add(Me.comboAudioDevice)
+ Me.groupInput.Controls.Add(Me.checkDefaultAudio)
+ Me.groupInput.Location = New System.Drawing.Point(12, 12)
+ Me.groupInput.Name = "groupInput"
+ Me.groupInput.Size = New System.Drawing.Size(260, 68)
+ Me.groupInput.TabIndex = 2
+ Me.groupInput.TabStop = False
+ Me.groupInput.Text = "Input Device"
+ '
+ 'groupRecog
+ '
+ Me.groupRecog.Controls.Add(Me.numThreshold)
+ Me.groupRecog.Controls.Add(Me.Label1)
+ Me.groupRecog.Location = New System.Drawing.Point(12, 86)
+ Me.groupRecog.Name = "groupRecog"
+ Me.groupRecog.Size = New System.Drawing.Size(260, 46)
+ Me.groupRecog.TabIndex = 3
+ Me.groupRecog.TabStop = False
+ Me.groupRecog.Text = "Recognition Settings"
+ '
+ 'numThreshold
+ '
+ Me.numThreshold.Location = New System.Drawing.Point(162, 16)
+ Me.numThreshold.Minimum = New Decimal(New Integer() {50, 0, 0, 0})
+ Me.numThreshold.Name = "numThreshold"
+ Me.numThreshold.Size = New System.Drawing.Size(91, 20)
+ Me.numThreshold.TabIndex = 1
+ Me.numThreshold.Value = New Decimal(New Integer() {90, 0, 0, 0})
+ '
+ 'Label1
+ '
+ Me.Label1.AutoSize = True
+ Me.Label1.Location = New System.Drawing.Point(7, 16)
+ Me.Label1.Name = "Label1"
+ Me.Label1.Size = New System.Drawing.Size(125, 13)
+ Me.Label1.TabIndex = 0
+ Me.Label1.Text = "Recognition Threshold %"
+ '
+ 'buttonSave
+ '
+ Me.buttonSave.Location = New System.Drawing.Point(190, 138)
+ Me.buttonSave.Name = "buttonSave"
+ Me.buttonSave.Size = New System.Drawing.Size(75, 23)
+ Me.buttonSave.TabIndex = 4
+ Me.buttonSave.Text = "Save"
+ Me.buttonSave.UseVisualStyleBackColor = True
+ '
+ 'checkLast
+ '
+ Me.checkLast.AutoSize = True
+ Me.checkLast.Location = New System.Drawing.Point(14, 141)
+ Me.checkLast.Name = "checkLast"
+ Me.checkLast.Size = New System.Drawing.Size(168, 17)
+ Me.checkLast.TabIndex = 5
+ Me.checkLast.Text = "Show last command executed"
+ Me.checkLast.UseVisualStyleBackColor = True
+ '
+ 'formConfig
+ '
+ Me.AutoScaleDimensions = New System.Drawing.SizeF(6.0!, 13.0!)
+ Me.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font
+ Me.ClientSize = New System.Drawing.Size(283, 172)
+ Me.Controls.Add(Me.checkLast)
+ Me.Controls.Add(Me.buttonSave)
+ Me.Controls.Add(Me.groupRecog)
+ Me.Controls.Add(Me.groupInput)
+ Me.FormBorderStyle = System.Windows.Forms.FormBorderStyle.FixedDialog
+ Me.MaximizeBox = False
+ Me.MinimizeBox = False
+ Me.Name = "formConfig"
+ Me.Text = "HDT-Voice Configuration"
+ Me.groupInput.ResumeLayout(False)
+ Me.groupInput.PerformLayout()
+ Me.groupRecog.ResumeLayout(False)
+ Me.groupRecog.PerformLayout()
+ CType(Me.numThreshold, System.ComponentModel.ISupportInitialize).EndInit()
+ Me.ResumeLayout(False)
+ Me.PerformLayout()
+
+ End Sub
+
+ Friend WithEvents checkDefaultAudio As System.Windows.Forms.CheckBox
+ Friend WithEvents comboAudioDevice As System.Windows.Forms.ComboBox
+ Friend WithEvents groupInput As System.Windows.Forms.GroupBox
+ Friend WithEvents groupRecog As System.Windows.Forms.GroupBox
+ Friend WithEvents numThreshold As System.Windows.Forms.NumericUpDown
+ Friend WithEvents Label1 As System.Windows.Forms.Label
+ Friend WithEvents buttonSave As System.Windows.Forms.Button
+ Friend WithEvents checkLast As System.Windows.Forms.CheckBox
+End Class
diff --git a/hsVoiceCommands/formConfig.resx b/hsVoiceCommands/formConfig.resx
new file mode 100644
index 0000000..1af7de1
--- /dev/null
+++ b/hsVoiceCommands/formConfig.resx
@@ -0,0 +1,120 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ text/microsoft-resx
+
+
+ 2.0
+
+
+ System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
+
+
+ System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
+
+
\ No newline at end of file
diff --git a/hsVoiceCommands/formConfig.vb b/hsVoiceCommands/formConfig.vb
new file mode 100644
index 0000000..14c10b2
--- /dev/null
+++ b/hsVoiceCommands/formConfig.vb
@@ -0,0 +1,13 @@
+Public Class formConfig
+ Private Sub buttonSave_Click(sender As Object, e As EventArgs) Handles buttonSave.Click
+ My.Settings.Threshold = numThreshold.Value
+ My.Settings.showLast = checkLast.Checked
+ My.Settings.Save()
+ Me.Close()
+ End Sub
+
+ Private Sub formConfig_Load(sender As Object, e As EventArgs) Handles MyBase.Load
+ numThreshold.Value = My.Settings.Threshold
+ checkLast.Checked = My.Settings.showLast
+ End Sub
+End Class
\ No newline at end of file
diff --git a/hsVoiceCommands/hsVoicePlugin.vb b/hsVoiceCommands/hsVoicePlugin.vb
new file mode 100644
index 0000000..c386dfd
--- /dev/null
+++ b/hsVoiceCommands/hsVoicePlugin.vb
@@ -0,0 +1,869 @@
+Imports System.Speech.Recognition
+Imports System.Threading.Thread
+Imports System.Windows.Controls
+Imports System.Windows.Forms
+Imports System.ComponentModel
+Imports System.Drawing
+
+Imports Hearthstone_Deck_Tracker
+Imports Hearthstone_Deck_Tracker.API
+Imports Hearthstone_Deck_Tracker.Enums
+Imports Hearthstone_Deck_Tracker.Hearthstone
+Imports Hearthstone_Deck_Tracker.Hearthstone.Entities
+Public Class hsVoicePlugin
+ ' Windows API Declarations
+ Private Declare Function FindWindow Lib "user32" Alias "FindWindowA" (ByVal lpClassName As String, ByVal lpWindowName As String) As IntPtr
+ Private Declare Function GetWindowRect Lib "user32" Alias "GetWindowRect" (ByVal hwnd As IntPtr, ByRef lpRect As RECT) As Integer
+ Private Declare Sub mouse_event Lib "user32.dll" (ByVal dwFlags As Integer, ByVal dx As Integer, ByVal dy As Integer, ByVal cButtons As Integer, ByVal dwExtraInfo As IntPtr)
+ Public Declare Function GetForegroundWindow Lib "user32" () As System.IntPtr
+ Public Declare Auto Function GetWindowText Lib "user32" _
+(ByVal hWnd As System.IntPtr,
+ByVal lpString As System.Text.StringBuilder,
+ByVal cch As Integer) As Integer
+
+ Public WithEvents timerResetStatus As Timer
+ Public lastCommand As New String("none")
+
+ Const MOUSEEVENTF_LEFTDOWN As UInteger = &H2
+ Const MOUSEEVENTF_LEFTUP As UInteger = &H4
+ Const MOUSEEVENTF_RIGHTDOWN As UInteger = &H8
+ Const MOUSEEVENTF_RIGHTUP As UInteger = &H10
+ Structure RECT
+ Public Left As Integer
+ Public Top As Integer
+ Public Right As Integer
+ Public Bottom As Integer
+ End Structure
+
+ ' Speech recognition objects
+ Public WithEvents hsRecog As SpeechRecognitionEngine
+ Public WithEvents recogWorker As New BackgroundWorker
+
+ Public hdtStatus As HearthstoneTextBlock
+
+ Public handCards, boardOpponent, boardFriendly As New List(Of Entity)
+ Public playerID, opponentID As Integer
+ Public mulliganDone As Boolean
+ Private ReadOnly Property Entities As Entity()
+ Get
+ ' Clone entities from game and return as array
+ Return Helper.DeepClone(Game.Entities).Values.ToArray
+ End Get
+ End Property
+ Private ReadOnly Property PlayerEntity As Entity
+ Get
+ ' Return the Entity representing the player
+ Try
+ Return Entities.First(Function(x) x.IsPlayer())
+ Catch ex As Exception
+ Return Nothing
+ End Try
+ End Get
+ End Property
+ Private ReadOnly Property OpponentEntity As Entity
+ Get
+ ' Return the Entity representing the player
+ Try
+ Return Entities.First(Function(x) x.IsOpponent())
+ Catch ex As Exception
+ Return Nothing
+ End Try
+ End Get
+ End Property
+ Public Sub Load()
+ ' Initialize speech recogition object
+ hsRecog = New SpeechRecognitionEngine
+ hsRecog.SetInputToDefaultAudioDevice()
+ hsRecog.BabbleTimeout = New TimeSpan(0, 0, 5)
+ hsRecog.InitialSilenceTimeout = New TimeSpan(0, 0, 5)
+
+ timerResetStatus = New Timer
+ timerResetStatus.Enabled = True
+ timerResetStatus.Interval = 2000
+
+ 'Initialize values
+ playerID = 0
+ opponentID = 0
+
+ ' Set up output block
+ hdtStatus = New HearthstoneTextBlock
+ hdtStatus.Text = "HDT-Voice: Loading, please wait..."
+ hdtStatus.FontSize = 16
+
+ Dim overlayCanvas = Overlay.OverlayCanvas
+
+ Canvas.SetTop(hdtStatus, 22)
+ Canvas.SetLeft(hdtStatus, 4)
+
+ overlayCanvas.Children.Add(hdtStatus)
+
+ 'Add event handlers
+ GameEvents.OnGameStart.Add(New Action(AddressOf onNewGame))
+ GameEvents.OnPlayerMulligan.Add(New Action(Of Card)(AddressOf onMulligan))
+ GameEvents.OnTurnStart.Add(New Action(Of ActivePlayer)(AddressOf rebuildCardData))
+ GameEvents.OnPlayerPlay.Add(New Action(Of Card)(AddressOf rebuildCardData))
+
+ recogWorker.RunWorkerAsync()
+
+ End Sub
+ Public Sub onNewGame()
+ ' Initialize controller IDs
+ playerID = Nothing
+ opponentID = Nothing
+ mulliganDone = False
+
+ If Not IsNothing(PlayerEntity) Then _
+ playerID = PlayerEntity.GetTag(GAME_TAG.CONTROLLER)
+ If Not IsNothing(OpponentEntity) Then _
+ opponentID = OpponentEntity.GetTag(GAME_TAG.CONTROLLER)
+ End Sub
+ Public Sub onMulligan(Optional c As Card = Nothing)
+ mulliganDone = True
+ End Sub
+ Public Sub onSpeechRecognized(sender As Object, e As SpeechRecognizedEventArgs) Handles hsRecog.SpeechRecognized
+
+ If Not checkActiveWindow() Then Return
+
+ 'If below preset confidence threshold then exit
+ If e.Result.Confidence < My.Settings.Threshold / 100 Then Return
+
+ rebuildCardData()
+ UpdateStatus("Executing """ & e.Result.Text & """...")
+
+ If e.Result.Semantics.ContainsKey("action") Then
+ Select Case e.Result.Semantics("action").Value
+ Case "focus"
+ doFocus(e)
+
+ Case "click"
+ doClick(e)
+
+ Case "mulligan" 'mulligan a card or confirm
+ doMulligan(e)
+
+ Case "play" 'play a card
+ doPlay(e)
+
+ Case "attack" 'Attack with minion
+ doAttack(e)
+
+ Case "hero" ' Use hero power
+ doHero(e)
+
+ Case "say" ' Do an emote
+ doSay(e)
+
+ Case "choose"
+ doChoose(e)
+
+ Case "cancel"
+ sendRightClick()
+
+ Case "end"
+ moveCursor(91, 46) 'end turn button
+ sendLeftClick()
+
+ End Select
+
+ End If
+
+ If e.Result.Semantics.ContainsKey("menu") And Game.IsInMenu Then
+ doMenu(e)
+ End If
+ lastCommand = e.Result.Text
+ End Sub
+
+ Private Sub doChoose(e As SpeechRecognizedEventArgs)
+ Dim optNum = e.Result.Semantics("option").Value
+ Dim optmax = e.Result.Semantics("max").Value
+ moveCursorToOption(optNum, optmax)
+ End Sub
+
+ Private Sub doSay(e As SpeechRecognizedEventArgs)
+ Dim emote = e.Result.Semantics("emote").Value
+ Select Case emote
+ Case "thanks"
+ moveCursor(50, 75)
+ sendRightClick()
+ Sleep(200)
+ moveCursor(40, 64)
+ sendLeftClick()
+ Case "well played"
+ moveCursor(50, 75)
+ sendRightClick()
+ Sleep(200)
+ moveCursor(40, 72)
+ sendLeftClick()
+ Case "greetings"
+ moveCursor(50, 75)
+ sendRightClick()
+ Sleep(200)
+ moveCursor(40, 80)
+ sendLeftClick()
+ Case "sorry"
+ moveCursor(50, 75)
+ sendRightClick()
+ Sleep(200)
+ moveCursor(60, 64)
+ sendLeftClick()
+ Case "oops"
+ moveCursor(50, 75)
+ sendRightClick()
+ Sleep(200)
+ moveCursor(60, 72)
+ sendLeftClick()
+ Case "threaten"
+ moveCursor(50, 75)
+ sendRightClick()
+ Sleep(200)
+ moveCursor(60, 80)
+ sendLeftClick()
+ End Select
+ End Sub
+
+ Private Sub doClick(e As SpeechRecognizedEventArgs)
+ If e.Result.Semantics.ContainsKey("heropower") Then 'focus hero or hero power
+ Dim x, y
+ If e.Result.Semantics("herotarget").Value = "friendly" Then y = 80 Else y = 20
+ If e.Result.Semantics("heropower").Value = "hero" Then x = 50 Else x = 60
+ moveCursor(x, y)
+ End If
+ If e.Result.Semantics.ContainsKey("card") Then
+ Dim targetName = e.Result.Semantics("card").Value
+ moveCursorToTarget(targetName)
+ End If
+ If e.Result.Semantics.ContainsKey("friendly") Then
+ Dim targetName = e.Result.Semantics("friendly").Value
+ moveCursorToTarget(targetName)
+ End If
+ If e.Result.Semantics.ContainsKey("opposing") Then
+ Dim targetName = e.Result.Semantics("opposing").Value
+ moveCursorToTarget(targetName)
+ End If
+ sendLeftClick()
+ End Sub
+
+ Private Sub onResetStatus() Handles timerResetStatus.Tick
+ UpdateStatus("Listening...")
+ timerResetStatus.Enabled = False
+ End Sub
+ Private Sub doMenu(e As SpeechRecognizedEventArgs)
+ Select Case e.Result.Semantics("menu").Value
+ Case "play"
+ moveCursor(50, 31)
+ sendLeftClick()
+ Case "solo"
+ moveCursor(50, 38)
+ sendLeftClick()
+ Case "arena"
+ moveCursor(50, 45)
+ sendLeftClick()
+ Case "brawl"
+ moveCursor(50, 52)
+ sendLeftClick()
+ Case "casual"
+ moveCursor(75, 20)
+ sendLeftClick()
+ Case "ranked"
+ moveCursor(85, 20)
+ sendLeftClick()
+ Case "basic"
+ moveCursor(23, 90)
+ sendLeftClick()
+ Case "custom"
+ moveCursor(45, 90)
+ sendLeftClick()
+ Case "start game"
+ moveCursor(80, 85)
+ sendLeftClick()
+ Case "start brawl"
+ moveCursor(65, 85)
+ sendLeftClick()
+ Case "cancel"
+ moveCursor(52, 85)
+ sendLeftClick()
+ Case "back"
+ moveCursor(92, 92)
+ sendLeftClick()
+ Case "deck"
+ Dim deckNum = e.Result.Semantics("deck").Value
+ Dim deckRow = 1
+ Dim deckCol = deckNum
+ Do While deckCol > 3
+ deckCol -= 3
+ Loop
+
+ If deckNum > 3 Then deckRow = 2
+ If deckNum > 6 Then deckRow = 3
+ Dim deckX As Integer
+ Dim deckY As Integer
+ deckX = 2 + (deckCol * 16)
+ deckY = 8 + (deckRow * 20)
+ moveCursor(deckX, deckY)
+ sendLeftClick()
+ End Select
+ End Sub ' handle menu commands
+ Private Sub doHero(e As SpeechRecognizedEventArgs)
+ If e.Result.Semantics.ContainsKey("friendly") Then
+ Dim friendlyName = e.Result.Semantics("friendly").Value
+ moveCursor(60, 75)
+ Sleep(100)
+ startDrag()
+ Sleep(100)
+ moveCursorToTarget(friendlyName)
+ Sleep(100)
+ endDrag()
+ ElseIf e.Result.Semantics.ContainsKey("opposing") Then
+ Dim friendlyName = e.Result.Semantics("opposing").Value
+ moveCursor(60, 75)
+ Sleep(100)
+ startDrag()
+ Sleep(100)
+ moveCursorToTarget(friendlyName)
+ Sleep(100)
+ endDrag()
+ Else
+ moveCursor(60, 75)
+ Sleep(100)
+ sendLeftClick()
+ End If
+ End Sub 'handle hero powers
+ Private Sub doAttack(e As SpeechRecognizedEventArgs)
+ If e.Result.Semantics.ContainsKey("opposing") Then
+ 'attack minion
+ Dim friendlyName = e.Result.Semantics("friendly").Value
+ Dim targetName = e.Result.Semantics("opposing").Value
+ moveCursorToTarget(friendlyName)
+ Sleep(100)
+ startDrag()
+ Sleep(100)
+ moveCursorToTarget(targetName)
+ Sleep(100)
+ endDrag()
+ Else
+ 'attack face
+ Dim friendlyName = e.Result.Semantics("friendly").Value
+ moveCursorToTarget(friendlyName)
+ Sleep(100)
+ startDrag()
+ Sleep(100)
+ moveCursor(50, 20)
+ Sleep(100)
+ endDrag()
+ End If
+ End Sub 'handle attacking
+ Private Sub doPlay(e As SpeechRecognizedEventArgs)
+ If e.Result.Semantics.ContainsKey("friendly") Then 'play to friendly target
+ Dim cardName = e.Result.Semantics("card").Value
+ Dim targetName = e.Result.Semantics("friendly").Value
+ Dim targetnum = targetName.ToString.Substring(1)
+ Dim newname = "f" & targetnum - 1
+
+ dragTargetToTarget(cardName, newname)
+
+ ElseIf e.Result.Semantics.ContainsKey("opposing") Then 'play to opposing target
+ Dim cardName = e.Result.Semantics("card").Value
+ Dim targetName = e.Result.Semantics("opposing").Value
+ dragTargetToTarget(cardName, targetName)
+
+ Else
+ Dim cardName = e.Result.Semantics("card").Value 'play to board
+ moveCursorToTarget(cardName)
+ startDrag()
+ moveCursor(85, 55)
+ endDrag()
+
+ End If
+ End Sub 'handle playing cards
+ Private Sub doMulligan(e As SpeechRecognizedEventArgs)
+ If e.Result.Semantics.ContainsKey("card") Then
+ Dim targetName = e.Result.Semantics("card").Value
+ Dim targetNum = Convert.ToInt32(targetName.ToString.Substring(1))
+ If Game.OpponentHasCoin Then
+ moveCursorToOption(targetNum, 3)
+ sendLeftClick()
+
+ Else
+ moveCursorToOption(targetNum, 4)
+ sendLeftClick()
+ End If
+ Else
+ moveCursor(50, 80)
+ sendLeftClick()
+ End If
+ End Sub 'handle mulligan
+ Private Sub doFocus(e As SpeechRecognizedEventArgs)
+ If e.Result.Semantics.ContainsKey("heropower") Then 'focus hero or hero power
+ Dim x, y
+ If e.Result.Semantics("herotarget").Value = "friendly" Then y = 80 Else y = 20
+ If e.Result.Semantics("heropower").Value = "hero" Then x = 50 Else x = 60
+ moveCursor(x, y)
+ End If
+ If e.Result.Semantics.ContainsKey("card") Then
+ Dim targetName = e.Result.Semantics("card").Value
+ moveCursorToTarget(targetName)
+ End If
+ If e.Result.Semantics.ContainsKey("friendly") Then
+ Dim targetName = e.Result.Semantics("friendly").Value
+ moveCursorToTarget(targetName)
+ End If
+ If e.Result.Semantics.ContainsKey("opposing") Then
+ Dim targetName = e.Result.Semantics("opposing").Value
+ moveCursorToTarget(targetName)
+ End If
+ End Sub 'handle focusing cursor
+ Public Sub sendLeftClick()
+ mouse_event(MOUSEEVENTF_LEFTDOWN, Cursor.Position.X, Cursor.Position.Y, 0, 0)
+ Sleep(50)
+ mouse_event(MOUSEEVENTF_LEFTUP, Cursor.Position.X, Cursor.Position.Y, 0, 0)
+ Sleep(50)
+ End Sub
+ Public Sub sendRightClick()
+ mouse_event(MOUSEEVENTF_RIGHTDOWN, Cursor.Position.X, Cursor.Position.Y, 0, 0)
+ Sleep(50)
+ mouse_event(MOUSEEVENTF_RIGHTUP, Cursor.Position.X, Cursor.Position.Y, 0, 0)
+ Sleep(50)
+ End Sub
+ Public Sub startDrag()
+ mouse_event(MOUSEEVENTF_LEFTDOWN, Cursor.Position.X, Cursor.Position.Y, 0, 0)
+ Sleep(50)
+ End Sub
+ Public Sub endDrag()
+ mouse_event(MOUSEEVENTF_LEFTUP, Cursor.Position.X, Cursor.Position.Y, 0, 0)
+ End Sub
+ Public Sub dragTargetToTarget(startTarget As String, endTarget As String)
+ moveCursorToTarget(startTarget)
+ startDrag()
+ moveCursorToTarget(endTarget)
+ endDrag()
+ End Sub
+ Public Sub moveCursorToOption(optionNum As Integer, totalOptions As Integer)
+ Dim optionsWidth As Integer = totalOptions * 20
+ Dim myOption As Integer = (optionNum * 20) - 10
+ Dim optionStart As Integer = 50 - (optionsWidth / 2)
+ moveCursor(optionStart + myOption, 50)
+ End Sub
+ Public Sub moveCursorToTarget(TargetName As String)
+ 'Reads a target returned by the speech recognition semantic key
+ Select Case TargetName.Substring(0, 1)
+ Case "c" ' Target is a card
+ Dim cardNum = Convert.ToInt32(TargetName.Substring(1))
+ Dim totalCards = handCards.Count
+ Dim cardWidth
+ If totalCards > 3 Then
+ cardWidth = (36 / totalCards)
+ Else
+ cardWidth = 11
+ End If
+ Dim cardsWidth = (totalCards * cardWidth)
+ Dim myCardPos = (cardNum) * cardWidth
+ Dim cardX As Integer = 45 - (cardsWidth / 2) + myCardPos - (cardWidth / 2) + 1
+ moveCursor(cardX, 93)
+ Case "f" ' Target is a friendly minion
+ Dim tarMinion = Convert.ToInt32(TargetName.Substring(1))
+ Dim allMinions = boardFriendly.Count
+
+ Dim allWidth = allMinions * 10
+ Dim myMinion = tarMinion * 10 - 5
+
+ Dim minX = 50 - (allWidth / 2) + myMinion
+ moveCursor(minX, 55)
+ Case "e" ' Target is an enemy minion
+ Dim tarMinion = Convert.ToInt32(TargetName.Substring(1))
+ Dim allMinions = boardOpponent.Count
+
+ Dim allWidth = allMinions * 10
+ Dim myMinion = tarMinion * 10
+
+ Dim minX = 50 - (allWidth / 2) + myMinion - 5
+ moveCursor(minX, 40)
+ Case "h" ' Target is a hero
+ If TargetName.Substring(1) = 1 Then
+ moveCursor(50, 75)
+ Else
+ moveCursor(50, 20)
+ End If
+ End Select
+ End Sub
+ Public Sub moveCursor(xPercent As Integer, yPercent As Integer)
+ Dim hsWindow As IntPtr = FindWindow(Nothing, "Hearthstone")
+ Dim hsRect As RECT
+ GetWindowRect(hsWindow, hsRect)
+ Dim windowWidth, windowHeight, uiWidth, uiOffset As Integer
+ windowWidth = hsRect.Right - hsRect.Left
+ windowHeight = hsRect.Bottom - hsRect.Top + 8
+
+ uiWidth = windowHeight / 3 * 4
+ uiOffset = (windowWidth - uiWidth) / 2
+ Cursor.Position = New Point(hsRect.Left + uiOffset + (xPercent / 100 * uiWidth), hsRect.Top + (yPercent / 100 * windowHeight))
+ Sleep(100)
+ End Sub
+ Public Function checkActiveWindow()
+ Dim activeHwnd = GetForegroundWindow()
+ Dim activeWindowText As New System.Text.StringBuilder(32)
+ GetWindowText(activeHwnd, activeWindowText, activeWindowText.Capacity)
+ If activeWindowText.ToString = "Hearthstone" Then
+ Return True
+ Else
+ Return False
+ End If
+ End Function
+ Public Sub recogWorker_DoWork() Handles recogWorker.DoWork
+
+ Do While Not recogWorker.CancellationPending
+ If Not Game.IsRunning Then
+ System.Threading.Thread.Sleep(1000)
+ Else
+ UpdateStatus("Listening...")
+
+ hsRecog.UnloadAllGrammars()
+ hsRecog.LoadGrammar(buildGrammar)
+ hsRecog.Recognize()
+ End If
+
+ Loop
+ End Sub
+ Public Sub UpdateStatus(Status As String)
+ Try
+ hdtStatus.Dispatcher.Invoke(Sub()
+ Dim newStatus = "HDT-Voice: "
+ newStatus &= Status
+ If My.Settings.showLast Then
+ newStatus &= vbNewLine & "Last executed: " & lastCommand
+ End If
+ hdtStatus.Text = newStatus
+ End Sub)
+ Catch ex As Exception
+ Return
+ End Try
+
+ End Sub
+ Public Function buildGrammar() As Grammar
+ Debug.WriteLine("Building grammar")
+
+ If Game.IsInMenu Then
+ Dim menuGrammar As New GrammarBuilder
+ Dim menuChoices As New Choices
+
+
+ menuChoices.Add(New SemanticResultKey("menu", "play"))
+ menuChoices.Add(New SemanticResultKey("menu", "solo"))
+ menuChoices.Add(New SemanticResultKey("menu", "arena"))
+ menuChoices.Add(New SemanticResultKey("menu", "brawl"))
+ menuChoices.Add(New SemanticResultKey("menu", "casual"))
+ menuChoices.Add(New SemanticResultKey("menu", "ranked"))
+ menuChoices.Add(New SemanticResultKey("menu", "basic"))
+ menuChoices.Add(New SemanticResultKey("menu", "custom"))
+ menuChoices.Add(New SemanticResultKey("menu", "start game"))
+ menuChoices.Add(New SemanticResultKey("menu", "start brawl"))
+ menuChoices.Add(New SemanticResultKey("menu", "cancel"))
+ menuChoices.Add(New SemanticResultKey("menu", "back"))
+
+ Dim deckGrammar As New GrammarBuilder
+ Dim deckChoices As New Choices
+ deckGrammar.Append(New SemanticResultKey("menu", "deck"))
+ For i = 1 To 9
+ deckChoices.Add(New SemanticResultKey("deck", i.ToString))
+ Next
+ deckGrammar.Append(deckChoices)
+ menuChoices.Add(deckGrammar)
+ menuGrammar.Append(menuChoices)
+
+ Return New Grammar(menuGrammar)
+ End If
+
+ ' if the player or opponent entity is unknown, try initiate a new game
+ If Game.IsRunning And playerID = 0 Or opponentID = 0 Then
+ onNewGame()
+ End If
+
+
+
+ rebuildCardData()
+
+ 'generate names and numbers for all targets
+ Dim cardGrammar As New GrammarBuilder
+
+ Dim friendlyNames As New Choices("friendly", "my")
+ Dim opposingNames As New Choices("opposing", "enemy", "opponent")
+
+ If handCards.Count > 0 Then
+ ' build grammar for cards in hand
+ Dim handGrammarNames, handGrammarNumbers As New Choices
+ For Each e In handCards
+ Dim CardName As New String(e.Card.Name)
+ Dim CardInstances = handCards.FindAll(Function(x) x.CardId = e.CardId)
+ If CardInstances.Count > 1 Then ' if we have multiple cards with the same name, add a numeric identifier
+ Dim CardNum As Integer = CardInstances.IndexOf(CardInstances.Find(Function(x) x.Id = e.Id)) + 1
+ CardName &= " " & CardNum.ToString
+ End If
+ handGrammarNames.Add(New SemanticResultValue(CardName, "c" & (handCards.IndexOf(e) + 1).ToString))
+ handGrammarNumbers.Add(New SemanticResultValue((handCards.IndexOf(e) + 1).ToString, "c" & (handCards.IndexOf(e) + 1).ToString))
+ Next
+ cardGrammar.Append(New SemanticResultKey("card", New Choices(handGrammarNames, handGrammarNumbers)))
+ End If
+
+ ' Build the grammar for friendly minions and hero
+ Dim friendlyGrammar As New GrammarBuilder ' Represents the names and numbers of minions, and the hero
+ Dim friendlyChoices As New Choices
+
+ If boardFriendly.Count > 0 Then
+ Dim friendlyGrammarNames, friendlyGrammarNumbers As New Choices
+ For Each e In boardFriendly
+ Dim CardName As New String(e.Card.Name)
+ Dim CardInstances = boardFriendly.FindAll(Function(x) x.CardId = e.CardId)
+ If CardInstances.Count > 1 Then ' More than one instance of the card on the board, append a number
+ Dim CardNum As Integer = CardInstances.IndexOf(CardInstances.Find(Function(x) x.Id = e.Id)) + 1
+ CardName &= " " & CardNum.ToString
+ End If
+ friendlyGrammarNames.Add(New SemanticResultValue(CardName, "f" & (boardFriendly.IndexOf(e) + 1).ToString))
+ friendlyGrammarNumbers.Add(New SemanticResultValue("minion " & (boardFriendly.IndexOf(e) + 1).ToString, "f" & (boardFriendly.IndexOf(e) + 1).ToString))
+ Next
+ friendlyChoices.Add(friendlyGrammarNames, friendlyGrammarNumbers)
+ End If
+
+ Dim friendlyHero As New Choices
+ friendlyHero.Add(New SemanticResultValue("hero", "h1"))
+ friendlyHero.Add(New SemanticResultValue("face", "h1"))
+ friendlyChoices.Add(friendlyHero)
+ friendlyGrammar.Append(New SemanticResultKey("friendly", friendlyChoices))
+
+ ' Build grammar for opposing minions and hero
+ Dim opposingGrammar As New GrammarBuilder
+ Dim opposingChoices As New Choices
+ If boardOpponent.Count > 0 Then
+
+ Dim opposingGrammarNames, opposingGrammarNumbers As New Choices
+ For Each e In boardOpponent
+ Dim CardName As New String(e.Card.Name)
+ Dim CardInstances = boardOpponent.FindAll(Function(x) x.CardId = e.CardId)
+ If CardInstances.Count > 1 Then
+ Dim CardNum As Integer = CardInstances.IndexOf(CardInstances.Find(Function(x) x.Id = e.Id)) + 1
+ CardName &= " " & CardNum.ToString
+ End If
+ opposingGrammarNames.Add(New SemanticResultValue(CardName, "e" & (boardOpponent.IndexOf(e) + 1).ToString))
+ opposingGrammarNumbers.Add(New SemanticResultValue("minion " & (boardOpponent.IndexOf(e) + 1).ToString, "e" & (boardOpponent.IndexOf(e) + 1).ToString))
+ Next
+ opposingChoices.Add(opposingGrammarNames, opposingGrammarNumbers)
+ End If
+ Dim opposingHero As New Choices
+ opposingHero.Add(New SemanticResultValue("hero", "h2"))
+ opposingHero.Add(New SemanticResultValue("face", "h2"))
+ opposingChoices.Add(opposingHero)
+ opposingGrammar.Append(New SemanticResultKey("opposing", New Choices(opposingChoices)))
+
+ ' Start building the final grammar
+ Dim finalChoices As New Choices
+
+ ' Check if we're at the mulligan, if so only the mulligan grammar will be returned
+ If (Not mulliganDone) And (Not Game.IsMulliganDone) Then
+ Dim mulliganBuilder As New GrammarBuilder
+ mulliganBuilder.Append(New SemanticResultKey("action", New SemanticResultValue("click", "mulligan")))
+ Dim mulliganChoices As New Choices
+ mulliganChoices.Add("confirm")
+ mulliganChoices.Add(cardGrammar)
+ mulliganBuilder.Append(New Choices(mulliganChoices, "confirm"))
+
+ finalChoices.Add(mulliganBuilder)
+ Return New Grammar(New GrammarBuilder(finalChoices))
+ End If
+
+ 'build grammar for card actions
+ If cardGrammar.DebugShowPhrases.Count Then
+ 'focus card
+ Dim focusCards As New GrammarBuilder
+ focusCards.Append(New SemanticResultKey("action", "focus"))
+ focusCards.Append("card")
+ focusCards.Append(cardGrammar)
+
+ 'play card with no target
+ Dim playCards As New GrammarBuilder
+ playCards.Append(New SemanticResultKey("action", "play"))
+ playCards.Append(cardGrammar)
+
+ 'play card with friendly target
+ If friendlyGrammar.DebugShowPhrases.Count Then
+ Dim playToFriendly As New GrammarBuilder
+ playToFriendly.Append(New SemanticResultKey("action", "play"))
+ playToFriendly.Append(cardGrammar)
+ playToFriendly.Append("to")
+ playToFriendly.Append(friendlyNames)
+ playToFriendly.Append(friendlyGrammar)
+
+ finalChoices.Add(playToFriendly)
+ End If
+
+ 'play card to opposing target
+ If opposingGrammar.DebugShowPhrases.Count Then
+ Dim playToOpposing As New GrammarBuilder
+ playToOpposing.Append(New SemanticResultKey("action", "play"))
+ playToOpposing.Append(cardGrammar)
+ playToOpposing.Append("to")
+ playToOpposing.Append(opposingNames)
+ playToOpposing.Append(opposingGrammar)
+
+ finalChoices.Add(playToOpposing)
+ End If
+
+ 'play card to position
+ Dim playToPosition As New GrammarBuilder
+ playToPosition.Append(New SemanticResultKey("action", "play"))
+ playToPosition.Append(cardGrammar)
+ playToPosition.Append("to position")
+ Dim posNumbers As New Choices
+ For i = 1 To boardFriendly.Count + 1
+ posNumbers.Add(i.ToString)
+ Next
+ playToPosition.Append(posNumbers)
+
+ finalChoices.Add(playToPosition)
+ finalChoices.Add(playCards)
+ finalChoices.Add(focusCards)
+ End If
+
+ 'build grammar friendly minion actions
+ If friendlyGrammar.DebugShowPhrases.Count Then
+ 'focus friendly minion
+ Dim focusFriendly As New GrammarBuilder
+ focusFriendly.Append(New SemanticResultKey("action", "focus"))
+ focusFriendly.Append(friendlyNames)
+ focusFriendly.Append(friendlyGrammar)
+ finalChoices.Add(focusFriendly)
+
+ 'attack target with friendly minion
+ Dim attackFriendly As New GrammarBuilder
+ attackFriendly.Append(New SemanticResultKey("action", "attack"))
+ attackFriendly.Append(opposingGrammar)
+ attackFriendly.Append("with")
+ attackFriendly.Append(friendlyGrammar)
+ finalChoices.Add(attackFriendly)
+
+ 'use hero power on friendly target
+ Dim heroFriendly As New GrammarBuilder
+ heroFriendly.Append("use")
+ heroFriendly.Append(New SemanticResultKey("action", "hero"))
+ heroFriendly.Append("power on")
+ heroFriendly.Append(friendlyNames)
+ heroFriendly.Append(friendlyGrammar)
+ finalChoices.Add(heroFriendly)
+
+ 'click friendly target
+ Dim clickFriendly As New GrammarBuilder
+ clickFriendly.Append(New SemanticResultKey("action", "click"))
+ clickFriendly.Append(friendlyNames)
+ clickFriendly.Append(friendlyGrammar)
+ finalChoices.Add(clickFriendly)
+
+
+ End If
+
+ If opposingGrammar.DebugShowPhrases.Count Then
+ Dim focusOpposing As New GrammarBuilder
+ focusOpposing.Append(New SemanticResultKey("action", "focus"))
+ focusOpposing.Append(opposingNames)
+ focusOpposing.Append(opposingGrammar)
+ finalChoices.Add(focusOpposing)
+
+ Dim heroOpposing As New GrammarBuilder
+ heroOpposing.Append("use")
+ heroOpposing.Append(New SemanticResultKey("action", "hero"))
+ heroOpposing.Append("power on")
+ heroOpposing.Append(opposingNames)
+ heroOpposing.Append(opposingGrammar)
+ finalChoices.Add(heroOpposing)
+
+ 'click opposing target
+ Dim clickOpposing As New GrammarBuilder
+ clickOpposing.Append(New SemanticResultKey("action", "click"))
+ clickOpposing.Append(opposingNames)
+ clickOpposing.Append(opposingGrammar)
+ finalChoices.Add(clickOpposing)
+ End If
+
+ Dim heroPower As New GrammarBuilder
+ heroPower.Append("use")
+ heroPower.Append(New SemanticResultKey("action", "hero"))
+ heroPower.Append("power")
+ finalChoices.Add(heroPower)
+
+ Dim endTurn As New GrammarBuilder
+ endTurn.Append(New SemanticResultKey("action", "end"))
+ endTurn.Append("turn")
+ finalChoices.Add(endTurn)
+
+ Dim sayEmote As New GrammarBuilder
+ sayEmote.Append(New SemanticResultKey("action", "say"))
+ Dim sayChoices As New Choices
+ sayChoices.Add(New SemanticResultValue("thanks", "thanks"))
+ sayChoices.Add(New SemanticResultValue("well played", "well played"))
+ sayChoices.Add(New SemanticResultValue("greetings", "greetings"))
+ sayChoices.Add(New SemanticResultValue("sorry", "sorry"))
+ sayChoices.Add(New SemanticResultValue("oops", "oops"))
+ sayChoices.Add(New SemanticResultValue("threaten", "threaten"))
+ sayEmote.append(New SemanticResultKey("emote", sayChoices))
+ finalChoices.Add(sayEmote)
+
+ Dim chooseOption As New GrammarBuilder
+ Dim maxOptions = 4
+ Dim optionChoices As New Choices
+ For optMax = 1 To maxOptions
+ optionChoices.Add(optMax.ToString)
+ Next
+
+ chooseOption.Append(New SemanticResultKey("action", "choose"))
+ chooseOption.Append("option")
+ chooseOption.Append(New SemanticResultKey("option", optionChoices))
+ chooseOption.Append("of")
+ chooseOption.Append(New SemanticResultKey("max", optionChoices))
+ finalChoices.Add(chooseOption)
+
+ finalChoices.Add(New SemanticResultKey("action", "click"))
+ finalChoices.Add(New SemanticResultKey("action", "cancel"))
+
+ Try
+ Return New Grammar(New GrammarBuilder(finalChoices))
+ Catch ex As Exception
+ Return New Grammar(New GrammarBuilder("error"))
+ End Try
+
+
+ End Function 'builds and returns grammar for the speech recognition engine
+ Public Sub rebuildCardData()
+ 'build list of cards in hand
+ handCards.Clear()
+
+ For Each e In Entities
+ If e.IsInHand And e.GetTag(GAME_TAG.CONTROLLER) = playerID Then
+ handCards.Add(e)
+ End If
+ Next
+
+ ' sort cards by position in hand
+ handCards.Sort(Function(e1 As Entity, e2 As Entity)
+ Return e1.GetTag(GAME_TAG.ZONE_POSITION).CompareTo(e2.GetTag(GAME_TAG.ZONE_POSITION))
+ End Function)
+
+ ' build list of minions on board
+ boardFriendly.Clear()
+ boardOpponent.Clear()
+
+ For Each e In Entities
+ If e.IsInPlay And e.IsMinion Then
+ If e.IsControlledBy(playerID) Then
+ boardFriendly.Add(e)
+ ElseIf e.IsControlledBy(opponentID) Then
+ boardOpponent.Add(e)
+ End If
+ End If
+ Next
+
+ ' sort by position on board
+ boardFriendly.Sort(Function(e1 As Entity, e2 As Entity)
+ Return e1.GetTag(GAME_TAG.ZONE_POSITION).CompareTo(e2.GetTag(GAME_TAG.ZONE_POSITION))
+ End Function)
+
+ boardOpponent.Sort(Function(e1 As Entity, e2 As Entity)
+ Return e1.GetTag(GAME_TAG.ZONE_POSITION).CompareTo(e2.GetTag(GAME_TAG.ZONE_POSITION))
+ End Function)
+ End Sub 'rebuilds data for cards in hand and on board
+End Class