mirror of
https://github.com/LmeSzinc/StarRailCopilot.git
synced 2024-11-25 18:05:26 +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),
|
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=[
|
||||||
|
@ -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:
|
||||||
|
@ -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)
|
||||||
|
@ -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
|
||||||
|
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