Advertisement
flippingkiwi

AutoHotkey_Mechwarrior5.ahk

Jul 5th, 2021 (edited)
1,832
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
  1. ;=====================
  2. ; SCRIPT VERSION HISTORY
  3. ;=====================
  4. ; SCRIPT VERSION: 1.03
  5. ; 1.03 Changes: Fixed issue with "all lance toggle fire" not working. Added a config entry to enable or disable the toggle fire binding to mouse back button, in case people don't want/need it, or use the button with arm lock
  6. ; 1.02 Changes: made the TTS' vocalised lance member names and orders configurable. Added toggle weapon hold/fire to the 'back' mouse button.
  7.  
  8. ;=====================
  9. ; USER CONFIGURATION
  10. ;=====================
  11. ;If you have a custom icon that you want this AutoHotkey script to use, put the path to it here. If you don't, simply leave it as is and it will fall back to the default.
  12. mw5SystrayIconPath = C:\IconPack\M\dg.ico
  13. ;The delay, in milliseconds, between commands sent to MW5. E.g. After you hit 'F1' to order the lance, you must wait a small period for the command to be processed before you can hit the next F-key to provide the order. I assume the input is checked each game frame, so this will need to be increased if you have low framerate, and probably be safely dropped if you have a high framerate.
  14. global mw5CommandDelay := 30
  15. ;the speaking rate of the voice that talks back to you. Range is [-10,10] (ignored for script-load greeting)
  16. mw5SpeakRate := 3
  17. ;the speaking pitch of the voice that talks back to you. Range is [-10,10]
  18. mw5SpeakPitch := 0
  19. ;the speaking volume. Range is [0,100]
  20. mw5SpeakVolume := 100
  21. ;Names for the lance members, this is what the TTS will call them. Perhaps you want to call your lance alpha, bravo, and charlie.
  22. global mw5LanceMember1Name := "one"
  23. global mw5LanceMember2Name := "two"
  24. global mw5LanceMember3Name := "three"
  25. ;This is what the TTS will say for each command. Perhaps you want to tell your lance to haul their skinny metal butts over there, or something.
  26. global mw5VocalisedCommandFollow := "follow"
  27. global mw5VocalisedCommandMove := "go here"
  28. global mw5VocalisedCommandAttack := "attack"
  29. global mw5VocalisedCommandFireToggle := "toggle fire"
  30. ;Do you want the nice friendly greeting when the script is loaded? :)
  31. mw5PlayGreetingOnStart := true
  32. ;Do you want to enable hotkeys for 'toggle fire' to mouse 'navigate back' button?
  33. mw5BindToggleFireToMouseBackButton := false
  34.  
  35.  
  36. ;=====================
  37. ; AUTOHOTKEY CONFIG
  38. ;=====================
  39. #SingleInstance Force
  40.  
  41.  
  42. ;=====================
  43. ; SET SYSTRAY ICON
  44. ;=====================
  45. ICON [mw5SystrayIconPath]    ;Changes a compiled script's icon (.exe)
  46. if mw5SystrayIconPath <>
  47. IfExist, %mw5SystrayIconPath%
  48.     Menu, Tray, Icon, %mw5SystrayIconPath%   ;Changes menu tray icon
  49.  
  50.  
  51. ;=====================
  52. ; GLOBAL VARIABLES
  53. ;=====================
  54. ;The instance of the TTS helper class.
  55. global mw5s := new TTS()
  56. mw5s.SetVolume(mw5SpeakVolume)
  57.  
  58. ;Boolean, used to determine if we're defining a new group. This gets set to true when the user presses down shift -- so that all key-presses from 1-3 while shift is held, will be defined as the selected mech group.
  59. global mw5StartNewGrouping := false
  60.  
  61. ;Bitflag integer for the selected mechs. First lancemember is bit 1 (value 1), second is bit 2 (value 2), third is bit 3 (value 4)
  62. global mw5MechGroup := 0
  63.  
  64. ;The list of mechs in the selected group. We calculate and cache this when the group is constructed, since we'll use it in all subsequent group commands.
  65. global mw5MechListText := ""
  66.  
  67.  
  68. ;=====================
  69. ; SET DEFAULTS
  70. ;=====================
  71. mw5s.SetPitch(mw5SpeakPitch)
  72. mw5s.SetRate(mw5SpeakRate)
  73.  
  74.  
  75. ;=====================
  76. ; SCRIPT GREETING
  77. ;=====================
  78. if(mw5PlayGreetingOnStart) {
  79.     mw5s.Speak("Mekk warrior command system online. All systems... nomimal.")
  80. }
  81.  
  82.  
  83. ;=====================
  84. ; FUNCTIONS
  85. ;=====================
  86. ;Perform a command for a specific lance member, and provide spoken feedback to user. playerKey = the F1-F4 key to select player, commandKey = F1-F3 to give command of attack, follow, go to. speakText = spoken feedback to user.
  87. MW5Command(playerKey, commandKey, speakText) {
  88.     if(speakText != "") {
  89.         mw5s.Speak(speakText)
  90.     }
  91.  
  92.     ;Send F5 first, which is the 'cancel' command if the player's selected a lance member but hasn't provided a command yet.
  93.     Send {F5}
  94.     Sleep, %mw5CommandDelay%
  95.     Send %playerKey%
  96.     Sleep, %mw5CommandDelay%
  97.     Send %commandKey%
  98.     return
  99. }
  100.  
  101. ;Perform a command for the selected mech group. This will either be ALL mechs, or some combination of lance members 1, 2, and 3.
  102. MW5GroupCommand(orderKey, speakSuffix) {
  103.    
  104.     if(mw5MechGroup = "" or mw5MechGroup = 0 or mw5MechGroup = 7) {
  105.         MW5Command("{F1}", orderKey, "All " . speakSuffix)
  106.     }
  107.     else {
  108.         finalSpeech := mw5MechListText . speakSuffix
  109.         mw5s.Speak(finalSpeech)
  110.         if(mw5MechGroup & 1 > 0) {
  111.             MW5Command("{F2}", orderKey, "")
  112.             Sleep, %mw5CommandDelay%
  113.         }
  114.         if(mw5MechGroup & 2 > 0) {
  115.             MW5Command("{F3}", orderKey, "")
  116.             Sleep, %mw5CommandDelay%
  117.         }
  118.         if(mw5MechGroup & 4 > 0) {
  119.             MW5Command("{F4}", orderKey, "")
  120.             Sleep, %mw5CommandDelay%
  121.         }
  122.     }
  123.    
  124.     return
  125. }
  126.  
  127. ;Add a lance member to the group of mechs you want to command.
  128. MW5AddMech(lanceMemeberBinaryFlag) {
  129.    
  130.     ;If we've JUST held down shift, or just selected the entire group... reset the mech group immediately, then add this mech.
  131.     if(mw5StartNewGrouping = true) {
  132.         mw5StartNewGrouping := false
  133.         mw5MechGroup := 0
  134.     }
  135.    
  136.     ;Ensure the provided member bit flag is set to 'true' on the integer.
  137.     mw5MechGroup := mw5MechGroup | lanceMemeberBinaryFlag
  138.  
  139.     ;Now, have we selected the whole group, or a part of the group??
  140.     if(mw5MechGroup = 0 or mw5MechGroup = 7) {
  141.         mw5s.Speak("Selected all")
  142.     }
  143.     else {
  144.         ;Right, so we've NOT selected the WHOLE lance... go through and make a list of the lance members in the selected sub-set, set it as a global variable.
  145.         ;We'll use this when we give commands to this sub-set of the lance, to allow the user to hear that the command is not going to the WHOLE lance.
  146.         mw5MechListText := ""
  147.         if(mw5MechGroup & 1 > 0) {
  148.             if(mw5MechListText = "") {
  149.                 mw5MechListText := mw5LanceMember1Name
  150.             }
  151.             else {
  152.                 mw5MechListText := mw5MechListText . " and " . mw5LanceMember1Name
  153.             }
  154.         }
  155.         if(mw5MechGroup & 2 > 0) {
  156.             if(mw5MechListText = "") {
  157.                 mw5MechListText := mw5LanceMember2Name
  158.             }
  159.             else {
  160.                 mw5MechListText := mw5MechListText . " and " . mw5LanceMember2Name
  161.             }
  162.         }
  163.         if(mw5MechGroup & 4 > 0) {
  164.             if(mw5MechListText = "") {
  165.                 mw5MechListText := mw5LanceMember3Name
  166.             }
  167.             else {
  168.                 mw5MechListText := mw5MechListText . " and " . mw5LanceMember3Name
  169.             }
  170.         }
  171.        
  172.         ;OK, so we've constructed the list of lance members, give spoken feedback to the player to let them know what they've selected.
  173.         selectmw5MechListText := "Selected " . mw5MechListText
  174.         mw5s.Speak(selectmw5MechListText)
  175.     }
  176.  
  177.    
  178.     return
  179. }
  180.  
  181.  
  182. ;=====================
  183. ; HOTKEY DEFINITIONS - only enabled if playing MW5.
  184. ;=====================
  185.  
  186. #IfWinActive ahk_exe MechWarrior-Win64-Shipping.exe
  187.  
  188. ;Disable LWin key, since we're going to use it as a modifier
  189. LWin::return
  190. ~LWin up::return
  191.  
  192.  
  193. ;When the user presses down shift, set this flag so that we'll know any shift-presses of keys 1-4 will be selecting a new mech group.
  194. ~LShift::
  195.     mw5StartNewGrouping := true
  196. return
  197.  
  198. ;shift+backtick key = select ENTIRE lance.
  199. +Sc029::
  200.     mw5MechGroup := 7
  201.     mw5s.Speak("Reset selection to all")
  202. return
  203.  
  204. ;shift+1 = add first lancemember to selection, if not already in it.
  205. +1::MW5AddMech(1)
  206.  
  207. ;shift+2 = add second lancemember to selection, if not already in it.
  208. +2::MW5AddMech(2)
  209.  
  210. ;shift+3 = add third lancemember to selection, if not already in it.
  211. +3::MW5AddMech(4)
  212.  
  213.  
  214. ;Set of commands for selected lance group (defaulting to entire lance if no group has been defined), using left shift key + scrollwheel.
  215. +WheelUp::MW5GroupCommand("{F3}", " " . mw5VocalisedCommandMove)
  216. +WheelDown::MW5GroupCommand("{F2}", " " . mw5VocalisedCommandFollow)
  217. +MButton::MW5GroupCommand("{F1}", " " . mw5VocalisedCommandAttack)
  218. #If mw5BindToggleFireToMouseBackButton
  219. +XButton1::MW5GroupCommand("{F4}", " " . mw5VocalisedCommandFireToggle)
  220. #If
  221.  
  222. ;Set of commands for lance member one, using left ctrl key + scrollwheel.
  223. ^WheelUp::MW5Command("{F2}", "{F3}", mw5LanceMember1Name . " " . mw5VocalisedCommandMove)
  224. ^WheelDown::MW5Command("{F2}", "{F2}", mw5LanceMember1Name . " " . mw5VocalisedCommandFollow)
  225. ^MButton::MW5Command("{F2}", "{F1}", mw5LanceMember1Name . " " . mw5VocalisedCommandAttack)
  226. #If mw5BindToggleFireToMouseBackButton
  227. ^XButton1::MW5Command("{F2}", "{F4}", mw5LanceMember1Name . " " . mw5VocalisedCommandFireToggle)
  228. #If
  229.  
  230. ;Set of commands for lance member two, using left win key + scrollwheel.
  231. LWin & WheelUp::MW5Command("{F3}", "{F3}", mw5LanceMember2Name . " " . mw5VocalisedCommandMove)
  232. LWin & WheelDown::MW5Command("{F3}", "{F2}", mw5LanceMember2Name . " " . mw5VocalisedCommandFollow)
  233. LWin & MButton::MW5Command("{F3}", "{F1}", mw5LanceMember2Name . " " . mw5VocalisedCommandAttack)
  234. #If mw5BindToggleFireToMouseBackButton
  235. LWin & XButton1::MW5Command("{F3}", "{F4}", mw5LanceMember2Name . " " . mw5VocalisedCommandFireToggle)
  236. #If
  237.  
  238. ;Set of commands for lance member three, using left alt key + scrollwheel.
  239. !WheelUp::MW5Command("{F4}", "{F3}", mw5LanceMember3Name . " " . mw5VocalisedCommandMove)
  240. !WheelDown::MW5Command("{F4}", "{F2}", mw5LanceMember3Name . " " . mw5VocalisedCommandFollow)
  241. !MButton::MW5Command("{F4}", "{F1}", mw5LanceMember3Name . " " . mw5VocalisedCommandAttack)
  242. #If mw5BindToggleFireToMouseBackButton
  243. !XButton1::MW5Command("{F4}", "{F4}", mw5LanceMember3Name . " " . mw5VocalisedCommandFireToggle)
  244. #If
  245.  
  246.  
  247.  
  248. #IfWinActive
  249.  
  250.  
  251.  
  252. ;=====================
  253. ; HELPER CLASS FOR Microsoft's TTS -- SOURCE: https://www.autohotkey.com/boards/viewtopic.php?f=6&t=12304
  254. ;=====================
  255.  
  256. ; Class TTS by evilC
  257. ; Based on code by Learning one. For AHK_L. Thanks: jballi, Sean, Frankie.
  258. ; AHK forum location:   www.autohotkey.com/forum/topic57773.html
  259. ; Read more:            msdn.microsoft.com/en-us/library/ms723602(v=VS.85).aspx, www.autohotkey.com/forum/topic45471.html, www.autohotkey.com/forum/topic83162.html
  260. Class TTS {
  261.     VoiceList := []     ; An indexed array of the available voice names
  262.     VoiceAssoc := {}    ; An Associative array of voice names, key = voice name, value = voice index (VoiceList lookup)
  263.     VoiceCount := 0     ; The number of voices available
  264.     VoiceNumber := 0    ; The number of the current voice
  265.     VoiceName := ""     ; The name of the current voice
  266.    
  267.     __New(){
  268.         this.oVoice := ComObjCreate("SAPI.SpVoice")
  269.         this._GetVoices()
  270.         this.SetVoice(this.VoiceList.1)
  271.     }
  272.  
  273.     ; speak or stop speaking
  274.     ToggleSpeak(text){
  275.         Status := this.oVoice.Status.RunningState
  276.         if Status = 1   ; finished
  277.         this.oVoice.Speak(text,0x1) ; speak asynchronously
  278.         Else if Status = 0  ; paused
  279.         {
  280.             this.oVoice.Resume
  281.             this.oVoice.Speak("",0x1|0x2)   ; stop
  282.             this.oVoice.Speak(text,0x1) ; speak asynchronously
  283.         }
  284.         Else if Status = 2  ; reading
  285.         this.oVoice.Speak("",0x1|0x2)   ; stop
  286.     }
  287.  
  288.     ; speak asynchronously
  289.     Speak(text){
  290.         Status := this.oVoice.Status.RunningState
  291.         if Status = 0   ; paused
  292.         this.oVoice.Resume
  293.         this.oVoice.Speak("",0x1|0x2)   ; stop
  294.         this.oVoice.Speak(text,0x1) ; speak asynchronously
  295.     }
  296.    
  297.     ; speak synchronously
  298.     SpeakWait(text){
  299.         Status := this.oVoice.Status.RunningState
  300.         if Status = 0   ; paused
  301.         this.oVoice.Resume
  302.         this.oVoice.Speak("",0x1|0x2)   ; stop
  303.         this.oVoice.Speak(text,0x0) ; speak synchronously
  304.     }
  305.    
  306.     ; Pause toggle
  307.     Pause(){
  308.         Status := this.oVoice.Status.RunningState
  309.         if Status = 0   ; paused
  310.         this.oVoice.Resume
  311.         else if Status = 2  ; reading
  312.         this.oVoice.Pause
  313.     }
  314.    
  315.     Stop(){
  316.         Status := this.oVoice.Status.RunningState
  317.         if Status = 0   ; paused
  318.         this.oVoice.Resume
  319.         this.oVoice.Speak("",0x1|0x2)   ; stop
  320.     }
  321.    
  322.     ; rate (reading speed): rate from -10 to 10. 0 is default.
  323.     SetRate(rate){
  324.         this.oVoice.Rate := rate
  325.     }
  326.    
  327.     ; volume (reading loudness): vol from 0 to 100. 100 is default
  328.     SetVolume(vol){
  329.         this.oVoice.Volume := vol
  330.     }
  331.    
  332.     ; pitch : From -10 to 10. 0 is default.
  333.     ; http://msdn.microsoft.com/en-us/library/ms717077(v=vs.85).aspx
  334.     SetPitch(pitch){
  335.         this.oVoice.Speak("<pitch absmiddle = '" pitch "'/>",0x20)
  336.     }
  337.  
  338.     ; Set voice by name
  339.     SetVoice(VoiceName){
  340.         if (!ObjHasKey(this.VoiceAssoc, VoiceName))
  341.             return 0
  342.         While !(this.oVoice.Status.RunningState = 1)
  343.         Sleep, 20
  344.         this.oVoice.Voice := this.oVoice.GetVoices("Name=" VoiceName).Item(0) ; set voice to param1
  345.         this.VoiceName := VoiceName
  346.         this.VoiceNumber := this.VoiceAssoc[VoiceName]
  347.         return 1
  348.     }
  349.  
  350.     ; Set voice by index
  351.     SetVoiceByIndex(VoiceIndex){
  352.         return this.SetVoice(this.VoiceList[VoiceIndex])
  353.     }
  354.  
  355.     ; Use the next voice. Loops around at end
  356.     NextVoice(){
  357.         v := this.VoiceNumber + 1
  358.         if (v > this.VoiceCount)
  359.             v := 1
  360.         return this.SetVoiceByIndex(v)
  361.     }
  362.    
  363.     ; Returns an array of voice names
  364.     GetVoices(){
  365.         return this.VoiceList
  366.     }
  367.  
  368.     GetStatus(){
  369.         Status := this.oVoice.Status.RunningState
  370.         if Status = 0 ; paused
  371.         Return "paused"
  372.         Else if Status = 1 ; finished
  373.         Return "finished"
  374.         Else if Status = 2 ; reading
  375.         Return "reading"
  376.     }
  377.    
  378.     GetCount(){
  379.         return this.VoiceCount
  380.     }
  381.    
  382.     SpeakToFile(param1, param2){
  383.         oldAOS := this.oVoice.AudioOutputStream
  384.         oldAAOFCONS := this.oVoice.AllowAudioOutputFormatChangesOnNextSet
  385.         this.oVoice.AllowAudioOutputFormatChangesOnNextSet := 1
  386.        
  387.         SpStream := ComObjCreate("SAPI.SpFileStream")
  388.         FileDelete, % param2    ; OutputFilePath
  389.         SpStream.Open(param2, 3)
  390.         this.oVoice.AudioOutputStream := SpStream
  391.         this.SpeakWait(param1)
  392.         SpStream.Close()
  393.         this.oVoice.AudioOutputStream := oldAOS
  394.         this.oVoice.AllowAudioOutputFormatChangesOnNextSet := oldAAOFCONS
  395.     }
  396.  
  397.     ; ====== Private funcs, not intended to be called by user =======
  398.     _GetVoices(){
  399.         this.VoiceList := []
  400.         this.VoiceAssoc := {}
  401.         this.VoiceCount := this.oVoice.GetVoices.Count
  402.         Loop, % this.VoiceCount
  403.         {
  404.             Name := this.oVoice.GetVoices.Item(A_Index-1).GetAttribute("Name")  ; 0 based
  405.             ;msgbox, %Name%
  406.             this.VoiceList.push(Name)
  407.             this.VoiceAssoc[Name] := A_Index
  408.         }
  409.     }
  410. }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement