BIN
assets/share/dungeon/ui_rogue/DIVERGENT_UNIVERSE_LOADED.png
Normal file
After Width: | Height: | Size: 5.9 KiB |
BIN
assets/share/dungeon/ui_rogue/LAST_TELEPORT.png
Normal file
After Width: | Height: | Size: 6.1 KiB |
After Width: | Height: | Size: 6.8 KiB |
Before Width: | Height: | Size: 7.2 KiB After Width: | Height: | Size: 7.2 KiB |
Before Width: | Height: | Size: 15 KiB After Width: | Height: | Size: 15 KiB |
Before Width: | Height: | Size: 6.6 KiB After Width: | Height: | Size: 6.6 KiB |
@ -554,8 +554,9 @@ class KeywordExtract:
|
||||
yield hash_
|
||||
|
||||
def generate(self):
|
||||
self.load_keywords(['模拟宇宙', '拟造花萼(金)', '拟造花萼(赤)', '凝滞虚影', '侵蚀隧洞', '历战余响',
|
||||
'忘却之庭', '虚构叙事'])
|
||||
self.load_keywords(['饰品提取', '差分宇宙', '模拟宇宙',
|
||||
'拟造花萼(金)', '拟造花萼(赤)', '凝滞虚影', '侵蚀隧洞', '历战余响',
|
||||
'最近更新', '忘却之庭', '虚构叙事', '末日幻影'])
|
||||
self.write_keywords(keyword_class='DungeonNav', output_file='./tasks/dungeon/keywords/nav.py')
|
||||
self.load_keywords(['行动摘要', '生存索引', '每日实训', '模拟宇宙', '逐光捡金', '战术训练'])
|
||||
self.write_keywords(keyword_class='DungeonTab', output_file='./tasks/dungeon/keywords/tab.py')
|
||||
|
@ -137,14 +137,14 @@ class Switch:
|
||||
current = self.get(main=main)
|
||||
logger.attr(self.name, current)
|
||||
|
||||
# Handle additional popups
|
||||
if self.handle_additional(main=main):
|
||||
continue
|
||||
|
||||
# End
|
||||
if current == state:
|
||||
return changed
|
||||
|
||||
# Handle additional popups
|
||||
if self.handle_additional(main=main):
|
||||
continue
|
||||
|
||||
# Warning
|
||||
if current == 'unknown':
|
||||
if warning_show_timer.reached():
|
||||
@ -165,3 +165,36 @@ class Switch:
|
||||
changed = True
|
||||
|
||||
return changed
|
||||
|
||||
def wait(self, main, skip_first_screenshot=True):
|
||||
"""
|
||||
Wait until any state activated
|
||||
|
||||
Args:
|
||||
main (ModuleBase):
|
||||
skip_first_screenshot:
|
||||
|
||||
Returns:
|
||||
bool: If success
|
||||
"""
|
||||
timeout = Timer(2, count=6).start()
|
||||
while 1:
|
||||
if skip_first_screenshot:
|
||||
skip_first_screenshot = False
|
||||
else:
|
||||
main.device.screenshot()
|
||||
|
||||
# Detect
|
||||
current = self.get(main=main)
|
||||
logger.attr(self.name, current)
|
||||
|
||||
# End
|
||||
if current != 'unknown':
|
||||
return True
|
||||
if timeout.reached():
|
||||
logger.warning(f'{self.name} wait activated timeout')
|
||||
return False
|
||||
|
||||
# Handle additional popups
|
||||
if self.handle_additional(main=main):
|
||||
continue
|
||||
|
@ -163,26 +163,6 @@ SURVIVAL_INDEX_CLICK = ButtonWrapper(
|
||||
button=(332, 94, 370, 133),
|
||||
),
|
||||
)
|
||||
SURVIVAL_INDEX_OE_LOADED = ButtonWrapper(
|
||||
name='SURVIVAL_INDEX_OE_LOADED',
|
||||
share=Button(
|
||||
file='./assets/share/dungeon/ui/SURVIVAL_INDEX_OE_LOADED.png',
|
||||
area=(473, 207, 498, 232),
|
||||
search=(453, 187, 518, 252),
|
||||
color=(185, 135, 74),
|
||||
button=(473, 207, 498, 232),
|
||||
),
|
||||
)
|
||||
SURVIVAL_INDEX_SU_LOADED = ButtonWrapper(
|
||||
name='SURVIVAL_INDEX_SU_LOADED',
|
||||
share=Button(
|
||||
file='./assets/share/dungeon/ui/SURVIVAL_INDEX_SU_LOADED.png',
|
||||
area=(451, 286, 476, 302),
|
||||
search=(449, 263, 489, 356),
|
||||
color=(142, 150, 197),
|
||||
button=(451, 286, 476, 302),
|
||||
),
|
||||
)
|
||||
TAB_SEARCH = ButtonWrapper(
|
||||
name='TAB_SEARCH',
|
||||
share=Button(
|
||||
|
55
tasks/dungeon/assets/assets_dungeon_ui_rogue.py
Normal file
@ -0,0 +1,55 @@
|
||||
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 ```
|
||||
|
||||
DIVERGENT_UNIVERSE_LOADED = ButtonWrapper(
|
||||
name='DIVERGENT_UNIVERSE_LOADED',
|
||||
share=Button(
|
||||
file='./assets/share/dungeon/ui_rogue/DIVERGENT_UNIVERSE_LOADED.png',
|
||||
area=(893, 608, 911, 628),
|
||||
search=(873, 588, 931, 648),
|
||||
color=(103, 102, 102),
|
||||
button=(893, 608, 911, 628),
|
||||
),
|
||||
)
|
||||
LAST_TELEPORT = ButtonWrapper(
|
||||
name='LAST_TELEPORT',
|
||||
share=Button(
|
||||
file='./assets/share/dungeon/ui_rogue/LAST_TELEPORT.png',
|
||||
area=(1018, 579, 1038, 599),
|
||||
search=(998, 559, 1058, 619),
|
||||
color=(84, 83, 85),
|
||||
button=(1018, 579, 1038, 599),
|
||||
),
|
||||
)
|
||||
SIMULATED_UNIVERSE_LOADED_CLASSIC = ButtonWrapper(
|
||||
name='SIMULATED_UNIVERSE_LOADED_CLASSIC',
|
||||
share=Button(
|
||||
file='./assets/share/dungeon/ui_rogue/SIMULATED_UNIVERSE_LOADED_CLASSIC.png',
|
||||
area=(549, 607, 572, 629),
|
||||
search=(529, 587, 592, 649),
|
||||
color=(147, 137, 157),
|
||||
button=(549, 607, 572, 629),
|
||||
),
|
||||
)
|
||||
SURVIVAL_INDEX_OE_LOADED = ButtonWrapper(
|
||||
name='SURVIVAL_INDEX_OE_LOADED',
|
||||
share=Button(
|
||||
file='./assets/share/dungeon/ui_rogue/SURVIVAL_INDEX_OE_LOADED.png',
|
||||
area=(473, 207, 498, 232),
|
||||
search=(453, 187, 518, 252),
|
||||
color=(185, 135, 74),
|
||||
button=(473, 207, 498, 232),
|
||||
),
|
||||
)
|
||||
SURVIVAL_INDEX_SU_LOADED = ButtonWrapper(
|
||||
name='SURVIVAL_INDEX_SU_LOADED',
|
||||
share=Button(
|
||||
file='./assets/share/dungeon/ui_rogue/SURVIVAL_INDEX_SU_LOADED.png',
|
||||
area=(451, 286, 476, 302),
|
||||
search=(449, 263, 489, 356),
|
||||
color=(142, 150, 197),
|
||||
button=(451, 286, 476, 302),
|
||||
),
|
||||
)
|
@ -3,8 +3,26 @@ from .classes import DungeonNav
|
||||
# This file was auto-generated, do not modify it manually. To generate:
|
||||
# ``` python -m dev_tools.keyword_extract ```
|
||||
|
||||
Simulated_Universe = DungeonNav(
|
||||
Ornament_Extraction = DungeonNav(
|
||||
id=1,
|
||||
name='Ornament_Extraction',
|
||||
cn='饰品提取',
|
||||
cht='飾品提取',
|
||||
en='Ornament Extraction',
|
||||
jp='オーナメント抽出',
|
||||
es='Extracción de ornamentos',
|
||||
)
|
||||
Divergent_Universe = DungeonNav(
|
||||
id=2,
|
||||
name='Divergent_Universe',
|
||||
cn='差分宇宙',
|
||||
cht='差分宇宙',
|
||||
en='Divergent Universe',
|
||||
jp='階差宇宙',
|
||||
es='Universo Diferenciado',
|
||||
)
|
||||
Simulated_Universe = DungeonNav(
|
||||
id=3,
|
||||
name='Simulated_Universe',
|
||||
cn='模拟宇宙',
|
||||
cht='模擬宇宙',
|
||||
@ -13,7 +31,7 @@ Simulated_Universe = DungeonNav(
|
||||
es='Universo Simulado',
|
||||
)
|
||||
Calyx_Golden = DungeonNav(
|
||||
id=2,
|
||||
id=4,
|
||||
name='Calyx_Golden',
|
||||
cn='拟造花萼(金)',
|
||||
cht='擬造花萼(金)',
|
||||
@ -22,7 +40,7 @@ Calyx_Golden = DungeonNav(
|
||||
es='Cáliz (oro)',
|
||||
)
|
||||
Calyx_Crimson = DungeonNav(
|
||||
id=3,
|
||||
id=5,
|
||||
name='Calyx_Crimson',
|
||||
cn='拟造花萼(赤)',
|
||||
cht='擬造花萼(赤)',
|
||||
@ -31,7 +49,7 @@ Calyx_Crimson = DungeonNav(
|
||||
es='Cáliz (carmesí)',
|
||||
)
|
||||
Stagnant_Shadow = DungeonNav(
|
||||
id=4,
|
||||
id=6,
|
||||
name='Stagnant_Shadow',
|
||||
cn='凝滞虚影',
|
||||
cht='凝滯虛影',
|
||||
@ -40,7 +58,7 @@ Stagnant_Shadow = DungeonNav(
|
||||
es='Sombra paralizada',
|
||||
)
|
||||
Cavern_of_Corrosion = DungeonNav(
|
||||
id=5,
|
||||
id=7,
|
||||
name='Cavern_of_Corrosion',
|
||||
cn='侵蚀隧洞',
|
||||
cht='侵蝕隧洞',
|
||||
@ -49,7 +67,7 @@ Cavern_of_Corrosion = DungeonNav(
|
||||
es='Caverna de la corrosión',
|
||||
)
|
||||
Echo_of_War = DungeonNav(
|
||||
id=6,
|
||||
id=8,
|
||||
name='Echo_of_War',
|
||||
cn='历战余响',
|
||||
cht='歷戰餘響',
|
||||
@ -57,8 +75,17 @@ Echo_of_War = DungeonNav(
|
||||
jp='歴戦余韻',
|
||||
es='Ecos de la guerra',
|
||||
)
|
||||
Latest_Update = DungeonNav(
|
||||
id=9,
|
||||
name='Latest_Update',
|
||||
cn='最近更新',
|
||||
cht='最近更新',
|
||||
en='Latest Update',
|
||||
jp='最近更新',
|
||||
es='Actualización reciente',
|
||||
)
|
||||
Forgotten_Hall = DungeonNav(
|
||||
id=7,
|
||||
id=10,
|
||||
name='Forgotten_Hall',
|
||||
cn='忘却之庭',
|
||||
cht='忘卻之庭',
|
||||
@ -67,7 +94,7 @@ Forgotten_Hall = DungeonNav(
|
||||
es='Salón olvidado',
|
||||
)
|
||||
Pure_Fiction = DungeonNav(
|
||||
id=8,
|
||||
id=11,
|
||||
name='Pure_Fiction',
|
||||
cn='虚构叙事',
|
||||
cht='虛構敘事',
|
||||
@ -75,3 +102,12 @@ Pure_Fiction = DungeonNav(
|
||||
jp='虚構叙事',
|
||||
es='Pura ficción',
|
||||
)
|
||||
Apocalyptic_Shadow = DungeonNav(
|
||||
id=12,
|
||||
name='Apocalyptic_Shadow',
|
||||
cn='末日幻影',
|
||||
cht='末日幻影',
|
||||
en='Apocalyptic Shadow',
|
||||
jp='末日の幻影',
|
||||
es='Espejismo apocalíptico',
|
||||
)
|
||||
|
@ -4,6 +4,7 @@ from module.logger import logger
|
||||
from module.ocr.ocr import Digit
|
||||
from tasks.base.page import page_guide
|
||||
from tasks.dungeon.assets.assets_dungeon_stamina import *
|
||||
from tasks.dungeon.keywords import KEYWORDS_DUNGEON_TAB
|
||||
from tasks.dungeon.ui import DungeonUI
|
||||
|
||||
|
||||
@ -138,7 +139,7 @@ class DungeonStamina(DungeonUI):
|
||||
"""
|
||||
logger.hr('Immersifier store', level=2)
|
||||
logger.info(f'Max store: {max_store}')
|
||||
self.dungeon_goto_rogue()
|
||||
self.dungeon_tab_goto(KEYWORDS_DUNGEON_TAB.Survival_Index)
|
||||
self.dungeon_update_stamina()
|
||||
before = self.config.stored.Immersifier.value
|
||||
|
||||
|
@ -139,6 +139,8 @@ class DungeonState(UI):
|
||||
limit = 30
|
||||
else:
|
||||
limit = 60
|
||||
if self.config.is_cloud_game:
|
||||
limit = 120
|
||||
|
||||
# Double event is not yet finished, do it today as possible
|
||||
update = get_server_next_update(self.config.Scheduler_ServerUpdate)
|
||||
|
@ -17,6 +17,7 @@ from tasks.base.page import page_guide
|
||||
from tasks.combat.assets.assets_combat_interact import DUNGEON_COMBAT_INTERACT, DUNGEON_COMBAT_INTERACT_TEXT
|
||||
from tasks.combat.assets.assets_combat_prepare import COMBAT_PREPARE
|
||||
from tasks.dungeon.assets.assets_dungeon_ui import *
|
||||
from tasks.dungeon.assets.assets_dungeon_ui_rogue import *
|
||||
from tasks.dungeon.keywords import (
|
||||
DungeonList,
|
||||
DungeonNav,
|
||||
@ -337,6 +338,17 @@ class DungeonUI(DungeonState):
|
||||
logger.info('Treasures lightward loaded (event locked)')
|
||||
return True
|
||||
|
||||
def _dungeon_list_button_has_content(self):
|
||||
# Check if having any content
|
||||
# List background: 254, guild border: 225
|
||||
r, g, b = cv2.split(self.image_crop(LIST_LOADED_CHECK, copy=False))
|
||||
minimum = cv2.min(cv2.min(r, g), b)
|
||||
minimum = inrange(minimum, lower=0, upper=180)
|
||||
if minimum.size > 100:
|
||||
return True
|
||||
else:
|
||||
return False
|
||||
|
||||
def _dungeon_wait_until_dungeon_list_loaded(self, skip_first_screenshot=True):
|
||||
timeout = Timer(1, count=3).start()
|
||||
while 1:
|
||||
@ -350,14 +362,9 @@ class DungeonUI(DungeonState):
|
||||
logger.warning('Wait until dungeon list loaded timeout')
|
||||
return False
|
||||
|
||||
# Check if having any content
|
||||
# List background: 254, guild border: 225
|
||||
r, g, b = cv2.split(self.image_crop(LIST_LOADED_CHECK, copy=False))
|
||||
minimum = cv2.min(cv2.min(r, g), b)
|
||||
minimum = inrange(minimum, lower=0, upper=180)
|
||||
if minimum.size > 100:
|
||||
if self._dungeon_list_button_has_content():
|
||||
logger.info('Dungeon list loaded')
|
||||
break
|
||||
return True
|
||||
|
||||
def _dungeon_wait_until_echo_or_war_stabled(self, skip_first_screenshot=True):
|
||||
"""
|
||||
@ -431,12 +438,14 @@ class DungeonUI(DungeonState):
|
||||
break
|
||||
|
||||
# Check if it's at the first page.
|
||||
if button := DUNGEON_NAV_LIST.keyword2button(KEYWORDS_DUNGEON_NAV.Simulated_Universe, show_warning=False):
|
||||
if DUNGEON_NAV_LIST.keyword2button(KEYWORDS_DUNGEON_NAV.Simulated_Universe, show_warning=False) \
|
||||
or DUNGEON_NAV_LIST.keyword2button(KEYWORDS_DUNGEON_NAV.Ornament_Extraction, show_warning=False):
|
||||
# Going to use a faster method to navigate but can only start from list top
|
||||
logger.info('DUNGEON_NAV_LIST at top')
|
||||
# Update points if possible
|
||||
if DUNGEON_NAV_LIST.is_row_selected(button, main=self):
|
||||
self.dungeon_update_simuni()
|
||||
# 2.3, No longer weekly points after Divergent Universe unlocked
|
||||
# if DUNGEON_NAV_LIST.is_row_selected(button, main=self):
|
||||
# self.dungeon_update_simuni()
|
||||
# Treasures lightward is always at top
|
||||
elif DUNGEON_NAV_LIST.keyword2button(KEYWORDS_DUNGEON_NAV.Forgotten_Hall, show_warning=False) \
|
||||
or DUNGEON_NAV_LIST.keyword2button(KEYWORDS_DUNGEON_NAV.Pure_Fiction, show_warning=False):
|
||||
@ -450,6 +459,8 @@ class DungeonUI(DungeonState):
|
||||
# Check the first page
|
||||
if nav in [
|
||||
KEYWORDS_DUNGEON_NAV.Simulated_Universe,
|
||||
KEYWORDS_DUNGEON_NAV.Divergent_Universe,
|
||||
KEYWORDS_DUNGEON_NAV.Ornament_Extraction,
|
||||
KEYWORDS_DUNGEON_NAV.Calyx_Golden,
|
||||
KEYWORDS_DUNGEON_NAV.Calyx_Crimson,
|
||||
KEYWORDS_DUNGEON_NAV.Stagnant_Shadow,
|
||||
@ -698,26 +709,6 @@ class DungeonUI(DungeonState):
|
||||
logger.attr('DungeonInteract', None)
|
||||
return None
|
||||
|
||||
def dungeon_goto_rogue(self):
|
||||
"""
|
||||
Goto Simulated Universe page but not pressing the TELEPORT button
|
||||
|
||||
Pages:
|
||||
in: Any
|
||||
out: page_guide, Survival_Index, Simulated_Universe
|
||||
|
||||
Examples:
|
||||
self = DungeonUI('src')
|
||||
self.device.screenshot()
|
||||
self.dungeon_goto_rogue()
|
||||
self._rogue_teleport()
|
||||
"""
|
||||
self.dungeon_tab_goto(KEYWORDS_DUNGEON_TAB.Survival_Index)
|
||||
if self.appear(SURVIVAL_INDEX_SU_LOADED):
|
||||
logger.info('Already at nav Simulated_Universe')
|
||||
else:
|
||||
self._dungeon_nav_goto(KEYWORDS_DUNGEON_NAV.Simulated_Universe)
|
||||
|
||||
def dungeon_goto(self, dungeon: DungeonList):
|
||||
"""
|
||||
Returns:
|
||||
|
131
tasks/dungeon/ui_rogue.py
Normal file
@ -0,0 +1,131 @@
|
||||
from module.base.timer import Timer
|
||||
from module.base.utils import random_rectangle_vector
|
||||
from module.logger import logger
|
||||
from tasks.base.page import page_guide
|
||||
from tasks.dungeon.assets.assets_dungeon_ui import *
|
||||
from tasks.dungeon.assets.assets_dungeon_ui_rogue import *
|
||||
from tasks.dungeon.keywords import KEYWORDS_DUNGEON_NAV, KEYWORDS_DUNGEON_TAB
|
||||
from tasks.dungeon.ui import DungeonUI, SWITCH_DUNGEON_TAB
|
||||
from tasks.forgotten_hall.assets.assets_forgotten_hall_ui import TELEPORT
|
||||
|
||||
|
||||
class DungeonRogueUI(DungeonUI):
|
||||
def dungeon_goto_rogue(self):
|
||||
"""
|
||||
Goto Simulated Universe page but not pressing the TELEPORT button
|
||||
|
||||
Pages:
|
||||
in: Any
|
||||
out: page_guide, Survival_Index, Simulated_Universe
|
||||
|
||||
Examples:
|
||||
self = DungeonUI('src')
|
||||
self.device.screenshot()
|
||||
self.dungeon_goto_rogue()
|
||||
self._rogue_teleport()
|
||||
"""
|
||||
logger.hr('Dungeon tab goto', level=2)
|
||||
ui_switched = self.ui_ensure(page_guide)
|
||||
SWITCH_DUNGEON_TAB.wait(main=self)
|
||||
|
||||
if (
|
||||
self.appear(SIMULATED_UNIVERSE_CLICK)
|
||||
or self.appear(SIMULATED_UNIVERSE_CHECK)
|
||||
or self.appear(SURVIVAL_INDEX_OE_LOADED)
|
||||
):
|
||||
logger.info('Having rogue tab')
|
||||
state = KEYWORDS_DUNGEON_TAB.Simulated_Universe
|
||||
# Switch tab
|
||||
tab_switched = SWITCH_DUNGEON_TAB.set(state, main=self)
|
||||
if ui_switched or tab_switched:
|
||||
logger.info(f'Tab goto {state}, wait until loaded')
|
||||
self._dungeon_wait_until_rogue_loaded()
|
||||
# Switch nav
|
||||
self._dungeon_nav_goto(KEYWORDS_DUNGEON_NAV.Simulated_Universe)
|
||||
# No idea how to wait list loaded
|
||||
# List is not able to swipe without fully loaded
|
||||
self.wait_until_stable(LIST_LOADED_CHECK)
|
||||
# Swipe
|
||||
self._dungeon_rogue_swipe_down()
|
||||
else:
|
||||
logger.info('No rogue tab')
|
||||
state = KEYWORDS_DUNGEON_TAB.Survival_Index
|
||||
# Switch tab
|
||||
tab_switched = SWITCH_DUNGEON_TAB.set(state, main=self)
|
||||
if ui_switched or tab_switched:
|
||||
logger.info(f'Tab goto {state}, wait until loaded')
|
||||
self._dungeon_wait_survival_index_loaded()
|
||||
# Switch nav
|
||||
if self.appear(SURVIVAL_INDEX_SU_LOADED):
|
||||
logger.info('Already at nav Simulated_Universe')
|
||||
else:
|
||||
self._dungeon_nav_goto(KEYWORDS_DUNGEON_NAV.Simulated_Universe)
|
||||
|
||||
def _dungeon_wait_until_rogue_loaded(self, skip_first_screenshot=True):
|
||||
"""
|
||||
Returns:
|
||||
bool: True if wait success, False if wait timeout.
|
||||
|
||||
Pages:
|
||||
in: page_guide, Simulated_Universe
|
||||
"""
|
||||
timeout = Timer(2, count=4).start()
|
||||
while 1:
|
||||
if skip_first_screenshot:
|
||||
skip_first_screenshot = False
|
||||
else:
|
||||
self.device.screenshot()
|
||||
|
||||
if timeout.reached():
|
||||
logger.warning('Wait rogue tab loaded timeout')
|
||||
return False
|
||||
if self.appear(DIVERGENT_UNIVERSE_LOADED):
|
||||
logger.info('Rogue tab loaded, DIVERGENT_UNIVERSE_LOADED')
|
||||
return True
|
||||
# No LAST_TELEPORT, may hit teleport button of old screenshots from Ornament Extraction
|
||||
# if self.appear(LAST_TELEPORT):
|
||||
# logger.info('Rogue tab loaded, LAST_TELEPORT')
|
||||
# return True
|
||||
|
||||
def _dungeon_rogue_swipe_down(self, skip_first_screenshot=True):
|
||||
"""
|
||||
Swipe down to find teleport button of classic rogue
|
||||
Note that this method will change SIMULATED_UNIVERSE_LOADED_CLASSIC.search, original value should have a backup
|
||||
"""
|
||||
# Already having classic rogue entry insight
|
||||
SIMULATED_UNIVERSE_LOADED_CLASSIC.load_search(OCR_DUNGEON_LIST.button)
|
||||
if self.appear(SIMULATED_UNIVERSE_LOADED_CLASSIC):
|
||||
buttons = TELEPORT.match_multi_template(self.device.image)
|
||||
y = SIMULATED_UNIVERSE_LOADED_CLASSIC.button[1]
|
||||
for button in buttons:
|
||||
# And having a teleport button below
|
||||
if button.button[1] > y:
|
||||
logger.info('Classic rogue teleport already in sight')
|
||||
return True
|
||||
|
||||
logger.info('Dungeon rogue swipe down')
|
||||
interval = Timer(2, count=4)
|
||||
while 1:
|
||||
if skip_first_screenshot:
|
||||
skip_first_screenshot = False
|
||||
else:
|
||||
self.device.screenshot()
|
||||
|
||||
# End
|
||||
if self.appear(SIMULATED_UNIVERSE_LOADED_CLASSIC):
|
||||
if self.appear(LAST_TELEPORT):
|
||||
logger.info('Classic rogue teleport at end')
|
||||
return True
|
||||
|
||||
# Swipe
|
||||
if interval.reached():
|
||||
p1, p2 = random_rectangle_vector(
|
||||
(0, -450), box=OCR_DUNGEON_LIST.button, random_range=(-20, -20, 20, 20), padding=5)
|
||||
self.device.swipe(p1, p2)
|
||||
interval.reset()
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
self = DungeonRogueUI('src')
|
||||
self.device.screenshot()
|
||||
self.dungeon_goto_rogue()
|
@ -4,10 +4,9 @@ from scipy import signal
|
||||
|
||||
from module.base.base import ModuleBase
|
||||
from module.base.button import ButtonWrapper
|
||||
from module.base.decorator import cached_property, del_cached_property
|
||||
from module.base.decorator import cached_property
|
||||
from module.base.timer import Timer
|
||||
from module.base.utils import Lines, area_center, area_offset, color_similarity_2d
|
||||
from module.exception import ScriptError
|
||||
from module.logger import logger
|
||||
|
||||
|
||||
@ -71,6 +70,8 @@ class InventoryManager:
|
||||
ERROR_LINES_TOLERANCE = (-10, 10)
|
||||
COINCIDENT_POINT_ENCOURAGE_DISTANCE = 1.
|
||||
|
||||
MAXIMUM_ITEMS = 30
|
||||
|
||||
def __init__(self, main: ModuleBase, inventory: ButtonWrapper):
|
||||
"""
|
||||
max_count: expected max count of this inventory page
|
||||
@ -248,7 +249,10 @@ class InventoryManager:
|
||||
else:
|
||||
self.selected = selected[0]
|
||||
|
||||
logger.info(f'Inventory: {len(self.items)} items, selected {self.selected}')
|
||||
count = len(self.items)
|
||||
logger.info(f'Inventory: {count} items, selected {self.selected}')
|
||||
if count > self.MAXIMUM_ITEMS:
|
||||
logger.warning('Too many inventory items detected')
|
||||
|
||||
def get_row_first(self, row=1, first=0) -> InventoryItem | None:
|
||||
"""
|
||||
@ -292,12 +296,9 @@ class InventoryManager:
|
||||
def select(self, item, skip_first_screenshot=True):
|
||||
logger.info(f'Inventory select {item}')
|
||||
if isinstance(item, InventoryItem):
|
||||
pass
|
||||
loca = item.loca
|
||||
else:
|
||||
try:
|
||||
item = self.items[item]
|
||||
except KeyError:
|
||||
raise ScriptError(f'Inventory select {item} but is not in current items')
|
||||
loca = item
|
||||
|
||||
interval = Timer(2, count=6)
|
||||
while 1:
|
||||
@ -306,8 +307,16 @@ class InventoryManager:
|
||||
else:
|
||||
self.main.device.screenshot()
|
||||
|
||||
self.update()
|
||||
if len(self.items) > self.MAXIMUM_ITEMS:
|
||||
continue
|
||||
try:
|
||||
item = self.items[loca]
|
||||
except KeyError:
|
||||
logger.warning(f'Item {loca} is not in inventory, cannot select')
|
||||
continue
|
||||
|
||||
# End
|
||||
del_cached_property(item, 'is_selected')
|
||||
if item.is_selected:
|
||||
logger.info('Inventory item selected')
|
||||
break
|
||||
@ -315,8 +324,7 @@ class InventoryManager:
|
||||
if interval.reached():
|
||||
self.main.device.click(item)
|
||||
interval.reset()
|
||||
|
||||
self.update()
|
||||
continue
|
||||
|
||||
def wait_selected(self, skip_first_screenshot=True):
|
||||
"""
|
||||
@ -334,8 +342,10 @@ class InventoryManager:
|
||||
self.main.device.screenshot()
|
||||
|
||||
self.update()
|
||||
if self.selected is not None:
|
||||
return True
|
||||
if timeout.reached():
|
||||
logger.warning('Wait inventory selected timeout')
|
||||
return False
|
||||
if len(self.items) > self.MAXIMUM_ITEMS:
|
||||
continue
|
||||
if self.selected is not None:
|
||||
return True
|
||||
|
@ -15,7 +15,7 @@ from tasks.base.page import page_guide, page_item, page_main, page_rogue
|
||||
from tasks.dungeon.keywords import DungeonList
|
||||
from tasks.dungeon.keywords.dungeon import Simulated_Universe_World_1
|
||||
from tasks.dungeon.state import OcrSimUniPoint
|
||||
from tasks.dungeon.ui import DungeonUI
|
||||
from tasks.dungeon.ui_rogue import DungeonRogueUI
|
||||
from tasks.forgotten_hall.assets.assets_forgotten_hall_ui import TELEPORT
|
||||
from tasks.rogue.assets.assets_rogue_entry import (
|
||||
LEVEL_CONFIRM,
|
||||
@ -103,7 +103,7 @@ class OcrRogueWorld(Ocr):
|
||||
return 0
|
||||
|
||||
|
||||
class RogueEntry(RouteBase, RogueRewardHandler, RoguePathHandler, DungeonUI):
|
||||
class RogueEntry(RouteBase, RogueRewardHandler, RoguePathHandler, DungeonRogueUI):
|
||||
def _rogue_world_wait(self, skip_first_screenshot=True):
|
||||
"""
|
||||
Wait is_page_rogue_main() fully loaded
|
||||
@ -308,7 +308,7 @@ class RogueEntry(RouteBase, RogueRewardHandler, RoguePathHandler, DungeonUI):
|
||||
def _rogue_teleport(self, skip_first_screenshot=True):
|
||||
"""
|
||||
Pages:
|
||||
in: page_guide, Survival_Index, Simulated_Universe
|
||||
in: page_guide, Simulated_Universe, Simulated_Universe
|
||||
out: page_rogue, is_page_rogue_main()
|
||||
"""
|
||||
logger.info('Rogue teleport')
|
||||
@ -333,7 +333,8 @@ class RogueEntry(RouteBase, RogueRewardHandler, RoguePathHandler, DungeonUI):
|
||||
if self.appear(page_guide.check_button, interval=2):
|
||||
buttons = TELEPORT.match_multi_template(self.device.image)
|
||||
if len(buttons):
|
||||
buttons = sorted(buttons, key=lambda x: x.area[1])
|
||||
# 2.3, classic rogue is always at bottom
|
||||
buttons = sorted(buttons, key=lambda x: x.area[1], reverse=True)
|
||||
self.device.click(buttons[0])
|
||||
continue
|
||||
|
||||
|