diff --git a/CHANGELOG.md b/CHANGELOG.md index 185c9d7..9b8e3d9 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,13 @@ # CHANGELOG +## v1.0.1.0304 +#### New features: +* 探索双开 +#### Fixes (bugs & defects): +* 修复了探索副本中不停反复点击准备按钮的问题。 +* 修复了部分玩家BitBlt失败的问题。 +* 优化了结算 + ## v1.0.1.0301 #### New features: * 增加延迟设定选项。 diff --git a/README.md b/README.md index d46085b..f69913a 100644 --- a/README.md +++ b/README.md @@ -23,7 +23,7 @@ 感谢壁咚咚咚咚咚、Tree.提供的技术指导,感谢Abc为本程序提供了应用图标。 -感谢以下人员为测试工作做出的努力:鼠白小验实,忒修斯之旅,Garry。 +感谢以下人员为测试工作做出的努力:鼠白小验实,忒修斯之旅,Garry,DD斩首, 暖。 # 注意事项 diff --git a/conf_example.ini b/conf_example.ini index c184de4..d1f0248 100644 --- a/conf_example.ini +++ b/conf_example.ini @@ -4,7 +4,7 @@ client = 0 #run_section 运行副本:0-御魂;1-御灵;2-探索 run_section = 0 -#run_mode 运行模式:对于御魂0-单刷;1-司机;2-乘客;3-双开 +#run_mode 御魂运行模式:0-单刷;1-司机;2-乘客;3-双开 run_mode = 0 #max_times 最大游戏次数:0-无数次;其他-其他次 max_times = 0 @@ -29,6 +29,11 @@ max_op_time = 20 [explore] #######探索参数###### +#explore_mode 探索模式:0-单刷;1-队长;2-队员;3-双开 +explore_mode = 0 +#更换狗粮设置:1-左; 2-中; 3-右; 4-左后; 5-右后,下同 +gouliang = [2, 3] +gouliang_b = [] #fight_boss_enable 结束后是否打BOSS:True-是;False-否 fight_boss_enable = False #slide_shikigami 换狗粮是否拖放式神进度条:True-是;False-否 diff --git a/explore/explore.py b/explore/explore.py index 3ab7411..8dc048e 100644 --- a/explore/explore.py +++ b/explore/explore.py @@ -9,13 +9,34 @@ class ExploreFight(Fighter): - def __init__(self): - # 初始化 - Fighter.__init__(self) + def __init__(self, hwnd=0, mode=0): + ''' + 初始化 + :param hwnd=0: 指定窗口句柄:0-否;其他-窗口句柄 + :param mode=0: 狗粮模式:0-正常模式,1-组队后排狗粮 + ''' + Fighter.__init__(self, hwnd=hwnd) # 读取配置文件 conf = configparser.ConfigParser() conf.read('conf.ini') + + # 读取狗粮配置 + if mode == 0: + raw_gouliang = conf.get('explore', 'gouliang') + else: + raw_gouliang = conf.get('explore', 'gouliang_b') + if len(raw_gouliang) == 2: + self.gouliang = None + elif len(raw_gouliang) == 3: + self.gouliang = [int(raw_gouliang[1])] + elif len(raw_gouliang) == 6: + self.gouliang = [int(raw_gouliang[1]), int(raw_gouliang[4])] + elif len(raw_gouliang) == 9: + self.gouliang = [int(raw_gouliang[1]), int( + raw_gouliang[4]), int(raw_gouliang[7])] + + # 读取其他配置 self.fight_boss_enable = conf.getboolean( 'explore', 'fight_boss_enable') self.slide_shikigami = conf.getboolean('explore', 'slide_shikigami') @@ -36,18 +57,34 @@ def next_scene(self): def check_exp_full(self): ''' 检查狗粮经验,并自动换狗粮 + 狗粮序列,1-左; 2-中; 3-右; 4-左后; 5-右后 ''' - # 狗粮经验判断, gouliang1是中间狗粮,gouliang2是右边狗粮 - gouliang1 = self.yys.find_game_img( - 'img\\MAN1.png', 1, *TansuoPos.gouliang_middle, 1) - gouliang2 = self.yys.find_game_img( - 'img\\MAN2.png', 1, *TansuoPos.gouliang_right, 1) + if self.gouliang == None: + return - # print(gouliang1) - # print(gouliang2) + # 狗粮经验判断 + gouliang = [] + if 1 in self.gouliang: + gouliang.append(self.yys.find_game_img( + 'img\\MAN2.png', 1, *TansuoPos.gouliang_left, 1, 0.8)) + if 2 in self.gouliang: + gouliang.append(self.yys.find_game_img( + 'img\\MAN2.png', 1, *TansuoPos.gouliang_middle, 1, 0.8)) + if 3 in self.gouliang: + gouliang.append(self.yys.find_game_img( + 'img\\MAN2.png', 1, *TansuoPos.gouliang_right, 1, 0.8)) + if 4 in self.gouliang: + gouliang.append(self.yys.find_game_img( + 'img\\MAN2.png', 1, *TansuoPos.gouliang_leftback, 1, 0.8)) + if 5 in self.gouliang: + gouliang.append(self.yys.find_game_img( + 'img\\MAN2.png', 1, *TansuoPos.gouliang_rightback, 1, 0.8)) # 如果都没满则退出 - if not gouliang1 and not gouliang2: + res = False + for item in gouliang: + res = res or bool(item) + if not res: return # 开始换狗粮 @@ -84,13 +121,22 @@ def check_exp_full(self): self.yys.mouse_drag_bg( TansuoPos.n_slide[0], (pos_end_x, pos_end_y)) + time.sleep(1) # 更换狗粮 - if gouliang1: - self.yys.mouse_drag_bg((309, 520), (554, 315)) - if gouliang2: - time.sleep(1) - self.yys.mouse_drag_bg((191, 520), (187, 315)) + for i in range(0, len(self.gouliang)): + if gouliang[i]: + if self.gouliang[i] == 1: + self.yys.mouse_drag_bg((422, 520), (955, 315)) + elif self.gouliang[i] == 2: + self.yys.mouse_drag_bg((309, 520), (554, 315)) + elif self.gouliang[i] == 3: + self.yys.mouse_drag_bg((191, 520), (167, 315)) + elif self.gouliang[i] == 4: + self.yys.mouse_drag_bg((309, 520), (829, 315)) + elif self.gouliang[i] == 5: + self.yys.mouse_drag_bg((191, 520), (301, 315)) + ut.mysleep(1000) def find_exp_moster(self): ''' @@ -160,7 +206,7 @@ def fight_moster(self, mood1, mood2): return -1 # 攻击怪 - self.yys.mouse_click_bg(fight_pos) + self.click_until('怪', 'img/YING-BING.png', fight_pos, step_time=0.3, appear=False) self.log.writeinfo('已进入战斗') # 等待式神准备 @@ -171,8 +217,8 @@ def fight_moster(self, mood1, mood2): self.check_exp_full() # 点击准备,直到进入战斗 - self.click_until('准备按钮', 'img\\ZI-DONG.png', * - TansuoPos.ready_btn, mood1.get1mood()/1000) + self.click_until('准备按钮', 'img/ZHUN-BEI.png', * + TansuoPos.ready_btn, mood1.get1mood()/1000, False) # 检查是否打完 state = self.check_end() @@ -204,6 +250,7 @@ def start(self): if result == 1: continue elif result == 2: + time.sleep(1) break else: self.log.writeinfo('移动至下一个场景') diff --git a/explore/explore_dual.py b/explore/explore_dual.py new file mode 100644 index 0000000..5907a17 --- /dev/null +++ b/explore/explore_dual.py @@ -0,0 +1,61 @@ +from gameLib.game_ctl import GameControl +from explore.explore_leader import ExploreLeader +from explore.explore_passenger import ExplorePassenger + +import logging +import threading +import win32gui + +hwndlist = [] + + +def get_all_hwnd(hwnd, mouse): + ''' + 获取所有阴阳师窗口 + ''' + if win32gui.IsWindow(hwnd) and win32gui.IsWindowEnabled(hwnd) and win32gui.IsWindowVisible(hwnd): + if win32gui.GetWindowText(hwnd) == u'阴阳师-网易游戏': + hwndlist.append(hwnd) + + +def get_game_hwnd(): + win32gui.EnumWindows(get_all_hwnd, 0) + + +class ExploreDual(): + def __init__(self): + # 初始化窗口信息 + get_game_hwnd() + self.hwndlist = hwndlist + + # 检测窗口信息是否正确 + num = len(self.hwndlist) + if num == 2: + logging.info('检测到两个窗口,窗口信息正常') + else: + logging.warning('检测到'+str(num)+'个窗口,窗口信息异常!') + + # 初始化司机和打手 + for hwnd in hwndlist: + yys = GameControl(hwnd) + if yys.find_game_img('img/DUI.png', 1, (68, 242), (135, 306), thread=0.8): + self.driver = ExploreLeader(hwnd=hwnd) + hwndlist.remove(hwnd) + logging.info('发现队长') + break + self.passenger = ExplorePassenger(hwnd=hwndlist[0]) + logging.info('发现乘客') + + def start(self): + task1 = threading.Thread(target=self.driver.start) + task2 = threading.Thread(target=self.passenger.start) + task1.start() + task2.start() + + task1.join() + task2.join() + + def deactivate(self): + self.hwndlist = [] + self.driver.deactivate() + self.passenger.deactivate() diff --git a/explore/explore_leader.py b/explore/explore_leader.py new file mode 100644 index 0000000..90a03ea --- /dev/null +++ b/explore/explore_leader.py @@ -0,0 +1,116 @@ +from explore.explore import ExploreFight +from tools.game_pos import TansuoPos +import tools.utilities as ut + +import logging +import random +import time + + +class ExploreLeader(ExploreFight): + ''' + 组队探索队长 + ''' + + def __init__(self, hwnd=0): + ''' + 初始化 + ''' + ExploreFight.__init__(self, hwnd=hwnd, mode=1) + self.name = 'Leader: ' + + def prev_scene(self): + ''' + 滑动到前一页面 + ''' + x0 = random.randint(510, 1126) + x1 = x0 - 500 + y0 = random.randint(110, 210) + y1 = random.randint(110, 210) + self.yys.mouse_drag_bg((x1, y1), (x0, y0)) + + def start(self): + ''' + 开始战斗 + ''' + mood1 = ut.Mood(3) + mood2 = ut.Mood(3) + mood3 = ut.Mood() + scene = self.get_scene() + if scene == 4: + logging.info('Leader: 已进入探索,就绪') + else: + logging.warning('Leader: 请检查是否进入探索内,退出') + return + + while self.run: + # 检测当前场景 + maxVal_list, maxLoc_list = self.yys.find_multi_img( + 'img/DUI.png', 'img/YING-BING.png') + if maxVal_list[0] < 0.8 and maxVal_list[1] > 0.8: + # 队长退出,结束 + logging.warning('Leader: 队员已退出,脚本结束') + self.yys.quit_game() + + # 开始打怪 + i = 0 + ok = False + while self.run: + if i >= 4: + break + result = self.fight_moster(mood1, mood2) + if result == 1: + ok = True + continue + elif result == 2: + break + else: + self.log.writeinfo('Leader: 移动至下一个场景') + self.next_scene() + i += 1 + + if not ok: + # 没有经验怪,随便打一个 + fight_pos = self.yys.find_game_img('img/FIGHT.png') + while not fight_pos: + self.prev_scene() + fight_pos = self.yys.find_game_img('img/FIGHT.png') + # 攻击怪 + self.yys.mouse_click_bg(fight_pos) + self.log.writeinfo('Leader: 已进入战斗') + + # 等待式神准备 + self.yys.wait_game_img_knn('img/ZHUN-BEI.png', thread=30) + logging.info('Leader: 式神准备完成') + + # 检查狗粮经验 + self.check_exp_full() + + # 点击准备,直到进入战斗 + self.click_until('准备按钮', 'img/ZHUN-BEI.png', * + TansuoPos.ready_btn, mood1.get1mood()/1000, False) + + # 检查是否打完 + state = self.check_end() + mood1.moodsleep() + + # 在战斗结算页面 + self.get_reward(mood2, state) + + # 退出探索 + self.log.writeinfo('Leader: 结束本轮探索') + # 点击退出探索 + self.click_until('退出按钮', 'img/QUE-REN.png', + *TansuoPos.quit_btn, 2) + # 点击确认 + self.click_until('确认按钮', 'img/QUE-REN.png', + *TansuoPos.confirm_btn, 2, False) + + # 下一轮自动邀请 + self.yys.wait_game_img('img/QUE-DING.png', self.max_win_time) + time.sleep(0.5) + self.click_until('继续邀请', 'img/QUE-DING.png', * + TansuoPos.yaoqing_comfirm, mood3.get1mood()/1000, False) + + # 检查游戏次数 + self.check_times() diff --git a/explore/explore_passenger.py b/explore/explore_passenger.py new file mode 100644 index 0000000..92fae07 --- /dev/null +++ b/explore/explore_passenger.py @@ -0,0 +1,76 @@ +from explore.explore import ExploreFight +from tools.game_pos import TansuoPos +import tools.utilities as ut + +import logging +import time + + +class ExplorePassenger(ExploreFight): + ''' + 组队探索队员 + ''' + + def __init__(self, hwnd=0): + ''' + 初始化 + ''' + ExploreFight.__init__(self, hwnd=hwnd) + self.name = 'Passenger: ' + + def start(self): + ''' + 开始战斗 + ''' + mood = ut.Mood(3) + scene = self.get_scene() + if scene == 4: + logging.info('Passenger: 已进入探索,就绪') + else: + logging.warning('Passenger: 请检查是否进入探索内,退出') + return + + while self.run: + # 检测当前场景 + maxVal_list, maxLoc_list = self.yys.find_multi_img( + 'img/DUI.png', 'img/YING-BING.png') + # print(maxVal_list) + if maxVal_list[0] < 0.8 and maxVal_list[1] > 0.8: + # 队长退出,则跟着退出 + logging.info('Passenger: 队长已退出,跟随退出') + self.switch_to_scene(3) + + # 等待邀请 + js_loc = self.yys.wait_game_img( + 'img/JIE-SHOU.png', self.max_win_time) + if js_loc: + # 点击接受邀请 + if self.yys.find_game_img('img/JIE-SHOU.png'): + self.yys.mouse_click_bg((js_loc[0]+33, js_loc[1]+34)) + self.log.writeinfo('Passenger: 接受邀请') + + # 检查游戏次数 + self.check_times() + + elif maxVal_list[0] > 0.8 and maxVal_list[1] < 0.8: + # 进入战斗,等待式神准备 + self.yys.wait_game_img_knn('img/ZHUN-BEI.png', thread=30) + logging.info('Passenger: 式神准备完成') + + # 检查狗粮经验 + self.check_exp_full() + + # 点击准备,直到进入战斗 + self.click_until_knn('准备按钮', 'img/ZI-DONG.png', * + TansuoPos.ready_btn, mood.get1mood()/1000, False, 30) + + # 检测是否打完 + state = self.check_end() + mood.moodsleep() + + # 点击结算 + self.get_reward(mood, state) + + else: + # 其他,不做任何操作 + time.sleep(0.5) diff --git a/gameLib/fighter.py b/gameLib/fighter.py index 89da64e..acdde4f 100644 --- a/gameLib/fighter.py +++ b/gameLib/fighter.py @@ -78,10 +78,13 @@ def check_end(self): 检测是否打完 :return: 胜利页面返回0;奖励页面返回1 ''' - self.yys.rejectbounty() self.log.writeinfo(self.name + '检测是战斗是否结束') start_time = time.time() + myend = -1 while time.time()-start_time <= self.max_win_time and self.run: + # 拒绝悬赏 + self.yys.rejectbounty() + maxVal, maxLoc = self.yys.find_multi_img( 'img/SHENG-LI.png', 'img/TIAO-DAN.png', 'img/JIN-BI.png', 'img/JIE-SU.png') end_cof = max(maxVal) @@ -91,7 +94,6 @@ def check_end(self): time.sleep(0.5) if myend in [0, 3]: logging.info(self.name + '战斗成功') - self.yys.mouse_click_bg(*ut.firstposition()) return 0 elif myend in [1, 2]: logging.info(self.name + '本轮战斗结束') @@ -121,25 +123,45 @@ def get_reward(self, mood, state): :param mood: 状态函数 :param state: 上一步的状态。0-战斗成功页面; 1-领取奖励页面 ''' + # 初始化结算点 + mypos = ut.secondposition() if state == 0: - self.click_until('奖励', 'img/TIAO-DAN.png', * - ut.firstposition(), mood.get1mood()/1000) - mood.moodsleep() - self.yys.mouse_click_bg(ut.secondposition()) + self.yys.mouse_click_bg(mypos) + logging.info(self.name + '点击结算') + mood.moodsleep() start_time = time.time() while time.time()-start_time <= self.max_op_time and self.run: + # 拒绝悬赏 + self.yys.rejectbounty() + + while True: + newpos = (mypos[0] + random.randint(-50, 50), + mypos[1] + random.randint(-50, 50)) + if ut.checkposition(newpos): + mypos = newpos + break + + # 点击一次结算 + self.yys.mouse_click_bg(mypos) + logging.info(self.name + '点击结算') + mood.moodsleep() + + # 错误纠正 maxVal, maxLoc = self.yys.find_multi_img( - 'img/FA-SONG-XIAO-XI.png', 'img/ZHI-LIAO-LIANG.png', 'img/JIE-SUAN-JIA-CHENG.png') + 'img/FA-SONG-XIAO-XI.png', 'img/ZHI-LIAO-LIANG.png') if max(maxVal) > 0.9: self.yys.mouse_click_bg((35, 295), (140, 475)) - result = self.yys.find_game_img_knn('img/TIAO-DAN.png', thread=2) - if not result: + logging.info(self.name + '错误纠正') + mood.moodsleep() + continue + + # 正常结算 + maxVal, maxLoc = self.yys.find_multi_img( + 'img/SHENG-LI.png', 'img/TIAO-DAN.png', 'img/JIN-BI.png', 'img/JIE-SU.png') + if max(maxVal) < 0.9: logging.info(self.name + '结算成功') return - else: - self.yys.mouse_click_bg(ut.secondposition()) - self.log.writeinfo(self.name + '点击结算') - mood.moodsleep() + self.log.writewarning(self.name + '点击结算失败!') # 提醒玩家点击失败,并在5s后退出 self.yys.activate_window() @@ -197,20 +219,20 @@ def click_until(self, tag, img_path, pos, pos_end=None, step_time=0.8, appear=Tr # 在指定时间内反复监测画面并点击 start_time = time.time() while time.time()-start_time <= self.max_op_time and self.run: + # 点击指定位置 + self.yys.mouse_click_bg(pos, pos_end) + self.log.writeinfo(self.name + '点击 ' + tag) + ut.mysleep(step_time*1000) + result = self.yys.find_game_img(img_path) if not appear: result = not result if result: self.log.writeinfo(self.name + '点击 ' + tag + ' 成功') return True - else: - # 点击指定位置并等待下一轮 - self.yys.mouse_click_bg(pos, pos_end) - self.log.writeinfo(self.name + '点击 ' + tag) - ut.mysleep(step_time*1000) - self.log.writewarning(self.name + '点击 ' + tag + ' 失败!') # 提醒玩家点击失败,并在5s后退出 + self.log.writewarning(self.name + '点击 ' + tag + ' 失败!') self.yys.activate_window() time.sleep(5) self.yys.quit_game() @@ -230,20 +252,20 @@ def click_until_knn(self, tag, img_path, pos, pos_end=None, step_time=0.8, appea # 在指定时间内反复监测画面并点击 start_time = time.time() while time.time()-start_time <= self.max_op_time and self.run: + # 点击指定位置并等待下一轮 + self.yys.mouse_click_bg(pos, pos_end) + self.log.writeinfo(self.name + '点击 ' + tag) + ut.mysleep(step_time*1000) + result = self.yys.find_game_img_knn(img_path, thread=thread) if not appear: result = not result if result: self.log.writeinfo(self.name + '点击 ' + tag + ' 成功') return True - else: - # 点击指定位置并等待下一轮 - self.yys.mouse_click_bg(pos, pos_end) - self.log.writeinfo(self.name + '点击 ' + tag) - ut.mysleep(step_time*1000) - self.log.writewarning(self.name + '点击 ' + tag + ' 失败!') # 提醒玩家点击失败,并在5s后退出 + self.log.writewarning(self.name + '点击 ' + tag + ' 失败!') self.yys.activate_window() time.sleep(5) self.yys.quit_game() diff --git a/gameLib/game_ctl.py b/gameLib/game_ctl.py index 09ca273..77196a9 100644 --- a/gameLib/game_ctl.py +++ b/gameLib/game_ctl.py @@ -30,7 +30,7 @@ def __init__(self, hwnd, quit_game_enable=1): l1, t1, r1, b1 = win32gui.GetWindowRect(self.hwnd) #print(l1,t1, r1,b1) l2, t2, r2, b2 = win32gui.GetClientRect(self.hwnd) - #print(l2,t2,r2,b2) + # print(l2,t2,r2,b2) self._client_h = b2 - t2 self._client_w = r2 - l2 self._border_l = ((r1 - l1) - (r2 - l2)) // 2 @@ -42,6 +42,15 @@ def __init__(self, hwnd, quit_game_enable=1): os.system('adb connect 127.0.0.1:7555') os.system('adb devices') + def init_mem(self): + self.hwindc = win32gui.GetWindowDC(self.hwnd) + self.srcdc = win32ui.CreateDCFromHandle(self.hwindc) + self.memdc = self.srcdc.CreateCompatibleDC() + self.bmp = win32ui.CreateBitmap() + self.bmp.CreateCompatibleBitmap( + self.srcdc, self._client_w, self._client_h) + self.memdc.SelectObject(self.bmp) + def window_full_shot(self, file_name=None, gray=0): """ 窗口截图 @@ -51,13 +60,7 @@ def window_full_shot(self, file_name=None, gray=0): """ try: if (not hasattr(self, 'memdc')): - self.hwindc = win32gui.GetWindowDC(self.hwnd) - self.srcdc = win32ui.CreateDCFromHandle(self.hwindc) - self.memdc = self.srcdc.CreateCompatibleDC() - self.bmp = win32ui.CreateBitmap() - self.bmp.CreateCompatibleBitmap( - self.srcdc, self._client_w, self._client_h) - self.memdc.SelectObject(self.bmp) + self.init_mem() if self.client == 0: self.memdc.BitBlt((0, 0), (self._client_w, self._client_h), self.srcdc, (self._border_l, self._border_t), win32con.SRCCOPY) @@ -78,6 +81,7 @@ def window_full_shot(self, file_name=None, gray=0): else: return cv2.cvtColor(img, cv2.COLOR_BGRA2GRAY) except Exception: + self.init_mem() logging.warning('window_full_shot执行失败') a = traceback.format_exc() logging.warning(a) @@ -149,7 +153,7 @@ def find_color(self, region, color, tolerance=0): except Exception: logging.warning('find_color执行失败') a = traceback.format_exc() - logging.warning(a) + logging.warning(a) return -1 return -1 @@ -275,7 +279,7 @@ def find_multi_img(self, *img_template_path, part=0, pos1=None, pos2=None, gray= except Exception: logging.warning('find_multi_img执行失败') a = traceback.format_exc() - logging.warning(a) + logging.warning(a) maxVal_list.append(0) maxLoc_list.append(0) # 返回列表 @@ -492,7 +496,7 @@ def rejectbounty(self): return True return False - def find_game_img(self, img_path, part=0, pos1=None, pos2=None, gray=0): + def find_game_img(self, img_path, part=0, pos1=None, pos2=None, gray=0, thread=0.9): ''' 查找图片 :param img_path: 查找路径 @@ -500,12 +504,13 @@ def find_game_img(self, img_path, part=0, pos1=None, pos2=None, gray=0): :param pos1=None: 欲查找范围的左上角坐标 :param pos2=None: 欲查找范围的右下角坐标 :param gray=0: 是否查找黑白图片,0:查找彩色图片,1:查找黑白图片 + :param thread=0.9: 自定义阈值 :return: 查找成功返回位置坐标,否则返回False ''' self.rejectbounty() maxVal, maxLoc = self.find_img(img_path, part, pos1, pos2, gray) # print(maxVal) - if maxVal > 0.9: + if maxVal > thread: return maxLoc else: return False diff --git a/gui/tkui.py b/gui/tkui.py index 36e97c2..43330d7 100644 --- a/gui/tkui.py +++ b/gui/tkui.py @@ -22,6 +22,12 @@ def __init__(self, master=None): self.max_win_time = tk.IntVar() self.max_op_time = tk.IntVar() + self.explore_mode = tk.IntVar(value=0) + self.gouliang_1 = tk.BooleanVar(value=False) + self.gouliang_2 = tk.BooleanVar(value=True) + self.gouliang_3 = tk.BooleanVar(value=True) + self.gouliang_4 = tk.BooleanVar(value=False) + self.gouliang_5 = tk.BooleanVar(value=False) self.fight_boss_enable = tk.BooleanVar() self.slide_shikigami = tk.BooleanVar() self.slide_shikigami_progress = tk.IntVar() @@ -78,16 +84,19 @@ def create_menubar(self): # 创建菜单项 menu1 = tk.Menu(menubar, tearoff=0) - menu1.add_command(label='关于', command=self.say_hi) - - # 链接 menubar.add_cascade(label="文件", menu=menu1) + menu1.add_command(label='关于', command=self.say_hi) # 高级选项 menu2 = tk.Menu(menubar, tearoff=0) menubar.add_cascade(label="高级", menu=menu2) menu2.add_command(label='自定义延迟', command=self.delay_dialog) + # 帮助 + menu3 = tk.Menu(menubar, tearoff=0) + menubar.add_cascade(label='帮助', menu=menu3) + menu3.add_command(label='使用说明', command=self.help) + # 设置 self.master.config(menu=menubar) @@ -157,7 +166,7 @@ def create_frame0(self): value=3).grid(row=1, column=1, sticky=tk.W) # 游戏副本 - submode = tk.LabelFrame(self.frame0, text='副本') + submode = tk.LabelFrame(self.frame0, text='副本(请锁定阵容)') submode.pack(padx=5, pady=5, fill=tk.BOTH, expand=True) tk.Radiobutton(submode, text='八岐大蛇', variable=self.run_submode, value=0).grid(row=0, column=0, sticky=tk.W) @@ -190,18 +199,41 @@ def create_frame2(self): ''' 探索参数 ''' - # 提示文本 - textframe = tk.Frame(self.frame2) - textframe.pack(expand=True, fill=tk.BOTH) - s = tk.Scrollbar(textframe) - s.pack(side=tk.RIGHT) - text = tk.Text(textframe, height=5, width=21) - text.pack(side=tk.LEFT, expand=True, fill=tk.BOTH) - text.insert(tk.INSERT, '把狗粮队长放在最左边,点开需要打的章节,然后开始。\n') - text.insert(tk.INSERT, '支持自动换狗粮,只打经验怪。\n') - text.insert(tk.END, '最好把“合并相同式神”选项关闭。\n') - s.config(command=text.yview) - text.config(yscrollcommand=s.set, state=tk.DISABLED) + # 副本选择 + submode = tk.LabelFrame(self.frame2, text='模式') + submode.pack(fill=tk.BOTH, expand=True) + tk.Radiobutton(submode, text='单刷', variable=self.explore_mode, + value=0, command=lambda: self.gouliang_state(1)).grid(row=0, column=0, sticky=tk.W) + tk.Radiobutton(submode, text='单人队长', variable=self.explore_mode, + value=1, command=lambda: self.gouliang_state(2)).grid(row=0, column=1, sticky=tk.W) + tk.Radiobutton(submode, text='单人队员', variable=self.explore_mode, + value=2, command=lambda: self.gouliang_state(1)).grid(row=1, column=0, sticky=tk.W) + tk.Radiobutton(submode, text='桌面版双开', variable=self.explore_mode, + value=3, command=lambda: self.gouliang_state(3)).grid(row=1, column=1, sticky=tk.W) + + # 狗粮设置 + food = tk.LabelFrame(self.frame2, text='更换狗粮 (勿锁定阵容)') + food.pack(fill=tk.BOTH, expand=True) + self.gouliang_l = tk.Checkbutton( + food, text='左', variable=self.gouliang_1) + self.gouliang_l.grid(row=0, column=0) + self.gouliang_m = tk.Checkbutton( + food, text='中', variable=self.gouliang_2) + self.gouliang_m.grid(row=0, column=1) + self.gouliang_r = tk.Checkbutton( + food, text='右', variable=self.gouliang_3) + self.gouliang_r.grid(row=0, column=2) + tk.Label(food, text='单人/队员').grid(row=0, column=3, sticky=tk.W) + + self.gouliang_lb = tk.Checkbutton( + food, text='左', variable=self.gouliang_4) + self.gouliang_lb.grid(row=1, column=0) + self.gouliang_rb = tk.Checkbutton( + food, text='右', variable=self.gouliang_5) + self.gouliang_rb.grid(row=1, column=2) + tk.Label(food, text='队长').grid(row=1, column=3, sticky=tk.W) + self.gouliang_lb.config(state=tk.DISABLED) + self.gouliang_rb.config(state=tk.DISABLED) # 换狗粮设置 tk.Checkbutton(self.frame2, text='换狗粮拖放式神进度条,进度:', @@ -226,6 +258,8 @@ def create_frame3(self): text.pack(expand=True, fill=tk.BOTH) text.insert( tk.END, '网址:https://github.com/AcademicDog/onmyoji_bot\n\n交流Q群:592055060') + text.insert( + tk.END, '\n\n如果觉得脚本动作太慢,请到高级菜单自定义延迟。') text.config(state=tk.DISABLED) def create_times(self): @@ -285,8 +319,9 @@ def create_command(self): command=self.stop_onmyoji).pack(fill=tk.X) def show_params(self): + self.get_gouliang() self.params.config(state=tk.NORMAL) - self.params.insert(tk.END, '########1.0.1.0229########\n') + self.params.insert(tk.END, '########1.0.1.0304########\n') self.params.insert(tk.END, 'client: ' + str(self.client.current())) self.params.insert(tk.END, '\nrun_section: ' + str(self.section.index('current'))) @@ -304,6 +339,10 @@ def show_params(self): str(self.max_op_time.get())) self.params.insert(tk.END, '\nmitama_team_mark: ' + str(self.mitama_team_mark.current())) + self.params.insert(tk.END, '\nexplore_mode: ' + + str(self.explore_mode.get())) + self.params.insert(tk.END, '\ngouliang: ' + str(self.gouliang)) + self.params.insert(tk.END, '\ngouliang_b: ' + str(self.gouliang_b)) self.params.insert(tk.END, '\nfight_boss_enable: ' + str(self.fight_boss_enable.get())) self.params.insert(tk.END, '\nslide_shikigami: ' + @@ -329,16 +368,73 @@ def delay_dialog(self): pw = DelayDialog(self) self.wait_window(pw) + def help(self): + ''' + 使用说明 + ''' + tk.messagebox.showinfo( + "使用说明", '详细使用说明请参考https://academicdog.github.io/onmyoji_bot/') + + def gouliang_state(self, state): + ''' + 禁用狗粮选项 + :param state: 1-仅启用3狗粮,2-禁用3狗粮,3-全启用 + ''' + if state == 1: + self.gouliang_4.set(False) + self.gouliang_5.set(False) + self.gouliang_l.config(state=tk.NORMAL) + self.gouliang_m.config(state=tk.NORMAL) + self.gouliang_r.config(state=tk.NORMAL) + self.gouliang_lb.config(state=tk.DISABLED) + self.gouliang_rb.config(state=tk.DISABLED) + elif state == 2: + self.gouliang_1.set(False) + self.gouliang_2.set(False) + self.gouliang_3.set(False) + self.gouliang_l.config(state=tk.DISABLED) + self.gouliang_m.config(state=tk.DISABLED) + self.gouliang_r.config(state=tk.DISABLED) + self.gouliang_lb.config(state=tk.NORMAL) + self.gouliang_rb.config(state=tk.NORMAL) + elif state == 3: + self.gouliang_l.config(state=tk.NORMAL) + self.gouliang_m.config(state=tk.NORMAL) + self.gouliang_r.config(state=tk.NORMAL) + self.gouliang_lb.config(state=tk.NORMAL) + self.gouliang_rb.config(state=tk.NORMAL) + + def get_gouliang(self): + ''' + 计算狗粮坐标 + ''' + # 前狗粮 + self.gouliang = [] + if self.gouliang_1.get(): + self.gouliang.append(1) + if self.gouliang_2.get(): + self.gouliang.append(2) + if self.gouliang_3.get(): + self.gouliang.append(3) + + # 后狗粮 + self.gouliang_b = [] + if self.gouliang_4.get(): + self.gouliang_b.append(4) + if self.gouliang_5.get(): + self.gouliang_b.append(5) + def start_onmyoji(self): self.show_params() def stop_onmyoji(self): pass + class DelayDialog(tk.Toplevel): def __init__(self, parent): super().__init__() - self.title('延迟设置') + self.title('延迟设置') self.parent = parent # 参数 @@ -354,7 +450,7 @@ def __init__(self, parent): row1.pack(fill=tk.X) tk.Label(row1, text='延迟机制:').pack(anchor=tk.W) text = tk.Text(row1, height=11, width=40) - text.pack(expand=True, fill=tk.BOTH) + text.pack(expand=True, fill=tk.BOTH) text.insert(tk.END, '1-总共5级延迟,脚本随机从1-5级延迟中选择一级作为主延迟,\ 同时在1-3级延迟中选择一级作为副延迟。在此基础上乘以随机系数。\n\n') text.insert(tk.END, '2-每5分钟刷新选择,计算单位毫秒。\n\n') @@ -367,33 +463,43 @@ def __init__(self, parent): row2.pack(fill=tk.X) tk.Label(row2, text='一级: ').grid(row=0, column=0) tk.Label(row2, text='最低').grid(row=0, column=1) - tk.Entry(row2, width=7, textvariable=self.delay[1][0]).grid(row=0, column=3) + tk.Entry(row2, width=7, textvariable=self.delay[1][0]).grid( + row=0, column=3) tk.Label(row2, text='最高').grid(row=0, column=4) - tk.Entry(row2, width=7, textvariable=self.delay[1][1]).grid(row=0, column=5) + tk.Entry(row2, width=7, textvariable=self.delay[1][1]).grid( + row=0, column=5) tk.Label(row2, text='二级: ').grid(row=1, column=0) tk.Label(row2, text='最低').grid(row=1, column=1) - tk.Entry(row2, width=7, textvariable=self.delay[2][0]).grid(row=1, column=3) + tk.Entry(row2, width=7, textvariable=self.delay[2][0]).grid( + row=1, column=3) tk.Label(row2, text='最高').grid(row=1, column=4) - tk.Entry(row2, width=7, textvariable=self.delay[2][1]).grid(row=1, column=5) + tk.Entry(row2, width=7, textvariable=self.delay[2][1]).grid( + row=1, column=5) tk.Label(row2, text='三级: ').grid(row=2, column=0) tk.Label(row2, text='最低').grid(row=2, column=1) - tk.Entry(row2, width=7, textvariable=self.delay[3][0]).grid(row=2, column=3) + tk.Entry(row2, width=7, textvariable=self.delay[3][0]).grid( + row=2, column=3) tk.Label(row2, text='最高').grid(row=2, column=4) - tk.Entry(row2, width=7, textvariable=self.delay[3][1]).grid(row=2, column=5) + tk.Entry(row2, width=7, textvariable=self.delay[3][1]).grid( + row=2, column=5) tk.Label(row2, text='四级: ').grid(row=3, column=0) tk.Label(row2, text='最低').grid(row=3, column=1) - tk.Entry(row2, width=7, textvariable=self.delay[4][0]).grid(row=3, column=3) + tk.Entry(row2, width=7, textvariable=self.delay[4][0]).grid( + row=3, column=3) tk.Label(row2, text='最高').grid(row=3, column=4) - tk.Entry(row2, width=7, textvariable=self.delay[4][1]).grid(row=3, column=5) + tk.Entry(row2, width=7, textvariable=self.delay[4][1]).grid( + row=3, column=5) tk.Label(row2, text='五级: ').grid(row=4, column=0) tk.Label(row2, text='最低').grid(row=4, column=1) - tk.Entry(row2, width=7, textvariable=self.delay[5][0]).grid(row=4, column=3) + tk.Entry(row2, width=7, textvariable=self.delay[5][0]).grid( + row=4, column=3) tk.Label(row2, text='最高').grid(row=4, column=4) - tk.Entry(row2, width=7, textvariable=self.delay[5][1]).grid(row=4, column=5) + tk.Entry(row2, width=7, textvariable=self.delay[5][1]).grid( + row=4, column=5) # 按钮 row3 = tk.Frame(self) @@ -402,13 +508,13 @@ def __init__(self, parent): tk.Button(row3, text='取消', command=self.cancel).grid(row=0, column=1) def confirm(self): - mydelay ={ + mydelay = { 1: [self.delay[1][0].get(), self.delay[1][1].get() - self.delay[1][0].get()], 2: [self.delay[2][0].get(), self.delay[2][1].get() - self.delay[2][0].get()], 3: [self.delay[3][0].get(), self.delay[3][1].get() - self.delay[3][0].get()], 4: [self.delay[4][0].get(), self.delay[4][1].get() - self.delay[4][0].get()], 5: [self.delay[5][0].get(), self.delay[5][1].get() - self.delay[5][0].get()]} - jsObj = json.dumps(mydelay) + jsObj = json.dumps(mydelay) with open('delay.json', 'w') as f: f.write(jsObj) self.destroy() @@ -416,6 +522,7 @@ def confirm(self): def cancel(self): self.destroy() + if __name__ == "__main__": root = tk.Tk() app = Application(master=root) diff --git a/img/DUI.png b/img/DUI.png new file mode 100644 index 0000000..6658a89 Binary files /dev/null and b/img/DUI.png differ diff --git a/img/FEN-XIANG.png b/img/FEN-XIANG.png deleted file mode 100644 index c5756aa..0000000 Binary files a/img/FEN-XIANG.png and /dev/null differ diff --git a/img/JIE-SUAN-JIA-CHENG.png b/img/JIE-SUAN-JIA-CHENG.png deleted file mode 100644 index 155bfc3..0000000 Binary files a/img/JIE-SUAN-JIA-CHENG.png and /dev/null differ diff --git a/img/QUE-DING.png b/img/QUE-DING.png new file mode 100644 index 0000000..2759d03 Binary files /dev/null and b/img/QUE-DING.png differ diff --git a/onmyoji.py b/onmyoji.py index e8c5f5b..4b28ef7 100644 --- a/onmyoji.py +++ b/onmyoji.py @@ -1,4 +1,7 @@ from explore.explore import ExploreFight +from explore.explore_passenger import ExplorePassenger +from explore.explore_leader import ExploreLeader +from explore.explore_dual import ExploreDual from goryou.single_fight import GoryouFight from mitama.dual import DualFighter from mitama.fighter_driver import DriverFighter @@ -59,7 +62,19 @@ def init(): elif section == 2: # 探索 - fight = ExploreFight() + mode = conf.getint('explore', 'explore_mode') + if mode == 0: + # 单刷 + fight = ExploreFight() + elif mode == 1: + # 单人队长 + fight = ExploreLeader() + elif mode == 2: + # 单人队员 + fight = ExplorePassenger() + elif mode == 3: + # 双开 + fight = ExploreDual() fight.start() diff --git a/requirements.txt b/requirements.txt index 4603c20..bec434d 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1,5 +1,5 @@ -numpy==1.17.1 -pywin32==224 -opencv_python==4.1.0.25 -Pillow==6.1.0 +numpy +pywin32 +opencv_python +Pillow opencv_contrib_python==3.4.2.16 \ No newline at end of file diff --git a/tools/game_pos.py b/tools/game_pos.py index 7f5e0eb..49d3f45 100644 --- a/tools/game_pos.py +++ b/tools/game_pos.py @@ -23,8 +23,12 @@ class TansuoPos(): s_tab_btn = (33, 264), (82, 307) # 素材标签 r_tab_btn = (216, 322), (259, 366) # r卡标签 n_slide = (168, 615), (784, 615) # n卡进度条,从头至尾 + gouliang_left = (161, 174), (322, 288) # 左边狗粮位置 gouliang_middle = (397, 218), (500, 349) # 中间狗粮位置 gouliang_right = (628, 293), (730, 430) # 右边狗粮位置 + gouliang_leftback = (0, 273), (150, 393) # 左后狗粮位置 + gouliang_rightback = (433, 462), (567, 569) # 右后狗粮位置 + yaoqing_comfirm = (601, 361), (746, 406) # 继续邀请按钮 @staticmethod def InitPosWithClient__(): diff --git a/tools/utilities.py b/tools/utilities.py index c8ebd21..07120c4 100644 --- a/tools/utilities.py +++ b/tools/utilities.py @@ -92,7 +92,19 @@ def secondposition(): 获得点击位置,扣除御魂部分 :return: 返回随机位置坐标 ''' - return (random.randint(887, 1111), random.randint(56, 452)) + return (random.randint(970, 1111), random.randint(100, 452)) + + +def checkposition(pos): + ''' + 校核结算位置 + :param pos: (x, y)位置坐标 + :return: 如果合适返回True,否则返回False + ''' + if pos[0] < 1111 and pos[0] > 970: + if pos[1] < 452 and pos[1] > 100: + return True + return False def mysleep(slpa, slpb=0): diff --git a/ui.py b/ui.py index b6c8ede..5b505b3 100644 --- a/ui.py +++ b/ui.py @@ -52,6 +52,9 @@ def set_conf(self): str(self.mitama_team_mark.current())) # 探索参数 + self.conf.set('explore', 'explore_mode', str(self.explore_mode.get())) + self.conf.set('explore', 'gouliang', str(self.gouliang)) + self.conf.set('explore', 'gouliang_b', str(self.gouliang_b)) self.conf.set('explore', 'fight_boss_enable', str(self.fight_boss_enable.get())) self.conf.set('explore', 'slide_shikigami', @@ -79,12 +82,12 @@ def get_conf(self): self.conf.write(configfile) def start_onmyoji(self): - # 读取主要副本 - self.get_conf() - # 显示参数 self.show_params() + # 读取主要副本 + self.get_conf() + subprocess.Popen("cmd.exe /c start Core.exe") # os.system("onmyoji.exe")