Add: Combat preparation in ornament

This commit is contained in:
LmeSzinc 2024-07-01 02:17:43 +08:00
parent b1ef9d0786
commit 85ac47d6b6
12 changed files with 233 additions and 8 deletions

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 29 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 37 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.5 KiB

View File

@ -43,6 +43,16 @@ COMBAT_SUPPORT_LIST_SCROLL = ButtonWrapper(
button=(472, 162, 476, 598), button=(472, 162, 476, 598),
), ),
) )
FIRST_CHARACTER = ButtonWrapper(
name='FIRST_CHARACTER',
share=Button(
file='./assets/share/combat/support/FIRST_CHARACTER.png',
area=(136, 140, 386, 204),
search=(116, 120, 406, 224),
color=(255, 255, 255),
button=(136, 140, 386, 204),
),
)
SUPPORT_SELECTED = ButtonWrapper( SUPPORT_SELECTED = ButtonWrapper(
name='SUPPORT_SELECTED', name='SUPPORT_SELECTED',
share=[ share=[

View File

@ -8,8 +8,7 @@ from module.logger import logger
from module.ui.scroll import AdaptiveScroll from module.ui.scroll import AdaptiveScroll
from tasks.base.assets.assets_base_popup import POPUP_CANCEL from tasks.base.assets.assets_base_popup import POPUP_CANCEL
from tasks.base.ui import UI from tasks.base.ui import UI
from tasks.combat.assets.assets_combat_support import COMBAT_SUPPORT_ADD, COMBAT_SUPPORT_LIST, \ from tasks.combat.assets.assets_combat_support import *
COMBAT_SUPPORT_LIST_GRID, COMBAT_SUPPORT_LIST_SCROLL, SUPPORT_SELECTED
from tasks.combat.assets.assets_combat_team import COMBAT_TEAM_DISMISSSUPPORT, COMBAT_TEAM_SUPPORT from tasks.combat.assets.assets_combat_team import COMBAT_TEAM_DISMISSSUPPORT, COMBAT_TEAM_SUPPORT
@ -260,6 +259,27 @@ class CombatSupport(UI):
interval.reset() interval.reset()
continue continue
def _select_first(self):
logger.hr("Combat support select")
logger.info(f'Select: first')
skip_first_screenshot = False
interval = Timer(2)
while 1:
if skip_first_screenshot:
skip_first_screenshot = False
else:
self.device.screenshot()
# End
if SUPPORT_SELECTED.match_template(self.device.image, similarity=0.75):
logger.info('Character support selected')
return True
if interval.reached():
self.device.click(FIRST_CHARACTER)
interval.reset()
continue
def _cancel_popup(self): def _cancel_popup(self):
""" """
Pages: Pages:

View File

@ -76,6 +76,14 @@ class Dungeon(DungeonStamina, DungeonEvent, Combat):
wave_limit = relic wave_limit = relic
if relic == 0: if relic == 0:
return 0 return 0
if dungeon.is_Ornament_Extraction and self.running_double and \
self.config.stored.DungeonDouble.rogue > 0:
rogue = self.get_double_event_remain_at_combat()
if rogue is not None and rogue < self.config.stored.DungeonDouble.rogue:
self.config.stored.DungeonDouble.rogue = rogue
wave_limit = rogue
if rogue == 0:
return 0
# Combat # Combat
self.dungeon = dungeon self.dungeon = dungeon
count = self.combat(team=team, wave_limit=wave_limit, support_character=support_character) count = self.combat(team=team, wave_limit=wave_limit, support_character=support_character)

View File

@ -61,19 +61,19 @@ class DungeonEvent(UI):
logger.attr('Double rogue', has) logger.attr('Double rogue', has)
return has return has
def has_double_event_at_combat(self) -> bool: def has_double_event_at_combat(self, button=OCR_DOUBLE_EVENT_REMAIN_AT_COMBAT) -> bool:
""" """
Pages: Pages:
in: COMBAT_PREPARE in: COMBAT_PREPARE
""" """
has = self.image_color_count( has = self.image_color_count(
OCR_DOUBLE_EVENT_REMAIN_AT_COMBAT, button,
color=(231, 188, 103), color=(231, 188, 103),
threshold=240, count=1000 threshold=240, count=1000
) )
# Anniversary 3x event # Anniversary 3x event
has |= self.image_color_count( has |= self.image_color_count(
OCR_DOUBLE_EVENT_REMAIN_AT_COMBAT, button,
color=(229, 62, 44), color=(229, 62, 44),
threshold=221, count=50 threshold=221, count=50
) )
@ -109,16 +109,16 @@ class DungeonEvent(UI):
logger.attr('Double event remain', remain) logger.attr('Double event remain', remain)
return remain return remain
def get_double_event_remain_at_combat(self) -> int | None: def get_double_event_remain_at_combat(self, button=OCR_DOUBLE_EVENT_REMAIN_AT_COMBAT) -> int | None:
""" """
Pages: Pages:
in: COMBAT_PREPARE in: COMBAT_PREPARE
""" """
if not self.has_double_event_at_combat(): if not self.has_double_event_at_combat(button=button):
logger.attr('Double event remain at combat', 0) logger.attr('Double event remain at combat', 0)
return 0 return 0
ocr = DoubleEventOcr(OCR_DOUBLE_EVENT_REMAIN_AT_COMBAT) ocr = DoubleEventOcr(button)
for row in ocr.detect_and_ocr(self.device.image): for row in ocr.detect_and_ocr(self.device.image):
if not ocr.is_format_matched(row.ocr_text): if not ocr.is_format_matched(row.ocr_text):
continue continue

View File

@ -0,0 +1,45 @@
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 ```
CHARACTER_EMPTY_OE = ButtonWrapper(
name='CHARACTER_EMPTY_OE',
share=Button(
file='./assets/share/ornament/combat/CHARACTER_EMPTY_OE.png',
area=(549, 513, 559, 537),
search=(525, 498, 824, 554),
color=(112, 112, 112),
button=(549, 513, 559, 537),
),
)
OCR_DOUBLE_EVENT_REMAIN_AT_OE = ButtonWrapper(
name='OCR_DOUBLE_EVENT_REMAIN_AT_OE',
share=Button(
file='./assets/share/ornament/combat/OCR_DOUBLE_EVENT_REMAIN_AT_OE.png',
area=(812, 577, 1248, 631),
search=(792, 557, 1268, 651),
color=(124, 103, 61),
button=(812, 577, 1248, 631),
),
)
SUPPORT_ADD = ButtonWrapper(
name='SUPPORT_ADD',
share=Button(
file='./assets/share/ornament/combat/SUPPORT_ADD.png',
area=(848, 518, 876, 537),
search=(828, 498, 896, 557),
color=(167, 200, 176),
button=(848, 518, 876, 537),
),
)
SUPPORT_DISMISS = ButtonWrapper(
name='SUPPORT_DISMISS',
share=Button(
file='./assets/share/ornament/combat/SUPPORT_DISMISS.png',
area=(853, 513, 872, 538),
search=(833, 493, 892, 558),
color=(135, 135, 135),
button=(853, 513, 872, 538),
),
)

142
tasks/ornament/combat.py Normal file
View File

@ -0,0 +1,142 @@
from module.base.decorator import run_once
from module.exception import RequestHumanTakeover
from module.logger import logger
from tasks.base.assets.assets_base_popup import POPUP_CANCEL
from tasks.combat.assets.assets_combat_prepare import COMBAT_PREPARE
from tasks.combat.assets.assets_combat_support import COMBAT_SUPPORT_LIST
from tasks.combat.combat import Combat
from tasks.dungeon.event import DungeonEvent
from tasks.ornament.assets.assets_ornament_combat import *
class OrnamentCombat(DungeonEvent, Combat):
def combat_enter_from_map(self, skip_first_screenshot=True):
# Don't enter from map, UI too deep inside
# Enter from survival index instead
pass
def get_double_event_remain_at_combat(self, button=OCR_DOUBLE_EVENT_REMAIN_AT_OE):
# Different position to OCR
return super().get_double_event_remain_at_combat(button)
def support_set(self, support_character_name: str = "FirstCharacter"):
"""
Args:
support_character_name: Support character name
Returns:
bool: If clicked
Pages:
in: COMBAT_PREPARE
mid: COMBAT_SUPPORT_LIST
out: COMBAT_PREPARE
"""
logger.hr("Combat support")
self.interval_clear(SUPPORT_ADD)
skip_first_screenshot = True
selected_support = False
while 1:
if skip_first_screenshot:
skip_first_screenshot = False
else:
self.device.screenshot()
# End
if self.appear(SUPPORT_DISMISS):
return True
# Click
if self.appear(SUPPORT_ADD, interval=2):
self.device.click(SUPPORT_ADD)
self.interval_reset(SUPPORT_ADD)
continue
if self.appear(POPUP_CANCEL, interval=1):
logger.warning(
"selected identical character, trying select another")
self._cancel_popup()
self._select_next_support()
self.interval_reset(POPUP_CANCEL)
continue
if self.appear(COMBAT_SUPPORT_LIST, interval=2):
if not selected_support:
# In Ornament Extraction, first character isn't selected by default
if support_character_name == "FirstCharacter":
self._select_first()
else:
self._search_support(support_character_name) # Search support
selected_support = True
self.device.click(OCR_DOUBLE_EVENT_REMAIN_AT_OE)
self.interval_reset(COMBAT_SUPPORT_LIST)
continue
def is_team_prepared(self) -> bool:
"""
Pages:
in: COMBAT_PREPARE
"""
slots = CHARACTER_EMPTY_OE.match_multi_template(self.device.image)
slots = 4 - len(slots)
logger.attr('TeamSlotsPrepared', slots)
return slots > 0
def combat_prepare(self, team=1, support_character: str = None):
"""
Args:
team: 1 to 6.
support_character: Support character name
Returns:
bool: True
Pages:
in: COMBAT_PREPARE
out: is_in_main
"""
@run_once
def check_team_prepare():
if not self.is_team_prepared():
logger.error(f'Please prepare your team in Ornament Extraction')
raise RequestHumanTakeover
logger.hr('Combat prepare')
skip_first_screenshot = True
if support_character:
# Block COMBAT_TEAM_PREPARE before support set
support_set = False
else:
support_set = True
logger.info([support_character, support_set])
trial = 0
while 1:
if skip_first_screenshot:
skip_first_screenshot = False
else:
self.device.screenshot()
# End
if self.is_in_main():
logger.info('Combat entered')
return True
# Relics full
# Clicking between COMBAT_PREPARE and COMBAT_TEAM_PREPARE
if trial > 5:
logger.critical('Failed to enter dungeon after 5 trial, probably because relics are full')
raise RequestHumanTakeover
if self.appear(SUPPORT_ADD):
check_team_prepare()
# Click
if support_character and self.appear(SUPPORT_ADD, interval=2):
self.support_set(support_character)
self.interval_reset(SUPPORT_ADD)
support_set = True
continue
if support_set and self.appear(COMBAT_PREPARE, interval=5):
# Long loading after COMBAT_PREPARE
self.device.click(COMBAT_PREPARE)
trial += 1
continue
if self.handle_popup_confirm():
continue