diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..c940161 --- /dev/null +++ b/.gitignore @@ -0,0 +1,14 @@ +.DS_Store +node_modules/ +dist/ +build/ +npm-debug.log +yarn-error.log + +# Editor directories and files +.idea +.vscode +*.suo +*.ntvs* +*.njsproj +*.sln \ No newline at end of file diff --git a/CHANGELOG.md b/CHANGELOG.md index 9bc2c9d..a689e43 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,18 @@ # CHANGELOG +## v1.0.1.0102 +#### New features: +* 增加了简单的自检逻辑。 +#### Fixes (bugs & defects): +* 根据[#28](https://github.com/AcademicDog/onmyoji_bot/issues/28),修复了探索的时候如果拉到场景图的最后,不会判断有没有经验怪的问题。 +* 修复了双开结束后不清除窗口信息的问题。 + +## v1.0.0.1129 +#### Fixes (bugs & defects): +* 调整了探索战斗的结算逻辑,现在不检查邮箱图标了,同时修复[#21](https://github.com/AcademicDog/onmyoji_bot/issues/21)、[#28](https://github.com/AcademicDog/onmyoji_bot/issues/28)。 +* 删除了冗余代码。 +* 根据[#24](https://github.com/AcademicDog/onmyoji_bot/issues/24),调整了结算点击范围。 + ## v1.0.0.1009 #### New features: * 增加了探索中“满级狗粮识别延迟”的设置选项。 diff --git a/README.md b/README.md index 3369d35..14b2c75 100644 --- a/README.md +++ b/README.md @@ -1,40 +1,124 @@ -# 欢迎 +copy URL to clipboard -[![GitHub release](https://img.shields.io/github/release/academicdog/onmyoji_bot)](https://github.com/AcademicDog/onmyoji_bot/releases) ![GitHub top language](https://img.shields.io/github/languages/top/academicdog/onmyoji_bot) ![GitHub code size in bytes](https://img.shields.io/github/languages/code-size/academicdog/onmyoji_bot) ![GitHub repo size](https://img.shields.io/github/repo-size/academicdog/onmyoji_bot) ![GitHub](https://img.shields.io/github/license/academicdog/onmyoji_bot) ![platforms](https://img.shields.io/badge/platform-win32|win64-brightgreen.svg) [![GitHub issues](https://img.shields.io/github/issues/academicdog/onmyoji_bot.svg)](https://github.com/academicdog/onmyoji_bot/issues) [![GitHub closed issues](https://img.shields.io/github/issues-closed/academicdog/onmyoji_bot.svg)](https://github.com/academicdog/onmyoji_bot/issues?q=is:issue+is:closed) ![GitHub commit activity](https://img.shields.io/github/commit-activity/m/academicdog/onmyoji_bot) ![GitHub contributors](https://img.shields.io/github/contributors/academicdog/onmyoji_bot.svg) +本项目fork至 [https://github.com/AcademicDog/onmyoji_bot/](https://github.com/AcademicDog/onmyoji_bot/) 并做出了以下修改: -copy URL to clipboard +* 新增打包相关配置 +* 新增虚拟环境的兼容 +* 功能新增 + + +### 特性 + +- 御魂 + - 单人御魂 + - 作为司机组队御魂,自动邀请 + - 作为乘客组队御魂,自动接受邀请 + - 双开御魂 +- 业原火 + - 自动刷贪、嗔、痴卷 +- 御灵 + - 自动刷御灵 +- 探索 + - 完成探索,识别经验怪,支持自动换狗粮 +- 其他 + - 在战斗过程中,该脚本会自动拒绝所有悬赏封印的邀请。 + - 如果60s程序没有任何操作(卡机、体力空等),视为体力用光,为了保护加成,自动关闭YYS。 + - 该脚本仅使用了画面找色,鼠标后台点击的函数,完全模拟人类玩家行为,没有使用任何内存读写函数。在敏感位置添加了均匀分布的随机时间漂移,和随机坐标漂移。**但仍然可能存在使用风险**。 + +### 使用环境 + +> 阴阳师PC版客户端,默认分辨率(1136x640) +> +> Windows 10和Windows 7,屏幕(1920x1080),显示设置100% +> +> 如需运行源码,需要Python3 32位 +* * * + +# 使用方法 + +### 单人刷御魂/业原火/御灵 + +1. 打开本工具,切换至御魂选项卡; + +1. 游戏中进入御魂/业原火/御灵主界面(就是有“挑战”按钮的页面),请提前备好式神并**锁定阵容**; + +1. 点击本工具的“开始”按钮。 + +### 组队刷御魂 + +1. 打开本工具,切换至御魂选项卡,根据自身情况选择“单人司机”或者“单人乘客”; -本工具用于阴阳师代肝,为各位阴阳师大佬养老护肝所用。 +1. 游戏中进入组队页面,请提前备好式神并**锁定阵容**; -目前已开通项目网站,请访问🌍[此地址](https://academicdog.github.io/onmyoji_bot/)获取最新信息。 +1. 点击本工具的“开始”按钮。 -# 特别感谢 +### 单人探索 -特别感谢society765在本项目中给与的启发,本项目在其[工作基础](https://github.com/society765/yys-auto-yuhun)上修改完成。 +1. 打开本工具,切换至探索选项卡; -同时感谢sup817ch的图像识别思路,本项目game_ctl模块基于其[工作基础](https://github.com/sup817ch/AutoOnmyoji)。 +1. 在游戏种提前将狗粮队长放在阴阳师中间,并且**取消锁定阵容**; + +1. 游戏中点开需要探索的章节(就是有“探索”按钮的页面); + +1. 点击本工具的“开始”按钮。 + +* * * # 注意事项 -环境:python 3.7, 32 bit;yys PC端 默认分辨率 (1136x640);win 10系统,屏幕(1920x1080),显示设置100%。 +1. 要求使用Windows 10或Windows 7,屏幕(1920x1080),显示设置100%”。 + +1. 当使用 Windows 7 系统时,需要调整系统的画面设置:把主题调为最丑最挫的那个。在 Windows 10 系统中,不需要调整系统画面设置。 + +1. 需要关闭电脑的自动息屏/休眠。 1. 窗口现在可以完全后台,可以被遮挡,但是**不能最小化**。 1. 不要开启游戏中的“模型描边”。 -1. 当使用 Windows 7 系统时,需要调整系统的画面设置:把主题调为最丑最挫的那个。在 Windows 10 系统中,不需要调整系统画面设置。 +1. 不要移动游戏窗口。 1. 当使用高分辨率屏幕时,在阴阳师客户端程序兼容性选项里,不要勾选“替代高DPI缩放行为”,这个选项应该是默认不勾选的。 -1. 如果不想安装运行环境,可以访问下载最新已[编译](https://github.com/AcademicDog/onmyoji_bot/releases)版本,该版本有图形界面,同时注意.exe文件和/img文件夹应该放在同一目录后再运行。 +1. exe文件可能被杀毒软件隔离,若被隔离需自行恢复并添加到信任区 + +1. 命令行模式下运行脚本时不要左键点击命令行以免选中文本,这可能导致进程暂停引起其他问题,如不小心暂停,按空格才能继续脚本。(也可以在窗口属性面板处关闭命令行窗口的快速编辑模式,以避免不小心中断) + +1. 需要锁定阵容。 + +1. 刷御魂,房主需要在房间内开启脚本,乘客在房间内或战斗中开启均可。 + +1. 中途有事暂停记得关闭脚本,因为操作超时脚本会把游戏关闭。 + +1. 不建议使用刷探索,目前经验怪的识别成功度不高。N卡满级自动换N卡时是会拖动N卡40%进度条再拖放,所以用户需要关闭式神折叠。刷2星1级白蛋则需要开启式神折叠。刷高级白蛋目前有bug,自动换素材有问题。 + +1. 探索换狗粮的时候,如果是关闭了滚动换卡,换上第一个N卡,因此注意**不要**对N卡点击“喜欢”,导致反复换上一个满级的狗粮。 -1. 探索换狗粮的时候,默认是换上第一个N卡,因此注意**不要**对N卡点击“喜欢”,导致反复换上一个满级的狗粮。 +1. 标记式神功能会标记左边第二位式神,需要关闭式神技能动画特写 -# 更新说明 -更新日志请点击[这里](https://github.com/AcademicDog/onmyoji_bot/blob/master/CHANGELOG.md) +1. 如果不想安装运行环境,可以访问releases下载最新已[编译]版本,该版本有图形界面,同时注意.exe文件和/img文件夹应该放在同一目录后再运行。 -# 协议 (License) +# 运行未编译脚本 +安装python3.7.0 +安装依赖 +~~~ +pip install -r requirements.txt +~~~ +运行run.bat(若有使用虚拟环境,编辑runInVirtualEnv.bat内的虚拟环境路径,再运行bat) -该源代码使用了 [GPLv3](https://www.gnu.org/licenses/gpl-3.0.html) 开源协议。 +# 打包说明 +安装pyinstaller,若有使用虚拟环境,需要在虚拟环境中安装再打包 +~~~ +pip install pyinstaller +~~~ +打包exe +~~~ +pyinstaller -F -w ui.py +~~~ +或 +~~~ +pyinstaller -F omj.py +~~~ -This project is licensed under the [GPLv3](https://www.gnu.org/licenses/gpl-3.0.html) license. \ No newline at end of file +注意,有个坑!!! +> exe打包过程若无报错,但是打包出的exe打不开(例如报错:文件所在的卷已被更改,打开的文件不再有效),可以关闭杀毒软件再打包 \ No newline at end of file diff --git a/Ui_onmyoji.py b/Ui_onmyoji.py index e602d54..5507c1a 100644 --- a/Ui_onmyoji.py +++ b/Ui_onmyoji.py @@ -1,6 +1,6 @@ # -*- coding: utf-8 -*- -# Form implementation generated from reading ui file 'd:\软件\github\onmyoji_bot\onmyoji.ui' +# Form implementation generated from reading ui file 'd:\软件\github\onmyoji_bot\omj.ui' # # Created by: PyQt5 UI code generator 5.9.2 # @@ -70,24 +70,42 @@ def setupUi(self, MainWindow): self.tab.setObjectName("tab") self.gridLayout_2 = QtWidgets.QGridLayout(self.tab) self.gridLayout_2.setObjectName("gridLayout_2") + self.groupBox_4 = QtWidgets.QGroupBox(self.tab) + self.groupBox_4.setObjectName("groupBox_4") + self.gridLayout_9 = QtWidgets.QGridLayout(self.groupBox_4) + self.gridLayout_9.setObjectName("gridLayout_9") + self.radioButton_1 = QtWidgets.QRadioButton(self.groupBox_4) + self.radioButton_1.setChecked(True) + self.radioButton_1.setObjectName("radioButton_1") + self.gridLayout_9.addWidget(self.radioButton_1, 0, 0, 1, 1) + self.radioButton_3 = QtWidgets.QRadioButton(self.groupBox_4) + self.radioButton_3.setObjectName("radioButton_3") + self.gridLayout_9.addWidget(self.radioButton_3, 1, 0, 1, 2) + self.radioButton_4 = QtWidgets.QRadioButton(self.groupBox_4) + self.radioButton_4.setObjectName("radioButton_4") + self.gridLayout_9.addWidget(self.radioButton_4, 1, 2, 1, 1) + self.radioButton_2 = QtWidgets.QRadioButton(self.groupBox_4) + self.radioButton_2.setObjectName("radioButton_2") + self.gridLayout_9.addWidget(self.radioButton_2, 0, 2, 1, 1) + self.gridLayout_2.addWidget(self.groupBox_4, 1, 0, 1, 1) self.groupBox = QtWidgets.QGroupBox(self.tab) self.groupBox.setObjectName("groupBox") self.gridLayout = QtWidgets.QGridLayout(self.groupBox) self.gridLayout.setObjectName("gridLayout") - self.mitama_passenger = QtWidgets.QRadioButton(self.groupBox) - self.mitama_passenger.setObjectName("mitama_passenger") - self.gridLayout.addWidget(self.mitama_passenger, 0, 2, 1, 1) - self.mitama_driver = QtWidgets.QRadioButton(self.groupBox) - self.mitama_driver.setObjectName("mitama_driver") - self.gridLayout.addWidget(self.mitama_driver, 0, 1, 1, 1) self.mitama_single = QtWidgets.QRadioButton(self.groupBox) self.mitama_single.setAutoFillBackground(False) self.mitama_single.setChecked(True) self.mitama_single.setObjectName("mitama_single") self.gridLayout.addWidget(self.mitama_single, 0, 0, 1, 1) + self.mitama_driver = QtWidgets.QRadioButton(self.groupBox) + self.mitama_driver.setObjectName("mitama_driver") + self.gridLayout.addWidget(self.mitama_driver, 0, 1, 1, 1) + self.mitama_passenger = QtWidgets.QRadioButton(self.groupBox) + self.mitama_passenger.setObjectName("mitama_passenger") + self.gridLayout.addWidget(self.mitama_passenger, 1, 0, 1, 1) self.mitama_dual = QtWidgets.QRadioButton(self.groupBox) self.mitama_dual.setObjectName("mitama_dual") - self.gridLayout.addWidget(self.mitama_dual, 1, 0, 1, 1) + self.gridLayout.addWidget(self.mitama_dual, 1, 1, 1, 1) self.gridLayout_2.addWidget(self.groupBox, 0, 0, 1, 1) self.tabWidget.addTab(self.tab, "") self.tab_2 = QtWidgets.QWidget() @@ -157,16 +175,16 @@ def setupUi(self, MainWindow): self.groupBox_2.setObjectName("groupBox_2") self.gridLayout_7 = QtWidgets.QGridLayout(self.groupBox_2) self.gridLayout_7.setObjectName("gridLayout_7") - self.checkBox = QtWidgets.QCheckBox(self.groupBox_2) - self.checkBox.setChecked(True) - self.checkBox.setObjectName("checkBox") - self.gridLayout_7.addWidget(self.checkBox, 0, 0, 1, 1) self.label_2 = QtWidgets.QLabel(self.groupBox_2) self.label_2.setObjectName("label_2") - self.gridLayout_7.addWidget(self.label_2, 2, 0, 1, 1) + self.gridLayout_7.addWidget(self.label_2, 3, 0, 1, 1) self.label_3 = QtWidgets.QLabel(self.groupBox_2) self.label_3.setObjectName("label_3") - self.gridLayout_7.addWidget(self.label_3, 3, 0, 1, 1) + self.gridLayout_7.addWidget(self.label_3, 4, 0, 1, 1) + self.checkBox = QtWidgets.QCheckBox(self.groupBox_2) + self.checkBox.setChecked(True) + self.checkBox.setObjectName("checkBox") + self.gridLayout_7.addWidget(self.checkBox, 1, 0, 1, 1) self.lineEdit = QtWidgets.QLineEdit(self.groupBox_2) sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Preferred, QtWidgets.QSizePolicy.Preferred) sizePolicy.setHorizontalStretch(0) @@ -176,12 +194,15 @@ def setupUi(self, MainWindow): self.lineEdit.setMaximumSize(QtCore.QSize(16777215, 20)) self.lineEdit.setAlignment(QtCore.Qt.AlignRight|QtCore.Qt.AlignTrailing|QtCore.Qt.AlignVCenter) self.lineEdit.setObjectName("lineEdit") - self.gridLayout_7.addWidget(self.lineEdit, 2, 1, 1, 1) + self.gridLayout_7.addWidget(self.lineEdit, 3, 1, 1, 1) self.lineEdit_2 = QtWidgets.QLineEdit(self.groupBox_2) self.lineEdit_2.setMaximumSize(QtCore.QSize(16777215, 20)) self.lineEdit_2.setAlignment(QtCore.Qt.AlignRight|QtCore.Qt.AlignTrailing|QtCore.Qt.AlignVCenter) self.lineEdit_2.setObjectName("lineEdit_2") - self.gridLayout_7.addWidget(self.lineEdit_2, 3, 1, 1, 1) + self.gridLayout_7.addWidget(self.lineEdit_2, 4, 1, 1, 1) + self.checkBox_4 = QtWidgets.QCheckBox(self.groupBox_2) + self.checkBox_4.setObjectName("checkBox_4") + self.gridLayout_7.addWidget(self.checkBox_4, 0, 0, 1, 1) self.verticalLayout.addWidget(self.groupBox_2) self.gridLayout_3.addLayout(self.verticalLayout, 1, 0, 1, 1) self.line_2 = QtWidgets.QFrame(self.frame) @@ -223,10 +244,15 @@ def retranslateUi(self, MainWindow): self.start_btn.setText(_translate("MainWindow", "开始")) self.pushButton.setText(_translate("MainWindow", "结束")) self.label.setText(_translate("MainWindow", "辅助助手")) + self.groupBox_4.setTitle(_translate("MainWindow", "副本(调试中)")) + self.radioButton_1.setText(_translate("MainWindow", "八岐大蛇")) + self.radioButton_3.setText(_translate("MainWindow", "卑弥呼")) + self.radioButton_4.setText(_translate("MainWindow", "御灵")) + self.radioButton_2.setText(_translate("MainWindow", "业原火")) self.groupBox.setTitle(_translate("MainWindow", "模式")) - self.mitama_passenger.setText(_translate("MainWindow", "单人乘客")) - self.mitama_driver.setText(_translate("MainWindow", "单人司机")) self.mitama_single.setText(_translate("MainWindow", "单刷")) + self.mitama_driver.setText(_translate("MainWindow", "单人司机")) + self.mitama_passenger.setText(_translate("MainWindow", "单人乘客")) self.mitama_dual.setText(_translate("MainWindow", "双开")) self.tabWidget.setTabText(self.tabWidget.indexOf(self.tab), _translate("MainWindow", "御魂/御灵")) self.groupBox_3.setTitle(_translate("MainWindow", "延迟设置")) @@ -234,7 +260,7 @@ def retranslateUi(self, MainWindow): self.label_5.setText(_translate("MainWindow", "满级狗粮识别延迟(秒):")) self.checkBox_3.setText(_translate("MainWindow", "换狗粮拖放式神进度条,进度:")) self.checkBox_2.setText(_translate("MainWindow", "结束后打BOSS")) - self.plainTextEdit_2.setPlainText(_translate("MainWindow", "把狗粮队长放在最左边,点开需要打的章节,然后开始。\n" + self.plainTextEdit_2.setPlainText(_translate("MainWindow", "把狗粮队长放在中间,点开需要打的章节,然后开始。\n" "\n" "支持自动换狗粮,只打经验怪。\n" "\n" @@ -245,13 +271,13 @@ def retranslateUi(self, MainWindow): "交流Q群:592055060")) self.tabWidget.setTabText(self.tabWidget.indexOf(self.tab_3), _translate("MainWindow", "关于")) self.groupBox_2.setTitle(_translate("MainWindow", "高级选项")) - self.checkBox.setText(_translate("MainWindow", "超时自动关闭阴阳师")) self.label_2.setText(_translate("MainWindow", " 画面超时时间(秒):")) self.label_3.setText(_translate("MainWindow", " 操作超时时间(秒):")) + self.checkBox.setText(_translate("MainWindow", "超时自动关闭阴阳师")) self.lineEdit.setText(_translate("MainWindow", "100")) self.lineEdit_2.setText(_translate("MainWindow", "20")) + self.checkBox_4.setText(_translate("MainWindow", "调试模式")) self.menu.setTitle(_translate("MainWindow", "帮助")) self.actionFile.setText(_translate("MainWindow", "File")) self.actionAbout_2.setText(_translate("MainWindow", "About")) - self.actionAbout.setText(_translate("MainWindow", "About")) - +self.actionAbout.setText(_translate("MainWindow", "About")) \ No newline at end of file diff --git a/conf.ini b/conf.ini new file mode 100644 index 0000000..e24dc1e --- /dev/null +++ b/conf.ini @@ -0,0 +1,19 @@ +[common] +sign_shikigami = False + +[watchdog] +watchdog_enable = True +max_win_time = 100 +max_win_time_yuling = 180 +max_win_time_yeyuanhuo = 240 +max_op_time = 42 + +[explore] +fight_boss_enable = True +slide_shikigami = True +slide_shikigami_progress = 40 +shikigami_type = 1 +zhunbei_delay = 42 + +[others] +debug_enable = True diff --git a/explore/driver_explore.py b/explore/driver_explore.py new file mode 100644 index 0000000..64a5ebd --- /dev/null +++ b/explore/driver_explore.py @@ -0,0 +1,53 @@ +from explore.explore import ExploreFight +from tools.game_pos import CommonPos, TansuoPos +import tools.utilities as ut + +import configparser +import logging +import random +import time + + +class DriverExploreFight(ExploreFight): + def __init__(self): + # 初始化 + ExploreFight.__init__(self) + self.mode = 2 + + def start(self): + '''司机探索主循环''' + mood1 = ut.Mood(2) + mood2 = ut.Mood(2) + while self.run: + # 进入探索内 + self.log.writeinfo('开始本轮探索') + + # 开始打怪 + i = 0 + while self.run: + if i >= 4: + break + result = self.fight_moster(mood1, mood2) + if result == 1: + continue + elif result == 2: + break + else: + self.log.writeinfo('移动至下一个场景') + self.next_scene() + i += 1 + + # 退出探索 + if result == 2: + self.click_box() + else: + self.switch_to_scene(3) + + self.log.writeinfo('结束本轮探索') + time.sleep(0.5) + + # 邀请好友 + if self.yys.wait_game_img('img\\YAO-QING.png', self.max_op_time): + # 点击确认 + self.click_until('确认按钮', 'img\\YAO-QING.png', + *TansuoPos.confirm_btn, 2, False) \ No newline at end of file diff --git a/explore/explore.py b/explore/explore.py index 9e4c852..7f6bd54 100644 --- a/explore/explore.py +++ b/explore/explore.py @@ -19,7 +19,10 @@ def __init__(self): self.fight_boss_enable = conf.getboolean('explore', 'fight_boss_enable') self.slide_shikigami = conf.getboolean('explore', 'slide_shikigami') self.slide_shikigami_progress = conf.getint('explore', 'slide_shikigami_progress') - self.zhunbei_delay = conf.getint('explore', 'zhunbei_delay') + self.shikigami_type = conf.getboolean('explore', 'shikigami_type') + self.zhunbei_delay = conf.getfloat('explore', 'zhunbei_delay') + + self.fight_count = 0 def next_scene(self): ''' @@ -35,11 +38,11 @@ def check_exp_full(self): ''' 检查狗粮经验,并自动换狗粮 ''' - # 狗粮经验判断, gouliang1是中间狗粮,gouliang2是右边狗粮 + # 狗粮经验判断, gouliang1是左边狗粮,gouliang2是右边狗粮 gouliang1 = self.yys.find_game_img( - 'img\\MAN1.png', 1, *TansuoPos.gouliang_middle, 1) + 'img\\MAN0.png', 1, *TansuoPos.gouliang_man_left, 1) gouliang2 = self.yys.find_game_img( - 'img\\MAN2.png', 1, *TansuoPos.gouliang_right, 1) + 'img\\MAN2.png', 1, *TansuoPos.gouliang_man_right, 1) # print(gouliang1) # print(gouliang2) @@ -60,30 +63,109 @@ def check_exp_full(self): self.yys.mouse_click_bg(*TansuoPos.quanbu_btn) time.sleep(1) - # 点击“N”卡 - self.yys.mouse_click_bg(*TansuoPos.n_tab_btn) + # 点击“N”卡或“素材” + if self.shikigami_type == 1: + self.yys.mouse_click_bg(*TansuoPos.n_tab_btn) + else: + self.yys.mouse_click_bg(*TansuoPos.sucai_tab_btn) time.sleep(1) - # 拖放进度条 - if self.slide_shikigami: - # 读取坐标范围 - star_x = TansuoPos.n_slide[0][0] - end_x = TansuoPos.n_slide[1][0] - length = end_x - star_x - - # 计算拖放范围 - pos_end_x = int(star_x + length/100*self.slide_shikigami_progress) - pos_end_y = TansuoPos.n_slide[0][1] + self.change_shikigami(gouliang1,gouliang2) - self.yys.mouse_drag_bg( - TansuoPos.n_slide[0], (pos_end_x, pos_end_y)) + def change_shikigami(self,gouliang1,gouliang2): + ''' + 变更式神 + ''' + if self.shikigami_type == 0: + return - # 更换狗粮 - 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)) + # 换n卡 + elif self.shikigami_type == 1: + # 拖放进度条 + if self.slide_shikigami: + # 读取坐标范围 + star_x = TansuoPos.n_slide[0][0] + end_x = TansuoPos.n_slide[1][0] + length = end_x - star_x + + # 计算拖放范围 + pos_end_x = int(star_x + length/100*self.slide_shikigami_progress) + pos_end_y = TansuoPos.n_slide[0][1] + + self.yys.mouse_drag_bg( + TansuoPos.n_slide[0], (pos_end_x, pos_end_y)) + + # 更换狗粮 + if gouliang1: + if self.mode == 0: + pos = TansuoPos.gouliang_left + if self.mode == 2: + pos = TansuoPos.gouliang_driver_left + if self.mode == 3: + pos = TansuoPos.gouliang_passenger_left + self.yys.mouse_drag_bg(*pos) + if gouliang2: + time.sleep(1) + if self.mode == 0: + pos = TansuoPos.gouliang_right + if self.mode == 2: + pos = TansuoPos.gouliang_driver_right + if self.mode == 3: + pos = TansuoPos.gouliang_passenger_right + self.yys.mouse_drag_bg(*pos) + + # 换2星1级白蛋 + elif self.shikigami_type == 2: + if gouliang1: + if self.mode == 0: + pos2 = TansuoPos.gouliang_target_left + if self.mode == 2: + pos2 = TansuoPos.gouliang_target_left + if self.mode == 3: + pos2 = TansuoPos.gouliang_target_left + self.yys.mouse_drag_bg(TansuoPos.gouliang_sucai_0,pos2) + if gouliang2: + time.sleep(1) + if gouliang1: + self.yys.mouse_drag_bg(TansuoPos.gouliang_sucai_0,(TansuoPos.gouliang_sucai_0[0]+3,TansuoPos.gouliang_sucai_0[1]+3)) + time.sleep(0.7) + if self.mode == 0: + pos2 = TansuoPos.gouliang_target_right + if self.mode == 2: + pos2 = TansuoPos.gouliang_target_right + if self.mode == 3: + pos2 = TansuoPos.gouliang_target_right + self.yys.mouse_drag_bg(TansuoPos.gouliang_sucai_0,pos2) + + # 换高级白蛋 + elif self.shikigami_type == 3: + if gouliang1: + if gouliang2: + pos1 = TansuoPos.gouliang_sucai_1 + else: + pos1 = TansuoPos.gouliang_sucai_2 + if self.mode == 0: + pos2 = TansuoPos.gouliang_target_left + if self.mode == 2: + pos2 = TansuoPos.gouliang_target_left + if self.mode == 3: + pos2 = TansuoPos.gouliang_target_left + self.yys.mouse_drag_bg(pos1,pos2) + if gouliang2: + time.sleep(1) + if gouliang1: + pos1 = TansuoPos.gouliang_sucai_2 + self.yys.mouse_drag_bg(TansuoPos.gouliang_sucai_0,(pos1[0]+3,pos1[1]+3)) + time.sleep(0.7) + else: + pos1 = TansuoPos.gouliang_sucai_1 + if self.mode == 0: + pos2 = TansuoPos.gouliang_target_right + if self.mode == 2: + pos2 = TansuoPos.gouliang_target_right + if self.mode == 3: + pos2 = TansuoPos.gouliang_target_right + self.yys.mouse_drag_bg(pos1,pos2) def find_exp_moster(self): ''' @@ -92,10 +174,20 @@ def find_exp_moster(self): ''' # 查找经验图标 exp_pos = self.yys.find_color( - ((2, 205), (1127, 545)), (140, 122, 44), 2) + ((2, 115), (1127, 545)), (140, 122, 44), 4) + if exp_pos == -1: + exp_pos = self.yys.find_color( + ((2, 115), (1127, 545)), (52, 23, 10), 4) + if exp_pos == -1: + exp_pos = self.yys.find_color( + ((2, 115), (1127, 545)), (44, 18, 9), 4) + if exp_pos == -1: + exp_pos = self.yys.find_color( + ((2, 115), (1127, 545)), (140, 76, 40), 4) if exp_pos == -1: return -1 + # 查找经验怪攻打图标位置 find_pos = self.yys.find_game_img( 'img\\FIGHT.png', 1, (exp_pos[0]-150, exp_pos[1]-250), (exp_pos[0]+150, exp_pos[1]-50)) @@ -107,6 +199,21 @@ def find_exp_moster(self): (find_pos[1]+exp_pos[1]-250)) return fight_pos + def find_moster(self): + ''' + 寻找普通怪 + :return: 成功返回攻打图标位置;失败返回-1 + ''' + # 查找攻打图标位置 + find_pos = self.yys.find_game_img( + 'img\\FIGHT.png', 1, (2, 115), (1127, 545)) + if not find_pos: + return -1 + + # 返回攻打图标位置 + fight_pos = ((find_pos[0]+2), (find_pos[1]++115)) + return fight_pos + def find_boss(self): ''' 寻找BOSS @@ -114,12 +221,12 @@ def find_boss(self): ''' # 查找BOSS攻打图标位置 find_pos = self.yys.find_game_img( - 'img\\BOSS.png', 1, (2, 205), (1127, 545)) + 'img\\BOSS.png', 1, (2, 115), (1127, 545)) if not find_pos: return -1 # 返回BOSS攻打图标位置 - fight_pos = ((find_pos[0]+2), (find_pos[1]+205)) + fight_pos = ((find_pos[0]+2), (find_pos[1]+115)) return fight_pos def fight_moster(self, mood1, mood2): @@ -133,37 +240,46 @@ def fight_moster(self, mood1, mood2): self.yys.wait_game_img('img\\YING-BING.png') self.log.writeinfo('进入探索页面') - # 寻找经验怪,未找到则寻找boss,再未找到则退出 - fight_pos = self.find_exp_moster() + # 寻找普通或经验怪,未找到则寻找boss,再未找到则退出 + if self.only_fight_exp: + fight_pos = self.find_exp_moster() + else: + fight_pos = self.find_moster() boss = False if fight_pos == -1: if self.fight_boss_enable: fight_pos = self.find_boss() boss = True if fight_pos == -1: - self.log.writeinfo('未找到经验怪和boss') + self.log.writeinfo('未找到你想刷的怪和boss') return -2 else: - self.log.writeinfo('未找到经验怪') + self.log.writeinfo('未找到你想刷的怪') return -1 # 攻击怪 + self.log.writeinfo('click') self.yys.mouse_click_bg(fight_pos) - if not self.yys.wait_game_img('img\\ZHUN-BEI.png', self.zhunbei_delay, False): - break + self.log.writeinfo(fight_pos) + if self.shikigami_type != 0: + if not self.yys.wait_game_img('img\\ZHUN-BEI.png', self.zhunbei_delay, False): + break + else: + if not self.yys.wait_game_img('img\\ZI-DONG.png', self.zhunbei_delay, False): + break self.log.writeinfo('已进入战斗') time.sleep(1) # 等待式神准备 - self.yys.wait_game_color(((1024,524),(1044, 544)), (138,198,233), 30) + # self.yys.wait_game_color(((1024,524),(1044, 544)), (138,198,233), 30) logging.info('式神准备完成') # 检查狗粮经验 - self.check_exp_full() - - # 点击准备,直到进入战斗 - self.click_until('准备按钮', 'img\\ZI-DONG.png', * - TansuoPos.ready_btn, mood1.get1mood()/1000) + if self.shikigami_type != 0: + self.check_exp_full() + # 点击准备,直到进入战斗 + self.click_until('准备按钮', 'img\\ZI-DONG.png', * + TansuoPos.ready_btn, mood1.get1mood()/1000) # 检查是否打完 self.check_end() @@ -171,8 +287,19 @@ def fight_moster(self, mood1, mood2): # 在战斗结算页面 self.yys.mouse_click_bg(ut.firstposition()) - self.click_until('结算', 'img\\MESSAGE.png', + self.click_until('结算', 'img\\JIN-BI.png', *CommonPos.second_position, mood2.get1mood()/1000) + self.click_until('结算', 'img\\JIN-BI.png', + *CommonPos.second_position, mood2.get1mood()/1000, False) + + self.fight_count = self.fight_count + 1 + if self.fight_count>=self.shikigami_brush_max: + if self.shikigami_brush_max_quit: + self.yys.activate_window() + time.sleep(5) + self.yys.quit_game() + else: + self.deactivate() # 返回结果 if boss: @@ -180,28 +307,20 @@ def fight_moster(self, mood1, mood2): else: return 1 - def start(self): - '''单人探索主循环''' - mood1 = ut.Mood(2) - mood2 = ut.Mood(3) - while self.run: - # 进入探索内 - self.switch_to_scene(4) - - # 开始打怪 - i = 0 - while i < 4 and self.run: - result = self.fight_moster(mood1, mood2) - if result == 1: - continue - elif result == 2: - break - else: - self.log.writeinfo('移动至下一个场景') - self.next_scene() - i += 1 - - # 退出探索 - self.switch_to_scene(3) - self.log.writeinfo('结束本轮探索') - time.sleep(0.5) + def click_box(self): + ''' + 点击宝箱 + ''' + time.sleep(1) + start_time = time.time() + while True: + scene_now = self.get_scene() + if scene_now != 4 or ( time.time() - start_time > 10000): + break + pos = self.yys.find_game_img('img\\BAO-WU.png') + if pos: + self.log.writeinfo('点击打开宝物') + self.yys.mouse_click_bg(pos) + time.sleep(0.5) + self.yys.mouse_click_bg(*CommonPos.second_position) + time.sleep(0.5) \ No newline at end of file diff --git a/explore/passenger_explore.py b/explore/passenger_explore.py new file mode 100644 index 0000000..55abf5b --- /dev/null +++ b/explore/passenger_explore.py @@ -0,0 +1,69 @@ +from explore.explore import ExploreFight +from tools.game_pos import CommonPos, TansuoPos +import tools.utilities as ut + +import configparser +import logging +import random +import time + + +class PassengerExploreFight(ExploreFight): + def __init__(self): + # 初始化 + ExploreFight.__init__(self) + self.mode = 3 + + def start(self): + '''乘客探索主循环''' + mood1 = ut.Mood(2) + mood2 = ut.Mood(2) + while self.run: + # 进入探索内 + self.log.writeinfo('开始本轮探索') + + while True: + + if self.yys.find_game_img('img\\ZHUN-BEI.png'): + self.log.writeinfo('已进入战斗') + time.sleep(1) + + # 等待式神准备 + # self.yys.wait_game_color(((1024,524),(1044, 544)), (138,198,233), 30) + logging.info('式神准备完成') + + # 检查狗粮经验 + self.check_exp_full() + + # 点击准备,直到进入战斗 + self.click_until('准备按钮', 'img\\ZI-DONG.png', * + TansuoPos.ready_btn, mood1.get1mood()/1000) + + # 检查是否打完 + self.check_end() + mood1.moodsleep() + + # 在战斗结算页面 + self.yys.mouse_click_bg(ut.firstposition()) + self.click_until('结算', 'img\\JIN-BI.png', + *CommonPos.second_position, mood2.get1mood()/1000) + self.click_until('结算', 'img\\JIN-BI.png', + *CommonPos.second_position, mood2.get1mood()/1000, False) + + + + + # 退出探索 + if result == 2: + self.click_box() + else: + self.switch_to_scene(3) + + self.log.writeinfo('结束本轮探索') + time.sleep(0.5) + + # 邀请好友 + if self.yys.wait_game_img('img\\YAO-QING.png', self.max_op_time): + # 点击确认 + self.click_until('确认按钮', 'img\\YAO-QING.png', + *TansuoPos.confirm_btn, 2, False) \ No newline at end of file diff --git a/explore/single_explore.py b/explore/single_explore.py new file mode 100644 index 0000000..5849211 --- /dev/null +++ b/explore/single_explore.py @@ -0,0 +1,48 @@ +from explore.explore import ExploreFight +from tools.game_pos import CommonPos, TansuoPos +import tools.utilities as ut + +import configparser +import logging +import random +import time + + +class SingleExploreFight(ExploreFight): + def __init__(self): + # 初始化 + ExploreFight.__init__(self) + self.mode = 0 + + def start(self): + '''单人探索主循环''' + mood1 = ut.Mood(1) + mood2 = ut.Mood(2) + while self.run: + # 进入探索内 + self.switch_to_scene(4) + + # 开始打怪 + i = 0 + while self.run: + if i >= 4: + break + result = self.fight_moster(mood1, mood2) + if result == 1: + continue + elif result == 2: + break + else: + self.log.writeinfo('移动至下一个场景') + self.next_scene() + i += 1 + + # 退出探索 + if self.run: + if result == 2: + self.click_box() + else: + self.switch_to_scene(3) + + self.log.writeinfo('结束本轮探索') + time.sleep(0.5) \ No newline at end of file diff --git a/gameLib/fighter.py b/gameLib/fighter.py index f93ad6a..28b3d5a 100644 --- a/gameLib/fighter.py +++ b/gameLib/fighter.py @@ -1,13 +1,17 @@ from gameLib.game_ctl import GameControl from tools.logsystem import WriteLog -from tools.game_pos import TansuoPos +from tools.game_pos import TansuoPos, CommonPos +import os import configparser import logging import random import time import win32gui +import threading +import tools.utilities as ut +confPath = os.path.join(os.getcwd(), "conf.ini") #拼接上配置文件名称目录 class Fighter: @@ -23,12 +27,17 @@ def __init__(self, name='', emyc=0, hwnd=0): self.name = name self.run = True + self.fight_type = 'default' + # 读取配置文件 conf = configparser.ConfigParser() - conf.read('conf.ini') + conf.read(confPath) quit_game_enable = conf.getboolean('watchdog', 'watchdog_enable') self.max_op_time = conf.getint('watchdog', 'max_op_time') self.max_win_time = conf.getint('watchdog', 'max_win_time') + self.max_win_time_yeyuanhuo = conf.getint('watchdog', 'max_win_time_yeyuanhuo') + self.max_win_time_yuling = conf.getint('watchdog', 'max_win_time_yuling') + self.sign_shikigami = conf.getboolean('common', 'sign_shikigami') # 启动日志 self.log = WriteLog() @@ -45,6 +54,12 @@ def __init__(self, name='', emyc=0, hwnd=0): self.log.writeinfo(self.name + '激活窗口成功') time.sleep(0.5) + # 自检 + debug_enable = conf.getboolean('others', 'debug_enable') + if debug_enable: + task = threading.Thread(target=self.yys.debug) + task.start() + def check_battle(self): # 检测是否进入战斗 self.log.writeinfo(self.name + '检测是否进入战斗') @@ -54,14 +69,30 @@ def check_battle(self): def check_end(self): # 检测是否打完 self.log.writeinfo(self.name + '检测是战斗是否结束') - self.yys.wait_game_img('img\\JIE-SU.png', self.max_win_time) + if self.fight_type == 'yuling': + self.yys.wait_game_img('img\\JIN-BI.png', self.max_win_time_yuling) + elif self.fight_type == 'yeyuanhuo': + self.yys.wait_game_img('img\\JIE-SU.png', self.max_win_time_yeyuanhuo) + elif self.fight_type == 'yuhun1p': + self.yys.wait_game_img('img\\JIE-SU-1p.png', self.max_win_time) + else: + self.yys.wait_game_img('img\\JIE-SU.png', self.max_win_time) self.log.writeinfo(self.name + "战斗结束") def click_monster(self): # 点击怪物 pass - def click_until(self, tag, img_path, pos, pos_end=None, step_time=0.5, appear=True): + def click_shikigami(self): + # 点击第二位式神 + if self.sign_shikigami: + self.log.writeinfo("开始标记式神") + ut.mysleep(200, 50) + self.click_until('标记式神', 'img/GREEN-SIGN.png', * + CommonPos.shikigami_position_2, 0.4, True, False) + self.log.writeinfo("标记式神完成") + + def click_until(self, tag, img_path, pos, pos_end=None, step_time=0.5, appear=True, quit=True): ''' 在某一时间段内,后台点击鼠标,直到出现某一图片出现或消失 :param tag: 按键名 @@ -70,12 +101,22 @@ def click_until(self, tag, img_path, pos, pos_end=None, step_time=0.5, appear=Tr :param pos_end=None: (x,y) 若pos_end不为空,则鼠标单击以pos为左上角坐标pos_end为右下角坐标的区域内的随机位置 :step_time=0.5: 查询间隔 :appear: 图片出现或消失:Ture-出现;False-消失 + :quit=True: 超时后是否退出 :return: 成功返回True, 失败退出游戏 ''' # 在指定时间内反复监测画面并点击 start_time = time.time() while time.time()-start_time <= self.max_op_time and self.run: - result = self.yys.find_game_img(img_path) + if isinstance(img_path,list): + i = 0 + result = False + while i 0.97: - self.mouse_click_bg((757, 460)) + self.mouse_click_bg((757, 460),(770, 474)) return True return False @@ -409,20 +418,41 @@ def find_game_img(self, img_path, part=0, pos1=None, pos2=None, gray=0): else: return False + def debug(self): + ''' + 自检分辨率和点击范围 + ''' + # 开启自检 + self.debug_enable = True + + # 分辨率 + self.img = self.window_full_shot() + logging.info('游戏分辨率:' + str(self.img.shape)) + + while(1): + # 点击范围标记 + cv2.imshow('Click Area (Press \'q\' to exit)', self.img) + + # 候选图片 + + k = cv2.waitKey(1) & 0xFF + if k == ord('q'): + break + + cv2.destroyAllWindows() + self.debug_enable = False + # 测试用 + def show_img(img): cv2.imshow("image", img) cv2.waitKey(0) def main(): - yys = GameControl(u'阴阳师-网易游戏') - # yys.mouse_click_bg((427,419),(457,452)) - # yys.mouse_drag_bg((1130,118),(20,118)) - # print(yys.window_full_shot('tmp\\full.png')) - # print(yys.find_color(((380,200),(480,400)),(251,237,2),3)) - # print(yys.find_color(((630,250),(730,450)),(251,237,2),3)) - # print(yys.find_color(((1006,526),(1058,549)),(242,215,165),0)) + hwnd = win32gui.FindWindow(0, u'阴阳师-网易游戏') + yys = GameControl(hwnd, 0) + yys.debug() if __name__ == '__main__': diff --git a/img/BAO-WU.png b/img/BAO-WU.png new file mode 100644 index 0000000..52bb9bc Binary files /dev/null and b/img/BAO-WU.png differ diff --git a/img/BAO-XIANG.png b/img/BAO-XIANG.png new file mode 100644 index 0000000..8019ae7 Binary files /dev/null and b/img/BAO-XIANG.png differ diff --git a/img/FANG-JIAN-YAO-QING.png b/img/FANG-JIAN-YAO-QING.png new file mode 100644 index 0000000..2053109 Binary files /dev/null and b/img/FANG-JIAN-YAO-QING.png differ diff --git a/img/FANG-JIAN-YAO-QING2.png b/img/FANG-JIAN-YAO-QING2.png new file mode 100644 index 0000000..7607b8b Binary files /dev/null and b/img/FANG-JIAN-YAO-QING2.png differ diff --git a/img/GREEN-SIGN.png b/img/GREEN-SIGN.png new file mode 100644 index 0000000..5a9b263 Binary files /dev/null and b/img/GREEN-SIGN.png differ diff --git a/img/JIE-SU-1p.png b/img/JIE-SU-1p.png new file mode 100644 index 0000000..64d48c1 Binary files /dev/null and b/img/JIE-SU-1p.png differ diff --git a/img/JIE-SU.png b/img/JIE-SU.png index d9393c2..87c38d3 100644 Binary files a/img/JIE-SU.png and b/img/JIE-SU.png differ diff --git a/img/JUE-XING.png b/img/JUE-XING.png index 0b54134..52e7ce7 100644 Binary files a/img/JUE-XING.png and b/img/JUE-XING.png differ diff --git a/img/MAN0.png b/img/MAN0.png new file mode 100644 index 0000000..8ba9212 Binary files /dev/null and b/img/MAN0.png differ diff --git a/img/MESSAGE.png b/img/MESSAGE.png index 8414093..6eafcfd 100644 Binary files a/img/MESSAGE.png and b/img/MESSAGE.png differ diff --git a/img/TAN-SUO.png b/img/TAN-SUO.png index 151c1e5..3b5952e 100644 Binary files a/img/TAN-SUO.png and b/img/TAN-SUO.png differ diff --git a/img/TIAO-ZHAN.png b/img/TIAO-ZHAN.png index 795f98f..ff497fd 100644 Binary files a/img/TIAO-ZHAN.png and b/img/TIAO-ZHAN.png differ diff --git a/img/TUI-CHU-FU-BEN.png b/img/TUI-CHU-FU-BEN.png new file mode 100644 index 0000000..0d5959e Binary files /dev/null and b/img/TUI-CHU-FU-BEN.png differ diff --git a/img/XIE-ZHAN-DUI-WU.png b/img/XIE-ZHAN-DUI-WU.png index 8c6b62c..6294701 100644 Binary files a/img/XIE-ZHAN-DUI-WU.png and b/img/XIE-ZHAN-DUI-WU.png differ diff --git a/img/XUAN-SHANG.png b/img/XUAN-SHANG.png index 2303b08..a10ac8c 100644 Binary files a/img/XUAN-SHANG.png and b/img/XUAN-SHANG.png differ diff --git a/img/YAO-QING.png b/img/YAO-QING.png new file mode 100644 index 0000000..be97735 Binary files /dev/null and b/img/YAO-QING.png differ diff --git a/img/YE-YUAN-HUO.png b/img/YE-YUAN-HUO.png new file mode 100644 index 0000000..385319f Binary files /dev/null and b/img/YE-YUAN-HUO.png differ diff --git a/img/YU-HUN-XUAN-DAN.png b/img/YU-HUN-XUAN-DAN.png new file mode 100644 index 0000000..e6fa59b Binary files /dev/null and b/img/YU-HUN-XUAN-DAN.png differ diff --git a/img/YU-LING.png b/img/YU-LING.png new file mode 100644 index 0000000..ad2b532 Binary files /dev/null and b/img/YU-LING.png differ diff --git a/img/ZI-DONG.bak.png b/img/ZI-DONG.bak.png new file mode 100644 index 0000000..350947c Binary files /dev/null and b/img/ZI-DONG.bak.png differ diff --git a/img/ZI-DONG.png b/img/ZI-DONG.png index 350947c..9608442 100644 Binary files a/img/ZI-DONG.png and b/img/ZI-DONG.png differ diff --git a/img/full.png b/img/full.png new file mode 100644 index 0000000..b8ee258 Binary files /dev/null and b/img/full.png differ diff --git a/mitama/dual.py b/mitama/dual.py index 08da36a..0594368 100644 --- a/mitama/dual.py +++ b/mitama/dual.py @@ -56,5 +56,6 @@ def start(self): task2.join() def deactivate(self): + self.hwndlist = [] self.driver.deactivate() self.passenger.deactivate() diff --git a/mitama/fighter_driver.py b/mitama/fighter_driver.py index 0c5b71b..33129c0 100644 --- a/mitama/fighter_driver.py +++ b/mitama/fighter_driver.py @@ -17,45 +17,60 @@ def start(self): '''单人御魂司机''' # 设定点击疲劳度 mood1 = ut.Mood() - mood2 = ut.Mood() - mood3 = ut.Mood(3) + mood2 = ut.Mood(2) + mood3 = ut.Mood(2) # 战斗主循环 - self.yys.wait_game_img('img\\KAI-SHI-ZHAN-DOU.png', - self.max_win_time) + while self.run: # 司机点击开始战斗,需要锁定御魂阵容 + self.log.writeinfo('Driver: 进入队伍') mood1.moodsleep() + + # 拒绝悬赏 + self.yys.rejectbounty() + + self.yys.wait_game_img('img\\KAI-SHI-ZHAN-DOU.png', + self.max_win_time) + + # 全部队员进入房间才开始 + if self.multiPassenger: + self.wait_two_passenger() + self.log.writeinfo('Driver: 点击开始战斗按钮') self.click_until('开始战斗按钮', 'img\\ZI-DONG.png', * - YuhunPos.kaishizhandou_btn, mood2.get1mood()/1000) + YuhunPos.kaishizhandou_btn, mood1.get1mood()/1000) self.log.writeinfo('Driver: 已进入战斗') + # 已经进入战斗,乘客自动标记第二位式神 + self.click_shikigami() + # 已经进入战斗,司机自动点怪 self.click_monster() # 检测是否打完 self.check_end() mood2.moodsleep() + time.sleep(0.9) # 在战斗结算页面 + logging.info('Driver: 开始结算') self.yys.mouse_click_bg(ut.firstposition()) - self.click_until('结算', 'img/JIN-BI.png', + self.click_until('结算', ['img\\JIN-BI.png','img\\XIE-ZHAN-DUI-WU.png'], *CommonPos.second_position, mood3.get1mood()/1000) - self.click_until('结算', 'img/JIN-BI.png', - *CommonPos.second_position, mood3.get1mood()/1000, False) + self.click_until('结算', 'img\\JIN-BI.png', + *CommonPos.second_position, mood3.get1mood()/1000, False) # 等待下一轮 logging.info('Driver: 等待下一轮') start_time = time.time() while time.time() - start_time <= 20 and self.run: - if(self.yys.wait_game_img('img\\KAI-SHI-ZHAN-DOU.png', 1, False)): - self.log.writeinfo('Driver: 进入队伍') + if(self.yys.wait_game_img('img\\XIE-ZHAN-DUI-WU.png', 1, False)): break # 点击默认邀请 if self.yys.find_game_img('img\\ZI-DONG-YAO-QING.png'): - self.yys.mouse_click_bg((497, 319)) + self.yys.mouse_click_bg((497, 319),(503, 325)) time.sleep(0.2) - self.yys.mouse_click_bg((674, 384)) + self.yys.mouse_click_bg((674, 384),(680, 390)) self.log.writeinfo('Driver: 自动邀请') diff --git a/mitama/fighter_passenger.py b/mitama/fighter_passenger.py index 9512fd1..b2a1d60 100644 --- a/mitama/fighter_passenger.py +++ b/mitama/fighter_passenger.py @@ -16,27 +16,32 @@ def __init__(self, emyc=0, hwnd=0): def start(self): '''单人御魂乘客''' # 设定点击疲劳度 - mood2 = ut.Mood() - mood3 = ut.Mood(3) + mood2 = ut.Mood(2) + mood3 = ut.Mood(2) # 战斗主循环 while self.run: # 检测是否进入战斗 self.check_battle() + # 已经进入战斗,乘客自动标记第二位式神 + self.click_shikigami() + # 已经进入战斗,乘客自动点怪 self.click_monster() # 检测是否打完 self.check_end() mood2.moodsleep() + time.sleep(0.9) - # 在战斗结算页面 + # 等待下一轮 + logging.info('Driver: 开始结算') self.yys.mouse_click_bg(ut.firstposition()) - self.click_until('结算', 'img/JIN-BI.png', - *CommonPos.second_position, mood3.get1mood()/1000) - self.click_until('结算', 'img/JIN-BI.png', - *CommonPos.second_position, mood3.get1mood()/1000, False) + self.click_until('结算', ['img\\JIN-BI.png','img\\XIE-ZHAN-DUI-WU.png'], + *CommonPos.second_position, mood3.get1mood()/1000) + self.click_until('结算', 'img\\JIN-BI.png', + *CommonPos.second_position, mood3.get1mood()/1000, False) # 等待下一轮 logging.info('Passenger: 等待下一轮') @@ -53,10 +58,10 @@ def start(self): if yuhun_loc: # 点击自动接受邀请 if self.yys.find_game_img('img\\ZI-DONG-JIE-SHOU.png'): - self.yys.mouse_click_bg((210, yuhun_loc[1])) + self.yys.mouse_click_bg((210, yuhun_loc[1]),(216, yuhun_loc[1]+6)) self.log.writeinfo('Passenger: 自动接受邀请') # 点击普通接受邀请 elif self.yys.find_game_img('img\\JIE-SHOU.png'): - self.yys.mouse_click_bg((125, yuhun_loc[1])) - self.log.writeinfo('Passenger: 接受邀请') + self.yys.mouse_click_bg((125, yuhun_loc[1]),(130, yuhun_loc[1]+6)) + self.log.writeinfo('Passenger: 接受邀请') \ No newline at end of file diff --git a/mitama/single_fight.py b/mitama/single_fight.py index de45f51..5d83a25 100644 --- a/mitama/single_fight.py +++ b/mitama/single_fight.py @@ -1,6 +1,7 @@ from gameLib.fighter import Fighter from tools.game_pos import CommonPos, YuhunPos import tools.utilities as ut +import time class SingleFight(Fighter): @@ -9,12 +10,21 @@ class SingleFight(Fighter): def __init__(self, done=1, emyc=0): # 初始化 Fighter.__init__(self, '', emyc) + result = self.yys.find_game_img('img\\YE-YUAN-HUO.png') + result2 = self.yys.find_game_img('img\\YU-LING.png') + if result: + self.fight_type = 'yeyuanhuo' + elif result2: + self.fight_type = 'yuling' + else: + self.fight_type = 'yuhun1p' def start(self): '''单人战斗主循环''' mood1 = ut.Mood() - mood2 = ut.Mood() - mood3 = ut.Mood(3) + mood2 = ut.Mood(2) + mood3 = ut.Mood(2) + while self.run: # 在御魂主选单,点击“挑战”按钮, 需要使用“阵容锁定”! self.yys.wait_game_img('img\\TIAO-ZHAN.png', @@ -26,15 +36,19 @@ def start(self): # 检测是否进入战斗 self.check_battle() + # 已经进入战斗,乘客自动标记第二位式神 + self.click_shikigami() + # 在战斗中,自动点怪 self.click_monster() # 检测是否打完 self.check_end() mood2.moodsleep() + time.sleep(0.9) # 在战斗结算页面 self.yys.mouse_click_bg(ut.firstposition()) self.click_until('结算', 'img\\TIAO-ZHAN.png', *CommonPos.second_position, mood3.get1mood()/1000) - self.log.writeinfo("回到御魂选择界面") + self.log.writeinfo("回到选择界面") diff --git a/omj.py b/omj.py new file mode 100644 index 0000000..973deb7 --- /dev/null +++ b/omj.py @@ -0,0 +1,204 @@ +import sys +import os +import logging +import ctypes + +from explore.single_explore import SingleExploreFight +from explore.explore import ExploreFight +from mitama.fighter_driver import DriverFighter +from mitama.fighter_passenger import FighterPassenger +from mitama.single_fight import SingleFight +from tools.logsystem import WriteLog + +# 设置 +global mode +global emyc +global done +global sign_shikigami + +#初始化对象 +log = WriteLog() + +def init(): + global section + global mode + global emyc + global done + global sign_shikigami + global multiPassenger + global shikigami_type + global shikigami_brush_max + global shikigami_brush_max_quit + global only_fight_exp + + multiPassenger = False + + try: + # 选择打什么 + section = int(input('\n选择刷什么(Ctrl-C跳过并单刷御魂:\n0-御魂/业原火/御灵\n1-探索\n')) + log.writeinfo('Section = %d', section) + if section == 0: + # 御魂模式选择 + mode=int(input('\n选择游戏模式(Ctrl-C跳过并单刷):\n0-单刷\n2-组队司机\n3-组队打手\n22-组队司机(双乘客)\n')) + if(mode==1): + log.writewarning('未开发,告辞!') + os._exit(0) + elif(mode == 22): + mode=2 + multiPassenger = True + elif(mode != 2 and mode != 0 and mode != 3): + mode=0 + + # 标记式神设置 + sign_shikigami=int(input('\n是否标记式神?\n3-使用配置文件的设置\n0-不标记\n1-标记\n')) + if((sign_shikigami!=3) and (sign_shikigami!=0) and (sign_shikigami!=1)): + sign_shikigami=3 + else: + # 探索模式选择 + # mode=int(input('\n选择游戏模式(Ctrl-C跳过并单刷):\n0-单刷\n2-组队司机\n3-组队打手\n')) + # if(mode==1): + # log.writewarning('未开发,告辞!') + # os._exit(0) + # elif(mode != 2 and mode != 0 and mode != 3): + # mode=0 + mode=0 + + log.writewarning('提示!!!!探索建议手动刷,探索相关的脚本 防检测机制 不够完善') + log.writewarning('狗粮队长请放中间') + shikigami_type=int(input('\n选择要自动换满级式神的类型:\n0-不替换满级式神(需锁定阵容)\n1-替换N卡(不能锁定阵容,需要关闭式神折叠)\n2-替换1级2星白蛋(不能锁定阵容,需要折叠相同式神)\n')) + if shikigami_type!=1 and shikigami_type!=2 and shikigami_type!=3: + shikigami_type = 0 + + only_fight_exp=int(input('\是否只刷经验怪:\n1:是\n2:否\n')) + if only_fight_exp == 1: + only_fight_exp = True + else: + only_fight_exp = False + + shikigami_brush_max=int(input('\n填写要刷的局数:\n')) + if not shikigami_brush_max: + shikigami_brush_max = 999 + + shikigami_brush_max_quit=int(input('\是否刷完关闭游戏:\n1:是\n2:否\n')) + if shikigami_brush_max_quit == 1: + shikigami_brush_max_quit = True + else: + shikigami_brush_max_quit = False + + # 点怪设置 + # emyc=int(input('\n是否点怪?\n0-不点怪\n1-点中间怪\n2-点右边怪\n')) + # if((emyc!=0) and (emyc!=1) and (emyc!=2)): + # emyc=0 + + # 结束设置 + # done=int(input('\n结束后如何处理?\n0-退出\n1-关机\n')) + # if not ((done == 0) or (done == 1)): + # done = 0 + log.writeinfo('Mode = %d',mode) + # log.writeinfo('Emyc = %d',emyc) + # log.writeinfo('Postoperation = %d',done) + except: + section = 0 + mode=0 + emyc=0 + done=1 + sign_shikigami=3 + log.writeinfo('Use default parameters') + +def is_admin(): + # UAC申请,获得管理员权限 + try: + return ctypes.windll.shell32.IsUserAnAdmin() + except: + return False + +def yuhun(): + '''御魂战斗''' + try: + if mode == 0: + # 单刷 + fight = SingleFight() + + if mode == 2: + # 司机 + fight = DriverFighter() + + if mode == 3: + # 乘客 + fight = FighterPassenger() + + if sign_shikigami != 3: + fight.sign_shikigami = sign_shikigami + fight.multiPassenger = multiPassenger + fight.start() + + except Exception as e: + log.writeinfo(e) + os.system("pause") + +def tansuo(): + '''探索战斗''' + try: + if mode == 0: + # 单刷 + fight = SingleExploreFight() + + if mode == 2: + # 司机 + fight = DriverExploreFight() + + if mode == 3: + # 乘客 + fight = PassengerExploreFight() + + fight.shikigami_type = shikigami_type + if shikigami_brush_max: + fight.shikigami_brush_max = shikigami_brush_max + fight.shikigami_brush_max_quit = shikigami_brush_max_quit + fight.only_fight_exp = only_fight_exp + fight.start() + + except Exception as e: + log.writeinfo(e) + os.system("pause") + +def my_excepthook(exc_type, exc_value, tb): + msg = ' Traceback (most recent call last):\n' + while tb: + filename = tb.tb_frame.f_code.co_filename + name = tb.tb_frame.f_code.co_name + lineno = tb.tb_lineno + msg += ' File "%.500s", line %d, in %.500s\n' % (filename, lineno, name) + tb = tb.tb_next + + msg += ' %s: %s\n' %(exc_type.__name__, exc_value) + + logging.error(msg) + +if __name__ == "__main__": + log.writeinfo('python version: %s', sys.version) + + try: + # 检测管理员权限 + if is_admin(): + sys.excepthook = my_excepthook + + # 注册插件,获取权限 + log.writeinfo('UAC pass') + + # 设置战斗参数 + init() + + # 开始战斗 + if section == 0: + yuhun() + elif section == 1: + tansuo() + + else: + ctypes.windll.shell32.ShellExecuteW(None, "runas", sys.executable, __file__, None, 1) + except KeyboardInterrupt: + log.writeinfo('terminated') + os._exit(0) + else: + pass \ No newline at end of file diff --git a/onmyoji.ui b/omj.ui similarity index 99% rename from onmyoji.ui rename to omj.ui index a932cd4..c1a59a0 100644 --- a/onmyoji.ui +++ b/omj.ui @@ -272,7 +272,7 @@ true - 把狗粮队长放在最左边,点开需要打的章节,然后开始。 + 把狗粮队长放在中间,点开需要打的章节,然后开始。 支持自动换狗粮,只打经验怪。 diff --git a/onmyoji.py b/onmyoji.py deleted file mode 100644 index 24b786e..0000000 --- a/onmyoji.py +++ /dev/null @@ -1,110 +0,0 @@ -import sys -import os -import ctypes - -from explore.explore import ExploreFight -from mitama.fighter_driver import DriverFighter -from mitama.fighter_passenger import FighterPassenger -from mitama.single_fight import SingleFight -from tools.logsystem import WriteLog - -# 设置 -global mode -global emyc -global done - -#初始化对象 -log = WriteLog() - -def init(): - global section - global mode - global emyc - global done - - try: - # 选择打什么 - section = int(input('\n选择刷什么(Ctrl-C跳过并单刷御魂:\n0-御魂\n1-探索\n')) - log.writeinfo('Section = %d', section) - if section == 0: - # 御魂模式选择 - mode=int(input('\n选择游戏模式(Ctrl-C跳过并单刷):\n0-单刷\n2-组队司机\n3-组队打手\n')) - if(mode==1): - log.writewarning('未开发,告辞!') - os._exit(0) - elif(mode != 2 and mode != 0 and mode != 3): - mode=0 - - # 点怪设置 - # emyc=int(input('\n是否点怪?\n0-不点怪\n1-点中间怪\n2-点右边怪\n')) - # if((emyc!=0) and (emyc!=1) and (emyc!=2)): - # emyc=0 - - # 结束设置 - # done=int(input('\n结束后如何处理?\n0-退出\n1-关机\n')) - # if not ((done == 0) or (done == 1)): - # done = 0 - log.writeinfo('Mode = %d',mode) - # log.writeinfo('Emyc = %d',emyc) - # log.writeinfo('Postoperation = %d',done) - except: - section = 0 - mode=0 - emyc=0 - done=1 - log.writeinfo('Use default parameters') - -def is_admin(): - # UAC申请,获得管理员权限 - try: - return ctypes.windll.shell32.IsUserAnAdmin() - except: - return False - -def yuhun(): - '''御魂战斗''' - if mode == 0: - # 单刷 - fight = SingleFight() - fight.start() - - if mode == 2: - # 司机 - fight = DriverFighter() - fight.start() - - if mode == 3: - # 乘客 - fight = FighterPassenger() - fight.start() - -def tansuo(): - '''探索战斗''' - fight = ExploreFight() - fight.start() - -if __name__ == "__main__": - log.writeinfo('python version: %s', sys.version) - - try: - # 检测管理员权限 - if is_admin(): - # 注册插件,获取权限 - log.writeinfo('UAC pass') - - # 设置战斗参数 - init() - - # 开始战斗 - if section == 0: - yuhun() - elif section == 1: - tansuo() - - else: - ctypes.windll.shell32.ShellExecuteW(None, "runas", sys.executable, __file__, None, 1) - except KeyboardInterrupt: - log.writeinfo('terminated') - os._exit(0) - else: - pass \ No newline at end of file diff --git a/requirements.txt b/requirements.txt index a6148a8..b4bfb4f 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 -PyQt5==5.12.2 +numpy==1.17.3 +pywin32==225 +opencv_python==4.1.1.26 +Pillow==6.2.1 +PyQt5==5.13.1 diff --git a/run.bat b/run.bat index ed44c15..965c6c2 100644 --- a/run.bat +++ b/run.bat @@ -1 +1 @@ -python onmyoji.py \ No newline at end of file +python omj.py \ No newline at end of file diff --git a/runInVirtualEnv.bat b/runInVirtualEnv.bat new file mode 100644 index 0000000..4336377 --- /dev/null +++ b/runInVirtualEnv.bat @@ -0,0 +1,3 @@ +call F:\workplace_zc\Python\Envs\env-onmyoji_bot\Scripts\activate.bat +python omj.py +cmd . \ No newline at end of file diff --git a/tools/game_pos.py b/tools/game_pos.py index e164797..a7d8b74 100644 --- a/tools/game_pos.py +++ b/tools/game_pos.py @@ -4,7 +4,8 @@ def __init__(self,pos,pos_end=None): self.pos_end=pos_end class CommonPos(): - second_position = (877, 56), (1111, 452) # 第二次结算所点击的位置 + second_position = (960, 60), (1111, 452) # 第二次结算所点击的位置 + shikigami_position_2 = (315, 390), (365, 506) # 标记第二只式神的位置 class TansuoPos(): last_chapter = (934, 493), (1108, 572) # 列表最后一章 @@ -17,12 +18,36 @@ class TansuoPos(): change_monster = (427, 419), (457, 452) # 切换狗粮点击区域 quanbu_btn = (37, 574), (80, 604) # “全部”按钮 n_tab_btn = (142, 288), (164, 312) # n卡标签 + sucai_tab_btn = (44, 268), (88, 308) # 素材卡标签 n_slide = (168, 615), (784, 615) # n卡进度条,从头至尾 quit_change_monster=GamePos((19,17),(43,38)) #退出换狗粮界面 - gouliang_middle = (397, 218), (500, 349) # 中间狗粮位置 - gouliang_right = (628, 293), (730, 430) # 右边狗粮位置 + + gouliang_man_left = (190, 122), (370, 430) # 左边狗粮满字位置 + gouliang_man_middle = (397, 122), (500, 430) # 中间狗粮满字位置 + gouliang_man_right = (578, 122), (750, 430) # 右边狗粮满字位置 + + # 拖放相关位置 + gouliang_target_left = (990, 315) # 左边狗粮拖放位置 + gouliang_target_middle = (554, 315) # 中间狗粮拖放位置 + gouliang_target_right = (187, 315) # 右边狗粮拖放位置 + + # n卡拖放相关位置 + gouliang_left = (309, 520), gouliang_target_left # 左边狗粮拖放路线 + gouliang_middle = (309, 520), gouliang_target_middle # 中间狗粮拖放路线 + gouliang_right = (191, 520), gouliang_target_right # 右边狗粮拖放路线 + + gouliang_driver_left = (309, 520), (308, 306) # 左边狗粮拖放路线(司机) + gouliang_driver_right = (191, 520), (835, 306) # 右边狗粮拖放路线(司机) + + gouliang_passenger_left = (309, 520), (554, 325) # 左边狗粮拖放路线(乘客) + gouliang_passenger_right = (191, 520), (187, 325) # 右边狗粮拖放路线(乘客) + + # 素材卡拖放相关位置 + gouliang_sucai_0 = 204, 520 # 1级素材拖放起点 + gouliang_sucai_1 = 526, 520 # 1+级素材拖放起点1 + gouliang_sucai_2 = 648, 520 # 1+级素材拖放起点2 class YuhunPos(): - tiaozhan_btn = (790, 418), (903, 469) # 御魂挑战按钮 + tiaozhan_btn = (960, 501), (1090, 631) # 御魂挑战按钮 kaishizhandou_btn = (1048, 535), (1113, 604) # 御魂开始战斗按钮 diff --git a/tools/utilities.py b/tools/utilities.py index e4ba01d..40bf317 100644 --- a/tools/utilities.py +++ b/tools/utilities.py @@ -9,22 +9,22 @@ class Mood: ''' 用于模拟随机的点击频率,每5分钟更换一次点击规律\n - energetic: 状态极佳,点击延迟在1-1.5s\n - joyful: 状态不错,点击延迟在1.3-2.1s\n - normal: 状态一般,点击延迟在1.8-3s\n - tired: 状态疲劳,点击延迟在2.5-4\n - exhausted: CHSM,点击延迟在3-5s\n + energetic: 状态极佳,点击延迟在1-1.3s\n + joyful: 状态不错,点击延迟在1.3-1.8s\n + normal: 状态一般,点击延迟在1.8-2.3s\n + tired: 状态疲劳,点击延迟在2.3-2.8\n + exhausted: CHSM,点击延迟在2.8-3.6s\n ''' def __init__(self, state=5): self.lastime = time.time() self.state = state Mood.mymood = { - 1: (1000, 500), - 2: (1300, 800), - 3: (1800, 1200), - 4: (2500, 1500), - 5: (3000, 2000)} + 1: (1000, 300), + 2: (1300, 500), + 3: (1800, 500), + 4: (2300, 500), + 5: (2800, 800)} a = random.randint(1, self.state) log.writeinfo("Now you mood is level %d", a) self.lastmood = Mood.mymood[a] @@ -50,93 +50,21 @@ def firstposition(): :return: 返回随机位置坐标 ''' w = 1136 - h = 640 + h = 530 while True: position = (random.randint(0, w), random.randint(50, h)) - if position[0] < 332 or position[0] > 931: + if position[0] < 123 and position[1] <108: + continue + if position[0] < 210 or position[0] > 1083: return position - elif position[1] < 350 or position[1] > 462: + elif position[1] < 260: return position -def secondposition(): - ''' - 获得点击位置,扣除御魂部分 - :return: 返回随机位置坐标 - ''' - return (random.randint(887, 1111), random.randint(56, 452)) - ''' - while True: - position = (random.randint(0, w), random.randint(50, h - 90)) - if position[0] < 180 or position[0] > 956: - return position - elif position[1] < 112: - return position - ''' - - def mysleep(slpa, slpb=0): ''' randomly sleep for a short time between `slpa` and `slpa + slpb` \n because of the legacy reason, slpa and slpb are in millisecond ''' - slp = random.randint(slpa, slpa+slpb) - time.sleep(slp/1000) - - -def crnd(ts, x1, x2, y1, y2): - ''' - randomly click a point in a rectangle region (x1, y1), (x2, y2) - ''' - xr = random.randint(x1, x2) - yr = random.randint(y1, y2) - ts.MoveTo(xr, yr) - mysleep(100, 100) - ts.LeftClick() - mysleep(100, 100) - - -def rejxs(ts): - '''拒绝悬赏''' - colxs = ts.GetColor(750, 458) - # print(colxs) - if colxs == "df715e": - crnd(ts, 750-5, 750+5, 458-5, 458+5) - log.writeinfo("Successfully rejected bounty") - mysleep(1000) - mysleep(50) - - -def wtfc1(ts, colx, coly, coll, x1, x2, y1, y2, zzz, adv, mood): - ''' - Usage: - 等待并且持续判断点 (colx, coly) 的颜色,直到该点颜色 - 等于 coll (if zzz == 0) 或者 不等于 coll (if zzz == 1) - 然后开始随机点击范围 (x1, x2) (y1, y2) 内的点,直到点 (colx, coly) 的颜色 - if adv == 1: - 不等于 coll (if zzz == 0) 或者 等于 coll (if zzz == 1) - if adv == 0: - 不判断,点击一次后退出循环 - Example: - 在准备界面时,通过判断鼓锤上某点的颜色(因为UI不会随着游戏人物摆动),来持续点击鼓面, - 直到鼓锤上该点的颜色改变,说明进入了战斗 - ''' - j = 0 - flgj = 0 - while j == 0: - rejxs(ts) - coltest = ts.GetColor(colx, coly) - #print(colx, coly, coltest) - if (coltest == coll and zzz == 0) or (coltest != coll and zzz == 1): - flgj = 1 - if flgj == 1: - rejxs(ts) - crnd(ts, x1, x2, y1, y2) - mysleep(*mood) - if adv == 0: - j = 1 - rejxs(ts) - coltest2 = ts.GetColor(colx, coly) - if (coltest2 == coll and zzz == 1) or (coltest2 != coll and zzz == 0): - j = 1 - return 1 + slp = random.randint(int(slpa), int(slpa+slpb)) + time.sleep(slp/1000) \ No newline at end of file diff --git a/ui.py b/ui.py index 35c2b00..6703ca7 100644 --- a/ui.py +++ b/ui.py @@ -15,6 +15,7 @@ import sys import threading +confPath = os.path.join(os.getcwd(), "conf.ini") #拼接上配置文件名称目录 def is_admin(): # UAC申请,获得管理员权限 @@ -71,7 +72,7 @@ def set_conf(self, conf, section): def get_conf(self, section): conf = configparser.ConfigParser() # 读取配置文件 - conf.read('conf.ini', encoding="utf-8") + conf.read(confPath, encoding="utf-8") # 修改配置 try: @@ -82,7 +83,7 @@ def get_conf(self, section): self.set_conf(conf, section) # 保存配置文件 - with open('conf.ini', 'w') as configfile: + with open(confPath, 'w') as configfile: conf.write(configfile) def start_onmyoji(self):