PoE Automatic Potion Drink!! If Hit point is half…
Warning
This posting is for educational purposes only. Never abuse, it gets misused.
Hello this is lifeonroom
I added an upgrade to my last post and this time I used OpenCV to create a Python code that automatically takes potions when your health or mana is half-baked! Note that the feature only works on the main monitor. If you’re using dual monitors, you won’t be able to work on sub monitors!!
First, let’s learn about the files that were added or changed before entering.
- drinkportion.py – Changed to press a specific key as a result of the change and image processing.
- config.cfg – Added options for changes, video processing, and the keyboard value to press at critical point Trigger.
- cvFunc.py – It is about additional and video processing.
Now let’s find out which libraries you need to install!
1. Library
pip install opencv-python pip install pillow pip install numpy pip install mss pip install pyautogui==0.9.38
Here’s a certain version of pyautogui! For the latest version of pyautogui, the installation in Hangul windows is error…. So you need to install the version mentioned above to make it work normally.
2. config.cfg
[portion_drink_delay] delay = 0.1 delay_triggered = 1 [portion_key] k_1 = 2,3,4,5 # m_right = 5 m_middle = 4 s_hp = 1 s_mp = 5 [screen] bgr_lower = {'sheild': (89, 132, 72), 'mp': (109, 47, 13), 'hp': (33, 94, 30)} bgr_upper = {'sheild': (169, 199, 137), 'mp': (158, 71, 32), 'hp': (47, 147, 33)} hpmp_region = (1818, 655, 201, 38) #hpmp_region = (911, 319, 101, 18) #full hd #hpmp_region = (906, 314, 107, 20) # full hd whole screen mode hpmp_trigger = 0.5
Let’s take a look at the config.cfg file giving the program options
The screen section, the delay_triggered option in the part_drink_delay section, and the portion_key section have been added to the s_hp and s_mp options. The meaning of each option is the same as:
- bgr_lower, bgr_upper: BGR minimum and maximum value of sheild, mp, hp bar.
- hpmp_region: Where sheild, mp, and hp bars exist.
- hpmp_trigger: mp, hp, it’s a shame to take a potion when it’s dropped. In this case, if you have 50% left, you will take the potion.
- delay_triggered: mp, how much Delay should be placed and potion when the hp level is under hpmp_trigger. In this case, it is 1 second.
- s_hp, s_mp: Hp, mp is about which key to press when going down under hpmp_trigger. In this case, the hp is 1 key and mp is 2.
Note that the value of bgr_lower, bgr_uppwer works well with the above values that I’ve tested with 3 monitors. So i think you can use the above value without getting it aside!
2. Code
In the last post, a file called cvFunc.py was added. The file detects the character’s blood and manatong and tells you when to take the potion! In addition, we’ve implemented the following features:
- Get coordinate values for a specific Image area
- Get the minimum and maximum channel-specific value of brg value for a particular photo
- Detecting rectangles with specific BGR values in an image
- Take a series of screenshots to detect blood and manatong
cvFunc.py
#-*- coding: utf-8 -*- from ast import literal_eval import os import time import cv2.cv2 as cv2 import numpy as np import pyautogui as pa from PIL import Image import copy from mss import mss class ScreenShot(): finalRegion = 0 def __init__(self, region=(0, 0, 0, 0)): if region == (0, 0, 0, 0): screen = np.array(pa.screenshot()) self.img = screen[:, :, ::-1].copy() else: screen = np.array(pa.screenshot(region=region)) self.img = screen[:, :, ::-1].copy() #self.overlay = self.img.copy() self.output = self.img.copy() self.drawing = False self.ix = 0 self.iy = 0 sz = pa.size() coord = (0, 0, sz[0], sz[1]) self.scrCenter = pa.center(coord) self.mouseCoord = pa.position() def drawBlueRect(self, event, x, y, flags, param): #global ix, iy, drawing, mode, output if event == cv2.EVENT_LBUTTONDOWN: # 마우스를 누른 상태 self.drawing = True self.ix, self.iy = x, y elif event == cv2.EVENT_MOUSEMOVE: # 마우스 이동 if self.drawing == True: # 마우스를 누른 상태 일경우 self.output = self.img.copy() cv2.rectangle(self.output, (self.ix, self.iy), (x, y), (255, 0, 0), 2) pass elif event == cv2.EVENT_LBUTTONUP: self.drawing = False; # 마우스를 때면 상태 변경 cv2.rectangle(self.output, (self.ix, self.iy), (x, y), (255, 0, 0), 2) startX, endX = self.ix, x startY, endY = self.iy, y if x > self.ix : startX, endX = self.ix, x else: startX, endX = x, self.ix if y > self.iy: startY, endY = self.iy, y else: startY, endY = y, self.iy self.finalRegion = (startX, startY, endX - startX, endY - startY) def partScreenShot(self): cv2.namedWindow('image', cv2.WINDOW_NORMAL) cv2.setWindowProperty("image", cv2.WND_PROP_FULLSCREEN, cv2.WINDOW_FULLSCREEN); cv2.setMouseCallback('image', self.drawBlueRect) while True: cv2.imshow('image', self.output) k = cv2.waitKey(1) & 0xFF if k == 27: # esc를 누르면 종료 break cv2.destroyAllWindows() print("Screen Shot Region(x, y, w, h): ", self.finalRegion) return self.finalRegion def saveImage(self, fileName, region=()): if len(region) == 0: x, y, w, h = self.finalRegion else: x, y, w, h = region croped_img = self.img[y:y+h, x:x+w] path = os.path.dirname(os.path.realpath(__file__)) + '\\' + str(fileName) cv2.imwrite(path, croped_img) class ScreenProcess(): drinkTime = {} HPMPText = 'Text' recogCnt = 0 def __init__(self, dict_bgr_lower, dict_bgr_upper, trigger=0.5, delayTriggered = 3, region = (0, 0, 0, 0)): self.lower = dict_bgr_lower self.upper = dict_bgr_upper for key, _ in self.upper.items(): self.drinkTime[key] = time.time() self.x, self.y, self.w, self.h = region self.mon = {'top': self.y, 'left': self.x, 'width': self.w, 'height': self.h} self.sct = mss() self.delayTriggered = delayTriggered self.trigger = trigger def checkHPMP(self, frame, show=0, videoShow = 0): rects = [] triggered = [] for key, value in self.upper.items(): img = copy.copy(frame) height, width = img.shape[:2] #print(height, width) img = cv2.GaussianBlur(img, (11, 11), 0) mask = cv2.inRange(img, self.lower[key], self.upper[key]) res = cv2.bitwise_and(img, img, mask=mask) gray = cv2.cvtColor(res, cv2.COLOR_BGR2GRAY) #ret, thresh = cv2.threshold(gray, 0, 255, cv2.THRESH_BINARY) #kernel = cv2.getStructuringElement(cv2.MORPH_RECT, (3, 5)) #erosion = cv2.erode(thresh, kernel, iterations=1) cnts = cv2.findContours(gray.copy(), cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)[-2] for cnt in cnts: approx = cv2.approxPolyDP(cnt, 0.1 * cv2.arcLength(cnt, True), True) if (len(approx) >= 2): # print("approx:", len(approx), "CountourArea: ", cv2.contourArea(cnt)) (x, y, w, h) = cv2.boundingRect(approx) rects.append((x, y, w, h)) currentHPMP = w/(width * 1.0) if currentHPMP < self.trigger and x < 10: if (time.time() - self.drinkTime[key] > self.delayTriggered and key != 'sheild'): self.drinkTime[key] = time.time() showText = key + ' need portion!' + str(self.recogCnt) print(showText) self.recogCnt += 1 self.HPMPText = showText triggered.append(key) break if show == 1: showImg = copy.copy(frame) textImg = np.zeros((height * 2, width*2, 3), np.uint8) cv2.putText(textImg, self.HPMPText, (5, height+ 5), cv2.FONT_HERSHEY_SIMPLEX, 0.5, (255, 255, 255), lineType=cv2.LINE_AA) for detectRect in rects: (x, y, w, h) = detectRect cv2.rectangle(showImg, (x, y), (x + w, y + h), (255, 0, 255), 2) viewImage = np.hstack([frame, showImg]) finalView = np.vstack([viewImage, textImg]) cv2.imshow("Frame Result", finalView) cv2.resizeWindow('Frame Result', 300, 300) #cv2.imshow("OneFrame", np.hstack([thresh, gray, erosion])) if videoShow == 0: cv2.waitKey(0) if show == 1 and videoShow == 0: cv2.destroyAllWindows() return triggered def screenProcess(self, showVideo=0): self.sct.grab(self.mon) img = Image.frombytes('RGB', (self.w, self.h), self.sct.grab(self.mon).rgb) frame = cv2.cvtColor(np.array(img), cv2.COLOR_RGB2BGR) return self.checkHPMP(frame, show=showVideo, videoShow=showVideo) # if cv2.waitKey(25) & 0xFF == ord('q'): # cv2.destroyAllWindows() # break def checkColorMinMax(listImageName): cmin = {} cmax = {} for imageName in listImageName: frame = cv2.imread(imageName) frame = cv2.GaussianBlur(frame, (11, 11), 0) max_ch = (np.amax(frame[:, :, 0]), np.amax(frame[:, :, 1]), np.amax(frame[:, :, 2])) min_ch = (np.amin(frame[:, :, 0]), np.amin(frame[:, :, 1]), np.amin(frame[:, :, 2])) specName = imageName.split('.')[0] cmin[specName] = min_ch cmax[specName] = max_ch print("lower = ", cmin) print("upper = ", cmax) if __name__=="__main__": import configparser configFile = os.path.dirname(os.path.realpath(__file__)) + '\\' + 'config.cfg' config = configparser.ConfigParser() config.read(configFile) delay_triggered = int(config['portion_drink_delay']['delay_triggered']) brg_lower = literal_eval(config['screen']['bgr_lower']) bgr_upper = literal_eval(config['screen']['bgr_upper']) hpmp_region = literal_eval(config['screen']['hpmp_region']) hpmp_trigger = float(config['screen']['hpmp_trigger']) test = 1 # -------- ScreenSize ------------ if test == 1: ip = ScreenShot() ip.partScreenShot() # -------- Check Color BGR min max ------------ elif test == 2: checkColorMinMax(["sheild.png", "mana.png", "health.png"]) # -------- detect HP/MP on image ------------ elif test == 3: frame = cv2.imread("testpoe.png") sp = ScreenProcess(brg_lower, bgr_upper, hpmp_trigger, delay_triggered, hpmp_region) sp.checkHPMP(frame, show=1) # -------- detect HP/MP on continuous Screen ------------ elif test == 4: sp = ScreenProcess(brg_lower, bgr_upper, hpmp_trigger, delay_triggered, hpmp_region) while True: sp.screenProcess(showVideo=1) if cv2.waitKey(25) & 0xFF == ord('q'): cv2.destroyAllWindows() break
If you look at the Main below, you can change the test variable to test the features mentioned above 1-4 times. !! Please refer to the video of the behavior of the code.
drinkPortion.py
import mouse as mo import keyboard as keys import time import configparser import os from ast import literal_eval import cv2.cv2 as cv2 #try: import keyEvent as ke # import screen process module import cvFunc as cvf # except: # import POE.keyEvent as ke # import POE.cvFunc as cvf try: import serialFunc as sf ser = sf.ExternalHID('COM16') except Exception as e: print(e) print("Hardware Macro Disabled") def generateKeyEvent(val, key_s, delay): if val == True: for outVal in key_s: # hardware macro #ser.keyboardInput(outVal) # software macro ke.press(outVal) time.sleep(delay) def drinkPortionWithInput(listDevKeyOutVal, delay=0.001, sProcess=None): listKeyState = [0] * len(listDevKeyOutVal) triggereds = [] while True: if sProcess != None: # screenProcess if triggered return data triggereds = sProcess.screenProcess(showVideo=1) if cv2.waitKeyEx(25) == ord('`'): cv2.destroyAllWindows() break for idx, dictDevVal in enumerate(listDevKeyOutVal): keyormo = list(dictDevVal.keys())[0] generateKeys = dictDevVal[keyormo].split(',') # [0] = k is keyboard [1] = pushed key if keyormo.split('_')[0].strip() == 'k': value = keys.is_pressed(keyormo.split('_')[1].strip()) if listKeyState[idx] != value: generateKeyEvent(value, generateKeys, delay) listKeyState[idx] = value # [0] = m is mouse [1] = pushed mouse btn elif keyormo.split('_')[0].strip() == 'm': possList = [mo.LEFT, mo.RIGHT, mo.MIDDLE] try: possList.index(keyormo.split('_')[1].strip()) except Exception as e: continue value = mo.is_pressed(keyormo.split('_')[1].strip()) if listKeyState[idx] != value: generateKeyEvent(value, generateKeys, delay) listKeyState[idx] = value elif keyormo.split('_')[0].strip() == 's': stat = keyormo.split('_')[1].strip() # drink potion if HP, MP below specific percentage for triggered in triggereds: if triggered == stat: generateKeyEvent(True, generateKeys, delay) if __name__=="__main__": configFile = os.path.dirname(os.path.realpath(__file__)) + '\\' + 'config.cfg' config = configparser.ConfigParser() config.read(configFile) itemList = [] for option in config.options('portion_key'): itemList.append({option:config['portion_key'][option]}) drinkDelay = float(config['portion_drink_delay']['delay']) delay_triggered = int(config['portion_drink_delay']['delay_triggered']) brg_lower = literal_eval(config['screen']['bgr_lower']) bgr_upper = literal_eval(config['screen']['bgr_upper']) hpmp_region = literal_eval(config['screen']['hpmp_region']) hpmp_trigger = float(config['screen']['hpmp_trigger']) print("macro start drink delay %s " % str(drinkDelay)) # make screenProcess instance sp = cvf.ScreenProcess(brg_lower, bgr_upper, hpmp_trigger, delay_triggered, hpmp_region) drinkPortionWithInput(itemList, drinkDelay, sp)
The new drinkPortion.py. I’ve commented on the main part.
3. Run
After coding, enable the virtual environment in the CMD environment and then python drinkPortion the code will run. And if you want to keep the video processing window open, you can change it to showVideo = 0.
Yep today’s post is here. I’m going to act 4 mill now, but i’ve done my way to build it, and i’ve almost folded the game.