mirror of
https://github.com/LmeSzinc/StarRailCopilot.git
synced 2024-11-15 22:19:18 +00:00
Add: Combat preparation in ornament
This commit is contained in:
parent
b1ef9d0786
commit
85ac47d6b6
BIN
assets/share/combat/support/FIRST_CHARACTER.png
Normal file
BIN
assets/share/combat/support/FIRST_CHARACTER.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 5.5 KiB |
BIN
assets/share/ornament/combat/CHARACTER_EMPTY_OE.SEARCH.png
Normal file
BIN
assets/share/ornament/combat/CHARACTER_EMPTY_OE.SEARCH.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 29 KiB |
BIN
assets/share/ornament/combat/CHARACTER_EMPTY_OE.png
Normal file
BIN
assets/share/ornament/combat/CHARACTER_EMPTY_OE.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 6.1 KiB |
BIN
assets/share/ornament/combat/OCR_DOUBLE_EVENT_REMAIN_AT_OE.png
Normal file
BIN
assets/share/ornament/combat/OCR_DOUBLE_EVENT_REMAIN_AT_OE.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 37 KiB |
BIN
assets/share/ornament/combat/SUPPORT_ADD.png
Normal file
BIN
assets/share/ornament/combat/SUPPORT_ADD.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 6.7 KiB |
BIN
assets/share/ornament/combat/SUPPORT_DISMISS.png
Normal file
BIN
assets/share/ornament/combat/SUPPORT_DISMISS.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 6.5 KiB |
@ -43,6 +43,16 @@ COMBAT_SUPPORT_LIST_SCROLL = ButtonWrapper(
|
||||
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(
|
||||
name='SUPPORT_SELECTED',
|
||||
share=[
|
||||
|
@ -8,8 +8,7 @@ from module.logger import logger
|
||||
from module.ui.scroll import AdaptiveScroll
|
||||
from tasks.base.assets.assets_base_popup import POPUP_CANCEL
|
||||
from tasks.base.ui import UI
|
||||
from tasks.combat.assets.assets_combat_support import COMBAT_SUPPORT_ADD, COMBAT_SUPPORT_LIST, \
|
||||
COMBAT_SUPPORT_LIST_GRID, COMBAT_SUPPORT_LIST_SCROLL, SUPPORT_SELECTED
|
||||
from tasks.combat.assets.assets_combat_support import *
|
||||
from tasks.combat.assets.assets_combat_team import COMBAT_TEAM_DISMISSSUPPORT, COMBAT_TEAM_SUPPORT
|
||||
|
||||
|
||||
@ -260,6 +259,27 @@ class CombatSupport(UI):
|
||||
interval.reset()
|
||||
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):
|
||||
"""
|
||||
Pages:
|
||||
|
@ -76,6 +76,14 @@ class Dungeon(DungeonStamina, DungeonEvent, Combat):
|
||||
wave_limit = relic
|
||||
if relic == 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
|
||||
self.dungeon = dungeon
|
||||
count = self.combat(team=team, wave_limit=wave_limit, support_character=support_character)
|
||||
|
@ -61,19 +61,19 @@ class DungeonEvent(UI):
|
||||
logger.attr('Double rogue', 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:
|
||||
in: COMBAT_PREPARE
|
||||
"""
|
||||
has = self.image_color_count(
|
||||
OCR_DOUBLE_EVENT_REMAIN_AT_COMBAT,
|
||||
button,
|
||||
color=(231, 188, 103),
|
||||
threshold=240, count=1000
|
||||
)
|
||||
# Anniversary 3x event
|
||||
has |= self.image_color_count(
|
||||
OCR_DOUBLE_EVENT_REMAIN_AT_COMBAT,
|
||||
button,
|
||||
color=(229, 62, 44),
|
||||
threshold=221, count=50
|
||||
)
|
||||
@ -109,16 +109,16 @@ class DungeonEvent(UI):
|
||||
logger.attr('Double event remain', 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:
|
||||
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)
|
||||
return 0
|
||||
|
||||
ocr = DoubleEventOcr(OCR_DOUBLE_EVENT_REMAIN_AT_COMBAT)
|
||||
ocr = DoubleEventOcr(button)
|
||||
for row in ocr.detect_and_ocr(self.device.image):
|
||||
if not ocr.is_format_matched(row.ocr_text):
|
||||
continue
|
||||
|
45
tasks/ornament/assets/assets_ornament_combat.py
Normal file
45
tasks/ornament/assets/assets_ornament_combat.py
Normal 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
142
tasks/ornament/combat.py
Normal 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
|
Loading…
Reference in New Issue
Block a user