mirror of
https://github.com/LmeSzinc/StarRailCopilot.git
synced 2024-11-22 00:35:34 +00:00
Add: Task Ornament
This commit is contained in:
parent
71e01d9bd8
commit
4afe0bf908
@ -10,7 +10,7 @@ class ManualConfig:
|
||||
|
||||
SCHEDULER_PRIORITY = """
|
||||
Restart
|
||||
> Weekly > Dungeon > Assignment
|
||||
> Weekly > Ornament > Dungeon > Assignment
|
||||
> BattlePass > DailyQuest
|
||||
> Freebies > DataUpdate
|
||||
> Rogue
|
||||
|
4
src.py
4
src.py
@ -58,6 +58,10 @@ class StarRailCopilot(AzurLaneAutoScript):
|
||||
from tasks.rogue.rogue import Rogue
|
||||
Rogue(config=self.config, device=self.device).run()
|
||||
|
||||
def ornament(self):
|
||||
from tasks.ornament.ornament import Ornament
|
||||
Ornament(config=self.config, device=self.device).run()
|
||||
|
||||
def benchmark(self):
|
||||
from module.daemon.benchmark import run_benchmark
|
||||
run_benchmark(config=self.config)
|
||||
|
@ -15,6 +15,7 @@ class Dungeon(DungeonStamina, DungeonEvent, Combat):
|
||||
achieved_daily_quest = False
|
||||
achieved_weekly_quest = False
|
||||
running_double = False
|
||||
support_once = True
|
||||
daily_quests = []
|
||||
weekly_quests = []
|
||||
|
||||
@ -76,14 +77,16 @@ 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
|
||||
# No need, already checked in Survival_Index
|
||||
# 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)
|
||||
@ -177,7 +180,7 @@ class Dungeon(DungeonStamina, DungeonEvent, Combat):
|
||||
out: page_main
|
||||
"""
|
||||
require = self.require_compulsory_support()
|
||||
if require:
|
||||
if require and self.support_once:
|
||||
logger.info('Run once with support')
|
||||
count = self._dungeon_run(dungeon=dungeon, team=team, wave_limit=1,
|
||||
support_character=self.config.DungeonSupport_Character)
|
||||
@ -192,22 +195,22 @@ class Dungeon(DungeonStamina, DungeonEvent, Combat):
|
||||
|
||||
return count
|
||||
|
||||
elif require and not self.support_once:
|
||||
# Run with support all the way
|
||||
return self._dungeon_run(dungeon=dungeon, team=team, wave_limit=1,
|
||||
support_character=self.config.DungeonSupport_Character)
|
||||
|
||||
else:
|
||||
# Normal run
|
||||
return self._dungeon_run(dungeon=dungeon, team=team, wave_limit=wave_limit,
|
||||
support_character=support_character)
|
||||
|
||||
def run(self):
|
||||
self.config.update_battle_pass_quests()
|
||||
self.config.update_daily_quests()
|
||||
self.check_synthesize()
|
||||
self.called_daily_support = False
|
||||
self.achieved_daily_quest = False
|
||||
self.achieved_weekly_quest = False
|
||||
self.running_double = False
|
||||
self.daily_quests = self.config.stored.DailyQuest.load_quests()
|
||||
self.weekly_quests = self.config.stored.BattlePassWeeklyQuest.load_quests()
|
||||
|
||||
def update_double_event_record(self):
|
||||
"""
|
||||
Pages:
|
||||
in: Any
|
||||
out: page_guide, Survival_Index
|
||||
"""
|
||||
# Update double event records
|
||||
if (self.config.stored.DungeonDouble.is_expired()
|
||||
or self.config.stored.DungeonDouble.calyx > 0
|
||||
@ -216,7 +219,8 @@ class Dungeon(DungeonStamina, DungeonEvent, Combat):
|
||||
logger.info('Get dungeon double remains')
|
||||
# UI switches
|
||||
switched = self.dungeon_tab_goto(KEYWORDS_DUNGEON_TAB.Survival_Index)
|
||||
if not switched:
|
||||
if not switched and not self._dungeon_survival_index_top_appear():
|
||||
logger.info('Reset nav states')
|
||||
# Nav must at top, reset nav states
|
||||
self.ui_goto_main()
|
||||
self.dungeon_tab_goto(KEYWORDS_DUNGEON_TAB.Survival_Index)
|
||||
@ -237,6 +241,18 @@ class Dungeon(DungeonStamina, DungeonEvent, Combat):
|
||||
self.config.stored.DungeonDouble.relic = relic
|
||||
self.config.stored.DungeonDouble.rogue = rogue
|
||||
|
||||
def run(self):
|
||||
self.config.update_battle_pass_quests()
|
||||
self.config.update_daily_quests()
|
||||
self.check_synthesize()
|
||||
self.called_daily_support = False
|
||||
self.achieved_daily_quest = False
|
||||
self.achieved_weekly_quest = False
|
||||
self.running_double = False
|
||||
self.daily_quests = self.config.stored.DailyQuest.load_quests()
|
||||
self.weekly_quests = self.config.stored.BattlePassWeeklyQuest.load_quests()
|
||||
self.update_double_event_record()
|
||||
|
||||
# Run double events
|
||||
planner = self.planner.get_dungeon(double_calyx=True)
|
||||
# Double calyx
|
||||
@ -274,14 +290,6 @@ class Dungeon(DungeonStamina, DungeonEvent, Combat):
|
||||
final = planner
|
||||
self.is_doing_planner = True
|
||||
|
||||
# Check daily
|
||||
if self.achieved_daily_quest:
|
||||
self.config.task_call('DailyQuest')
|
||||
self.config.task_stop()
|
||||
if self.achieved_weekly_quest:
|
||||
self.config.task_call('BattlePass')
|
||||
self.config.task_stop()
|
||||
|
||||
# Use all stamina
|
||||
if do_rogue:
|
||||
# Use support if prioritize rogue
|
||||
|
@ -131,7 +131,7 @@ class DungeonState(UI):
|
||||
"""
|
||||
Delay tasks that use stamina
|
||||
"""
|
||||
if dungeon.is_Simulated_Universe:
|
||||
if dungeon.is_Simulated_Universe or dungeon.is_Ornament_Extraction:
|
||||
limit = 80
|
||||
elif dungeon.is_Cavern_of_Corrosion:
|
||||
limit = 80
|
||||
@ -182,7 +182,7 @@ class DungeonState(UI):
|
||||
logger.info(f'Approaching next monday, delay to {next_monday} instead')
|
||||
future = next_monday
|
||||
|
||||
tasks = ['Dungeon', 'Weekly']
|
||||
tasks = ['Dungeon', 'Weekly', 'Ornament']
|
||||
with self.config.multi_set():
|
||||
for task in tasks:
|
||||
next_run = self.config.cross_get(keys=f'{task}.Scheduler.NextRun', default=DEFAULT_TIME)
|
||||
|
@ -311,6 +311,13 @@ class DungeonUI(DungeonState):
|
||||
logger.info('Survival index loaded, SURVIVAL_INDEX_OE_LOADED')
|
||||
return True
|
||||
|
||||
def _dungeon_survival_index_top_appear(self):
|
||||
if self.appear(SURVIVAL_INDEX_SU_LOADED):
|
||||
return True
|
||||
if self.appear(SURVIVAL_INDEX_OE_LOADED):
|
||||
return True
|
||||
return False
|
||||
|
||||
def _dungeon_wait_treasures_lightward_loaded(self, skip_first_screenshot=True):
|
||||
"""
|
||||
Returns:
|
||||
|
@ -5,15 +5,15 @@ from tasks.base.assets.assets_base_page import MAP_EXIT
|
||||
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.dungeon.dungeon import Dungeon
|
||||
from tasks.dungeon.state import DungeonState
|
||||
from tasks.map.route.loader import RouteLoader
|
||||
from tasks.map.route.route.daily import OrnamentExtraction__route
|
||||
from tasks.ornament.assets.assets_ornament_combat import *
|
||||
from tasks.ornament.assets.assets_ornament_ui import *
|
||||
|
||||
|
||||
class OrnamentCombat(DungeonEvent, Combat, RouteLoader):
|
||||
class OrnamentCombat(Dungeon, RouteLoader, DungeonState):
|
||||
def combat_enter_from_map(self, skip_first_screenshot=True):
|
||||
# Don't enter from map, UI too deep inside
|
||||
# Enter from survival index instead
|
||||
@ -23,23 +23,6 @@ class OrnamentCombat(DungeonEvent, Combat, RouteLoader):
|
||||
# Different position to OCR
|
||||
return super().get_double_event_remain_at_combat(button)
|
||||
|
||||
def _dungeon_wait_until_dungeon_list_loaded(self, skip_first_screenshot=True):
|
||||
# Check save file before entering
|
||||
result = super()._dungeon_wait_until_dungeon_list_loaded(skip_first_screenshot)
|
||||
|
||||
if self.image_color_count(
|
||||
DIVERGENT_UNIVERSE_SAVE_UNAVAILABLE,
|
||||
color=(195, 89, 79), threshold=221, count=1000,
|
||||
):
|
||||
logger.error(
|
||||
'Divergent Universe save unavailable, '
|
||||
'please clear Divergent Universe once before running Ornament Extraction'
|
||||
)
|
||||
self.config.task_delay(server_update=True)
|
||||
self.config.task_stop()
|
||||
|
||||
return result
|
||||
|
||||
def oe_leave(self, skip_first_screenshot=True):
|
||||
self.interval_clear([COMBAT_PREPARE, MAP_EXIT])
|
||||
logger.hr('OE leave')
|
||||
@ -121,6 +104,32 @@ class OrnamentCombat(DungeonEvent, Combat, RouteLoader):
|
||||
self.interval_reset(COMBAT_SUPPORT_LIST)
|
||||
continue
|
||||
|
||||
def combat_get_trailblaze_power(self, expect_reduce=False, skip_first_screenshot=True) -> int:
|
||||
"""
|
||||
Args:
|
||||
expect_reduce: Current value is supposed to be lower than the previous.
|
||||
skip_first_screenshot:
|
||||
|
||||
Returns:
|
||||
int: Equivalent stamina
|
||||
|
||||
Pages:
|
||||
in: COMBAT_PREPARE or COMBAT_REPEAT
|
||||
"""
|
||||
before = self.config.stored.TrailblazePower.value + self.config.stored.Immersifier.value * 40
|
||||
|
||||
after = before
|
||||
for _ in range(3):
|
||||
self.dungeon_update_stamina()
|
||||
after = self.config.stored.TrailblazePower.value + self.config.stored.Immersifier.value * 40
|
||||
if expect_reduce:
|
||||
if before > after:
|
||||
break
|
||||
else:
|
||||
break
|
||||
|
||||
return after
|
||||
|
||||
def is_team_prepared(self) -> bool:
|
||||
"""
|
||||
Pages:
|
||||
@ -169,7 +178,11 @@ class OrnamentCombat(DungeonEvent, Combat, RouteLoader):
|
||||
# End
|
||||
if self.is_in_main():
|
||||
logger.info('Combat map entered')
|
||||
self.device.screenshot_interval_set()
|
||||
break
|
||||
if self.is_combat_executing():
|
||||
self.device.screenshot_interval_set()
|
||||
return True
|
||||
# Relics full
|
||||
# Clicking between COMBAT_PREPARE and COMBAT_TEAM_PREPARE
|
||||
if trial > 5:
|
||||
@ -187,6 +200,7 @@ class OrnamentCombat(DungeonEvent, Combat, RouteLoader):
|
||||
if support_set and self.appear(COMBAT_PREPARE, interval=5):
|
||||
# Long loading after COMBAT_PREPARE
|
||||
self.device.click(COMBAT_PREPARE)
|
||||
self.device.screenshot_interval_set('combat')
|
||||
trial += 1
|
||||
continue
|
||||
if self.handle_popup_confirm():
|
||||
|
99
tasks/ornament/ornament.py
Normal file
99
tasks/ornament/ornament.py
Normal file
@ -0,0 +1,99 @@
|
||||
from datetime import timedelta
|
||||
|
||||
from module.config.stored.classes import now
|
||||
from module.config.utils import DEFAULT_TIME
|
||||
from module.exception import ScriptError
|
||||
from module.logger import logger
|
||||
from tasks.dungeon.assets.assets_dungeon_ui_rogue import DIVERGENT_UNIVERSE_SAVE_UNAVAILABLE
|
||||
from tasks.dungeon.keywords import DungeonList
|
||||
from tasks.ornament.combat import OrnamentCombat
|
||||
|
||||
|
||||
class Ornament(OrnamentCombat):
|
||||
# Reuse support, cause exit and re-enter is so time-wasting in Divergent Universe
|
||||
support_once = False
|
||||
|
||||
def _dungeon_wait_until_dungeon_list_loaded(self, skip_first_screenshot=True):
|
||||
|
||||
result = super()._dungeon_wait_until_dungeon_list_loaded(skip_first_screenshot)
|
||||
|
||||
# Check save file before entering
|
||||
if self.image_color_count(
|
||||
DIVERGENT_UNIVERSE_SAVE_UNAVAILABLE,
|
||||
color=(195, 89, 79), threshold=221, count=1000,
|
||||
):
|
||||
logger.error(
|
||||
'Divergent Universe save unavailable, '
|
||||
'please clear Divergent Universe once before running Ornament Extraction'
|
||||
)
|
||||
self.config.task_delay(server_update=True)
|
||||
self.config.task_stop()
|
||||
|
||||
# Always update double rogue
|
||||
record = self.config.stored.DungeonDouble.time
|
||||
if now() - record < timedelta(seconds=5):
|
||||
# Updated just now
|
||||
pass
|
||||
else:
|
||||
if self.has_double_relic_event():
|
||||
rogue = self.get_double_rogue_remain()
|
||||
self.config.stored.DungeonDouble.rogue = rogue
|
||||
else:
|
||||
logger.info('No double rogue event')
|
||||
|
||||
# Check stamina
|
||||
logger.info('Check stamina')
|
||||
stamina = self.combat_get_trailblaze_power()
|
||||
if stamina < self.combat_wave_cost:
|
||||
logger.info('Current trailblaze power is not enough for a run')
|
||||
self.delay_dungeon_task(self.dungeon)
|
||||
self.config.task_stop()
|
||||
if not self.config.Ornament_UseStamina and self.config.stored.DungeonDouble.rogue <= 0:
|
||||
if self.config.stored.Immersifier.value <= 0:
|
||||
logger.info('Current immersifier is not enough for a run')
|
||||
self.delay_dungeon_task(self.dungeon)
|
||||
self.config.task_stop()
|
||||
|
||||
return result
|
||||
|
||||
def run(self):
|
||||
self.config.update_battle_pass_quests()
|
||||
self.config.update_daily_quests()
|
||||
# self.check_synthesize()
|
||||
self.called_daily_support = False
|
||||
self.achieved_daily_quest = False
|
||||
self.achieved_weekly_quest = False
|
||||
self.running_double = False
|
||||
self.daily_quests = self.config.stored.DailyQuest.load_quests()
|
||||
self.weekly_quests = self.config.stored.BattlePassWeeklyQuest.load_quests()
|
||||
self.update_double_event_record()
|
||||
|
||||
# During double event, do it first
|
||||
if self.config.stored.DungeonDouble.calyx or self.config.stored.DungeonDouble.relic:
|
||||
logger.info('During double calyx or relic event, delay Ornament')
|
||||
future = self.config.cross_get('Dungeon.Scheduler.NextRun', default=DEFAULT_TIME)
|
||||
future = future + timedelta(minutes=1)
|
||||
with self.config.multi_set():
|
||||
self.config.task_delay(target=future)
|
||||
self.config.task_stop()
|
||||
|
||||
# Run
|
||||
dungeon = DungeonList.find(self.config.Ornament_Dungeon)
|
||||
self.combat_wave_cost = 40
|
||||
self.dungeon = dungeon
|
||||
if self.config.Ornament_UseStamina:
|
||||
# No limit
|
||||
self.dungeon_run(dungeon, wave_limit=0)
|
||||
# Stamina should have exhausted in dungeon_run
|
||||
raise ScriptError('Ornament finished but stamina was not exhausted')
|
||||
elif self.config.stored.DungeonDouble.rogue > 0:
|
||||
# Limited in double events
|
||||
self.running_double = True
|
||||
self.dungeon_run(dungeon, wave_limit=self.config.stored.DungeonDouble.rogue)
|
||||
self.running_double = False
|
||||
|
||||
self.config.task_delay(server_update=True)
|
||||
else:
|
||||
# Use immersifier only, wave limited in _dungeon_wait_until_dungeon_list_loaded
|
||||
self.dungeon_run(dungeon, wave_limit=0)
|
||||
self.config.task_delay(server_update=True)
|
Loading…
Reference in New Issue
Block a user