diff --git a/tasks/BondlingFairyland/assets.py b/tasks/BondlingFairyland/assets.py index 4e9b6581d..527b7a8f7 100644 --- a/tasks/BondlingFairyland/assets.py +++ b/tasks/BondlingFairyland/assets.py @@ -12,17 +12,21 @@ class BondlingFairylandAssets: # Click Rule Assets # description - C_STONE_1 = RuleClick(roi_front=(230,533,23,20), roi_back=(0,0,100,100), name="stone_1") + C_STONE_1 = RuleClick(roi_front=(228,502,26,58), roi_back=(0,0,100,100), name="stone_1") # description - C_STONE_2 = RuleClick(roi_front=(441,569,23,20), roi_back=(0,0,100,100), name="stone_2") + C_STONE_2 = RuleClick(roi_front=(439,528,25,62), roi_back=(0,0,100,100), name="stone_2") # description - C_STONE_3 = RuleClick(roi_front=(692,537,23,20), roi_back=(0,0,100,100), name="stone_3") + C_STONE_3 = RuleClick(roi_front=(687,505,26,56), roi_back=(0,0,100,100), name="stone_3") # description - C_STONE_4 = RuleClick(roi_front=(944,529,23,20), roi_back=(0,0,100,100), name="stone_4") + C_STONE_4 = RuleClick(roi_front=(944,497,22,50), roi_back=(0,0,100,100), name="stone_4") # description C_STONE_5 = RuleClick(roi_front=(1041,494,25,25), roi_back=(0,0,100,100), name="stone_5") # description C_CAP_SUCCESS = RuleClick(roi_front=(317,102,378,363), roi_back=(0,0,100,100), name="cap_success") + # 逢魔之原地域 + C_AREA_2 = RuleClick(roi_front=(689,118,121,77), roi_back=(0,0,100,100), name="area_2") + # 平安京地域 + C_AREA_1 = RuleClick(roi_front=(628,314,108,137), roi_back=(0,0,100,100), name="area_1") # Ocr Rule Assets @@ -58,12 +62,16 @@ class BondlingFairylandAssets: # 求援 I_BALL_HELP = RuleImage(roi_front=(963,571,100,100), roi_back=(963,571,100,100), threshold=0.8, method="Template matching", file="./tasks/BondlingFairyland/ball/ball_ball_help.png") # 契灵创建队伍 - I_CREATE_TEAM = RuleImage(roi_front=(569,491,141,50), roi_back=(569,491,141,50), threshold=0.8, method="Template matching", file="./tasks/BondlingFairyland/ball/create_team.png") + I_CREATE_TEAM = RuleImage(roi_front=(569,491,141,50), roi_back=(569,491,141,50), threshold=0.8, method="Template matching", file="./tasks/BondlingFairyland/ball/ball_create_team.png") + # 地域 + I_BALL_AREA = RuleImage(roi_front=(61,631,50,48), roi_back=(8,582,138,137), threshold=0.8, method="Template matching", file="./tasks/BondlingFairyland/ball/ball_ball_area.png") + # 地域页面 + I_CHECK_AREA = RuleImage(roi_front=(489,377,238,95), roi_back=(454,337,314,170), threshold=0.8, method="Template matching", file="./tasks/BondlingFairyland/ball/ball_check_area.png") # Image Rule Assets - # description - I_BF_SEARSH = RuleImage(roi_front=(1133,577,100,100), roi_back=(1133,577,100,100), threshold=0.8, method="Template matching", file="./tasks/BondlingFairyland/bf/bf_bf_searsh.png") + # 探查按钮 + I_BF_SEARSH = RuleImage(roi_front=(1144,580,88,85), roi_back=(1102,531,176,188), threshold=0.8, method="Template matching", file="./tasks/BondlingFairyland/bf/bf_bf_searsh.png") # description I_BF_LOCK = RuleImage(roi_front=(826,653,24,26), roi_back=(826,653,24,26), threshold=0.8, method="Template matching", file="./tasks/BondlingFairyland/bf/bf_bf_lock.png") # description @@ -103,33 +111,43 @@ class BondlingFairylandAssets: I_BATTLE_FAIL_ABANDON = RuleImage(roi_front=(436,606,115,36), roi_back=(436,606,115,36), threshold=0.8, method="Template matching", file="./tasks/BondlingFairyland/capture/battle_fail_abandon.png") # description I_BATTLE_SUCCESS = RuleImage(roi_front=(651,203,70,81), roi_back=(651,203,70,81), threshold=0.8, method="Template matching", file="./tasks/BondlingFairyland/capture/battle_success.png") + # 再次结契 + I_CAP_AGAIN = RuleImage(roi_front=(730,598,113,53), roi_back=(693,572,176,99), threshold=0.8, method="Template matching", file="./tasks/BondlingFairyland/capture/capture_cap_again.png") # Image Rule Assets - # description - I_C_AUTO_TRUE = RuleImage(roi_front=(524,175,38,35), roi_back=(524,175,38,35), threshold=0.8, method="Template matching", file="./tasks/BondlingFairyland/capture/capture_c_auto_true.png") - # description - I_C_AUTO_FALSE = RuleImage(roi_front=(524,174,38,37), roi_back=(524,174,38,37), threshold=0.8, method="Template matching", file="./tasks/BondlingFairyland/capture/capture_c_auto_false.png") - # description - I_C_LOW_TRUE = RuleImage(roi_front=(543,271,30,32), roi_back=(543,271,30,32), threshold=0.8, method="Template matching", file="./tasks/BondlingFairyland/capture/capture_c_low_true.png") - # description - I_C_LOW_FALSE = RuleImage(roi_front=(539,269,37,35), roi_back=(539,269,37,35), threshold=0.8, method="Template matching", file="./tasks/BondlingFairyland/capture/capture_c_low_false.png") - # description - I_C_MIDUM_TRUE = RuleImage(roi_front=(680,277,35,27), roi_back=(680,277,35,27), threshold=0.8, method="Template matching", file="./tasks/BondlingFairyland/capture/capture_c_midum_true.png") - # description - I_C_MIDUM_FALSE = RuleImage(roi_front=(681,272,31,32), roi_back=(681,272,31,32), threshold=0.8, method="Template matching", file="./tasks/BondlingFairyland/capture/capture_c_midum_false.png") - # description - I_C_HIGH_TRUE = RuleImage(roi_front=(819,272,37,31), roi_back=(819,272,37,31), threshold=0.8, method="Template matching", file="./tasks/BondlingFairyland/capture/capture_c_high_true.png") - # description - I_C_HIGH_FALSE = RuleImage(roi_front=(818,272,36,34), roi_back=(818,272,36,34), threshold=0.8, method="Template matching", file="./tasks/BondlingFairyland/capture/capture_c_high_false.png") - # description - I_C_FIRST_ENABLE = RuleImage(roi_front=(524,472,33,31), roi_back=(524,472,33,31), threshold=0.8, method="Template matching", file="./tasks/BondlingFairyland/capture/capture_c_first_enable.png") - # description - I_C_FIRST_DISABLE = RuleImage(roi_front=(713,469,38,34), roi_back=(713,469,38,34), threshold=0.8, method="Template matching", file="./tasks/BondlingFairyland/capture/capture_c_first_disable.png") - # description - I_CAPTION_ENSURE = RuleImage(roi_front=(690,532,129,56), roi_back=(690,532,129,56), threshold=0.8, method="Template matching", file="./tasks/BondlingFairyland/capture/capture_caption_ensure.png") - # 结契设置 - I_CLICK_CAPTION = RuleImage(roi_front=(177,625,59,51), roi_back=(177,625,59,51), threshold=0.8, method="Template matching", file="./tasks/BondlingFairyland/capture/capture_click_caption.png") + # 启用自动结契 + I_C_AUTO_TRUE = RuleImage(roi_front=(765,200,50,24), roi_back=(749,187,79,51), threshold=0.8, method="Template matching", file="./tasks/BondlingFairyland/capture/capture_c_auto_true.png") + # 关闭自动结契 + I_C_AUTO_FALSE = RuleImage(roi_front=(766,200,43,25), roi_back=(745,189,88,44), threshold=0.8, method="Template matching", file="./tasks/BondlingFairyland/capture/capture_c_auto_false.png") + # 启用低级盘子 + I_C_LOW_TRUE = RuleImage(roi_front=(523,284,30,32), roi_back=(514,274,51,50), threshold=0.8, method="Template matching", file="./tasks/BondlingFairyland/capture/capture_c_low_true.png") + # 禁用低级盘子 + I_C_LOW_FALSE = RuleImage(roi_front=(521,282,33,35), roi_back=(513,275,48,47), threshold=0.8, method="Template matching", file="./tasks/BondlingFairyland/capture/capture_c_low_false.png") + # 启用中级盘子 + I_C_MIDUM_TRUE = RuleImage(roi_front=(663,283,31,31), roi_back=(653,277,49,46), threshold=0.8, method="Template matching", file="./tasks/BondlingFairyland/capture/capture_c_midum_true.png") + # 禁用中级盘子 + I_C_MIDUM_FALSE = RuleImage(roi_front=(662,283,31,32), roi_back=(654,276,49,45), threshold=0.8, method="Template matching", file="./tasks/BondlingFairyland/capture/capture_c_midum_false.png") + # 启用高级盘子 + I_C_HIGH_TRUE = RuleImage(roi_front=(800,283,33,36), roi_back=(792,273,49,50), threshold=0.8, method="Template matching", file="./tasks/BondlingFairyland/capture/capture_c_high_true.png") + # 禁用高级盘子 + I_C_HIGH_FALSE = RuleImage(roi_front=(801,283,32,34), roi_back=(792,273,51,50), threshold=0.8, method="Template matching", file="./tasks/BondlingFairyland/capture/capture_c_high_false.png") + # 启用优先连接羁绊式神 + I_C_FIRST_ENABLE = RuleImage(roi_front=(507,563,33,31), roi_back=(500,553,49,47), threshold=0.8, method="Template matching", file="./tasks/BondlingFairyland/capture/capture_c_first_enable.png") + # 禁用优先连接羁绊式神 + I_C_FIRST_DISABLE = RuleImage(roi_front=(708,560,38,34), roi_back=(702,553,49,49), threshold=0.8, method="Template matching", file="./tasks/BondlingFairyland/capture/capture_c_first_disable.png") + # 结契设置确定 + I_CAPTION_ENSURE = RuleImage(roi_front=(665,610,129,56), roi_back=(652,601,153,77), threshold=0.8, method="Template matching", file="./tasks/BondlingFairyland/capture/capture_caption_ensure.png") + # 结契设置按钮 + I_CLICK_CAPTION = RuleImage(roi_front=(68,414,54,42), roi_back=(48,398,97,81), threshold=0.8, method="Template matching", file="./tasks/BondlingFairyland/capture/capture_click_caption.png") + # 禁用连续使用盘子 + I_C_CONTINUOUS_DISABLE = RuleImage(roi_front=(709,468,33,36), roi_back=(702,462,50,52), threshold=0.8, method="Template matching", file="./tasks/BondlingFairyland/capture/capture_c_continuous_disable.png") + # 启用连续使用盘子 + I_C_CONTINUOUS_ENABLE = RuleImage(roi_front=(508,468,32,34), roi_back=(500,461,47,48), threshold=0.8, method="Template matching", file="./tasks/BondlingFairyland/capture/capture_c_continuous_enable.png") + # 启用结契极简模式 + I_C_MINIMAL_MODE_ENABLE = RuleImage(roi_front=(764,155,48,24), roi_back=(757,149,63,39), threshold=0.8, method="Template matching", file="./tasks/BondlingFairyland/capture/capture_c_minimal_mode_enable.png") + # 禁用结契极简模式 + I_C_MINIMAL_MODE_DISABLE = RuleImage(roi_front=(764,156,46,23), roi_back=(758,148,62,39), threshold=0.8, method="Template matching", file="./tasks/BondlingFairyland/capture/capture_c_minimal_mode_disable.png") # Image Rule Assets @@ -165,5 +183,7 @@ class BondlingFairylandAssets: I_BUY_ADD = RuleImage(roi_front=(678,540,43,40), roi_back=(678,540,43,40), threshold=0.8, method="Template matching", file="./tasks/BondlingFairyland/stone/buy_add.png") # description I_BUY_SUB = RuleImage(roi_front=(468,540,43,40), roi_back=(468,540,43,40), threshold=0.8, method="Template matching", file="./tasks/BondlingFairyland/stone/buy_sub.png") + # 关闭购买契灵页面 + I_STONE_CLOSE = RuleImage(roi_front=(911,56,42,38), roi_back=(888,49,100,100), threshold=0.8, method="Template matching", file="./tasks/BondlingFairyland/stone/stone_stone_close.png") diff --git a/tasks/BondlingFairyland/ball/ball_ball_area.png b/tasks/BondlingFairyland/ball/ball_ball_area.png new file mode 100644 index 000000000..cf7cbeb35 Binary files /dev/null and b/tasks/BondlingFairyland/ball/ball_ball_area.png differ diff --git a/tasks/BondlingFairyland/ball/ball_check_area.png b/tasks/BondlingFairyland/ball/ball_check_area.png new file mode 100644 index 000000000..c867554a9 Binary files /dev/null and b/tasks/BondlingFairyland/ball/ball_check_area.png differ diff --git a/tasks/BondlingFairyland/ball/create_team.png b/tasks/BondlingFairyland/ball/ball_create_team.png similarity index 100% rename from tasks/BondlingFairyland/ball/create_team.png rename to tasks/BondlingFairyland/ball/ball_create_team.png diff --git a/tasks/BondlingFairyland/ball/image.json b/tasks/BondlingFairyland/ball/image.json index 77e9281f5..ce01da530 100644 --- a/tasks/BondlingFairyland/ball/image.json +++ b/tasks/BondlingFairyland/ball/image.json @@ -46,11 +46,29 @@ }, { "itemName": "create_team", - "imageName": "create_team.png", + "imageName": "ball_create_team.png", "roiFront": "569,491,141,50", "roiBack": "569,491,141,50", "method": "Template matching", "threshold": 0.8, "description": "契灵创建队伍" + }, + { + "itemName": "ball_area", + "imageName": "ball_ball_area.png", + "roiFront": "61,631,50,48", + "roiBack": "8,582,138,137", + "method": "Template matching", + "threshold": 0.8, + "description": "地域" + }, + { + "itemName": "check_area", + "imageName": "ball_check_area.png", + "roiFront": "489,377,238,95", + "roiBack": "454,337,314,170", + "method": "Template matching", + "threshold": 0.8, + "description": "地域页面" } ] \ No newline at end of file diff --git a/tasks/BondlingFairyland/battle.py b/tasks/BondlingFairyland/battle.py index fcbfd78d5..ce3ecef3b 100644 --- a/tasks/BondlingFairyland/battle.py +++ b/tasks/BondlingFairyland/battle.py @@ -6,6 +6,7 @@ import random from module.server.i18n import I18n +from tasks.BondlingFairyland.config import BondlingMode from tasks.Component.GeneralBattle.general_battle import GeneralBattle from tasks.BondlingFairyland.assets import BondlingFairylandAssets from tasks.BondlingFairyland.config_battle import BattleConfig @@ -64,15 +65,28 @@ def catch_battle_wait(self, random_click_swipt_enable: bool) -> bool: # 战斗过程 随机点击和滑动 防封 logger.info("Start battle process") win: bool = False + bondling_mode = self.config.bondling_fairyland.bondling_config.bondling_mode + cap_again = bondling_mode in [BondlingMode.MODE3, BondlingMode.MODE4] + cap_cnt, max_cap = 0, 10 while 1: + # 捕获次数超过最大次数限制, 则不再进行捕获 + if cap_cnt >= max_cap: + cap_again = False self.screenshot() # 如果捕获成功 if self.appear_then_click(self.I_CAP_SUCCESS, action=self.C_CAP_SUCCESS, interval=1): win = True - # 如果捕获失败 + # 连续结契捕获失败 if self.appear_then_click(self.I_CAP_FAILURE, action=self.C_CAP_SUCCESS, interval=1): win = False - + # 非连续结契且单次抓捕失败 + if not cap_again and self.appear_then_click(self.I_BATTLE_FAIL_ABANDON, interval=1): + win = False + # 连续结契则继续结契 + if cap_again and self.appear_then_click(self.I_CAP_AGAIN, interval=1): + self.device.click_record_clear() # 需要10次结契因此清空点击记录 + cap_cnt += 1 + continue # 如果领奖励 if self.appear(self.I_REWARD, threshold=0.6): break @@ -80,8 +94,6 @@ def catch_battle_wait(self, random_click_swipt_enable: bool) -> bool: continue if self.appear_then_click(self.I_BATTLE_SUCCESS, threshold=0.6, interval=1): continue - if self.appear_then_click(self.I_BATTLE_FAIL_ABANDON, interval=1): - continue if self.appear_then_click(self.I_BATTLE_FAIL, threshold=0.6, interval=1): continue # 如果开启战斗过程随机滑动 diff --git a/tasks/BondlingFairyland/bf/bf_bf_searsh.png b/tasks/BondlingFairyland/bf/bf_bf_searsh.png index 9a491580e..c3ad9a6ac 100644 Binary files a/tasks/BondlingFairyland/bf/bf_bf_searsh.png and b/tasks/BondlingFairyland/bf/bf_bf_searsh.png differ diff --git a/tasks/BondlingFairyland/bf/image.json b/tasks/BondlingFairyland/bf/image.json index 45eb640cd..fd9279e25 100644 --- a/tasks/BondlingFairyland/bf/image.json +++ b/tasks/BondlingFairyland/bf/image.json @@ -2,11 +2,11 @@ { "itemName": "bf_searsh", "imageName": "bf_bf_searsh.png", - "roiFront": "1133,577,100,100", - "roiBack": "1133,577,100,100", + "roiFront": "1144,580,88,85", + "roiBack": "1102,531,176,188", "method": "Template matching", "threshold": 0.8, - "description": "description" + "description": "探查按钮" }, { "itemName": "bf_lock", diff --git a/tasks/BondlingFairyland/capture/capture.json b/tasks/BondlingFairyland/capture/capture.json index 2912ee1a2..99d964b4e 100644 --- a/tasks/BondlingFairyland/capture/capture.json +++ b/tasks/BondlingFairyland/capture/capture.json @@ -79,5 +79,14 @@ "method": "Template matching", "threshold": 0.8, "description": "description" + }, + { + "itemName": "cap_again", + "imageName": "capture_cap_again.png", + "roiFront": "730,598,113,53", + "roiBack": "693,572,176,99", + "method": "Template matching", + "threshold": 0.8, + "description": "再次结契" } ] \ No newline at end of file diff --git a/tasks/BondlingFairyland/capture/capture_c_auto_false.png b/tasks/BondlingFairyland/capture/capture_c_auto_false.png index a28cf56c1..27f42778a 100644 Binary files a/tasks/BondlingFairyland/capture/capture_c_auto_false.png and b/tasks/BondlingFairyland/capture/capture_c_auto_false.png differ diff --git a/tasks/BondlingFairyland/capture/capture_c_auto_true.png b/tasks/BondlingFairyland/capture/capture_c_auto_true.png index f15bda17d..ff72285d9 100644 Binary files a/tasks/BondlingFairyland/capture/capture_c_auto_true.png and b/tasks/BondlingFairyland/capture/capture_c_auto_true.png differ diff --git a/tasks/BondlingFairyland/capture/capture_c_continuous_disable.png b/tasks/BondlingFairyland/capture/capture_c_continuous_disable.png new file mode 100644 index 000000000..c8968f49c Binary files /dev/null and b/tasks/BondlingFairyland/capture/capture_c_continuous_disable.png differ diff --git a/tasks/BondlingFairyland/capture/capture_c_continuous_enable.png b/tasks/BondlingFairyland/capture/capture_c_continuous_enable.png new file mode 100644 index 000000000..ecc43daf2 Binary files /dev/null and b/tasks/BondlingFairyland/capture/capture_c_continuous_enable.png differ diff --git a/tasks/BondlingFairyland/capture/capture_c_first_disable.png b/tasks/BondlingFairyland/capture/capture_c_first_disable.png index 73a99373d..95a7dc699 100644 Binary files a/tasks/BondlingFairyland/capture/capture_c_first_disable.png and b/tasks/BondlingFairyland/capture/capture_c_first_disable.png differ diff --git a/tasks/BondlingFairyland/capture/capture_c_first_enable.png b/tasks/BondlingFairyland/capture/capture_c_first_enable.png index d26428a6c..b4a27f170 100644 Binary files a/tasks/BondlingFairyland/capture/capture_c_first_enable.png and b/tasks/BondlingFairyland/capture/capture_c_first_enable.png differ diff --git a/tasks/BondlingFairyland/capture/capture_c_high_false.png b/tasks/BondlingFairyland/capture/capture_c_high_false.png index f50c0348b..fb25d1f89 100644 Binary files a/tasks/BondlingFairyland/capture/capture_c_high_false.png and b/tasks/BondlingFairyland/capture/capture_c_high_false.png differ diff --git a/tasks/BondlingFairyland/capture/capture_c_high_true.png b/tasks/BondlingFairyland/capture/capture_c_high_true.png index 8ccae45f8..d899cf774 100644 Binary files a/tasks/BondlingFairyland/capture/capture_c_high_true.png and b/tasks/BondlingFairyland/capture/capture_c_high_true.png differ diff --git a/tasks/BondlingFairyland/capture/capture_c_low_false.png b/tasks/BondlingFairyland/capture/capture_c_low_false.png index 0937b540d..5994a5208 100644 Binary files a/tasks/BondlingFairyland/capture/capture_c_low_false.png and b/tasks/BondlingFairyland/capture/capture_c_low_false.png differ diff --git a/tasks/BondlingFairyland/capture/capture_c_low_true.png b/tasks/BondlingFairyland/capture/capture_c_low_true.png index 828eafd01..f68b12757 100644 Binary files a/tasks/BondlingFairyland/capture/capture_c_low_true.png and b/tasks/BondlingFairyland/capture/capture_c_low_true.png differ diff --git a/tasks/BondlingFairyland/capture/capture_c_midum_false.png b/tasks/BondlingFairyland/capture/capture_c_midum_false.png index 862c6e422..c1b01a967 100644 Binary files a/tasks/BondlingFairyland/capture/capture_c_midum_false.png and b/tasks/BondlingFairyland/capture/capture_c_midum_false.png differ diff --git a/tasks/BondlingFairyland/capture/capture_c_midum_true.png b/tasks/BondlingFairyland/capture/capture_c_midum_true.png index 5d0d0b382..6cd3387f7 100644 Binary files a/tasks/BondlingFairyland/capture/capture_c_midum_true.png and b/tasks/BondlingFairyland/capture/capture_c_midum_true.png differ diff --git a/tasks/BondlingFairyland/capture/capture_c_minimal_mode_disable.png b/tasks/BondlingFairyland/capture/capture_c_minimal_mode_disable.png new file mode 100644 index 000000000..b054e2bf9 Binary files /dev/null and b/tasks/BondlingFairyland/capture/capture_c_minimal_mode_disable.png differ diff --git a/tasks/BondlingFairyland/capture/capture_c_minimal_mode_enable.png b/tasks/BondlingFairyland/capture/capture_c_minimal_mode_enable.png new file mode 100644 index 000000000..77db34f81 Binary files /dev/null and b/tasks/BondlingFairyland/capture/capture_c_minimal_mode_enable.png differ diff --git a/tasks/BondlingFairyland/capture/capture_cap_again.png b/tasks/BondlingFairyland/capture/capture_cap_again.png new file mode 100644 index 000000000..fc378e9f8 Binary files /dev/null and b/tasks/BondlingFairyland/capture/capture_cap_again.png differ diff --git a/tasks/BondlingFairyland/capture/capture_caption_ensure.png b/tasks/BondlingFairyland/capture/capture_caption_ensure.png index 4142e8345..b098f6f23 100644 Binary files a/tasks/BondlingFairyland/capture/capture_caption_ensure.png and b/tasks/BondlingFairyland/capture/capture_caption_ensure.png differ diff --git a/tasks/BondlingFairyland/capture/capture_click_caption.png b/tasks/BondlingFairyland/capture/capture_click_caption.png index 9e2680bef..7316d7993 100644 Binary files a/tasks/BondlingFairyland/capture/capture_click_caption.png and b/tasks/BondlingFairyland/capture/capture_click_caption.png differ diff --git a/tasks/BondlingFairyland/capture/image.json b/tasks/BondlingFairyland/capture/image.json index d8b55a04b..618620e51 100644 --- a/tasks/BondlingFairyland/capture/image.json +++ b/tasks/BondlingFairyland/capture/image.json @@ -2,109 +2,145 @@ { "itemName": "c_auto_true", "imageName": "capture_c_auto_true.png", - "roiFront": "524,175,38,35", - "roiBack": "524,175,38,35", + "roiFront": "765,200,50,24", + "roiBack": "749,187,79,51", "method": "Template matching", "threshold": 0.8, - "description": "description" + "description": "启用自动结契" }, { "itemName": "c_auto_false", "imageName": "capture_c_auto_false.png", - "roiFront": "524,174,38,37", - "roiBack": "524,174,38,37", + "roiFront": "766,200,43,25", + "roiBack": "745,189,88,44", "method": "Template matching", "threshold": 0.8, - "description": "description" + "description": "关闭自动结契" }, { "itemName": "c_low_true", "imageName": "capture_c_low_true.png", - "roiFront": "543,271,30,32", - "roiBack": "543,271,30,32", + "roiFront": "523,284,30,32", + "roiBack": "514,274,51,50", "method": "Template matching", "threshold": 0.8, - "description": "description" + "description": "启用低级盘子" }, { "itemName": "c_low_false", "imageName": "capture_c_low_false.png", - "roiFront": "539,269,37,35", - "roiBack": "539,269,37,35", + "roiFront": "521,282,33,35", + "roiBack": "513,275,48,47", "method": "Template matching", "threshold": 0.8, - "description": "description" + "description": "禁用低级盘子" }, { "itemName": "c_midum_true", "imageName": "capture_c_midum_true.png", - "roiFront": "680,277,35,27", - "roiBack": "680,277,35,27", + "roiFront": "663,283,31,31", + "roiBack": "653,277,49,46", "method": "Template matching", "threshold": 0.8, - "description": "description" + "description": "启用中级盘子" }, { "itemName": "c_midum_false", "imageName": "capture_c_midum_false.png", - "roiFront": "681,272,31,32", - "roiBack": "681,272,31,32", + "roiFront": "662,283,31,32", + "roiBack": "654,276,49,45", "method": "Template matching", "threshold": 0.8, - "description": "description" + "description": "禁用中级盘子" }, { "itemName": "c_high_true", "imageName": "capture_c_high_true.png", - "roiFront": "819,272,37,31", - "roiBack": "819,272,37,31", + "roiFront": "800,283,33,36", + "roiBack": "792,273,49,50", "method": "Template matching", "threshold": 0.8, - "description": "description" + "description": "启用高级盘子" }, { "itemName": "c_high_false", "imageName": "capture_c_high_false.png", - "roiFront": "818,272,36,34", - "roiBack": "818,272,36,34", + "roiFront": "801,283,32,34", + "roiBack": "792,273,51,50", "method": "Template matching", "threshold": 0.8, - "description": "description" + "description": "禁用高级盘子" }, { "itemName": "c_first_enable", "imageName": "capture_c_first_enable.png", - "roiFront": "524,472,33,31", - "roiBack": "524,472,33,31", + "roiFront": "507,563,33,31", + "roiBack": "500,553,49,47", "method": "Template matching", "threshold": 0.8, - "description": "description" + "description": "启用优先连接羁绊式神" }, { "itemName": "c_first_disable", "imageName": "capture_c_first_disable.png", - "roiFront": "713,469,38,34", - "roiBack": "713,469,38,34", + "roiFront": "708,560,38,34", + "roiBack": "702,553,49,49", "method": "Template matching", "threshold": 0.8, - "description": "description" + "description": "禁用优先连接羁绊式神" }, { "itemName": "caption_ensure", "imageName": "capture_caption_ensure.png", - "roiFront": "690,532,129,56", - "roiBack": "690,532,129,56", + "roiFront": "665,610,129,56", + "roiBack": "652,601,153,77", "method": "Template matching", "threshold": 0.8, - "description": "description" + "description": "结契设置确定" }, { "itemName": "click_caption", "imageName": "capture_click_caption.png", - "roiFront": "177,625,59,51", - "roiBack": "177,625,59,51", + "roiFront": "68,414,54,42", + "roiBack": "48,398,97,81", "method": "Template matching", "threshold": 0.8, - "description": "结契设置" + "description": "结契设置按钮" + }, + { + "itemName": "c_continuous_disable", + "imageName": "capture_c_continuous_disable.png", + "roiFront": "709,468,33,36", + "roiBack": "702,462,50,52", + "method": "Template matching", + "threshold": 0.8, + "description": "禁用连续使用盘子" + }, + { + "itemName": "c_continuous_enable", + "imageName": "capture_c_continuous_enable.png", + "roiFront": "508,468,32,34", + "roiBack": "500,461,47,48", + "method": "Template matching", + "threshold": 0.8, + "description": "启用连续使用盘子" + }, + { + "itemName": "c_minimal_mode_enable", + "imageName": "capture_c_minimal_mode_enable.png", + "roiFront": "764,155,48,24", + "roiBack": "757,149,63,39", + "method": "Template matching", + "threshold": 0.8, + "description": "启用结契极简模式" + }, + { + "itemName": "c_minimal_mode_disable", + "imageName": "capture_c_minimal_mode_disable.png", + "roiFront": "764,156,46,23", + "roiBack": "758,148,62,39", + "method": "Template matching", + "threshold": 0.8, + "description": "禁用结契极简模式" } ] \ No newline at end of file diff --git a/tasks/BondlingFairyland/click.json b/tasks/BondlingFairyland/click.json index 024bce6a7..332831bc0 100644 --- a/tasks/BondlingFairyland/click.json +++ b/tasks/BondlingFairyland/click.json @@ -1,25 +1,25 @@ [ { "itemName": "stone_1", - "roiFront": "230,533,23,20", + "roiFront": "228,502,26,58", "roiBack": "0,0,100,100", "description": "description" }, { "itemName": "stone_2", - "roiFront": "441,569,23,20", + "roiFront": "439,528,25,62", "roiBack": "0,0,100,100", "description": "description" }, { "itemName": "stone_3", - "roiFront": "692,537,23,20", + "roiFront": "687,505,26,56", "roiBack": "0,0,100,100", "description": "description" }, { "itemName": "stone_4", - "roiFront": "944,529,23,20", + "roiFront": "944,497,22,50", "roiBack": "0,0,100,100", "description": "description" }, @@ -34,5 +34,17 @@ "roiFront": "317,102,378,363", "roiBack": "0,0,100,100", "description": "description" + }, + { + "itemName": "area_2", + "roiFront": "689,118,121,77", + "roiBack": "0,0,100,100", + "description": "逢魔之原地域" + }, + { + "itemName": "area_1", + "roiFront": "628,314,108,137", + "roiBack": "0,0,100,100", + "description": "平安京地域" } ] \ No newline at end of file diff --git a/tasks/BondlingFairyland/config.py b/tasks/BondlingFairyland/config.py index 3eec824a3..01f7ca20e 100644 --- a/tasks/BondlingFairyland/config.py +++ b/tasks/BondlingFairyland/config.py @@ -1,30 +1,45 @@ # This Python file uses the following encoding: utf-8 # @author runhey # github https://github.com/runhey -from pydantic import BaseModel, Field +from pydantic import BaseModel, Field, field_validator from enum import Enum from datetime import datetime, time -from tasks.Component.SwitchSoul.switch_soul_config import SwitchSoulConfig from tasks.Component.config_scheduler import Scheduler from tasks.Component.config_base import ConfigBase, DateTime, TimeDelta, Time from tasks.BondlingFairyland.config_battle import BattleConfig from tasks.Component.GeneralInvite.config_invite import InviteConfig -from tasks.Component.GeneralBattle.config_general_battle import GeneralBattleConfig - class BondlingMode(str, Enum): - MODE1 = 'mode_1' - MODE2 = 'mode_2' - MODE3 = 'mode_3' + MODE1 = '只刷探查(仅限单刷)' + MODE2 = '只刷契灵(低级式盘)' + MODE3 = '只刷契灵(中级式盘)' + MODE4 = '只刷契灵(高级式盘)' class BondlingClass(str, Enum): TOMB_GUARD = '镇墓兽' + AZURE_BASAN = '火灵' SNOWBALL = '茨球' LITTLE_KURO = '小黑' - AZURE_BASAN = '火灵' + + BONDLING_2_1 = '针女' + BONDLING_2_2 = '薙魂' + BONDLING_2_3 = '月魔兔' + BONDLING_2_4 = '狐火' + + @staticmethod + def get_index(value) -> int: + """根据枚举值或枚举返回对应顺序(从1开始)""" + if isinstance(value, BondlingClass): + member = value + else: + try: + member = BondlingClass(value) + except ValueError: + return None + return list(BondlingClass).index(member) + 1 class UserStatus(str, Enum): @@ -39,42 +54,60 @@ class UserStatus(str, Enum): class BondlingConfig(ConfigBase): # 身份 user_status: UserStatus = Field(default=UserStatus.ALONE, description='user_status_help') - bondling_mode: BondlingMode = Field(default=BondlingMode.MODE1, description='bondling_mode_help') + bondling_mode: BondlingMode = Field(default=BondlingMode.MODE1, + description='只刷探查:自动切换契灵对应地域\n低级式盘:自动切换非连续,非羁绊\n中级式盘:自动切换连续,羁绊') limit_time: Time = Field(default=Time(minute=30), description='limit_time_help') limit_count: int = Field(default=30, description='limit_count_help') - bondling_stone_enable: bool = Field(default=False, description='bondling_stone_enable_help') - bondling_stone_class: BondlingClass = Field(default=BondlingClass.TOMB_GUARD, description='bondling_stone_class_help') + bondling_stone_class: BondlingClass = Field(default=BondlingClass.TOMB_GUARD, description='设置需要刷的契灵') + bondling_stone_enable: bool = Field(default=False, description='没有契灵了是否使用鸣契石购买契灵') + bondling_search_enable: bool = Field(default=False, description='没有契灵了是否自动探查(要求身份必须是alone,否则此项无效)\n' + '若启用了购买契灵则优先购买契灵,购买失败则进行探查\n' + '若启用了切换御魂则切换契灵御魂的同时也会切换探查御魂\n' + '注:探查耗费的时间与次数也计入总时间和次数中') + check_enable: bool = Field(default=True, description='是否检查契忆数量') + limit_num: int = Field(default=2000, description='契忆数量限制,到达此限制将自动结束任务(仅在任务开始时判断)') + + @field_validator("bondling_mode", mode="before") + def convert_old_value(cls, v): + old_new_map = { + "mode_1": "只刷探查(仅限单刷)", + 'mode_2': '只刷契灵(低级式盘)', + 'mode_3': '只刷契灵(中级式盘)' + } + return old_new_map.get(v, v) class BondlingSwitchSoul(ConfigBase): - auto_switch_soul: bool = Field(default=False, description='auto_switch_soul_help') - # 镇墓兽 config - tomb_guard_switch: str = Field(default='-1,-1', description='tomb_guard_switch_help') - # 茨球 config - snowball_switch: str = Field(default='-1,-1', description='snowball_switch_help') - # 小黑 config - little_kuro_switch: str = Field(default='-1,-1', description='little_kuro_switch_help') - # 火灵 config - azure_basan_switch: str = Field(default='-1,-1', description='azure_basan_switch_help') - - -class BondlingCheck(ConfigBase): - check_enable: bool = Field(default=True, description='是否检查契忆数量') - limit_num: int = Field(default=2000, description='契忆数量限制') + enable: bool = Field(default=False, + description='若是数字,则以编号方式切换御魂(组号,队伍号),组号1-7,队伍号1-4\n若非数字,则自动以ocr方式切换御魂(组名,队伍名)') + search_switch: str = Field(default='', description='设置探查御魂装配分组') + tomb_guard_switch: str = Field(default='', description='tomb_guard_switch_help') + snowball_switch: str = Field(default='', description='snowball_switch_help') + little_kuro_switch: str = Field(default='', description='little_kuro_switch_help') + azure_basan_switch: str = Field(default='', description='azure_basan_switch_help') + bondling_2_1_switch: str = Field(default='', description='设置针女御魂装配分组') + bondling_2_2_switch: str = Field(default='', description='设置薙魂御魂装配分组') + bondling_2_3_switch: str = Field(default='', description='设置月魔兔御魂装配分组') + bondling_2_4_switch: str = Field(default='', description='设置狐火御魂装配分组') + + def get_switch_by_enum(self, bondling_enum: BondlingClass) -> tuple[str, tuple[str | int, str | int]]: + """根据枚举获取对应的 切换类型, (group,team)""" + return self.get_switch_by_name(f"{bondling_enum.name.lower()}_switch") + + def get_switch_by_name(self, switch_name: str) -> tuple[str, tuple[str | int, str | int]]: + """根据名称获取对应的御魂预设""" + group_team = getattr(self, switch_name, None) + if group_team is None or group_team.strip() == '' or ',' not in group_team or len(group_team.split(',')) != 2: + return None, (None, None) + group, team = group_team.split(',') + if group.isdigit() and team.isdigit(): + return 'int', (int(group), int(team)) + return 'str', (group, team) class BondlingFairyland(ConfigBase): scheduler: Scheduler = Field(default_factory=Scheduler) - bondling_check: BondlingCheck = Field(default_factory=BondlingCheck) bondling_config: BondlingConfig = Field(default_factory=BondlingConfig) - bondling_switch_soul: BondlingSwitchSoul = Field(default_factory=BondlingSwitchSoul) invite_config: InviteConfig = Field(default_factory=InviteConfig) + bondling_switch_soul: BondlingSwitchSoul = Field(default_factory=BondlingSwitchSoul) battle_config: BattleConfig = Field(default_factory=BattleConfig) - # battle_config: GeneralBattleConfig = Field(default_factory=GeneralBattleConfig) - - switch_soul_config: SwitchSoulConfig = Field(default_factory=SwitchSoulConfig) - - - - - diff --git a/tasks/BondlingFairyland/script_task.py b/tasks/BondlingFairyland/script_task.py index 1384babde..ce7a60761 100644 --- a/tasks/BondlingFairyland/script_task.py +++ b/tasks/BondlingFairyland/script_task.py @@ -4,6 +4,7 @@ from time import sleep +import random from cached_property import cached_property from datetime import datetime from datetime import timedelta, time @@ -36,57 +37,40 @@ class ScriptTask(GameUi, GeneralInvite, GeneralRoom, BondlingBattle, SwitchSoul, first_catch = True # 用于记录是否是第一次捕捉 def run(self): - # 引用配置 cong = self.config.bondling_fairyland - if cong.bondling_check.check_enable: + if cong.bondling_config.check_enable: logger.hr('第一步, 检查契忆数量', 2) self.ui_get_current_page() self.ui_goto(page_mall, confirm_wait=2.5) self.ui_click(self.I_MALL_SCCALES, self.I_MALL_SCCALES_CHECK) self.ui_click(self.I_MALL_BONDLINGS_SURE, self.I_MALL_BONDLINGS_ON) - - MAX_COUNT = cong.bondling_check.limit_num + MAX_COUNT = cong.bondling_config.limit_num cu, re, total = self.O_BL_CHECK_MONEY.ocr(self.device.image) - if cu >= MAX_COUNT: logger.info(f'契忆数量: {cu} 大于 {MAX_COUNT}') self.ui_get_current_page() self.ui_goto(page_main) self.set_next_run(task='BondlingFairyland', finish=True, success=True) raise TaskEnd - logger.info(f'契忆数量: {cu} 小于 {MAX_COUNT}, 继续任务') - logger.hr('第二步, 切换御魂', 2) - # 御魂切换方式一 - if cong.switch_soul_config.enable: - self.ui_get_current_page() - self.ui_goto(page_shikigami_records) - self.run_switch_soul(cong.switch_soul_config.switch_group_team) - # 御魂切换方式二 - if cong.switch_soul_config.enable_switch_by_name: - self.ui_get_current_page() - self.ui_goto(page_shikigami_records) - self.run_switch_soul_by_name(cong.switch_soul_config.group_name, cong.switch_soul_config.team_name) - + self.switch_soul() logger.hr('第三步, 前往契灵主界面', 2) - self.ui_get_current_page() - self.ui_goto(page_bondling_fairyland) - - while 1: - self.screenshot() - if self.appear(self.I_CHECK_BONDLING_FAIRYLAND, interval=1): - break - if self.appear(self.I_BALL_HELP, interval=1): - self.ui_get_current_page() - self.ui_goto(page_bondling_fairyland) - continue - + self.ui_goto_page(page_bondling_fairyland) logger.hr('第四步, 开始战斗准备', 2) self.current_count = 0 self.limit_count = cong.bondling_config.limit_count # 默认limit_count值 - + logger.hr('Goto bondling area') + self.goto_ball_area(BondlingClass.get_index(cong.bondling_config.bondling_stone_class)) + + if cong.bondling_config.bondling_mode == BondlingMode.MODE1: # model1只刷探查 + if cong.bondling_config.user_status != UserStatus.ALONE: + raise ValueError(f'Now is model1, but user status is not alone, current: {cong.bondling_config.user_status.value}') + self.run_search(cong.bondling_config) + self.ui_goto_page(page_main) + self.set_next_run(task='BondlingFairyland', finish=True, success=True) + raise TaskEnd match cong.bondling_config.user_status: case UserStatus.handoff1: self.limit_count //= 2 @@ -132,7 +116,7 @@ def create_bond_team(): self.appear_then_click(self.I_CREATE_TEAM, interval=2) continue # 求援 - if self.appear(self.I_CHECK_BONDLING_FAIRYLAND, interval=1): + if self.appear(self.I_BALL_AREA, interval=1): return False if self.appear(self.I_BALL_HELP, interval=1): cu, res, total = self.O_B_BALL_NUMBER.ocr(self.device.image) @@ -256,7 +240,7 @@ def run_member(self): while 1: # 有一种情况是本来要退出的,但是队长邀请了进入的战斗的加载界面 - if self.appear(self.I_GI_HOME) or self.appear(self.I_GI_EXPLORE) or self.appear(self.I_CHECK_BONDLING_FAIRYLAND) or self.appear(self.I_BALL_HELP) : + if self.appear(self.I_GI_HOME) or self.appear(self.I_GI_EXPLORE) or self.appear(self.I_BALL_AREA) or self.appear(self.I_BALL_HELP) : break # 如果可能在房间就退出 if self.exit_room(): @@ -276,41 +260,39 @@ def switch_ball(self): cong = self.config.bondling_fairyland bondling_config = cong.bondling_config - bondling_switch_soul = cong.bondling_switch_soul battle_config = cong.battle_config logger.info(f'抓捕契灵: [{bondling_config.bondling_stone_class}] ') - match bondling_config.bondling_stone_class: - case BondlingClass.TOMB_GUARD: - current_ball_index = 1 - case BondlingClass.AZURE_BASAN: - current_ball_index = 2 - case BondlingClass.SNOWBALL: - current_ball_index = 3 - case BondlingClass.LITTLE_KURO: - current_ball_index = 4 - case _: - current_ball_index = 1 - + idx = BondlingClass.get_index(bondling_config.bondling_stone_class) + current_ball_index = idx if idx is not None else 1 + capture_setting_checked = False while 1: - if not self.in_search_ui(screenshot=True): self.ui_get_current_page() self.ui_goto(page_bondling_fairyland) continue - if bondling_config.bondling_mode != BondlingMode.MODE1: if self.ball_click(current_ball_index): - logger.info(f'Current ball number: {current_ball_index} ') + logger.info(f'Current ball index: {current_ball_index} ') else: - if self.run_stone(bondling_config.bondling_stone_enable, bondling_config.bondling_stone_class): + if self.run_stone(bondling_config.bondling_stone_enable): continue + elif bondling_config.bondling_search_enable and bondling_config.user_status == UserStatus.ALONE: + if self.run_search(bondling_config, limit_cnt=random.randint(5, 20)): + logger.info('Bondling search finish, try to run catch') + continue + else: + break # 时间到了或次数到了直接退出 else: logger.info('No bondling stone, exit') break + # 检查结契设置 + if not capture_setting_checked: + self.capture_setting(bondling_config.bondling_mode) + capture_setting_checked = True try: # 执行捕捉 - if self.run_catch(bondling_config, bondling_switch_soul, battle_config): + if self.run_catch(bondling_config, battle_config): logger.info(f'Catch successful and current ball number: {current_ball_index} ') else: break @@ -335,51 +317,54 @@ def switch_ball(self): self.set_next_run(task='BondlingFairyland', finish=True, success=True) raise TaskEnd - def run_stone(self, bondling_stone_enable: bool, bondling_stone_class: BondlingClass): + def run_stone(self, bondling_stone_enable: bool): """ 使用结契石 进行召唤 契灵 - :param bondling_stone_class: :param bondling_stone_enable: :return: (0) 不开启使用结契石,(探查界面)返回False (1) 没有结契石了,(探查界面)返回False """ - if not bondling_stone_enable: + # 没有启用使用石头购买契灵或者当前不在购买界面则直接退出 + if not bondling_stone_enable or not self.appear(self.I_STONE_SURE): + self.ui_click_until_disappear(self.I_STONE_CLOSE, interval=1.2) + return False + cu, res, total = self.O_B_STONE_NUMBER.ocr(self.device.image) + # 如果没有石头了 + if cu == 0 and cu + res == total: + self.ui_click_until_disappear(self.I_STONE_CLOSE, interval=1.2) + logger.warning(f'已经没有鸣契石召唤契灵了') return False while 1: self.screenshot() if not self.appear(self.I_STONE_SURE): - return False - # 如果没有石头了 - cu, res, total = self.O_B_STONE_NUMBER.ocr(self.device.image) - if cu == 0 and cu + res == total: - logger.warning(f'已经没有鸣契石召唤契灵了') - return False - while 1: - self.screenshot() - if not self.appear(self.I_STONE_SURE): - return True - for i in range(3): - if self.appear_then_click(self.I_BUY_PLUS, interval=1): - sleep(0.5) - if self.appear_then_click(self.I_GI_SURE, interval=1): - continue - if self.appear_then_click(self.I_STONE_SURE, interval=1): - continue + sleep(random.uniform(1.5, 2)) # 等待购买后的动画, 否则已经买了但是下次再点击还会出现该界面 + return True + for i in range(3): + if self.appear_then_click(self.I_BUY_PLUS, interval=1): + sleep(0.5) + if self.appear_then_click(self.I_GI_SURE, interval=1): + continue + if self.appear_then_click(self.I_STONE_SURE, interval=1): + continue - def run_search(self, bondling_config: BondlingConfig): + def run_search(self, bondling_config: BondlingConfig, limit_cnt: int = None): """ 运行探查 :return: (1) 超出战斗的次数的了,(探查页面)返回False (2) 超过时间限制了,(探查页面)返回False (3) 打满五只球了,(探查界面)返回True + (4) 打满对应limit_cnt次, (探查界面)返回True """ self.lock_team() while 1: # 检查是不是在探查界面, if not self.in_search_ui(screenshot=True): continue + # 检查是否打满limit_cnt次 + if limit_cnt is not None and limit_cnt <= 0: + return True # 检查是否有挑战次数 if self.current_count >= bondling_config.limit_count: logger.warning(f'No challenge count, exit') @@ -388,16 +373,16 @@ def run_search(self, bondling_config: BondlingConfig): if datetime.now() - self.start_time >= self.limit_time: logger.warning(f'No time, exit') return False - if self.click_search(): self.run_general_battle(self.general_battle_config) + if limit_cnt is not None: + limit_cnt = limit_cnt - 1 + logger.info(f'Remain search battle: {limit_cnt}') else: logger.warning(f'Full five ball') return True - def run_catch(self, bondling_config: BondlingConfig, - bondling_switch_soul: BondlingSwitchSoul, - battle_config: BattleConfig): + def run_catch(self, bondling_config: BondlingConfig, battle_config: BattleConfig): """ 执行捕捉的(确保进入了结契界面) :return: @@ -415,6 +400,8 @@ def check_plate_number(): target_plate = self.O_B_LOW_NUMBER case BondlingMode.MODE3: target_plate = self.O_B_MEDIUM_NUMBER + case BondlingMode.MODE4: + target_plate = self.O_B_HIGH_NUMBER case _: logger.error('Invalid bondling mode') return False @@ -446,7 +433,7 @@ def check_ball_number(): while 1: self.screenshot() - if self.appear(self.I_CHECK_BONDLING_FAIRYLAND): + if self.appear(self.I_BALL_AREA): return True # 如果不在结契界面,就等待 @@ -491,10 +478,8 @@ def ball_click(self, index: int) -> bool: :param index: :return: """ - def get_click_target(ind: int): - if ind > 5 or ind < 1: - raise ValueError('index must be 1-5') + """获取对应契灵点击位置""" match = { 1: self.C_STONE_1, 2: self.C_STONE_2, @@ -502,7 +487,7 @@ def get_click_target(ind: int): 4: self.C_STONE_4, 5: self.C_STONE_5, } - return match[ind] + return match[(ind - 1) % 4 + 1] click_target = get_click_target(index) click_count = 0 @@ -517,6 +502,25 @@ def get_click_target(ind: int): if self.click(click_target, interval=1): click_count += 1 + def goto_ball_area(self, index: int): + """进入契灵对应地域,最终在探查界面""" + def get_click_area(ind: int): + """获取对应契灵地域点击位置""" + if 1 <= ind <= 4: # 平安京 + return self.C_AREA_1 + if 5 <= ind <= 8: # 逢魔之原 + return self.C_AREA_2 + return None + # 进入地域页面 + while True: + self.screenshot() + if self.appear(self.I_CHECK_AREA, interval=0.6): + break + if self.appear_then_click(self.I_BALL_AREA, interval=1.2): + continue + # 点击对应地域并返回契灵主界面 + self.ui_click(get_click_area(index), self.I_BALL_AREA, interval=0.8) + def capture_setting(self, mode: BondlingMode) -> None: """ 第一次进入任务的时候触发这一项方法:为了确保用户的选择默认是正确的 @@ -527,51 +531,36 @@ def capture_setting(self, mode: BondlingMode) -> None: if mode == BondlingMode.MODE1: return None logger.info(f'Capture setting mode: {mode}') - while 1: - self.screenshot() - if self.appear(self.I_CAPTION_ENSURE): - break - if self.appear_then_click(self.I_CLICK_CAPTION, interval=1): - continue - - while 1: - self.screenshot() - if self.appear(self.I_C_AUTO_TRUE): - break - if self.appear_then_click(self.I_C_AUTO_FALSE, interval=1): - continue + self.ui_click(self.I_CLICK_CAPTION, self.I_CAPTION_ENSURE, interval=1) # 打开结契设置 + self.ui_click(self.I_C_AUTO_FALSE, self.I_C_AUTO_TRUE, interval=1) # 自动结契 + self.ui_click(self.I_C_MINIMAL_MODE_DISABLE, self.I_C_MINIMAL_MODE_ENABLE, interval=0.8) # 极简模式 target_true = None target_false = None target_first = None + target_continuous = None if mode == BondlingMode.MODE3: target_true = self.I_C_MIDUM_TRUE target_false = self.I_C_MIDUM_FALSE target_first = self.I_C_FIRST_ENABLE + target_continuous = self.I_C_CONTINUOUS_ENABLE elif mode == BondlingMode.MODE2: target_true = self.I_C_LOW_TRUE target_false = self.I_C_LOW_FALSE target_first = self.I_C_FIRST_DISABLE - while 1: - self.screenshot() - if self.appear(target_true): - break - if self.appear_then_click(target_false, interval=1): - continue - while 1: - self.screenshot() - if not self.appear(target_first): - break - if self.appear_then_click(target_first, interval=1): - continue - + target_continuous = self.I_C_CONTINUOUS_DISABLE + elif mode == BondlingMode.MODE4: # 高级盘子不需要设置连续结契和羁绊式神 + target_true = self.I_C_HIGH_TRUE + target_false = self.I_C_HIGH_FALSE + if target_true is not None: # 切换盘子 + self.ui_click(target_false, target_true, interval=1) + if target_continuous is not None: # 是否连续结契 + self.ui_click_until_disappear(target_continuous, interval=1) + if target_first is not None: # 是否使用羁绊式神 + self.ui_click_until_disappear(target_first, interval=1) # 点击确定退出 - while 1: - self.screenshot() - if not self.appear(self.I_CAPTION_ENSURE): - break - if self.appear_then_click(self.I_CAPTION_ENSURE, interval=1): - continue + self.ui_click_until_disappear(self.I_CAPTION_ENSURE, interval=1) + return None def enter_shikigami_records(self) -> None: """ @@ -662,7 +651,7 @@ def wait_battle(self, wait_time: time) -> bool: self.screenshot() # 如果自己在探索界面或者是庭院,那就是房间已经被销毁了 - if self.appear(self.I_GI_HOME) or self.appear(self.I_GI_EXPLORE) or self.appear(self.I_CHECK_BONDLING_FAIRYLAND) or self.appear(self.I_BALL_HELP): + if self.appear(self.I_GI_HOME) or self.appear(self.I_GI_EXPLORE) or self.appear(self.I_BALL_AREA) or self.appear(self.I_BALL_HELP): logger.warning('Room destroyed') success = False break @@ -790,6 +779,33 @@ def general_battle_config(self): gbc.random_click_swipt_enable = False return gbc + def switch_soul(self): + def do_switch_soul(ts: str, g: str | int, te: str | int): + if ts is None: + raise ValueError(f'Invalid switch soul config on {bondling_config.bondling_stone_class.value}') + if ts == 'int': + self.run_switch_soul((g, te)) + if ts == 'str': + self.run_switch_soul_by_name(g, te) + cong = self.config.bondling_fairyland + if not cong.bondling_switch_soul.enable: + return + bondling_config = cong.bondling_config + bondling_switch_soul = cong.bondling_switch_soul + self.ui_goto_page(page_shikigami_records) + # 单刷探查配置 + if bondling_config.bondling_mode == BondlingMode.MODE1: + type_str, (group, team) = bondling_switch_soul.get_switch_by_name('search_switch') + do_switch_soul(type_str, group, team) + return + # 刷契灵配置 + type_str, (group, team) = bondling_switch_soul.get_switch_by_enum(bondling_config.bondling_stone_class) + do_switch_soul(type_str, group, team) + # 启用了刷契灵时开启探查且是单人模式 + if bondling_config.bondling_search_enable and bondling_config.user_status == UserStatus.ALONE: + type_str, (group, team) = bondling_switch_soul.get_switch_by_name('search_switch') + do_switch_soul(type_str, group, team) + if __name__ == '__main__': from module.config.config import Config diff --git a/tasks/BondlingFairyland/stone/image.json b/tasks/BondlingFairyland/stone/image.json index 7406bab5c..a232e2390 100644 --- a/tasks/BondlingFairyland/stone/image.json +++ b/tasks/BondlingFairyland/stone/image.json @@ -43,5 +43,14 @@ "method": "Template matching", "threshold": 0.8, "description": "description" + }, + { + "itemName": "stone_close", + "imageName": "stone_stone_close.png", + "roiFront": "911,56,42,38", + "roiBack": "888,49,100,100", + "method": "Template matching", + "threshold": 0.8, + "description": "关闭购买契灵页面" } ] \ No newline at end of file diff --git a/tasks/BondlingFairyland/stone/stone_stone_close.png b/tasks/BondlingFairyland/stone/stone_stone_close.png new file mode 100644 index 000000000..bb8356fce Binary files /dev/null and b/tasks/BondlingFairyland/stone/stone_stone_close.png differ diff --git a/tasks/GameUi/page.py b/tasks/GameUi/page.py index c8d3383cb..5700087f1 100644 --- a/tasks/GameUi/page.py +++ b/tasks/GameUi/page.py @@ -4,6 +4,7 @@ import traceback from module.atom.click import RuleClick +from tasks.BondlingFairyland.assets import BondlingFairylandAssets from tasks.GlobalGame.assets import GlobalGameAssets as GGA from tasks.GameUi.assets import GameUiAssets as G from tasks.KekkaiUtilize.assets import KekkaiUtilizeAssets @@ -110,7 +111,7 @@ def link(self, button, destination): page_six_gates.link(button=G.I_SIX_GATES_GOTO_EXPLORATION, destination=page_exploration) page_exploration.link(button=G.I_EXPLORATION_GOTO_SIX_GATES, destination=page_six_gates) # 契灵之境 bondling fairyland -page_bondling_fairyland = Page(G.I_CHECK_BONDLING_FAIRYLAND) +page_bondling_fairyland = Page(BondlingFairylandAssets.I_BALL_AREA) page_bondling_fairyland.link(button=G.I_BACK_YOLLOW, destination=page_exploration) page_exploration.link(button=G.I_EXPLORATION_GOTO_BONDLING_FAIRYLAND, destination=page_bondling_fairyland) # 英杰试炼 hero test diff --git a/tasks/GuildActivityMonitor/config.py b/tasks/GuildActivityMonitor/config.py index e39ccca16..dee218685 100644 --- a/tasks/GuildActivityMonitor/config.py +++ b/tasks/GuildActivityMonitor/config.py @@ -9,6 +9,7 @@ class GuildActivityMonitorCombatTime(BaseModel): detection_interval: int = Field(default=30, description="通知检测间隔(秒)\n通过adb检测系统中收到的活动推送,自动拉起对应任务") monitor_duration: int = Field(default=15, description="监控持续时间(分)\n请确保已开启游戏通知权限,游戏设置权限中对应活动推送") recheck_interval: int = Field(default=5, description="拉起对应活动后,间隔多久再次开启检测(分)\n若监控时间内未检测到活动,则按调度器设置下次运行时间") + run_days: str = Field(default="1,2,3,4,5,6,7", description="运行日期,1-7 对应周一到周日;例如 5,6,7") class GuildActivity(BaseModel): # 道馆 diff --git a/tasks/GuildActivityMonitor/script_task.py b/tasks/GuildActivityMonitor/script_task.py index 29578ea4e..f527b3a43 100644 --- a/tasks/GuildActivityMonitor/script_task.py +++ b/tasks/GuildActivityMonitor/script_task.py @@ -15,8 +15,30 @@ def run(self): :return: """ + monitor_config = self.config.guild_activity_monitor.guild_activity_monitor_combat_time + now = datetime.now() + today = now.weekday() + 1 + run_days = sorted({day for day in map(int, re.findall(r'\d+', monitor_config.run_days)) if 1 <= day <= 7}) + if not run_days: + logger.warning(f"运行日期配置无效: {monitor_config.run_days},跳过 GuildActivityMonitor") + raise TaskEnd('GuildActivityMonitor') + + in_run_days = today in run_days + candidate_days = [day for day in run_days if day != today] if in_run_days else run_days + delta_days = min((day - today) % 7 for day in candidate_days) + next_date = now + timedelta(days=delta_days or 7) + + server_update = self.config.guild_activity_monitor.scheduler.server_update + use_server_time = (server_update.hour, server_update.minute, server_update.second) != (9, 0, 0) + next_target = datetime.combine(next_date.date(), server_update) if use_server_time else next_date + status = '在' if in_run_days else '不在' + action = '本次继续执行' if in_run_days else '跳过 GuildActivityMonitor' + logger.info(f"今天是周{today},{status}配置运行日期({monitor_config.run_days})内,"f"{action},下次运行时间: {next_target}") + self.set_next_run(task='GuildActivityMonitor',success=None,finish=False,server=False,target=next_target) + if not in_run_days: + raise TaskEnd('GuildActivityMonitor') + # 构建关键字映射 - self.set_next_run(task='GuildActivityMonitor', success=True, finish=True) self.ui_get_current_page() self.ui_goto(page_main) guild_config = self.config.guild_activity_monitor.guild_activity @@ -45,43 +67,48 @@ def run(self): # 获取初始通知时间 init_time, _ = self.get_notification_info() + # 监控任务属于长等待场景,加入长等待白名单,避免被全局卡死检测误判 + self.device.stuck_record_add('PAUSE') + # 主监控循环 - while True: - if check_timer.reached(): - logger.info("监控时间到,任务结束") - raise TaskEnd('GuildActivityMonitor') - - if log_timer.reached(): - remaining = int(check_timer.remain() // 60) - logger.info(f"监控中... 剩余时间: {remaining}分钟") - log_timer.reset() - - # 处理突发事件 - self.screenshot() - - # 检测新通知 - current_time, notification_text = self.get_notification_info() - if current_time > init_time and notification_text: - logger.info(f"检测到新通知: {notification_text}") - for keyword, task_name in KEYWORD_MAP.items(): - if keyword in notification_text: - logger.info(f"检测到关键字 '{keyword}',启动任务: {task_name}") - self.set_next_run(task=task_name, success=False, finish=False, server=False, target=datetime.now()) - recheck_interval = monitor_config.recheck_interval - self.set_next_run(task='GuildActivityMonitor', success=False, finish=False, server=False, target=datetime.now() + timedelta(minutes=recheck_interval)) - raise TaskEnd('GuildActivityMonitor') - - time.sleep(interval) + try: + while True: + if check_timer.reached(): + logger.info("监控时间到,任务结束") + raise TaskEnd('GuildActivityMonitor') + + if log_timer.reached(): + remaining = int(check_timer.remain() // 60) + logger.info(f"监控中... 剩余时间: {remaining}分钟") + log_timer.reset() + + # 处理突发事件 + self.screenshot() + + # 检测新通知 + current_time, notification_text = self.get_notification_info() + if current_time > init_time and notification_text: + logger.info(f"检测到新通知: {notification_text}") + for keyword, task_name in KEYWORD_MAP.items(): + if keyword in notification_text: + logger.info(f"检测到关键字 '{keyword}',启动任务: {task_name}") + self.set_next_run(task=task_name, success=False, finish=False, server=False, target=datetime.now()) + recheck_interval = monitor_config.recheck_interval + self.set_next_run(task='GuildActivityMonitor', success=False, finish=False, server=False, target=datetime.now() + timedelta(minutes=recheck_interval)) + raise TaskEnd('GuildActivityMonitor') + + time.sleep(interval) + finally: + self.device.stuck_record_clear() def get_notification_info(self) -> tuple: try: output = self.device.adb_shell(['dumpsys', 'notification', '--noredact']) - # 改进的通知时间提取逻辑 - 只获取最新的通知 + # 通知时间提取逻辑 - 只获取最新的通知 notification_time = 0 notification_text = "" - - # 使用更精确的正则表达式匹配每个通知块 + # 查找所有通知块,每个块包含时间戳和文本 notification_blocks = re.findall(r'(when=(\d+)[\s\S]*?(?=when=|\Z))', output) @@ -131,4 +158,4 @@ def clear_notifications(self): c = Config('oas1') d = Device(c) t = ScriptTask(c, d) - t.run() + t.run() \ No newline at end of file