📜 ⬆️ ⬇️

Automation of fishing for World of Warcraft

I got acquainted with World of Warcraft for a very long time and I love it all, but one thing that most haunted me was fishing. This is a tedious repetitive action, where you just press the fishing button and poke on the float every 5-15 seconds. My development skill grew, and the fishing situation did not improve every year that I played, so I decided to kill two birds with one stone - start learning python and still make a bot for myself.

I have already seen bots that know how to fish, working in the minimized mode without intercepting computer control. I also know how ruthless blizzard on bans cheaters. Changing data in RAM is easily detected by the built-in anti-cheat. And finally - I did not find a single bot on the poppy.

So I decided to close all these issues at once and make a bot that will intercept the mouse control, throw a float, and poke it on the screen when necessary. As I thought, python has a wide selection of tools for automating such pieces, and it was not a mistake.

A little google, I found OpenCV , in which there is a search for a template with a simple guide . With it, we will look for our float on the screen.
')
First we have to get the picture itself with a float. We search and find the pyscreenshot library with a guide how to take screenshots, edit it a little bit:

import pyscreenshot as ImageGrab screen_size = None screen_start_point = None screen_end_point = None #               def check_screen_size(): print "Checking screen size" img = ImageGrab.grab() # img.save('temp.png') global screen_size global screen_start_point global screen_end_point #            grab   bbox,       2.        x1=100, y1=100, x2=200, y2=200),    200200 (sic!),    2 coefficient = 2 screen_size = (img.size[0] / coefficient, img.size[1] / coefficient) #       . screen_start_point = (screen_size[0] * 0.35, screen_size[1] * 0.35) screen_end_point = (screen_size[0] * 0.65, screen_size[1] * 0.65) print ("Screen size is " + str(screen_size)) def make_screenshot(): print 'Capturing screen' screenshot = ImageGrab.grab(bbox=(screen_start_point[0], screen_start_point[1], screen_end_point[0], screen_end_point[1])) #  ,      OpenCV screenshot_name = 'var/fishing_session_' + str(int(time.time())) + '.png' screenshot.save(screenshot_name) return screenshot_name def main(): check_screensize() make_screenshot() 

We get about the following picture:



Next - find a float. To do this, we must have the template of the float itself, which we are looking for. After hundreds of attempts, I still picked up the ones that OpenCV defines best. Here they are:



Take the code from the link above, add the loop and our templates:

 import cv2 import numpy as np from matplotlib import pyplot as plt def find_float(screenshot_name): print 'Looking for a float' for x in range(0, 7): #   template = cv2.imread('var/fishing_float_' + str(x) + '.png', 0) #        src_rgb = cv2.imread(screenshot_name) src_gray = cv2.cvtColor(src_rgb, cv2.COLOR_BGR2GRAY) #      w, h = template.shape[::-1] #  OpenCV,        res = cv2.matchTemplate(src_gray, template, cv2.TM_CCOEFF_NORMED) #       0.8  0.6,           ,     ,         threshold = 0.6 # numpy      loc = np.where( res >= threshold) #     for pt in zip(*loc[::-1]): cv2.rectangle(src_rgb, pt, (pt[0] + w, pt[1] + h), (0,0,255), 2) #      ,       if loc[0].any(): print 'Found float at ' + str(x) cv2.imwrite('var/fishing_session_' + str(int(time.time())) + '_success.png', src_rgb) return (loc[1][0] + w / 2) / 2, (loc[0][0] + h / 2) / 2 #    ,     ?      2 def main(): check_screensize() img_name = make_screenshot() find_float(img_name) 

So, we have the coordinates of the float, autopy can literally move the mouse cursor with a single line, we substitute our coordinates:

 import autopy def move_mouse(place): x,y = place[0], place[1] print("Moving cursor to " + str(place)) autopy.mouse.smooth_move(int(screen_start_point[0]) + x , int(screen_start_point[1]) + y) def main(): check_screensize() img_name = make_screenshot() cords = find_float(img_name) move_mouse(cords) 

The cursor on the float and now the most interesting - how do you know when to press? Indeed, in the game itself, the float jumps up and makes a sound like something flops into the water. After the image search tests, I noticed that OpenCV has to think half a second before it returns the result, and the float jumps even faster and we can hardly determine the change of the image using OpenCV, then we will listen to the sound. For this task, I had to dig into different solutions and stopped here above this - an example of using Google for voice recognition, from there we take a code that reads sound.

 import pyaudio import wave import audioop from collections import deque import time import math def listen(): print 'Listening for loud sounds...' CHUNK = 1024 FORMAT = pyaudio.paInt16 CHANNELS = 2 RATE = 18000 #  ,     THRESHOLD = 1200 #   ,   ,        SILENCE_LIMIT = 1 #  ,       ,     #   p = pyaudio.PyAudio() stream = p.open(format=FORMAT, channels=CHANNELS, rate=RATE, # output=True, #       output,       <a href="https://github.com/RogueAmoeba/Soundflower-Original">Soundflower</a>,     output  input,          input=True, frames_per_buffer=CHUNK) cur_data = '' rel = RATE/CHUNK slid_win = deque(maxlen=SILENCE_LIMIT * rel) #      20  (     ),   . success = False listening_start_time = time.time() while True: try: cur_data = stream.read(CHUNK) slid_win.append(math.sqrt(abs(audioop.avg(cur_data, 4)))) if(sum([x > THRESHOLD for x in slid_win]) > 0): print 'I heart something!' success = True break if time.time() - listening_start_time > 20: print 'I don\'t hear anything during 20 seconds!' break except IOError: break #    stream.close() p.terminate() return success def main(): check_screensize() img_name = make_screenshot() cords = find_float(img_name) move_mouse(cords) listen() 

The last thing left is to catch the fish itself, when we hear the sound, we use autopy again:

 def snatch(): print('Snatching!') autopy.mouse.click(autopy.mouse.RIGHT_BUTTON) def main(): check_screensize() img_name = make_screenshot() cords = find_float(img_name) move_mouse(cords) if listen(): snatch() 

According to my tests, that I left the bot to fish at night, during the week of such an abuse, he made about 7,000 throws and caught about 5,000 fish. The error of 30% is caused by the fact that sometimes it is impossible to catch the sound or to find a float due to lighting or turning the float. But I am satisfied with the result - I tried python for the first time, made a bot and saved myself a lot of time.

The full code can be viewed here , but I strongly advise you not to use phishing for an abuse, because automating the processes of the game violates the user agreement and you can get a ban.

I would welcome any comments.

Source: https://habr.com/ru/post/335580/


All Articles