Add: Select rogue path (#145)
BIN
assets/share/rogue/path/CHECK_ABUNDANCE.png
Normal file
After Width: | Height: | Size: 9.5 KiB |
BIN
assets/share/rogue/path/CHECK_DESTRUCTION.png
Normal file
After Width: | Height: | Size: 8.4 KiB |
BIN
assets/share/rogue/path/CHECK_ELATION.png
Normal file
After Width: | Height: | Size: 8.3 KiB |
BIN
assets/share/rogue/path/CHECK_NIHILITY.png
Normal file
After Width: | Height: | Size: 8.7 KiB |
BIN
assets/share/rogue/path/CHECK_PRESERVATION.png
Normal file
After Width: | Height: | Size: 9.1 KiB |
BIN
assets/share/rogue/path/CHECK_REMEMBRANCE.png
Normal file
After Width: | Height: | Size: 8.0 KiB |
BIN
assets/share/rogue/path/CHECK_THE_HUNT.png
Normal file
After Width: | Height: | Size: 9.6 KiB |
BIN
assets/share/rogue/path/CLICK_ABUNDANCE.png
Normal file
After Width: | Height: | Size: 10 KiB |
BIN
assets/share/rogue/path/CLICK_DESTRUCTION.png
Normal file
After Width: | Height: | Size: 8.6 KiB |
BIN
assets/share/rogue/path/CLICK_ELATION.png
Normal file
After Width: | Height: | Size: 8.2 KiB |
BIN
assets/share/rogue/path/CLICK_NIHILITY.png
Normal file
After Width: | Height: | Size: 9.5 KiB |
BIN
assets/share/rogue/path/CLICK_PRESERVATION.png
Normal file
After Width: | Height: | Size: 7.8 KiB |
BIN
assets/share/rogue/path/CLICK_REMEMBRANCE.png
Normal file
After Width: | Height: | Size: 9.7 KiB |
BIN
assets/share/rogue/path/CLICK_THE_HUNT.png
Normal file
After Width: | Height: | Size: 9.8 KiB |
BIN
assets/share/rogue/path/CONFIRM_PATH.BUTTON.png
Normal file
After Width: | Height: | Size: 8.9 KiB |
BIN
assets/share/rogue/path/CONFIRM_PATH.png
Normal file
After Width: | Height: | Size: 6.6 KiB |
BIN
assets/share/rogue/ui/ROGUE_LAUNCH.BUTTON.png
Normal file
After Width: | Height: | Size: 11 KiB |
BIN
assets/share/rogue/ui/ROGUE_LAUNCH.png
Normal file
After Width: | Height: | Size: 6.6 KiB |
155
tasks/rogue/assets/assets_rogue_path.py
Normal file
@ -0,0 +1,155 @@
|
||||
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 ```
|
||||
|
||||
CHECK_ABUNDANCE = ButtonWrapper(
|
||||
name='CHECK_ABUNDANCE',
|
||||
share=Button(
|
||||
file='./assets/share/rogue/path/CHECK_ABUNDANCE.png',
|
||||
area=(202, 315, 252, 365),
|
||||
search=(182, 295, 272, 385),
|
||||
color=(143, 120, 86),
|
||||
button=(202, 315, 252, 365),
|
||||
),
|
||||
)
|
||||
CHECK_DESTRUCTION = ButtonWrapper(
|
||||
name='CHECK_DESTRUCTION',
|
||||
share=Button(
|
||||
file='./assets/share/rogue/path/CHECK_DESTRUCTION.png',
|
||||
area=(219, 336, 269, 386),
|
||||
search=(199, 316, 289, 406),
|
||||
color=(131, 109, 78),
|
||||
button=(219, 336, 269, 386),
|
||||
),
|
||||
)
|
||||
CHECK_ELATION = ButtonWrapper(
|
||||
name='CHECK_ELATION',
|
||||
share=Button(
|
||||
file='./assets/share/rogue/path/CHECK_ELATION.png',
|
||||
area=(220, 309, 270, 359),
|
||||
search=(200, 289, 290, 379),
|
||||
color=(142, 119, 85),
|
||||
button=(220, 309, 270, 359),
|
||||
),
|
||||
)
|
||||
CHECK_NIHILITY = ButtonWrapper(
|
||||
name='CHECK_NIHILITY',
|
||||
share=Button(
|
||||
file='./assets/share/rogue/path/CHECK_NIHILITY.png',
|
||||
area=(220, 306, 270, 356),
|
||||
search=(200, 286, 290, 376),
|
||||
color=(130, 106, 75),
|
||||
button=(220, 306, 270, 356),
|
||||
),
|
||||
)
|
||||
CHECK_PRESERVATION = ButtonWrapper(
|
||||
name='CHECK_PRESERVATION',
|
||||
share=Button(
|
||||
file='./assets/share/rogue/path/CHECK_PRESERVATION.png',
|
||||
area=(220, 308, 270, 358),
|
||||
search=(200, 288, 290, 378),
|
||||
color=(144, 120, 86),
|
||||
button=(220, 308, 270, 358),
|
||||
),
|
||||
)
|
||||
CHECK_REMEMBRANCE = ButtonWrapper(
|
||||
name='CHECK_REMEMBRANCE',
|
||||
share=Button(
|
||||
file='./assets/share/rogue/path/CHECK_REMEMBRANCE.png',
|
||||
area=(220, 326, 270, 376),
|
||||
search=(200, 306, 290, 396),
|
||||
color=(128, 105, 75),
|
||||
button=(220, 326, 270, 376),
|
||||
),
|
||||
)
|
||||
CHECK_THE_HUNT = ButtonWrapper(
|
||||
name='CHECK_THE_HUNT',
|
||||
share=Button(
|
||||
file='./assets/share/rogue/path/CHECK_THE_HUNT.png',
|
||||
area=(221, 324, 271, 374),
|
||||
search=(201, 304, 291, 394),
|
||||
color=(127, 104, 74),
|
||||
button=(221, 324, 271, 374),
|
||||
),
|
||||
)
|
||||
CLICK_ABUNDANCE = ButtonWrapper(
|
||||
name='CLICK_ABUNDANCE',
|
||||
share=Button(
|
||||
file='./assets/share/rogue/path/CLICK_ABUNDANCE.png',
|
||||
area=(633, 354, 683, 404),
|
||||
search=(613, 334, 703, 424),
|
||||
color=(70, 70, 74),
|
||||
button=(633, 354, 683, 404),
|
||||
),
|
||||
)
|
||||
CLICK_DESTRUCTION = ButtonWrapper(
|
||||
name='CLICK_DESTRUCTION',
|
||||
share=Button(
|
||||
file='./assets/share/rogue/path/CLICK_DESTRUCTION.png',
|
||||
area=(1024, 373, 1074, 423),
|
||||
search=(1004, 353, 1094, 443),
|
||||
color=(64, 64, 65),
|
||||
button=(1024, 373, 1074, 423),
|
||||
),
|
||||
)
|
||||
CLICK_ELATION = ButtonWrapper(
|
||||
name='CLICK_ELATION',
|
||||
share=Button(
|
||||
file='./assets/share/rogue/path/CLICK_ELATION.png',
|
||||
area=(1185, 354, 1215, 404),
|
||||
search=(1165, 334, 1235, 424),
|
||||
color=(39, 40, 46),
|
||||
button=(1185, 354, 1215, 404),
|
||||
),
|
||||
)
|
||||
CLICK_NIHILITY = ButtonWrapper(
|
||||
name='CLICK_NIHILITY',
|
||||
share=Button(
|
||||
file='./assets/share/rogue/path/CLICK_NIHILITY.png',
|
||||
area=(465, 343, 515, 393),
|
||||
search=(445, 323, 535, 413),
|
||||
color=(57, 58, 63),
|
||||
button=(465, 343, 515, 393),
|
||||
),
|
||||
)
|
||||
CLICK_PRESERVATION = ButtonWrapper(
|
||||
name='CLICK_PRESERVATION',
|
||||
share=Button(
|
||||
file='./assets/share/rogue/path/CLICK_PRESERVATION.png',
|
||||
area=(65, 340, 88, 405),
|
||||
search=(45, 320, 108, 425),
|
||||
color=(31, 34, 44),
|
||||
button=(65, 340, 88, 405),
|
||||
),
|
||||
)
|
||||
CLICK_REMEMBRANCE = ButtonWrapper(
|
||||
name='CLICK_REMEMBRANCE',
|
||||
share=Button(
|
||||
file='./assets/share/rogue/path/CLICK_REMEMBRANCE.png',
|
||||
area=(278, 362, 328, 412),
|
||||
search=(258, 342, 348, 432),
|
||||
color=(61, 62, 69),
|
||||
button=(278, 362, 328, 412),
|
||||
),
|
||||
)
|
||||
CLICK_THE_HUNT = ButtonWrapper(
|
||||
name='CLICK_THE_HUNT',
|
||||
share=Button(
|
||||
file='./assets/share/rogue/path/CLICK_THE_HUNT.png',
|
||||
area=(837, 362, 887, 412),
|
||||
search=(817, 342, 907, 432),
|
||||
color=(57, 57, 61),
|
||||
button=(837, 362, 887, 412),
|
||||
),
|
||||
)
|
||||
CONFIRM_PATH = ButtonWrapper(
|
||||
name='CONFIRM_PATH',
|
||||
share=Button(
|
||||
file='./assets/share/rogue/path/CONFIRM_PATH.png',
|
||||
area=(845, 634, 868, 681),
|
||||
search=(825, 614, 888, 701),
|
||||
color=(178, 178, 178),
|
||||
button=(865, 640, 1139, 675),
|
||||
),
|
||||
)
|
@ -123,3 +123,13 @@ PAGE_EVENT = ButtonWrapper(
|
||||
button=(983, 485, 1007, 509),
|
||||
),
|
||||
)
|
||||
ROGUE_LAUNCH = ButtonWrapper(
|
||||
name='ROGUE_LAUNCH',
|
||||
share=Button(
|
||||
file='./assets/share/rogue/ui/ROGUE_LAUNCH.png',
|
||||
area=(875, 629, 896, 677),
|
||||
search=(855, 609, 916, 697),
|
||||
color=(171, 172, 172),
|
||||
button=(896, 635, 1169, 671),
|
||||
),
|
||||
)
|
||||
|
@ -47,7 +47,10 @@ class RogueUI(UI):
|
||||
return self.appear(PAGE_EVENT)
|
||||
|
||||
def is_page_rogue_main(self):
|
||||
return self.appear(REWARD_ENTER)
|
||||
return self.match_template_color(REWARD_ENTER)
|
||||
|
||||
def is_page_rogue_launch(self):
|
||||
return self.match_template_color(ROGUE_LAUNCH)
|
||||
|
||||
def handle_obtain_item_popup(self, interval=5) -> bool:
|
||||
"""After selecting some curio (e.g. Sealing_Wax_of_*), there will be a popup after back to main page"""
|
||||
|
@ -2,11 +2,17 @@ import tasks.rogue.keywords.blessing as KEYWORDS_ROGUE_BLESSING
|
||||
import tasks.rogue.keywords.bonus as KEYWORDS_ROGUE_BONUS
|
||||
import tasks.rogue.keywords.curio as KEYWORDS_ROGUE_CURIO
|
||||
import tasks.rogue.keywords.enhancement as KEYWORDS_ROGUE_ENHANCEMENT
|
||||
import tasks.rogue.keywords.event_option as KEYWORDS_ROGUE_EVENT_OPTION
|
||||
import tasks.rogue.keywords.event_title as KEYWORDS_ROGUE_EVENT_TITLE
|
||||
import tasks.rogue.keywords.path as KEYWORDS_ROGUE_PATH
|
||||
import tasks.rogue.keywords.resonance as KEYWORDS_ROGUE_RESONANCE
|
||||
import tasks.rogue.keywords.event_title as KEYWORDS_ROGUE_EVENT_TITLE
|
||||
import tasks.rogue.keywords.event_option as KEYWORDS_ROGUE_EVENT_OPTION
|
||||
from tasks.rogue.keywords.classes import (RogueBlessing, RogueBonus,
|
||||
RogueCurio, RogueEnhancement,
|
||||
RoguePath, RogueResonance,
|
||||
RogueEventTitle, RogueEventOption)
|
||||
from tasks.rogue.keywords.classes import (
|
||||
RogueBlessing,
|
||||
RogueBonus,
|
||||
RogueCurio,
|
||||
RogueEnhancement,
|
||||
RogueEventOption,
|
||||
RogueEventTitle,
|
||||
RoguePath,
|
||||
RogueResonance
|
||||
)
|
||||
|
@ -27,6 +27,9 @@ class RogueBlessing(Keyword):
|
||||
class RoguePath(Keyword):
|
||||
instances: ClassVar = {}
|
||||
|
||||
def __hash__(self) -> int:
|
||||
return super().__hash__()
|
||||
|
||||
@property
|
||||
def path_name(self):
|
||||
return [self.__getattribute__(f"{server}_parsed").replace("the", '')
|
||||
|
136
tasks/rogue/path.py
Normal file
@ -0,0 +1,136 @@
|
||||
from typing import Dict, Optional
|
||||
|
||||
from module.base.decorator import cached_property
|
||||
from module.base.timer import Timer
|
||||
from module.exception import ScriptError
|
||||
from module.logger import logger
|
||||
from tasks.base.assets.assets_base_page import BACK
|
||||
from tasks.rogue.assets.assets_rogue_path import *
|
||||
from tasks.rogue.assets.assets_rogue_ui import ROGUE_LAUNCH
|
||||
from tasks.rogue.bleesing.ui import RogueUI
|
||||
from tasks.rogue.keywords import KEYWORDS_ROGUE_PATH, RoguePath
|
||||
|
||||
|
||||
def area_pad_around(area, pad):
|
||||
"""
|
||||
Inner offset an area.
|
||||
|
||||
Args:
|
||||
area: (upper_left_x, upper_left_y, bottom_right_x, bottom_right_y).
|
||||
pad (tuple):
|
||||
|
||||
Returns:
|
||||
tuple: (upper_left_x, upper_left_y, bottom_right_x, bottom_right_y).
|
||||
"""
|
||||
upper_left_x, upper_left_y, bottom_right_x, bottom_right_y = area
|
||||
upper_left_x_pad, upper_left_y_pad, bottom_right_x_pad, bottom_right_y_pad = pad
|
||||
return upper_left_x + upper_left_x_pad, \
|
||||
upper_left_y + upper_left_y_pad, \
|
||||
bottom_right_x - bottom_right_x_pad, \
|
||||
bottom_right_y - bottom_right_y_pad
|
||||
|
||||
|
||||
class RoguePathHandler(RogueUI):
|
||||
@cached_property
|
||||
def _rogue_path_checks(self) -> Dict[RoguePath, ButtonWrapper]:
|
||||
buttons = {
|
||||
KEYWORDS_ROGUE_PATH.Preservation: CHECK_PRESERVATION,
|
||||
KEYWORDS_ROGUE_PATH.Remembrance: CHECK_REMEMBRANCE,
|
||||
KEYWORDS_ROGUE_PATH.Nihility: CHECK_NIHILITY,
|
||||
KEYWORDS_ROGUE_PATH.Abundance: CHECK_ABUNDANCE,
|
||||
KEYWORDS_ROGUE_PATH.The_Hunt: CHECK_THE_HUNT,
|
||||
KEYWORDS_ROGUE_PATH.Destruction: CHECK_DESTRUCTION,
|
||||
KEYWORDS_ROGUE_PATH.Elation: CHECK_ELATION,
|
||||
}
|
||||
return buttons
|
||||
|
||||
@cached_property
|
||||
def _rogue_path_clicks(self) -> Dict[RoguePath, ButtonWrapper]:
|
||||
buttons = {
|
||||
KEYWORDS_ROGUE_PATH.Preservation: CLICK_PRESERVATION,
|
||||
KEYWORDS_ROGUE_PATH.Remembrance: CLICK_REMEMBRANCE,
|
||||
KEYWORDS_ROGUE_PATH.Nihility: CLICK_NIHILITY,
|
||||
KEYWORDS_ROGUE_PATH.Abundance: CLICK_ABUNDANCE,
|
||||
KEYWORDS_ROGUE_PATH.The_Hunt: CLICK_THE_HUNT,
|
||||
KEYWORDS_ROGUE_PATH.Destruction: CLICK_DESTRUCTION,
|
||||
KEYWORDS_ROGUE_PATH.Elation: CLICK_ELATION,
|
||||
}
|
||||
# Path list is sliding, expand search area
|
||||
for b in buttons.values():
|
||||
b.load_search(area_pad_around(b.area, pad=(-100, -5, -100, -5)))
|
||||
return buttons
|
||||
|
||||
def _get_path_click(self, path: RoguePath) -> ButtonWrapper:
|
||||
try:
|
||||
return self._rogue_path_clicks[path]
|
||||
except KeyError:
|
||||
logger.critical(f'Invalid rogue path: {path}')
|
||||
raise ScriptError
|
||||
|
||||
def _get_selected_path(self, skip_first_screenshot=True) -> Optional[RoguePath]:
|
||||
timeout = Timer(1, count=5).start()
|
||||
while 1:
|
||||
if skip_first_screenshot:
|
||||
skip_first_screenshot = False
|
||||
else:
|
||||
self.device.screenshot()
|
||||
|
||||
if timeout.reached():
|
||||
break
|
||||
for path, button in self._rogue_path_checks.items():
|
||||
# Check colors to wait appear animation
|
||||
if self.match_template_color(button):
|
||||
logger.attr('SelectPath', path)
|
||||
return path
|
||||
|
||||
logger.warning('Unable to get select path')
|
||||
return None
|
||||
|
||||
def _is_page_rogue_path(self) -> bool:
|
||||
appear = [self.appear(button) for button in self._rogue_path_clicks.values()]
|
||||
return all(appear)
|
||||
|
||||
def rogue_path_select(self, path: str | RoguePath, skip_first_screenshot=True):
|
||||
"""
|
||||
Pages:
|
||||
in: LAUNCH_ROGUE
|
||||
out: is_page_choose_bonus()
|
||||
or page_main if previous rogue run had bonus selected but didn't finish any domain
|
||||
"""
|
||||
logger.hr('Rogue path select', level=2)
|
||||
path: RoguePath = RoguePath.find(path)
|
||||
logger.info(f'Select path: {path}')
|
||||
entry = self._get_path_click(path)
|
||||
while 1:
|
||||
if skip_first_screenshot:
|
||||
skip_first_screenshot = False
|
||||
else:
|
||||
self.device.screenshot()
|
||||
|
||||
# End
|
||||
if self.is_page_choose_bonus():
|
||||
logger.info('rogue_path_select ended at is_page_choose_bonus')
|
||||
break
|
||||
if self.is_in_main():
|
||||
logger.info('rogue_path_select ended at page_main')
|
||||
break
|
||||
|
||||
if self.appear_then_click(ROGUE_LAUNCH, interval=2):
|
||||
continue
|
||||
# The average level of your team is lower than the recommended level.
|
||||
# Continue anyway?
|
||||
if self.handle_popup_confirm():
|
||||
continue
|
||||
# Select path
|
||||
if self.interval_is_reached(entry) and self._is_page_rogue_path():
|
||||
if self.appear_then_click(entry):
|
||||
self.interval_reset(entry)
|
||||
# Confirm path
|
||||
if self.appear(CONFIRM_PATH, interval=2):
|
||||
if self._get_selected_path() == path:
|
||||
self.device.click(CONFIRM_PATH)
|
||||
continue
|
||||
else:
|
||||
logger.warning('Selected to the wrong path')
|
||||
self.device.click(BACK)
|
||||
continue
|
@ -104,8 +104,8 @@ class RogueRewardHandler(RogueUI):
|
||||
in: is_page_rogue_main()
|
||||
out: is_page_rogue_main()
|
||||
"""
|
||||
logger.hr('Rogue reward claim', level=2)
|
||||
if self._rogue_reward_appear():
|
||||
logger.hr('Rogue reward claim', level=2)
|
||||
self._rogue_reward_enter()
|
||||
self._rogue_reward_claim()
|
||||
self._rogue_reward_exit()
|
||||
|
@ -1,8 +1,9 @@
|
||||
from tasks.rogue.path import RoguePathHandler
|
||||
from tasks.rogue.reward import RogueRewardHandler
|
||||
from tasks.rogue.route.loader import RouteLoader
|
||||
|
||||
|
||||
class RogueHandler(RouteLoader, RogueRewardHandler):
|
||||
class RogueHandler(RouteLoader, RogueRewardHandler, RoguePathHandler):
|
||||
def rogue_once(self):
|
||||
"""
|
||||
Do a complete rogue run.
|
||||
@ -11,6 +12,7 @@ class RogueHandler(RouteLoader, RogueRewardHandler):
|
||||
in: page_rogue, is_page_rogue_main()
|
||||
out: page_rogue, is_page_rogue_main()
|
||||
"""
|
||||
self.rogue_path_select(self.config.RoguePath_Path)
|
||||
self.rogue_run()
|
||||
self.rogue_reward_claim()
|
||||
|
||||
|