diff --git a/AutoHotkey64.exe b/AutoHotkey64.exe new file mode 100644 index 00000000..86957dbf Binary files /dev/null and b/AutoHotkey64.exe differ diff --git a/OneFiledispatch.ahk b/OneFiledispatch.ahk new file mode 100644 index 00000000..3e49ab10 --- /dev/null +++ b/OneFiledispatch.ahk @@ -0,0 +1,150 @@ +#SingleInstance +;基于火er作品修改 +;久岐忍会导致错误 +;---------------------------引用贴入------------------------------ + +;#Include genshin.ahk + + +class Config { + + static game_name_cn:='YuanShen.exe' + static game_name_global:='GenshinImpact.exe' +} + +class Genshin { + static get_game_pos() { + if ProcessExist(Config.game_name_cn) { + WinGetClientPos(, , &width, &height, 'ahk_exe ' Config.game_name_cn) + } else if ProcessExist(Config.game_name_global) { + WinGetClientPos(, , &width, &height, 'ahk_exe ' Config.game_name_global) + } else { + width := 0 + height := 0 + } + return [width, height] + } + + static is_game_exist() { + return ProcessExist(Config.game_name_cn) or ProcessExist(Config.game_name_global) + } + + static is_game_active() { + return WinActive('ahk_exe ' Config.game_name_cn) or WinActive('ahk_exe ' Config.game_name_global) + } +} + +class Point { + __New(x := '', y := '') { + this.x := x + this.y := y + this.x0 := x + this.y0 := y + } + + refresh_pos(game_width, game_height) { + if this.x0 != '' { + this.x := this.x0 * game_width / 2560 + } + if this.y0 != '' { + this.y := this.y0 * game_height / 1440 + } + } +} + + + +;---------------------------脚本本身代码------------------------------ +class Dispatch { + static p_area_range_1 := Point(500, 160) + static p_area_range_2 := Point(1800, 1280) + static p_dispatch_button := Point(2465, 1360) + static characters := [Point(600, 240), Point(600, 384), Point(600, 528), Point(600, 672), Point(600, 816), Point(600, 960), Point(600, 1104)] + static dispatch_countries := [Point(200, 200), Point(200, 320), Point(200, 400), Point(200, 480),Point(200, 200)] + static p_dispatch_icon := Point(102, 60) + static p_choose_character_icon := Point(25, 80) + static color_off_white := '0xECE5D8' + static color_off_red := '0xDC6148' + static color_yellow_choose_character_icon := '0x263240' + static color_green_under_avatar := '0xD3E6AE' + static color_green_under_avatar2 := '0xD3E5AE' + static sleep_time := 100 + static sleep_time1 := 300 + + static refresh_pos() { + size := Genshin.get_game_pos() + width := size[1] + height := size[2] + this.p_area_range_1.refresh_pos(width, height) + this.p_area_range_2.refresh_pos(width, height) + this.p_dispatch_button.refresh_pos(width, height) + for i in this.characters { + i.refresh_pos(width, height) + } + for i in this.dispatch_countries { + i.refresh_pos(width, height) + } + this.p_dispatch_icon.refresh_pos(width, height) + this.p_choose_character_icon.refresh_pos(width, height) + } + + static dispatch() { + this.refresh_pos() + if PixelGetColor((this.p_dispatch_button.x, this.p_dispatch_button.y) = this.color_off_white or this.p_dispatch_button.x, this.p_dispatch_button.y = this.color_off_red ) and PixelGetColor(this.p_dispatch_icon.x, this.p_dispatch_icon.y) = this.color_off_white { + size := Genshin.get_game_pos() + width := size[1] + height := size[2] + for country in this.dispatch_countries { + MouseClick(, country.x, country.y) + Sleep(this.sleep_time) + i := 0 + ; 重试次数为5 + while i < 5 and (PixelSearch(&x, &y, this.p_area_range_1.x, this.p_area_range_1.y, this.p_area_range_2.x, this.p_area_range_2.y, this.color_green_under_avatar, 5) or PixelSearch(&x, &y, this.p_area_range_1.x, this.p_area_range_1.y, this.p_area_range_2.x, this.p_area_range_2.y, this.color_green_under_avatar2, 5)) { + MouseClick(, x, y) + Sleep(this.sleep_time1) + MouseClick(, this.p_dispatch_button.x, this.p_dispatch_button.y) + Sleep(this.sleep_time1) + MouseClick(, this.p_dispatch_button.x, this.p_dispatch_button.y) + Sleep(this.sleep_time1) + MouseClick(, this.p_dispatch_button.x, this.p_dispatch_button.y) + Sleep(this.sleep_time1) + ; 选人 + for character in this.characters { + mouseClick(, character.x, character.y) + Sleep(this.sleep_time1) + j := 0 + if PixelGetColor(this.p_choose_character_icon.x, this.p_choose_character_icon.y) != this.color_yellow_choose_character_icon { + break + } + } + i++ + Sleep(this.sleep_time) + } + + + } + + ;TipOnce.tip('完成', , ) + ToolTip('完成', width / 2, height / 2, 3) + ;mouseClick(, this.p_area_range_2.x, this.p_area_range_2.y) ;点击测试2 + Sleep(1500) + Send ("{esc}") + } else { + size := Genshin.get_game_pos() + width := size[1] + height := size[2] + ToolTip('当前不是派遣界面', width / 2, height / 2, 3) + ;TipOnce.tip('当前不是派遣界面', , width / 2, height / 2) + ;mouseClick(, this.p_choose_character_icon.x, this.p_choose_character_icon.y) ;这里是位置点击测试 + Sleep(1500) + } + } +} + +; ---执行--- +;WinActive('原神') +WinWaitActive('原神') +;WinWaitActive (,'ahk_exe YuanShen.exe') +Dispatch.dispatch() + + diff --git a/config/json_doc/General.yaml b/config/json_doc/General.yaml index fa635f72..bb656f35 100644 --- a/config/json_doc/General.yaml +++ b/config/json_doc/General.yaml @@ -20,6 +20,28 @@ BlossomType: select_items: [Wealth, Revelation] DomainName: - special_index: $INPUT_VERIFY$#domain_name + select_items: [ + "椛染之庭", + "砂流之庭", + "菫色之庭", + "沉眠之庭", + "华池岩岫", + "太山府", + "孤云凌霄之处", + "山脊守望", + "无妄引咎密宫", + "震雷连山密宫", + "岩中幽谷", + "仲夏庭园", + "塞西莉亚苗圃", + "忘却之峡", + "铭记之谷", + "芬德尼尔之顶", + "昏识塔", + "有顶塔", + "缘觉塔", + "赤金的城墟", + "熔铁的孤塞" + ] diff --git a/source/api/pdocr_api.py b/source/api/pdocr_api.py index d49b24c2..0b87e5aa 100644 --- a/source/api/pdocr_api.py +++ b/source/api/pdocr_api.py @@ -158,9 +158,11 @@ def get_text_position(self, return list(ret_position) - def get_all_texts(self, img, mode=0, per_monitor=False): + def get_all_texts(self, img, mode=0, per_monitor=False,extract_white_threshold=None): if per_monitor: pt=time.time() + if extract_white_threshold!=None: + img = extract_white_letters(img, threshold = extract_white_threshold) res = self.analyze(img) if per_monitor: logger.info(f"ocr performance: {round(time.time()-pt,2)}") diff --git a/source/interaction/interaction_core.py b/source/interaction/interaction_core.py index e9fd27cb..94370e27 100644 --- a/source/interaction/interaction_core.py +++ b/source/interaction/interaction_core.py @@ -263,6 +263,100 @@ def appear(self, obj, use_cache=False): elif isinstance(obj, img_manager.ImgIcon): # Button is also an Icon return self.get_img_existence(obj, use_cache=use_cache) + def appear_then_nothing(self, inputvar, is_gray=False, is_log = False): + """appear then click + + Args: + inputvar (img_manager.ImgIcon/text_manager.TextTemplate/button_manager.Button) + is_gray (bool, optional): 是否启用灰度匹配. Defaults to False. + + Returns: + bool: bool,点击操作是否成功 + """ + + if isinstance(inputvar, button_manager.Button): + imgicon = inputvar + upper_func_name = inspect.getframeinfo(inspect.currentframe().f_back)[2] + + if not inputvar.click_retry_timer.reached(): + return False + + if inputvar.click_fail_timer.reached_and_reset(): + logger.error(t2t("appear then click fail")) + logger.info(f"{inputvar.name} {inputvar.click_position}") + return False + + cap = self.capture(posi=imgicon.cap_posi, jpgmode=imgicon.jpgmode) + # min_rate = img_manager.matching_rate_dict[imgname] + + if inputvar.is_bbg == False: + matching_rate, click_posi = similar_img(imgicon.image, cap, is_gray=is_gray, ret_mode=IMG_POSI) + else: + matching_rate = similar_img(imgicon.image, cap, is_gray=is_gray) + + if matching_rate >= imgicon.threshold: + if imgicon.win_text != None: + from source.api.pdocr_complete import ocr + r = ocr.get_text_position(cap, imgicon.win_text) + if r==-1: + matching_rate = 0 + + if imgicon.is_print_log(matching_rate >= imgicon.threshold) or is_log: + logger.debug( + 'imgname: ' + imgicon.name + 'matching_rate: ' + str( + matching_rate) + ' |function name: ' + upper_func_name) + + if matching_rate >= imgicon.threshold: + p = imgicon.cap_posi + logger.debug(f"appear then click: True: {imgicon.name} func: {upper_func_name}") + inputvar.click_fail_timer.reset() + inputvar.click_retry_timer.reset() + return True + else: + return False + + elif isinstance(inputvar, img_manager.ImgIcon): + imgicon = inputvar + upper_func_name = inspect.getframeinfo(inspect.currentframe().f_back)[2] + + cap = self.capture(posi=imgicon.cap_posi, jpgmode=imgicon.jpgmode) + # min_rate = img_manager.matching_rate_dict[imgname] + + matching_rate = similar_img(imgicon.image, cap, is_gray=is_gray) + + if matching_rate >= imgicon.threshold: + if imgicon.win_text != None: + from source.api.pdocr_complete import ocr + r = ocr.get_text_position(cap, imgicon.win_text) + if r==-1: + matching_rate = 0 + + if imgicon.is_print_log(matching_rate >= imgicon.threshold) or is_log: + logger.debug('imgname: ' + imgicon.name + 'matching_rate: ' + str(matching_rate) + ' |function name: ' + upper_func_name) + + if matching_rate >= imgicon.threshold: + p = imgicon.cap_posi + center_p = [(p[0] + p[2]) / 2, (p[1] + p[3]) / 2] + + logger.debug(f"appear then click: True: {imgicon.name} func: {upper_func_name}") + return True + else: + return False + + elif isinstance(inputvar, text_manager.TextTemplate): + from source.api.pdocr_complete import ocr + upper_func_name = inspect.getframeinfo(inspect.currentframe().f_back)[2] + p1 = ocr.get_text_position(self.capture(jpgmode=NORMAL_CHANNELS, posi=inputvar.cap_area), inputvar.text, cap_posi_leftup=inputvar.cap_area[:2]) + if is_log: + logger.debug('text: ' + inputvar.text + 'position: ' + str(p1) + ' |function name: ' + upper_func_name) + if p1 != -1: + logger.debug(f"appear then click: True: {inputvar.text} func: {upper_func_name}") + return True + else: + return False + + + def appear_then_click(self, inputvar, is_gray=False, is_log = False): """appear then click diff --git a/source/manager/asset.py b/source/manager/asset.py index e6fe664f..1704fcc7 100644 --- a/source/manager/asset.py +++ b/source/manager/asset.py @@ -67,6 +67,8 @@ AreaDomainLeyLineDisorder = PosiTemplate() AreaGeneralInteractiveItemInformation = ImgIcon() IconGeneralTalkBubble = ImgIcon() +AreaDomainResidue = Area() +AreaDomainResidue1 = Area() # Text QTSX = TextTemplate(text={"zh_CN":"七天神像","en_US":"Statues of The Seven"}, cap_area = AreaBigmapChoose.position) diff --git a/source/task/claim_reward/claim_reward.py b/source/task/claim_reward/claim_reward.py index bc8d9ba7..fc036c90 100644 --- a/source/task/claim_reward/claim_reward.py +++ b/source/task/claim_reward/claim_reward.py @@ -4,7 +4,8 @@ from source.talk.talk import Talk from source.manager import asset from source.assets.claim_rewards import * - +import os + class ClaimRewardMission(MissionExecutor, Talk): """这个类以MissionExecutor的方式执行任务,因为Mission中已有许多适合该任务的函数可以直接调用。 @@ -36,36 +37,9 @@ def get_available_reward(self): return rewards def _exec_dispatch(self): - def reset_character(): - while 1: - cap = itt.capture(jpgmode=NORMAL_CHANNELS) - complete_posi = match_multiple_img(cap, IconExpeditionComplete.image, ignore_close=True) - complete_posi += match_multiple_img(cap, IconExpeditionComplete2.image, ignore_close=True) - if len(complete_posi)==0: - return - chara_head_posi = np.array(complete_posi)+np.array([80,80]) - for posi in chara_head_posi: - itt.move_and_click(posi) - itt.delay("2animation") - r1 = itt.appear_then_click(ButtonExpeditionClaim) - itt.delay("2animation") - itt.move_and_click(ButtonExpeditionClaim.click_position()) - itt.delay("2animation") - itt.appear_then_click(ButtonExpeditionSelectCharacters) - itt.delay("2animation") - i=0 - while 1: - cp = ButtonExpeditionFirstCharacter.click_position() - itt.move_and_click([cp[0],cp[1]+i]) - itt.delay("2animation") - if itt.get_img_existence(IconClaimRewardExpedition): - break - i+=80 - for area in [ButtonExpeditionMD, ButtonExpeditionLY, ButtonExpeditionDQ, ButtonExpeditionXM]: - r = itt.appear_then_click(area) - if not r: continue - itt.delay("2animation") - reset_character() + itt.delay(1) + cmd = "start AutoHotkey64.exe OneFiledispatch.ahk" + os.system(cmd) def exec_mission(self): self.available_rewards = self.get_available_reward() @@ -81,7 +55,6 @@ def exec_mission(self): self.talk_until_switch(self.checkup_stop_func) self.talk_switch(DispatchCharacterOnExpedition) self._exec_dispatch() - self.exit_talk() class ClaimRewardTask(TaskTemplate): def __init__(self): diff --git a/source/task/domain/domain_task.py b/source/task/domain/domain_task.py index f3843f2a..9b8e686d 100644 --- a/source/task/domain/domain_task.py +++ b/source/task/domain/domain_task.py @@ -62,20 +62,22 @@ def _enter_domain(self): cap_area = asset.AreaDomainSwitchChallenge.position itt.delay(1,comment="genshin animation") self.domain_stage_name = self._domain_text_process(self.domain_stage_name) - p1 = ocr.get_text_position(itt.capture(jpgmode=NORMAL_CHANNELS, posi=cap_area), self.domain_stage_name, - cap_posi_leftup=cap_area[:2], - text_process = self._domain_text_process, - mode=CONTAIN_MATCHING, - extract_white_threshold=254) - if p1 != -1: - if len(p1)>1: - p1 = p1[0] - itt.move_and_click([p1[0] + 5, p1[1] + 5], delay=1) - else: - texts = ocr.get_all_texts(itt.capture(jpgmode=NORMAL_CHANNELS, posi=cap_area)) - - logger.warning(t2t("找不到秘境名称,放弃选择。")) - logger.info(f"all texts: {list(map(self._domain_text_process, texts))}") + retry_count = 0 + while retry_count < 3: + p1 = ocr.get_text_position(itt.capture(jpgmode=NORMAL_CHANNELS, posi=cap_area), self.domain_stage_name, + cap_posi_leftup=cap_area[:2], + text_process = self._domain_text_process, + mode=CONTAIN_MATCHING) + logger.info(f"domain_stage_name:{self.domain_stage_name}, p1:{p1}, cap_area:{cap_area}") + if p1 != -1: + itt.move_and_click([p1[0] + 5, p1[1] + 5], delay=1) + break + else: + texts = ocr.get_all_texts(itt.capture(jpgmode=NORMAL_CHANNELS, posi=cap_area)) + logger.warning(t2t("找不到秘境名称,重试中。")) + logger.info(f"all texts: {list(map(self._domain_text_process, texts))}") + itt.delay(1.5) + retry_count += 1 # itt.delay(1, comment="too fast TAT") ctimer = timer_module.TimeoutTimer(5) @@ -103,24 +105,55 @@ def _end_domain(self): self.last_domain_times -= 1 while 1: if self.checkup_stop_func():return - r = itt.appear_then_click(asset.conti_challenge) + r = itt.appear_then_nothing(asset.conti_challenge) if r: - break + from source.api.pdocr_complete import ocr + from source.api.pdocr_api import SHAPE_MATCHING, ACCURATE_MATCHING, CONTAIN_MATCHING + resin_mode = GIAconfig.Domain_Resin + if str(resin_mode) == '40': + area = asset.AreaDomainResidue.position + text = ocr.get_all_texts(itt.capture(jpgmode=NORMAL_CHANNELS, posi=area),extract_white_threshold=255) + print(text) + if len(text) > 0 and text[0].isdigit() and int(text[0]) >= 1: + logger.info(t2t('有足够的树脂,继续下一次')) + else: + logger.info(t2t('树脂不足,提前退出')) + self._exit_domain() + return + elif str(resin_mode) == '20': + area = asset.AreaDomainResidue1.position + text = ocr.get_all_texts(itt.capture(jpgmode=NORMAL_CHANNELS, posi=area),extract_white_threshold=255) + print(text) + if len(text) > 0 and text[0].isdigit() and int(text[0]) >= 20: + logger.info(t2t('有足够的树脂,继续下一次')) + else: + logger.info(t2t('树脂不足,提前退出')) + self._exit_domain() + return + + r = itt.appear_then_click(asset.conti_challenge) + if r: + break + self.flow_mode = TI.DT_IN_DOMAIN self.dfc.reset() else: logger.info(t2t('次数结束。退出秘境')) # logger.info('no more times. exit domain.') - while 1: - if self.checkup_stop_func():return - r = itt.appear_then_click(asset.exit_challenge) - if r: - break - - # exit all threads - self.pause_threading() - time.sleep(10) + self._exit_domain() + + + def _exit_domain(self): + while 1: + if self.checkup_stop_func():return + r = itt.appear_then_click(asset.exit_challenge) + if r: + break + + # exit all threads + self.pause_threading() + time.sleep(10) def _check_state(self): diff --git "a/\350\260\203\347\224\250\346\264\276\351\201\243.lnk" "b/\350\260\203\347\224\250\346\264\276\351\201\243.lnk" new file mode 100644 index 00000000..e1244fce Binary files /dev/null and "b/\350\260\203\347\224\250\346\264\276\351\201\243.lnk" differ