diff --git a/config/template.json b/config/template.json index 1a066fef3..f930c95aa 100644 --- a/config/template.json +++ b/config/template.json @@ -206,7 +206,8 @@ }, "Daemon": { "Daemon": { - "Enable": true + "Enable": true, + "AimClicker": "do_not_click" } } } \ No newline at end of file diff --git a/module/config/argument/args.json b/module/config/argument/args.json index 87e2afac5..27e0773f2 100644 --- a/module/config/argument/args.json +++ b/module/config/argument/args.json @@ -1374,6 +1374,16 @@ "option_bold": [ true ] + }, + "AimClicker": { + "type": "select", + "value": "do_not_click", + "option": [ + "item_enemy", + "item", + "enemy", + "do_not_click" + ] } } } diff --git a/module/config/argument/argument.yaml b/module/config/argument/argument.yaml index 7735641b1..3e0d467e8 100644 --- a/module/config/argument/argument.yaml +++ b/module/config/argument/argument.yaml @@ -277,4 +277,6 @@ Daemon: value: true option: [ true ] option_bold: [ true, ] - + AimClicker: + value: do_not_click + option: [ item_enemy, item, enemy, do_not_click ] diff --git a/module/config/config_generated.py b/module/config/config_generated.py index da2a17684..df92ca4ce 100644 --- a/module/config/config_generated.py +++ b/module/config/config_generated.py @@ -148,3 +148,4 @@ class GeneratedConfig: # Group `Daemon` Daemon_Enable = True # True + Daemon_AimClicker = 'do_not_click' # item_enemy, item, enemy, do_not_click diff --git a/module/config/i18n/en-US.json b/module/config/i18n/en-US.json index d9dd273d4..3827d0f63 100644 --- a/module/config/i18n/en-US.json +++ b/module/config/i18n/en-US.json @@ -950,6 +950,14 @@ "name": "Dialogue Clicker", "help": "Monitor game, automatically click dialogue, phone chatting, and blessing in simulated universe (follow the simulated universe task settings)", "True": "Enabled" + }, + "AimClicker": { + "name": "Click Aimed Items and Enemies", + "help": "", + "item_enemy": "Click items and enemies", + "item": "Click items only", + "enemy": "Click enemies only", + "do_not_click": "Don't click" } }, "Gui": { diff --git a/module/config/i18n/es-ES.json b/module/config/i18n/es-ES.json index 2492c16e1..e6a38f61e 100644 --- a/module/config/i18n/es-ES.json +++ b/module/config/i18n/es-ES.json @@ -950,6 +950,14 @@ "name": "Clic de diálogo", "help": "Monitorear el juego, hacer clic automáticamente en el diálogo, chatear por teléfono y bendecir en el universo simulado (sigue la configuración de tareas del universo simulado)", "True": "Activado" + }, + "AimClicker": { + "name": "Haz clic en Objetos y enemigos apuntados", + "help": "", + "item_enemy": "Haz clic en elementos y enemigos", + "item": "Haz clic solo en elementos", + "enemy": "Haz clic solo en enemigos", + "do_not_click": "No hacer clic" } }, "Gui": { diff --git a/module/config/i18n/ja-JP.json b/module/config/i18n/ja-JP.json index 3d4216685..d4efefcb2 100644 --- a/module/config/i18n/ja-JP.json +++ b/module/config/i18n/ja-JP.json @@ -950,6 +950,14 @@ "name": "Daemon.Enable.name", "help": "Daemon.Enable.help", "True": "True" + }, + "AimClicker": { + "name": "Daemon.AimClicker.name", + "help": "Daemon.AimClicker.help", + "item_enemy": "item_enemy", + "item": "item", + "enemy": "enemy", + "do_not_click": "do_not_click" } }, "Gui": { diff --git a/module/config/i18n/zh-CN.json b/module/config/i18n/zh-CN.json index 3c49637d8..7a8294222 100644 --- a/module/config/i18n/zh-CN.json +++ b/module/config/i18n/zh-CN.json @@ -950,6 +950,14 @@ "name": "剧情连点器", "help": "监听画面自动点击剧情、手机聊天、模拟宇宙祝福(遵循模拟宇宙任务设置)", "True": "已启用" + }, + "AimClicker": { + "name": "点击被瞄准破坏物和敌人", + "help": "", + "item_enemy": "点击破坏物和敌人", + "item": "仅点击破坏物", + "enemy": "仅点击敌人", + "do_not_click": "不点击" } }, "Gui": { diff --git a/module/config/i18n/zh-TW.json b/module/config/i18n/zh-TW.json index 5a73b45f8..93808715e 100644 --- a/module/config/i18n/zh-TW.json +++ b/module/config/i18n/zh-TW.json @@ -950,6 +950,14 @@ "name": "劇情連點器", "help": "監聽畫面自動點擊劇情、手機聊天、模擬宇宙祝福(遵循模擬宇宙任務設定)", "True": "已啟用" + }, + "AimClicker": { + "name": "點擊被瞄準破壞物和敵人", + "help": "", + "item_enemy": "點擊破壞物和敵人", + "item": "僅點擊破壞物", + "enemy": "僅點擊敵人", + "do_not_click": "不點擊" } }, "Gui": { diff --git a/tasks/base/daemon.py b/tasks/base/daemon.py index 572a3ebd5..86bf70863 100644 --- a/tasks/base/daemon.py +++ b/tasks/base/daemon.py @@ -1,18 +1,63 @@ from module.base.timer import Timer +from module.daemon.daemon_base import DaemonBase +from module.device.method import maatouch from module.logger import logger from tasks.base.assets.assets_base_daemon import * from tasks.base.main_page import MainPage from tasks.base.page import page_main, page_rogue from tasks.daily.assets.assets_daily_camera import PICTURE_TAKEN from tasks.map.assets.assets_map_bigmap import TELEPORT_RIGHT +from tasks.map.interact.aim import AimDetectorMixin from tasks.rogue.route.base import RouteBase -class Daemon(RouteBase): +class SecondaryMaatouchBuilder(maatouch.MaatouchBuilder): + def __init__(self, device, contact=0, handle_orientation=False): + """ + Click on secondary contact to avoid interruption of real-person contact + """ + super().__init__(device, contact=1, handle_orientation=handle_orientation) + + +maatouch.MaatouchBuilder = SecondaryMaatouchBuilder + + +class Daemon(RouteBase, DaemonBase, AimDetectorMixin): + aim_interval = Timer(0.3, count=1) + + def handle_aim_click(self, item=True, enemy=True): + """ + Args: + item: + enemy: + + Returns: + bool: If clicked + """ + if not item and not enemy: + return False + if not self.is_in_main(): + return False + + if self.aim_interval.reached_and_reset(): + self.aim.predict(self.device.image, item=item, enemy=enemy) + if self.aim.aimed_enemy: + if self.handle_map_A(): + return True + if self.aim.aimed_item: + if self.handle_map_A(): + return True + return False + def run(self): # Rebind daemon settings along with rogue settings self.config.bind('Daemon', func_list=['Rogue']) - self.device.disable_stuck_detection() + # Check contact + builder = self.device.maatouch_builder + if builder.contact >= 1: + logger.info(f'Maatouch contact on {builder.contact}') + else: + logger.warning(f'Maatouch contact on {builder.contact}, may cause interruptions') teleport_confirm = Timer(1, count=5) while 1: @@ -65,3 +110,9 @@ class Daemon(RouteBase): continue if self.handle_event_option(): continue + # Aim click + if self.handle_aim_click( + item='item' in self.config.Daemon_AimClicker, + enemy='enemy' in self.config.Daemon_AimClicker, + ): + continue diff --git a/tasks/combat/combat.py b/tasks/combat/combat.py index 3ba806dad..d14e4fc39 100644 --- a/tasks/combat/combat.py +++ b/tasks/combat/combat.py @@ -1,4 +1,5 @@ from module.base.decorator import run_once +from module.exception import RequestHumanTakeover from module.logger import logger from tasks.combat.assets.assets_combat_finish import COMBAT_AGAIN, COMBAT_EXIT from tasks.combat.assets.assets_combat_prepare import COMBAT_PREPARE @@ -81,6 +82,7 @@ class Combat(CombatInteract, CombatPrepare, CombatState, CombatTeam, CombatSuppo logger.hr('Combat prepare') skip_first_screenshot = True pre_set_team = bool(support_character) + trial = 0 while 1: if skip_first_screenshot: skip_first_screenshot = False @@ -90,6 +92,11 @@ class Combat(CombatInteract, CombatPrepare, CombatState, CombatTeam, CombatSuppo # End if self.is_combat_executing(): return True + # Relics full + # Clicking between COMBAT_PREPARE and COMBAT_TEAM_PREPARE + if trial > 3: + logger.critical('Failed to enter dungeon after 3 trial, probably because relics are full') + raise RequestHumanTakeover # Click if self.appear(COMBAT_TEAM_SUPPORT) and support_character: @@ -112,6 +119,7 @@ class Combat(CombatInteract, CombatPrepare, CombatState, CombatTeam, CombatSuppo return False self.device.click(COMBAT_PREPARE) self.interval_reset(COMBAT_PREPARE) + trial += 1 continue if self.handle_combat_interact(): continue @@ -308,6 +316,9 @@ class Combat(CombatInteract, CombatPrepare, CombatState, CombatTeam, CombatSuppo Returns: int: Run count + Raises: + RequestHumanTakeover: If relics are full + Pages: in: COMBAT_PREPARE or page_main with DUNGEON_COMBAT_INTERACT diff --git a/tasks/dungeon/dungeon.py b/tasks/dungeon/dungeon.py index 10afe2bae..5bfb4e171 100644 --- a/tasks/dungeon/dungeon.py +++ b/tasks/dungeon/dungeon.py @@ -405,11 +405,15 @@ class Dungeon(DungeonStamina, DungeonEvent, Combat): return require def check_stamina_quest(self, stamina_used: int): - if KEYWORD_BATTLE_PASS_QUEST.Consume_a_total_of_1_Trailblaze_Power_1400_Trailblazer_Power_max not in self.weekly_quests: - return + logger.info(f'Used {stamina_used} stamina') - logger.info(f'Done Consume_a_total_of_1_Trailblaze_Power_1400_Trailblazer_Power_max stamina {stamina_used}') - self.config.stored.BattlePassQuestTrailblazePower.add(stamina_used) - if self.config.stored.BattlePassQuestTrailblazePower.is_full(): - logger.info('Achieved weekly quest Consume_a_total_of_1_Trailblaze_Power_1400_Trailblazer_Power_max') - self.achieved_weekly_quest = True + if KEYWORD_BATTLE_PASS_QUEST.Consume_a_total_of_1_Trailblaze_Power_1400_Trailblazer_Power_max in self.weekly_quests: + logger.info(f'Done Consume_a_total_of_1_Trailblaze_Power_1400_Trailblazer_Power_max stamina {stamina_used}') + self.config.stored.BattlePassQuestTrailblazePower.add(stamina_used) + if self.config.stored.BattlePassQuestTrailblazePower.is_full(): + logger.info('Achieved weekly quest Consume_a_total_of_1_Trailblaze_Power_1400_Trailblazer_Power_max') + self.achieved_weekly_quest = True + + if KEYWORDS_DAILY_QUEST.Consume_120_Trailblaze_Power in self.daily_quests: + logger.info(f'Done Consume_120_Trailblaze_Power stamina {stamina_used}') + self.achieved_daily_quest = True