Add: Task Echo of War

This commit is contained in:
LmeSzinc 2023-09-27 03:14:12 +08:00
parent 05096c9105
commit 96b6bdadf0
14 changed files with 137 additions and 9 deletions

Binary file not shown.

After

Width:  |  Height:  |  Size: 11 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 12 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 10 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 12 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 8.7 KiB

4
src.py
View File

@ -26,6 +26,10 @@ class StarRailCopilot(AzurLaneAutoScript):
from tasks.dungeon.dungeon import Dungeon from tasks.dungeon.dungeon import Dungeon
Dungeon(config=self.config, device=self.device).run() Dungeon(config=self.config, device=self.device).run()
def weekly(self):
from tasks.dungeon.weekly import WeeklyDungeon
WeeklyDungeon(config=self.config, device=self.device).run()
def daily_quest(self): def daily_quest(self):
from tasks.daily.daily_quest import DailyQuestUI from tasks.daily.daily_quest import DailyQuestUI
DailyQuestUI(config=self.config, device=self.device).run() DailyQuestUI(config=self.config, device=self.device).run()

View File

@ -8,14 +8,14 @@ COMBAT_AGAIN = ButtonWrapper(
cn=Button( cn=Button(
file='./assets/cn/combat/finish/COMBAT_AGAIN.png', file='./assets/cn/combat/finish/COMBAT_AGAIN.png',
area=(846, 601, 924, 619), area=(846, 601, 924, 619),
search=(826, 581, 944, 639), search=(709, 592, 979, 628),
color=(162, 162, 162), color=(162, 162, 162),
button=(709, 592, 979, 628), button=(709, 592, 979, 628),
), ),
en=Button( en=Button(
file='./assets/en/combat/finish/COMBAT_AGAIN.png', file='./assets/en/combat/finish/COMBAT_AGAIN.png',
area=(809, 602, 902, 618), area=(809, 602, 902, 618),
search=(789, 582, 922, 638), search=(709, 591, 981, 628),
color=(159, 159, 159), color=(159, 159, 159),
button=(709, 591, 981, 628), button=(709, 591, 981, 628),
), ),

View File

@ -8,14 +8,14 @@ COMBAT_PREPARE = ButtonWrapper(
cn=Button( cn=Button(
file='./assets/cn/combat/prepare/COMBAT_PREPARE.png', file='./assets/cn/combat/prepare/COMBAT_PREPARE.png',
area=(1071, 649, 1110, 667), area=(1071, 649, 1110, 667),
search=(1051, 629, 1130, 687), search=(836, 640, 1225, 677),
color=(141, 140, 141), color=(141, 140, 141),
button=(956, 640, 1224, 676), button=(956, 640, 1224, 676),
), ),
en=Button( en=Button(
file='./assets/en/combat/prepare/COMBAT_PREPARE.png', file='./assets/en/combat/prepare/COMBAT_PREPARE.png',
area=(1043, 650, 1137, 666), area=(1043, 650, 1137, 666),
search=(1023, 630, 1157, 686), search=(836, 640, 1225, 677),
color=(153, 154, 155), color=(153, 154, 155),
button=(956, 640, 1225, 676), button=(956, 640, 1225, 676),
), ),

View File

@ -118,6 +118,8 @@ class Combat(CombatInteract, CombatPrepare, CombatState, CombatTeam, CombatSuppo
continue continue
if self.handle_ascension_dungeon_prepare(): if self.handle_ascension_dungeon_prepare():
continue continue
if self.handle_popup_confirm():
continue
def combat_execute(self, expected_end=None): def combat_execute(self, expected_end=None):
""" """
@ -165,7 +167,7 @@ class Combat(CombatInteract, CombatPrepare, CombatState, CombatTeam, CombatSuppo
Pages: Pages:
in: COMBAT_AGAIN in: COMBAT_AGAIN
""" """
current = self.combat_get_trailblaze_power(expect_reduce=True) current = self.combat_get_trailblaze_power(expect_reduce=self.combat_wave_cost > 0)
# Wave limit # Wave limit
if self.combat_wave_limit: if self.combat_wave_limit:
if self.combat_wave_done + self.combat_waves > self.combat_wave_limit: if self.combat_wave_done + self.combat_waves > self.combat_wave_limit:
@ -181,6 +183,9 @@ class Combat(CombatInteract, CombatPrepare, CombatState, CombatTeam, CombatSuppo
else: else:
logger.info(f'Current has {current}, combat costs {self.combat_wave_cost}, can not run again') logger.info(f'Current has {current}, combat costs {self.combat_wave_cost}, can not run again')
return False return False
elif self.combat_wave_cost <= 0:
logger.info(f'Free combat, combat costs {self.combat_wave_cost}, can not run again')
return False
else: else:
if current >= self.combat_wave_cost: if current >= self.combat_wave_cost:
logger.info(f'Current has {current}, combat costs {self.combat_wave_cost}, can run again') logger.info(f'Current has {current}, combat costs {self.combat_wave_cost}, can run again')

View File

@ -2,6 +2,7 @@ import re
import module.config.server as server import module.config.server as server
from module.base.timer import Timer from module.base.timer import Timer
from module.base.utils import color_similar, get_color
from module.logger import logger from module.logger import logger
from module.ocr.ocr import Digit, DigitCounter from module.ocr.ocr import Digit, DigitCounter
from tasks.base.ui import UI from tasks.base.ui import UI
@ -75,7 +76,7 @@ class CombatPrepare(UI):
# Empty result # Empty result
if total == 0: if total == 0:
continue continue
# Confirm if it is > 180, sometimes just OCR errors # Confirm if it is > 240, sometimes just OCR errors
if current > 240 and timeout.reached(): if current > 240 and timeout.reached():
break break
if expect_reduce and current >= self.config.stored.TrailblazePower.value: if expect_reduce and current >= self.config.stored.TrailblazePower.value:
@ -106,6 +107,12 @@ class CombatPrepare(UI):
else: else:
self.device.screenshot() self.device.screenshot()
color = get_color(self.device.image, OCR_WAVE_COST.area)
if color_similar(color, (229, 231, 223), threshold=30):
logger.info(f'Combat is trailblaze power free')
self.combat_wave_cost = 0
return 0
cost = Digit(OCR_WAVE_COST).ocr_single_line(self.device.image) cost = Digit(OCR_WAVE_COST).ocr_single_line(self.device.image)
if cost == 10: if cost == 10:
if multi: if multi:

View File

@ -73,6 +73,16 @@ OCR_SIMUNI_POINT_OFFSET = ButtonWrapper(
button=(685, 250, 717, 273), button=(685, 250, 717, 273),
), ),
) )
OCR_WEEKLY_LIMIT = ButtonWrapper(
name='OCR_WEEKLY_LIMIT',
share=Button(
file='./assets/share/dungeon/ui/OCR_WEEKLY_LIMIT.png',
area=(580, 225, 680, 257),
search=(560, 205, 700, 277),
color=(132, 192, 247),
button=(580, 225, 680, 257),
),
)
OPERATION_BRIEFING_CHECK = ButtonWrapper( OPERATION_BRIEFING_CHECK = ButtonWrapper(
name='OPERATION_BRIEFING_CHECK', name='OPERATION_BRIEFING_CHECK',
share=Button( share=Button(

View File

@ -1,4 +1,8 @@
from datetime import timedelta
from module.base.utils import area_offset from module.base.utils import area_offset
from module.config.stored.classes import now
from module.config.utils import DEFAULT_TIME
from module.logger import logger from module.logger import logger
from tasks.combat.combat import Combat from tasks.combat.combat import Combat
from tasks.daily.keywords import KEYWORDS_DAILY_QUEST from tasks.daily.keywords import KEYWORDS_DAILY_QUEST
@ -7,6 +11,7 @@ from tasks.dungeon.keywords import DungeonList, KEYWORDS_DUNGEON_LIST, KEYWORDS_
from tasks.dungeon.ui import DungeonUI from tasks.dungeon.ui import DungeonUI
from tasks.battle_pass.keywords import KEYWORD_BATTLE_PASS_QUEST from tasks.battle_pass.keywords import KEYWORD_BATTLE_PASS_QUEST
class Dungeon(DungeonUI, DungeonEvent, Combat): class Dungeon(DungeonUI, DungeonEvent, Combat):
called_daily_support = False called_daily_support = False
achieved_daily_quest = False achieved_daily_quest = False
@ -210,6 +215,8 @@ class Dungeon(DungeonUI, DungeonEvent, Combat):
def delay_dungeon_task(self, dungeon): def delay_dungeon_task(self, dungeon):
if dungeon.is_Cavern_of_Corrosion: if dungeon.is_Cavern_of_Corrosion:
limit = 80 limit = 80
elif dungeon.is_Echo_of_War:
limit = 30
else: else:
limit = 60 limit = 60
# Recover 1 trailbaze power each 6 minutes # Recover 1 trailbaze power each 6 minutes
@ -226,8 +233,14 @@ class Dungeon(DungeonUI, DungeonEvent, Combat):
# Check daily # Check daily
if self.achieved_daily_quest: if self.achieved_daily_quest:
self.config.task_call('DailyQuest') self.config.task_call('DailyQuest')
# Delay self # Delay tasks
self.config.task_delay(minute=cover) future = now() + timedelta(minutes=cover)
for task in ['Dungeon', 'Weekly']:
next_run = self.config.cross_get(keys=f'{task}.Scheduler.NextRun', default=DEFAULT_TIME)
if future > next_run:
logger.info(f"Delay task `{task}` to {future}")
self.config.cross_set(keys=f'{task}.Scheduler.NextRun', value=future)
self.config.task_stop() self.config.task_stop()
def handle_destructible_around_blaze(self): def handle_destructible_around_blaze(self):

View File

@ -428,7 +428,8 @@ class DungeonUI(UI):
if dungeon.is_Calyx_Golden \ if dungeon.is_Calyx_Golden \
or dungeon.is_Calyx_Crimson \ or dungeon.is_Calyx_Crimson \
or dungeon.is_Stagnant_Shadow \ or dungeon.is_Stagnant_Shadow \
or dungeon.is_Cavern_of_Corrosion: or dungeon.is_Cavern_of_Corrosion \
or dungeon.is_Echo_of_War:
self._dungeon_nav_goto(dungeon) self._dungeon_nav_goto(dungeon)
self._dungeon_insight(dungeon) self._dungeon_insight(dungeon)
self._dungeon_enter(dungeon) self._dungeon_enter(dungeon)

88
tasks/dungeon/weekly.py Normal file
View File

@ -0,0 +1,88 @@
from module.logger import logger
from module.ocr.ocr import DigitCounter
from tasks.daily.keywords import KEYWORDS_DAILY_QUEST
from tasks.dungeon.assets.assets_dungeon_ui import OCR_DUNGEON_LIST, OCR_WEEKLY_LIMIT
from tasks.dungeon.dungeon import Dungeon
from tasks.dungeon.keywords import DungeonList, KEYWORDS_DUNGEON_TAB
from tasks.dungeon.ui import DUNGEON_LIST
class WeeklyDungeon(Dungeon):
def require_compulsory_support(self) -> bool:
return False
def _dungeon_run(self, dungeon: DungeonList, team: int = None, wave_limit: int = 0, support_character: str = None,
skip_ui_switch: bool = False):
if team is None:
team = self.config.Weekly_Team
# No support
support_character = ''
skip_ui_switch = True
return super()._dungeon_run(
dungeon=dungeon, team=team, wave_limit=wave_limit,
support_character=support_character, skip_ui_switch=skip_ui_switch)
def get_weekly_remain(self) -> int:
"""
Pages:
in: page_guide, Survival_Index, KEYWORDS_DUNGEON_NAV.Echo_of_War
"""
ocr = DigitCounter(OCR_WEEKLY_LIMIT)
current, _, _ = ocr.ocr_single_line(self.device.image)
total = self.config.stored.EchoOfWar.FIXED_TOTAL
remain = total - current
if current <= total:
logger.attr('EchoOfWar', f'{current}/{total}')
self.config.stored.EchoOfWar.value = current
return current
else:
logger.warning(f'Invalid EchoOfWar limit: {current}/{total}')
return 0
def run(self):
# self.config.update_battle_pass_quests()
self.config.update_daily_quests()
self.called_daily_support = False
self.achieved_daily_quest = False
self.daily_quests = self.config.stored.DailyQuest.load_quests()
dungeon = DungeonList.find(self.config.Weekly_Name)
# UI switches
self.dungeon_tab_goto(KEYWORDS_DUNGEON_TAB.Survival_Index)
# Equivalent to self.dungeon_goto(dungeon), but check limit remains
DUNGEON_LIST.search_button = OCR_DUNGEON_LIST
self._dungeon_nav_goto(dungeon)
# Check limit
remain = self.get_weekly_remain()
if remain <= 0:
if KEYWORDS_DAILY_QUEST.Complete_Echo_of_War_1_times in self.daily_quests:
logger.info('Reached the limit to get Echo_of_War rewards, continue cause daily quests require it')
remain = 1
else:
logger.info('Reached the limit to get Echo_of_War rewards, stop')
self.config.task_delay(server_update=True)
self.config.task_stop()
self._dungeon_insight(dungeon)
self._dungeon_enter(dungeon)
# Combat
count = self.dungeon_run(dungeon, wave_limit=min(remain, 3))
with self.config.multi_set():
# Check daily quests
if count:
if KEYWORDS_DAILY_QUEST.Complete_Echo_of_War_1_times in self.daily_quests:
logger.info('Achieve daily quest Complete_Echo_of_War_1_times')
self.config.task_call('DailyQuest')
# Finished all remains
if count >= remain:
logger.info('All Echo_of_War rewards got')
self.config.task_delay(server_update=True)
self.config.task_stop()
logger.warning(f'Unexpected Echo_of_War case, count={count}, remain={remain}')
self.config.task_delay(server_update=True)
self.config.task_stop()