Advertisement
Guest User

Untitled

a guest
Mar 15th, 2020
1,801
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
  1. ; WHAT THE SCRIPT ACTUALLY DOES
  2. ; It uses AutoHotKey automation scripting language to control computer's keyboard and mouse. It moves player and shoots randomly, it says random messages at random time, it says randomly messages to killed opponents and it even reads the opponents' messages and answers to them by putting their words in random order with postfix. It also changes player's nickname randomly to make ignoring almost impossible and keeps track of used nickanems in file usednicknames.txt file (if you e.g. want to parse the log file later)
  3.  
  4. ; INSTRUCTIONS
  5. ; 1. Download and install AutoHotKey from https://www.autohotkey.com/
  6. ; 2. Save the script as bot.ahk in Quake 2 root path
  7. ; 3. Download file tf.ahk from https://github.com/hi5/TF and put it to Quake 2 root path
  8. ; 4. Put following setting to Quake 2 config: "logfile 3". This should create log file to baseq2\qconsole.log . If the file path is different in your Quake 2 installation, change variable logFilePath
  9. ; 5. Change you screen resolution to variables xResolution and yResolution
  10. ; 6. Change Quake 2 executable name to variable quake2ExecutableName (e.g. quake2.exe, kmquake2.exe, q2pro.exe ...)
  11. ; 7. Create file messages.txt to Quake 2 root path. Put one message per line that you want the bot to say randomly
  12. ; 8. Create file deaths.txt to Quake 2 root path. Put one message per line that you want the bot to say randomly to the opponent when he/she dies
  13. ; 9. Right click bot.ahk file and select "Run Script"
  14. ; 10. Launch Quake 2 and start the game. The script is paused by default. Press Ctrl+Z to toggle the pause. Press Ctrl+X to stop the script
  15.  
  16. ; TIPS / KNOWN ISSUES
  17. ; - You might want to use VPN to avoid banning of your real IP-address!
  18. ; - Function MapKeys might need adjusting depending on your regional keyboard setup (if you live in US, it's possible that mapping is not needed at all). More info about the mapping process at https://www.autohotkey.com/docs/KeyList.htm#SpecialKeys
  19. ; - It's possible that the bot sometimes answers to itself, because it doesn't remember nickname it was using previously (would need to scan file usednicknames.txt)
  20.  
  21. ; !!! PLEASE FEEL FREE TO MODIFY THE SCRIPT AND HAPPY BOTTING !!!
  22.  
  23.  
  24. ; -------------- VARIABLES --------------
  25.  
  26. ; Executable name that the script runs in. If the application is alt+tabbed to something else, the script stops running automatically
  27. quake2ExecutableName := "kmquake2.exe"
  28. xResolution := 2560
  29. yResolution := 1440
  30. logFilePath := "baseq2\qconsole.log"
  31. messagesFilePath := "messages.txt"
  32. deathsFilePath := "deaths.txt"
  33. usedNickNamesFilePath := "usednicknames.txt"
  34.  
  35.  
  36. ; -------------- SCRIPT STARTS --------------
  37.  
  38. #If WinActive("ahk_exe " . quake2ExecutableName)
  39.  
  40. nickName := ""
  41.  
  42. Pause On
  43.  
  44. xShootCoordinate := Ceil((xResolution/2)*1.06)
  45. ; for 2560x1400 center is 1279, 720
  46. yShootCoordinate := (yResolution/2)-1
  47.  
  48. Loop
  49. {
  50.     if WinActive("ahk_exe " . quake2ExecutableName)
  51.     {
  52.         Random, rand, 1, 60
  53.        
  54.         if (rand = 4)
  55.         {
  56.             nickName := RandomString(15, "lI()!i1 []{}|ll11")
  57.             ConsoleCommand("set name """ . nickName . """")
  58.             FileAppend, %nickName%`r`n, %usedNickNamesFilePath%
  59.         }
  60.         else if (rand > 5 && rand < 10)
  61.         {
  62.             SayMessage(RandomRowFromFile(messagesFilePath))
  63.         }
  64.         else if (rand > 10 && rand < 20)
  65.         {
  66.             ; Second last line, to give some delay for the message
  67.             logRow := LastRowFromFile(logFilePath, -2)
  68.            
  69.             if (IsChatMessageRow(logRow))
  70.             {
  71.                 rowNickName := GetNicknameFromChatMessageRow(logRow)
  72.                
  73.                 ; Only answer to real players and public chat messages
  74.                 if (!InStr(rowNickName, nickName) && !InStr(rowNickName, "console") && !InStr(rowNickName, "WallFly") && !InStr(rowNickName, "(private message)") && !InStr(rowNickName, "(~"))
  75.                 {
  76.                     SayMessage(rowNickName . ", " . WordsToRandomOrder(GetMessageFromChatMessageRow(logRow)) . " LOL :D")
  77.                 }
  78.             }
  79.             else if (IsDeathRow(logRow))
  80.             {
  81.                 rowNickName := GetNicknameFromDeathRow(logRow)
  82.                
  83.                 if (!InStr(rowNickName, nickName))
  84.                 {
  85.                     SayMessage(rowNickName . ", " . RandomRowFromFile(deathsFilePath))
  86.                 }
  87.             }
  88.         }
  89.  
  90.         sleepTime := rand * 40
  91.        
  92.         if (rand < 45)
  93.         {
  94.             Send, {w Down}
  95.             Click, Right
  96.             Sleep %sleepTime%
  97.             Send, {w Up}
  98.         }
  99.         else
  100.         {
  101.             Send, {s Down}
  102.             Click, Right
  103.             Sleep %sleepTime%
  104.             Send, {s Up}
  105.         }
  106.        
  107.         MouseMove, xShootCoordinate, yShootCoordinate
  108.        
  109.         if (rand > 20)
  110.         {
  111.             Click
  112.         }
  113.        
  114.         if (rand > 30)
  115.         {
  116.             Send, {d Down}
  117.             Send, {c Down}
  118.             Sleep 300
  119.             Send, {d Up}
  120.             Send, {c Up}
  121.         }
  122.     }
  123. }
  124. return
  125.  
  126. ; Ctrl + z to toggle pause
  127. ^z::Pause
  128. ; Ctrl + x to exit the script
  129. ^x::ExitApp
  130.  
  131.  
  132. ; -------------- FUNCTIONS STARTS --------------
  133.  
  134. #Include tf.ahk
  135.  
  136. MapKeys(input)
  137. {
  138.     mappedInput := ""
  139.  
  140.     Loop, Parse, input
  141.     {
  142.         char := ""
  143.    
  144.         ; Normal characters that does not need a mapping
  145.         if (RegExMatch(A_LoopField, "[0-9a-zA-Z,.\s]"))
  146.         {
  147.             char := A_LoopField
  148.         }
  149.         else
  150.         {
  151.             ; Special characters that needs special mapping
  152.             switch A_LoopField
  153.             {
  154.                 case "!": char := "+{SC002}"
  155.                 case "@": char := "+{SC003}"
  156.                 case "#": char := "+{SC004}"
  157.                 case "$": char := "+{SC005}"
  158.                 case "%": char := "+{SC006}"
  159.                 case "^": char := "+{SC007}"
  160.                 case "&": char := "+{SC008}"
  161.                 case "*": char := "+{SC009}"
  162.                 case "(": char := "+{SC00A}"
  163.                 case ")": char := "+{SC00B}"
  164.                 case "-": char := "{SC00C}"
  165.                 case "_": char := "+{SC00C}"
  166.                 case "=": char := "{SC00D}"
  167.                 case "+": char := "+{SC00D}"
  168.                 case "[": char := "{SC01A}"
  169.                 case "{": char := "+{SC01A}"
  170.                 case "]": char := "{SC01B}"
  171.                 case "}": char := "+{SC01B}"
  172.                 case ";": char := "{SC027}"
  173.                 case ":": char := "+{SC027}"
  174.                 case "'": char := "{SC028}"
  175.                 case """": char := "+{SC028}"
  176.                 case "\": char := "{SC02B}"
  177.                 case "|": char := "+{SC02B}"
  178.                 case "<": char := "+{SC033}"
  179.                 case ">": char := "+{SC034}"
  180.                 case "/": char := "{SC035}"
  181.                 case "?": char := "+{SC035}"
  182.             }
  183.         }
  184.        
  185.         mappedInput .= char
  186.     }
  187.    
  188.     return mappedInput
  189. }
  190.  
  191. SayMessage(message)
  192. {
  193.     ; Remove/convert characters that cannot be used in chat message
  194.     message := StrReplace(message, """", "'")
  195.  
  196.     message := MapKeys(message)
  197.  
  198.     Send, t
  199.     Sleep 20
  200.     Send, %message%
  201.     Send, {Enter}
  202. }
  203.  
  204. ConsoleCommand(command)
  205. {
  206.     command := MapKeys(command)
  207.  
  208.     Send, {SC029}
  209.     Sleep 20
  210.     Send, %command%
  211.     Send, {Enter}
  212.     Send, {SC029}
  213. }
  214.  
  215. RandomString(length, characters)
  216. {
  217.     returnValue := ""
  218.    
  219.     Loop % length
  220.     {
  221.         Random, rand, 1, StrLen(characters)
  222.         returnValue := returnValue . SubStr(characters, rand, 1)
  223.     }
  224.  
  225.     return returnValue
  226. }
  227.  
  228. WordsToRandomOrder(words)
  229. {
  230.     randomWords := words
  231.     Sort, randomWords, D  Random
  232.    
  233.     return randomWords
  234. }
  235.  
  236. GetWord(word, number)
  237. {
  238.     StringSplit, wordArray, word, % A_Space
  239.     return wordArray%number%
  240. }
  241.  
  242. RemoveNewLines(input)
  243. {
  244.     returnValue := input
  245.     StringReplace,returnValue,returnValue,`n,,A
  246.     StringReplace,returnValue,returnValue,`r,,A
  247.    
  248.     return returnValue
  249. }
  250.  
  251. IsChatMessageRow(row)
  252. {
  253.     if (SubStr(row, 1, 2) = "^a")
  254.     {
  255.         return true
  256.     }
  257.    
  258.     return false
  259. }
  260.  
  261. GetNicknameFromChatMessageRow(row)
  262. {
  263.     firstWord := GetWord(row, 1)
  264.     return SubStr(firstWord, 3, StrLen(firstWord)-3)
  265. }
  266.  
  267. GetMessageFromChatMessageRow(row)
  268. {
  269.     parts := StrSplit(row, ": ")
  270.    
  271.     if (parts[2])
  272.     {
  273.         return parts[2]
  274.     }
  275.    
  276.     return ""
  277. }
  278.  
  279. IsDeathRow(row)
  280. {
  281.     if (InStr(row,"was railed by")
  282.     || InStr(row,"was popped by")
  283.     || InStr(row,"was blown away")
  284.     || InStr(row,"almost dodged"))
  285.     {
  286.         return true
  287.     }
  288.    
  289.     return false
  290. }
  291.  
  292. GetNicknameFromDeathRow(row)
  293. {
  294.     firstWord := GetWord(row, 1)
  295.     return firstWord
  296. }
  297.  
  298. RandomRowFromFile(filePath)
  299. {
  300.     linesCount := TF_CountLines(filePath)
  301.     Random, lineRand, 1, linesCount
  302.     row := TF_ReadLines(filePath, lineRand, lineRand)
  303.     row := RemoveNewLines(row)
  304.    
  305.     return row
  306. }
  307.  
  308. ; Retrieves the last row by default
  309. LastRowFromFile(filePath, rowNumber := 0)
  310. {
  311.     row := TF_Tail(filePath, rowNumber, 0, 0)
  312.     row := RemoveNewLines(row)
  313.    
  314.     return row
  315. }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement