mirror of
https://github.com/LmeSzinc/StarRailCopilot.git
synced 2024-11-16 06:25:24 +00:00
Add: Task Echo of War
This commit is contained in:
parent
05096c9105
commit
96b6bdadf0
BIN
assets/cn/combat/finish/COMBAT_AGAIN.SEARCH.png
Normal file
BIN
assets/cn/combat/finish/COMBAT_AGAIN.SEARCH.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 11 KiB |
BIN
assets/cn/combat/prepare/COMBAT_PREPARE.SEARCH.png
Normal file
BIN
assets/cn/combat/prepare/COMBAT_PREPARE.SEARCH.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 12 KiB |
BIN
assets/en/combat/finish/COMBAT_AGAIN.SEARCH.png
Normal file
BIN
assets/en/combat/finish/COMBAT_AGAIN.SEARCH.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 10 KiB |
BIN
assets/en/combat/prepare/COMBAT_PREPARE.SEARCH.png
Normal file
BIN
assets/en/combat/prepare/COMBAT_PREPARE.SEARCH.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 12 KiB |
BIN
assets/share/dungeon/ui/OCR_WEEKLY_LIMIT.png
Normal file
BIN
assets/share/dungeon/ui/OCR_WEEKLY_LIMIT.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 8.7 KiB |
4
src.py
4
src.py
@ -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()
|
||||||
|
@ -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),
|
||||||
),
|
),
|
||||||
|
@ -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),
|
||||||
),
|
),
|
||||||
|
@ -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')
|
||||||
|
@ -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:
|
||||||
|
@ -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(
|
||||||
|
@ -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):
|
||||||
|
@ -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
88
tasks/dungeon/weekly.py
Normal 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()
|
Loading…
Reference in New Issue
Block a user