diff --git a/src/char/BaseChar.py b/src/char/BaseChar.py index ec3cd1b..3376f84 100644 --- a/src/char/BaseChar.py +++ b/src/char/BaseChar.py @@ -114,10 +114,10 @@ class BaseChar: else: invalid_count += 1 has_cd = invalid_count == 0 and (has_dot and 2 <= number_count <= 3) - if self.task.debug: - msg = f"{self}_{has_cd}_{box_name} number_count {number_count} big_count {big_area_count} invalid_count {invalid_count} has_dot {has_dot}" - # self.task.screenshot(msg, frame=cropped) - self.logger.debug(msg) + # if self.task.debug: + # msg = f"{self}_{has_cd}_{box_name} number_count {number_count} big_count {big_area_count} invalid_count {invalid_count} has_dot {has_dot}" + # self.task.screenshot(msg, frame=cropped) + # self.logger.debug(msg) return has_cd def is_available(self, percent, box_name): diff --git a/src/combat/CombatCheck.py b/src/combat/CombatCheck.py index 52dbd6f..3946f68 100644 --- a/src/combat/CombatCheck.py +++ b/src/combat/CombatCheck.py @@ -3,7 +3,7 @@ import time import cv2 -from ok.color.Color import find_color_rectangles, keep_pixels_in_color_range +from ok.color.Color import find_color_rectangles, keep_pixels_in_color_range, is_pure_black from ok.feature.Box import find_boxes_by_name from ok.logging.Logger import get_logger from src import text_white_color @@ -22,8 +22,12 @@ class CombatCheck: self.last_combat_check = 0 self.boss_lv_box = None self.boss_health_box = None + self.out_of_combat_reason = "" - def reset_to_false(self, recheck=False): + def reset_to_false(self, recheck=False, reason=""): + if is_pure_black(self.frame): + logger.error('getting a pure black frame for unknown reason, reset_to_false return true') + return True if recheck and time.time() - self.last_out_of_combat_time > 2.1: logger.info('out of combat start double check') if self.debug: @@ -32,6 +36,7 @@ class CombatCheck: return True else: # logger.info('out of combat start double check sleep end') + self.out_of_combat_reason = reason self._in_combat = False self.boss_lv_edge = None self.in_liberation = False # return True @@ -110,7 +115,7 @@ class CombatCheck: def find_target_enemy(self): start = time.time() target_enemy = self.find_one('target_enemy_white', box=self.box_of_screen(0.14, 0.12, 0.8, 0.8), - use_gray_scale=True, threshold=0.92, + use_gray_scale=True, threshold=0.83, frame_processor=process_target_enemy_area) # if self.debug and target_enemy is not None: # self.screenshot('find_target_enemy') @@ -126,19 +131,19 @@ class CombatCheck: if now - self.last_combat_check > 1: self.last_combat_check = now if not self.in_team()[0]: - return self.reset_to_false(recheck=True) + return self.reset_to_false(recheck=False, reason="not in team") if self.boss_lv_edge is not None: if self.check_boss(): return True else: - return self.reset_to_false(recheck=False) + return self.reset_to_false(recheck=False, reason="boss disappear") if self.check_count_down(): return True if not self.check_health_bar(): logger.debug('not in team or no health bar') if not self.target_enemy(): logger.error('target_enemy failed, break out of combat') - return self.reset_to_false() + return self.reset_to_false(reason='target enemy failed') return True else: logger.debug( diff --git a/src/task/AutoCombatTask.py b/src/task/AutoCombatTask.py index 049cbdc..04d1fff 100644 --- a/src/task/AutoCombatTask.py +++ b/src/task/AutoCombatTask.py @@ -13,9 +13,9 @@ class AutoCombatTask(BaseCombatTask, TriggerTask): logger.debug(f'autocombat loop {self.chars}') self.get_current_char().perform() except NotInCombatException as e: - logger.info(f'out of combat break {e}') + logger.info(f'auto_combat_task_out_of_combat {e}') if self.debug: - self.screenshot(f'out of combat break {e}') + self.screenshot(f'auto_combat_task_out_of_combat {e}') break def trigger(self): diff --git a/src/task/BaseCombatTask.py b/src/task/BaseCombatTask.py index 0aeddf9..64d6e15 100644 --- a/src/task/BaseCombatTask.py +++ b/src/task/BaseCombatTask.py @@ -40,11 +40,13 @@ class BaseCombatTask(BaseTask, FindFeature, OCR, CombatCheck): def raise_not_in_combat(self, message): logger.error(message) - self.reset_to_false() + self.reset_to_false(reason=message) raise NotInCombatException(message) - def combat_once(self, wait_combat_time=180): + def combat_once(self, wait_combat_time=180, wait_before=2): self.wait_until(lambda: self.in_combat(), time_out=wait_combat_time, raise_if_not_found=True) + self.sleep(wait_before) + self.wait_until(lambda: self.in_combat(), time_out=3, raise_if_not_found=True) self.load_chars() while self.in_combat(): try: @@ -52,9 +54,30 @@ class BaseCombatTask(BaseTask, FindFeature, OCR, CombatCheck): self.get_current_char().perform() except NotInCombatException as e: logger.info(f'combat_once out of combat break {e}') - self.screenshot(f'out of combat break {e}') + self.screenshot(f'out of combat break {self.out_of_combat_reason}') break + # @property + # def frame(self): + # frame = super().frame + # if frame is not None: + # start = time.time() + # # if cv2.countNonZero(cv2.split(frame)) == 0: + # means, stddevs = cv2.meanStdDev(frame) + # + # # Check if all channel means are very close to zero (black) + # all_black_means = np.all(np.isclose(means, 0.0, atol=1e-3)) + # + # # Check if all channel standard deviations are low (uniform) + # low_stddevs = np.all(stddevs[0] < 1e-3) + # + # # Return True if all channels are black and uniform + # if all_black_means and low_stddevs: + # logger.error('got a pure black frame!') + # return self.next_frame() + # logger.debug(f'black check:{time.time() - start}') + # return frame + def switch_next_char(self, current_char, post_action=None, free_intro=False, target_low_con=False): max_priority = Priority.MIN switch_to = None @@ -152,43 +175,41 @@ class BaseCombatTask(BaseTask, FindFeature, OCR, CombatCheck): def check_combat(self): if not self.in_combat(): if self.debug: - self.screenshot('not_in_combat') + self.screenshot('not_in_combat_calling_check_combat') self.raise_not_in_combat('combat check not in combat') - def walk_until_f(self, direction='w', time_out=0, raise_if_not_found=True): + def send_key_and_wait_f(self, direction, raise_if_not_found, time_out): + if time_out <= 0: + return + self.send_key_down(direction) + f_found = self.wait_feature('pick_up_f', horizontal_variance=0.1, vertical_variance=0.1, + use_gray_scale=True, threshold=0.8, + wait_until_before_delay=0, time_out=time_out, raise_if_not_found=False) + if not f_found: + if raise_if_not_found: + self.send_key_up(direction) + raise CannotFindException('cant find the f to enter') + else: + logger.warning(f"can't find the f to enter") + self.send_key_up(direction) + return False + self.send_key('f') + self.sleep(0.2) + self.send_key('f') + self.send_key_up(direction) + if self.wait_click_feature('cancel_button', relative_x=1, raise_if_not_found=False, + use_gray_scale=True, time_out=2): + logger.warning(f"found a claim reward") + return False + return f_found + + def walk_until_f(self, direction='w', time_out=0, raise_if_not_found=True, backward_time=0): if not self.find_one('pick_up_f', horizontal_variance=0.1, vertical_variance=0.1, threshold=0.8, use_gray_scale=True): - self.send_key_down(direction) - f_found = self.wait_feature('pick_up_f', horizontal_variance=0.1, vertical_variance=0.1, - use_gray_scale=True, threshold=0.8, - wait_until_before_delay=0, time_out=time_out, raise_if_not_found=False) - if not f_found: - if raise_if_not_found: - self.send_key_up(direction) - raise CannotFindException('cant find the f to enter') - else: - logger.warning(f"can't find the f to enter") - self.send_key_up(direction) - return False - self.send_key('f') - self.sleep(0.2) - self.send_key('f') - self.send_key_up(direction) - if self.wait_click_feature('cancel_button', relative_x=1, raise_if_not_found=True, - use_gray_scale=True, time_out=2): - logger.warning(f"found a claim reward") - return False - # while self.in_team_and_world(): - # - # self.send_key('f') - # count += 1 - # if count > 20: - # self.send_key_up(direction) - # logger.error('failed to enter') - # if raise_if_not_found: - # raise CannotFindException('cant find the f to enter') - # else: - # return False + if backward_time > 0: + if self.send_key_and_wait_f('s', raise_if_not_found, backward_time): + return True + return self.send_key_and_wait_f(direction, raise_if_not_found, time_out) and self.sleep(0.5) else: self.send_key('f') self.sleep(0.5) diff --git a/src/task/FarmWorldBossTask.py b/src/task/FarmWorldBossTask.py index 128d176..acfb8c0 100644 --- a/src/task/FarmWorldBossTask.py +++ b/src/task/FarmWorldBossTask.py @@ -17,12 +17,12 @@ class FarmWorldBossTask(BaseCombatTask): 'Feilian Beringal', 'Mourning Aix', 'Impermanence Heron', 'Lampylumen Myriad', 'Mech Abomination', 'Bell-Borne Geochelone'] + self.weekly_boss_index = {'Bell-Borne Geochelone': 3} self.weekly_boss_count = 1 # Bell-Borne Geochelone default_config = { 'Boss1': 'N/A', 'Boss2': 'N/A', 'Boss3': 'N/A', - 'Boss4': 'N/A', 'Repeat Farm Count': 1000 } default_config.update(self.default_config) @@ -30,7 +30,6 @@ class FarmWorldBossTask(BaseCombatTask): self.config_type["Boss1"] = {'type': "drop_down", 'options': self.boss_names} self.config_type["Boss2"] = {'type': "drop_down", 'options': self.boss_names} self.config_type["Boss3"] = {'type': "drop_down", 'options': self.boss_names} - self.config_type["Boss4"] = {'type': "drop_down", 'options': self.boss_names} self.config_description = { 'Level': '(1-6) Important, Choose which level to farm, lower levels might not produce a echo', 'Entrance Direction': 'Choose Forward for Dreamless, Backward for Jue' @@ -43,7 +42,6 @@ class FarmWorldBossTask(BaseCombatTask): index = self.boss_names.index(boss_name) index -= 1 self.log_info(f'teleport to {boss_name} index {index}') - self.sleep(1) self.log_info('click f2 to open the book') self.send_key('f2') @@ -55,7 +53,13 @@ class FarmWorldBossTask(BaseCombatTask): self.sleep(1.5) self.click_relative(0.04, 0.29) self.sleep(1) - self.click_relative(0.21, 0.36) + if index >= (len(self.boss_names) - self.weekly_boss_count - 1): # weekly turtle + logger.info('click weekly boss') + index = self.weekly_boss_index[boss_name] + self.click_relative(0.21, 0.59) + else: + logger.info('click normal boss') + self.click_relative(0.21, 0.36) # self.wait_click_feature('gray_book_forgery', raise_if_not_found=True, use_gray_scale=True, threshold=0.7) # self.wait_click_feature('gray_book_boss', raise_if_not_found=True, use_gray_scale=True, threshold=0.7) self.sleep(1) @@ -79,7 +83,7 @@ class FarmWorldBossTask(BaseCombatTask): self.click_relative(0.5, 0.5) self.wait_click_feature('gray_custom_way_point', box=self.box_of_screen(0.62, 0.48, 0.70, 0.66), raise_if_not_found=True, - use_gray_scale=True, threshold=0.75) + use_gray_scale=True, threshold=0.75, time_out=2) travel = self.wait_feature('fast_travel_custom', raise_if_not_found=True, use_gray_scale=True, threshold=0.8) self.click_box(travel, relative_x=1.5) @@ -91,17 +95,20 @@ class FarmWorldBossTask(BaseCombatTask): return True def scroll_down_a_page(self): - self.click_relative(0.5, 0.5) - self.sleep(0.2) source_box = self.box_of_screen(0.38, 0.78, 0.42, 0.85) source_template = Feature(source_box.crop_frame(self.frame), source_box.x, source_box.y) target_box = self.box_of_screen(0.38, 0.18, 0.42, 0.31) start = time.time() + # count = 0 while True: if time.time() - start > 20: raise Exception("scroll to long") - self.scroll_relative(0.7, 0.5, -1) - self.sleep(0.2) + # if count % 10 == 0: + self.click_relative(0.5, 0.5) + self.sleep(0.1) + # count += 1 + self.scroll_relative(0.7, 0.5, -2) + self.sleep(0.1) targets = self.find_feature('target_box', box=target_box, template=source_template) if targets: self.log_info(f'scroll to targets {targets} successfully') @@ -124,7 +131,7 @@ class FarmWorldBossTask(BaseCombatTask): logger.info(f'farm echo combat end') self.wait_in_team_and_world(time_out=20) logger.info(f'farm echo move forward walk_until_f to find echo') - if self.walk_until_f(time_out=3, + if self.walk_until_f(time_out=6, backward_time=1, raise_if_not_found=False): # find and pick echo logger.debug(f'farm echo found echo move forward walk_until_f to find echo') self.incr_drop(True)