コード例 #1
0
class ArknightsHelper(object):
    def __init__(
            self,
            current_strength=None,  # 当前理智
            adb_host=None,  # 当前绑定到的设备
            out_put=True,  # 是否有命令行输出
            call_by_gui=False):  # 是否为从 GUI 程序调用
        if adb_host is None:
            adb_host = config.ADB_HOST
        try:
            self.adb = ADBShell(adb_host=adb_host)
        except ConnectionRefusedError as e:
            logger.error("错误: {}".format(e))
            logger.info("尝试启动本地adb")
            try:
                os.system(config.ADB_ROOT + "\\adb kill-server")
                os.system(config.ADB_ROOT + "\\adb start-server")
                self.adb = ADBShell(adb_host=adb_host)
            except Exception as e:
                logger.error("尝试解决失败,错误: {}".format(e))
                logger.info("建议检查adb版本夜神模拟器正确的版本为: 1.0.36")
        self.__is_game_active = False
        self.__call_by_gui = call_by_gui
        self.CURRENT_STRENGTH = 100
        self.selector = BattleSelector()
        self.ocr_active = True
        self.is_called_by_gui = call_by_gui
        self.viewport = self.adb.get_screen_shoot().size
        self.operation_time = []
        if DEBUG_LEVEL >= 1:
            self.__print_info()
        logger.debug("成功初始化模块")

    def __print_info(self):
        logger.info('当前系统信息:')
        logger.info('ADB 服务器:\t%s:%d', *config.ADB_SERVER)
        logger.info('分辨率:\t%dx%d', *self.viewport)
        logger.info('OCR 引擎:\t%s', ocr.engine.info)
        logger.info('截图路径 (legacy):\t%s', config.SCREEN_SHOOT_SAVE_PATH)
        logger.info('存储路径 (legacy):\t%s', config.STORAGE_PATH)

        if config.enable_baidu_api:
            logger.info(
                '%s', """百度API配置信息:
        APP_ID\t{app_id}
        API_KEY\t{api_key}
        SECRET_KEY\t{secret_key}
                        """.format(app_id=config.APP_ID,
                                   api_key=config.API_KEY,
                                   secret_key=config.SECRET_KEY))

    def __del(self):
        self.adb.run_device_cmd("am force-stop {}".format(
            config.ArkNights_PACKAGE_NAME))

    def destroy(self):
        self.__del()

    def check_game_active(self):  # 启动游戏 需要手动调用
        logger.debug("base.check_game_active")
        current = self.adb.run_device_cmd(
            'dumpsys window windows | grep mCurrentFocus').decode(
                errors='ignore')
        logger.debug("正在尝试启动游戏")
        logger.debug(current)
        if config.ArkNights_PACKAGE_NAME in current:
            self.__is_game_active = True
            logger.debug("游戏已启动")
        else:
            self.adb.run_device_cmd("am start -n {}/{}".format(
                config.ArkNights_PACKAGE_NAME, config.ArkNights_ACTIVITY_NAME))
            logger.debug("成功启动游戏")
            self.__is_game_active = True

    @staticmethod
    def __wait(
            n=10,  # 等待时间中值
            MANLIKE_FLAG=True):  # 是否在此基础上设偏移量
        if MANLIKE_FLAG:
            m = uniform(0, 0.3)
            n = uniform(n - m * 0.5 * n, n + m * n)
        sleep(n)

    def mouse_click(
            self,  # 点击一个按钮
            XY):  # 待点击的按钮的左上和右下坐标
        assert (self.viewport == (1280, 720))
        logger.debug("base.mouse_click")
        xx = randint(XY[0][0], XY[1][0])
        yy = randint(XY[0][1], XY[1][1])
        logger.info("接收到点击坐标并传递xx:{}和yy:{}".format(xx, yy))
        self.adb.touch_tap((xx, yy))
        self.__wait(TINY_WAIT, MANLIKE_FLAG=True)

    def tap_rect(self, rc):
        hwidth = (rc[2] - rc[0]) / 2
        hheight = (rc[3] - rc[1]) / 2
        midx = rc[0] + hwidth
        midy = rc[1] + hheight
        xdiff = max(-1, min(1, gauss(0, 0.2)))
        ydiff = max(-1, min(1, gauss(0, 0.2)))
        tapx = int(midx + xdiff * hwidth)
        tapy = int(midy + ydiff * hheight)
        self.adb.touch_tap((tapx, tapy))
        self.__wait(TINY_WAIT, MANLIKE_FLAG=True)

    def tap_quadrilateral(self, pts):
        pts = np.asarray(pts)
        acdiff = max(0, min(2, gauss(1, 0.2)))
        bddiff = max(0, min(2, gauss(1, 0.2)))
        halfac = (pts[2] - pts[0]) / 2
        m = pts[0] + halfac * acdiff
        pt2 = pts[1] if bddiff > 1 else pts[3]
        halfvec = (pt2 - m) / 2
        finalpt = m + halfvec * bddiff
        self.adb.touch_tap(tuple(int(x) for x in finalpt))
        self.__wait(TINY_WAIT, MANLIKE_FLAG=True)

    def module_login(self):
        logger.debug("base.module_login")
        logger.info("发送坐标LOGIN_QUICK_LOGIN: {}".format(
            CLICK_LOCATION['LOGIN_QUICK_LOGIN']))
        self.mouse_click(CLICK_LOCATION['LOGIN_QUICK_LOGIN'])
        self.__wait(BIG_WAIT)
        logger.info("发送坐标LOGIN_START_WAKEUP: {}".format(
            CLICK_LOCATION['LOGIN_START_WAKEUP']))
        self.mouse_click(CLICK_LOCATION['LOGIN_START_WAKEUP'])
        self.__wait(BIG_WAIT)

    def module_battle_slim(
            self,
            c_id=None,  # 待战斗的关卡编号
            set_count=1000,  # 战斗次数
            check_ai=True,  # 是否检查代理指挥
            **kwargs):  # 扩展参数:
        '''
        :param sub 是否为子程序 (是否为module_battle所调用)
        :param auto_close 是否自动关闭, 默认为 false
        :param self_fix 是否尝试自动修复, 默认为 false
        :param MAX_TIME 最大检查轮数, 默认在 config 中设置,
            每隔一段时间进行一轮检查判断战斗是否结束
            建议自定义该数值以便在出现一定失误,
            超出最大判断次数后有一定的自我修复能力
        :return:
            True 完成指定次数的战斗
            False 理智不足, 退出战斗
        '''
        logger.debug("base.module_battle_slim")
        sub = kwargs["sub"] \
            if "sub" in kwargs else False
        auto_close = kwargs["auto_close"] \
            if "auto_close" in kwargs else False
        if not sub:
            logger.info("战斗-选择{}...启动".format(c_id))
        if set_count == 0:
            return True
        self.operation_time = []
        try:
            for count in range(set_count):
                logger.info("开始第 %d 次战斗", count + 1)
                self.operation_once_statemachine(c_id, )
                logger.info("第 %d 次战斗完成", count + 1)
                if count != set_count - 1:
                    # 2019.10.06 更新逻辑后,提前点击后等待时间包括企鹅物流
                    if config.reporter:
                        self.__wait(SMALL_WAIT, MANLIKE_FLAG=True)
                    else:
                        self.__wait(BIG_WAIT, MANLIKE_FLAG=True)
        except StopIteration:
            logger.error('未能进行第 %d 次战斗', count + 1)
            remain = set_count - count - 1
            if remain > 0:
                logger.error('已忽略余下的 %d 次战斗', remain)
        logger.info("等待返回{}关卡界面".format(c_id))
        self.__wait(SMALL_WAIT, True)

        if not sub:
            if auto_close:
                logger.info("简略模块{}结束,系统准备退出".format(c_id))
                self.__wait(120, False)
                self.__del()
            else:
                logger.info("简略模块{}结束".format(c_id))
                return True
        else:
            logger.info("当前任务{}结束,准备进行下一项任务".format(c_id))
            return True

    class operation_once_state:
        def __init__(self):
            self.state = None
            self.stop = False
            self.operation_start = None
            self.first_wait = True

    def operation_once_statemachine(self, c_id):
        smobj = ArknightsHelper.operation_once_state()

        def on_prepare(smobj):
            count_times = 0
            while True:
                screenshot = self.adb.get_screen_shoot()
                recoresult = imgreco.before_operation.recognize(screenshot)
                not_in_scene = False
                if not recoresult['AP']:
                    # ASSUMPTION: 只有在战斗前界面才能识别到右上角体力
                    not_in_scene = True
                if recoresult['consume'] is None:
                    # ASSUMPTION: 所有关卡都显示并能识别体力消耗
                    not_in_scene = True

                logger.info('当前画面关卡:%s', recoresult['operation'])

                if (not not_in_scene) and c_id is not None:
                    # 如果传入了关卡 ID,检查识别结果
                    if recoresult['operation'] != c_id:
                        not_in_scene = True

                if not_in_scene:
                    count_times += 1
                    if count_times <= 7:
                        logger.warning('不在关卡界面,继续等待……')
                        self.__wait(TINY_WAIT, False)
                        continue
                    else:
                        logger.error('{}次检测后都不再关卡界面,退出进程'.format(count_times))
                        raise StopIteration()
                else:
                    break

            self.CURRENT_STRENGTH = int(recoresult['AP'].split('/')[0])
            logger.info('当前理智 %d, 关卡消耗 %d', self.CURRENT_STRENGTH,
                        recoresult['consume'])
            if self.CURRENT_STRENGTH < int(recoresult['consume']):
                logger.error('理智不足')
                raise StopIteration()

            if not recoresult['delegated']:
                logger.info('设置代理指挥')
                self.tap_rect(
                    imgreco.before_operation.get_delegate_rect(self.viewport))

            logger.info("开始行动")
            self.tap_rect(
                imgreco.before_operation.get_start_operation_rect(
                    self.viewport))
            smobj.state = on_troop

        def on_troop(smobj):
            count_times = 0
            while True:
                self.__wait(TINY_WAIT, False)
                screenshot = self.adb.get_screen_shoot()
                recoresult = imgreco.before_operation.check_confirm_troop_rect(
                    screenshot)
                if recoresult:
                    logger.info('确认编队')
                    break
                else:
                    count_times += 1
                    if count_times <= 7:
                        logger.warning('等待确认编队')
                        continue
                    else:
                        logger.error('{}次检测后不再确认编队界面'.format(count_times))
                        raise StopIteration()
            self.tap_rect(
                imgreco.before_operation.get_confirm_troop_rect(self.viewport))
            smobj.operation_start = monotonic()
            smobj.state = on_operation

        def on_operation(smobj):
            if smobj.first_wait:
                if len(self.operation_time) == 0:
                    wait_time = BATTLE_NONE_DETECT_TIME
                else:
                    wait_time = sum(self.operation_time) / len(
                        self.operation_time) - 7
                logger.info('等待 %d s' % wait_time)
                self.__wait(wait_time, MANLIKE_FLAG=False)
                smobj.first_wait = False
            t = monotonic() - smobj.operation_start

            logger.info('已进行 %.1f s,判断是否结束', t)

            screenshot = self.adb.get_screen_shoot()
            if imgreco.end_operation.check_level_up_popup(screenshot):
                logger.info("检测到升级")
                self.operation_time.append(t)
                smobj.state = on_level_up_popup
                return
            if imgreco.end_operation.check_end_operation(screenshot):
                logger.info('战斗结束')
                self.operation_time.append(t)
                self.__wait(SMALL_WAIT)
                smobj.state = on_end_operation
                return
            logger.info('战斗未结束')
            self.__wait(BATTLE_FINISH_DETECT)

        def on_level_up_popup(smobj):
            self.__wait(SMALL_WAIT, MANLIKE_FLAG=True)
            logger.info('关闭升级提示')
            self.tap_rect(
                imgreco.end_operation.get_dismiss_level_up_popup_rect(
                    self.viewport))
            self.__wait(SMALL_WAIT, MANLIKE_FLAG=True)
            smobj.state = on_end_operation

        def on_end_operation(smobj):
            screenshot = self.adb.get_screen_shoot()
            logger.info('离开结算画面')
            self.tap_rect(
                imgreco.end_operation.get_dismiss_end_operation_rect(
                    self.viewport))
            try:
                # 掉落识别
                drops = imgreco.end_operation.recognize(screenshot)
                logger.info('掉落识别结果:%s', repr(drops))
                _penguin_report(drops)
            except Exception as e:
                logger.error('', exc_info=True)
            smobj.stop = True

        smobj.state = on_prepare
        smobj.stop = False
        smobj.operation_start = 0

        while not smobj.stop:
            oldstate = smobj.state
            smobj.state(smobj)
            if smobj.state != oldstate:
                logger.debug('state changed to %s', smobj.state.__name__)

    def back_to_main(self):  # 回到主页
        logger.debug("base.back_to_main")
        logger.info("返回主页...")
        while True:
            screenshot = self.adb.get_screen_shoot()

            if imgreco.main.check_main(screenshot):
                break

            # 检查是否有返回按钮
            if imgreco.common.check_nav_button(screenshot):
                logger.info('发现返回按钮,点击返回')
                self.tap_rect(
                    imgreco.common.get_nav_button_back_rect(self.viewport))
                # FIXME: 检查基建退出提示
                self.__wait(SMALL_WAIT)
                # 点击返回按钮之后重新检查
                continue

            if imgreco.common.check_get_item_popup(screenshot):
                logger.info('当前为获得物资画面,关闭')
                self.tap_rect(
                    imgreco.common.get_reward_popup_dismiss_rect(
                        self.viewport))
                self.__wait(SMALL_WAIT)
                continue

            # 检查是否在设置画面
            if imgreco.common.check_setting_scene(screenshot):
                logger.info("当前为设置/邮件画面,返回")
                self.tap_rect(
                    imgreco.common.get_setting_back_rect(self.viewport))
                self.__wait(SMALL_WAIT)
                continue

            # 检测是否有关闭按钮
            rect, confidence = imgreco.common.find_close_button(screenshot)
            if confidence > 0.9:
                logger.info("发现关闭按钮")
                self.tap_rect(rect)
                self.__wait(SMALL_WAIT)
                continue

            raise RuntimeError('未知画面')
        logger.info("已回到主页")

    def module_battle(
            self,  # 完整的战斗模块
            c_id,  # 选择的关卡
            set_count=1000):  # 作战次数
        logger.debug("base.module_battle")
        assert (self.viewport == (1280, 720))
        self.back_to_main()
        self.__wait(3, MANLIKE_FLAG=False)
        self.selector.id = c_id
        logger.info("发送坐标BATTLE_CLICK_IN: {}".format(
            CLICK_LOCATION['BATTLE_CLICK_IN']))
        self.mouse_click(CLICK_LOCATION['BATTLE_CLICK_IN'])
        self.battle_selector(c_id)  # 选关
        self.module_battle_slim(c_id,
                                set_count=set_count,
                                check_ai=True,
                                sub=True)
        return True

    def main_handler(self, task_list=None, clear_tasks=False, auto_close=True):
        logger.debug("base.main_handler")
        if task_list is None:
            task_list = OrderedDict()

        logger.info("装载模块...")
        logger.info("战斗模块...启动")
        flag = False
        if task_list.__len__() == 0:
            logger.fatal("任务清单为空!")

        for c_id, count in task_list.items():
            if c_id not in MAIN_TASK_SUPPORT.keys():
                raise IndexError("无此关卡!")
            logger.info("战斗{} 启动".format(c_id))
            self.selector.id = c_id
            flag = self.module_battle(c_id, count)

        if flag:
            if self.__call_by_gui or auto_close is False:
                logger.info("所有模块执行完毕")
            else:
                if clear_tasks:
                    self.clear_daily_task()
                logger.info("所有模块执行完毕... 60s后退出")
                self.__wait(60)
                self.__del()
        else:
            if self.__call_by_gui or auto_close is False:
                logger.error("发生未知错误... 进程已结束")
            else:
                logger.error("发生未知错误... 60s后退出")
                self.__wait(60)
                self.__del()

    def battle_selector(self, c_id, first_battle_signal=True):  # 选关
        logger.debug("base.battle_selector")
        assert (self.viewport == (1280, 720))
        mode = self.selector.id_checker(c_id)  # 获取当前关卡所属章节
        if mode == 1:
            if first_battle_signal:
                logger.info("发送坐标BATTLE_SELECT_MAIN_TASK: {}".format(
                    CLICK_LOCATION['BATTLE_SELECT_MAIN_TASK']))
                self.mouse_click(XY=CLICK_LOCATION['BATTLE_SELECT_MAIN_TASK'])
                logger.info(
                    "发送滑动坐标BATTLE_TO_MAP_LEFT: {}; FLAG=FLAGS_SWIPE_BIAS_TO_LEFT"
                    .format(SWIPE_LOCATION['BATTLE_TO_MAP_LEFT']))
                self.adb.touch_swipe(SWIPE_LOCATION['BATTLE_TO_MAP_LEFT'],
                                     FLAG=FLAGS_SWIPE_BIAS_TO_LEFT)

                # 拖动到正确的地方
                if c_id[0] in MAIN_TASK_CHAPTER_SWIPE.keys(
                ) or c_id[1] in MAIN_TASK_CHAPTER_SWIPE.keys():
                    if c_id[0].isnumeric():
                        x = MAIN_TASK_CHAPTER_SWIPE[c_id[0]]
                    else:
                        x = MAIN_TASK_CHAPTER_SWIPE[c_id[1]]
                    logger.info("拖动 {} 次".format(x))
                    for x in range(0, x):
                        logger.info(
                            "发送滑动坐标BATTLE_TO_MAP_RIGHT: {}; FLAG=FLAGS_SWIPE_BIAS_TO_RIGHT"
                            .format(SWIPE_LOCATION['BATTLE_TO_MAP_RIGHT']))
                        self.adb.touch_swipe(
                            SWIPE_LOCATION['BATTLE_TO_MAP_RIGHT'],
                            FLAG=FLAGS_SWIPE_BIAS_TO_RIGHT)
                        self.__wait(MEDIUM_WAIT)

                # 章节选择
                if c_id[0].isnumeric():
                    logger.info("发送坐标BATTLE_SELECT_MAIN_TASK_{}: {}".format(
                        c_id[0],
                        CLICK_LOCATION['BATTLE_SELECT_MAIN_TASK_{}'.format(
                            c_id[0])]))
                    self.mouse_click(XY=CLICK_LOCATION[
                        'BATTLE_SELECT_MAIN_TASK_{}'.format(c_id[0])])
                elif c_id[0] == "S":
                    logger.info("发送坐标BATTLE_SELECT_MAIN_TASK_{}: {}".format(
                        c_id[1],
                        CLICK_LOCATION['BATTLE_SELECT_MAIN_TASK_{}'.format(
                            c_id[1])]))
                    self.mouse_click(XY=CLICK_LOCATION[
                        'BATTLE_SELECT_MAIN_TASK_{}'.format(c_id[1])])
                else:
                    raise IndexError("C_ID Error")
                self.__wait(3)
                # 章节选择结束
                # 拖动
                logger.info(
                    "发送滑动坐标BATTLE_TO_MAP_LEFT: {}; FLAG=FLAGS_SWIPE_BIAS_TO_LEFT"
                    .format(SWIPE_LOCATION['BATTLE_TO_MAP_LEFT']))
                self.adb.touch_swipe(SWIPE_LOCATION['BATTLE_TO_MAP_LEFT'],
                                     FLAG=FLAGS_SWIPE_BIAS_TO_LEFT)
                self.__wait(SMALL_WAIT)
                logger.info(
                    "发送滑动坐标BATTLE_TO_MAP_LEFT: {}; FLAG=FLAGS_SWIPE_BIAS_TO_LEFT"
                    .format(SWIPE_LOCATION['BATTLE_TO_MAP_LEFT']))
                self.adb.touch_swipe(SWIPE_LOCATION['BATTLE_TO_MAP_LEFT'],
                                     FLAG=FLAGS_SWIPE_BIAS_TO_LEFT)
                self.__wait(SMALL_WAIT)
                logger.info(
                    "发送滑动坐标BATTLE_TO_MAP_LEFT: {}; FLAG=FLAGS_SWIPE_BIAS_TO_LEFT"
                    .format(SWIPE_LOCATION['BATTLE_TO_MAP_LEFT']))
                self.adb.touch_swipe(SWIPE_LOCATION['BATTLE_TO_MAP_LEFT'],
                                     FLAG=FLAGS_SWIPE_BIAS_TO_LEFT)

                # 拖动到正确的地方
                if c_id in MAIN_TASK_BATTLE_SWIPE.keys():
                    x = MAIN_TASK_BATTLE_SWIPE[c_id]
                    logger.info("拖动 {} 次".format(x))
                    for x in range(0, x):
                        logger.info(
                            "发送滑动坐标BATTLE_TO_MAP_RIGHT: {}; FLAG=FLAGS_SWIPE_BIAS_TO_RIGHT"
                            .format(SWIPE_LOCATION['BATTLE_TO_MAP_RIGHT']))
                        self.adb.touch_swipe(
                            SWIPE_LOCATION['BATTLE_TO_MAP_RIGHT'],
                            FLAG=FLAGS_SWIPE_BIAS_TO_RIGHT)
                        self.__wait(MEDIUM_WAIT)
                logger.info("发送坐标BATTLE_SELECT_MAIN_TASK_{}: {}".format(
                    c_id,
                    CLICK_LOCATION['BATTLE_SELECT_MAIN_TASK_{}'.format(c_id)]))
                self.mouse_click(XY=CLICK_LOCATION[
                    'BATTLE_SELECT_MAIN_TASK_{}'.format(c_id)])

            else:
                self.__wait(MEDIUM_WAIT)

        elif mode == 2:
            try:
                X = DAILY_LIST[str(mode)][self.selector.get_week()][c_id[0:2]]
            except Exception as e:
                logger.error('\tclick_location 文件配置错误', exc_info=True)
                X = None
                exit(0)
            if first_battle_signal:
                logger.info(
                    "发送滑动坐标BATTLE_TO_MAP_LEFT: {}; FLAG=FLAGS_SWIPE_BIAS_TO_LEFT"
                    .format(SWIPE_LOCATION['BATTLE_TO_MAP_LEFT']))
                self.adb.touch_swipe(SWIPE_LOCATION['BATTLE_TO_MAP_LEFT'],
                                     FLAG=FLAGS_SWIPE_BIAS_TO_LEFT)
                logger.info("发送坐标BATTLE_SELECT_MATERIAL_COLLECTION: {}".format(
                    CLICK_LOCATION['BATTLE_SELECT_MATERIAL_COLLECTION']))
                self.mouse_click(
                    XY=CLICK_LOCATION['BATTLE_SELECT_MATERIAL_COLLECTION'])
                logger.info(
                    "发送坐标BATTLE_SELECT_MATERIAL_COLLECTION_{}: {}".format(
                        X, CLICK_LOCATION[
                            'BATTLE_SELECT_MATERIAL_COLLECTION_{}'.format(X)]))
                self.mouse_click(XY=CLICK_LOCATION[
                    'BATTLE_SELECT_MATERIAL_COLLECTION_{}'.format(X)])
                logger.info(
                    "发送坐标BATTLE_SELECT_MATERIAL_COLLECTION_X-{}: {}".format(
                        c_id[-1], CLICK_LOCATION[
                            'BATTLE_SELECT_MATERIAL_COLLECTION_X-{}'.format(
                                c_id[-1])]))
                self.mouse_click(XY=CLICK_LOCATION[
                    'BATTLE_SELECT_MATERIAL_COLLECTION_X-{}'.format(c_id[-1])])
            else:
                logger.info(
                    "发送坐标BATTLE_SELECT_MATERIAL_COLLECTION_X-{}: {}".format(
                        c_id[-1], CLICK_LOCATION[
                            'BATTLE_SELECT_MATERIAL_COLLECTION_X-{}'.format(
                                c_id[-1])]))
                self.mouse_click(XY=CLICK_LOCATION[
                    'BATTLE_SELECT_MATERIAL_COLLECTION_X-{}'.format(c_id[-1])])
        elif mode == 3:
            try:
                X = DAILY_LIST[str(mode)][self.selector.get_week()][c_id[3]]
            except Exception as e:
                logger.error('\tclick_location 文件配置错误', exc_info=True)
                X = None
                exit(0)
            if first_battle_signal:
                logger.info("发送坐标BATTLE_SELECT_CHIP_SEARCH: {}".format(
                    CLICK_LOCATION['BATTLE_SELECT_CHIP_SEARCH']))
                self.mouse_click(
                    XY=CLICK_LOCATION['BATTLE_SELECT_CHIP_SEARCH'])
                logger.info("发送坐标BATTLE_SELECT_CHIP_SEARCH_PR-{}: {}".format(
                    X, CLICK_LOCATION['BATTLE_SELECT_CHIP_SEARCH_PR-{}'.format(
                        X)]))
                self.mouse_click(XY=CLICK_LOCATION[
                    'BATTLE_SELECT_CHIP_SEARCH_PR-{}'.format(X)])
                logger.info("发送坐标BATTLE_SELECT_CHIP_SEARCH_PR-X-{}: {}".format(
                    c_id[-1],
                    CLICK_LOCATION['BATTLE_SELECT_CHIP_SEARCH_PR-X-{}'.format(
                        c_id[-1])]))
                self.mouse_click(XY=CLICK_LOCATION[
                    'BATTLE_SELECT_CHIP_SEARCH_PR-X-{}'.format(c_id[-1])])
            else:
                logger.info("发送坐标BATTLE_SELECT_CHIP_SEARCH_PR-X-{}: {}".format(
                    c_id[-1],
                    CLICK_LOCATION['BATTLE_SELECT_CHIP_SEARCH_PR-X-{}'.format(
                        c_id[-1])]))
                self.mouse_click(XY=CLICK_LOCATION[
                    'BATTLE_SELECT_CHIP_SEARCH_PR-X-{}'.format(c_id[-1])])
        elif mode == 5:
            logger.info("发送坐标BATTLE_SELECT_HEART_OF_SURGING_FLAME: {}".format(
                CLICK_LOCATION["BATTLE_SELECT_HEART_OF_SURGING_FLAME"]))
            self.mouse_click(
                XY=CLICK_LOCATION["BATTLE_SELECT_HEART_OF_SURGING_FLAME"])
            logger.info("欢迎来到火蓝之心副本\n祝你在黑曜石音乐节上玩的愉快\n目前主舞台只支持OF-7,OF-8")
            try:
                if c_id[-2] == "F":
                    logger.info(
                        "发送坐标BATTLE_SELECT_HEART_OF_SURGING_FLAME_OF-F: {}".
                        format(CLICK_LOCATION[
                            "BATTLE_SELECT_HEART_OF_SURGING_FLAME_OF-F"]))
                    self.mouse_click(XY=CLICK_LOCATION[
                        "BATTLE_SELECT_HEART_OF_SURGING_FLAME_OF-F"])
                    logger.info(
                        "发送坐标BATTLE_SELECT_HEART_OF_SURGING_FLAME_{}: {}".
                        format(
                            c_id, CLICK_LOCATION[
                                "BATTLE_SELECT_HEART_OF_SURGING_FLAME_{}".
                                format(c_id)]))
                    self.mouse_click(XY=CLICK_LOCATION[
                        "BATTLE_SELECT_HEART_OF_SURGING_FLAME_{}".format(
                            c_id)])
                elif c_id[-2] == "-":
                    logger.info(
                        "发送坐标BATTLE_SELECT_HEART_OF_SURGING_FLAME_OF-: {}".
                        format(CLICK_LOCATION[
                            "BATTLE_SELECT_HEART_OF_SURGING_FLAME_OF-"]))
                    self.mouse_click(XY=CLICK_LOCATION[
                        "BATTLE_SELECT_HEART_OF_SURGING_FLAME_OF-"])

                    for x in range(0, 3):
                        logger.info(
                            "发送滑动坐标BATTLE_TO_MAP_RIGHT: {}; FLAG=FLAGS_SWIPE_BIAS_TO_RIGHT"
                            .format(SWIPE_LOCATION['BATTLE_TO_MAP_RIGHT']))
                        self.adb.touch_swipe(
                            SWIPE_LOCATION['BATTLE_TO_MAP_RIGHT'],
                            FLAG=FLAGS_SWIPE_BIAS_TO_RIGHT)
                        self.__wait(MEDIUM_WAIT)
                    logger.info(
                        "发送坐标BATTLE_SELECT_HEART_OF_SURGING_FLAME_{}: {}".
                        format(
                            c_id, CLICK_LOCATION[
                                "BATTLE_SELECT_HEART_OF_SURGING_FLAME_{}".
                                format(c_id)]))
                    self.mouse_click(XY=CLICK_LOCATION[
                        "BATTLE_SELECT_HEART_OF_SURGING_FLAME_{}".format(
                            c_id)])
                else:
                    logger.error('click_location 文件配置错误')
                    exit(0)
            except Exception as e:
                logger.error('click_location 文件配置错误', exc_info=True)
                exit(0)

    def clear_daily_task(self):
        logger.debug("base.clear_daily_task")
        logger.info("领取每日任务")
        self.back_to_main()
        screenshot = self.adb.get_screen_shoot()
        logger.info('进入任务界面')
        self.tap_quadrilateral(imgreco.main.get_task_corners(screenshot))
        self.__wait(SMALL_WAIT)
        screenshot = self.adb.get_screen_shoot()

        hasbeginner = imgreco.task.check_beginners_task(screenshot)
        if hasbeginner:
            logger.info('发现见习任务,切换到每日任务')
            self.tap_rect(
                imgreco.task.get_daily_task_rect(screenshot, hasbeginner))
            self.__wait(TINY_WAIT)

        while imgreco.task.check_collectable_reward(screenshot):
            logger.info('完成任务')
            self.tap_rect(
                imgreco.task.get_collect_reward_button_rect(self.viewport))
            self.__wait(SMALL_WAIT)
            while True:
                screenshot = self.adb.get_screen_shoot()
                if imgreco.common.check_get_item_popup(screenshot):
                    logger.info('领取奖励')
                    self.tap_rect(
                        imgreco.common.get_reward_popup_dismiss_rect(
                            self.viewport))
                    self.__wait(SMALL_WAIT)
                else:
                    break
            screenshot = self.adb.get_screen_shoot()
        logger.info("奖励已领取完毕")
コード例 #2
0
class ArknightsHelper(object):
    def __init__(self, current_strength=None, adb_host=None):
        if adb_host is None:
            adb_host = ADB_HOST
        self.adb = ADBShell(adb_host=adb_host)
        self.shell_color = ShellColor()
        self.__is_game_active = False
        self.__check_game_active()
        self.CURRENT_STRENGTH = 100
        self.selector = BattleSelector()
        self.ocr_active = False
        self.__is_ocr_active(current_strength)

    def __is_ocr_active(self, current_strength):
        os.popen(
            "tesseract {} {} --psm 7".format(
                STORAGE_PATH + "OCR_TEST_1.png", SCREEN_SHOOT_SAVE_PATH + "ocr_test_result"
            )
        )
        self.__wait(3)
        try:
            with open(SCREEN_SHOOT_SAVE_PATH + "ocr_test_result.txt", 'r', encoding="utf8") as f:
                tmp = f.read()
                test_1 = int(tmp.split("/")[0])
                if test_1 == 51:
                    self.ocr_active = True
                else:
                    self.shell_color.failure_text("[!] OCR 模块识别错误...装载初始理智值")
                    if current_strength is not None:
                        self.CURRENT_STRENGTH = current_strength
                    else:
                        self.shell_color.failure_text("[!] 未装载初始理智值,请在初始化Ark nights助手时候赋予初值")
                        exit(0)
        except Exception as e:
            self.shell_color.failure_text("[!] OCR 模块未检测...装载初始理智值")
            if current_strength is not None:
                self.CURRENT_STRENGTH = current_strength
            else:
                self.shell_color.failure_text("[!] 未装载初始理智值,请在初始化Ark nights助手时候赋予初值")
                exit(0)

    def __del(self):
        self.adb.ch_tools("shell")
        self.adb.ch_abd_command("am force-stop {}".format(ArkNights_PACKAGE_NAME))
        self.adb.run_cmd()

    def __check_apk_info_active(self):
        """
        IT IS JUST A HELPER FUNCTION
        :return:
        """
        self.adb.ch_tools("shell")
        self.adb.ch_abd_command("dumpsys window windows | findstr \"Current\" > {}"
                                .format(STORAGE_PATH + "package.txt"))
        self.adb.run_cmd(DEBUG_LEVEL=0)

    def __check_game_active(self):
        self.__check_apk_info_active()

        with open(STORAGE_PATH + "current.txt", 'r', encoding='utf8') as f:
            if ArkNights_PACKAGE_NAME in f.read():
                self.__is_game_active = True
            else:
                self.adb.ch_tools("shell")
                self.adb.ch_abd_command("am start -n {}/{}".format(ArkNights_PACKAGE_NAME, ArkNights_ACTIVITY_NAME))
                self.adb.run_cmd()
                self.__is_game_active = True

    @staticmethod
    def __wait(n=10, MANLIKE_FLAG=True):
        '''
        n的+-随机值服从均匀分布
        :param n:
        :param MANLIKE_FLAG:
        :return:
        '''
        if MANLIKE_FLAG:
            m = uniform(0, 0.3)
            n = uniform(n - m * 0.5 * n, n + m * n)
            sleep(n)
        else:
            sleep(n)

    def __simulate_man(self):
        '''
        模仿人操作,给检测机制提供一些困扰
        :return:
        '''
        action = randint(1, 4)
        if action == 1:
            pass
        elif action == 2:
            pass
        elif action == 3:
            pass
        elif action == 4:
            pass

    def module_login(self):
        self.__wait(SECURITY_WAIT)
        self.adb.get_mouse_click(
            XY=CLICK_LOCATION['LOGIN_QUICK_LOGIN']
        )
        self.__wait(SECURITY_WAIT)
        self.adb.get_mouse_click(
            XY=CLICK_LOCATION['LOGIN_START_WAKEUP']
        )
        self.__wait(SECURITY_WAIT)
        # self.adb.get_screen_shoot("login.png")

    def module_battle_slim(self, c_id, set_count=1000, set_ai=True, sub=False, auto_close=True):
        '''
        简单的战斗模式,请参考 Arknights README.md 中的使用方法调用
        该模块 略去了选关部分,直接开始打
        :param c_id: 关卡 ID
        :param set_count: 设置总次数
        :param set_ai: 是否设置代理指挥,默认已经设置
        :param sub: 是否是子程序。(是否为module_battle所调用的)
        :param auto_close: 是否自动关闭,默认为 True
        :return:
            True  当且仅当所有战斗计数达到设定值的时候
            False 当且仅当理智不足的时候
        '''
        if not sub:
            self.shell_color.helper_text("[+] 战斗-选择{}...启动!".format(c_id))
        if not set_ai:
            self.set_ai_commander(c_id=c_id, first_battle_signal=False)

        strength_end_signal = False
        count = 0
        while not strength_end_signal:
            # 初始化 变量
            battle_end_signal = False
            battle_end_signal_max_execute_time = BATTLE_END_SIGNAL_MAX_EXECUTE_TIME
            # 初始化 返回主页面

            # 查看理智剩余部分
            strength_end_signal = not self.check_current_strength(c_id)
            if strength_end_signal:
                return True
            # 查看理智剩余部分结束

            self.shell_color.info_text("[+] 开始战斗")
            self.adb.get_mouse_click(
                XY=CLICK_LOCATION['BATTLE_CLICK_START_BATTLE'], FLAG=FLAGS_START_BATTLE_BIAS
            )
            self.__wait(4, False)
            self.adb.get_mouse_click(
                XY=CLICK_LOCATION['BATTLE_CLICK_ENSURE_TEAM_INFO'], FLAG=FLAGS_ENSURE_TEAM_INFO_BIAS,
            )
            t = 0

            while not battle_end_signal:
                # 先打个60S,不检测
                if t == 0:
                    self.__wait(60)
                    t += 60
                else:
                    self.__wait(BATTLE_FINISH_DETECT)
                t += BATTLE_FINISH_DETECT
                self.shell_color.helper_text("[*] 战斗进行{}S 判断是否结束".format(t))

                # 升级的情况
                self.adb.get_screen_shoot(
                    file_name="level_up_real_time.png",
                    screen_range=MAP_LOCATION['BATTLE_INFO_LEVEL_UP']
                )
                num = self.adb.img_difference(img1=SCREEN_SHOOT_SAVE_PATH + "level_up_real_time.png",
                                              img2=STORAGE_PATH + "BATTLE_INFO_BATTLE_END_LEVEL_UP.png")
                if num > .7:
                    battle_end_signal = True
                    self.__wait(SMALL_WAIT, MANLIKE_FLAG=True)
                    self.adb.shell_color.helper_text("[*] 检测到升级!")
                    self.adb.get_mouse_click(
                        XY=CLICK_LOCATION['CENTER_CLICK'], FLAG=(400, 150)
                    )
                    self.__wait(SMALL_WAIT, MANLIKE_FLAG=True)
                    self.adb.get_mouse_click(
                        XY=CLICK_LOCATION['CENTER_CLICK'], FLAG=(200, 150)
                    )
                    self.__wait(SMALL_WAIT, MANLIKE_FLAG=True)
                else:
                    self.adb.get_screen_shoot(
                        file_name="battle_end.png",
                        screen_range=MAP_LOCATION['BATTLE_INFO_BATTLE_END']
                    )

                    if self.adb.img_difference(
                            img1=SCREEN_SHOOT_SAVE_PATH + "battle_end.png",
                            img2=STORAGE_PATH + "BATTLE_INFO_BATTLE_END_TRUE.png"
                    ) >= 0.8:
                        battle_end_signal = True
                        self.adb.get_mouse_click(
                            XY=CLICK_LOCATION['CENTER_CLICK'], FLAG=(200, 150)
                            # 点到了经验尝试降低从(200, 200)降低(200, 150)
                        )
                    else:
                        battle_end_signal_max_execute_time -= 1
                    if battle_end_signal_max_execute_time < 1:
                        self.shell_color.failure_text("[!] 超过最大战斗时常,默认战斗结束")
                        battle_end_signal = True

            count += 1
            self.shell_color.info_text("[*] 当前战斗次数  {}".format(count))

            if count >= set_count:
                strength_end_signal = True
            self.shell_color.info_text("[-] 战斗结束 重新开始")
            self.__wait(10, MANLIKE_FLAG=True)

        if not sub:
            if auto_close:
                self.shell_color.helper_text("[+] 简略模块结束,系统准备退出".format(c_id))
                self.__wait(120, False)
                self.__del()
            else:
                return False
        else:
            return False

    def module_battle(self, c_id, set_count=1000):
        '''
            保留 first_battle_signal 尽管这样的代码有些冗余但是可能会在之后用到。
        :param c_id:
        :param set_count:
        :return:
        '''
        self.__wait(3, MANLIKE_FLAG=False)
        self.selector.id = c_id
        strength_end_signal = False
        first_battle_signal = True
        while not strength_end_signal:
            # 初始化 返回主页面
            if first_battle_signal:
                for i in range(4):
                    self.adb.get_mouse_click(
                        XY=CLICK_LOCATION['MAIN_RETURN_INDEX'], FLAG=None
                    )
                # 进入战斗选择页面
                self.adb.get_mouse_click(
                    XY=CLICK_LOCATION['BATTLE_CLICK_IN']
                )

            # 选关部分
            self.battle_selector(c_id, first_battle_signal)
            # 选关结束
            strength_end_signal = self.module_battle_slim(c_id, set_count=set_count, set_ai=False, sub=True)
            first_battle_signal = False
        return True

    def main_handler(self, battle_task_list=None):
        if battle_task_list == None:
            battle_task_list = OrderedDict()

        self.shell_color.warning_text("[*] 装在模块....")
        self.shell_color.warning_text("[+] 战斗模块...启动!")
        flag = False
        if battle_task_list.__len__() == 0:
            self.shell_color.failure_text("[!] ⚠ 任务清单为空")

        for c_id, count in battle_task_list.items():
            if c_id not in LIZHI_CONSUME.keys():
                raise IndexError("无此关卡")
            self.shell_color.helper_text("[+] 战斗-选择{}...启动!".format(c_id))
            self.selector.id = c_id
            flag = self.module_battle(c_id, count)
            # flag = self.module_battle_for_test(c_id, count)

        if flag:
            self.shell_color.warning_text("[*] 所有模块执行完毕...无限休眠启动!")
            self.__wait(1024)
            self.shell_color.failure_text("[*] 休眠过度...启动自毁程序!")
            self.__del()
        else:
            self.shell_color.failure_text("[*] 未知模块异常...无限休眠启动!")
            self.__wait(1024)
            self.shell_color.failure_text("[*] 休眠过度...启动自毁程序!")
            self.__del()

    def restart(self):
        '''
        由于重启的逻辑比较困难,暂时废弃这里的功能
        :return:
        '''
        self.shell_color.failure_text("[!] 检测异常发生 重新唤醒所有模块")
        self.__del()
        self.__init__()
        self.shell_color.warning_text("[+] 正在唤醒...明日方舟...")
        self.module_login()
        self.main_handler()

    def __module_battle_for_test(self, c_id, set_count=1000):
        strength_end_signal = False
        first_battle_signal = True
        count = 0
        while not strength_end_signal:
            # 初始化 变量
            # 战斗状态存活检测
            # 初始化 返回主页面
            if first_battle_signal:
                for i in range(4):
                    self.adb.get_mouse_click(
                        XY=CLICK_LOCATION['MAIN_RETURN_INDEX'], FLAG=None
                    )
                # 进入战斗选择页面
                self.adb.get_mouse_click(
                    XY=CLICK_LOCATION['BATTLE_CLICK_IN']
                )
            # 选关部分
            self.battle_selector(c_id, first_battle_signal)
            # 选关结束
            count += 1
            self.shell_color.info_text("[*] 当前战斗次数  {}".format(count))
            if count >= set_count:
                strength_end_signal = True
            first_battle_signal = False
            self.shell_color.info_text("[-] 战斗结束 重新开始")
        return True

    def set_ai_commander(self, c_id, first_battle_signal=False):
        if first_battle_signal:
            self.adb.get_screen_shoot('{}.png'.format(c_id), MAP_LOCATION['BATTLE_CLICK_AI_COMMANDER'])
            if self.adb.img_difference(
                    SCREEN_SHOOT_SAVE_PATH + "{}.png".format(c_id),
                    STORAGE_PATH + "BATTLE_CLICK_AI_COMMANDER_TRUE.png"
            ) <= 0.8:
                self.shell_color.helper_text("[-] 代理指挥未设置,设置代理指挥")
                self.adb.get_mouse_click(
                    XY=CLICK_LOCATION['BATTLE_CLICK_AI_COMMANDER']
                )
            else:
                self.shell_color.helper_text("[+] 代理指挥已设置")

    def check_current_strength(self, c_id):
        if self.ocr_active:
            sleep(4)
            self.adb.get_screen_shoot(
                file_name="strength.png", screen_range=MAP_LOCATION["BATTLE_INFO_STRENGTH_REMAIN"]
            )
            os.popen(
                "tesseract {} {} --psm 7".format(
                    SCREEN_SHOOT_SAVE_PATH + "strength.png", SCREEN_SHOOT_SAVE_PATH + "1"
                )
            )
            self.__wait(3)
            with open(SCREEN_SHOOT_SAVE_PATH + "1.txt", 'r', encoding="utf8") as f:
                tmp = f.read()  #
                try:
                    self.CURRENT_STRENGTH = int(tmp.split("/")[0])
                    self.shell_color.helper_text("[+] 理智剩余 {}".format(self.CURRENT_STRENGTH))
                except Exception as e:
                    self.shell_color.failure_text("[!] {}".format(e))
                    self.CURRENT_STRENGTH -= LIZHI_CONSUME[c_id]
        else:
            self.CURRENT_STRENGTH -= LIZHI_CONSUME[c_id]
            self.shell_color.warning_text("[*] OCR 模块为装载,系统将直接计算理智值")
            self.__wait(TINY_WAIT)
            self.shell_color.helper_text("[+] 理智剩余 {}".format(self.CURRENT_STRENGTH))

        if self.CURRENT_STRENGTH - LIZHI_CONSUME[c_id] < 0:
            self.shell_color.failure_text("[!] 理智不足 退出战斗")
            return False
        else:
            return True
            # 理智不够退出战斗

    def battle_selector(self, c_id, first_battle_signal=True):
        mode = self.selector.id_checker()
        if mode == 1:
            if first_battle_signal:
                self.adb.get_mouse_swipe(SWIPE_LOCATION['BATTLE_TO_MAP_LEFT'], FLAG=FLAGS_SWIPE_BIAS_TO_LEFT)
                self.adb.get_mouse_click(
                    XY=CLICK_LOCATION['BATTLE_SELECT_MAIN_TASK']
                )

                # 拖动到正确的地方
                if c_id[0] in MAIN_TASK_CHAPTER_SWIPE.keys() or c_id[1] in MAIN_TASK_CHAPTER_SWIPE.keys():
                    if c_id[0].isnumeric():
                        x = MAIN_TASK_CHAPTER_SWIPE[c_id[0]]
                    else:
                        x = MAIN_TASK_CHAPTER_SWIPE[c_id[1]]
                    self.shell_color.helper_text("[-] 拖动%{}次".format(x))
                    for x in range(0, x):
                        self.adb.get_mouse_swipe(SWIPE_LOCATION['BATTLE_TO_MAP_RIGHT'], FLAG=FLAGS_SWIPE_BIAS_TO_RIGHT)
                        self.__wait(MEDIUM_WAIT)

                # 章节选择
                if c_id[0].isnumeric():
                    self.adb.get_mouse_click(
                        XY=CLICK_LOCATION['BATTLE_SELECT_MAIN_TASK_{}'.format(c_id[0])]
                    )
                elif c_id[0] == "S":
                    self.adb.get_mouse_click(
                        XY=CLICK_LOCATION['BATTLE_SELECT_MAIN_TASK_{}'.format(c_id[1])]
                    )
                else:
                    raise IndexError("C_ID Error")
                self.__wait(3)
                # 章节选择结束
                # 拖动
                self.adb.get_mouse_swipe(SWIPE_LOCATION['BATTLE_TO_MAP_LEFT'], FLAG=FLAGS_SWIPE_BIAS_TO_LEFT)
                sleep(SMALL_WAIT)
                self.adb.get_mouse_swipe(SWIPE_LOCATION['BATTLE_TO_MAP_LEFT'], FLAG=FLAGS_SWIPE_BIAS_TO_LEFT)
                sleep(SMALL_WAIT)
                self.adb.get_mouse_swipe(SWIPE_LOCATION['BATTLE_TO_MAP_LEFT'], FLAG=FLAGS_SWIPE_BIAS_TO_LEFT)

                # 拖动到正确的地方
                if c_id in MAIN_TASK_BATTLE_SWIPE.keys():
                    x = MAIN_TASK_BATTLE_SWIPE[c_id]
                    self.shell_color.helper_text("[-] 拖动%{}次".format(x))
                    for x in range(0, x):
                        self.adb.get_mouse_swipe(SWIPE_LOCATION['BATTLE_TO_MAP_RIGHT'], FLAG=FLAGS_SWIPE_BIAS_TO_RIGHT)
                        # self.__wait(MEDIUM_WAIT)
                        sleep(5)
                self.adb.get_mouse_click(
                    XY=CLICK_LOCATION['BATTLE_SELECT_MAIN_TASK_{}'.format(c_id)]
                )

            else:
                sleep(5)
                # 好像打过了就不用再点了,直接PASS就行
                # self.adb.get_mouse_swipe(SWIPE_LOCATION['BATTLE_TO_MAP_LEFT'], FLAG=FLAGS_SWIPE_BIAS_TO_LEFT)
                # if c_id in MAIN_TASK_RELOCATE.keys():
                #     self.adb.get_mouse_click(MAIN_TASK_RELOCATE[c_id])
                # else:
                #     self.adb.get_mouse_click(
                #         XY=CLICK_LOCATION['BATTLE_SELECT_MAIN_TASK_{}'.format(c_id)]
                #     )

        elif mode == 2:
            try:

                X = DAILY_LIST[mode][self.selector.get_week()][c_id[0:2]]
            except Exception as e:
                self.shell_color.failure_text(e.__str__() + '\tclick_location 文件配置错误')
                X = None
                exit(0)
            if first_battle_signal:
                self.adb.get_mouse_swipe(SWIPE_LOCATION['BATTLE_TO_MAP_LEFT'], FLAG=FLAGS_SWIPE_BIAS_TO_LEFT)
                self.adb.get_mouse_click(
                    XY=CLICK_LOCATION['BATTLE_SELECT_MATERIAL_COLLECTION']
                )
                self.adb.get_mouse_click(
                    XY=CLICK_LOCATION['BATTLE_SELECT_MATERIAL_COLLECTION_{}'.format(X)]
                )
                self.adb.get_mouse_click(
                    XY=CLICK_LOCATION['BATTLE_SELECT_MATERIAL_COLLECTION_X-{}'.format(c_id[-1])]
                )
            else:
                self.adb.get_mouse_click(
                    XY=CLICK_LOCATION['BATTLE_SELECT_MATERIAL_COLLECTION_X-{}'.format(c_id[-1])]
                )
        elif mode == 3:
            try:
                X = DAILY_LIST[mode][self.selector.get_week()][c_id[3]]
            except Exception as e:
                self.shell_color.failure_text(e.__str__() + '\tclick_location 文件配置错误')
                X = None
                exit(0)
            if first_battle_signal:
                self.adb.get_mouse_click(
                    XY=CLICK_LOCATION['BATTLE_SELECT_CHIP_SEARCH']
                )
                self.adb.get_mouse_click(
                    XY=CLICK_LOCATION['BATTLE_SELECT_CHIP_SEARCH_PR-{}'.format(X)]
                )
                self.adb.get_mouse_click(
                    XY=CLICK_LOCATION['BATTLE_SELECT_CHIP_SEARCH_PR-X-{}'.format(c_id[-1])]
                )
            else:
                self.adb.get_mouse_click(
                    XY=CLICK_LOCATION['BATTLE_SELECT_CHIP_SEARCH_PR-X-{}'.format(c_id[-1])]
                )
コード例 #3
0
class ArknightsHelper(object):
    def __init__(self, current_strength=None, adb_host=None,
                 out_put=0, call_by_gui=False):
        '''
        :param current_strength:
        :param adb_host:
        :param out_put:  0 default with console
                          1 no out put
        '''
        if adb_host is None:
            adb_host = ADB_HOST
        self.adb = ADBShell(adb_host=adb_host)
        self.shell_color = ShellColor() if out_put == 0 else BufferColor()
        self.__is_game_active = False
        self.__call_by_gui = call_by_gui
        self.__rebase_to_null = " 1>nul 2>nul" if "win" in os.sys.platform else " 1>/dev/null 2>/dev/null &" \
            if enable_rebase_to_null else ""
        self.CURRENT_STRENGTH = 100
        self.selector = BattleSelector()
        self.ocr_active = True
        self.is_call_by_gui = call_by_gui
        # 为了让 GUI 启动快一些,这里关闭了激活ocr的选项以及确认游戏开启的设置
        if not call_by_gui:
            self.is_ocr_active(current_strength)
            # self.check_game_active()

    def __ocr_check(self, file_path, save_path, option=None, change_image=True):
        """
        选择百度ocr识别,还是tesseract识别;以及图片二值化是否开启,
        :param file_path: ocr识别图片路径
        :param save_path: ocr结果保存路径,建议使用txt跟tesseract同一
        :param option: 对tesseract的命令传递
        :param change_image:是否进行二值化,默认使用二值化
        :return:
        """
        global enable_api
        if change_image:
            binarization_image(file_path)
        if enable_api:
            try:
                ocr(file_path, save_path + ".txt")
            except ConnectionError:
                self.shell_color.failure_text("[!] 百度API无法连接")
                enable_api = False
                self.shell_color.helper_text("继续使用tesseract")
                if option is not None:
                    option = " " + option
                os.popen(
                    "tesseract {} {}{}".format(file_path, save_path, option) + self.__rebase_to_null
                )
                self.__wait(3)
        else:
            if option is not None:
                option = " " + option
            os.popen(
                "tesseract {} {}{}".format(file_path, save_path, option) + self.__rebase_to_null
            )
            self.__wait(3)

    def is_ocr_active(self, current_strength):
        """
        启用ocr判断
        :param current_strength: 当前理智
        :return:
        """
        global enable_api
        self.__ocr_check(STORAGE_PATH + "OCR_TEST_1.png", SCREEN_SHOOT_SAVE_PATH + "ocr_test_result", "--psm 7",
                         change_image=False)
        try:
            with open(SCREEN_SHOOT_SAVE_PATH + "ocr_test_result.txt", 'r', encoding="utf8") as f:
                tmp = f.read()
                test_1 = int(tmp.split("/")[0])
                if test_1 == 51:
                    self.ocr_active = True
                else:
                    # 如果启动了api检测失误的话,关闭api
                    if enable_api:
                        enable_api = False
                    self.shell_color.failure_text("[!] OCR 模块识别错误...装载初始理智值")
                    if current_strength is not None:
                        self.CURRENT_STRENGTH = current_strength
                    else:
                        self.shell_color.failure_text("[!] 未装载初始理智值,请在初始化Ark nights助手时候赋予初值")
                        if not self.is_call_by_gui:
                            exit(0)
                        else:
                            return False
        except Exception as e:
            self.shell_color.failure_text("[!] OCR 模块未检测...装载初始理智值")
            if current_strength is not None:
                self.CURRENT_STRENGTH = current_strength
            else:
                self.shell_color.failure_text("[!] 未装载初始理智值,请在初始化Ark nights助手时候赋予初值")
                if not self.is_call_by_gui:
                    exit(0)
                else:
                    return False

    def __del(self):
        self.adb.ch_tools("shell")
        self.adb.ch_abd_command("am force-stop {}".format(ArkNights_PACKAGE_NAME))
        self.adb.run_cmd()

    def destroy(self):
        self.__del()

    def __check_apk_info_active(self):
        """
        IT IS JUST A HELPER FUNCTION
        :return:
        """
        self.adb.ch_tools("shell")
        self.adb.ch_abd_command("dumpsys window windows | findstr \"Current\" > {}"
                                .format(STORAGE_PATH + "package.txt"))
        self.adb.run_cmd(DEBUG_LEVEL=0)

    def check_game_active(self):
        '''
        该命令是启动 官服的 明日方舟的函数
        在之后的GUI里调用。启动脚本的时候不调用了。默认你已经打开了
        :return:
        '''
        # self.__check_apk_info_active()

        with open(STORAGE_PATH + "current.txt", 'r', encoding='utf8') as f:
            if ArkNights_PACKAGE_NAME in f.read():
                self.__is_game_active = True
            else:
                self.adb.ch_tools("shell")
                self.adb.ch_abd_command("am start -n {}/{}".format(ArkNights_PACKAGE_NAME, ArkNights_ACTIVITY_NAME))
                self.adb.run_cmd()
                self.__is_game_active = True

    @staticmethod
    def __wait(n=10, MANLIKE_FLAG=True):
        """
        n的+-随机值服从均匀分布
        :param n:
        :param MANLIKE_FLAG:
        :return:
        """
        if MANLIKE_FLAG:
            m = uniform(0, 0.3)
            n = uniform(n - m * 0.5 * n, n + m * n)
            sleep(n)
        else:
            sleep(n)

    def __simulate_man(self):
        """
        模仿人操作,给检测机制提供一些困扰
        :return:
        """
        action = randint(1, 4)
        if action == 1:
            pass
        elif action == 2:
            pass
        elif action == 3:
            pass
        elif action == 4:
            pass

    def module_login(self):
        self.__wait(SECURITY_WAIT)
        self.adb.get_mouse_click(
            XY=CLICK_LOCATION['LOGIN_QUICK_LOGIN']
        )
        self.__wait(SECURITY_WAIT)
        self.adb.get_mouse_click(
            XY=CLICK_LOCATION['LOGIN_START_WAKEUP']
        )
        self.__wait(SECURITY_WAIT)

    def module_battle_slim(self, c_id, set_count=1000, set_ai=False, **kwargs):
        """
        简单的战斗模式,请参考 Arknights README.md 中的使用方法调用
        该模块 略去了选关部分,直接开始打
        :param c_id: 关卡 ID
        :param set_count: 设置总次数
        :param set_ai: 是否设置代理指挥,默认没有设置
                        True 的时候,系统不会判断 AI 是否设置
                        False 的时候,系统会判断 AI 是否设置,所以省略不写该参数事一个比较保险的选择
        扩展参数
        :param sub: 是否是子程序。(是否为module_battle所调用的)
        :param auto_close: 是否自动关闭,默认为 False
        :param self_fix: 是否自动修复,默认为 False
                            该参数如果设置为 True 会在安装OCR模块且获取理智失败的情况下进入DEBUG逻辑
                            目前只支持不小心点到素材页面导致卡死的状况
        :param MAX_TIME: 最大迭代次数,默认为config的设置
                            该次数 * 14 S  + 60 得到每次战斗的最长时间
                            建议自定义这个数值,如果出现一定失误,超出最大判断次数后有一定的自我修复能力
        :return:
            True  当且仅当所有战斗计数达到设定值的时候
            False 当且仅当理智不足的时候
        """
        if "sub" in kwargs.keys():
            sub = kwargs['sub']
        else:
            sub = False
        if "auto_close" in kwargs.keys():
            auto_close = kwargs['auto_close']
        else:
            auto_close = True
        if "self_fix" in kwargs.keys():
            self_fix = kwargs['self_fix']
        else:
            self_fix = False
        if not sub:
            self.shell_color.helper_text("[+] 战斗-选择{}...启动!".format(c_id))
        if not set_ai:
            self.set_ai_commander()

        strength_end_signal = False
        count = 0
        while not strength_end_signal:
            # 初始化 变量
            battle_end_signal = False
            if "MAX_TIME" in kwargs.keys():
                battle_end_signal_max_execute_time = kwargs["MAX_TIME"]
            else:
                battle_end_signal_max_execute_time = BATTLE_END_SIGNAL_MAX_EXECUTE_TIME
            # 查看理智剩余部分
            strength_end_signal = not self.check_current_strength(c_id, self_fix)
            if strength_end_signal:
                return True
            # 查看理智剩余部分结束

            self.shell_color.info_text("[+] 开始战斗")
            self.adb.get_mouse_click(
                XY=CLICK_LOCATION['BATTLE_CLICK_START_BATTLE'], FLAG=FLAGS_START_BATTLE_BIAS
            )
            self.__wait(4, False)
            self.adb.get_mouse_click(
                XY=CLICK_LOCATION['BATTLE_CLICK_ENSURE_TEAM_INFO'], FLAG=FLAGS_ENSURE_TEAM_INFO_BIAS,
            )
            t = 0

            while not battle_end_signal:
                # 先打个60S,不检测
                if t == 0:
                    self.__wait(60)
                    t += 60
                else:
                    self.__wait(BATTLE_FINISH_DETECT)
                t += BATTLE_FINISH_DETECT
                self.shell_color.helper_text("[*] 战斗进行{}S 判断是否结束".format(t))
                # 升级的情况
                self.adb.get_screen_shoot(
                    file_name="level_up_real_time.png",
                    screen_range=MAP_LOCATION['BATTLE_INFO_LEVEL_UP']
                )
                level_up_signal = False
                level_up_num = 0
                # 检测是否启动ocr检查升级情况
                if enable_ocr_check_update:
                    self.__ocr_check(SCREEN_SHOOT_SAVE_PATH + "level_up_real_time.png",
                                     SCREEN_SHOOT_SAVE_PATH + "1",
                                     "--psm 7 -l chi_sim")
                    level_up_text = "等级提升"
                    f = open(SCREEN_SHOOT_SAVE_PATH + "1.txt", 'r', encoding="utf8")
                    tmp = f.readline()
                    if level_up_text in tmp:
                        level_up_signal = True
                else:
                    level_up_num = self.adb.img_difference(img1=SCREEN_SHOOT_SAVE_PATH + "level_up_real_time.png",
                                                           img2=STORAGE_PATH + "BATTLE_INFO_BATTLE_END_LEVEL_UP.png")
                if level_up_num > .7 or level_up_signal:
                    battle_end_signal = True
                    self.__wait(SMALL_WAIT, MANLIKE_FLAG=True)
                    self.adb.shell_color.helper_text("[*] 检测到升级!")
                    self.adb.get_mouse_click(
                        XY=CLICK_LOCATION['CENTER_CLICK'], FLAG=(200, 150)
                    )
                    self.__wait(SMALL_WAIT, MANLIKE_FLAG=True)
                    self.adb.get_mouse_click(
                        XY=CLICK_LOCATION['CENTER_CLICK'], FLAG=(200, 150)
                    )
                    self.__wait(SMALL_WAIT, MANLIKE_FLAG=True)
                else:
                    # 检测游戏是否结束
                    self.adb.get_screen_shoot(
                        file_name="battle_end.png",
                        screen_range=MAP_LOCATION['BATTLE_INFO_BATTLE_END']
                    )
                    end_num = 0
                    end_signal = False

                    if enable_ocr_check_end:
                        self.__ocr_check(SCREEN_SHOOT_SAVE_PATH + "battle_end.png",
                                         SCREEN_SHOOT_SAVE_PATH + "1",
                                         "--psm 7 -l chi_sim")
                        end_text = "行动结束"
                        f = open(SCREEN_SHOOT_SAVE_PATH + "1.txt", 'r', encoding="utf8")
                        tmp = f.readline()
                        if end_text in tmp:
                            end_signal = True
                    else:
                        end_num = self.adb.img_difference(
                            img1=SCREEN_SHOOT_SAVE_PATH + "battle_end.png",
                            img2=STORAGE_PATH + "BATTLE_INFO_BATTLE_END_TRUE.png")

                    if end_num >= 0.8 or end_signal:
                        battle_end_signal = True
                        self.adb.get_mouse_click(
                            XY=CLICK_LOCATION['CENTER_CLICK'], FLAG=(200, 150)
                            # 点到了经验尝试降低从(200, 200)降低(200, 150)
                        )
                    else:
                        battle_end_signal_max_execute_time -= 1
                    if battle_end_signal_max_execute_time < 1:
                        self.shell_color.failure_text("[!] 超过最大战斗时常")  # 推测BUG发生,启动自检测模块")
                        battle_end_signal = True

            count += 1
            self.shell_color.info_text("[*] 当前战斗次数  {}".format(count))

            if count >= set_count:
                strength_end_signal = True
            self.shell_color.info_text("[-] 战斗结束 重新开始")
            self.__wait(10, MANLIKE_FLAG=True)

        if not sub:
            if auto_close:
                self.shell_color.helper_text("[+] 简略模块结束,系统准备退出".format(c_id))
                self.__wait(120, False)
                self.__del()
            else:
                self.shell_color.helper_text("[+] 简略模块结束")
                return True
        else:
            self.shell_color.helper_text("[+] 当前任务清单 {} 结束,准备执行下一任务".format(c_id))
            return True

    def __check_is_on_setting(self):
        """
        检查是否在设置页面
        :return: True 如果在设置页面
        """
        self.adb.get_screen_shoot(
            'is_setting.png', MAP_LOCATION['INDEX_INFO_IS_SETTING']
        )
        if enable_ocr_debugger:
            self.__ocr_check(SCREEN_SHOOT_SAVE_PATH + "is_setting.png",
                             SCREEN_SHOOT_SAVE_PATH + "1",
                             "--psm 7 -l chi_sim")
            end_text = "保持"
            f = open(SCREEN_SHOOT_SAVE_PATH + "1.txt", 'r', encoding="utf8")
            tmp = f.readline()
            if end_text in tmp:
                return True
            else:
                return False
        else:
            if self.adb.img_difference(
                    img1=STORAGE_PATH + "INDEX_INFO_IS_SETTING.png",
                    img2=SCREEN_SHOOT_SAVE_PATH + "is_setting.png"
            ) > .85:
                return True
            else:
                return False

    def module_battle(self, c_id, set_count=1000):
        """
            保留 first_battle_signal 尽管这样的代码有些冗余但是可能会在之后用到。
        :param c_id:
        :param set_count:
        :return:
        """
        self.__wait(3, MANLIKE_FLAG=False)
        self.selector.id = c_id
        # 初始化 返回主页面
        for i in range(3):
            self.adb.get_mouse_click(
                XY=CLICK_LOCATION['MAIN_RETURN_INDEX'], FLAG=None
            )
        if self.__check_is_on_setting():
            self.shell_color.helper_text("[=] 不小心点到设置了,点击返回")
            self.adb.get_mouse_click(
                XY=CLICK_LOCATION['MAIN_RETURN_INDEX'], FLAG=None
            )
        # 进入战斗选择页面
        self.adb.get_mouse_click(
            XY=CLICK_LOCATION['BATTLE_CLICK_IN']
        )

        # 选关部分
        self.battle_selector(c_id)
        # 选关结束
        self.module_battle_slim(c_id, set_count=set_count, set_ai=False, sub=True,
                                self_fix=self.ocr_active)
        return True

    def main_handler(self, battle_task_list=None):
        if battle_task_list is None:
            battle_task_list = OrderedDict()

        self.shell_color.warning_text("[*] 装在模块....")
        self.shell_color.warning_text("[+] 战斗模块...启动!")
        flag = False
        if battle_task_list.__len__() == 0:
            self.shell_color.failure_text("[!] ⚠ 任务清单为空")

        for c_id, count in battle_task_list.items():
            if c_id not in LIZHI_CONSUME.keys():
                raise IndexError("无此关卡")
            self.shell_color.helper_text("[+] 战斗-选择{}...启动!".format(c_id))
            self.selector.id = c_id
            flag = self.module_battle(c_id, count)
            # flag = self.module_battle_for_test(c_id, count)

        if flag:
            self.shell_color.warning_text("[*] 所有模块执行完毕...无限休眠启动!")
            if not self.__call_by_gui:
                self.__wait(1024)
                self.shell_color.failure_text("[*] 休眠过度...启动自毁程序!")
                self.__del()
        else:
            self.shell_color.failure_text("[*] 未知模块异常...无限休眠启动!")
            self.__wait(1024)
            self.shell_color.failure_text("[*] 休眠过度...启动自毁程序!")
            self.__del()

    def restart(self):
        """
        由于重启的逻辑比较困难,暂时废弃这里的功能
        :return:
        """
        self.shell_color.failure_text("[!] 检测异常发生 重新唤醒所有模块")
        self.__del()
        self.__init__()
        self.shell_color.warning_text("[+] 正在唤醒...明日方舟...")
        self.module_login()
        self.main_handler()

    def set_ai_commander(self):
        self.adb.get_screen_shoot('is_ai.png', MAP_LOCATION['BATTLE_CLICK_AI_COMMANDER'])
        if self.adb.img_difference(
                SCREEN_SHOOT_SAVE_PATH + "is_ai.png",
                STORAGE_PATH + "BATTLE_CLICK_AI_COMMANDER_TRUE.png"
        ) <= 0.8:
            self.shell_color.helper_text("[-] 代理指挥未设置,设置代理指挥")
            self.adb.get_mouse_click(
                XY=CLICK_LOCATION['BATTLE_CLICK_AI_COMMANDER']
            )
        else:
            self.shell_color.helper_text("[+] 代理指挥已设置")

    def __check_current_strength(self):
        """
        简易的模式,在debug后重新启动
        :return:
        """
        assert self.ocr_active
        sleep(4)
        self.adb.get_screen_shoot(
            file_name="strength.png", screen_range=MAP_LOCATION["BATTLE_INFO_STRENGTH_REMAIN"]
        )
        self.__ocr_check(SCREEN_SHOOT_SAVE_PATH + "strength.png", SCREEN_SHOOT_SAVE_PATH + "1", "--psm 7")
        with open(SCREEN_SHOOT_SAVE_PATH + "1.txt", 'r', encoding="utf8") as f:
            tmp = f.read()  #
            try:
                self.CURRENT_STRENGTH = int(tmp.split("/")[0])
                self.shell_color.helper_text("[+] 理智剩余 {}".format(self.CURRENT_STRENGTH))
                return True
            except Exception as e:
                self.shell_color.failure_text("[!] {}".format(e))
                return False

    def __check_current_strength_debug(self):
        # 查看是否在素材页面
        self.shell_color.helper_text("[+] 启动自修复模块,检查是否停留在素材页面")
        self.adb.get_screen_shoot(
            file_name="debug.png",
            screen_range=MAP_LOCATION['BATTLE_DEBUG_WHEN_OCR_ERROR']
        )
        if enable_ocr_debugger:
            self.__ocr_check(SCREEN_SHOOT_SAVE_PATH + "debug.png",
                             SCREEN_SHOOT_SAVE_PATH + "debug",
                             "--psm 7 -l chi_sim")
            end_text = "首次掉落"
            f = open(SCREEN_SHOOT_SAVE_PATH + "debug.txt", 'r', encoding="utf8")
            tmp = f.readline()
            if end_text in tmp:
                self.shell_color.helper_text("[$] 检测 BUG 成功,系统停留在素材页面,请求返回...")
                self.adb.get_mouse_click(CLICK_LOCATION['MAIN_RETURN_INDEX'], FLAG=None)
                self.__check_current_strength()
            else:
                self.shell_color.failure_text("[-] 检测 BUG 失败,系统将继续执行任务")
        else:
            if self.adb.img_difference(
                    img1=SCREEN_SHOOT_SAVE_PATH + "debug.png",
                    img2=STORAGE_PATH + "BATTLE_DEBUG_CHECK_LOCATION_IN_SUCAI.png"
            ) > 0.75:
                self.shell_color.helper_text("[$] 检测 BUG 成功,系统停留在素材页面,请求返回...")
                self.adb.get_mouse_click(CLICK_LOCATION['MAIN_RETURN_INDEX'], FLAG=None)
                self.__check_current_strength()
            else:
                self.shell_color.failure_text("[-] 检测 BUG 失败,系统将继续执行任务")

    def check_current_strength(self, c_id, self_fix=False):
        if self.ocr_active:
            sleep(4)
            self.adb.get_screen_shoot(
                file_name="strength.png", screen_range=MAP_LOCATION["BATTLE_INFO_STRENGTH_REMAIN"]
            )
            self.__ocr_check(SCREEN_SHOOT_SAVE_PATH + "strength.png", SCREEN_SHOOT_SAVE_PATH + "1", "--psm 7")
            with open(SCREEN_SHOOT_SAVE_PATH + "1.txt", 'r', encoding="utf8") as f:
                tmp = f.read()  #
                try:
                    self.CURRENT_STRENGTH = int(tmp.split("/")[0])
                    self.shell_color.helper_text("[+] 理智剩余 {}".format(self.CURRENT_STRENGTH))
                except Exception as e:
                    self.shell_color.failure_text("[!] {}".format(e))
                    if self_fix:
                        self.__check_current_strength_debug()
                    else:
                        self.CURRENT_STRENGTH -= LIZHI_CONSUME[c_id]
        else:
            self.CURRENT_STRENGTH -= LIZHI_CONSUME[c_id]
            self.shell_color.warning_text("[*] OCR 模块为装载,系统将直接计算理智值")
            self.__wait(TINY_WAIT)
            self.shell_color.helper_text("[+] 理智剩余 {}".format(self.CURRENT_STRENGTH))

        if self.CURRENT_STRENGTH - LIZHI_CONSUME[c_id] < 0:
            self.shell_color.failure_text("[!] 理智不足 退出战斗")
            return False
        else:
            return True
            # 理智不够退出战斗

    def battle_selector(self, c_id, first_battle_signal=True):
        mode = self.selector.id_checker()
        if mode == 1:
            if first_battle_signal:
                self.adb.get_mouse_swipe(SWIPE_LOCATION['BATTLE_TO_MAP_LEFT'], FLAG=FLAGS_SWIPE_BIAS_TO_LEFT)
                self.adb.get_mouse_click(
                    XY=CLICK_LOCATION['BATTLE_SELECT_MAIN_TASK']
                )

                # 拖动到正确的地方
                if c_id[0] in MAIN_TASK_CHAPTER_SWIPE.keys() or c_id[1] in MAIN_TASK_CHAPTER_SWIPE.keys():
                    if c_id[0].isnumeric():
                        x = MAIN_TASK_CHAPTER_SWIPE[c_id[0]]
                    else:
                        x = MAIN_TASK_CHAPTER_SWIPE[c_id[1]]
                    self.shell_color.helper_text("[-] 拖动%{}次".format(x))
                    for x in range(0, x):
                        self.adb.get_mouse_swipe(SWIPE_LOCATION['BATTLE_TO_MAP_RIGHT'], FLAG=FLAGS_SWIPE_BIAS_TO_RIGHT)
                        self.__wait(MEDIUM_WAIT)

                # 章节选择
                if c_id[0].isnumeric():
                    self.adb.get_mouse_click(
                        XY=CLICK_LOCATION['BATTLE_SELECT_MAIN_TASK_{}'.format(c_id[0])]
                    )
                elif c_id[0] == "S":
                    self.adb.get_mouse_click(
                        XY=CLICK_LOCATION['BATTLE_SELECT_MAIN_TASK_{}'.format(c_id[1])]
                    )
                else:
                    raise IndexError("C_ID Error")
                self.__wait(3)
                # 章节选择结束
                # 拖动
                self.adb.get_mouse_swipe(SWIPE_LOCATION['BATTLE_TO_MAP_LEFT'], FLAG=FLAGS_SWIPE_BIAS_TO_LEFT)
                sleep(SMALL_WAIT)
                self.adb.get_mouse_swipe(SWIPE_LOCATION['BATTLE_TO_MAP_LEFT'], FLAG=FLAGS_SWIPE_BIAS_TO_LEFT)
                sleep(SMALL_WAIT)
                self.adb.get_mouse_swipe(SWIPE_LOCATION['BATTLE_TO_MAP_LEFT'], FLAG=FLAGS_SWIPE_BIAS_TO_LEFT)

                # 拖动到正确的地方
                if c_id in MAIN_TASK_BATTLE_SWIPE.keys():
                    x = MAIN_TASK_BATTLE_SWIPE[c_id]
                    self.shell_color.helper_text("[-] 拖动%{}次".format(x))
                    for x in range(0, x):
                        self.adb.get_mouse_swipe(SWIPE_LOCATION['BATTLE_TO_MAP_RIGHT'], FLAG=FLAGS_SWIPE_BIAS_TO_RIGHT)
                        # self.__wait(MEDIUM_WAIT)
                        sleep(5)
                self.adb.get_mouse_click(
                    XY=CLICK_LOCATION['BATTLE_SELECT_MAIN_TASK_{}'.format(c_id)]
                )

            else:
                sleep(5)

        elif mode == 2:
            try:
                X = DAILY_LIST[mode][self.selector.get_week()][c_id[0:2]]
            except Exception as e:
                self.shell_color.failure_text(e.__str__() + '\tclick_location 文件配置错误')
                X = None
                exit(0)
            if first_battle_signal:
                self.adb.get_mouse_swipe(SWIPE_LOCATION['BATTLE_TO_MAP_LEFT'], FLAG=FLAGS_SWIPE_BIAS_TO_LEFT)
                self.adb.get_mouse_click(
                    XY=CLICK_LOCATION['BATTLE_SELECT_MATERIAL_COLLECTION']
                )
                self.adb.get_mouse_click(
                    XY=CLICK_LOCATION['BATTLE_SELECT_MATERIAL_COLLECTION_{}'.format(X)]
                )
                self.adb.get_mouse_click(
                    XY=CLICK_LOCATION['BATTLE_SELECT_MATERIAL_COLLECTION_X-{}'.format(c_id[-1])]
                )
            else:
                self.adb.get_mouse_click(
                    XY=CLICK_LOCATION['BATTLE_SELECT_MATERIAL_COLLECTION_X-{}'.format(c_id[-1])]
                )
        elif mode == 3:
            try:
                X = DAILY_LIST[mode][self.selector.get_week()][c_id[3]]
            except Exception as e:
                self.shell_color.failure_text(e.__str__() + '\tclick_location 文件配置错误')
                X = None
                exit(0)
            if first_battle_signal:
                self.adb.get_mouse_click(
                    XY=CLICK_LOCATION['BATTLE_SELECT_CHIP_SEARCH']
                )
                self.adb.get_mouse_click(
                    XY=CLICK_LOCATION['BATTLE_SELECT_CHIP_SEARCH_PR-{}'.format(X)]
                )
                self.adb.get_mouse_click(
                    XY=CLICK_LOCATION['BATTLE_SELECT_CHIP_SEARCH_PR-X-{}'.format(c_id[-1])]
                )
            else:
                self.adb.get_mouse_click(
                    XY=CLICK_LOCATION['BATTLE_SELECT_CHIP_SEARCH_PR-X-{}'.format(c_id[-1])]
                )
コード例 #4
0
class ArknightsHelper(object):
    def __init__(self,
                 current_strength=None,  # 当前理智
                 adb_host=None,  # 当前绑定到的设备
                 out_put=True,  # 是否有命令行输出
                 call_by_gui=False):  # 是否为从 GUI 程序调用
        if adb_host is None:
            adb_host = ADB_HOST
        self.adb = ADBShell(adb_host=adb_host)
        self.shell_log = ShellColor() if out_put else BufferColor(debug_level=DEBUG_LEVEL)
        self.__is_game_active = False
        self.__call_by_gui = call_by_gui
        self.__rebase_to_null = " 1>nul 2>nul" \
            if "win32" in os.sys.platform \
            else " 1>/dev/null 2>/dev/null &" \
            if enable_rebase_to_null else ""
        self.CURRENT_STRENGTH = 100
        self.selector = BattleSelector()
        self.ocr_active = True
        self.is_called_by_gui = call_by_gui
        if DEBUG_LEVEL >= 1:
            self.__print_info()
        if not call_by_gui:
            self.is_ocr_active(current_strength)
        self.shell_log.debug_text("成功初始化模块")

    def __print_info(self):
        self.shell_log.info_text(
            """当前系统信息:
ADB 路径\t{adb_path}
ADB 端口\t{adb_host}
截图路径\t{screen_shoot_path}
存储路径\t{storage_path}
            """.format(
                adb_path=ADB_ROOT, adb_host=ADB_HOST,
                screen_shoot_path=SCREEN_SHOOT_SAVE_PATH, storage_path=STORAGE_PATH
            )
        )
        if enable_baidu_api:
            self.shell_log.info_text(
                """百度API配置信息:
APP_ID\t{app_id}
API_KEY\t{api_key}
SECRET_KEY\t{secret_key}
                """.format(
                    app_id=APP_ID, api_key=API_KEY, secret_key=SECRET_KEY
                )
            )

    def __ocr_check(self,
                    file_path,  # 输入文件路径
                    save_path,  # 输出文件路径
                    option=None,  # 附加选项
                    change_image=True):  # 是否预处理图片
        self.shell_log.debug_text("base.__ocr_check")
        global enable_baidu_api
        if change_image:
            if enable_baidu_api:
                if enable_help_baidu:
                    binarization_image(filepath=file_path, save_backup=True)
                else:
                    self.shell_log.info_text("不对百度ocr进行图像处理")
            else:
                binarization_image(filepath=file_path, save_backup=True)
        if enable_baidu_api:
            try:
                ocr(file_path, save_path + ".txt")
            except ConnectionError:
                self.shell_log.failure_text("[!] 百度API无法连接")
                enable_baidu_api = False
                self.shell_log.helper_text("继续使用tesseract")
        if not enable_baidu_api:
            self.shell_log.debug_text("使用 tesseract OCR")
            if option is not None:
                option = " " + option
            os.popen(
                'tesseract "{}"  "{}" {}'.format(file_path, save_path, option) + self.__rebase_to_null
            )
            self.__wait(3)
        else:
            self.shell_log.debug_text("使用 baidu api")

    def is_ocr_active(self,  # 判断 OCR 是否可用
                      current_strength=None):  # 如果不可用时用于初始化的理智值
        self.shell_log.debug_text("base.is_ocr_active")
        global enable_baidu_api
        self.__ocr_check(os.path.join(STORAGE_PATH, "OCR_TEST_1.png"),
                         os.path.join(SCREEN_SHOOT_SAVE_PATH, "ocr_test_result"), "--psm 7",
                         change_image=False)
        try:
            with open(os.path.join(SCREEN_SHOOT_SAVE_PATH, "ocr_test_result.txt"),
                      "r") as f:
                tmp = f.read()
                test_1 = int(tmp.split("/")[0])
                if test_1 == 51:
                    self.ocr_active = True
                    self.shell_log.debug_text("OCR 模块工作正常")
                    return True
                else:
                    raise Exception
        except Exception as e:
            if enable_baidu_api:
                enable_baidu_api = False
                return self.is_ocr_active(current_strength)
            self.shell_log.failure_text("OCR 模块识别错误, 使用初始理智值")
            if current_strength is not None:
                self.CURRENT_STRENGTH = current_strength
            else:
                self.shell_log.failure_text(
                    "未装载初始理智值, 请在初始化 Arknights 助手时赋予初值")
                if not self.is_called_by_gui:
                    exit(0)
                else:
                    return False

    def __del(self):
        self.shell_log.debug_text("base.__del")
        self.adb.ch_tools("shell")
        self.adb.ch_abd_command(
            "am force-stop {}".format(ArkNights_PACKAGE_NAME))
        self.adb.run_cmd()

    def destroy(self):
        self.__del()

    def __check_apk_info_active(self):
        self.adb.ch_tools("shell")
        self.adb.ch_abd_command("dumpsys window windows | findstr \"Current\" > {}".format(
            os.path.join(STORAGE_PATH, "package.txt")))
        self.adb.run_cmd(DEBUG_LEVEL=0)

    def check_game_active(self):  # 启动游戏 需要手动调用
        self.shell_log.debug_text("base.check_game_active")
        self.__check_apk_info_active()
        self.shell_log.debug_text("正在尝试启动游戏")
        with open(os.path.join(STORAGE_PATH, "current.txt"), "r") as f:
            if ArkNights_PACKAGE_NAME in f.read():
                self.__is_game_active = True
                self.shell_log.debug_text("游戏已启动")
            else:
                self.adb.ch_tools("shell")
                self.adb.ch_abd_command(
                    "am start -n {}/{}".format(ArkNights_PACKAGE_NAME, ArkNights_ACTIVITY_NAME))
                self.adb.run_cmd()
                self.shell_log.debug_text("成功启动游戏")
                self.__is_game_active = True

    @staticmethod
    def __wait(n=10,  # 等待时间中值
               MANLIKE_FLAG=True):  # 是否在此基础上设偏移量
        if MANLIKE_FLAG:
            m = uniform(0, 0.3)
            n = uniform(n - m * 0.5 * n, n + m * n)
        sleep(n)

    def mouse_click(self,  # 点击一个按钮
                    XY):  # 待点击的按钮的左上和右下坐标
        self.shell_log.debug_text("base.mouse_click")
        xx = randint(XY[0][0], XY[1][0])
        yy = randint(XY[0][1], XY[1][1])
        self.adb.get_mouse_click((xx, yy))
        self.__wait(TINY_WAIT, MANLIKE_FLAG=True)

    def module_login(self):
        self.shell_log.debug_text("base.module_login")
        self.mouse_click(CLICK_LOCATION['LOGIN_QUICK_LOGIN'])
        self.__wait(BIG_WAIT)
        self.mouse_click(CLICK_LOCATION['LOGIN_START_WAKEUP'])
        self.__wait(BIG_WAIT)

    def module_battle_slim(self,
                           c_id,  # 待战斗的关卡编号
                           set_count=1000,  # 战斗次数
                           check_ai=True,  # 是否检查代理指挥
                           **kwargs):  # 扩展参数:
        '''
        :param sub 是否为子程序 (是否为module_battle所调用)
        :param auto_close 是否自动关闭, 默认为 false
        :param self_fix 是否尝试自动修复, 默认为 false
        :param MAX_TIME 最大检查轮数, 默认在 config 中设置,
            每隔一段时间进行一轮检查判断战斗是否结束
            建议自定义该数值以便在出现一定失误,
            超出最大判断次数后有一定的自我修复能力
        :return:
            True 完成指定次数的战斗
            False 理智不足, 退出战斗
        '''
        self.shell_log.debug_text("base.module_battle_slim")
        sub = kwargs["sub"] \
            if "sub" in kwargs.keys() else False
        auto_close = kwargs["auto_close"] \
            if "auto_close" in kwargs.keys() else False
        self_fix = kwargs["self_fix"] \
            if "self_fix" in kwargs.keys() else False
        if not sub:
            self.shell_log.helper_text("战斗-选择{}...启动".format(c_id))
        if check_ai:
            self.set_ai_commander()
        if set_count == 0:
            return True
        strength_end_signal = False
        count = 0
        while not strength_end_signal:
            # 初始化变量
            battle_end_signal = False
            if "MAX_TIME" in kwargs.keys():
                battle_end_signal_max_execute_time = kwargs["MAX_TIME"]
            else:
                battle_end_signal_max_execute_time = BATTLE_END_SIGNAL_MAX_EXECUTE_TIME
            # 查看剩余理智
            strength_end_signal = not self.check_current_strength(
                c_id, self_fix)
            # 需要重新启动
            if self.CURRENT_STRENGTH == -1:
                self.back_to_main()
                self.__wait(3, MANLIKE_FLAG=False)
                self.selector.id = c_id
                self.mouse_click(CLICK_LOCATION['BATTLE_CLICK_IN'])
                self.battle_selector(c_id)  # 选关
                return self.module_battle_slim(c_id, set_count - count, check_ai, **kwargs)
            if strength_end_signal:
                return True

            self.shell_log.helper_text("开始战斗")
            self.mouse_click(CLICK_LOCATION['BATTLE_CLICK_START_BATTLE'])
            self.__wait(4, False)
            self.mouse_click(CLICK_LOCATION['BATTLE_CLICK_ENSURE_TEAM_INFO'])
            t = 0

            while not battle_end_signal:
                # 前 60s 不进行检测
                if t == 0:
                    self.__wait(BATTLE_NONE_DETECT_TIME)
                    t += BATTLE_NONE_DETECT_TIME
                else:
                    self.__wait(BATTLE_FINISH_DETECT)
                t += BATTLE_FINISH_DETECT
                self.shell_log.helper_text("战斗进行{}s 判断是否结束".format(t))
                # 判断是否升级
                self.adb.get_screen_shoot(file_name="battle_status.png")
                self.adb.get_sub_screen(
                    file_name="battle_status.png",
                    screen_range=MAP_LOCATION['BATTLE_INFO_LEVEL_UP'],
                    save_name="level_up_real_time.png"
                )
                level_up_signal = False
                # 检查升级情况
                if enable_ocr_check_update:
                    self.__ocr_check(
                        os.path.join(SCREEN_SHOOT_SAVE_PATH, "level_up_real_time.png"),
                        os.path.join(SCREEN_SHOOT_SAVE_PATH, "1"),
                        "--psm 7 -l chi_sim"
                    )
                    level_up_text = "提升"
                    f = open(os.path.join(SCREEN_SHOOT_SAVE_PATH, "1.txt"),
                             "r")
                    tmp = f.readline()
                    tmp = tmp.replace(' ', '')
                    self.shell_log.debug_text("OCR 识别结果: {}".format(tmp))
                    level_up_signal = level_up_text in tmp
                else:
                    level_up_signal = self.adb.img_difference(
                        img1=os.path.join(SCREEN_SHOOT_SAVE_PATH, "level_up_real_time.png"),
                        img2=os.path.join(STORAGE_PATH, "BATTLE_INFO_BATTLE_END_LEVEL_UP.png")
                    ) > .7
                if level_up_signal:
                    battle_end_signal = True
                    self.__wait(SMALL_WAIT, MANLIKE_FLAG=True)
                    self.shell_log.helper_text("检测到升级")
                    self.mouse_click(CLICK_LOCATION['CENTER_CLICK'])
                    self.__wait(SMALL_WAIT, MANLIKE_FLAG=True)
                    self.mouse_click(CLICK_LOCATION['CENTER_CLICK'])
                    self.__wait(SMALL_WAIT, MANLIKE_FLAG=True)
                else:
                    self.adb.get_sub_screen(
                        file_name="battle_status.png",
                        screen_range=MAP_LOCATION['BATTLE_INFO_BATTLE_END'],
                        save_name="battle_end.png"
                    )
                    end_signal = False
                    if enable_ocr_check_end:
                        self.__ocr_check(
                            os.path.join(SCREEN_SHOOT_SAVE_PATH, "battle_end.png"),
                            os.path.join(SCREEN_SHOOT_SAVE_PATH, "1"),
                            "--psm 7 -l chi_sim"
                        )
                        end_text = "结束"
                        f = open(os.path.join(SCREEN_SHOOT_SAVE_PATH, "1.txt"),
                                 "r")
                        tmp = f.readline()
                        tmp = tmp.replace(' ', '')
                        self.shell_log.debug_text("OCR 识别结果: {}".format(tmp))
                        end_signal = end_text in tmp
                    else:
                        end_signal = self.adb.img_difference(
                            img1=os.path.join(SCREEN_SHOOT_SAVE_PATH, "battle_end.png"),
                            img2=os.path.join(STORAGE_PATH, "BATTLE_INFO_BATTLE_END_TRUE.png")
                        ) > .7
                    if end_signal:
                        battle_end_signal = True
                        self.mouse_click(CLICK_LOCATION['CENTER_CLICK'])
                    else:
                        battle_end_signal_max_execute_time -= 1
                    if battle_end_signal_max_execute_time < 1:
                        self.shell_log.failure_text("超过最大战斗时长!")
                        battle_end_signal = True
            count += 1
            self.shell_log.info_text("当前战斗次数 {}".format(count))
            if count >= set_count:
                strength_end_signal = True
            self.shell_log.info_text("战斗结束")
            self.__wait(10, MANLIKE_FLAG=True)
        if not sub:
            if auto_close:
                self.shell_log.helper_text("简略模块{}结束,系统准备退出".format(c_id))
                self.__wait(120, False)
                self.__del()
            else:
                self.shell_log.helper_text("简略模块{}结束".format(c_id))
                return True
        else:
            self.shell_log.helper_text("当前任务{}结束,准备进行下一项任务".format(c_id))
            return True

    def __check_is_on_setting(self):  # 检查是否在设置页面,True 为是
        self.shell_log.debug_text("base.__check_is_on_setting")
        self.adb.get_screen_shoot(
            file_name="is_setting.png",
            screen_range=MAP_LOCATION['INDEX_INFO_IS_SETTING']
        )
        if enable_ocr_debugger:
            self.__ocr_check(
                os.path.join(SCREEN_SHOOT_SAVE_PATH, "is_setting.png"),
                os.path.join(SCREEN_SHOOT_SAVE_PATH, "1"),
                "--psm 7 -l chi_sim",
                change_image=False
            )
            end_text = "设置"
            f = open(os.path.join(SCREEN_SHOOT_SAVE_PATH, "1.txt"), "r")
            tmp = f.readline()
            tmp = tmp.replace(' ', '')
            self.shell_log.debug_text("OCR 识别结果: {}".format(tmp))
            return end_text in tmp
        else:
            return self.adb.img_difference(
                img1=os.path.join(STORAGE_PATH, "INDEX_INFO_IS_SETTING.png"),
                img2=os.path.join(SCREEN_SHOOT_SAVE_PATH, "is_setting.png")
            ) > .85

    def __check_is_on_notice(self):  # 检查是否有公告,True为是
        self.shell_log.debug_text("base.__check_is_on_notice")
        self.adb.get_screen_shoot(
            file_name="is_notice.png",
            screen_range=MAP_LOCATION['INDEX_INFO_IS_NOTICE']
        )
        if enable_ocr_debugger:
            self.__ocr_check(
                os.path.join(SCREEN_SHOOT_SAVE_PATH, "is_notice.png"),
                os.path.join(SCREEN_SHOOT_SAVE_PATH, "1"),
                "--psm 7 -l chi_sim",
                change_image=False
            )
            end_text = "活动公告"
            f = open(os.path.join(SCREEN_SHOOT_SAVE_PATH, "1.txt"), "r")
            tmp = f.readline()
            tmp = tmp.replace(' ', '')
            self.shell_log.debug_text("OCR 识别结果: {}".format(tmp))
            return end_text in tmp
        else:
            return self.adb.img_difference(
                img1=os.path.join(STORAGE_PATH, "INDEX_INFO_IS_NOTICE.png"),
                img2=os.path.join(SCREEN_SHOOT_SAVE_PATH, "is_notice.png")
            ) > .85

    def back_to_main(self):  # 回到主页
        self.shell_log.debug_text("base.back_to_main")
        self.shell_log.helper_text("返回主页ing...")
        # 检测是否有公告,如果有就点掉,点掉公告就是在主页
        if self.__check_is_on_notice():
            self.shell_log.helper_text("触发公告,点掉公告")
            self.mouse_click(CLICK_LOCATION['CLOSE_NOTICE'])
            self.shell_log.helper_text("已回到主页")
            self.__wait(SMALL_WAIT, True)
            return
        # 检测左上角是否有返回标志,有就返回,没有就结束
        for i in range(5):
            self.adb.get_screen_shoot(
                file_name="is_return.png",
                screen_range=MAP_LOCATION['INDEX_INFO_IS_RETURN']
            )
            if self.adb.img_difference(
                    img1=os.path.join(STORAGE_PATH, "INDEX_INFO_IS_RETURN.png"),
                    img2=os.path.join(SCREEN_SHOOT_SAVE_PATH, "is_return.png")
            ) > .75:
                self.shell_log.helper_text("未回到主页,点击返回")
                self.mouse_click(CLICK_LOCATION['MAIN_RETURN_INDEX'])
                self.__wait(TINY_WAIT, True)
                if self.__check_is_on_notice():
                    self.shell_log.helper_text("触发公告,点掉公告")
                    self.mouse_click(CLICK_LOCATION['CLOSE_NOTICE'])
                    break
            else:
                break
        if self.__check_is_on_setting():
            self.shell_log.helper_text("触发设置,返回")
            self.mouse_click(CLICK_LOCATION['MAIN_RETURN_INDEX'])
        self.shell_log.helper_text("已回到主页")
        self.__wait(SMALL_WAIT, True)

    def module_battle(self,  # 完整的战斗模块
                      c_id,  # 选择的关卡
                      set_count=1000):  # 作战次数
        self.shell_log.debug_text("base.module_battle")
        self.back_to_main()
        self.__wait(3, MANLIKE_FLAG=False)
        self.selector.id = c_id
        self.mouse_click(CLICK_LOCATION['BATTLE_CLICK_IN'])
        self.battle_selector(c_id)  # 选关
        self.module_battle_slim(c_id,
                                set_count=set_count,
                                check_ai=True,
                                sub=True,
                                self_fix=self.ocr_active)
        return True

    def main_handler(self, battle_task_list=None):
        self.shell_log.debug_text("base.main_handler")
        if battle_task_list is None:
            battle_task_list = OrderedDict()

        self.shell_log.warning_text("装载模块...")
        self.shell_log.warning_text("战斗模块...启动")
        flag = False
        if battle_task_list.__len__() == 0:
            self.shell_log.failure_text("任务清单为空!")

        for c_id, count in battle_task_list.items():
            if c_id not in MAIN_TASK_SUPPORT.keys():
                raise IndexError("无此关卡!")
            self.shell_log.helper_text("战斗{} 启动".format(c_id))
            self.selector.id = c_id
            flag = self.module_battle(c_id, count)

        if flag:
            if not self.__call_by_gui:
                self.shell_log.warning_text("所有模块执行完毕... 60s后退出")
                self.__wait(60)
                self.__del()
            else:
                self.shell_log.warning_text("所有模块执行完毕")
        else:
            if not self.__call_by_gui:
                self.shell_log.warning_text("发生未知错误... 60s后退出")
                self.__wait(60)
                self.__del()
            else:
                self.shell_log.warning_text("发生未知错误... 进程已结束")

    def set_ai_commander(self):
        self.shell_log.debug_text("base.set_ai_commander")
        self.adb.get_screen_shoot(
            file_name="is_ai.png",
            screen_range=MAP_LOCATION['BATTLE_CLICK_AI_COMMANDER']
        )
        if self.adb.img_difference(
                os.path.join(SCREEN_SHOOT_SAVE_PATH, "is_ai.png"),
                os.path.join(STORAGE_PATH, "BATTLE_CLICK_AI_COMMANDER_TRUE.png")
        ) <= 0.8:
            self.shell_log.helper_text("代理指挥未设置,设置代理指挥")
            self.mouse_click(CLICK_LOCATION['BATTLE_CLICK_AI_COMMANDER'])
        else:
            self.shell_log.helper_text("代理指挥已设置")

    def __check_current_strength(self):  # 检查当前理智是否足够
        self.shell_log.debug_text("base.__check_current_strength")
        assert self.ocr_active
        self.__wait(SMALL_WAIT, False)
        self.adb.get_screen_shoot(
            file_name="strength.png",
            screen_range=MAP_LOCATION["BATTLE_INFO_STRENGTH_REMAIN"]
        )

        self.__ocr_check(
            os.path.join(SCREEN_SHOOT_SAVE_PATH, "strength.png"),
            os.path.join(SCREEN_SHOOT_SAVE_PATH, "1"),
            "--psm 7")
        with open(SCREEN_SHOOT_SAVE_PATH + "1.txt",
                  'r') as f:
            tmp = f.read()  #
            try:
                self.CURRENT_STRENGTH = int(tmp.split("/")[0])
                self.shell_log.helper_text(
                    "理智剩余 {}".format(self.CURRENT_STRENGTH))
                return True
            except Exception as e:
                self.shell_log.failure_text("{}".format(e))
                return False

    def __check_current_strength_debug(self, c_id):
        # 查看是否在素材页面
        self.shell_log.debug_text("base.__check_current_strength_debug")
        self.shell_log.helper_text("启动自修复模块,检查是否停留在素材页面")
        self.adb.get_screen_shoot(
            file_name="debug.png",
            screen_range=MAP_LOCATION['BATTLE_DEBUG_WHEN_OCR_ERROR']
        )
        if enable_ocr_debugger:
            self.__ocr_check(os.path.join(SCREEN_SHOOT_SAVE_PATH, "debug.png"),
                             os.path.join(SCREEN_SHOOT_SAVE_PATH, "debug"),
                             "--psm 7 -l chi_sim")
            end_text = "掉落"
            f = open(os.path.join(SCREEN_SHOOT_SAVE_PATH, "debug.txt"), 'r')
            tmp = f.readline()
            tmp = tmp.replace(' ', '')
            self.shell_log.debug_text("OCR 识别结果: {}".format(tmp))
            if end_text in tmp:
                self.shell_log.helper_text("检测 BUG 成功,系统停留在素材页面,请求返回...")
                self.adb.get_mouse_click(
                    CLICK_LOCATION['MAIN_RETURN_INDEX'], FLAG=None)
                self.__check_current_strength()
            else:
                self.shell_log.failure_text("检测 BUG 失败,系统将返回主页重新开始")
                self.CURRENT_STRENGTH = -1 # CURRENT_STRENGTH = -1 代表需要需要回到主页重来
        else:
            if self.adb.img_difference(
                    img1=os.path.join(SCREEN_SHOOT_SAVE_PATH, "debug.png"),
                    img2=os.path.join(STORAGE_PATH, "BATTLE_DEBUG_CHECK_LOCATION_IN_SUCAI.png")
            ) > 0.75:
                self.shell_log.helper_text("检测 BUG 成功,系统停留在素材页面,请求返回...")
                self.adb.get_mouse_click(
                    CLICK_LOCATION['MAIN_RETURN_INDEX'], FLAG=None)
                self.__check_current_strength()
            else:
                self.shell_log.failure_text("检测 BUG 失败,系统将返回主页重新开始")
                self.CURRENT_STRENGTH = -1 # CURRENT_STRENGTH = -1 代表需要需要回到主页重来

    def check_current_strength(self, c_id, self_fix=False):
        self.shell_log.debug_text("base.check_current_strength")
        if self.ocr_active:
            self.__wait(SMALL_WAIT, False)
            self.adb.get_screen_shoot(
                file_name="strength.png",
                screen_range=MAP_LOCATION["BATTLE_INFO_STRENGTH_REMAIN"]
            )

            self.__ocr_check(os.path.join(SCREEN_SHOOT_SAVE_PATH, "strength.png"),
                             os.path.join(SCREEN_SHOOT_SAVE_PATH, "1"),
                             "--psm 7")
            with open(os.path.join(SCREEN_SHOOT_SAVE_PATH, "1.txt"), 'r') as f:
                tmp = f.read()  #
                try:
                    self.CURRENT_STRENGTH = int(tmp.split("/")[0])
                    self.shell_log.helper_text(
                        "理智剩余 {}".format(self.CURRENT_STRENGTH))
                except Exception as e:
                    self.shell_log.failure_text("{}".format(e))
                    if self_fix:
                        self.__check_current_strength_debug(c_id)
                        if self.CURRENT_STRENGTH == -1:
                            return False
                    else:
                        self.CURRENT_STRENGTH -= LIZHI_CONSUME[c_id]
        else:
            self.CURRENT_STRENGTH -= LIZHI_CONSUME[c_id]
            self.shell_log.warning_text("OCR 模块未装载,系统将直接计算理智值")
            self.__wait(TINY_WAIT)
            self.shell_log.helper_text(
                "理智剩余 {}".format(self.CURRENT_STRENGTH))

        if self.CURRENT_STRENGTH - LIZHI_CONSUME[c_id] < 0:
            self.shell_log.failure_text("理智不足 退出战斗")
            return False
        else:
            return True

    def battle_selector(self, c_id, first_battle_signal=True):  # 选关
        self.shell_log.debug_text("base.battle_selector")
        mode = self.selector.id_checker(c_id)  # 获取当前关卡所属章节
        if mode == 1:
            if first_battle_signal:
                self.mouse_click(XY=CLICK_LOCATION['BATTLE_SELECT_MAIN_TASK'])
                self.adb.get_mouse_swipe(
                    SWIPE_LOCATION['BATTLE_TO_MAP_LEFT'],
                    FLAG=FLAGS_SWIPE_BIAS_TO_LEFT
                )

                # 拖动到正确的地方
                if c_id[0] in MAIN_TASK_CHAPTER_SWIPE.keys() or c_id[1] in MAIN_TASK_CHAPTER_SWIPE.keys():
                    if c_id[0].isnumeric():
                        x = MAIN_TASK_CHAPTER_SWIPE[c_id[0]]
                    else:
                        x = MAIN_TASK_CHAPTER_SWIPE[c_id[1]]
                    self.shell_log.helper_text("拖动 {} 次".format(x))
                    for x in range(0, x):
                        self.adb.get_mouse_swipe(
                            SWIPE_LOCATION['BATTLE_TO_MAP_RIGHT'], FLAG=FLAGS_SWIPE_BIAS_TO_RIGHT)
                        self.__wait(MEDIUM_WAIT)

                # 章节选择
                if c_id[0].isnumeric():
                    self.mouse_click(
                        XY=CLICK_LOCATION['BATTLE_SELECT_MAIN_TASK_{}'.format(c_id[0])])
                elif c_id[0] == "S":
                    self.mouse_click(
                        XY=CLICK_LOCATION['BATTLE_SELECT_MAIN_TASK_{}'.format(c_id[1])])
                else:
                    raise IndexError("C_ID Error")
                self.__wait(3)
                # 章节选择结束
                # 拖动
                self.adb.get_mouse_swipe(
                    SWIPE_LOCATION['BATTLE_TO_MAP_LEFT'], FLAG=FLAGS_SWIPE_BIAS_TO_LEFT)
                sleep(SMALL_WAIT)
                self.adb.get_mouse_swipe(
                    SWIPE_LOCATION['BATTLE_TO_MAP_LEFT'], FLAG=FLAGS_SWIPE_BIAS_TO_LEFT)
                sleep(SMALL_WAIT)
                self.adb.get_mouse_swipe(
                    SWIPE_LOCATION['BATTLE_TO_MAP_LEFT'], FLAG=FLAGS_SWIPE_BIAS_TO_LEFT)

                # 拖动到正确的地方
                if c_id in MAIN_TASK_BATTLE_SWIPE.keys():
                    x = MAIN_TASK_BATTLE_SWIPE[c_id]
                    self.shell_log.helper_text("拖动 {} 次".format(x))
                    for x in range(0, x):
                        self.adb.get_mouse_swipe(
                            SWIPE_LOCATION['BATTLE_TO_MAP_RIGHT'], FLAG=FLAGS_SWIPE_BIAS_TO_RIGHT)
                        sleep(5)
                self.mouse_click(
                    XY=CLICK_LOCATION['BATTLE_SELECT_MAIN_TASK_{}'.format(c_id)])

            else:
                sleep(5)

        elif mode == 2:
            try:
                X = DAILY_LIST[str(mode)][self.selector.get_week()][c_id[0:2]]
            except Exception as e:
                self.shell_log.failure_text(
                    e.__str__() + '\tclick_location 文件配置错误')
                X = None
                exit(0)
            if first_battle_signal:
                self.adb.get_mouse_swipe(
                    SWIPE_LOCATION['BATTLE_TO_MAP_LEFT'], FLAG=FLAGS_SWIPE_BIAS_TO_LEFT)
                self.mouse_click(
                    XY=CLICK_LOCATION['BATTLE_SELECT_MATERIAL_COLLECTION'])
                self.mouse_click(
                    XY=CLICK_LOCATION['BATTLE_SELECT_MATERIAL_COLLECTION_{}'.format(X)])
                self.mouse_click(
                    XY=CLICK_LOCATION['BATTLE_SELECT_MATERIAL_COLLECTION_X-{}'.format(c_id[-1])])
            else:
                self.mouse_click(
                    XY=CLICK_LOCATION['BATTLE_SELECT_MATERIAL_COLLECTION_X-{}'.format(c_id[-1])])
        elif mode == 3:
            try:
                X = DAILY_LIST[str(mode)][self.selector.get_week()][c_id[3]]
            except Exception as e:
                self.shell_log.failure_text(
                    e.__str__() + '\tclick_location 文件配置错误')
                X = None
                exit(0)
            if first_battle_signal:
                self.mouse_click(
                    XY=CLICK_LOCATION['BATTLE_SELECT_CHIP_SEARCH'])
                self.mouse_click(
                    XY=CLICK_LOCATION['BATTLE_SELECT_CHIP_SEARCH_PR-{}'.format(X)])
                self.mouse_click(
                    XY=CLICK_LOCATION['BATTLE_SELECT_CHIP_SEARCH_PR-X-{}'.format(c_id[-1])])
            else:
                self.mouse_click(
                    XY=CLICK_LOCATION['BATTLE_SELECT_CHIP_SEARCH_PR-X-{}'.format(c_id[-1])])
        elif mode == 5:
            self.mouse_click(
                XY=CLICK_LOCATION["BATTLE_SELECT_HEART_OF_SURGING_FLAME"])
            self.shell_log.helper_text(
                "欢迎来到火蓝之心副本\n祝你在黑曜石音乐节上玩的愉快\n目前主舞台只支持OF-7,OF-8")
            try:
                if c_id[-2] == "F":
                    self.mouse_click(
                        XY=CLICK_LOCATION["BATTLE_SELECT_HEART_OF_SURGING_FLAME_OF-F"])
                    self.mouse_click(
                        XY=CLICK_LOCATION["BATTLE_SELECT_HEART_OF_SURGING_FLAME_{}".format(c_id)])
                elif c_id[-2] == "-":
                    self.mouse_click(
                        XY=CLICK_LOCATION["BATTLE_SELECT_HEART_OF_SURGING_FLAME_OF-"])

                    for x in range(0, 3):
                        self.adb.get_mouse_swipe(SWIPE_LOCATION['BATTLE_TO_MAP_RIGHT'],
                                                 FLAG=FLAGS_SWIPE_BIAS_TO_RIGHT)
                        self.__wait(MEDIUM_WAIT)

                    self.mouse_click(
                        XY=CLICK_LOCATION["BATTLE_SELECT_HEART_OF_SURGING_FLAME_{}".format(c_id)])
                else:
                    self.shell_log.failure_text('click_location 文件配置错误')
                    exit(0)
            except Exception as e:
                self.shell_log.failure_text(
                    e.__str__() + 'click_location 文件配置错误')
                exit(0)

    def clear_daily_task(self):
        self.shell_log.debug_text("base.clear_daily_task")
        self.back_to_main()
        self.mouse_click(CLICK_LOCATION['TASK_CLICK_IN'])
        self.__wait(TINY_WAIT, True)
        self.mouse_click(CLICK_LOCATION['TASK_DAILY_TASK'])
        self.__wait(TINY_WAIT, True)
        task_ok_signal = True
        while task_ok_signal:
            self.adb.get_screen_shoot(file_name="task_status.png")
            self.shell_log.helper_text("正在检查任务状况")
            self.adb.get_sub_screen(
                file_name="task_status.png",
                screen_range=MAP_LOCATION['TASK_INFO'],
                save_name="task_status_1.png"
            )
            if enable_ocr_check_task:
                self.__ocr_check(os.path.join(SCREEN_SHOOT_SAVE_PATH, "task_status_1.png"),
                                 os.path.join(SCREEN_SHOOT_SAVE_PATH, "1"),
                                 "--psm 7 -l chi_sim")
                task_ok_text = "领取"
                f = open(os.path.join(SCREEN_SHOOT_SAVE_PATH, "1.txt"), "r")
                tmp = f.readline()
                tmp = tmp.replace(' ', '')
                self.shell_log.debug_text("OCR 识别结果: {}".format(tmp))
                task_ok_signal = task_ok_text in tmp
            else:
                task_ok_signal = self.adb.img_difference(
                    img1=os.path.join(SCREEN_SHOOT_SAVE_PATH, "task_status_1.png"),
                    img2=os.path.join(STORAGE_PATH, "TASK_COMPLETE.png")
                ) > .7
            if not task_ok_signal:  # 检查当前是否在获得物资页面
                self.shell_log.debug_text("未检测到可领取奖励,检查是否在获得物资页面")
                self.adb.get_sub_screen(
                    file_name="task_status.png",
                    screen_range=MAP_LOCATION['REWARD_GET'],
                    save_name="task_status_2.png"
                )
                if enable_ocr_check_task:
                    self.__ocr_check(os.path.join(SCREEN_SHOOT_SAVE_PATH, "task_status_2.png"),
                                     os.path.join(SCREEN_SHOOT_SAVE_PATH, "1"),
                                     "--psm 7 -l chi_sim")
                    reward_text = "物资"
                    f = open(os.path.join(SCREEN_SHOOT_SAVE_PATH, "1.txt"), "r")
                    tmp = f.readline()
                    tmp = tmp.replace(' ', '')
                    self.shell_log.debug_text("OCR 识别结果: {}".format(tmp))
                    task_ok_signal = reward_text in tmp
                else:
                    task_ok_signal = self.adb.img_difference(
                        img1=os.path.join(SCREEN_SHOOT_SAVE_PATH, "task_status_2.png"),
                        img2=os.path.join(STORAGE_PATH, "REWARD_GET.png")
                    ) > .7
            if task_ok_signal:
                self.shell_log.debug_text("当前有可领取奖励")
                self.mouse_click(CLICK_LOCATION['TASK_DAILY_TASK_CHECK'])
                self.__wait(2, False)
        self.shell_log.helper_text("奖励已领取完毕")