Add: Battle Pass Claim Rewards (#13)
* Add: Battle Pass Claim Rewards * Upd: comments of public methods * Fix: Break half way if not waiting for animation change finish * Fix: set dataclass repr to false * Add: Tasks BattlePass * Upd: break get_rewards into two loops
BIN
assets/cn/battle_pass/REWARDS_CLAIM_ALL.png
Normal file
After Width: | Height: | Size: 9.3 KiB |
BIN
assets/share/battle_pass/CLOSE_CHOOSE_GIFT.png
Normal file
After Width: | Height: | Size: 7.0 KiB |
BIN
assets/share/battle_pass/EXP_CLAIM_ALL.png
Normal file
After Width: | Height: | Size: 6.5 KiB |
BIN
assets/share/battle_pass/MISSIONS_CHECK.png
Normal file
After Width: | Height: | Size: 6.4 KiB |
BIN
assets/share/battle_pass/MISSIONS_CLICK.png
Normal file
After Width: | Height: | Size: 6.3 KiB |
BIN
assets/share/battle_pass/MISSIONS_LOADED.png
Normal file
After Width: | Height: | Size: 5.4 KiB |
BIN
assets/share/battle_pass/REWARDS_CHECK.png
Normal file
After Width: | Height: | Size: 7.4 KiB |
BIN
assets/share/battle_pass/REWARDS_CLICK.png
Normal file
After Width: | Height: | Size: 6.3 KiB |
BIN
assets/share/battle_pass/REWARDS_LOADED.png
Normal file
After Width: | Height: | Size: 7.8 KiB |
@ -51,5 +51,13 @@
|
||||
"Command": "DailyQuest",
|
||||
"ServerUpdate": "04:00"
|
||||
}
|
||||
},
|
||||
"BattlePass": {
|
||||
"Scheduler": {
|
||||
"Enable": false,
|
||||
"NextRun": "2020-01-01 00:00:00",
|
||||
"Command": "BattlePass",
|
||||
"ServerUpdate": "04:00"
|
||||
}
|
||||
}
|
||||
}
|
@ -168,6 +168,8 @@ class KeywordExtract:
|
||||
text_convert=dungeon_name)
|
||||
self.load_keywords(['传送', '追踪'])
|
||||
self.write_keywords(keyword_class='DungeonEntrance', output_file='./tasks/dungeon/keywords/dungeon_entrance.py')
|
||||
self.load_keywords(['奖励', '任务'])
|
||||
self.write_keywords(keyword_class='BattlePassTab', output_file='./tasks/battle_pass/keywords/tab.py')
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
|
@ -235,5 +235,28 @@
|
||||
"display": "hide"
|
||||
}
|
||||
}
|
||||
},
|
||||
"BattlePass": {
|
||||
"Scheduler": {
|
||||
"Enable": {
|
||||
"type": "checkbox",
|
||||
"value": false
|
||||
},
|
||||
"NextRun": {
|
||||
"type": "datetime",
|
||||
"value": "2020-01-01 00:00:00",
|
||||
"validate": "datetime"
|
||||
},
|
||||
"Command": {
|
||||
"type": "input",
|
||||
"value": "BattlePass",
|
||||
"display": "hide"
|
||||
},
|
||||
"ServerUpdate": {
|
||||
"type": "input",
|
||||
"value": "04:00",
|
||||
"display": "hide"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -12,7 +12,8 @@
|
||||
"page": "setting",
|
||||
"tasks": [
|
||||
"Dungeon",
|
||||
"DailyQuest"
|
||||
"DailyQuest",
|
||||
"BattlePass"
|
||||
]
|
||||
}
|
||||
}
|
@ -27,3 +27,5 @@ Daily:
|
||||
- Dungeon
|
||||
DailyQuest:
|
||||
- Scheduler
|
||||
BattlePass:
|
||||
- Scheduler
|
||||
|
@ -1,5 +1,3 @@
|
||||
from pywebio.io_ctrl import Output
|
||||
|
||||
import module.config.server as server
|
||||
|
||||
|
||||
@ -10,7 +8,7 @@ class ManualConfig:
|
||||
|
||||
SCHEDULER_PRIORITY = """
|
||||
Restart
|
||||
> Dungeon > DailyQuest
|
||||
> Dungeon > DailyQuest > BattlePass
|
||||
"""
|
||||
|
||||
"""
|
||||
|
@ -25,6 +25,10 @@
|
||||
"DailyQuest": {
|
||||
"name": "Daily Quest",
|
||||
"help": ""
|
||||
},
|
||||
"BattlePass": {
|
||||
"name": "Nameless Honor",
|
||||
"help": ""
|
||||
}
|
||||
},
|
||||
"Scheduler": {
|
||||
|
@ -25,6 +25,10 @@
|
||||
"DailyQuest": {
|
||||
"name": "Task.DailyQuest.name",
|
||||
"help": "Task.DailyQuest.help"
|
||||
},
|
||||
"BattlePass": {
|
||||
"name": "ナナシの勲功",
|
||||
"help": ""
|
||||
}
|
||||
},
|
||||
"Scheduler": {
|
||||
|
@ -25,6 +25,10 @@
|
||||
"DailyQuest": {
|
||||
"name": "每日任务",
|
||||
"help": ""
|
||||
},
|
||||
"BattlePass": {
|
||||
"name": "无名勋礼",
|
||||
"help": ""
|
||||
}
|
||||
},
|
||||
"Scheduler": {
|
||||
|
@ -25,6 +25,10 @@
|
||||
"DailyQuest": {
|
||||
"name": "每日任務",
|
||||
"help": ""
|
||||
},
|
||||
"BattlePass": {
|
||||
"name": "無名勳禮",
|
||||
"help": ""
|
||||
}
|
||||
},
|
||||
"Scheduler": {
|
||||
|
4
src.py
@ -30,6 +30,10 @@ class StarRailCopilot(AzurLaneAutoScript):
|
||||
from tasks.daily.daily_quest import DailyQuestUI
|
||||
DailyQuestUI(config=self.config, device=self.device).run()
|
||||
|
||||
def battle_pass(self):
|
||||
from tasks.battle_pass.battle_pass import BattlePassUI
|
||||
BattlePassUI(config=self.config, device=self.device).run()
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
src = StarRailCopilot('src')
|
||||
|
95
tasks/battle_pass/assets/assets_battle_pass.py
Normal file
@ -0,0 +1,95 @@
|
||||
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 ```
|
||||
|
||||
CLOSE_CHOOSE_GIFT = ButtonWrapper(
|
||||
name='CLOSE_CHOOSE_GIFT',
|
||||
share=Button(
|
||||
file='./assets/share/battle_pass/CLOSE_CHOOSE_GIFT.png',
|
||||
area=(387, 634, 412, 658),
|
||||
search=(367, 614, 432, 678),
|
||||
color=(104, 99, 86),
|
||||
button=(387, 634, 412, 658),
|
||||
),
|
||||
)
|
||||
EXP_CLAIM_ALL = ButtonWrapper(
|
||||
name='EXP_CLAIM_ALL',
|
||||
share=Button(
|
||||
file='./assets/share/battle_pass/EXP_CLAIM_ALL.png',
|
||||
area=(1016, 664, 1036, 686),
|
||||
search=(996, 644, 1056, 706),
|
||||
color=(118, 98, 58),
|
||||
button=(1016, 664, 1036, 686),
|
||||
),
|
||||
)
|
||||
MISSIONS_CHECK = ButtonWrapper(
|
||||
name='MISSIONS_CHECK',
|
||||
share=Button(
|
||||
file='./assets/share/battle_pass/MISSIONS_CHECK.png',
|
||||
area=(44, 210, 74, 230),
|
||||
search=(24, 190, 94, 250),
|
||||
color=(68, 69, 68),
|
||||
button=(44, 210, 74, 230),
|
||||
),
|
||||
)
|
||||
MISSIONS_CLICK = ButtonWrapper(
|
||||
name='MISSIONS_CLICK',
|
||||
share=Button(
|
||||
file='./assets/share/battle_pass/MISSIONS_CLICK.png',
|
||||
area=(44, 211, 74, 230),
|
||||
search=(24, 191, 94, 250),
|
||||
color=(145, 143, 139),
|
||||
button=(44, 211, 74, 230),
|
||||
),
|
||||
)
|
||||
MISSIONS_LOADED = ButtonWrapper(
|
||||
name='MISSIONS_LOADED',
|
||||
share=Button(
|
||||
file='./assets/share/battle_pass/MISSIONS_LOADED.png',
|
||||
area=(1163, 573, 1179, 589),
|
||||
search=(1143, 553, 1199, 609),
|
||||
color=(186, 183, 170),
|
||||
button=(1163, 573, 1179, 589),
|
||||
),
|
||||
)
|
||||
REWARDS_CHECK = ButtonWrapper(
|
||||
name='REWARDS_CHECK',
|
||||
share=Button(
|
||||
file='./assets/share/battle_pass/REWARDS_CHECK.png',
|
||||
area=(39, 119, 78, 140),
|
||||
search=(19, 99, 98, 160),
|
||||
color=(131, 133, 133),
|
||||
button=(39, 119, 78, 140),
|
||||
),
|
||||
)
|
||||
REWARDS_CLAIM_ALL = ButtonWrapper(
|
||||
name='REWARDS_CLAIM_ALL',
|
||||
cn=Button(
|
||||
file='./assets/cn/battle_pass/REWARDS_CLAIM_ALL.png',
|
||||
area=(827, 665, 907, 684),
|
||||
search=(807, 645, 927, 704),
|
||||
color=(172, 136, 69),
|
||||
button=(827, 665, 907, 684),
|
||||
),
|
||||
)
|
||||
REWARDS_CLICK = ButtonWrapper(
|
||||
name='REWARDS_CLICK',
|
||||
share=Button(
|
||||
file='./assets/share/battle_pass/REWARDS_CLICK.png',
|
||||
area=(44, 118, 73, 132),
|
||||
search=(24, 98, 93, 152),
|
||||
color=(119, 119, 114),
|
||||
button=(44, 118, 73, 132),
|
||||
),
|
||||
)
|
||||
REWARDS_LOADED = ButtonWrapper(
|
||||
name='REWARDS_LOADED',
|
||||
share=Button(
|
||||
file='./assets/share/battle_pass/REWARDS_LOADED.png',
|
||||
area=(173, 286, 248, 324),
|
||||
search=(153, 266, 268, 344),
|
||||
color=(96, 96, 94),
|
||||
button=(173, 286, 248, 324),
|
||||
),
|
||||
)
|
154
tasks/battle_pass/battle_pass.py
Normal file
@ -0,0 +1,154 @@
|
||||
import numpy as np
|
||||
|
||||
from module.base.timer import Timer
|
||||
from module.base.utils import get_color
|
||||
from module.logger.logger import logger
|
||||
from module.ui.switch import Switch
|
||||
from tasks.base.assets.assets_base_page import BATTLE_PASS_CHECK
|
||||
from tasks.base.assets.assets_base_popup import GET_REWARD
|
||||
from tasks.base.page import page_battle_pass
|
||||
from tasks.base.ui import UI
|
||||
from tasks.battle_pass.assets.assets_battle_pass import *
|
||||
from tasks.battle_pass.keywords import KEYWORD_BATTLE_PASS_TAB
|
||||
|
||||
SWITCH_BATTLE_PASS_TAB = Switch('BattlePassTab', is_selector=True)
|
||||
SWITCH_BATTLE_PASS_TAB.add_state(
|
||||
KEYWORD_BATTLE_PASS_TAB.Rewards,
|
||||
check_button=REWARDS_CHECK,
|
||||
click_button=REWARDS_CLICK
|
||||
)
|
||||
SWITCH_BATTLE_PASS_TAB.add_state(
|
||||
KEYWORD_BATTLE_PASS_TAB.Missions,
|
||||
check_button=MISSIONS_CHECK,
|
||||
click_button=MISSIONS_CLICK
|
||||
)
|
||||
|
||||
|
||||
class BattlePassUI(UI):
|
||||
def _battle_pass_wait_rewards_loaded(self, skip_first_screenshot=True):
|
||||
timeout = Timer(2, count=4).start()
|
||||
while 1:
|
||||
if skip_first_screenshot:
|
||||
skip_first_screenshot = False
|
||||
else:
|
||||
self.device.screenshot()
|
||||
|
||||
if timeout.reached():
|
||||
logger.warning('Wait rewards tab loaded timeout')
|
||||
break
|
||||
if self.appear(REWARDS_LOADED):
|
||||
logger.info('Rewards tab loaded')
|
||||
break
|
||||
|
||||
def _battle_pass_wait_missions_loaded(self, skip_first_screenshot=True):
|
||||
timeout = Timer(2, count=4).start()
|
||||
while 1:
|
||||
if skip_first_screenshot:
|
||||
skip_first_screenshot = False
|
||||
else:
|
||||
self.device.screenshot()
|
||||
|
||||
if timeout.reached():
|
||||
logger.warning('Wait missions tab loaded timeout')
|
||||
break
|
||||
color = get_color(self.device.image, MISSIONS_LOADED.area)
|
||||
if np.mean(color) > 128:
|
||||
logger.info('Missions tab loaded')
|
||||
break
|
||||
|
||||
def battle_pass_goto(self, state: KEYWORD_BATTLE_PASS_TAB):
|
||||
"""
|
||||
Args:
|
||||
state:
|
||||
|
||||
Examples:
|
||||
self = BattlePassUI('alas')
|
||||
self.device.screenshot()
|
||||
self.battle_pass_goto(KEYWORDS_DUNGEON_TAB.Missions)
|
||||
self.battle_pass_goto(KEYWORDS_DUNGEON_TAB.Rewards)
|
||||
"""
|
||||
logger.hr('Battle pass tab goto', level=2)
|
||||
self.ui_ensure(page_battle_pass)
|
||||
if SWITCH_BATTLE_PASS_TAB.set(state, main=self):
|
||||
logger.info(f'Tab goto {state}, wait until loaded')
|
||||
if state == KEYWORD_BATTLE_PASS_TAB.Missions:
|
||||
self._battle_pass_wait_missions_loaded()
|
||||
if state == KEYWORD_BATTLE_PASS_TAB.Rewards:
|
||||
self._battle_pass_wait_rewards_loaded()
|
||||
|
||||
def handle_choose_gifts(self, interval=5):
|
||||
"""
|
||||
Popup when you have purchase Nameless Glory
|
||||
|
||||
Args:
|
||||
interval:
|
||||
|
||||
Returns:
|
||||
If handled
|
||||
"""
|
||||
if self.appear_then_click(CLOSE_CHOOSE_GIFT, interval=interval):
|
||||
return True
|
||||
|
||||
return False
|
||||
|
||||
def _claim_exp(self, skip_first_screenshot=True):
|
||||
self.battle_pass_goto(KEYWORD_BATTLE_PASS_TAB.Missions)
|
||||
while 1:
|
||||
if skip_first_screenshot:
|
||||
skip_first_screenshot = False
|
||||
else:
|
||||
self.device.screenshot()
|
||||
|
||||
if not self.appear(EXP_CLAIM_ALL):
|
||||
break
|
||||
if self.appear_then_click(EXP_CLAIM_ALL):
|
||||
logger.info("All EXP claimed")
|
||||
continue
|
||||
|
||||
def _claim_rewards(self, skip_first_screenshot=True):
|
||||
self.battle_pass_goto(KEYWORD_BATTLE_PASS_TAB.Rewards)
|
||||
while 1:
|
||||
if skip_first_screenshot:
|
||||
skip_first_screenshot = False
|
||||
else:
|
||||
self.device.screenshot()
|
||||
|
||||
if self.appear(GET_REWARD) or self.appear(CLOSE_CHOOSE_GIFT):
|
||||
break
|
||||
if self.appear_then_click(REWARDS_CLAIM_ALL):
|
||||
continue
|
||||
|
||||
skip_first_screenshot = True
|
||||
while 1:
|
||||
if skip_first_screenshot:
|
||||
skip_first_screenshot = False
|
||||
else:
|
||||
self.device.screenshot()
|
||||
|
||||
if self.appear(BATTLE_PASS_CHECK):
|
||||
logger.info("Claiming rewards complete")
|
||||
break
|
||||
if self.handle_choose_gifts():
|
||||
logger.info("You have unclaimed gift to choose")
|
||||
continue
|
||||
if self.handle_reward():
|
||||
continue
|
||||
|
||||
def claim_battle_pass_rewards(self):
|
||||
"""
|
||||
Examples:
|
||||
self = BattlePassUI('alas')
|
||||
self.device.screenshot()
|
||||
self.claim_rewards()
|
||||
"""
|
||||
self._claim_exp()
|
||||
self._claim_rewards()
|
||||
return True
|
||||
|
||||
def run(self):
|
||||
for _ in range(5):
|
||||
claimed = self.claim_battle_pass_rewards()
|
||||
if claimed:
|
||||
break
|
||||
|
||||
self.config.task_delay(server_update=True)
|
2
tasks/battle_pass/keywords/__init__.py
Normal file
@ -0,0 +1,2 @@
|
||||
import tasks.battle_pass.keywords.tab as KEYWORD_BATTLE_PASS_TAB
|
||||
from tasks.battle_pass.keywords.classes import BattlePassTab
|
9
tasks/battle_pass/keywords/classes.py
Normal file
@ -0,0 +1,9 @@
|
||||
from dataclasses import dataclass
|
||||
from typing import ClassVar
|
||||
|
||||
from module.ocr.keyword import Keyword
|
||||
|
||||
|
||||
@dataclass(repr=False)
|
||||
class BattlePassTab(Keyword):
|
||||
instances: ClassVar = {}
|
21
tasks/battle_pass/keywords/tab.py
Normal file
@ -0,0 +1,21 @@
|
||||
from .classes import BattlePassTab
|
||||
|
||||
# This file was auto-generated, do not modify it manually. To generate:
|
||||
# ``` python -m dev_tools.keyword_extract ```
|
||||
|
||||
Rewards = BattlePassTab(
|
||||
id=1,
|
||||
name='Rewards',
|
||||
cn='奖励',
|
||||
cht='獎勵',
|
||||
en='Rewards',
|
||||
jp='報酬',
|
||||
)
|
||||
Missions = BattlePassTab(
|
||||
id=2,
|
||||
name='Missions',
|
||||
cn='任务',
|
||||
cht='任務',
|
||||
en='Missions',
|
||||
jp='クエスト',
|
||||
)
|