mirror of
https://github.com/LmeSzinc/StarRailCopilot.git
synced 2024-11-16 06:25:24 +00:00
Upd: reformat code, extract RogueSelector
This commit is contained in:
parent
039eca2de9
commit
d6bdc286ca
BIN
assets/share/rogue/blessing/OCR_RESET_COST.png
Normal file
BIN
assets/share/rogue/blessing/OCR_RESET_COST.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 6.5 KiB |
BIN
assets/share/rogue/ui/CHECK_BLESSING.png
Normal file
BIN
assets/share/rogue/ui/CHECK_BLESSING.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 9.5 KiB |
BIN
assets/share/rogue/ui/COSMIC_FRAGMENT.png
Normal file
BIN
assets/share/rogue/ui/COSMIC_FRAGMENT.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 8.7 KiB |
BIN
assets/share/rogue/ui/OCR_COSMIC_FRAGMENT.png
Normal file
BIN
assets/share/rogue/ui/OCR_COSMIC_FRAGMENT.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 6.9 KiB |
@ -90,7 +90,9 @@
|
||||
"PresetResonanceFilter": "preset-1",
|
||||
"CustomResonanceFilter": "回响构音:均晶转变 > 回响构音:零维强化\n> 回响构音:第二次初恋 > 回响构音:体验的富翁\n> 回响构音:局外人 > 回响构音:怀疑的四重根\n> 回响构音:诸法无我 > 回响构音:诸行无常\n> 回响构音:射不主皮 > 回响构音:柘弓危矢\n> 回响构音:激变变星 > 回响构音:极端氦闪\n> 回响构音:末日狂欢 > 回响构音:树苗长高舞",
|
||||
"PresetBlessingFilter": "preset-1",
|
||||
"CustomBlessingFilter": "巡猎-3 > 《冠军晚餐·猫的摇篮》 > 丰饶众生,一法界心 > 毁灭-3 \n> 火堆外的夜 > 巡猎-2 > 毁灭-2 > 巡猎 > reset > random"
|
||||
"CustomBlessingFilter": "巡猎-3 > 《冠军晚餐·猫的摇篮》 > 丰饶众生,一法界心 > 毁灭-3 \n> 火堆外的夜 > 巡猎-2 > 毁灭-2 > 巡猎 > reset > random",
|
||||
"PresetCurioFilter": "preset-1",
|
||||
"CustomCurioFilter": "博士之袍 > 福灵胶 > 巡猎火漆 > 分裂金币 > 信仰债券 > random"
|
||||
}
|
||||
}
|
||||
}
|
@ -125,13 +125,11 @@ class MultiLangFilter(Filter):
|
||||
continue
|
||||
|
||||
obj_value = obj.__getattribute__(attr)
|
||||
if isinstance(obj_value, str):
|
||||
if obj_value.lower() != str(value):
|
||||
if isinstance(obj_value, (str, int)):
|
||||
if str(obj_value).lower() != str(value):
|
||||
return False
|
||||
if isinstance(obj_value, list):
|
||||
for candidate in obj_value:
|
||||
if str(candidate) == str(value):
|
||||
return True
|
||||
if value not in obj_value:
|
||||
return False
|
||||
|
||||
return True
|
||||
|
@ -492,6 +492,18 @@
|
||||
"CustomBlessingFilter": {
|
||||
"type": "textarea",
|
||||
"value": "巡猎-3 > 《冠军晚餐·猫的摇篮》 > 丰饶众生,一法界心 > 毁灭-3 \n> 火堆外的夜 > 巡猎-2 > 毁灭-2 > 巡猎 > reset > random"
|
||||
},
|
||||
"PresetCurioFilter": {
|
||||
"type": "select",
|
||||
"value": "preset-1",
|
||||
"option": [
|
||||
"preset-1",
|
||||
"custom"
|
||||
]
|
||||
},
|
||||
"CustomCurioFilter": {
|
||||
"type": "textarea",
|
||||
"value": "博士之袍 > 福灵胶 > 巡猎火漆 > 分裂金币 > 信仰债券 > random"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -130,3 +130,8 @@ Rogue:
|
||||
CustomBlessingFilter: |-
|
||||
巡猎-3 > 《冠军晚餐·猫的摇篮》 > 丰饶众生,一法界心 > 毁灭-3
|
||||
> 火堆外的夜 > 巡猎-2 > 毁灭-2 > 巡猎 > reset > random
|
||||
PresetCurioFilter:
|
||||
value: preset-1
|
||||
option: [ preset-1, custom ]
|
||||
CustomCurioFilter: |-
|
||||
博士之袍 > 福灵胶 > 分裂金币 > 信仰债券 > 换境桂冠 > 俱乐部券 > 碎星芳饵 > random
|
||||
|
@ -58,3 +58,5 @@ class GeneratedConfig:
|
||||
Rogue_CustomResonanceFilter = '回响构音:均晶转变 > 回响构音:零维强化\n> 回响构音:第二次初恋 > 回响构音:体验的富翁\n> 回响构音:局外人 > 回响构音:怀疑的四重根\n> 回响构音:诸法无我 > 回响构音:诸行无常\n> 回响构音:射不主皮 > 回响构音:柘弓危矢\n> 回响构音:激变变星 > 回响构音:极端氦闪\n> 回响构音:末日狂欢 > 回响构音:树苗长高舞'
|
||||
Rogue_PresetBlessingFilter = 'preset-1' # preset-1, custom
|
||||
Rogue_CustomBlessingFilter = '巡猎-3 > 《冠军晚餐·猫的摇篮》 > 丰饶众生,一法界心 > 毁灭-3 \n> 火堆外的夜 > 巡猎-2 > 毁灭-2 > 巡猎 > reset > random'
|
||||
Rogue_PresetCurioFilter = 'preset-1' # preset-1, custom
|
||||
Rogue_CustomCurioFilter = '博士之袍 > 福灵胶 > 巡猎火漆 > 分裂金币 > 信仰债券 > random'
|
||||
|
@ -402,6 +402,16 @@
|
||||
"CustomBlessingFilter": {
|
||||
"name": "Rogue.CustomBlessingFilter.name",
|
||||
"help": "Rogue.CustomBlessingFilter.help"
|
||||
},
|
||||
"PresetCurioFilter": {
|
||||
"name": "Rogue.PresetCurioFilter.name",
|
||||
"help": "Rogue.PresetCurioFilter.help",
|
||||
"preset-1": "preset-1",
|
||||
"custom": "custom"
|
||||
},
|
||||
"CustomCurioFilter": {
|
||||
"name": "Rogue.CustomCurioFilter.name",
|
||||
"help": "Rogue.CustomCurioFilter.help"
|
||||
}
|
||||
},
|
||||
"Gui": {
|
||||
|
@ -402,6 +402,16 @@
|
||||
"CustomBlessingFilter": {
|
||||
"name": "Rogue.CustomBlessingFilter.name",
|
||||
"help": "Rogue.CustomBlessingFilter.help"
|
||||
},
|
||||
"PresetCurioFilter": {
|
||||
"name": "Rogue.PresetCurioFilter.name",
|
||||
"help": "Rogue.PresetCurioFilter.help",
|
||||
"preset-1": "preset-1",
|
||||
"custom": "custom"
|
||||
},
|
||||
"CustomCurioFilter": {
|
||||
"name": "Rogue.CustomCurioFilter.name",
|
||||
"help": "Rogue.CustomCurioFilter.help"
|
||||
}
|
||||
},
|
||||
"Gui": {
|
||||
|
@ -402,6 +402,16 @@
|
||||
"CustomBlessingFilter": {
|
||||
"name": "自定义祝福过滤器",
|
||||
"help": ""
|
||||
},
|
||||
"PresetCurioFilter": {
|
||||
"name": "奇物过滤器",
|
||||
"help": "",
|
||||
"preset-1": "预设 1",
|
||||
"custom": "自定义"
|
||||
},
|
||||
"CustomCurioFilter": {
|
||||
"name": "自定义祝福过滤器",
|
||||
"help": ""
|
||||
}
|
||||
},
|
||||
"Gui": {
|
||||
|
@ -402,6 +402,16 @@
|
||||
"CustomBlessingFilter": {
|
||||
"name": "Rogue.CustomBlessingFilter.name",
|
||||
"help": "Rogue.CustomBlessingFilter.help"
|
||||
},
|
||||
"PresetCurioFilter": {
|
||||
"name": "Rogue.PresetCurioFilter.name",
|
||||
"help": "Rogue.PresetCurioFilter.help",
|
||||
"preset-1": "preset-1",
|
||||
"custom": "custom"
|
||||
},
|
||||
"CustomCurioFilter": {
|
||||
"name": "Rogue.CustomCurioFilter.name",
|
||||
"help": "Rogue.CustomCurioFilter.help"
|
||||
}
|
||||
},
|
||||
"Gui": {
|
||||
|
@ -43,6 +43,16 @@ BOTTOM_WHITE_BAR = ButtonWrapper(
|
||||
button=(166, 520, 1114, 542),
|
||||
),
|
||||
)
|
||||
OCR_RESET_COST = ButtonWrapper(
|
||||
name='OCR_RESET_COST',
|
||||
share=Button(
|
||||
file='./assets/share/rogue/blessing/OCR_RESET_COST.png',
|
||||
area=(689, 642, 715, 665),
|
||||
search=(669, 622, 735, 685),
|
||||
color=(39, 23, 25),
|
||||
button=(689, 642, 715, 665),
|
||||
),
|
||||
)
|
||||
OCR_RESET_COUNT = ButtonWrapper(
|
||||
name='OCR_RESET_COUNT',
|
||||
share=Button(
|
||||
|
@ -3,6 +3,16 @@ 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 ```
|
||||
|
||||
CHECK_BLESSING = ButtonWrapper(
|
||||
name='CHECK_BLESSING',
|
||||
share=Button(
|
||||
file='./assets/share/rogue/ui/CHECK_BLESSING.png',
|
||||
area=(946, 17, 986, 57),
|
||||
search=(926, 0, 1006, 77),
|
||||
color=(50, 48, 43),
|
||||
button=(946, 17, 986, 57),
|
||||
),
|
||||
)
|
||||
CONFIRM = ButtonWrapper(
|
||||
name='CONFIRM',
|
||||
share=Button(
|
||||
@ -13,6 +23,26 @@ CONFIRM = ButtonWrapper(
|
||||
button=(960, 629, 1233, 677),
|
||||
),
|
||||
)
|
||||
COSMIC_FRAGMENT = ButtonWrapper(
|
||||
name='COSMIC_FRAGMENT',
|
||||
share=Button(
|
||||
file='./assets/share/rogue/ui/COSMIC_FRAGMENT.png',
|
||||
area=(1146, 19, 1181, 55),
|
||||
search=(1126, 0, 1201, 75),
|
||||
color=(86, 68, 62),
|
||||
button=(1146, 19, 1181, 55),
|
||||
),
|
||||
)
|
||||
OCR_COSMIC_FRAGMENT = ButtonWrapper(
|
||||
name='OCR_COSMIC_FRAGMENT',
|
||||
share=Button(
|
||||
file='./assets/share/rogue/ui/OCR_COSMIC_FRAGMENT.png',
|
||||
area=(1183, 27, 1256, 46),
|
||||
search=(1163, 7, 1276, 66),
|
||||
color=(30, 32, 32),
|
||||
button=(1183, 27, 1256, 46),
|
||||
),
|
||||
)
|
||||
PAGE_CHOOSE_BUFF = ButtonWrapper(
|
||||
name='PAGE_CHOOSE_BUFF',
|
||||
share=Button(
|
||||
|
@ -6,12 +6,12 @@ from module.base.filter import MultiLangFilter
|
||||
from module.base.timer import Timer
|
||||
from module.base.utils import area_offset, get_color
|
||||
from module.logger import logger
|
||||
from module.ocr.keyword import Keyword
|
||||
from module.ocr.ocr import Ocr, OcrResultButton, DigitCounter
|
||||
from module.ocr.ocr import Ocr, OcrResultButton, DigitCounter, Digit
|
||||
from tasks.rogue.assets.assets_rogue_blessing import *
|
||||
from tasks.rogue.assets.assets_rogue_ui import CONFIRM
|
||||
from tasks.rogue.keywords import *
|
||||
from tasks.rogue.preset import *
|
||||
from tasks.rogue.selector import RogueSelector
|
||||
from tasks.rogue.ui import RogueUI
|
||||
from tasks.rogue.utils import get_regex_from_keyword_name, parse_name
|
||||
|
||||
@ -54,46 +54,61 @@ class RogueBuffOcr(Ocr):
|
||||
"柘弓危失": "柘弓危矢",
|
||||
"飞虹凿齿": "飞虹诛凿齿",
|
||||
"天培步危": "天棓步危",
|
||||
"云[摘销]": "云镝",
|
||||
"云[摘销]?逐步离": "云镝逐步离",
|
||||
"制桑": "制穹桑",
|
||||
"乌号基": "乌号綦",
|
||||
"追摩物": "追孽物",
|
||||
"特月": "狩月",
|
||||
"彤弓素增": "彤弓素矰",
|
||||
"彤弓素增?": "彤弓素矰",
|
||||
"白决射御": "白矢决射御",
|
||||
"苦表": "苦衷",
|
||||
"[沦沧]肌髓": "沦浃肌髓",
|
||||
"进发": "迸发",
|
||||
"永缩体": "永坍缩体",
|
||||
"完美体验:绒默": "完美体验:缄默",
|
||||
r"\w*灾$": "禳灾",
|
||||
"灭回归不等式": "湮灭回归不等式",
|
||||
r".*灾$": "禳灾",
|
||||
"虚安供品": "虚妄供品",
|
||||
"原初的苦$": "原初的苦衷",
|
||||
"厌离邪苦": "厌离邪秽苦",
|
||||
r".*繁.*": "葳蕤繁祉,延彼遐龄"
|
||||
}
|
||||
for pattern, replace in replace_pattern_dict.items():
|
||||
result = re.sub(pattern, replace, result)
|
||||
for pat, replace in replace_pattern_dict.items():
|
||||
result = re.sub(pat, replace, result)
|
||||
return result
|
||||
|
||||
|
||||
class RogueBlessingUI(RogueUI):
|
||||
class RogueBlessingSelector(RogueUI, RogueSelector):
|
||||
"""
|
||||
Usage:
|
||||
self = RogueBlessingSelector('alas')
|
||||
self.device.screenshot()
|
||||
self.recognize_and_select()
|
||||
"""
|
||||
|
||||
def get_blessing_count(self) -> int:
|
||||
"""
|
||||
Returns: The number of blessing
|
||||
"""
|
||||
if not self.image_color_count(BOTTOM_WHITE_BAR.area, color=(255, 255, 255), count=5000):
|
||||
return 0
|
||||
color = get_color(self.device.image, BOTTOM_WHITE_BAR.area)
|
||||
mean = np.mean(color)
|
||||
return int(mean // 60) # the magic number that maps blessing num with mean_color
|
||||
|
||||
def buffs_recognition(self):
|
||||
self.wait_until_blessing_loaded()
|
||||
def recognition(self):
|
||||
self.ocr_results = []
|
||||
self._wait_until_blessing_loaded()
|
||||
ocr = RogueBuffOcr(OCR_ROGUE_BUFF)
|
||||
results = ocr.matched_ocr(self.device.image, [RogueBlessing, RogueResonance])
|
||||
blessing_count = self.get_blessing_count()
|
||||
if blessing_count != len(results):
|
||||
logger.warning(f"The OCR result does not match the blessing count. "
|
||||
f"Expect {blessing_count}, but recognized {len(results)} only.")
|
||||
self.blessings = results
|
||||
self.ocr_results = results
|
||||
return results
|
||||
|
||||
def ui_select_blessing(self, blessing: OcrResultButton | None, skip_first_screenshot=True, enforce=False):
|
||||
def ui_select(self, target: OcrResultButton | None, skip_first_screenshot=True):
|
||||
"""
|
||||
Select buff once. Multiple calls needed if there's more than one time to choose
|
||||
It might occur that all listed blessings are not recognized
|
||||
@ -104,7 +119,7 @@ class RogueBlessingUI(RogueUI):
|
||||
"""
|
||||
There is a white border if a blessing is selected.
|
||||
"""
|
||||
top_border = area_offset(blessing.area, (0, -180))
|
||||
top_border = area_offset(target.area, (0, -180))
|
||||
return self.image_color_count(top_border, (255, 255, 255))
|
||||
|
||||
def is_select_blessing_complete():
|
||||
@ -117,7 +132,9 @@ class RogueBlessingUI(RogueUI):
|
||||
or (self.is_page_choose_blessing() and not is_blessing_selected()))
|
||||
|
||||
interval = Timer(1)
|
||||
if not blessing:
|
||||
enforce = False
|
||||
|
||||
if not target:
|
||||
enforce = True
|
||||
|
||||
# start -> selected
|
||||
@ -131,13 +148,13 @@ class RogueBlessingUI(RogueUI):
|
||||
if enforce:
|
||||
logger.info("Buff selected (enforce)")
|
||||
else:
|
||||
logger.info(f"Buff {blessing} selected")
|
||||
logger.info(f"Buff {target} selected")
|
||||
break
|
||||
if interval.reached():
|
||||
if enforce:
|
||||
self.device.click(BLESSING_ENFORCE)
|
||||
else:
|
||||
self.device.click(blessing)
|
||||
self.device.click(target)
|
||||
interval.reset()
|
||||
|
||||
skip_first_screenshot = True
|
||||
@ -154,11 +171,11 @@ class RogueBlessingUI(RogueUI):
|
||||
self.device.click(CONFIRM)
|
||||
interval.reset()
|
||||
|
||||
def get_reset_count(self):
|
||||
def _get_reset_count(self):
|
||||
current, _, _ = DigitCounter(OCR_RESET_COUNT).ocr_single_line(self.device.image)
|
||||
return current
|
||||
|
||||
def wait_until_blessing_loaded(self, timer=Timer(0.3, count=1), timeout=Timer(5, count=10)):
|
||||
def _wait_until_blessing_loaded(self, timer=Timer(0.3, count=1), timeout=Timer(5, count=10)):
|
||||
timer.reset()
|
||||
timeout.reset()
|
||||
previous_count = self.get_blessing_count()
|
||||
@ -182,8 +199,14 @@ class RogueBlessingUI(RogueUI):
|
||||
if not self.is_page_choose_blessing():
|
||||
return False
|
||||
|
||||
reset_count = self.get_reset_count()
|
||||
reset_count = self._get_reset_count()
|
||||
if not reset_count:
|
||||
logger.info("Does not have enough reset count")
|
||||
return False
|
||||
|
||||
reset_cost = Digit(OCR_RESET_COST).ocr_single_line(self.device.image)
|
||||
if reset_cost > self.cosmic_fragment:
|
||||
logger.info("Does not have enough cosmic fragment")
|
||||
return False
|
||||
|
||||
interval = Timer(1)
|
||||
@ -193,7 +216,7 @@ class RogueBlessingUI(RogueUI):
|
||||
else:
|
||||
self.device.screenshot()
|
||||
|
||||
new_count = self.get_reset_count()
|
||||
new_count = self._get_reset_count()
|
||||
|
||||
if reset_count - new_count == 1:
|
||||
logger.info("Reset once")
|
||||
@ -203,19 +226,9 @@ class RogueBlessingUI(RogueUI):
|
||||
interval.reset()
|
||||
return True
|
||||
|
||||
|
||||
class RogueBlessingSelector(RogueBlessingUI):
|
||||
"""
|
||||
Usage:
|
||||
self = RogueBlessingSelector('alas')
|
||||
self.device.screenshot()
|
||||
self.buff_recognition()
|
||||
self.select_blessing(self.)
|
||||
"""
|
||||
|
||||
def load_filter(self) -> MultiLangFilter:
|
||||
def load_filter(self):
|
||||
filter_ = None
|
||||
keyword = self.blessings[0].matched_keyword
|
||||
keyword = self.ocr_results[0].matched_keyword
|
||||
if isinstance(keyword, RogueBlessing):
|
||||
filter_ = BLESSING_FILTER
|
||||
if self.config.Rogue_PresetBlessingFilter == 'preset-1':
|
||||
@ -223,61 +236,25 @@ class RogueBlessingSelector(RogueBlessingUI):
|
||||
if self.config.Rogue_PresetBlessingFilter == 'custom':
|
||||
filter_.load(parse_name(self.config.Rogue_CustomBlessingFilter))
|
||||
if isinstance(keyword, RogueResonance):
|
||||
if len(self.blessings) == 1:
|
||||
return filter_
|
||||
filter_ = RESONANCE_FILTER
|
||||
if self.config.Rogue_PresetResonanceFilter == 'preset-1':
|
||||
RESONANCE_FILTER.load(parse_name(RESONANCE_PRESET_1))
|
||||
if self.config.Rogue_PresetResonanceFilter == 'custom':
|
||||
RESONANCE_FILTER.load(parse_name(self.config.Rogue_CustomResonanceFilter))
|
||||
return filter_
|
||||
self.filter_ = filter_
|
||||
|
||||
def apply_filter(self):
|
||||
def match_ocr_result(matched_keyword: Keyword):
|
||||
for blessing in self.blessings:
|
||||
if blessing.matched_keyword == matched_keyword:
|
||||
return blessing
|
||||
return None
|
||||
|
||||
if not self.blessings:
|
||||
return []
|
||||
|
||||
filter_ = self.load_filter()
|
||||
if not filter_:
|
||||
return self.blessings
|
||||
blessing_keywords = [blessing.matched_keyword for blessing in self.blessings]
|
||||
priority = filter_.apply(blessing_keywords)
|
||||
priority = [option if isinstance(option, str) else match_ocr_result(option) for option in priority]
|
||||
return priority
|
||||
|
||||
def select_blessing(self, priority: list):
|
||||
if not self.blessings:
|
||||
logger.info('No blessing recognized, randomly choose one')
|
||||
self.ui_select_blessing(None, enforce=True)
|
||||
return
|
||||
|
||||
if not len(priority):
|
||||
logger.info('No blessing project satisfies current filter, randomly choose one')
|
||||
choose = np.random.choice(self.blessings)
|
||||
self.ui_select_blessing(choose)
|
||||
return
|
||||
|
||||
for option in priority:
|
||||
# preset
|
||||
def try_select(self, option: OcrResultButton | str):
|
||||
if isinstance(option, str):
|
||||
if option.lower() == 'reset':
|
||||
if self.reset_blessing_list():
|
||||
self.wait_until_blessing_loaded()
|
||||
self.buffs_recognition()
|
||||
self.select_blessing(self.apply_filter())
|
||||
return
|
||||
else:
|
||||
continue
|
||||
self.recognize_and_select()
|
||||
return True
|
||||
if option.lower() == 'random':
|
||||
choose = np.random.choice(self.blessings)
|
||||
self.ui_select_blessing(choose)
|
||||
return
|
||||
choose = np.random.choice(self.ocr_results)
|
||||
self.ui_select(choose)
|
||||
return True
|
||||
|
||||
if isinstance(option, OcrResultButton):
|
||||
self.ui_select_blessing(option)
|
||||
return
|
||||
self.ui_select(option)
|
||||
return True
|
||||
return False
|
||||
|
@ -2,6 +2,7 @@ import re
|
||||
|
||||
import numpy as np
|
||||
|
||||
from module.base.filter import MultiLangFilter
|
||||
from module.base.timer import Timer
|
||||
from module.base.utils import get_color
|
||||
from module.logger import logger
|
||||
@ -9,7 +10,18 @@ from module.ocr.ocr import Ocr, OcrResultButton
|
||||
from tasks.rogue.assets.assets_rogue_curio import *
|
||||
from tasks.rogue.assets.assets_rogue_ui import CONFIRM
|
||||
from tasks.rogue.keywords import RogueCurio
|
||||
from tasks.rogue.preset import CURIO_PRESET_1
|
||||
from tasks.rogue.selector import RogueSelector
|
||||
from tasks.rogue.ui import RogueUI
|
||||
from tasks.rogue.utils import get_regex_from_keyword_name, parse_name
|
||||
|
||||
CURIO_FILTER_ATTR = tuple()
|
||||
CURIO_ATTR_NAME = 'curio_name'
|
||||
pattern = get_regex_from_keyword_name(RogueCurio, CURIO_ATTR_NAME)
|
||||
CURIO_FILTER_ATTR += (CURIO_ATTR_NAME,)
|
||||
CURIO_FILTER_PRESET = ('random',)
|
||||
FILTER_REGEX = re.compile(pattern)
|
||||
CURIO_FILTER = MultiLangFilter(FILTER_REGEX, CURIO_FILTER_ATTR, CURIO_FILTER_PRESET)
|
||||
|
||||
|
||||
class RogueCurioOcr(Ocr):
|
||||
@ -17,27 +29,28 @@ class RogueCurioOcr(Ocr):
|
||||
result = super().after_process(result)
|
||||
if self.lang == 'ch':
|
||||
replace_pattern_dict = {
|
||||
"降维般子": "降维骰子"
|
||||
"般": "骰",
|
||||
}
|
||||
for pattern, replace in replace_pattern_dict.items():
|
||||
result = re.sub(pattern, replace, result)
|
||||
return result
|
||||
|
||||
|
||||
class RogueCurioUI(RogueUI):
|
||||
def curio_recognition(self):
|
||||
class RogueCurioSelector(RogueUI, RogueSelector):
|
||||
def recognition(self):
|
||||
self.ocr_results = []
|
||||
ocr = RogueCurioOcr(OCR_ROGUE_CURIO)
|
||||
results = ocr.matched_ocr(self.device.image, RogueCurio)
|
||||
expect_num = 3
|
||||
if len(results) != expect_num:
|
||||
logger.warning(f"The OCR result does not match the curio count. "
|
||||
f"Expect {expect_num}, but recognized {len(results)} only.")
|
||||
self.ocr_curios = results
|
||||
self.ocr_results = results
|
||||
return results
|
||||
|
||||
def ui_select_curio(self, curio: OcrResultButton | None, skip_first_screenshot=True, enforce=True):
|
||||
def ui_select(self, target: OcrResultButton | None, skip_first_screenshot=True):
|
||||
def is_curio_selected():
|
||||
return np.mean(get_color(self.device.image, tuple(curio.area))) > 70
|
||||
return np.mean(get_color(self.device.image, tuple(target.area))) > 70 # shiny background
|
||||
|
||||
def is_select_curio_complete():
|
||||
"""
|
||||
@ -45,6 +58,9 @@ class RogueCurioUI(RogueUI):
|
||||
"""
|
||||
return self.is_in_main()
|
||||
|
||||
enforce = False
|
||||
if not target:
|
||||
enforce = True
|
||||
interval = Timer(1)
|
||||
# start -> selected
|
||||
while 1:
|
||||
@ -57,13 +73,13 @@ class RogueCurioUI(RogueUI):
|
||||
if enforce:
|
||||
logger.info("Curio selected (enforce)")
|
||||
else:
|
||||
logger.info(f"Curio {curio} selected")
|
||||
logger.info(f"Curio {target} selected")
|
||||
break
|
||||
if interval.reached():
|
||||
if enforce:
|
||||
self.device.click(CURIO_ENFORCE)
|
||||
else:
|
||||
self.device.click(curio)
|
||||
self.device.click(target)
|
||||
interval.reset()
|
||||
|
||||
skip_first_screenshot = True
|
||||
@ -79,3 +95,21 @@ class RogueCurioUI(RogueUI):
|
||||
if interval.reached():
|
||||
self.device.click(CONFIRM)
|
||||
interval.reset()
|
||||
|
||||
def try_select(self, option: OcrResultButton | str):
|
||||
if option == 'random':
|
||||
target = np.random.choice(self.ocr_results)
|
||||
self.ui_select(target)
|
||||
return True
|
||||
if isinstance(option, OcrResultButton):
|
||||
self.ui_select(option)
|
||||
return True
|
||||
return False
|
||||
|
||||
def load_filter(self):
|
||||
filter_ = CURIO_FILTER
|
||||
if self.config.Rogue_PresetCurioFilter == 'preset-1':
|
||||
filter_.load(parse_name(CURIO_PRESET_1))
|
||||
if self.config.Rogue_PresetCurioFilter == 'custom':
|
||||
filter_.load(parse_name(self.config.Rogue_CustomCurioFilter))
|
||||
self.filter_ = filter_
|
||||
|
@ -47,3 +47,8 @@ class RogueResonance(Keyword):
|
||||
@dataclass(repr=False)
|
||||
class RogueCurio(Keyword):
|
||||
instances: ClassVar = {}
|
||||
|
||||
@property
|
||||
def curio_name(self):
|
||||
return [self.__getattribute__(f"{server}_parsed")
|
||||
for server in UI_LANGUAGES if hasattr(self, f"{server}_parsed")]
|
||||
|
@ -7,3 +7,4 @@ RESONANCE_PRESET_1 = ("回响构音:均晶转变 > 回响构音:零维强化
|
||||
"> 回响构音:射不主皮 > 回响构音:柘弓危矢"
|
||||
"> 回响构音:激变变星 > 回响构音:极端氦闪"
|
||||
"> 回响构音:末日狂欢 > 回响构音:树苗长高舞")
|
||||
CURIO_PRESET_1 = "博士之袍 > 福灵胶 > 分裂金币 > 信仰债券 > 换境桂冠 > 俱乐部券 > 碎星芳饵 > random"
|
||||
|
65
tasks/rogue/selector.py
Normal file
65
tasks/rogue/selector.py
Normal file
@ -0,0 +1,65 @@
|
||||
import numpy as np
|
||||
|
||||
from module.base.filter import MultiLangFilter
|
||||
from module.logger import logger
|
||||
from module.ocr.keyword import Keyword
|
||||
from module.ocr.ocr import OcrResultButton
|
||||
|
||||
|
||||
class RogueSelector:
|
||||
"""
|
||||
An Interface used in blessing, curio, and other ui selection in rogue
|
||||
"""
|
||||
ocr_results: list[OcrResultButton]
|
||||
filter_: MultiLangFilter
|
||||
preset_methods: dict[str, callable]
|
||||
|
||||
def recognition(self):
|
||||
...
|
||||
|
||||
def ui_select(self, target: OcrResultButton | None, skip_first_screenshot=True):
|
||||
...
|
||||
|
||||
def try_select(self, option: OcrResultButton | str):
|
||||
...
|
||||
|
||||
def load_filter(self):
|
||||
...
|
||||
|
||||
def perform_selection(self, priority):
|
||||
if not self.ocr_results:
|
||||
logger.warning('No blessing recognized, randomly choose one')
|
||||
self.ui_select(None)
|
||||
return False
|
||||
|
||||
if not len(priority):
|
||||
logger.info('No blessing project satisfies current filter, randomly choose one')
|
||||
choose = np.random.choice(self.ocr_results)
|
||||
self.ui_select(choose)
|
||||
return False
|
||||
|
||||
for option in priority:
|
||||
logger.info(f"Try to choose option: {option}")
|
||||
if self.try_select(option):
|
||||
return True
|
||||
else:
|
||||
logger.info(f"Can not choose option: {option}")
|
||||
|
||||
def recognize_and_select(self):
|
||||
def match_ocr_result(matched_keyword: Keyword):
|
||||
for result in self.ocr_results:
|
||||
if result.matched_keyword == matched_keyword:
|
||||
return result
|
||||
return None
|
||||
|
||||
self.recognition()
|
||||
self.load_filter()
|
||||
if self.filter_:
|
||||
keywords = [result.matched_keyword for result in self.ocr_results]
|
||||
priority = self.filter_.apply(keywords)
|
||||
priority = [option if isinstance(option, str) else match_ocr_result(option) for option in priority]
|
||||
else:
|
||||
logger.warning("No filter loaded, use random instead")
|
||||
priority = ['random']
|
||||
logger.info(f"Priority: {priority}")
|
||||
self.perform_selection(priority)
|
@ -1,3 +1,4 @@
|
||||
from module.ocr.ocr import Digit
|
||||
from tasks.base.ui import UI
|
||||
from tasks.rogue.assets.assets_rogue_ui import *
|
||||
from tasks.rogue.keywords import *
|
||||
@ -5,13 +6,17 @@ from tasks.rogue.keywords import *
|
||||
|
||||
class RogueUI(UI):
|
||||
path: RoguePath
|
||||
ocr_blessings: list
|
||||
ocr_curios: list
|
||||
claimed_blessings: list
|
||||
claimed_curios: list
|
||||
cosmic_fragment_cache: int
|
||||
|
||||
@property
|
||||
def cosmic_fragment(self):
|
||||
if self.appear(COSMIC_FRAGMENT):
|
||||
self.cosmic_fragment_cache = Digit(OCR_COSMIC_FRAGMENT).ocr_single_line(self.device.image)
|
||||
return self.cosmic_fragment_cache
|
||||
|
||||
def is_page_choose_blessing(self):
|
||||
return self.image_color_count(PAGE_CHOOSE_BUFF, (245, 245, 245), count=200)
|
||||
return (self.image_color_count(PAGE_CHOOSE_BUFF, (245, 245, 245), count=200)
|
||||
and self.appear(CHECK_BLESSING))
|
||||
|
||||
def is_page_choose_curio(self):
|
||||
return self.appear(PAGE_CHOOSE_CURIO)
|
||||
|
Loading…
Reference in New Issue
Block a user