class Application(Frame): def __init__(self, master=None): """ 控件初始化 :param master: """ self.debug = False self.warning = '【封号防止】\n' + \ '请尽量在自己的日常刷魂时间使用\n' + \ '请不要长时间连续使用,任何使你看起来明显违背人类正常作息规律的行为,很容易会被鬼使黑盯上\n' + \ '当你离开了常在城市,请不要使用,这会被认为是找了代练\n' + \ '点到为止,贪婪是万恶之源\n' self.label = r'阴阳师-网易游戏' self.hwnd = None self.shell = None if not self.info_get(): self.scaling = 1 self.clear_time = 35 self.delay_time = 1 self.fight = None self.timing_value = None # 控件初始化 Frame.__init__(self, master) self.pack() self.frame1 = Frame(self) self.frame1.pack() self.frame2 = Frame(self) self.frame2.pack() self.label_scaling = Label(self.frame1) self.var_scaling = StringVar(self.frame1) self.entry_scaling = Entry(self.frame1) self.button_scaling_explain = Button(self.frame1) self.label_mode = Label(self.frame1) self.var_mode = StringVar(self.frame1) self.listbox_mode = ttk.Combobox(self.frame1) self.button_mode_explain = Button(self.frame1) self.label_member = Label(self.frame1) self.var_member = IntVar() self.radio1 = Radiobutton(self.frame1) self.radio2 = Radiobutton(self.frame1) self.label_clear_time = Label(self.frame1) self.var_clear_time = StringVar(self.frame1) self.entry_clear_time = Entry(self.frame1) self.button_clear_time_explain = Button(self.frame1) self.label_delay_time = Label(self.frame1) self.var_delay_time = StringVar(self.frame1) self.entry_delay_time = Entry(self.frame1) self.button_delay_time_explain = Button(self.frame1) self.label_offer = Label(self.frame1) self.var_offer_mode = StringVar(self.frame1) self.listbox_offer_mode = ttk.Combobox(self.frame1) self.label_timing_mode = Label(self.frame1) self.var_timing_mode = StringVar(self.frame1) self.listbox_timing_mode = ttk.Combobox(self.frame1) self.var_timing_value = StringVar(self.frame1) self.entry_timing_value = Entry(self.frame1) self.label_done_action_mode = Label(self.frame1) self.var_done_action_mode = StringVar(self.frame1) self.listbox_done_action_mode = ttk.Combobox(self.frame1) self.entry_test = Entry(self.frame1) self.test_btn = Button(self.frame1) self.start_ctn = Button(self.frame2) self.stop_ctn = Button(self.frame2) self.info_box = ScrolledText(self.frame2) self.queue = Queue(maxsize=1) self._running = 1 self.create_main() def setdebug(self, debug): self.debug = debug @staticmethod def check_hwnd(label): """ 获取游戏窗口句柄 :param label: 游戏窗口title :return: 游戏窗口存在则返回句柄对象,不存在则返回False """ hwnd = win32gui.FindWindow(None, label) if hwnd: return hwnd else: print('游戏没有运行') return False @staticmethod def init_window_place(root, x, y): """ 初始化窗口位置 :param root: 顶层窗体 :param x: 横轴分母 :param y: 竖轴分母 :return: """ screenwidth = root.winfo_screenwidth() screenheight = root.winfo_screenheight() root.resizable(False, False) root.update_idletasks() root.deiconify() width = root.winfo_width() height = root.winfo_height() size = '%dx%d+%d+%d' % (width, height, (screenwidth - width) / x, (screenheight - height) / y) root.geometry(size) def jump_window(self): """ 使游戏窗口到最顶层 :return: """ win32gui.SetForegroundWindow(self.hwnd) win32gui.PostMessage(self.hwnd, win32con.WM_SYSCOMMAND, win32con.SC_RESTORE, 0) def get_scaling(self): """ 校验windows缩放倍率输入值 :return: 校验通过则返回浮点型数字,否则返回False """ var = self.entry_scaling.get() try: var = float(var) except ValueError: messagebox.showinfo(title='提示', message='缩放倍率只能为数字') return False if var > 2: messagebox.showinfo(title='提示', message='缩放倍率过高') return False return var def get_clear_time(self): """ 校验平均通关时间输入值 :return: 校验通过则返回浮点型数字,否则返回False """ var = self.var_clear_time.get() try: var = float(var) except ValueError: messagebox.showinfo(title='提示', message='平均通关时间只能为数字') return False if var <= 5: messagebox.showinfo(title='提示', message='平均通关时间不能小于5') return False return var def get_delay_time(self): """ 校验平均通关时间输入值 :return: 校验通过则返回浮点型数字,否则返回False """ var = self.var_delay_time.get() try: var = float(var) except ValueError: messagebox.showinfo(title='提示', message='战斗后等待时间只能为数字') return False if var <= 0: messagebox.showinfo(title='提示', message='战斗后等待时间不能小于0') return False return var def get_timimg(self): """ 校验预定结束输入值 :return: 校验通过则返回浮点型数字,否则返回False """ if self.listbox_timing_mode.get() == '无': return True var = self.var_timing_value.get() try: var = float(var) except ValueError: messagebox.showinfo(title='提示', message='预定结束只能填入数字') return False if var < 1: messagebox.showinfo(title='提示', message='数字过小,无法执行') return False return var @staticmethod def time_format(second): """ 时间数值格式化 :param second: 总秒数 :return: 时间大于60秒则返回00:00:00格式 """ try: second = int(second) except ValueError: return second if second > 60: m, s = divmod(second, 60) h, m = divmod(m, 60) return ':'.join( (str(h).zfill(2), str(m).zfill(2), str(s).zfill(2))) else: return second def info_get(self): """ 读取存储文件 :return: """ try: with shelve.open('mysetting.db') as data: setting_data = data['setting'] self.scaling = setting_data['scaling'] self.clear_time = setting_data['clear_time'] self.delay_time = setting_data['delay_time'] except KeyError: return False return True def info_save(self): """ 存储设置 :return: """ with shelve.open('mysetting.db') as data: setting_data = dict() setting_data['scaling'] = self.var_scaling.get() setting_data['clear_time'] = self.var_clear_time.get() setting_data['delay_time'] = self.var_delay_time.get() data['setting'] = setting_data def turn_radio_on(self, *args): """ 根据条件激活相应控件 :param args: :return: """ type(args) var = self.listbox_mode.get() if var == '司机': self.radio1.configure(state='active') self.radio2.configure(state='active') else: self.radio1.configure(state='disabled') self.radio2.configure(state='disabled') def turn_entry_on(self, *args): """ 根据条件激活相应控件 :param args: :return: """ type(args) var = self.listbox_timing_mode.get() if var == '定时[分钟]' or var == '场数': self.entry_timing_value.configure(state='normal') self.listbox_done_action_mode.configure(state='normal') self.var_done_action_mode.set('关闭游戏窗口') else: self.entry_timing_value.configure(state='disabled') self.var_done_action_mode.set('') self.listbox_done_action_mode.configure(state='disabled') def fight_start(self): """ START按钮响应流程 :return: """ self.scaling = self.get_scaling() if not self.scaling: return False self.clear_time = self.get_clear_time() if not self.clear_time: return False self.delay_time = self.get_delay_time() if not self.delay_time: return False self.timing_value = self.get_timimg() if not self.timing_value: return False self.info_save() # 获取游戏窗口句柄 self.hwnd = self.check_hwnd(self.label) if not self.hwnd: messagebox.showinfo(title='提示', message='游戏没有运行') return False self.shell = win32com.client.Dispatch("WScript.Shell") # self.shell.SendKeys('%') self.jump_window() time.sleep(0.5) self.fight = GameController(self.hwnd, self.scaling) if self.debug: self.fight.setdebug(True) thread1 = threading.Thread(target=self.fight_thread, name='fight_thread') thread2 = threading.Thread(target=self.offer_thread, name='offer_thread') # 将线程状态、队列内容置为1 self._running = 1 if self.queue.empty(): self.queue.put(1) else: self.queue.get() self.queue.put(1) self.start_ctn.configure(state='disabled') self.stop_ctn.configure(state='active') thread1.start() thread2.start() def fight_stop(self): """ STOP按钮响应流程 :return: """ # 将线程状态、队列内容置为0 self._running = 0 self.queue.put(0) self.start_ctn.configure(state='active') self.stop_ctn.configure(state='disabled') var = '[%s]挂机结束。记得关御魂buff' % datetime.datetime.now().strftime( "%H:%M:%S") self.info_box.mark_set('insert', END) self.info_box.insert('insert', str(var) + '\n') self.info_box.see(END) def fight_thread(self): """ 战斗控制线程,并输出相关信息 :return: """ self.jump_window() if not self.queue.empty(): self.queue.get() # if self.debug: # self.fight.move_curpos_test() # self.fight_stop() # return self.info_box.mark_set('insert', END) self.info_box.insert('insert', str(self.warning) + '\n', 'RED') self.info_box.tag_config('RED', foreground='red') var = '[%s]挂机开始' % datetime.datetime.now().strftime("%H:%M:%S") self.info_box.mark_set('insert', END) self.info_box.insert('insert', str(var) + '\n') self.info_box.see(END) rounds = 0 total_time = 0 beginning_timg = time.clock() while True: if self._running == 1: # self.fight.move_curpos_test() # self.fight_stop() # time.sleep(5) fight_start_time = time.clock() self.fight.form_team_phase(self.listbox_mode.get(), self.var_member.get(), self.queue) self.fight.wait_fight_finish_phase(self.listbox_mode.get(), self.clear_time, self.queue) self.jump_window() self.fight.settle_phase_2(self.queue) if self._running == 1: fight_end_time = time.clock() fight_time = fight_end_time - fight_start_time # time.sleep(0.5) rounds = rounds + 1 total_time = total_time + fight_time elapsed_time = fight_end_time - beginning_timg var = '第 %s 场 耗时:%s 共计:%s' % \ (rounds, self.time_format(fight_time), self.time_format(elapsed_time)) self.info_box.mark_set('insert', END) self.info_box.insert('insert', str(var) + '\n') self.info_box.see(END) # 检查是否到达预定结束场数或时间 if (self.listbox_timing_mode.get() == '场数' and rounds >= self.timing_value) or \ (self.listbox_timing_mode.get() == '定时[分钟]' and elapsed_time / 60 >= self.timing_value): if self.listbox_done_action_mode.get() == '关闭游戏窗口': win32gui.PostMessage(self.hwnd, win32con.WM_CLOSE, 0, 0) time.sleep(1) lebel_exit = '退出游戏' hwnd_exit = self.check_hwnd(lebel_exit) win32gui.PostMessage(hwnd_exit, win32con.WM_KEYDOWN, win32con.VK_RETURN, 0) win32gui.PostMessage(hwnd_exit, win32con.WM_KEYUP, win32con.VK_RETURN, 0) var = '已到达预定目标,游戏窗口已关闭。下线15分钟后buff自动关闭' elif self.listbox_done_action_mode.get() == '仅停止挂机': var = '已到达预定目标,挂机已停止。' self.fight_stop() self.info_box.mark_set('insert', END) self.info_box.insert('insert', str(var) + '\n') self.info_box.see(END) random.uniform(1, 2) delay_time = int(self.delay_time) + random.uniform( 0.2, 0.5) time.sleep(delay_time) elif self._running == 0: return def offer_thread(self): """ 悬赏协助控制线程 :return: """ while True: if self._running == 1: self.fight.check_offer(self.listbox_offer_mode.get(), self.queue) elif self._running == 0: return @staticmethod def resource_path(relative_path): """ Get absolute path to resource, works for dev and for PyInstaller """ base_path = getattr(sys, '_MEIPASS', os.path.dirname(os.path.abspath(__file__))) return os.path.join(base_path, relative_path) def what_is_scaling_window(self): what_is_scaling = Toplevel(self) what_is_scaling.title('缩放倍率 - 不能自动获取,技术就是这么菜,不服憋着_(:3」∠)_') frame1 = Frame(what_is_scaling) frame1.pack() frame2 = Frame(what_is_scaling) frame2.pack() title = Label(frame1) title['text'] = '\n【 缩放倍率 】' title.pack() desc1 = Message(frame1) desc1['width'] = 600 desc1['text'] = '\n缩放倍率是指Windows系统在不改变分辨率的情况下,将窗口和图标放大以达到更加舒适的显示效果的功能\n' + \ '\n在某些分辨率下,Windows会自动设置一个超过100%的倍率。请确定自己系统当前的缩放倍率设置,并填入缩放倍率一栏中\n' + \ '\n不正确的缩放倍率设置,会导致坐标计算不准\n' + \ '\n若设置的缩放倍率是100%,则填入1,若是125%,则填1.25,依次类推\n' desc1.pack() label_win10 = Label(frame2) label_win10['text'] = 'Windows 10' label_win10.grid(row=0, column=0) label_win7 = Label(frame2) label_win7['text'] = 'Windows 7' label_win7.grid(row=0, column=1) ipath = self.resource_path('image/win10.png') load = PLI_Image.open(ipath) load = load.resize(tuple(map(lambda x: int(x * 0.5), load.size))) render = ImageTk.PhotoImage(load) img_win10 = Label(frame2, image=render) img_win10.image = render img_win10.grid(row=1, column=0) ipath = self.resource_path('image/win7.png') load = PLI_Image.open(ipath) load = load.resize(tuple(map(lambda x: int(x * 0.5), load.size))) render = ImageTk.PhotoImage(load) img_win7 = Label(frame2, image=render) img_win7.image = render img_win7.grid(row=1, column=1) self.init_window_place(what_is_scaling, 1.3, 3) def when_click_start_window(self): when_click_start = Toplevel(self) when_click_start.title('模式说明') var = self.listbox_mode.get() if var == '单刷': title = Label(when_click_start) title['text'] = '\n【 单刷模式 】' title.pack() desc = Message(when_click_start) desc['text'] = '\n请把游戏调整至如图所示界面,再点START\n' desc['width'] = 300 desc.pack() ipath = self.resource_path('image/single.png') load = PLI_Image.open(ipath) load = load.resize(tuple(map(lambda x: int(x * 0.7), load.size))) render = ImageTk.PhotoImage(load) img = Label(when_click_start, image=render) img.image = render img.pack() elif var == '乘客': title = Label(when_click_start) title['text'] = '\n【 乘客模式 】' title.pack() desc = Message(when_click_start) desc['text'] = '\n建议接受了司机的默认邀请,再点START\n' + \ '因为我不会在战斗里帮你点开始...不服憋着\n_(:3」∠)_\n' desc['width'] = 300 desc.pack() ipath = self.resource_path('image/passenger_accept.png') load = PLI_Image.open(ipath) load = load.resize(tuple(map(lambda x: int(x * 0.7), load.size))) render = ImageTk.PhotoImage(load) img = Label(when_click_start, image=render) img.image = render img.pack() elif var == '司机': title = Label(when_click_start) title['text'] = '\n【 司机模式 】' title.pack() desc = Message(when_click_start) desc['text'] = '\n建议对乘客发出默认邀请,回到组队界面再点START\n' + \ '因为自动发出邀请这个功能没写...不服憋着\n_(:3」∠)_\n' desc['width'] = 300 desc.pack() ipath = self.resource_path('image/driver_invite.png') load = PLI_Image.open(ipath) load = load.resize(tuple(map(lambda x: int(x * 0.5), load.size))) render = ImageTk.PhotoImage(load) img1 = Label(when_click_start, image=render) img1.image = render img1.pack() ipath = self.resource_path('image/driver_form.png') load = PLI_Image.open(ipath) load = load.resize(tuple(map(lambda x: int(x * 0.5), load.size))) render = ImageTk.PhotoImage(load) img2 = Label(when_click_start, image=render) img2.image = render img2.pack() self.init_window_place(when_click_start, 1.3, 3) def what_is_clear_time(self): what_is_clear = Toplevel(self) what_is_clear.title('平均通关时间说明') title = Label(what_is_clear) title['text'] = '\n【 平均通关时间 】' title.pack() desc = Message(what_is_clear) desc['text'] = '\n平均通关时间是指在游戏中,从按下开始战斗到进入结算奖励界面所经过的时间(秒)\n' + \ '\n程序会在经过指定的时间后,再开始检测游戏画面是否进入了结算界面\n' + \ '\n如果设置一个较短的时间也可以,不过设置一个合理的时间,能节省你CPU资源\n(其实也没占多少_(:3」∠)_\n' desc['width'] = 300 desc.pack() self.init_window_place(what_is_clear, 1.3, 3) def what_is_delay_time(self): what_is_delay = Toplevel(self) what_is_delay.title('战斗后等待时间说明') title = Label(what_is_delay) title['text'] = '\n【 战斗后等待时间 】' title.pack() desc = Message(what_is_delay) desc['text'] = '\n战斗后等待时间是指,在下一次战斗开始前强制等待的时间(秒)\n' + \ '\n填入的时间还会加上一个300毫秒以内的随机时间\n' desc['width'] = 300 desc.pack() self.init_window_place(what_is_delay, 1.3, 3) def create_main(self): """ 窗体、控件绘制 :return: """ self.label_scaling['text'] = '缩放倍率' self.var_scaling.set(self.scaling) self.entry_scaling['textvariable'] = self.var_scaling self.label_scaling.grid(row=0, column=0, sticky='E') self.entry_scaling.grid(row=0, column=1, sticky='W', columnspan=2) self.button_scaling_explain['text'] = '?' self.button_scaling_explain['command'] = self.what_is_scaling_window self.button_scaling_explain['relief'] = 'flat' self.button_scaling_explain.grid(row=0, column=2, sticky='E') self.label_mode['text'] = '模式' self.var_mode.set('单刷') self.listbox_mode['textvariable'] = self.var_mode self.listbox_mode['width'] = 10 self.listbox_mode['values'] = ["单刷", "乘客", "司机"] self.listbox_mode.bind("<<ComboboxSelected>>", self.turn_radio_on) self.label_mode.grid(row=1, column=0, sticky='E') self.listbox_mode.grid(row=1, column=1, sticky='W') self.button_mode_explain['text'] = '?' self.button_mode_explain['command'] = self.when_click_start_window self.button_mode_explain['relief'] = 'flat' self.button_mode_explain.grid(row=1, column=2, sticky='W') self.var_member.set(2) self.label_member['text'] = '车队人数' self.label_member.grid(row=2, column=0, sticky='E') self.radio1['text'] = '2人' self.radio1['variable'] = self.var_member self.radio1['value'] = 2 # self.radio1['command'] = self.test_val3 self.radio1.grid(row=2, column=1, sticky='W') self.radio1.configure(state='disabled') self.radio2['text'] = '3人' self.radio2['variable'] = self.var_member self.radio2['value'] = 3 # self.radio2['command'] = self.test_val3 self.radio2.grid(row=2, column=2, sticky='W') self.radio2.configure(state='disabled') self.label_clear_time['text'] = '平均通关时间' self.var_clear_time.set(self.clear_time) self.entry_clear_time['textvariable'] = self.var_clear_time self.label_clear_time.grid(row=3, column=0, sticky='E') self.entry_clear_time.grid(row=3, column=1, sticky='W', columnspan=2) self.button_clear_time_explain['text'] = '?' self.button_clear_time_explain['command'] = self.what_is_clear_time self.button_clear_time_explain['relief'] = 'flat' self.button_clear_time_explain.grid(row=3, column=2, sticky='E') self.label_delay_time['text'] = '战斗结束后等待时间' self.var_delay_time.set(self.delay_time) self.entry_delay_time['textvariable'] = self.var_delay_time self.label_delay_time.grid(row=4, column=0, sticky='E') self.entry_delay_time.grid(row=4, column=1, sticky='W', columnspan=2) self.button_delay_time_explain['text'] = '?' self.button_delay_time_explain['command'] = self.what_is_delay_time self.button_delay_time_explain['relief'] = 'flat' self.button_delay_time_explain.grid(row=4, column=2, sticky='E') self.label_offer['text'] = '好友发来悬赏' self.var_offer_mode.set('接受') self.listbox_offer_mode['textvariable'] = self.var_offer_mode self.listbox_offer_mode['width'] = 10 self.listbox_offer_mode['values'] = ["接受", "拒绝"] # self.listbox_offer_mode.bind("<<ComboboxSelected>>", self.turn_entry_on) self.label_offer.grid(row=5, column=0, sticky='E') self.listbox_offer_mode.grid(row=5, column=1, sticky='W') self.label_timing_mode['text'] = '预定结束' self.var_timing_mode.set('无') self.listbox_timing_mode['textvariable'] = self.var_timing_mode self.listbox_timing_mode['width'] = 10 self.listbox_timing_mode['values'] = ["无", "定时[分钟]", "场数"] self.listbox_timing_mode.bind("<<ComboboxSelected>>", self.turn_entry_on) self.label_timing_mode.grid(row=6, column=0, sticky='E') self.listbox_timing_mode.grid(row=6, column=1, sticky='W') self.var_timing_value.set('') self.entry_timing_value['textvariable'] = self.var_timing_value self.entry_timing_value['width'] = 5 self.entry_timing_value.configure(state='disabled') self.entry_timing_value.grid(row=6, column=2, sticky='W') self.label_done_action_mode['text'] = '预定结束后动作' self.var_done_action_mode.set('') self.listbox_done_action_mode[ 'textvariable'] = self.var_done_action_mode self.listbox_done_action_mode['width'] = 10 self.listbox_done_action_mode.configure(state='disabled') self.listbox_done_action_mode['values'] = ["关闭游戏窗口", "仅停止挂机"] # self.listbox_done_action_mode.bind("<<ComboboxSelected>>", self.turn_entry_on) self.label_done_action_mode.grid(row=7, column=0, sticky='E') self.listbox_done_action_mode.grid(row=7, column=1, sticky='W') self.start_ctn['text'] = 'START' self.start_ctn['width'] = 10 self.start_ctn['height'] = 2 self.start_ctn['command'] = self.fight_start self.start_ctn['relief'] = 'groove' self.start_ctn.grid(row=0, column=0, sticky='E') self.stop_ctn['text'] = 'STOP' self.stop_ctn['width'] = 10 self.stop_ctn['height'] = 2 self.stop_ctn['command'] = self.fight_stop self.stop_ctn['relief'] = 'groove' self.stop_ctn.grid(row=0, column=1, sticky='W') self.stop_ctn.configure(state='disabled') self.info_box['width'] = 40 self.info_box['height'] = 20 self.info_box.grid(row=1, column=0, columnspan=2) self.info_box.see(END) var = 'Build 20190421' self.info_box.mark_set('insert', END) self.info_box.insert('insert', str(var) + '\n') self.info_box.see(END) var = '请授予此程序管理员权限运行,否则在游戏窗口内鼠标无法被控制' self.info_box.mark_set('insert', END) self.info_box.insert('insert', str(var) + '\n') self.info_box.see(END)
class Application(Frame): def __init__(self, master=None): """ 控件初始化 :param master: """ self.debug = False self.version = 'miss' self.warning = '【封号防止】\n' + \ '请尽量在自己的日常刷魂时间使用\n' + \ '请不要长时间连续使用,任何使你看起来明显违背人类正常作息规律的行为,很容易会被鬼使黑盯上\n' + \ '当你离开了常在城市,请不要使用,这会被认为是找了代练\n' + \ '点到为止,贪婪是万恶之源\n' self.label = r'阴阳师-网易游戏' self.hwnd = None self.shell = None if not self.info_get(): self.scaling = 1 self.clear_time = 35 self.delay_time = 1 self.fight = None self.timing_value = None # 控件初始化 Frame.__init__(self, master) self.pack() self.frame1 = Frame(self) self.frame1.pack() self.frame2 = Frame(self) self.frame2.pack() self.label_mode = Label(self.frame1) self.var_mode = StringVar(self.frame1) self.listbox_mode = ttk.Combobox(self.frame1) self.button_mode_explain = Button(self.frame1) self.label_member = Label(self.frame1) self.var_member = IntVar() self.radio1 = Radiobutton(self.frame1) self.radio2 = Radiobutton(self.frame1) self.label_clear_time = Label(self.frame1) self.var_clear_time = StringVar(self.frame1) self.entry_clear_time = Entry(self.frame1) self.button_clear_time_explain = Button(self.frame1) self.label_delay_time = Label(self.frame1) self.var_delay_time = StringVar(self.frame1) self.entry_delay_time = Entry(self.frame1) self.button_delay_time_explain = Button(self.frame1) self.label_offer = Label(self.frame1) self.var_offer_mode = StringVar(self.frame1) self.listbox_offer_mode = ttk.Combobox(self.frame1) self.label_timing_mode = Label(self.frame1) self.var_timing_mode = StringVar(self.frame1) self.listbox_timing_mode = ttk.Combobox(self.frame1) self.var_timing_value = StringVar(self.frame1) self.entry_timing_value = Entry(self.frame1) self.label_done_action_mode = Label(self.frame1) self.var_done_action_mode = StringVar(self.frame1) self.listbox_done_action_mode = ttk.Combobox(self.frame1) self.entry_test = Entry(self.frame1) self.test_btn = Button(self.frame1) self.start_ctn = Button(self.frame2) self.stop_ctn = Button(self.frame2) self.info_box = ScrolledText(self.frame2) self.queue = Queue(maxsize=1) self._running = 0 hot_key = threading.Thread(target=self.hotkey_thread, name='hotkey_thread') hot_key.setDaemon(True) hot_key.start() def setdebug(self, debug): self.debug = debug def setversion(self, version): self.version = version def get_clear_time(self): """ 校验平均通关时间输入值 :return: 校验通过则返回浮点型数字,否则返回False """ var = self.var_clear_time.get() try: var = float(var) except ValueError: messagebox.showinfo(title='提示', message='平均通关时间只能为数字') return False if var <= 5: messagebox.showinfo(title='提示', message='平均通关时间不能小于5') return False return var def get_delay_time(self): """ 校验平均通关时间输入值 :return: 校验通过则返回浮点型数字,否则返回False """ var = self.var_delay_time.get() try: var = float(var) except ValueError: messagebox.showinfo(title='提示', message='战斗后等待时间只能为数字') return False if var <= 0: messagebox.showinfo(title='提示', message='战斗后等待时间不能小于0') return False return var def get_timimg(self): """ 校验预定结束输入值 :return: 校验通过则返回浮点型数字,否则返回False """ if self.listbox_timing_mode.get() == '无' or \ self.listbox_timing_mode.get() == '超鬼王模式1' or \ self.listbox_timing_mode.get() == '超鬼王模式2': return True var = self.var_timing_value.get() try: var = float(var) except ValueError: messagebox.showinfo(title='提示', message='预定结束只能填入数字') return False if var < 1: messagebox.showinfo(title='提示', message='数字过小,无法执行') return False return var def info_get(self): """ 读取存储文件 :return: """ try: with shelve.open('mysetting.db') as data: setting_data = data['setting'] self.scaling = setting_data['scaling'] self.clear_time = setting_data['clear_time'] self.delay_time = setting_data['delay_time'] except KeyError: return False return True def info_save(self): """ 存储设置 :return: """ with shelve.open('mysetting.db') as data: setting_data = dict() setting_data['clear_time'] = self.var_clear_time.get() setting_data['delay_time'] = self.var_delay_time.get() data['setting'] = setting_data def turn_radio_on(self, *args): """ 根据条件激活相应控件 :param args: :return: """ type(args) var = self.listbox_mode.get() if var == '司机': self.radio1.configure(state='active') self.radio2.configure(state='active') else: self.radio1.configure(state='disabled') self.radio2.configure(state='disabled') def turn_entry_on(self, *args): """ 根据条件激活相应控件 :param args: :return: """ type(args) var = self.listbox_timing_mode.get() if var == '定时[分钟]' or var == '场数': self.entry_timing_value.configure(state='normal') self.listbox_done_action_mode.configure(state='normal') self.var_done_action_mode.set('关闭游戏窗口') elif var == '超鬼王模式1': self.entry_timing_value.configure(state='disabled') self.listbox_done_action_mode.configure(state='normal') self.var_done_action_mode.set('仅停止挂机') content = '\n超鬼王模式1:\n仅自己发现的鬼王\n' self.info_box.mark_set('insert', END) self.info_box.insert('insert', str(content) + '\n') self.info_box.see(END) elif var == '超鬼王模式2': self.entry_timing_value.configure(state='disabled') self.listbox_done_action_mode.configure(state='normal') self.var_done_action_mode.set('仅停止挂机') content = '\n超鬼王模式2:\n自己发现的鬼王或好友邀请的鬼王\n' self.info_box.mark_set('insert', END) self.info_box.insert('insert', str(content) + '\n') self.info_box.see(END) else: self.entry_timing_value.configure(state='disabled') self.var_done_action_mode.set('') self.listbox_done_action_mode.configure(state='disabled') def turn_all_widget_off(self): self.entry_clear_time.configure(state='disabled') self.entry_delay_time.configure(state='disabled') self.entry_timing_value.configure(state='disabled') self.listbox_mode.configure(state='disabled') self.listbox_offer_mode.configure(state='disabled') self.listbox_timing_mode.configure(state='disabled') self.listbox_done_action_mode.configure(state='disabled') def turn_all_widget_on(self): self.entry_clear_time.configure(state='normal') self.entry_delay_time.configure(state='normal') self.entry_timing_value.configure(state='normal') self.listbox_mode.configure(state='normal') self.listbox_offer_mode.configure(state='normal') self.listbox_timing_mode.configure(state='normal') self.listbox_done_action_mode.configure(state='normal') def fight_start(self): """ START按钮响应流程 :return: """ self.clear_time = self.get_clear_time() if not self.clear_time: return False self.delay_time = self.get_delay_time() if not self.delay_time: return False self.timing_value = self.get_timimg() if not self.timing_value: return False self.info_save() # 获取游戏窗口句柄 self.hwnd = check_hwnd(self.label) if not self.hwnd: messagebox.showinfo(title='提示', message='游戏没有运行') return False # self.shell = win32com.client.Dispatch("WScript.Shell") # self.shell.SendKeys('%') jump_window(self.hwnd) time.sleep(0.5) try: self.fight = GameController(self.hwnd) print('原分辨率 %s * %s' % (self.fight.resolution['width'], self.fight.resolution['height'])) print('缩放后分辨率 %s * %s' % (self.fight.resolution['width_scale'], self.fight.resolution['height_scale'])) print('缩放比例 %s' % self.fight.resolution['scaling']) except ResolutionGetError: messagebox.showinfo(title='提示', message='获取Windows缩放比例失败,无法计算坐标') return False if self.debug: self.fight.setdebug(True) threads = [] thread1 = threading.Thread(target=self.fight_thread, name='fight_thread') threads.append(thread1) thread2 = threading.Thread(target=self.offer_thread, name='offer_thread') threads.append(thread2) thread3 = threading.Thread(target=self.fullrepo_thread, name='fullrepo_thread') threads.append(thread3) if self.listbox_timing_mode.get( ) == '超鬼王模式1' or self.listbox_timing_mode.get() == '超鬼王模式2': thread4 = threading.Thread(target=self.boss_monitoring_thread, name='boss_thread') threads.append(thread4) # 将线程状态、队列内容置为1 self._running = 1 if self.queue.empty(): self.queue.put(1) else: self.queue.get() self.queue.put(1) self.start_ctn.configure(state='disabled') self.stop_ctn.configure(state='active') for thread in threads: thread.setDaemon(True) thread.start() def fight_stop(self): """ STOP按钮响应流程 :return: """ # 将线程状态、队列内容置为0 self._running = 0 self.queue.put(0) self.start_ctn.configure(state='active') self.stop_ctn.configure(state='disabled') self.turn_all_widget_on() var = '[%s]挂机结束。记得关御魂buff' % datetime.datetime.now().strftime( "%H:%M:%S") self.info_box.mark_set('insert', END) self.info_box.insert('insert', str(var) + '\n') self.info_box.see(END) if self.debug: logging('STOP指令-----------------') if len(sys.argv) == 1 or (len(sys.argv) > 1 and sys.argv[1] != 'debug'): self.setdebug(False) def fight_thread(self): """ 战斗控制线程,并输出相关信息 :return: """ jump_window(self.hwnd) if not self.queue.empty(): self.queue.get() self.info_box.mark_set('insert', END) self.info_box.insert('insert', str(self.warning) + '\n', 'RED') self.info_box.tag_config('RED', foreground='red') var = '[%s]挂机开始。按Ctrl + F1可以停止挂机' % datetime.datetime.now().strftime( "%H:%M:%S") if self.debug: var = var + '\n当前以debug模式运行,在当前目录下将生成debug.log' self.turn_all_widget_off() self.info_box.mark_set('insert', END) self.info_box.insert('insert', str(var) + '\n') self.info_box.see(END) rounds = 0 total_time = 0 beginning_time = int(time.time()) while True: if self._running == 1: fight_start_time = time.time() self.fight.form_team_phase(self.listbox_mode.get(), self.var_member.get(), self.queue) self.fight.wait_fight_finish_phase(self.listbox_mode.get(), self.clear_time, self.queue) jump_window(self.hwnd) self.fight.settle_phase(self.queue) if self._running == 1: fight_end_time = int(time.time()) fight_time = fight_end_time - fight_start_time rounds = rounds + 1 total_time = total_time + fight_time elapsed_time = fight_end_time - beginning_time var = '第 %s 场 耗时:%s 共计:%s' % \ (rounds, time_format(fight_time), time_format(elapsed_time)) self.info_box.mark_set('insert', END) self.info_box.insert('insert', str(var) + '\n') self.info_box.see(END) if self.debug: logging('------------------------') # 检查是否到达预定结束场数或时间 if (self.listbox_timing_mode.get() == '场数' and rounds >= self.timing_value) or \ (self.listbox_timing_mode.get() == '定时[分钟]' and elapsed_time / 60 >= self.timing_value): if self.listbox_done_action_mode.get() == '关闭游戏窗口': win32gui.PostMessage(self.hwnd, win32con.WM_CLOSE, 0, 0) time.sleep(1) lebel_exit = '退出游戏' hwnd_exit = check_hwnd(lebel_exit) win32gui.PostMessage(hwnd_exit, win32con.WM_KEYDOWN, win32con.VK_RETURN, 0) win32gui.PostMessage(hwnd_exit, win32con.WM_KEYUP, win32con.VK_RETURN, 0) var = '已到达预定目标,游戏窗口已关闭。下线15分钟后buff自动关闭' elif self.listbox_done_action_mode.get() == '仅停止挂机': var = '已到达预定目标,挂机已停止。' self.fight_stop() self.info_box.mark_set('insert', END) self.info_box.insert('insert', str(var) + '\n') self.info_box.see(END) random.uniform(1, 2) delay_time = int(self.delay_time) + random.uniform( 0.2, 0.5) time.sleep(delay_time) elif self._running == 0: return def offer_thread(self): """ 悬赏协助控制线程 :return: """ while True: if self._running == 1: mode = None if self.listbox_offer_mode.get() == "接受": mode = 1 elif self.listbox_offer_mode.get() == "拒绝": mode = 2 self.fight.check_offer(mode, self.queue) elif self._running == 0: return def fullrepo_thread(self): """ 点击满仓提示控制线程 :return: """ while True: if self._running == 1: self.fight.check_fullrepo_alert(self.queue) elif self._running == 0: return def hotkey_thread(self): """ 快捷键监听线程 :return: """ user32 = ctypes.windll.user32 byref = ctypes.byref user32.RegisterHotKey(None, 10001, win32con.MOD_CONTROL, win32con.VK_F1) user32.RegisterHotKey(None, 10002, win32con.MOD_CONTROL, win32con.VK_F2) try: msg = ctypes.wintypes.MSG() while user32.GetMessageA(byref(msg), None, 0, 0) != 0: if msg.message == win32con.WM_HOTKEY: if self._running == 1 and msg.wParam == 10001: self.fight_stop() elif self._running == 0 and msg.wParam == 10002: self.setdebug(True) self.fight_start() user32.TranslateMessage(byref(msg)) user32.DispatchMessageA(byref(msg)) finally: user32.UnregisterHotKey(None, 10001) user32.UnregisterHotKey(None, 10002) def boss_monitoring_thread(self): """ 点击发现超鬼王提示控制线程 :return: """ "" mode = None if self.listbox_timing_mode.get() == '超鬼王模式1': mode = 1 elif self.listbox_timing_mode.get() == '超鬼王模式2': mode = 2 logging('mode:%s' % mode) while True: if self._running == 1: self.fight.click_boss_notice(mode, self.queue) self.fight_stop() time.sleep(3) audio_play() messagebox.showinfo('就你鬼王多', '发现超鬼王啦!还不快冲鸭!') audio_stop() return elif self._running == 0: return def when_click_start_window(self): when_click_start = Toplevel(self) when_click_start.title('模式说明') var = self.listbox_mode.get() if var == '单刷': title = Label(when_click_start) title['text'] = '\n【 单刷模式 】' title.pack() desc = Message(when_click_start) desc['text'] = '\n请把游戏调整至如图所示界面,再点START\n' desc['width'] = 300 desc.pack() ipath = resource_path('image/single.png') load = PLI_Image.open(ipath) load = load.resize(tuple(map(lambda x: int(x * 0.7), load.size))) render = ImageTk.PhotoImage(load) img = Label(when_click_start, image=render) img.image = render img.pack() elif var == '乘客': title = Label(when_click_start) title['text'] = '\n【 乘客模式 】' title.pack() desc = Message(when_click_start) desc['text'] = '\n建议接受了司机的默认邀请,再点START\n' + \ '因为我不会在战斗里帮你点开始...不服憋着\n_(:3」∠)_\n' desc['width'] = 300 desc.pack() ipath = resource_path('image/passenger_accept.png') load = PLI_Image.open(ipath) load = load.resize(tuple(map(lambda x: int(x * 0.7), load.size))) render = ImageTk.PhotoImage(load) img = Label(when_click_start, image=render) img.image = render img.pack() elif var == '司机': title = Label(when_click_start) title['text'] = '\n【 司机模式 】' title.pack() desc = Message(when_click_start) desc['text'] = '\n建议对乘客发出默认邀请,回到组队界面再点START\n' + \ '因为自动发出邀请这个功能没写...不服憋着\n_(:3」∠)_\n' desc['width'] = 300 desc.pack() ipath = resource_path('image/driver_invite.png') load = PLI_Image.open(ipath) load = load.resize(tuple(map(lambda x: int(x * 0.5), load.size))) render = ImageTk.PhotoImage(load) img1 = Label(when_click_start, image=render) img1.image = render img1.pack() ipath = resource_path('image/driver_form.png') load = PLI_Image.open(ipath) load = load.resize(tuple(map(lambda x: int(x * 0.5), load.size))) render = ImageTk.PhotoImage(load) img2 = Label(when_click_start, image=render) img2.image = render img2.pack() init_window_position(when_click_start, 1.3, 3) def what_is_clear_time(self): what_is_clear = Toplevel(self) what_is_clear.title('平均通关时间说明') title = Label(what_is_clear) title['text'] = '\n【 平均通关时间 】' title.pack() desc = Message(what_is_clear) desc['text'] = '\n平均通关时间是指在游戏中,从按下开始战斗到进入结算奖励界面所经过的时间(秒)\n' + \ '\n程序会在经过指定的时间后,再开始检测游戏画面是否进入了结算界面\n' + \ '\n如果设置一个较短的时间也可以,不过设置一个合理的时间,能节省你CPU资源\n(其实也没占多少_(:3」∠)_\n' desc['width'] = 300 desc.pack() init_window_position(what_is_clear, 1.3, 3) def what_is_delay_time(self): what_is_delay = Toplevel(self) what_is_delay.title('战斗后等待时间说明') title = Label(what_is_delay) title['text'] = '\n【 战斗后等待时间 】' title.pack() desc = Message(what_is_delay) desc['text'] = '\n战斗后等待时间是指,在下一次战斗开始前强制等待的时间(秒)\n' + \ '\n填入的时间还会加上一个300毫秒以内的随机时间\n' desc['width'] = 300 desc.pack() init_window_position(what_is_delay, 1.3, 3) def create_main(self): """ 窗体、控件绘制 :return: """ self.label_mode['text'] = '模式' self.var_mode.set('单刷') self.listbox_mode['textvariable'] = self.var_mode self.listbox_mode['width'] = 10 self.listbox_mode['values'] = ["单刷", "乘客", "司机"] self.listbox_mode.bind("<<ComboboxSelected>>", self.turn_radio_on) self.label_mode.grid(row=1, column=0, sticky='E') self.listbox_mode.grid(row=1, column=1, sticky='W') self.button_mode_explain['text'] = '?' self.button_mode_explain['command'] = self.when_click_start_window self.button_mode_explain['relief'] = 'flat' self.button_mode_explain.grid(row=1, column=2, sticky='W') self.var_member.set(2) self.label_member['text'] = '车队人数' self.label_member.grid(row=2, column=0, sticky='E') self.radio1['text'] = '2人' self.radio1['variable'] = self.var_member self.radio1['value'] = 2 # self.radio1['command'] = self.test_val3 self.radio1.grid(row=2, column=1, sticky='W') self.radio1.configure(state='disabled') self.radio2['text'] = '3人' self.radio2['variable'] = self.var_member self.radio2['value'] = 3 # self.radio2['command'] = self.test_val3 self.radio2.grid(row=2, column=2, sticky='W') self.radio2.configure(state='disabled') self.label_clear_time['text'] = '平均通关时间' self.var_clear_time.set(self.clear_time) self.entry_clear_time['textvariable'] = self.var_clear_time self.label_clear_time.grid(row=3, column=0, sticky='E') self.entry_clear_time.grid(row=3, column=1, sticky='W', columnspan=2) self.button_clear_time_explain['text'] = '?' self.button_clear_time_explain['command'] = self.what_is_clear_time self.button_clear_time_explain['relief'] = 'flat' self.button_clear_time_explain.grid(row=3, column=2, sticky='E') self.label_delay_time['text'] = '战斗结束后等待时间' self.var_delay_time.set(self.delay_time) self.entry_delay_time['textvariable'] = self.var_delay_time self.label_delay_time.grid(row=4, column=0, sticky='E') self.entry_delay_time.grid(row=4, column=1, sticky='W', columnspan=2) self.button_delay_time_explain['text'] = '?' self.button_delay_time_explain['command'] = self.what_is_delay_time self.button_delay_time_explain['relief'] = 'flat' self.button_delay_time_explain.grid(row=4, column=2, sticky='E') self.label_offer['text'] = '好友发来悬赏' self.var_offer_mode.set('接受') self.listbox_offer_mode['textvariable'] = self.var_offer_mode self.listbox_offer_mode['width'] = 10 self.listbox_offer_mode['values'] = ["接受", "拒绝"] # self.listbox_offer_mode.bind("<<ComboboxSelected>>", self.turn_entry_on) self.label_offer.grid(row=5, column=0, sticky='E') self.listbox_offer_mode.grid(row=5, column=1, sticky='W') self.label_timing_mode['text'] = '预定结束' self.var_timing_mode.set('无') self.listbox_timing_mode['textvariable'] = self.var_timing_mode self.listbox_timing_mode['width'] = 10 self.listbox_timing_mode['values'] = [ "无", "定时[分钟]", "场数", "超鬼王模式1", "超鬼王模式2" ] self.listbox_timing_mode.bind("<<ComboboxSelected>>", self.turn_entry_on) self.label_timing_mode.grid(row=6, column=0, sticky='E') self.listbox_timing_mode.grid(row=6, column=1, sticky='W') self.var_timing_value.set('') self.entry_timing_value['textvariable'] = self.var_timing_value self.entry_timing_value['width'] = 5 self.entry_timing_value.configure(state='disabled') self.entry_timing_value.grid(row=6, column=2, sticky='W') self.label_done_action_mode['text'] = '预定结束后动作' self.var_done_action_mode.set('') self.listbox_done_action_mode[ 'textvariable'] = self.var_done_action_mode self.listbox_done_action_mode['width'] = 10 self.listbox_done_action_mode.configure(state='disabled') self.listbox_done_action_mode['values'] = ["关闭游戏窗口", "仅停止挂机"] # self.listbox_done_action_mode.bind("<<ComboboxSelected>>", self.turn_entry_on) self.label_done_action_mode.grid(row=7, column=0, sticky='E') self.listbox_done_action_mode.grid(row=7, column=1, sticky='W') self.start_ctn['text'] = 'START' self.start_ctn['width'] = 10 self.start_ctn['height'] = 2 self.start_ctn['command'] = self.fight_start self.start_ctn['relief'] = 'groove' self.start_ctn.grid(row=0, column=0, sticky='E') self.stop_ctn['text'] = 'STOP' self.stop_ctn['width'] = 10 self.stop_ctn['height'] = 2 self.stop_ctn['command'] = self.fight_stop self.stop_ctn['relief'] = 'groove' self.stop_ctn.grid(row=0, column=1, sticky='W') self.stop_ctn.configure(state='disabled') self.info_box['width'] = 40 self.info_box['height'] = 20 self.info_box.grid(row=1, column=0, columnspan=2) self.info_box.see(END) var = 'Build ' + self.version self.info_box.mark_set('insert', END) self.info_box.insert('insert', str(var) + '\n') self.info_box.see(END) var = '请授予此程序管理员权限运行,否则在游戏窗口内鼠标无法被控制' self.info_box.mark_set('insert', END) self.info_box.insert('insert', str(var) + '\n') self.info_box.see(END)