diff --git a/assets/share/rogue/ui/BONUS_BOTTOM_WHITE_BAR.png b/assets/share/rogue/bonus/BONUS_BOTTOM_WHITE_BAR.png similarity index 100% rename from assets/share/rogue/ui/BONUS_BOTTOM_WHITE_BAR.png rename to assets/share/rogue/bonus/BONUS_BOTTOM_WHITE_BAR.png diff --git a/assets/share/rogue/ui/BONUS_CONFIRM.png b/assets/share/rogue/bonus/BONUS_CONFIRM.png similarity index 100% rename from assets/share/rogue/ui/BONUS_CONFIRM.png rename to assets/share/rogue/bonus/BONUS_CONFIRM.png diff --git a/tasks/rogue/assets/assets_rogue_bonus.py b/tasks/rogue/assets/assets_rogue_bonus.py new file mode 100644 index 000000000..42bcd9fb8 --- /dev/null +++ b/tasks/rogue/assets/assets_rogue_bonus.py @@ -0,0 +1,25 @@ +from module.base.button import Button, ButtonWrapper + +# This file was auto-generated, do not modify it manually. To generate: +# ``` python -m dev_tools.button_extract ``` + +BONUS_BOTTOM_WHITE_BAR = ButtonWrapper( + name='BONUS_BOTTOM_WHITE_BAR', + share=Button( + file='./assets/share/rogue/bonus/BONUS_BOTTOM_WHITE_BAR.png', + area=(182, 568, 1098, 590), + search=(162, 548, 1118, 610), + color=(221, 221, 222), + button=(182, 568, 1098, 590), + ), +) +BONUS_CONFIRM = ButtonWrapper( + name='BONUS_CONFIRM', + share=Button( + file='./assets/share/rogue/bonus/BONUS_CONFIRM.png', + area=(504, 629, 620, 677), + search=(484, 609, 640, 697), + color=(222, 224, 224), + button=(504, 629, 620, 677), + ), +) diff --git a/tasks/rogue/assets/assets_rogue_ui.py b/tasks/rogue/assets/assets_rogue_ui.py index 384c3aa3b..f534400cd 100644 --- a/tasks/rogue/assets/assets_rogue_ui.py +++ b/tasks/rogue/assets/assets_rogue_ui.py @@ -3,26 +3,6 @@ from module.base.button import Button, ButtonWrapper # This file was auto-generated, do not modify it manually. To generate: # ``` python -m dev_tools.button_extract ``` -BONUS_BOTTOM_WHITE_BAR = ButtonWrapper( - name='BONUS_BOTTOM_WHITE_BAR', - share=Button( - file='./assets/share/rogue/ui/BONUS_BOTTOM_WHITE_BAR.png', - area=(182, 568, 1098, 590), - search=(162, 548, 1118, 610), - color=(221, 221, 222), - button=(182, 568, 1098, 590), - ), -) -BONUS_CONFIRM = ButtonWrapper( - name='BONUS_CONFIRM', - share=Button( - file='./assets/share/rogue/ui/BONUS_CONFIRM.png', - area=(504, 629, 620, 677), - search=(484, 609, 640, 697), - color=(222, 224, 224), - button=(504, 629, 620, 677), - ), -) CHECK_BLESSING = ButtonWrapper( name='CHECK_BLESSING', share=Button( diff --git a/tasks/rogue/blessing.py b/tasks/rogue/blessing.py index 9e0ae67fc..47a160ce3 100644 --- a/tasks/rogue/blessing.py +++ b/tasks/rogue/blessing.py @@ -12,7 +12,6 @@ from tasks.rogue.assets.assets_rogue_ui import CONFIRM from tasks.rogue.keywords import * from tasks.rogue.preset import * from tasks.rogue.selector import RogueSelector -from tasks.rogue.ui import RogueUI from tasks.rogue.utils import get_regex_from_keyword_name, parse_name, is_card_selected # normal blessing @@ -78,7 +77,7 @@ class RogueBuffOcr(Ocr): return result -class RogueBlessingSelector(RogueUI, RogueSelector): +class RogueBlessingSelector(RogueSelector): """ Usage: self = RogueBlessingSelector('alas') @@ -90,9 +89,9 @@ class RogueBlessingSelector(RogueUI, RogueSelector): """ Returns: The number of blessing """ - if not self.image_color_count(BOTTOM_WHITE_BAR.area, color=(255, 255, 255), count=5000): + if not self.main.image_color_count(BOTTOM_WHITE_BAR.area, color=(255, 255, 255), count=5000): return 0 - color = get_color(self.device.image, BOTTOM_WHITE_BAR.area) + color = get_color(self.main.device.image, BOTTOM_WHITE_BAR.area) mean = np.mean(color) return int(mean // 60) # the magic number that maps blessing num with mean_color @@ -100,7 +99,7 @@ class RogueBlessingSelector(RogueUI, RogueSelector): self.ocr_results = [] self._wait_until_blessing_loaded() ocr = RogueBuffOcr(OCR_ROGUE_BUFF) - results = ocr.matched_ocr(self.device.image, [RogueBlessing, RogueResonance]) + results = ocr.matched_ocr(self.main.device.image, [RogueBlessing, RogueResonance]) blessing_count = self.get_blessing_count() if blessing_count != len(results): logger.warning(f"The OCR result does not match the blessing count. " @@ -121,8 +120,9 @@ class RogueBlessingSelector(RogueUI, RogueSelector): Case 2: choose curio Case 3: another choose blessings, but no blessing is selected when the new selection page loaded """ - return (self.is_in_main() or self.is_page_choose_curio() - or (self.is_page_choose_blessing() and not is_card_selected(self, target, confirm_button=CONFIRM))) + return (self.main.is_in_main() or self.main.is_page_choose_curio() + or (self.main.is_page_choose_blessing() and + not is_card_selected(self.main, target, confirm_button=CONFIRM))) interval = Timer(1) enforce = False @@ -135,9 +135,9 @@ class RogueBlessingSelector(RogueUI, RogueSelector): if skip_first_screenshot: skip_first_screenshot = False else: - self.device.screenshot() + self.main.device.screenshot() - if is_card_selected(self, target, confirm_button=CONFIRM): + if is_card_selected(self.main, target, confirm_button=CONFIRM): if enforce: logger.info("Buff selected (enforce)") else: @@ -145,9 +145,9 @@ class RogueBlessingSelector(RogueUI, RogueSelector): break if interval.reached(): if enforce: - self.device.click(BLESSING_ENFORCE) + self.main.device.click(BLESSING_ENFORCE) else: - self.device.click(target) + self.main.device.click(target) interval.reset() skip_first_screenshot = True @@ -156,16 +156,16 @@ class RogueBlessingSelector(RogueUI, RogueSelector): if skip_first_screenshot: skip_first_screenshot = False else: - self.device.screenshot() + self.main.device.screenshot() if is_select_blessing_complete(): break if interval.reached(): - self.device.click(CONFIRM) + self.main.device.click(CONFIRM) interval.reset() def _get_reset_count(self): - current, _, _ = DigitCounter(OCR_RESET_COUNT).ocr_single_line(self.device.image) + current, _, _ = DigitCounter(OCR_RESET_COUNT).ocr_single_line(self.main.device.image) return current def _wait_until_blessing_loaded(self, timer=Timer(0.3, count=1), timeout=Timer(5, count=10)): @@ -173,7 +173,7 @@ class RogueBlessingSelector(RogueUI, RogueSelector): timeout.reset() previous_count = self.get_blessing_count() while 1: - self.device.screenshot() + self.main.device.screenshot() blessing_count = self.get_blessing_count() if timeout.reached(): @@ -189,7 +189,7 @@ class RogueBlessingSelector(RogueUI, RogueSelector): timer.reset() def reset_blessing_list(self, skip_first_screenshot=True): - if not self.is_page_choose_blessing(): + if not self.main.is_page_choose_blessing(): return False reset_count = self._get_reset_count() @@ -197,8 +197,8 @@ class RogueBlessingSelector(RogueUI, RogueSelector): logger.info("Does not have enough reset count") return False - reset_cost = Digit(OCR_RESET_COST).ocr_single_line(self.device.image) - if reset_cost > self.cosmic_fragment: + reset_cost = Digit(OCR_RESET_COST).ocr_single_line(self.main.device.image) + if reset_cost > self.main.cosmic_fragment: logger.info("Does not have enough cosmic fragment") return False @@ -207,7 +207,7 @@ class RogueBlessingSelector(RogueUI, RogueSelector): if skip_first_screenshot: skip_first_screenshot = False else: - self.device.screenshot() + self.main.device.screenshot() new_count = self._get_reset_count() @@ -215,7 +215,7 @@ class RogueBlessingSelector(RogueUI, RogueSelector): logger.info("Reset once") break if interval.reached(): - self.device.click(BLESSING_RESET) + self.main.device.click(BLESSING_RESET) interval.reset() return True @@ -224,16 +224,16 @@ class RogueBlessingSelector(RogueUI, RogueSelector): keyword = self.ocr_results[0].matched_keyword if isinstance(keyword, RogueBlessing): filter_ = BLESSING_FILTER - if self.config.Rogue_PresetBlessingFilter == 'preset-1': + if self.main.config.Rogue_PresetBlessingFilter == 'preset-1': filter_.load(parse_name(BLESSING_PRESET_1)) - if self.config.Rogue_PresetBlessingFilter == 'custom': - filter_.load(parse_name(self.config.Rogue_CustomBlessingFilter)) + if self.main.config.Rogue_PresetBlessingFilter == 'custom': + filter_.load(parse_name(self.main.config.Rogue_CustomBlessingFilter)) if isinstance(keyword, RogueResonance): filter_ = RESONANCE_FILTER - if self.config.Rogue_PresetResonanceFilter == 'preset-1': + if self.main.config.Rogue_PresetResonanceFilter == 'preset-1': RESONANCE_FILTER.load(parse_name(RESONANCE_PRESET_1)) - if self.config.Rogue_PresetResonanceFilter == 'custom': - RESONANCE_FILTER.load(parse_name(self.config.Rogue_CustomResonanceFilter)) + if self.main.config.Rogue_PresetResonanceFilter == 'custom': + RESONANCE_FILTER.load(parse_name(self.main.config.Rogue_CustomResonanceFilter)) self.filter_ = filter_ def try_select(self, option: OcrResultButton | str): diff --git a/tasks/rogue/bonus.py b/tasks/rogue/bonus.py new file mode 100644 index 000000000..02d3b85a6 --- /dev/null +++ b/tasks/rogue/bonus.py @@ -0,0 +1,83 @@ +import numpy as np + +from module.base.timer import Timer +from module.logger import logger +from module.ocr.ocr import OcrResultButton +from tasks.rogue.assets.assets_rogue_blessing import OCR_ROGUE_BUFF +from tasks.rogue.assets.assets_rogue_bonus import BONUS_BOTTOM_WHITE_BAR, BONUS_CONFIRM +from tasks.rogue.keywords import RogueBonus +from tasks.rogue.selector import RogueSelector +from tasks.rogue.ui import RogueBonusOcr +from tasks.rogue.utils import is_card_selected + + +class RogueBonusSelector(RogueSelector): + def _wait_bonus_page_loaded(self, timer=Timer(0.3, count=1), timeout=Timer(5, count=10)): + timer.reset() + timeout.reset() + while 1: + self.main.device.screenshot() + + if timeout.reached(): + logger.warning('Wait bonus page loaded timeout') + break + + if self.main.appear(BONUS_BOTTOM_WHITE_BAR): + if timer.reached(): + logger.info('Bonus page stabled') + break + else: + timer.reset() + + def recognition(self): + self._wait_bonus_page_loaded() + ocr = RogueBonusOcr(OCR_ROGUE_BUFF) + results = ocr.matched_ocr(self.main.device.image, [RogueBonus]) + expected_count = 3 + if expected_count != len(results): + logger.warning(f"The OCR result does not match the bonus count. " + f"Expect {expected_count}, but recognized {len(results)} only.") + self.ocr_results = results + return results + + def ui_select(self, target: OcrResultButton | None, skip_first_screenshot=True): + interval = Timer(1) + # start -> select + while 1: + if skip_first_screenshot: + skip_first_screenshot = False + else: + self.main.device.screenshot() + + if is_card_selected(self.main, target, confirm_button=BONUS_CONFIRM): + break + if interval.reached(): + self.main.device.click(target) + interval.reset() + + skip_first_screenshot = True + # select -> confirm + while 1: + if skip_first_screenshot: + skip_first_screenshot = False + else: + self.main.device.screenshot() + + if self.main.is_in_main() or self.main.is_page_choose_curio() or self.main.is_page_choose_blessing(): + break + if interval.reached(): + self.main.device.click(BONUS_CONFIRM) + interval.reset() + + def recognize_and_select(self): + self.recognition() + if not self.ocr_results: + self.ui_select(None) + options = {result.matched_keyword.en: result for result in self.ocr_results} + if self.main.config.Rogue_Bonus not in options.keys(): + logger.warning(f"Can not find option: {self.main.config.Rogue_Bonus}, randomly choose one") + target = np.random.choice(options) + else: + target = options[self.main.config.Rogue_Bonus] + logger.info(f"Choose bonus: {target}") + self.ui_select(target) diff --git a/tasks/rogue/curio.py b/tasks/rogue/curio.py index 92afe5b77..8589b75c5 100644 --- a/tasks/rogue/curio.py +++ b/tasks/rogue/curio.py @@ -12,7 +12,6 @@ from tasks.rogue.assets.assets_rogue_ui import CONFIRM from tasks.rogue.keywords import RogueCurio from tasks.rogue.preset import CURIO_PRESET_1 from tasks.rogue.selector import RogueSelector -from tasks.rogue.ui import RogueUI from tasks.rogue.utils import get_regex_from_keyword_name, parse_name CURIO_FILTER_ATTR = tuple() @@ -36,11 +35,11 @@ class RogueCurioOcr(Ocr): return result -class RogueCurioSelector(RogueUI, RogueSelector): +class RogueCurioSelector(RogueSelector): def recognition(self): self.ocr_results = [] ocr = RogueCurioOcr(OCR_ROGUE_CURIO) - results = ocr.matched_ocr(self.device.image, RogueCurio) + results = ocr.matched_ocr(self.main.device.image, RogueCurio) expect_num = 3 if len(results) != expect_num: logger.warning(f"The OCR result does not match the curio count. " @@ -50,13 +49,13 @@ class RogueCurioSelector(RogueUI, RogueSelector): def ui_select(self, target: OcrResultButton | None, skip_first_screenshot=True): def is_curio_selected(): - return np.mean(get_color(self.device.image, tuple(target.area))) > 70 # shiny background + return np.mean(get_color(self.main.device.image, tuple(target.area))) > 70 # shiny background def is_select_curio_complete(): """ Case 1: back to main page """ - return self.is_in_main() + return self.main.is_in_main() enforce = False if not target: @@ -67,7 +66,7 @@ class RogueCurioSelector(RogueUI, RogueSelector): if skip_first_screenshot: skip_first_screenshot = False else: - self.device.screenshot() + self.main.device.screenshot() if is_curio_selected(): if enforce: @@ -77,9 +76,9 @@ class RogueCurioSelector(RogueUI, RogueSelector): break if interval.reached(): if enforce: - self.device.click(CURIO_ENFORCE) + self.main.device.click(CURIO_ENFORCE) else: - self.device.click(target) + self.main.device.click(target) interval.reset() skip_first_screenshot = True @@ -88,12 +87,12 @@ class RogueCurioSelector(RogueUI, RogueSelector): if skip_first_screenshot: skip_first_screenshot = False else: - self.device.screenshot() + self.main.device.screenshot() if is_select_curio_complete(): break if interval.reached(): - self.device.click(CONFIRM) + self.main.device.click(CONFIRM) interval.reset() def try_select(self, option: OcrResultButton | str): @@ -108,8 +107,8 @@ class RogueCurioSelector(RogueUI, RogueSelector): def load_filter(self): filter_ = CURIO_FILTER - if self.config.Rogue_PresetCurioFilter == 'preset-1': + if self.main.config.Rogue_PresetCurioFilter == 'preset-1': filter_.load(parse_name(CURIO_PRESET_1)) - if self.config.Rogue_PresetCurioFilter == 'custom': - filter_.load(parse_name(self.config.Rogue_CustomCurioFilter)) + if self.main.config.Rogue_PresetCurioFilter == 'custom': + filter_.load(parse_name(self.main.config.Rogue_CustomCurioFilter)) self.filter_ = filter_ diff --git a/tasks/rogue/selector.py b/tasks/rogue/selector.py index ee2103255..702a5186b 100644 --- a/tasks/rogue/selector.py +++ b/tasks/rogue/selector.py @@ -4,12 +4,17 @@ from module.base.filter import MultiLangFilter from module.logger import logger from module.ocr.keyword import Keyword from module.ocr.ocr import OcrResultButton +from tasks.rogue.ui import RogueUI class RogueSelector: """ An Interface used in blessing, curio, and other ui selection in rogue """ + + def __init__(self, main: RogueUI): + self.main = main + ocr_results: list[OcrResultButton] filter_: MultiLangFilter preset_methods: dict[str, callable] diff --git a/tasks/rogue/ui.py b/tasks/rogue/ui.py index 09b274560..5b6717b56 100644 --- a/tasks/rogue/ui.py +++ b/tasks/rogue/ui.py @@ -1,15 +1,9 @@ import re -import numpy as np - -from module.base.timer import Timer -from module.logger import logger -from module.ocr.ocr import Digit, Ocr, OcrResultButton +from module.ocr.ocr import Digit, Ocr from tasks.base.ui import UI -from tasks.rogue.assets.assets_rogue_blessing import OCR_ROGUE_BUFF from tasks.rogue.assets.assets_rogue_ui import * from tasks.rogue.keywords import * -from tasks.rogue.utils import is_card_selected class RogueBonusOcr(Ocr): @@ -43,72 +37,3 @@ class RogueUI(UI): def is_page_choose_bonus(self): return self.appear(PAGE_CHOOSE_BONUS) - - def _wait_bonus_page_loaded(self, timer=Timer(0.3, count=1), timeout=Timer(5, count=10)): - timer.reset() - timeout.reset() - while 1: - self.device.screenshot() - - if timeout.reached(): - logger.warning('Wait bonus page loaded timeout') - break - - if self.appear(BONUS_BOTTOM_WHITE_BAR): - if timer.reached(): - logger.info('Bonus page stabled') - break - else: - timer.reset() - - def bonus_recognition(self): - self._wait_bonus_page_loaded() - ocr = RogueBonusOcr(OCR_ROGUE_BUFF) - results = ocr.matched_ocr(self.device.image, [RogueBonus]) - expected_count = 3 - if expected_count != len(results): - logger.warning(f"The OCR result does not match the bonus count. " - f"Expect {expected_count}, but recognized {len(results)} only.") - return results - - def ui_choose_bonus(self, target: OcrResultButton | None, skip_first_screenshot=True): - interval = Timer(1) - # start -> select - while 1: - if skip_first_screenshot: - skip_first_screenshot = False - else: - self.device.screenshot() - - if is_card_selected(self, target, confirm_button=BONUS_CONFIRM): - break - if interval.reached(): - self.device.click(target) - interval.reset() - - skip_first_screenshot = True - # select -> confirm - while 1: - if skip_first_screenshot: - skip_first_screenshot = False - else: - self.device.screenshot() - - if self.is_in_main() or self.is_page_choose_curio() or self.is_page_choose_blessing(): - break - if interval.reached(): - self.device.click(BONUS_CONFIRM) - interval.reset() - - def recognize_and_select_bonus(self): - results = self.bonus_recognition() - if not results: - self.ui_choose_bonus(None) - options = {result.matched_keyword.en: result for result in results} - if self.config.Rogue_Bonus not in options.keys(): - logger.warning(f"Can not find option: {self.config.Rogue_Bonus}, randomly choose one") - target = np.random.choice(options) - else: - target = options[self.config.Rogue_Bonus] - logger.info(f"Choose bonus: {target}") - self.ui_choose_bonus(target)