Add: daily_request_recognition; get_daily_rewards (#3)
* Add: daily_request_recognition; get_daily_rewards * Fix: typo * Fix: typo * Upd: delete eval; use one loop to handle 5 active point rewards; * Upd: change DAILY_QUEST_GOTO/REWARD pattern; update swipe private method name; extract keyword compare method * Upd: move warning to single page recognition * Upd: merge from main * Add: methods that load daily quests keywords from QuestData.json * Upd: avoid read TextMap twice * Upd: revert Keyword.find method * Add: preprocess of keyword extract; after_process of daily quest ocr * Upd: move assets to daily/reward * Upd: simplify ocr result replacement
BIN
assets/cn/daily/reward/DAILY_QUEST_FULL.png
Normal file
After Width: | Height: | Size: 10 KiB |
BIN
assets/share/daily/reward/ACTIVE_POINTS_1_CHECKED.png
Normal file
After Width: | Height: | Size: 8.7 KiB |
BIN
assets/share/daily/reward/ACTIVE_POINTS_1_LOCKED.png
Normal file
After Width: | Height: | Size: 7.3 KiB |
BIN
assets/share/daily/reward/ACTIVE_POINTS_1_UNLOCK.png
Normal file
After Width: | Height: | Size: 8.9 KiB |
BIN
assets/share/daily/reward/ACTIVE_POINTS_2_CHECKED.png
Normal file
After Width: | Height: | Size: 9.0 KiB |
BIN
assets/share/daily/reward/ACTIVE_POINTS_2_LOCKED.png
Normal file
After Width: | Height: | Size: 7.4 KiB |
BIN
assets/share/daily/reward/ACTIVE_POINTS_2_UNLOCK.png
Normal file
After Width: | Height: | Size: 8.9 KiB |
BIN
assets/share/daily/reward/ACTIVE_POINTS_3_CHECKED.png
Normal file
After Width: | Height: | Size: 9.0 KiB |
BIN
assets/share/daily/reward/ACTIVE_POINTS_3_LOCKED.png
Normal file
After Width: | Height: | Size: 7.3 KiB |
BIN
assets/share/daily/reward/ACTIVE_POINTS_3_UNLOCK.png
Normal file
After Width: | Height: | Size: 8.7 KiB |
BIN
assets/share/daily/reward/ACTIVE_POINTS_4_CHECKED.png
Normal file
After Width: | Height: | Size: 8.9 KiB |
BIN
assets/share/daily/reward/ACTIVE_POINTS_4_LOCKED.png
Normal file
After Width: | Height: | Size: 7.4 KiB |
BIN
assets/share/daily/reward/ACTIVE_POINTS_4_UNLOCK.png
Normal file
After Width: | Height: | Size: 8.9 KiB |
BIN
assets/share/daily/reward/ACTIVE_POINTS_5_CHECKED.png
Normal file
After Width: | Height: | Size: 8.9 KiB |
BIN
assets/share/daily/reward/ACTIVE_POINTS_5_LOCKED.png
Normal file
After Width: | Height: | Size: 7.3 KiB |
BIN
assets/share/daily/reward/ACTIVE_POINTS_5_UNLOCK.png
Normal file
After Width: | Height: | Size: 8.9 KiB |
BIN
assets/share/daily/reward/DAILY_QUEST_GOTO.png
Normal file
After Width: | Height: | Size: 6.0 KiB |
BIN
assets/share/daily/reward/DAILY_QUEST_LEFT_START.png
Normal file
After Width: | Height: | Size: 11 KiB |
BIN
assets/share/daily/reward/DAILY_QUEST_REWARD.png
Normal file
After Width: | Height: | Size: 6.1 KiB |
BIN
assets/share/daily/reward/DAILY_QUEST_RIGHT_END.png
Normal file
After Width: | Height: | Size: 9.9 KiB |
BIN
assets/share/daily/reward/OCR_DAILY_QUEST.png
Normal file
After Width: | Height: | Size: 80 KiB |
@ -1,4 +1,5 @@
|
|||||||
import os
|
import os
|
||||||
|
import re
|
||||||
import typing as t
|
import typing as t
|
||||||
from functools import cached_property
|
from functools import cached_property
|
||||||
|
|
||||||
@ -54,6 +55,19 @@ class TextMap:
|
|||||||
return 0, ''
|
return 0, ''
|
||||||
|
|
||||||
|
|
||||||
|
def replace_templates(text: str) -> str:
|
||||||
|
"""
|
||||||
|
Replace templates in data to make sure it equals to what is shown in game
|
||||||
|
|
||||||
|
Examples:
|
||||||
|
replace_templates("Complete Echo of War #4 time(s)")
|
||||||
|
== "Complete Echo of War 1 time(s)"
|
||||||
|
"""
|
||||||
|
text = re.sub(r'#4', '1', text)
|
||||||
|
text = re.sub(r'</?\w+>', '', text)
|
||||||
|
return text
|
||||||
|
|
||||||
|
|
||||||
class KeywordExtract:
|
class KeywordExtract:
|
||||||
def __init__(self):
|
def __init__(self):
|
||||||
self.text_map: dict[str, TextMap] = {lang: TextMap(lang) for lang in UI_LANGUAGES}
|
self.text_map: dict[str, TextMap] = {lang: TextMap(lang) for lang in UI_LANGUAGES}
|
||||||
@ -90,10 +104,17 @@ class KeywordExtract:
|
|||||||
with gen.Object(key=en, object_class=keyword_class):
|
with gen.Object(key=en, object_class=keyword_class):
|
||||||
gen.ObjectAttr(key='id', value=index + 1)
|
gen.ObjectAttr(key='id', value=index + 1)
|
||||||
for lang in UI_LANGUAGES:
|
for lang in UI_LANGUAGES:
|
||||||
gen.ObjectAttr(key=lang, value=self.find_keyword(keyword, lang=lang)[1])
|
gen.ObjectAttr(key=lang, value=replace_templates(self.find_keyword(keyword, lang=lang)[1]))
|
||||||
|
|
||||||
gen.write(output_file)
|
gen.write(output_file)
|
||||||
|
|
||||||
|
def load_daily_quests_keywords(self, lang='cn'):
|
||||||
|
daily_quest = read_file(os.path.join(TextMap.DATA_FOLDER, 'ExcelOutput', 'DailyQuest.json'))
|
||||||
|
quest_data = read_file(os.path.join(TextMap.DATA_FOLDER, 'ExcelOutput', 'QuestData.json'))
|
||||||
|
quests_hash = [quest_data[quest_id]["QuestTitle"]["Hash"] for quest_id in daily_quest]
|
||||||
|
quest_keywords = [self.text_map[lang].find(quest_hash)[1] for quest_hash in quests_hash]
|
||||||
|
self.load_keywords(quest_keywords, lang)
|
||||||
|
|
||||||
|
|
||||||
def generate():
|
def generate():
|
||||||
ex = KeywordExtract()
|
ex = KeywordExtract()
|
||||||
@ -101,6 +122,8 @@ def generate():
|
|||||||
ex.write_keywords(keyword_class='DungeonNav', output_file='./tasks/dungeon/keywords/nav.py')
|
ex.write_keywords(keyword_class='DungeonNav', output_file='./tasks/dungeon/keywords/nav.py')
|
||||||
ex.load_keywords(['行动摘要', '生存索引', '每日实训'])
|
ex.load_keywords(['行动摘要', '生存索引', '每日实训'])
|
||||||
ex.write_keywords(keyword_class='DungeonTab', output_file='./tasks/dungeon/keywords/tab.py')
|
ex.write_keywords(keyword_class='DungeonTab', output_file='./tasks/dungeon/keywords/tab.py')
|
||||||
|
ex.load_daily_quests_keywords()
|
||||||
|
ex.write_keywords(keyword_class='DailyQuest', output_file='./tasks/daily/keywords/daily_quest.py')
|
||||||
|
|
||||||
|
|
||||||
if __name__ == '__main__':
|
if __name__ == '__main__':
|
||||||
|
@ -6,7 +6,7 @@ from typing import ClassVar
|
|||||||
from module.exception import ScriptError
|
from module.exception import ScriptError
|
||||||
import module.config.server as server
|
import module.config.server as server
|
||||||
|
|
||||||
REGEX_PUNCTUATION = re.compile(r'[ ,.\'",。\-—/\\\n\t()()]')
|
REGEX_PUNCTUATION = re.compile(r'[ ,.\'",。\-—/\\\n\t()()「」『』【】]')
|
||||||
|
|
||||||
|
|
||||||
def parse_name(n):
|
def parse_name(n):
|
||||||
@ -15,8 +15,9 @@ def parse_name(n):
|
|||||||
|
|
||||||
|
|
||||||
def text_to_variable(text):
|
def text_to_variable(text):
|
||||||
text = re.sub('[ \-]', '_', text)
|
text = re.sub(r'[ \-]', '_', text)
|
||||||
text = re.sub('[()]', '', text)
|
text = re.sub(r'[(),#]|</?\w+>|\'s', '', text)
|
||||||
|
text = re.sub(r'[#_]?\d+(_times?)?', '', text)
|
||||||
return text
|
return text
|
||||||
|
|
||||||
|
|
||||||
|
215
tasks/daily/assets/assets_daily_reward.py
Normal file
@ -0,0 +1,215 @@
|
|||||||
|
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 ```
|
||||||
|
|
||||||
|
ACTIVE_POINTS_1_CHECKED = ButtonWrapper(
|
||||||
|
name='ACTIVE_POINTS_1_CHECKED',
|
||||||
|
share=Button(
|
||||||
|
file='./assets/share/daily/reward/ACTIVE_POINTS_1_CHECKED.png',
|
||||||
|
area=(377, 139, 424, 207),
|
||||||
|
search=(357, 119, 444, 227),
|
||||||
|
color=(223, 205, 185),
|
||||||
|
button=(377, 139, 424, 207),
|
||||||
|
),
|
||||||
|
)
|
||||||
|
ACTIVE_POINTS_1_LOCKED = ButtonWrapper(
|
||||||
|
name='ACTIVE_POINTS_1_LOCKED',
|
||||||
|
share=Button(
|
||||||
|
file='./assets/share/daily/reward/ACTIVE_POINTS_1_LOCKED.png',
|
||||||
|
area=(378, 141, 423, 185),
|
||||||
|
search=(358, 121, 443, 205),
|
||||||
|
color=(222, 222, 222),
|
||||||
|
button=(378, 141, 423, 185),
|
||||||
|
),
|
||||||
|
)
|
||||||
|
ACTIVE_POINTS_1_UNLOCK = ButtonWrapper(
|
||||||
|
name='ACTIVE_POINTS_1_UNLOCK',
|
||||||
|
share=Button(
|
||||||
|
file='./assets/share/daily/reward/ACTIVE_POINTS_1_UNLOCK.png',
|
||||||
|
area=(377, 141, 424, 185),
|
||||||
|
search=(357, 121, 444, 205),
|
||||||
|
color=(233, 178, 98),
|
||||||
|
button=(377, 141, 424, 185),
|
||||||
|
),
|
||||||
|
)
|
||||||
|
ACTIVE_POINTS_2_CHECKED = ButtonWrapper(
|
||||||
|
name='ACTIVE_POINTS_2_CHECKED',
|
||||||
|
share=Button(
|
||||||
|
file='./assets/share/daily/reward/ACTIVE_POINTS_2_CHECKED.png',
|
||||||
|
area=(560, 141, 606, 205),
|
||||||
|
search=(540, 121, 626, 225),
|
||||||
|
color=(221, 202, 180),
|
||||||
|
button=(560, 141, 606, 205),
|
||||||
|
),
|
||||||
|
)
|
||||||
|
ACTIVE_POINTS_2_LOCKED = ButtonWrapper(
|
||||||
|
name='ACTIVE_POINTS_2_LOCKED',
|
||||||
|
share=Button(
|
||||||
|
file='./assets/share/daily/reward/ACTIVE_POINTS_2_LOCKED.png',
|
||||||
|
area=(561, 141, 606, 185),
|
||||||
|
search=(541, 121, 626, 205),
|
||||||
|
color=(222, 222, 222),
|
||||||
|
button=(561, 141, 606, 185),
|
||||||
|
),
|
||||||
|
)
|
||||||
|
ACTIVE_POINTS_2_UNLOCK = ButtonWrapper(
|
||||||
|
name='ACTIVE_POINTS_2_UNLOCK',
|
||||||
|
share=Button(
|
||||||
|
file='./assets/share/daily/reward/ACTIVE_POINTS_2_UNLOCK.png',
|
||||||
|
area=(561, 141, 606, 185),
|
||||||
|
search=(541, 121, 626, 205),
|
||||||
|
color=(244, 192, 99),
|
||||||
|
button=(561, 141, 606, 185),
|
||||||
|
),
|
||||||
|
)
|
||||||
|
ACTIVE_POINTS_3_CHECKED = ButtonWrapper(
|
||||||
|
name='ACTIVE_POINTS_3_CHECKED',
|
||||||
|
share=Button(
|
||||||
|
file='./assets/share/daily/reward/ACTIVE_POINTS_3_CHECKED.png',
|
||||||
|
area=(743, 141, 788, 205),
|
||||||
|
search=(723, 121, 808, 225),
|
||||||
|
color=(221, 201, 179),
|
||||||
|
button=(743, 141, 788, 205),
|
||||||
|
),
|
||||||
|
)
|
||||||
|
ACTIVE_POINTS_3_LOCKED = ButtonWrapper(
|
||||||
|
name='ACTIVE_POINTS_3_LOCKED',
|
||||||
|
share=Button(
|
||||||
|
file='./assets/share/daily/reward/ACTIVE_POINTS_3_LOCKED.png',
|
||||||
|
area=(743, 141, 788, 185),
|
||||||
|
search=(723, 121, 808, 205),
|
||||||
|
color=(222, 222, 222),
|
||||||
|
button=(743, 141, 788, 185),
|
||||||
|
),
|
||||||
|
)
|
||||||
|
ACTIVE_POINTS_3_UNLOCK = ButtonWrapper(
|
||||||
|
name='ACTIVE_POINTS_3_UNLOCK',
|
||||||
|
share=Button(
|
||||||
|
file='./assets/share/daily/reward/ACTIVE_POINTS_3_UNLOCK.png',
|
||||||
|
area=(744, 141, 788, 185),
|
||||||
|
search=(724, 121, 808, 205),
|
||||||
|
color=(231, 176, 94),
|
||||||
|
button=(744, 141, 788, 185),
|
||||||
|
),
|
||||||
|
)
|
||||||
|
ACTIVE_POINTS_4_CHECKED = ButtonWrapper(
|
||||||
|
name='ACTIVE_POINTS_4_CHECKED',
|
||||||
|
share=Button(
|
||||||
|
file='./assets/share/daily/reward/ACTIVE_POINTS_4_CHECKED.png',
|
||||||
|
area=(925, 141, 970, 205),
|
||||||
|
search=(905, 121, 990, 225),
|
||||||
|
color=(221, 201, 179),
|
||||||
|
button=(925, 141, 970, 205),
|
||||||
|
),
|
||||||
|
)
|
||||||
|
ACTIVE_POINTS_4_LOCKED = ButtonWrapper(
|
||||||
|
name='ACTIVE_POINTS_4_LOCKED',
|
||||||
|
share=Button(
|
||||||
|
file='./assets/share/daily/reward/ACTIVE_POINTS_4_LOCKED.png',
|
||||||
|
area=(926, 141, 971, 185),
|
||||||
|
search=(906, 121, 991, 205),
|
||||||
|
color=(222, 222, 222),
|
||||||
|
button=(926, 141, 971, 185),
|
||||||
|
),
|
||||||
|
)
|
||||||
|
ACTIVE_POINTS_4_UNLOCK = ButtonWrapper(
|
||||||
|
name='ACTIVE_POINTS_4_UNLOCK',
|
||||||
|
share=Button(
|
||||||
|
file='./assets/share/daily/reward/ACTIVE_POINTS_4_UNLOCK.png',
|
||||||
|
area=(926, 141, 971, 185),
|
||||||
|
search=(906, 121, 991, 205),
|
||||||
|
color=(237, 182, 97),
|
||||||
|
button=(926, 141, 971, 185),
|
||||||
|
),
|
||||||
|
)
|
||||||
|
ACTIVE_POINTS_5_CHECKED = ButtonWrapper(
|
||||||
|
name='ACTIVE_POINTS_5_CHECKED',
|
||||||
|
share=Button(
|
||||||
|
file='./assets/share/daily/reward/ACTIVE_POINTS_5_CHECKED.png',
|
||||||
|
area=(1108, 141, 1154, 205),
|
||||||
|
search=(1088, 121, 1174, 225),
|
||||||
|
color=(221, 201, 179),
|
||||||
|
button=(1108, 141, 1154, 205),
|
||||||
|
),
|
||||||
|
)
|
||||||
|
ACTIVE_POINTS_5_LOCKED = ButtonWrapper(
|
||||||
|
name='ACTIVE_POINTS_5_LOCKED',
|
||||||
|
share=Button(
|
||||||
|
file='./assets/share/daily/reward/ACTIVE_POINTS_5_LOCKED.png',
|
||||||
|
area=(1108, 141, 1153, 185),
|
||||||
|
search=(1088, 121, 1173, 205),
|
||||||
|
color=(222, 222, 222),
|
||||||
|
button=(1108, 141, 1153, 185),
|
||||||
|
),
|
||||||
|
)
|
||||||
|
ACTIVE_POINTS_5_UNLOCK = ButtonWrapper(
|
||||||
|
name='ACTIVE_POINTS_5_UNLOCK',
|
||||||
|
share=Button(
|
||||||
|
file='./assets/share/daily/reward/ACTIVE_POINTS_5_UNLOCK.png',
|
||||||
|
area=(1109, 141, 1154, 185),
|
||||||
|
search=(1089, 121, 1174, 205),
|
||||||
|
color=(237, 182, 96),
|
||||||
|
button=(1109, 141, 1154, 185),
|
||||||
|
),
|
||||||
|
)
|
||||||
|
DAILY_QUEST_FULL = ButtonWrapper(
|
||||||
|
name='DAILY_QUEST_FULL',
|
||||||
|
cn=Button(
|
||||||
|
file='./assets/cn/daily/reward/DAILY_QUEST_FULL.png',
|
||||||
|
area=(159, 546, 298, 564),
|
||||||
|
search=(139, 526, 318, 584),
|
||||||
|
color=(128, 111, 80),
|
||||||
|
button=(159, 546, 298, 564),
|
||||||
|
),
|
||||||
|
)
|
||||||
|
DAILY_QUEST_GOTO = ButtonWrapper(
|
||||||
|
name='DAILY_QUEST_GOTO',
|
||||||
|
share=Button(
|
||||||
|
file='./assets/share/daily/reward/DAILY_QUEST_GOTO.png',
|
||||||
|
area=(170, 544, 188, 563),
|
||||||
|
search=(150, 524, 208, 583),
|
||||||
|
color=(157, 156, 156),
|
||||||
|
button=(170, 544, 188, 563),
|
||||||
|
),
|
||||||
|
)
|
||||||
|
DAILY_QUEST_LEFT_START = ButtonWrapper(
|
||||||
|
name='DAILY_QUEST_LEFT_START',
|
||||||
|
share=Button(
|
||||||
|
file='./assets/share/daily/reward/DAILY_QUEST_LEFT_START.png',
|
||||||
|
area=(1100, 187, 1135, 625),
|
||||||
|
search=(1080, 167, 1155, 645),
|
||||||
|
color=(214, 214, 213),
|
||||||
|
button=(1100, 187, 1135, 625),
|
||||||
|
),
|
||||||
|
)
|
||||||
|
DAILY_QUEST_REWARD = ButtonWrapper(
|
||||||
|
name='DAILY_QUEST_REWARD',
|
||||||
|
share=Button(
|
||||||
|
file='./assets/share/daily/reward/DAILY_QUEST_REWARD.png',
|
||||||
|
area=(168, 544, 188, 564),
|
||||||
|
search=(148, 524, 208, 584),
|
||||||
|
color=(103, 83, 44),
|
||||||
|
button=(168, 544, 188, 564),
|
||||||
|
),
|
||||||
|
)
|
||||||
|
DAILY_QUEST_RIGHT_END = ButtonWrapper(
|
||||||
|
name='DAILY_QUEST_RIGHT_END',
|
||||||
|
share=Button(
|
||||||
|
file='./assets/share/daily/reward/DAILY_QUEST_RIGHT_END.png',
|
||||||
|
area=(142, 207, 175, 669),
|
||||||
|
search=(122, 187, 195, 689),
|
||||||
|
color=(219, 219, 218),
|
||||||
|
button=(142, 207, 175, 669),
|
||||||
|
),
|
||||||
|
)
|
||||||
|
OCR_DAILY_QUEST = ButtonWrapper(
|
||||||
|
name='OCR_DAILY_QUEST',
|
||||||
|
share=Button(
|
||||||
|
file='./assets/share/daily/reward/OCR_DAILY_QUEST.png',
|
||||||
|
area=(119, 232, 1165, 595),
|
||||||
|
search=(99, 212, 1185, 615),
|
||||||
|
color=(212, 210, 206),
|
||||||
|
button=(119, 232, 1165, 595),
|
||||||
|
),
|
||||||
|
)
|
128
tasks/daily/daily_quest.py
Normal file
@ -0,0 +1,128 @@
|
|||||||
|
import numpy as np
|
||||||
|
|
||||||
|
from module.base.timer import Timer
|
||||||
|
from module.logger import *
|
||||||
|
from module.ocr.ocr import Ocr, OcrResultButton
|
||||||
|
from tasks.daily.assets.assets_daily_reward import *
|
||||||
|
from tasks.daily.keywords import DailyQuest
|
||||||
|
from tasks.dungeon.keywords import KEYWORDS_DUNGEON_TAB
|
||||||
|
from tasks.dungeon.ui import DungeonUI
|
||||||
|
|
||||||
|
|
||||||
|
class DailyQuestOcr(Ocr):
|
||||||
|
def __init__(self, button: ButtonWrapper, lang=None, name=None):
|
||||||
|
super().__init__(button, lang, name)
|
||||||
|
|
||||||
|
def after_process(self, result):
|
||||||
|
result = super().after_process(result)
|
||||||
|
if self.lang == 'ch':
|
||||||
|
result = result.replace("宇审", "宇宙")
|
||||||
|
result = result.replace("响J", "响」")
|
||||||
|
return result
|
||||||
|
|
||||||
|
|
||||||
|
class DailyQuestUI(DungeonUI):
|
||||||
|
def _ensure_position(self, direction: str, skip_first_screenshot=True):
|
||||||
|
interval = Timer(5)
|
||||||
|
if direction == 'left':
|
||||||
|
template = DAILY_QUEST_LEFT_START
|
||||||
|
elif direction == 'right':
|
||||||
|
template = DAILY_QUEST_RIGHT_END
|
||||||
|
else:
|
||||||
|
logger.warning(f'Unknown drag direction: {direction}')
|
||||||
|
return
|
||||||
|
while 1:
|
||||||
|
if skip_first_screenshot:
|
||||||
|
skip_first_screenshot = False
|
||||||
|
else:
|
||||||
|
self.device.screenshot()
|
||||||
|
|
||||||
|
if self.appear(template):
|
||||||
|
logger.info(f"Ensure position: {direction}")
|
||||||
|
break
|
||||||
|
if interval.reached():
|
||||||
|
self._daily_quests_swipe(direction)
|
||||||
|
interval.reset()
|
||||||
|
continue
|
||||||
|
|
||||||
|
def _daily_quests_swipe(self, direction: str):
|
||||||
|
vector = np.random.uniform(0.65, 0.85)
|
||||||
|
if direction == 'left':
|
||||||
|
swipe_vector = (vector * OCR_DAILY_QUEST.width, 0)
|
||||||
|
elif direction == 'right':
|
||||||
|
swipe_vector = (-vector * OCR_DAILY_QUEST.width, 0)
|
||||||
|
else:
|
||||||
|
logger.warning(f'Unknown drag direction: {direction}')
|
||||||
|
return
|
||||||
|
self.device.swipe_vector(swipe_vector, box=OCR_DAILY_QUEST.button,
|
||||||
|
random_range=(-10, -10, 10, 10), name='DAILY_QUEST_DRAG')
|
||||||
|
|
||||||
|
def _ocr_single_page(self) -> list[OcrResultButton]:
|
||||||
|
ocr = DailyQuestOcr(OCR_DAILY_QUEST)
|
||||||
|
ocr.merge_thres_y = 20
|
||||||
|
results = ocr.matched_ocr(self.device.image, DailyQuest)
|
||||||
|
if len(results) < 4:
|
||||||
|
logger.warning(f"Recognition failed at {4 - len(results)} quests on one page")
|
||||||
|
return results
|
||||||
|
|
||||||
|
def daily_quests_recognition(self):
|
||||||
|
logger.info("Recognizing daily quests")
|
||||||
|
self.dungeon_tab_goto(KEYWORDS_DUNGEON_TAB.Daily_Training)
|
||||||
|
self._ensure_position('left')
|
||||||
|
results = self._ocr_single_page()
|
||||||
|
self._ensure_position('right')
|
||||||
|
results += [result for result in self._ocr_single_page() if result not in results]
|
||||||
|
logger.info("Daily quests recognition complete")
|
||||||
|
return results
|
||||||
|
|
||||||
|
def _get_quest_reward(self, skip_first_screenshot=True):
|
||||||
|
self._ensure_position('left')
|
||||||
|
while 1:
|
||||||
|
if skip_first_screenshot:
|
||||||
|
skip_first_screenshot = False
|
||||||
|
else:
|
||||||
|
self.device.screenshot()
|
||||||
|
|
||||||
|
if self.appear(DAILY_QUEST_FULL) or self.appear(DAILY_QUEST_GOTO):
|
||||||
|
break
|
||||||
|
if self.appear_then_click(DAILY_QUEST_REWARD):
|
||||||
|
continue
|
||||||
|
|
||||||
|
def _no_reward_to_get(self):
|
||||||
|
return (
|
||||||
|
(self.appear(ACTIVE_POINTS_1_LOCKED) or self.appear(ACTIVE_POINTS_1_CHECKED))
|
||||||
|
and (self.appear(ACTIVE_POINTS_2_LOCKED) or self.appear(ACTIVE_POINTS_2_CHECKED))
|
||||||
|
and (self.appear(ACTIVE_POINTS_3_LOCKED) or self.appear(ACTIVE_POINTS_3_CHECKED))
|
||||||
|
and (self.appear(ACTIVE_POINTS_4_LOCKED) or self.appear(ACTIVE_POINTS_4_CHECKED))
|
||||||
|
and (self.appear(ACTIVE_POINTS_5_LOCKED) or self.appear(ACTIVE_POINTS_5_CHECKED))
|
||||||
|
)
|
||||||
|
|
||||||
|
def _get_active_point_reward(self, skip_first_screenshot=True):
|
||||||
|
while 1:
|
||||||
|
if skip_first_screenshot:
|
||||||
|
skip_first_screenshot = False
|
||||||
|
else:
|
||||||
|
self.device.screenshot()
|
||||||
|
|
||||||
|
if self._no_reward_to_get():
|
||||||
|
break
|
||||||
|
if self.handle_reward():
|
||||||
|
continue
|
||||||
|
if self.appear_then_click(ACTIVE_POINTS_1_UNLOCK):
|
||||||
|
continue
|
||||||
|
if self.appear_then_click(ACTIVE_POINTS_2_UNLOCK):
|
||||||
|
continue
|
||||||
|
if self.appear_then_click(ACTIVE_POINTS_3_UNLOCK):
|
||||||
|
continue
|
||||||
|
if self.appear_then_click(ACTIVE_POINTS_4_UNLOCK):
|
||||||
|
continue
|
||||||
|
if self.appear_then_click(ACTIVE_POINTS_5_UNLOCK):
|
||||||
|
continue
|
||||||
|
|
||||||
|
def get_daily_rewards(self):
|
||||||
|
self.dungeon_tab_goto(KEYWORDS_DUNGEON_TAB.Daily_Training)
|
||||||
|
logger.info("Getting quest rewards")
|
||||||
|
self._get_quest_reward()
|
||||||
|
logger.info("Getting active point rewards")
|
||||||
|
self._get_active_point_reward()
|
||||||
|
logger.info("All daily reward got")
|
2
tasks/daily/keywords/__init__.py
Normal file
@ -0,0 +1,2 @@
|
|||||||
|
import tasks.daily.keywords.daily_quest as KEYWORDS_DAILY_QUEST
|
||||||
|
from tasks.daily.keywords.classes import DailyQuest
|
9
tasks/daily/keywords/classes.py
Normal file
@ -0,0 +1,9 @@
|
|||||||
|
from dataclasses import dataclass
|
||||||
|
from typing import ClassVar
|
||||||
|
|
||||||
|
from module.ocr.keyword import Keyword
|
||||||
|
|
||||||
|
|
||||||
|
@dataclass
|
||||||
|
class DailyQuest(Keyword):
|
||||||
|
instances: ClassVar = {}
|
180
tasks/daily/keywords/daily_quest.py
Normal file
@ -0,0 +1,180 @@
|
|||||||
|
from .classes import DailyQuest
|
||||||
|
|
||||||
|
# This file was auto-generated, do not modify it manually. To generate:
|
||||||
|
# ``` python -m dev_tools.keyword_extract ```
|
||||||
|
|
||||||
|
Complete_Daily_Mission = DailyQuest(
|
||||||
|
id=1,
|
||||||
|
cn='完成1个日常任务',
|
||||||
|
cht='完成1個每日任務',
|
||||||
|
en='Complete 1 Daily Mission',
|
||||||
|
jp='デイリークエストを1回クリアする',
|
||||||
|
)
|
||||||
|
Clear_Calyx_Golden = DailyQuest(
|
||||||
|
id=2,
|
||||||
|
cn='完成1次「拟造花萼(金)」',
|
||||||
|
cht='完成1次「擬造花萼(金)」',
|
||||||
|
en='Clear Calyx (Golden) 1 time(s)',
|
||||||
|
jp='「疑似花萼(金)」を1回クリアする',
|
||||||
|
)
|
||||||
|
Complete_Calyx_Crimson = DailyQuest(
|
||||||
|
id=3,
|
||||||
|
cn='完成1次「拟造花萼(赤)」',
|
||||||
|
cht='完成1次「擬造花萼(赤)」',
|
||||||
|
en='Complete Calyx (Crimson) 1 time',
|
||||||
|
jp='「疑似花萼(赤)」を1回クリアする',
|
||||||
|
)
|
||||||
|
Clear_Stagnant_Shadow = DailyQuest(
|
||||||
|
id=4,
|
||||||
|
cn='完成1次「凝滞虚影」',
|
||||||
|
cht='完成1次「凝滯虛影」',
|
||||||
|
en='Clear Stagnant Shadow 1 time(s)',
|
||||||
|
jp='「凝結虚影」を1回クリアする',
|
||||||
|
)
|
||||||
|
Clear_Cavern_of_Corrosion = DailyQuest(
|
||||||
|
id=5,
|
||||||
|
cn='完成1次「侵蚀隧洞」',
|
||||||
|
cht='完成1次「侵蝕隧洞」',
|
||||||
|
en='Clear Cavern of Corrosion 1 time(s)',
|
||||||
|
jp='「侵蝕トンネル」を1回クリアする',
|
||||||
|
)
|
||||||
|
In_a_single_battle_inflict_Weakness_Break_of_different_Types = DailyQuest(
|
||||||
|
id=6,
|
||||||
|
cn='单场战斗中,触发3种不同属性的弱点击破',
|
||||||
|
cht='單場戰鬥中,觸發3種不同屬性的弱點擊破',
|
||||||
|
en='In a single battle, inflict 3 Weakness Break of different Types',
|
||||||
|
jp='一度の戦闘で、異なる3種の属性の弱点撃破を発動する',
|
||||||
|
)
|
||||||
|
Inflict_Weakness_Break = DailyQuest(
|
||||||
|
id=7,
|
||||||
|
cn='累计触发弱点击破效果5次',
|
||||||
|
cht='累積觸發弱點擊破效果5次',
|
||||||
|
en='Inflict Weakness Break 5 times',
|
||||||
|
jp='累計で弱点撃破効果を5回発動する',
|
||||||
|
)
|
||||||
|
Defeat_a_total_of_enemies = DailyQuest(
|
||||||
|
id=8,
|
||||||
|
cn='累计消灭20个敌人',
|
||||||
|
cht='累積消滅20個敵人',
|
||||||
|
en='Defeat a total of 20 enemies',
|
||||||
|
jp='敵を累計で20体倒す',
|
||||||
|
)
|
||||||
|
Enter_combat_by_attacking_enemy_Weakness_and_win = DailyQuest(
|
||||||
|
id=9,
|
||||||
|
cn='利用弱点进入战斗并获胜3次',
|
||||||
|
cht='利用弱點進入戰鬥並獲勝3次',
|
||||||
|
en="Enter combat by attacking enemy's Weakness and win 3 times",
|
||||||
|
jp='弱点を攻撃して戦闘に入り、3回勝利する',
|
||||||
|
)
|
||||||
|
Use_Technique = DailyQuest(
|
||||||
|
id=10,
|
||||||
|
cn='累计施放2次秘技',
|
||||||
|
cht='累計施放2次秘技',
|
||||||
|
en='Use Technique 2 times',
|
||||||
|
jp='秘技を累計2回発動する',
|
||||||
|
)
|
||||||
|
Go_on_assignment = DailyQuest(
|
||||||
|
id=11,
|
||||||
|
cn='派遣1次委托',
|
||||||
|
cht='派遣1次委託',
|
||||||
|
en='Go on assignment 1 time',
|
||||||
|
jp='依頼に1回派遣する',
|
||||||
|
)
|
||||||
|
Take_photo = DailyQuest(
|
||||||
|
id=12,
|
||||||
|
cn='拍照1次',
|
||||||
|
cht='拍照1次',
|
||||||
|
en='Take 1 photo',
|
||||||
|
jp='1回撮影する',
|
||||||
|
)
|
||||||
|
Destroy_destructible_objects = DailyQuest(
|
||||||
|
id=13,
|
||||||
|
cn='累计击碎3个可破坏物',
|
||||||
|
cht='累計擊碎3個可破壞物',
|
||||||
|
en='Destroy 3 destructible objects',
|
||||||
|
jp='破壊できるオブジェクトを累計で3つ破壊する',
|
||||||
|
)
|
||||||
|
Complete_Forgotten_Hall = DailyQuest(
|
||||||
|
id=14,
|
||||||
|
cn='完成1次「忘却之庭」',
|
||||||
|
cht='完成1次「忘卻之庭」',
|
||||||
|
en='Complete Forgotten Hall 1 time',
|
||||||
|
jp='「忘却の庭」を1回クリアする',
|
||||||
|
)
|
||||||
|
Complete_Echo_of_War = DailyQuest(
|
||||||
|
id=15,
|
||||||
|
cn='完成1次「历战余响」',
|
||||||
|
cht='完成1次「歷戰餘響」',
|
||||||
|
en='Complete Echo of War 1 time(s)',
|
||||||
|
jp='「歴戦余韻」を1回クリアする',
|
||||||
|
)
|
||||||
|
Complete_stage_in_Simulated_Universe_Any_world = DailyQuest(
|
||||||
|
id=16,
|
||||||
|
cn='通关「模拟宇宙」(任意世界)的1个区域',
|
||||||
|
cht='完成「模擬宇宙」任意世界的1個區域',
|
||||||
|
en='Complete 1 stage in Simulated Universe (Any world)',
|
||||||
|
jp='「模擬宇宙」のエリアを1つクリアする(任意の世界)',
|
||||||
|
)
|
||||||
|
Obtain_victory_in_combat_with_support_characters = DailyQuest(
|
||||||
|
id=17,
|
||||||
|
cn='使用支援角色并获得战斗胜利1次',
|
||||||
|
cht='使用支援角色並獲得戰鬥勝利1次',
|
||||||
|
en='Obtain victory in combat with support characters 1 time',
|
||||||
|
jp='サポートキャラを使い、戦闘に1回勝利する',
|
||||||
|
)
|
||||||
|
Use_an_Ultimate_to_deal_the_final_blow = DailyQuest(
|
||||||
|
id=18,
|
||||||
|
cn='施放终结技造成制胜一击1次',
|
||||||
|
cht='施放終結技造成制勝一擊1次',
|
||||||
|
en='Use an Ultimate to deal the final blow 1 time',
|
||||||
|
jp='必殺技で最後の一撃を1回与える',
|
||||||
|
)
|
||||||
|
Level_up_any_character = DailyQuest(
|
||||||
|
id=19,
|
||||||
|
cn='将任意角色等级提升1次',
|
||||||
|
cht='將任意角色等級提升1次',
|
||||||
|
en='Level up any character 1 time',
|
||||||
|
jp='任意のキャラを1回レベルアップする',
|
||||||
|
)
|
||||||
|
Level_up_any_Light_Cone = DailyQuest(
|
||||||
|
id=20,
|
||||||
|
cn='将任意光锥等级提升1次',
|
||||||
|
cht='將任意光錐等級提升1次',
|
||||||
|
en='Level up any Light Cone 1 time',
|
||||||
|
jp='任意の光円錐を1回レベルアップする',
|
||||||
|
)
|
||||||
|
Level_up_any_Relic = DailyQuest(
|
||||||
|
id=21,
|
||||||
|
cn='将任意遗器等级提升1次',
|
||||||
|
cht='將任意遺器等級提升1次',
|
||||||
|
en='Level up any Relic 1 time',
|
||||||
|
jp='任意の遺物を1回レベルアップする',
|
||||||
|
)
|
||||||
|
Salvage_any_Relic = DailyQuest(
|
||||||
|
id=22,
|
||||||
|
cn='分解任意1件遗器',
|
||||||
|
cht='分解任意1件遺器',
|
||||||
|
en='Salvage any Relic',
|
||||||
|
jp='任意の遺物1つを分解する',
|
||||||
|
)
|
||||||
|
Synthesize_Consumable = DailyQuest(
|
||||||
|
id=23,
|
||||||
|
cn='合成1次消耗品',
|
||||||
|
cht='合成1次消耗品',
|
||||||
|
en='Synthesize Consumable 1 time',
|
||||||
|
jp='消耗品を1回合成する',
|
||||||
|
)
|
||||||
|
Synthesize_material = DailyQuest(
|
||||||
|
id=24,
|
||||||
|
cn='合成1次材料',
|
||||||
|
cht='合成1次素材',
|
||||||
|
en='Synthesize material 1 time',
|
||||||
|
jp='素材を1回合成する',
|
||||||
|
)
|
||||||
|
Use_Consumables = DailyQuest(
|
||||||
|
id=25,
|
||||||
|
cn='使用1件消耗品',
|
||||||
|
cht='使用1件消耗品',
|
||||||
|
en='Use Consumables 1 time',
|
||||||
|
jp='消耗品を1個使う',
|
||||||
|
)
|