Merge pull request #58 from 5upernova-heng/add/rouge_buff_selector
Add: rogue buff selector
BIN
assets/share/rogue/blessing/BLESSING_ENFORCE.png
Normal file
After Width: | Height: | Size: 39 KiB |
BIN
assets/share/rogue/blessing/BLESSING_RESET.png
Normal file
After Width: | Height: | Size: 13 KiB |
BIN
assets/share/rogue/blessing/BLESSING_STABLE_FLAG.png
Normal file
After Width: | Height: | Size: 5.8 KiB |
BIN
assets/share/rogue/blessing/BOTTOM_WHITE_BAR.png
Normal file
After Width: | Height: | Size: 13 KiB |
BIN
assets/share/rogue/blessing/OCR_RESET_COST.png
Normal file
After Width: | Height: | Size: 6.5 KiB |
BIN
assets/share/rogue/blessing/OCR_RESET_COUNT.png
Normal file
After Width: | Height: | Size: 11 KiB |
BIN
assets/share/rogue/blessing/OCR_ROGUE_BUFF.png
Normal file
After Width: | Height: | Size: 141 KiB |
BIN
assets/share/rogue/bonus/BONUS_BOTTOM_WHITE_BAR.png
Normal file
After Width: | Height: | Size: 5.8 KiB |
BIN
assets/share/rogue/bonus/BONUS_CONFIRM.png
Normal file
After Width: | Height: | Size: 6.9 KiB |
BIN
assets/share/rogue/curio/CURIO_ENFORCE.png
Normal file
After Width: | Height: | Size: 142 KiB |
BIN
assets/share/rogue/curio/OCR_ROGUE_CURIO.png
Normal file
After Width: | Height: | Size: 34 KiB |
BIN
assets/share/rogue/ui/BLESSING_CONFIRM.png
Normal file
After Width: | Height: | Size: 8.3 KiB |
BIN
assets/share/rogue/ui/CHECK_BLESSING.png
Normal file
After Width: | Height: | Size: 9.2 KiB |
BIN
assets/share/rogue/ui/COSMIC_FRAGMENT.png
Normal file
After Width: | Height: | Size: 8.7 KiB |
BIN
assets/share/rogue/ui/FLAG_UNRECORD.png
Normal file
After Width: | Height: | Size: 8.1 KiB |
BIN
assets/share/rogue/ui/OBTAIN_ITEM_POPUP.png
Normal file
After Width: | Height: | Size: 39 KiB |
BIN
assets/share/rogue/ui/OCR_COSMIC_FRAGMENT.png
Normal file
After Width: | Height: | Size: 6.9 KiB |
BIN
assets/share/rogue/ui/PAGE_CHOOSE_BONUS.png
Normal file
After Width: | Height: | Size: 6.3 KiB |
BIN
assets/share/rogue/ui/PAGE_CHOOSE_BUFF.png
Normal file
After Width: | Height: | Size: 6.6 KiB |
BIN
assets/share/rogue/ui/PAGE_CHOOSE_CURIO.png
Normal file
After Width: | Height: | Size: 9.5 KiB |
BIN
assets/share/rogue/ui/PAGE_EVENT.png
Normal file
After Width: | Height: | Size: 7.0 KiB |
@ -127,5 +127,26 @@
|
||||
"Duration": 20,
|
||||
"Assignment": {}
|
||||
}
|
||||
},
|
||||
"Rogue": {
|
||||
"Scheduler": {
|
||||
"Enable": false,
|
||||
"NextRun": "2020-01-01 00:00:00",
|
||||
"Command": "Rogue",
|
||||
"ServerUpdate": "04:00"
|
||||
},
|
||||
"Rogue": {
|
||||
"Path": "The Hunt",
|
||||
"Bonus": "Blessing Cosmos",
|
||||
"PresetResonanceFilter": "preset-1",
|
||||
"CustomResonanceFilter": "回响构音:均晶转变 > 回响构音:零维强化\n> 回响构音:第二次初恋 > 回响构音:体验的富翁\n> 回响构音:局外人 > 回响构音:怀疑的四重根\n> 回响构音:诸法无我 > 回响构音:诸行无常\n> 回响构音:射不主皮 > 回响构音:柘弓危矢\n> 回响构音:激变变星 > 回响构音:极端氦闪\n> 回响构音:末日狂欢 > 回响构音:树苗长高舞",
|
||||
"ResonanceSelectionStrategy": "follow-presets",
|
||||
"PresetBlessingFilter": "preset-1",
|
||||
"CustomBlessingFilter": "巡猎-3 > 《冠军晚餐·猫的摇篮》 > 丰饶众生,一法界心 > 毁灭-3 \n> 火堆外的夜 > 巡猎-2 > 毁灭-2 > 巡猎 > reset > random",
|
||||
"BlessingSelectionStrategy": "follow-presets",
|
||||
"PresetCurioFilter": "preset-1",
|
||||
"CustomCurioFilter": "博士之袍 > 福灵胶 > 分裂金币 > 信仰债券 > 换境桂冠 > 俱乐部券 > 碎星芳饵 > random",
|
||||
"CurioSelectionStrategy": "follow-presets"
|
||||
}
|
||||
}
|
||||
}
|
@ -13,8 +13,8 @@ UI_LANGUAGES = ['cn', 'cht', 'en', 'jp']
|
||||
|
||||
def text_to_variable(text):
|
||||
text = re.sub("'s |s' ", '_', text)
|
||||
text = re.sub('[ \-—:\'/•]+', '_', text)
|
||||
text = re.sub(r'[(),#"?]|</?\w+>', '', text)
|
||||
text = re.sub('[ \-—:\'/•.]+', '_', text)
|
||||
text = re.sub(r'[(),#"?!&]|</?\w+>', '', text)
|
||||
# text = re.sub(r'[#_]?\d+(_times?)?', '', text)
|
||||
return text
|
||||
|
||||
@ -30,6 +30,12 @@ def dungeon_name(name: str) -> str:
|
||||
return name
|
||||
|
||||
|
||||
def blessing_name(name: str) -> str:
|
||||
name = text_to_variable(name)
|
||||
name = re.sub(r'^\d', lambda match: f"_{match.group(0)}", name)
|
||||
return name
|
||||
|
||||
|
||||
nickname_count = 0
|
||||
|
||||
|
||||
@ -147,7 +153,8 @@ class KeywordExtract:
|
||||
keyword_class,
|
||||
output_file: str = '',
|
||||
text_convert=text_to_variable,
|
||||
generator: CodeGenerator = None
|
||||
generator: CodeGenerator = None,
|
||||
extra_attrs: dict[str, dict] = None
|
||||
):
|
||||
"""
|
||||
Args:
|
||||
@ -155,6 +162,7 @@ class KeywordExtract:
|
||||
output_file:
|
||||
text_convert:
|
||||
generator: Reuse an existing code generator
|
||||
extra_attrs: Extra attributes write in keywords
|
||||
"""
|
||||
if generator is None:
|
||||
gen = CodeGenerator()
|
||||
@ -166,6 +174,12 @@ class KeywordExtract:
|
||||
gen = generator
|
||||
|
||||
last_id = getattr(gen, 'last_id', 0)
|
||||
if extra_attrs:
|
||||
keyword_num = len(self.keywords_id)
|
||||
for attr_key, attr_value in extra_attrs.items():
|
||||
if len(attr_value) != keyword_num:
|
||||
print(f"Extra attribute {attr_key} does not match the size of keywords")
|
||||
return
|
||||
for index, keyword in enumerate(self.keywords_id):
|
||||
_, name = self.find_keyword(keyword, lang='en')
|
||||
name = text_convert(replace_templates(name))
|
||||
@ -174,6 +188,9 @@ class KeywordExtract:
|
||||
gen.ObjectAttr(key='name', value=name)
|
||||
for lang in UI_LANGUAGES:
|
||||
gen.ObjectAttr(key=lang, value=replace_templates(self.find_keyword(keyword, lang=lang)[1]))
|
||||
if extra_attrs:
|
||||
for attr_key, attr_value in extra_attrs.items():
|
||||
gen.ObjectAttr(key=attr_key, value=attr_value[keyword])
|
||||
gen.last_id = index + last_id + 1
|
||||
|
||||
if output_file:
|
||||
@ -279,6 +296,67 @@ class KeywordExtract:
|
||||
self.load_quests(quests)
|
||||
self.write_keywords(keyword_class='BattlePassQuest', output_file='./tasks/battle_pass/keywords/quest.py')
|
||||
|
||||
def generate_rogue_buff(self):
|
||||
# paths
|
||||
aeons = read_file(os.path.join(TextMap.DATA_FOLDER, 'ExcelOutput', 'RogueAeon.json'))
|
||||
aeons_hash = [deep_get(aeon, '1.RogueAeonPathName2.Hash') for aeon in aeons.values()]
|
||||
self.keywords_id = aeons_hash
|
||||
self.write_keywords(keyword_class='RoguePath', output_file='./tasks/rogue/keywords/path.py')
|
||||
|
||||
# blessings
|
||||
blessings_info = read_file(os.path.join(TextMap.DATA_FOLDER, 'ExcelOutput', 'RogueBuff.json'))
|
||||
blessings_name_map = read_file(os.path.join(TextMap.DATA_FOLDER, 'ExcelOutput', 'RogueMazeBuff.json'))
|
||||
blessings_id = [deep_get(blessing, '1.MazeBuffID') for blessing in blessings_info.values()
|
||||
if not deep_get(blessing, '1.AeonID')][1:]
|
||||
resonances_id = [deep_get(blessing, '1.MazeBuffID') for blessing in blessings_info.values()
|
||||
if deep_get(blessing, '1.AeonID')]
|
||||
|
||||
def get_blessing_infos(id_list, with_enhancement: bool):
|
||||
blessings_hash = [deep_get(blessings_name_map, f"{blessing_id}.1.BuffName.Hash")
|
||||
for blessing_id in id_list]
|
||||
blessings_path_id = {blessing_hash: int(deep_get(blessings_info, f'{blessing_id}.1.RogueBuffType')) - 119
|
||||
# 119 is the magic number make type match with path in keyword above
|
||||
for blessing_hash, blessing_id in zip(blessings_hash, id_list)}
|
||||
blessings_rarity = {blessing_hash: deep_get(blessings_info, f'{blessing_id}.1.RogueBuffRarity')
|
||||
for blessing_hash, blessing_id in zip(blessings_hash, id_list)}
|
||||
enhancement = {blessing_hash: "" for blessing_hash in blessings_hash}
|
||||
if with_enhancement:
|
||||
return blessings_hash, {'path_id': blessings_path_id, 'rarity': blessings_rarity,
|
||||
'enhancement': enhancement}
|
||||
else:
|
||||
return blessings_hash, {'path_id': blessings_path_id, 'rarity': blessings_rarity}
|
||||
|
||||
hash_list, extra_attrs = get_blessing_infos(blessings_id, with_enhancement=True)
|
||||
self.keywords_id = hash_list
|
||||
self.write_keywords(keyword_class='RogueBlessing', output_file='./tasks/rogue/keywords/blessing.py',
|
||||
text_convert=blessing_name, extra_attrs=extra_attrs)
|
||||
|
||||
hash_list, extra_attrs = get_blessing_infos(resonances_id, with_enhancement=False)
|
||||
self.keywords_id = hash_list
|
||||
self.write_keywords(keyword_class='RogueResonance', output_file='./tasks/rogue/keywords/resonance.py',
|
||||
text_convert=blessing_name, extra_attrs=extra_attrs)
|
||||
|
||||
def iter_without_duplication(self, file: dict, keys):
|
||||
visited = set()
|
||||
for data in file.values():
|
||||
hash_ = deep_get(data, keys=keys)
|
||||
_, name = self.find_keyword(hash_, lang='cn')
|
||||
if name in visited:
|
||||
continue
|
||||
visited.add(name)
|
||||
yield hash_
|
||||
|
||||
def iter_rogue_miracles(self):
|
||||
miracles = read_file(os.path.join(TextMap.DATA_FOLDER, 'ExcelOutput', 'RogueMiracle.json'))
|
||||
visited = set()
|
||||
for data in miracles.values():
|
||||
hash_ = deep_get(data, keys='MiracleName.Hash')
|
||||
_, name = self.find_keyword(hash_, lang='cn')
|
||||
if name in visited:
|
||||
continue
|
||||
visited.add(name)
|
||||
yield hash_
|
||||
|
||||
def generate(self):
|
||||
self.load_keywords(['模拟宇宙', '拟造花萼(金)', '拟造花萼(赤)', '凝滞虚影', '侵蚀隧洞', '历战余响', '忘却之庭'])
|
||||
self.write_keywords(keyword_class='DungeonNav', output_file='./tasks/dungeon/keywords/nav.py')
|
||||
@ -308,6 +386,15 @@ class KeywordExtract:
|
||||
self.load_keywords(['养成材料', '光锥', '遗器', '其他材料', '消耗品', '任务', '贵重物'])
|
||||
self.write_keywords(keyword_class='ItemTab', text_convert=lambda name: name.replace(' ', ''),
|
||||
output_file='./tasks/item/keywords/tab.py')
|
||||
self.generate_rogue_buff()
|
||||
self.load_keywords(['已强化'])
|
||||
self.write_keywords(keyword_class='RogueEnhancement', output_file='./tasks/rogue/keywords/enhancement.py')
|
||||
self.load_keywords(list(self.iter_without_duplication(
|
||||
read_file(os.path.join(TextMap.DATA_FOLDER, 'ExcelOutput', 'RogueMiracle.json')), 'MiracleName.Hash')))
|
||||
self.write_keywords(keyword_class='RogueCurio', output_file='./tasks/rogue/keywords/curio.py')
|
||||
self.load_keywords(list(self.iter_without_duplication(
|
||||
read_file(os.path.join(TextMap.DATA_FOLDER, 'ExcelOutput', 'RogueBonus.json')), 'BonusTitle.Hash')))
|
||||
self.write_keywords(keyword_class='RogueBonus', output_file='./tasks/rogue/keywords/bonus.py')
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
|
@ -101,3 +101,35 @@ class Filter:
|
||||
# Invalid filter will be ignored.
|
||||
# Return strange things and make it impossible to match
|
||||
return ['1nVa1d'] + [None] * (len(self.attr) - 1)
|
||||
|
||||
|
||||
class MultiLangFilter(Filter):
|
||||
"""
|
||||
To support multi-language, there might be different correct matches of same object.
|
||||
"""
|
||||
|
||||
def apply_filter_to_obj(self, obj, filter):
|
||||
"""
|
||||
Args:
|
||||
obj (object): In this case, attributes of object are array (instead of plain string).
|
||||
Any match of element in it will return True
|
||||
filter (list[str]):
|
||||
|
||||
Returns:
|
||||
bool: If an object satisfy a filter.
|
||||
"""
|
||||
for attr, value in zip(self.attr, filter):
|
||||
if not value:
|
||||
continue
|
||||
if not hasattr(obj, attr):
|
||||
continue
|
||||
|
||||
obj_value = obj.__getattribute__(attr)
|
||||
if isinstance(obj_value, (str, int)):
|
||||
if str(obj_value).lower() != str(value):
|
||||
return False
|
||||
if isinstance(obj_value, list):
|
||||
if value not in obj_value:
|
||||
return False
|
||||
|
||||
return True
|
||||
|
@ -982,5 +982,115 @@
|
||||
"color": "#79dbc4"
|
||||
}
|
||||
}
|
||||
},
|
||||
"Rogue": {
|
||||
"Scheduler": {
|
||||
"Enable": {
|
||||
"type": "checkbox",
|
||||
"value": false
|
||||
},
|
||||
"NextRun": {
|
||||
"type": "datetime",
|
||||
"value": "2020-01-01 00:00:00",
|
||||
"validate": "datetime"
|
||||
},
|
||||
"Command": {
|
||||
"type": "input",
|
||||
"value": "Rogue",
|
||||
"display": "hide"
|
||||
},
|
||||
"ServerUpdate": {
|
||||
"type": "input",
|
||||
"value": "04:00",
|
||||
"display": "hide"
|
||||
}
|
||||
},
|
||||
"Rogue": {
|
||||
"Path": {
|
||||
"type": "select",
|
||||
"value": "The Hunt",
|
||||
"option": [
|
||||
"Preservation",
|
||||
"Remembrance",
|
||||
"Nihility",
|
||||
"Abundance",
|
||||
"Hunt",
|
||||
"Destruction",
|
||||
"Elation"
|
||||
]
|
||||
},
|
||||
"Bonus": {
|
||||
"type": "select",
|
||||
"value": "Blessing Cosmos",
|
||||
"option": [
|
||||
"Blessing Cosmos",
|
||||
"Miracle Cosmos",
|
||||
"Fragmented Cosmos"
|
||||
]
|
||||
},
|
||||
"PresetResonanceFilter": {
|
||||
"type": "select",
|
||||
"value": "preset-1",
|
||||
"option": [
|
||||
"preset-1",
|
||||
"custom"
|
||||
]
|
||||
},
|
||||
"CustomResonanceFilter": {
|
||||
"type": "textarea",
|
||||
"value": "回响构音:均晶转变 > 回响构音:零维强化\n> 回响构音:第二次初恋 > 回响构音:体验的富翁\n> 回响构音:局外人 > 回响构音:怀疑的四重根\n> 回响构音:诸法无我 > 回响构音:诸行无常\n> 回响构音:射不主皮 > 回响构音:柘弓危矢\n> 回响构音:激变变星 > 回响构音:极端氦闪\n> 回响构音:末日狂欢 > 回响构音:树苗长高舞"
|
||||
},
|
||||
"ResonanceSelectionStrategy": {
|
||||
"type": "select",
|
||||
"value": "follow-presets",
|
||||
"option": [
|
||||
"follow-presets",
|
||||
"unrecorded-first",
|
||||
"before-random"
|
||||
]
|
||||
},
|
||||
"PresetBlessingFilter": {
|
||||
"type": "select",
|
||||
"value": "preset-1",
|
||||
"option": [
|
||||
"preset-1",
|
||||
"custom"
|
||||
]
|
||||
},
|
||||
"CustomBlessingFilter": {
|
||||
"type": "textarea",
|
||||
"value": "巡猎-3 > 《冠军晚餐·猫的摇篮》 > 丰饶众生,一法界心 > 毁灭-3 \n> 火堆外的夜 > 巡猎-2 > 毁灭-2 > 巡猎 > reset > random"
|
||||
},
|
||||
"BlessingSelectionStrategy": {
|
||||
"type": "select",
|
||||
"value": "follow-presets",
|
||||
"option": [
|
||||
"follow-presets",
|
||||
"unrecorded-first",
|
||||
"before-random"
|
||||
]
|
||||
},
|
||||
"PresetCurioFilter": {
|
||||
"type": "select",
|
||||
"value": "preset-1",
|
||||
"option": [
|
||||
"preset-1",
|
||||
"custom"
|
||||
]
|
||||
},
|
||||
"CustomCurioFilter": {
|
||||
"type": "textarea",
|
||||
"value": "博士之袍 > 福灵胶 > 分裂金币 > 信仰债券 > 换境桂冠 > 俱乐部券 > 碎星芳饵 > random"
|
||||
},
|
||||
"CurioSelectionStrategy": {
|
||||
"type": "select",
|
||||
"value": "follow-presets",
|
||||
"option": [
|
||||
"follow-presets",
|
||||
"unrecorded-first",
|
||||
"before-random"
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -164,3 +164,45 @@ Assignment:
|
||||
stored: StoredAssignment
|
||||
order: 3
|
||||
color: "#79dbc4"
|
||||
|
||||
# ==================== Rogue ====================
|
||||
|
||||
Rogue:
|
||||
Path:
|
||||
value: The Hunt
|
||||
option: [ Preservation, Remembrance, Nihility, Abundance, Hunt, Destruction, Elation ]
|
||||
Bonus:
|
||||
value: Blessing Cosmos
|
||||
option: [ Blessing Cosmos, Miracle Cosmos, Fragmented Cosmos ]
|
||||
PresetResonanceFilter:
|
||||
value: preset-1
|
||||
option: [ preset-1, custom ]
|
||||
CustomResonanceFilter: |-
|
||||
回响构音:均晶转变 > 回响构音:零维强化
|
||||
> 回响构音:第二次初恋 > 回响构音:体验的富翁
|
||||
> 回响构音:局外人 > 回响构音:怀疑的四重根
|
||||
> 回响构音:诸法无我 > 回响构音:诸行无常
|
||||
> 回响构音:射不主皮 > 回响构音:柘弓危矢
|
||||
> 回响构音:激变变星 > 回响构音:极端氦闪
|
||||
> 回响构音:末日狂欢 > 回响构音:树苗长高舞
|
||||
ResonanceSelectionStrategy:
|
||||
value: follow-presets
|
||||
option: [ follow-presets, unrecorded-first, before-random ]
|
||||
PresetBlessingFilter:
|
||||
value: preset-1
|
||||
option: [ preset-1, custom ]
|
||||
CustomBlessingFilter: |-
|
||||
巡猎-3 > 《冠军晚餐·猫的摇篮》 > 丰饶众生,一法界心 > 毁灭-3
|
||||
> 火堆外的夜 > 巡猎-2 > 毁灭-2 > 巡猎 > reset > random
|
||||
BlessingSelectionStrategy:
|
||||
value: follow-presets
|
||||
option: [ follow-presets, unrecorded-first, before-random ]
|
||||
PresetCurioFilter:
|
||||
value: preset-1
|
||||
option: [ preset-1, custom ]
|
||||
CustomCurioFilter: |-
|
||||
博士之袍 > 福灵胶 > 分裂金币 > 信仰债券 > 换境桂冠 > 俱乐部券 > 碎星芳饵 > random
|
||||
CurioSelectionStrategy:
|
||||
value: follow-presets
|
||||
option: [ follow-presets, unrecorded-first, before-random ]
|
||||
|
||||
|
@ -16,5 +16,12 @@
|
||||
"BattlePass",
|
||||
"Assignment"
|
||||
]
|
||||
},
|
||||
"Rogue": {
|
||||
"menu": "list",
|
||||
"page": "setting",
|
||||
"tasks": [
|
||||
"Rogue"
|
||||
]
|
||||
}
|
||||
}
|
@ -38,3 +38,13 @@ Daily:
|
||||
Assignment:
|
||||
- Scheduler
|
||||
- Assignment
|
||||
|
||||
# ==================== Rogue ====================
|
||||
|
||||
Rogue:
|
||||
menu: 'list'
|
||||
page: 'setting'
|
||||
tasks:
|
||||
Rogue:
|
||||
- Scheduler
|
||||
- Rogue
|
||||
|
@ -101,3 +101,16 @@ class GeneratedConfig:
|
||||
Assignment_Name_4 = 'Nine_Billion_Names' # Nine_Billion_Names, Destruction_of_the_Destroyer, Winter_Soldiers, Born_to_Obey, Root_Out_the_Turpitude, Fire_Lord_Inflames_Blades_of_War, Nameless_Land_Nameless_People, Akashic_Records, The_Invisible_Hand, Abandoned_and_Insulted, Spring_of_Life, The_Land_of_Gold, The_Blossom_in_the_Storm, Legend_of_the_Puppet_Master, The_Wages_of_Humanity
|
||||
Assignment_Duration = 20 # 4, 8, 12, 20
|
||||
Assignment_Assignment = {}
|
||||
|
||||
# Group `Rogue`
|
||||
Rogue_Path = 'The Hunt' # Preservation, Remembrance, Nihility, Abundance, Hunt, Destruction, Elation
|
||||
Rogue_Bonus = 'Blessing Cosmos' # Blessing Cosmos, Miracle Cosmos, Fragmented Cosmos
|
||||
Rogue_PresetResonanceFilter = 'preset-1' # preset-1, custom
|
||||
Rogue_CustomResonanceFilter = '回响构音:均晶转变 > 回响构音:零维强化\n> 回响构音:第二次初恋 > 回响构音:体验的富翁\n> 回响构音:局外人 > 回响构音:怀疑的四重根\n> 回响构音:诸法无我 > 回响构音:诸行无常\n> 回响构音:射不主皮 > 回响构音:柘弓危矢\n> 回响构音:激变变星 > 回响构音:极端氦闪\n> 回响构音:末日狂欢 > 回响构音:树苗长高舞'
|
||||
Rogue_ResonanceSelectionStrategy = 'follow-presets' # follow-presets, unrecorded-first, before-random
|
||||
Rogue_PresetBlessingFilter = 'preset-1' # preset-1, custom
|
||||
Rogue_CustomBlessingFilter = '巡猎-3 > 《冠军晚餐·猫的摇篮》 > 丰饶众生,一法界心 > 毁灭-3 \n> 火堆外的夜 > 巡猎-2 > 毁灭-2 > 巡猎 > reset > random'
|
||||
Rogue_BlessingSelectionStrategy = 'follow-presets' # follow-presets, unrecorded-first, before-random
|
||||
Rogue_PresetCurioFilter = 'preset-1' # preset-1, custom
|
||||
Rogue_CustomCurioFilter = '博士之袍 > 福灵胶 > 分裂金币 > 信仰债券 > 换境桂冠 > 俱乐部券 > 碎星芳饵 > random'
|
||||
Rogue_CurioSelectionStrategy = 'follow-presets' # follow-presets, unrecorded-first, before-random
|
||||
|
@ -7,6 +7,10 @@
|
||||
"Daily": {
|
||||
"name": "Daily",
|
||||
"help": ""
|
||||
},
|
||||
"Rogue": {
|
||||
"name": "Simulated Universe",
|
||||
"help": ""
|
||||
}
|
||||
},
|
||||
"Task": {
|
||||
@ -33,6 +37,10 @@
|
||||
"Assignment": {
|
||||
"name": "Assignment",
|
||||
"help": ""
|
||||
},
|
||||
"Rogue": {
|
||||
"name": "Simulated Universe",
|
||||
"help": ""
|
||||
}
|
||||
},
|
||||
"Scheduler": {
|
||||
@ -678,6 +686,81 @@
|
||||
"help": ""
|
||||
}
|
||||
},
|
||||
"Rogue": {
|
||||
"_info": {
|
||||
"name": "Simulated Universe",
|
||||
"help": ""
|
||||
},
|
||||
"Path": {
|
||||
"name": "Fate",
|
||||
"help": "",
|
||||
"Preservation": "Preservation",
|
||||
"Remembrance": "Remembrance",
|
||||
"Nihility": "Nihility",
|
||||
"Abundance": "Abundance",
|
||||
"Hunt": "The Hunt",
|
||||
"Destruction": "Destruction",
|
||||
"Elation": "Elation"
|
||||
},
|
||||
"Bonus": {
|
||||
"name": "Blessings of Trailblaze",
|
||||
"help": "",
|
||||
"Blessing Cosmos": "Blessing Cosmos (Choose a blessing)",
|
||||
"Miracle Cosmos": "Miracle Cosmos (Choose a curio)",
|
||||
"Fragmented Cosmos": "Fragmented Cosmos (Claim some Cosmic Fragments)"
|
||||
},
|
||||
"PresetResonanceFilter": {
|
||||
"name": "Preset Resonance Filter",
|
||||
"help": "",
|
||||
"preset-1": "preset-1",
|
||||
"custom": "custom"
|
||||
},
|
||||
"CustomResonanceFilter": {
|
||||
"name": "Custom Resonance Filter",
|
||||
"help": ""
|
||||
},
|
||||
"ResonanceSelectionStrategy": {
|
||||
"name": "Resonance Selection Strategy",
|
||||
"help": "",
|
||||
"follow-presets": "Follow presets",
|
||||
"unrecorded-first": "Choose index locked resonance first",
|
||||
"before-random": "Follow presets, but choose index locked one first when filter goes to randomly choose"
|
||||
},
|
||||
"PresetBlessingFilter": {
|
||||
"name": "Preset Blessing Filter",
|
||||
"help": "",
|
||||
"preset-1": "preset-1",
|
||||
"custom": "custom"
|
||||
},
|
||||
"CustomBlessingFilter": {
|
||||
"name": "Custom Blessing Filter",
|
||||
"help": ""
|
||||
},
|
||||
"BlessingSelectionStrategy": {
|
||||
"name": "Blessing jSelection Strategy",
|
||||
"help": "",
|
||||
"follow-presets": "Follow presets",
|
||||
"unrecorded-first": "Choose index locked blessing first",
|
||||
"before-random": "Follow presets, but choose index locked one first when filter goes to randomly choose"
|
||||
},
|
||||
"PresetCurioFilter": {
|
||||
"name": "Preset Curio Filter",
|
||||
"help": "",
|
||||
"preset-1": "preset-1",
|
||||
"custom": "custom"
|
||||
},
|
||||
"CustomCurioFilter": {
|
||||
"name": "Custom Curio Filter",
|
||||
"help": ""
|
||||
},
|
||||
"CurioSelectionStrategy": {
|
||||
"name": "Curio Selection Strategy",
|
||||
"help": "",
|
||||
"follow-presets": "Follow presets",
|
||||
"unrecorded-first": "Choose index locked curio first",
|
||||
"before-random": "Follow presets, but choose index locked one first when filter goes to randomly choose"
|
||||
}
|
||||
},
|
||||
"Gui": {
|
||||
"Aside": {
|
||||
"Install": "Install",
|
||||
@ -780,4 +863,4 @@
|
||||
"Clear": "Clear"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -7,6 +7,10 @@
|
||||
"Daily": {
|
||||
"name": "Menu.Daily.name",
|
||||
"help": "Menu.Daily.help"
|
||||
},
|
||||
"Rogue": {
|
||||
"name": "Menu.Rogue.name",
|
||||
"help": "Menu.Rogue.help"
|
||||
}
|
||||
},
|
||||
"Task": {
|
||||
@ -33,6 +37,10 @@
|
||||
"Assignment": {
|
||||
"name": "依頼設定",
|
||||
"help": ""
|
||||
},
|
||||
"Rogue": {
|
||||
"name": "Task.Rogue.name",
|
||||
"help": "Task.Rogue.help"
|
||||
}
|
||||
},
|
||||
"Scheduler": {
|
||||
@ -678,6 +686,81 @@
|
||||
"help": "Assignment.Assignment.help"
|
||||
}
|
||||
},
|
||||
"Rogue": {
|
||||
"_info": {
|
||||
"name": "Rogue._info.name",
|
||||
"help": "Rogue._info.help"
|
||||
},
|
||||
"Path": {
|
||||
"name": "Rogue.Path.name",
|
||||
"help": "Rogue.Path.help",
|
||||
"Preservation": "Preservation",
|
||||
"Remembrance": "Remembrance",
|
||||
"Nihility": "Nihility",
|
||||
"Abundance": "Abundance",
|
||||
"Hunt": "Hunt",
|
||||
"Destruction": "Destruction",
|
||||
"Elation": "Elation"
|
||||
},
|
||||
"Bonus": {
|
||||
"name": "Rogue.Bonus.name",
|
||||
"help": "Rogue.Bonus.help",
|
||||
"Blessing Cosmos": "Blessing Cosmos",
|
||||
"Miracle Cosmos": "Miracle Cosmos",
|
||||
"Fragmented Cosmos": "Fragmented Cosmos"
|
||||
},
|
||||
"PresetResonanceFilter": {
|
||||
"name": "Rogue.PresetResonanceFilter.name",
|
||||
"help": "Rogue.PresetResonanceFilter.help",
|
||||
"preset-1": "preset-1",
|
||||
"custom": "custom"
|
||||
},
|
||||
"CustomResonanceFilter": {
|
||||
"name": "Rogue.CustomResonanceFilter.name",
|
||||
"help": "Rogue.CustomResonanceFilter.help"
|
||||
},
|
||||
"ResonanceSelectionStrategy": {
|
||||
"name": "Rogue.ResonanceSelectionStrategy.name",
|
||||
"help": "Rogue.ResonanceSelectionStrategy.help",
|
||||
"follow-presets": "follow-presets",
|
||||
"unrecorded-first": "unrecorded-first",
|
||||
"before-random": "before-random"
|
||||
},
|
||||
"PresetBlessingFilter": {
|
||||
"name": "Rogue.PresetBlessingFilter.name",
|
||||
"help": "Rogue.PresetBlessingFilter.help",
|
||||
"preset-1": "preset-1",
|
||||
"custom": "custom"
|
||||
},
|
||||
"CustomBlessingFilter": {
|
||||
"name": "Rogue.CustomBlessingFilter.name",
|
||||
"help": "Rogue.CustomBlessingFilter.help"
|
||||
},
|
||||
"BlessingSelectionStrategy": {
|
||||
"name": "Rogue.BlessingSelectionStrategy.name",
|
||||
"help": "Rogue.BlessingSelectionStrategy.help",
|
||||
"follow-presets": "follow-presets",
|
||||
"unrecorded-first": "unrecorded-first",
|
||||
"before-random": "before-random"
|
||||
},
|
||||
"PresetCurioFilter": {
|
||||
"name": "Rogue.PresetCurioFilter.name",
|
||||
"help": "Rogue.PresetCurioFilter.help",
|
||||
"preset-1": "preset-1",
|
||||
"custom": "custom"
|
||||
},
|
||||
"CustomCurioFilter": {
|
||||
"name": "Rogue.CustomCurioFilter.name",
|
||||
"help": "Rogue.CustomCurioFilter.help"
|
||||
},
|
||||
"CurioSelectionStrategy": {
|
||||
"name": "Rogue.CurioSelectionStrategy.name",
|
||||
"help": "Rogue.CurioSelectionStrategy.help",
|
||||
"follow-presets": "follow-presets",
|
||||
"unrecorded-first": "unrecorded-first",
|
||||
"before-random": "before-random"
|
||||
}
|
||||
},
|
||||
"Gui": {
|
||||
"Aside": {
|
||||
"Install": "インストール",
|
||||
|
@ -7,6 +7,10 @@
|
||||
"Daily": {
|
||||
"name": "每日",
|
||||
"help": ""
|
||||
},
|
||||
"Rogue": {
|
||||
"name": "模拟宇宙",
|
||||
"help": ""
|
||||
}
|
||||
},
|
||||
"Task": {
|
||||
@ -33,6 +37,10 @@
|
||||
"Assignment": {
|
||||
"name": "委托",
|
||||
"help": ""
|
||||
},
|
||||
"Rogue": {
|
||||
"name": "模拟宇宙",
|
||||
"help": ""
|
||||
}
|
||||
},
|
||||
"Scheduler": {
|
||||
@ -678,6 +686,81 @@
|
||||
"help": ""
|
||||
}
|
||||
},
|
||||
"Rogue": {
|
||||
"_info": {
|
||||
"name": "模拟宇宙",
|
||||
"help": ""
|
||||
},
|
||||
"Path": {
|
||||
"name": "命途",
|
||||
"help": "",
|
||||
"Preservation": "存护",
|
||||
"Remembrance": "记忆",
|
||||
"Nihility": "虚无",
|
||||
"Abundance": "丰饶",
|
||||
"Hunt": "巡猎",
|
||||
"Destruction": "毁灭",
|
||||
"Elation": "欢愉"
|
||||
},
|
||||
"Bonus": {
|
||||
"name": "开拓祝福",
|
||||
"help": "开局三选一",
|
||||
"Blessing Cosmos": "祝福宇宙(获得一个祝福)",
|
||||
"Miracle Cosmos": "神奇宇宙(获得一个奇物)",
|
||||
"Fragmented Cosmos": "破碎宇宙(获得宇宙碎片)"
|
||||
},
|
||||
"PresetResonanceFilter": {
|
||||
"name": "回响构音过滤器",
|
||||
"help": "",
|
||||
"preset-1": "预设 1",
|
||||
"custom": "自定义"
|
||||
},
|
||||
"CustomResonanceFilter": {
|
||||
"name": "自定义回响构音过滤器",
|
||||
"help": ""
|
||||
},
|
||||
"ResonanceSelectionStrategy": {
|
||||
"name": "回响构音选择策略",
|
||||
"help": "",
|
||||
"follow-presets": "遵循预设",
|
||||
"unrecorded-first": "优先选择图鉴未解锁的回响构音",
|
||||
"before-random": "遵循预设,但选择\"图鉴未解锁\"的优先级高于\"随机选择\""
|
||||
},
|
||||
"PresetBlessingFilter": {
|
||||
"name": "祝福过滤器",
|
||||
"help": "",
|
||||
"preset-1": "预设 1",
|
||||
"custom": "自定义"
|
||||
},
|
||||
"CustomBlessingFilter": {
|
||||
"name": "自定义祝福过滤器",
|
||||
"help": ""
|
||||
},
|
||||
"BlessingSelectionStrategy": {
|
||||
"name": "祝福选择策略",
|
||||
"help": "",
|
||||
"follow-presets": "遵循预设",
|
||||
"unrecorded-first": "优先选择图鉴未解锁的祝福",
|
||||
"before-random": "遵循预设,但选择\"图鉴未解锁\"的优先级高于\"随机选择\""
|
||||
},
|
||||
"PresetCurioFilter": {
|
||||
"name": "奇物过滤器",
|
||||
"help": "",
|
||||
"preset-1": "预设 1",
|
||||
"custom": "自定义"
|
||||
},
|
||||
"CustomCurioFilter": {
|
||||
"name": "自定义祝福过滤器",
|
||||
"help": ""
|
||||
},
|
||||
"CurioSelectionStrategy": {
|
||||
"name": "奇物选择策略",
|
||||
"help": "",
|
||||
"follow-presets": "遵循预设",
|
||||
"unrecorded-first": "优先选择图鉴未解锁的奇物",
|
||||
"before-random": "遵循预设,但选择\"图鉴未解锁\"的优先级高于\"随机选择\""
|
||||
}
|
||||
},
|
||||
"Gui": {
|
||||
"Aside": {
|
||||
"Install": "安装",
|
||||
@ -780,4 +863,4 @@
|
||||
"Clear": "清除"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -7,6 +7,10 @@
|
||||
"Daily": {
|
||||
"name": "每日",
|
||||
"help": ""
|
||||
},
|
||||
"Rogue": {
|
||||
"name": "模擬宇宙",
|
||||
"help": ""
|
||||
}
|
||||
},
|
||||
"Task": {
|
||||
@ -33,6 +37,10 @@
|
||||
"Assignment": {
|
||||
"name": "委託",
|
||||
"help": ""
|
||||
},
|
||||
"Rogue": {
|
||||
"name": "模擬宇宙",
|
||||
"help": ""
|
||||
}
|
||||
},
|
||||
"Scheduler": {
|
||||
@ -678,6 +686,81 @@
|
||||
"help": ""
|
||||
}
|
||||
},
|
||||
"Rogue": {
|
||||
"_info": {
|
||||
"name": "模擬宇宙",
|
||||
"help": ""
|
||||
},
|
||||
"Path": {
|
||||
"name": "命途",
|
||||
"help": "",
|
||||
"Preservation": "存護",
|
||||
"Remembrance": "記憶",
|
||||
"Nihility": "虛無",
|
||||
"Abundance": "丰饶",
|
||||
"Hunt": "巡獵",
|
||||
"Destruction": "毀滅",
|
||||
"Elation": "歡愉"
|
||||
},
|
||||
"Bonus": {
|
||||
"name": "開拓祝福",
|
||||
"help": "开局三选一",
|
||||
"Blessing Cosmos": "祝福宇宙(獲得一個祝福)",
|
||||
"Miracle Cosmos": "神奇宇宙(獲得一個奇物)",
|
||||
"Fragmented Cosmos": "破碎宇宙(獲得宇宙碎片)"
|
||||
},
|
||||
"PresetResonanceFilter": {
|
||||
"name": "迴響構音过滤器",
|
||||
"help": "",
|
||||
"preset-1": "預設 1",
|
||||
"custom": "自訂"
|
||||
},
|
||||
"CustomResonanceFilter": {
|
||||
"name": "自訂迴響構音过滤器",
|
||||
"help": ""
|
||||
},
|
||||
"ResonanceSelectionStrategy": {
|
||||
"name": "迴響構音選擇策略",
|
||||
"help": "",
|
||||
"follow-presets": "遵循預設",
|
||||
"unrecorded-first": "優先選擇圖鑑未解鎖的迴響構音",
|
||||
"before-random": "遵循預設,但選擇\"圖鑑未解鎖\"的優先級高於\"隨機選擇\""
|
||||
},
|
||||
"PresetBlessingFilter": {
|
||||
"name": "祝福过滤器",
|
||||
"help": "",
|
||||
"preset-1": "預設 1",
|
||||
"custom": "自訂"
|
||||
},
|
||||
"CustomBlessingFilter": {
|
||||
"name": "自訂祝福过滤器",
|
||||
"help": ""
|
||||
},
|
||||
"BlessingSelectionStrategy": {
|
||||
"name": "祝福選擇策略",
|
||||
"help": "",
|
||||
"follow-presets": "遵循預設",
|
||||
"unrecorded-first": "優先選擇圖鑑未解鎖的祝福",
|
||||
"before-random": "遵循預設,但選擇\"圖鑑未解鎖\"的優先級高於\"隨機選擇\""
|
||||
},
|
||||
"PresetCurioFilter": {
|
||||
"name": "奇物过滤器",
|
||||
"help": "",
|
||||
"preset-1": "preset-1",
|
||||
"custom": "custom"
|
||||
},
|
||||
"CustomCurioFilter": {
|
||||
"name": "自訂奇物过滤器",
|
||||
"help": ""
|
||||
},
|
||||
"CurioSelectionStrategy": {
|
||||
"name": "奇物選擇策略",
|
||||
"help": "",
|
||||
"follow-presets": "遵循預設",
|
||||
"unrecorded-first": "優先選擇圖鑑未解鎖的奇物",
|
||||
"before-random": "遵循預設,但選擇\"圖鑑未解鎖\"的優先級高於\"隨機選擇\""
|
||||
}
|
||||
},
|
||||
"Gui": {
|
||||
"Aside": {
|
||||
"Install": "安裝",
|
||||
@ -780,4 +863,4 @@
|
||||
"Clear": "清除"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -3,10 +3,10 @@ from dataclasses import dataclass
|
||||
from functools import cached_property
|
||||
from typing import ClassVar
|
||||
|
||||
from module.exception import ScriptError
|
||||
import module.config.server as server
|
||||
from module.exception import ScriptError
|
||||
|
||||
REGEX_PUNCTUATION = re.compile(r'[ ,.\'"“”,。!!??·•\-—/\\\n\t()\[\]()「」『』【】]')
|
||||
REGEX_PUNCTUATION = re.compile(r'[ ,.\'"“”,。::!!??·•\-—/\\\n\t()\[\]()「」『』【】《》]')
|
||||
|
||||
|
||||
def parse_name(n):
|
||||
@ -26,6 +26,7 @@ class Keyword:
|
||||
"""
|
||||
Instance attributes and methods
|
||||
"""
|
||||
|
||||
@cached_property
|
||||
def ch(self) -> str:
|
||||
return self.cn
|
||||
|
75
tasks/rogue/assets/assets_rogue_blessing.py
Normal file
@ -0,0 +1,75 @@
|
||||
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 ```
|
||||
|
||||
BLESSING_ENFORCE = ButtonWrapper(
|
||||
name='BLESSING_ENFORCE',
|
||||
share=Button(
|
||||
file='./assets/share/rogue/blessing/BLESSING_ENFORCE.png',
|
||||
area=(500, 141, 608, 556),
|
||||
search=(480, 121, 628, 576),
|
||||
color=(123, 100, 78),
|
||||
button=(500, 141, 608, 556),
|
||||
),
|
||||
)
|
||||
BLESSING_RESET = ButtonWrapper(
|
||||
name='BLESSING_RESET',
|
||||
share=Button(
|
||||
file='./assets/share/rogue/blessing/BLESSING_RESET.png',
|
||||
area=(652, 629, 889, 677),
|
||||
search=(632, 609, 909, 697),
|
||||
color=(204, 203, 204),
|
||||
button=(652, 629, 889, 677),
|
||||
),
|
||||
)
|
||||
BLESSING_STABLE_FLAG = ButtonWrapper(
|
||||
name='BLESSING_STABLE_FLAG',
|
||||
share=Button(
|
||||
file='./assets/share/rogue/blessing/BLESSING_STABLE_FLAG.png',
|
||||
area=(846, 520, 896, 542),
|
||||
search=(826, 500, 916, 562),
|
||||
color=(250, 250, 250),
|
||||
button=(846, 520, 896, 542),
|
||||
),
|
||||
)
|
||||
BOTTOM_WHITE_BAR = ButtonWrapper(
|
||||
name='BOTTOM_WHITE_BAR',
|
||||
share=Button(
|
||||
file='./assets/share/rogue/blessing/BOTTOM_WHITE_BAR.png',
|
||||
area=(166, 520, 1114, 542),
|
||||
search=(146, 500, 1134, 562),
|
||||
color=(210, 211, 211),
|
||||
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(
|
||||
file='./assets/share/rogue/blessing/OCR_RESET_COUNT.png',
|
||||
area=(655, 593, 873, 623),
|
||||
search=(635, 573, 893, 643),
|
||||
color=(23, 24, 26),
|
||||
button=(655, 593, 873, 623),
|
||||
),
|
||||
)
|
||||
OCR_ROGUE_BUFF = ButtonWrapper(
|
||||
name='OCR_ROGUE_BUFF',
|
||||
share=Button(
|
||||
file='./assets/share/rogue/blessing/OCR_ROGUE_BUFF.png',
|
||||
area=(155, 140, 1123, 348),
|
||||
search=(135, 120, 1143, 368),
|
||||
color=(80, 87, 106),
|
||||
button=(155, 140, 1123, 348),
|
||||
),
|
||||
)
|
25
tasks/rogue/assets/assets_rogue_bonus.py
Normal file
@ -0,0 +1,25 @@
|
||||
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 ```
|
||||
|
||||
BONUS_BOTTOM_WHITE_BAR = ButtonWrapper(
|
||||
name='BONUS_BOTTOM_WHITE_BAR',
|
||||
share=Button(
|
||||
file='./assets/share/rogue/bonus/BONUS_BOTTOM_WHITE_BAR.png',
|
||||
area=(731, 568, 774, 590),
|
||||
search=(711, 548, 794, 610),
|
||||
color=(250, 250, 250),
|
||||
button=(731, 568, 774, 590),
|
||||
),
|
||||
)
|
||||
BONUS_CONFIRM = ButtonWrapper(
|
||||
name='BONUS_CONFIRM',
|
||||
share=Button(
|
||||
file='./assets/share/rogue/bonus/BONUS_CONFIRM.png',
|
||||
area=(504, 629, 620, 677),
|
||||
search=(484, 609, 640, 697),
|
||||
color=(222, 224, 224),
|
||||
button=(504, 629, 620, 677),
|
||||
),
|
||||
)
|
25
tasks/rogue/assets/assets_rogue_curio.py
Normal file
@ -0,0 +1,25 @@
|
||||
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 ```
|
||||
|
||||
CURIO_ENFORCE = ButtonWrapper(
|
||||
name='CURIO_ENFORCE',
|
||||
share=Button(
|
||||
file='./assets/share/rogue/curio/CURIO_ENFORCE.png',
|
||||
area=(465, 114, 815, 545),
|
||||
search=(445, 94, 835, 565),
|
||||
color=(80, 66, 61),
|
||||
button=(465, 114, 815, 545),
|
||||
),
|
||||
)
|
||||
OCR_ROGUE_CURIO = ButtonWrapper(
|
||||
name='OCR_ROGUE_CURIO',
|
||||
share=Button(
|
||||
file='./assets/share/rogue/curio/OCR_ROGUE_CURIO.png',
|
||||
area=(87, 128, 1203, 187),
|
||||
search=(67, 108, 1223, 207),
|
||||
color=(18, 19, 20),
|
||||
button=(87, 128, 1203, 187),
|
||||
),
|
||||
)
|
105
tasks/rogue/assets/assets_rogue_ui.py
Normal file
@ -0,0 +1,105 @@
|
||||
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 ```
|
||||
|
||||
BLESSING_CONFIRM = ButtonWrapper(
|
||||
name='BLESSING_CONFIRM',
|
||||
share=Button(
|
||||
file='./assets/share/rogue/ui/BLESSING_CONFIRM.png',
|
||||
area=(960, 629, 1233, 677),
|
||||
search=(940, 609, 1253, 697),
|
||||
color=(217, 218, 218),
|
||||
button=(960, 629, 1233, 677),
|
||||
),
|
||||
)
|
||||
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=(61, 58, 52),
|
||||
button=(946, 17, 986, 57),
|
||||
),
|
||||
)
|
||||
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),
|
||||
),
|
||||
)
|
||||
FLAG_UNRECORD = ButtonWrapper(
|
||||
name='FLAG_UNRECORD',
|
||||
share=Button(
|
||||
file='./assets/share/rogue/ui/FLAG_UNRECORD.png',
|
||||
area=(746, 149, 778, 181),
|
||||
search=(726, 129, 798, 201),
|
||||
color=(133, 130, 161),
|
||||
button=(746, 149, 778, 181),
|
||||
),
|
||||
)
|
||||
OBTAIN_ITEM_POPUP = ButtonWrapper(
|
||||
name='OBTAIN_ITEM_POPUP',
|
||||
share=Button(
|
||||
file='./assets/share/rogue/ui/OBTAIN_ITEM_POPUP.png',
|
||||
area=(180, 573, 432, 720),
|
||||
search=(160, 553, 452, 720),
|
||||
color=(131, 109, 73),
|
||||
button=(180, 573, 432, 720),
|
||||
),
|
||||
)
|
||||
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_BONUS = ButtonWrapper(
|
||||
name='PAGE_CHOOSE_BONUS',
|
||||
share=Button(
|
||||
file='./assets/share/rogue/ui/PAGE_CHOOSE_BONUS.png',
|
||||
area=(503, 180, 555, 230),
|
||||
search=(483, 160, 575, 250),
|
||||
color=(33, 29, 54),
|
||||
button=(503, 180, 555, 230),
|
||||
),
|
||||
)
|
||||
PAGE_CHOOSE_BUFF = ButtonWrapper(
|
||||
name='PAGE_CHOOSE_BUFF',
|
||||
share=Button(
|
||||
file='./assets/share/rogue/ui/PAGE_CHOOSE_BUFF.png',
|
||||
area=(1020, 78, 1160, 96),
|
||||
search=(1000, 58, 1180, 116),
|
||||
color=(38, 39, 41),
|
||||
button=(1020, 78, 1160, 96),
|
||||
),
|
||||
)
|
||||
PAGE_CHOOSE_CURIO = ButtonWrapper(
|
||||
name='PAGE_CHOOSE_CURIO',
|
||||
share=Button(
|
||||
file='./assets/share/rogue/ui/PAGE_CHOOSE_CURIO.png',
|
||||
area=(988, 17, 1028, 57),
|
||||
search=(968, 0, 1048, 77),
|
||||
color=(40, 39, 34),
|
||||
button=(988, 17, 1028, 57),
|
||||
),
|
||||
)
|
||||
PAGE_EVENT = ButtonWrapper(
|
||||
name='PAGE_EVENT',
|
||||
share=Button(
|
||||
file='./assets/share/rogue/ui/PAGE_EVENT.png',
|
||||
area=(983, 485, 1007, 509),
|
||||
search=(963, 465, 1027, 529),
|
||||
color=(51, 48, 42),
|
||||
button=(983, 485, 1007, 509),
|
||||
),
|
||||
)
|
322
tasks/rogue/blessing.py
Normal file
@ -0,0 +1,322 @@
|
||||
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
|
||||
from module.ocr.ocr import Ocr, OcrResultButton, DigitCounter, Digit
|
||||
from module.ocr.utils import split_and_pair_buttons
|
||||
from tasks.rogue.assets.assets_rogue_blessing import *
|
||||
from tasks.rogue.assets.assets_rogue_ui import BLESSING_CONFIRM
|
||||
from tasks.rogue.keywords import *
|
||||
from tasks.rogue.preset import *
|
||||
from tasks.rogue.selector import RogueSelector
|
||||
from tasks.rogue.utils import get_regex_from_keyword_name, parse_name, is_card_selected
|
||||
|
||||
# normal blessing filter
|
||||
# path name
|
||||
pattern = ""
|
||||
BLESSING_FILTER_ATTR = tuple()
|
||||
PATH_ATTR_NAME = 'path_name'
|
||||
path_regex = get_regex_from_keyword_name(RoguePath, PATH_ATTR_NAME)
|
||||
pattern += path_regex
|
||||
# remove 'the' in path 'the hunt'
|
||||
pattern = pattern.lower().replace('the', '')
|
||||
BLESSING_FILTER_ATTR += (PATH_ATTR_NAME,)
|
||||
|
||||
# rarity
|
||||
pattern += "([123])?-?"
|
||||
BLESSING_FILTER_ATTR += ("rarity",)
|
||||
|
||||
# blessing name
|
||||
BLESSING_ATTR_NAME = 'blessing_name'
|
||||
blessing_regex = get_regex_from_keyword_name(RogueBlessing, BLESSING_ATTR_NAME)
|
||||
pattern += blessing_regex
|
||||
BLESSING_FILTER_ATTR += (BLESSING_ATTR_NAME,)
|
||||
|
||||
# enhanced
|
||||
ENHANCEMENT_ATTR_NAME = "enhancement"
|
||||
enhancement_regex = get_regex_from_keyword_name(RogueEnhancement, "enhancement_keyword")
|
||||
pattern += enhancement_regex
|
||||
BLESSING_FILTER_ATTR += (ENHANCEMENT_ATTR_NAME,)
|
||||
|
||||
FILETER_REGEX = re.compile(pattern)
|
||||
BLESSING_FILTER_PRESET = ("reset", "random", "unrecorded")
|
||||
BLESSING_FILTER = MultiLangFilter(FILETER_REGEX, BLESSING_FILTER_ATTR, BLESSING_FILTER_PRESET)
|
||||
|
||||
# resonance filter
|
||||
RESONANCE_ATTR_NAME = 'resonance_name'
|
||||
pattern = get_regex_from_keyword_name(RogueResonance, RESONANCE_ATTR_NAME)
|
||||
|
||||
FILETER_REGEX = re.compile(pattern)
|
||||
RESONANCE_FILTER_PRESET = ("random", "unrecorded")
|
||||
RESONANCE_FILTER = MultiLangFilter(FILETER_REGEX, (RESONANCE_ATTR_NAME,), RESONANCE_FILTER_PRESET)
|
||||
|
||||
|
||||
class RogueBuffOcr(Ocr):
|
||||
merge_thres_x = 40
|
||||
merge_thres_y = 20
|
||||
|
||||
def after_process(self, result):
|
||||
result = super().after_process(result)
|
||||
if self.lang == 'ch':
|
||||
replace_pattern_dict = {
|
||||
"蓬失": "蓬矢",
|
||||
"柘弓危失": "柘弓危矢",
|
||||
"飞虹珠?凿?齿": "飞虹诛凿齿",
|
||||
"天培步危": "天棓步危",
|
||||
"云[摘销锅]?逐步离": "云镝逐步离",
|
||||
"制桑": "制穹桑",
|
||||
"乌号基": "乌号綦",
|
||||
"追摩物": "追孽物",
|
||||
"特月": "狩月",
|
||||
"彤弓素增?": "彤弓素矰",
|
||||
"白决射御": "白矢决射御",
|
||||
"苦表": "苦衷",
|
||||
"[沦沧]肌髓": "沦浃肌髓",
|
||||
"进发": "迸发",
|
||||
"永缩体": "永坍缩体",
|
||||
"完美体验:绒默": "完美体验:缄默",
|
||||
"灭回归不等式": "湮灭回归不等式",
|
||||
r".*灾$": "禳灾",
|
||||
"虚安供品": "虚妄供品",
|
||||
"原初的苦$": "原初的苦衷",
|
||||
"厌离邪苦": "厌离邪秽苦",
|
||||
r".*繁.*": "葳蕤繁祉,延彼遐龄",
|
||||
}
|
||||
for pat, replace in replace_pattern_dict.items():
|
||||
result = re.sub(pat, replace, result)
|
||||
return result
|
||||
|
||||
|
||||
class RogueBlessingSelector(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.main.image_color_count(BOTTOM_WHITE_BAR.area, color=(255, 255, 255), count=5000):
|
||||
return 0
|
||||
color = get_color(self.main.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 recognition(self):
|
||||
def not_enhancement_keyword(keyword):
|
||||
return keyword != KEYWORDS_ROGUE_ENHANCEMENT.Already_Enhanced
|
||||
|
||||
self.ocr_results = []
|
||||
self._wait_until_blessing_loaded()
|
||||
ocr = RogueBuffOcr(OCR_ROGUE_BUFF)
|
||||
results = ocr.matched_ocr(self.main.device.image,
|
||||
[RogueBlessing, RogueResonance, RogueEnhancement])
|
||||
|
||||
enhanced_blessing = [result for result, _ in
|
||||
split_and_pair_buttons(results, split_func=not_enhancement_keyword,
|
||||
relative_area=(-300, -720, 0, 0))]
|
||||
results = [result for result in results if not_enhancement_keyword(result)]
|
||||
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.")
|
||||
for result in results:
|
||||
if result in enhanced_blessing:
|
||||
result.matched_keyword.enhancement = KEYWORDS_ROGUE_ENHANCEMENT.Already_Enhanced.enhancement_keyword
|
||||
self.ocr_results = results
|
||||
return results
|
||||
|
||||
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
|
||||
So this method provides a hard code way to choose one, which fit in case when blessing num is 1-3
|
||||
"""
|
||||
|
||||
def is_select_blessing_complete():
|
||||
"""
|
||||
Case 1: back to main page
|
||||
Case 2: choose curio
|
||||
Case 3: another choose blessings, but no blessing is selected when the new selection page loaded
|
||||
Case 4: event ui
|
||||
"""
|
||||
if self.main.is_in_main():
|
||||
logger.info("Main page checked")
|
||||
return True
|
||||
if self.main.is_page_choose_curio():
|
||||
logger.info("Choose curio page checked")
|
||||
return True
|
||||
if self.main.is_page_choose_blessing() and not is_card_selected(self.main, target, BLESSING_CONFIRM):
|
||||
logger.info("A new choose blessing page checked")
|
||||
return True
|
||||
if self.main.is_page_event():
|
||||
logger.info("Event page checked")
|
||||
return True
|
||||
return False
|
||||
|
||||
interval = Timer(1)
|
||||
enforce = False
|
||||
|
||||
if not target:
|
||||
enforce = True
|
||||
|
||||
# start -> selected
|
||||
while 1:
|
||||
if skip_first_screenshot:
|
||||
skip_first_screenshot = False
|
||||
else:
|
||||
self.main.device.screenshot()
|
||||
|
||||
if is_card_selected(self.main, target, confirm_button=BLESSING_CONFIRM):
|
||||
if enforce:
|
||||
logger.info("Buff selected (enforce)")
|
||||
else:
|
||||
logger.info(f"Buff {target} selected")
|
||||
break
|
||||
if interval.reached():
|
||||
if enforce:
|
||||
self.main.device.click(BLESSING_ENFORCE)
|
||||
else:
|
||||
self.main.device.click(target)
|
||||
interval.reset()
|
||||
|
||||
skip_first_screenshot = True
|
||||
# selected -> confirm
|
||||
while 1:
|
||||
if skip_first_screenshot:
|
||||
skip_first_screenshot = False
|
||||
else:
|
||||
self.main.device.screenshot()
|
||||
|
||||
if is_select_blessing_complete():
|
||||
logger.info("Select blessing complete")
|
||||
break
|
||||
if interval.reached():
|
||||
self.main.device.click(BLESSING_CONFIRM)
|
||||
interval.reset()
|
||||
|
||||
def _get_reset_count(self):
|
||||
current, _, _ = DigitCounter(OCR_RESET_COUNT).ocr_single_line(self.main.device.image)
|
||||
return current
|
||||
|
||||
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()
|
||||
while 1:
|
||||
self.main.device.screenshot()
|
||||
blessing_count = self.get_blessing_count()
|
||||
|
||||
if timeout.reached():
|
||||
logger.warning('Wait blessing page loaded timeout')
|
||||
break
|
||||
|
||||
if previous_count and previous_count == blessing_count:
|
||||
if timer.reached():
|
||||
logger.info('Blessing page stabled')
|
||||
break
|
||||
else:
|
||||
previous_count = blessing_count
|
||||
timer.reset()
|
||||
|
||||
def reset_blessing_list(self, skip_first_screenshot=True):
|
||||
if not self.main.is_page_choose_blessing():
|
||||
return False
|
||||
|
||||
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.main.device.image)
|
||||
if reset_cost > self.main.cosmic_fragment:
|
||||
logger.info("Does not have enough cosmic fragment")
|
||||
return False
|
||||
|
||||
interval = Timer(1)
|
||||
while 1:
|
||||
if skip_first_screenshot:
|
||||
skip_first_screenshot = False
|
||||
else:
|
||||
self.main.device.screenshot()
|
||||
|
||||
new_count = self._get_reset_count()
|
||||
|
||||
if reset_count - new_count == 1:
|
||||
logger.info("Reset once")
|
||||
break
|
||||
if interval.reached():
|
||||
self.main.device.click(BLESSING_RESET)
|
||||
interval.reset()
|
||||
return True
|
||||
|
||||
def load_filter(self):
|
||||
keyword = self.ocr_results[0].matched_keyword
|
||||
if not isinstance(keyword, (RogueBlessing, RogueResonance)):
|
||||
return
|
||||
filter_configs = {
|
||||
RogueBlessing: {
|
||||
"filter_": BLESSING_FILTER,
|
||||
"preset_config": self.main.config.Rogue_PresetBlessingFilter,
|
||||
"strategy_config": self.main.config.Rogue_BlessingSelectionStrategy,
|
||||
"preset_values": {
|
||||
'preset-1': BLESSING_PRESET_1,
|
||||
'custom': self.main.config.Rogue_CustomBlessingFilter
|
||||
},
|
||||
},
|
||||
RogueResonance: {
|
||||
"filter_": RESONANCE_FILTER,
|
||||
"preset_config": self.main.config.Rogue_PresetResonanceFilter,
|
||||
"strategy_config": self.main.config.Rogue_ResonanceSelectionStrategy,
|
||||
"preset_values": {
|
||||
'preset-1': RESONANCE_PRESET_1,
|
||||
'custom': self.main.config.Rogue_PresetResonanceFilter,
|
||||
},
|
||||
}
|
||||
}
|
||||
# preset
|
||||
config = filter_configs[type(keyword)]
|
||||
filter_ = config['filter_']
|
||||
preset_config = config['preset_config']
|
||||
preset_values = config['preset_values']
|
||||
string = preset_values[preset_config]
|
||||
string = parse_name(string)
|
||||
|
||||
# strategy
|
||||
strategy_config = config['strategy_config']
|
||||
if strategy_config == 'unrecorded-first':
|
||||
string = "unrecorded > " + string
|
||||
if strategy_config == 'before-random':
|
||||
string = string.replace('random', 'unrecorded > random')
|
||||
|
||||
filter_.load(string)
|
||||
self.filter_ = filter_
|
||||
|
||||
def try_select(self, option: OcrResultButton | str):
|
||||
if isinstance(option, str):
|
||||
if option.lower() == 'reset':
|
||||
if self.reset_blessing_list():
|
||||
self.recognize_and_select()
|
||||
return True
|
||||
if option.lower() == 'random':
|
||||
choose = np.random.choice(self.ocr_results)
|
||||
self.ui_select(choose)
|
||||
return True
|
||||
if option.lower() == 'unrecorded':
|
||||
for result in self.ocr_results:
|
||||
if self.main.is_unrecorded(result, (0, -720, 300, 0)):
|
||||
self.ui_select(result)
|
||||
return True
|
||||
return False
|
||||
|
||||
if isinstance(option, OcrResultButton):
|
||||
self.ui_select(option)
|
||||
return True
|
||||
return False
|
90
tasks/rogue/bonus.py
Normal file
@ -0,0 +1,90 @@
|
||||
import numpy as np
|
||||
|
||||
from module.base.timer import Timer
|
||||
from module.logger import logger
|
||||
from module.ocr.ocr import OcrResultButton
|
||||
from tasks.rogue.assets.assets_rogue_blessing import OCR_ROGUE_BUFF
|
||||
from tasks.rogue.assets.assets_rogue_bonus import BONUS_BOTTOM_WHITE_BAR, BONUS_CONFIRM
|
||||
from tasks.rogue.keywords import RogueBonus
|
||||
from tasks.rogue.selector import RogueSelector
|
||||
from tasks.rogue.ui import RogueBonusOcr
|
||||
from tasks.rogue.utils import is_card_selected
|
||||
|
||||
|
||||
class RogueBonusSelector(RogueSelector):
|
||||
def _wait_bonus_page_loaded(self, timer=Timer(0.3, count=1), timeout=Timer(5, count=10)):
|
||||
timer.reset()
|
||||
timeout.reset()
|
||||
while 1:
|
||||
self.main.device.screenshot()
|
||||
|
||||
if timeout.reached():
|
||||
logger.warning('Wait bonus page loaded timeout')
|
||||
break
|
||||
|
||||
if self.main.appear(BONUS_BOTTOM_WHITE_BAR):
|
||||
if timer.reached():
|
||||
logger.info('Bonus page stabled')
|
||||
break
|
||||
else:
|
||||
timer.reset()
|
||||
|
||||
def recognition(self):
|
||||
self._wait_bonus_page_loaded()
|
||||
ocr = RogueBonusOcr(OCR_ROGUE_BUFF)
|
||||
results = ocr.matched_ocr(self.main.device.image, [RogueBonus])
|
||||
expected_count = 3
|
||||
if expected_count != len(results):
|
||||
logger.warning(f"The OCR result does not match the bonus count. "
|
||||
f"Expect {expected_count}, but recognized {len(results)} only.")
|
||||
self.ocr_results = results
|
||||
return results
|
||||
|
||||
def ui_select(self, target: OcrResultButton | None, skip_first_screenshot=True):
|
||||
interval = Timer(1)
|
||||
# start -> select
|
||||
while 1:
|
||||
if skip_first_screenshot:
|
||||
skip_first_screenshot = False
|
||||
else:
|
||||
self.main.device.screenshot()
|
||||
|
||||
if is_card_selected(self.main, target, confirm_button=BONUS_CONFIRM):
|
||||
break
|
||||
if interval.reached():
|
||||
self.main.device.click(target)
|
||||
interval.reset()
|
||||
|
||||
skip_first_screenshot = True
|
||||
# select -> confirm
|
||||
while 1:
|
||||
if skip_first_screenshot:
|
||||
skip_first_screenshot = False
|
||||
else:
|
||||
self.main.device.screenshot()
|
||||
|
||||
if self.main.is_in_main():
|
||||
logger.info("Main Page Checked")
|
||||
break
|
||||
if self.main.is_page_choose_curio():
|
||||
logger.info("Choose curio page checked")
|
||||
break
|
||||
if self.main.is_page_choose_blessing():
|
||||
logger.info("Choose blessing page checked")
|
||||
break
|
||||
if interval.reached():
|
||||
self.main.device.click(BONUS_CONFIRM)
|
||||
interval.reset()
|
||||
|
||||
def recognize_and_select(self):
|
||||
self.recognition()
|
||||
if not self.ocr_results:
|
||||
self.ui_select(None)
|
||||
options = {result.matched_keyword.en: result for result in self.ocr_results}
|
||||
if self.main.config.Rogue_Bonus not in options.keys():
|
||||
logger.warning(f"Can not find option: {self.main.config.Rogue_Bonus}, randomly choose one")
|
||||
target = np.random.choice(options)
|
||||
else:
|
||||
target = options[self.main.config.Rogue_Bonus]
|
||||
logger.info(f"Choose bonus: {target}")
|
||||
self.ui_select(target)
|
142
tasks/rogue/curio.py
Normal file
@ -0,0 +1,142 @@
|
||||
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
|
||||
from module.ocr.ocr import Ocr, OcrResultButton
|
||||
from tasks.rogue.assets.assets_rogue_curio import *
|
||||
from tasks.rogue.assets.assets_rogue_ui import BLESSING_CONFIRM
|
||||
from tasks.rogue.keywords import RogueCurio
|
||||
from tasks.rogue.preset import CURIO_PRESET_1
|
||||
from tasks.rogue.selector import RogueSelector
|
||||
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', 'unrecorded')
|
||||
FILTER_REGEX = re.compile(pattern)
|
||||
CURIO_FILTER = MultiLangFilter(FILTER_REGEX, CURIO_FILTER_ATTR, CURIO_FILTER_PRESET)
|
||||
|
||||
|
||||
class RogueCurioOcr(Ocr):
|
||||
merge_thres_y = 40
|
||||
|
||||
def after_process(self, result):
|
||||
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 RogueCurioSelector(RogueSelector):
|
||||
def recognition(self):
|
||||
self.ocr_results = []
|
||||
ocr = RogueCurioOcr(OCR_ROGUE_CURIO)
|
||||
results = ocr.matched_ocr(self.main.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_results = results
|
||||
return results
|
||||
|
||||
def ui_select(self, target: OcrResultButton | None, skip_first_screenshot=True):
|
||||
def is_curio_selected():
|
||||
return np.mean(get_color(self.main.device.image, tuple(target.area))) > 60 # shiny background
|
||||
|
||||
def is_select_curio_complete():
|
||||
"""
|
||||
Case 1: back to main page
|
||||
Case 2: event page
|
||||
"""
|
||||
if self.main.is_in_main():
|
||||
logger.info("Main page checked")
|
||||
return True
|
||||
if self.main.is_page_event():
|
||||
logger.info("Event page checked")
|
||||
return True
|
||||
return False
|
||||
|
||||
enforce = False
|
||||
if not target:
|
||||
enforce = True
|
||||
interval = Timer(1)
|
||||
# start -> selected
|
||||
while 1:
|
||||
if skip_first_screenshot:
|
||||
skip_first_screenshot = False
|
||||
else:
|
||||
self.main.device.screenshot()
|
||||
|
||||
if is_curio_selected():
|
||||
if enforce:
|
||||
logger.info("Curio selected (enforce)")
|
||||
else:
|
||||
logger.info(f"Curio {target} selected")
|
||||
break
|
||||
if interval.reached():
|
||||
if enforce:
|
||||
self.main.device.click(CURIO_ENFORCE)
|
||||
else:
|
||||
self.main.device.click(target)
|
||||
interval.reset()
|
||||
|
||||
skip_first_screenshot = True
|
||||
# selected -> confirm
|
||||
while 1:
|
||||
if skip_first_screenshot:
|
||||
skip_first_screenshot = False
|
||||
else:
|
||||
self.main.device.screenshot()
|
||||
|
||||
if is_select_curio_complete():
|
||||
break
|
||||
if interval.reached():
|
||||
self.main.device.click(BLESSING_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 option == 'unrecorded':
|
||||
for result in self.ocr_results:
|
||||
if self.main.is_unrecorded(result, (0, -720, 300, 0)):
|
||||
self.ui_select(result)
|
||||
return True
|
||||
return False
|
||||
|
||||
if isinstance(option, OcrResultButton):
|
||||
self.ui_select(option)
|
||||
return True
|
||||
return False
|
||||
|
||||
def load_filter(self):
|
||||
filter_ = CURIO_FILTER
|
||||
string = ""
|
||||
match self.main.config.Rogue_PresetCurioFilter:
|
||||
case 'preset-1':
|
||||
string = CURIO_PRESET_1
|
||||
case 'custom':
|
||||
string = self.main.config.Rogue_CustomCurioFilter
|
||||
string = parse_name(string)
|
||||
|
||||
match self.main.config.Rogue_CurioSelectionStrategy:
|
||||
case 'unrecorded-first':
|
||||
string = 'unrecorded > ' + string
|
||||
case 'before-random':
|
||||
string = string.replace('random', 'unrecorded > random')
|
||||
|
||||
filter_.load(string)
|
||||
self.filter_ = filter_
|
9
tasks/rogue/keywords/__init__.py
Normal file
@ -0,0 +1,9 @@
|
||||
import tasks.rogue.keywords.blessing as KEYWORDS_ROGUE_BLESSING
|
||||
import tasks.rogue.keywords.bonus as KEYWORDS_ROGUE_BONUS
|
||||
import tasks.rogue.keywords.curio as KEYWORDS_ROGUE_CURIO
|
||||
import tasks.rogue.keywords.enhancement as KEYWORDS_ROGUE_ENHANCEMENT
|
||||
import tasks.rogue.keywords.path as KEYWORDS_ROGUE_PATH
|
||||
import tasks.rogue.keywords.resonance as KEYWORDS_ROGUE_RESONANCE
|
||||
|
||||
from tasks.rogue.keywords.classes import (RogueBlessing, RogueBonus, RogueEnhancement,
|
||||
RoguePath, RogueResonance, RogueCurio)
|
1391
tasks/rogue/keywords/blessing.py
Normal file
29
tasks/rogue/keywords/bonus.py
Normal file
@ -0,0 +1,29 @@
|
||||
from .classes import RogueBonus
|
||||
|
||||
# This file was auto-generated, do not modify it manually. To generate:
|
||||
# ``` python -m dev_tools.keyword_extract ```
|
||||
|
||||
Fragmented_Cosmos = RogueBonus(
|
||||
id=1,
|
||||
name='Fragmented_Cosmos',
|
||||
cn='破碎宇宙',
|
||||
cht='破碎宇宙',
|
||||
en='Fragmented Cosmos',
|
||||
jp='破裂した宇宙',
|
||||
)
|
||||
Blessing_Cosmos = RogueBonus(
|
||||
id=2,
|
||||
name='Blessing_Cosmos',
|
||||
cn='祝福宇宙',
|
||||
cht='祝福宇宙',
|
||||
en='Blessing Cosmos',
|
||||
jp='祝福された宇宙',
|
||||
)
|
||||
Miracle_Cosmos = RogueBonus(
|
||||
id=3,
|
||||
name='Miracle_Cosmos',
|
||||
cn='神奇宇宙',
|
||||
cht='神奇宇宙',
|
||||
en='Miracle Cosmos',
|
||||
jp='奇跡的な宇宙',
|
||||
)
|
70
tasks/rogue/keywords/classes.py
Normal file
@ -0,0 +1,70 @@
|
||||
from dataclasses import dataclass
|
||||
from typing import ClassVar
|
||||
|
||||
from dev_tools.keyword_extract import UI_LANGUAGES
|
||||
from module.ocr.keyword import Keyword
|
||||
|
||||
|
||||
@dataclass(repr=False)
|
||||
class RogueBlessing(Keyword):
|
||||
instances: ClassVar = {}
|
||||
path_id: int
|
||||
rarity: int
|
||||
enhancement: str
|
||||
|
||||
@property
|
||||
def path_name(self):
|
||||
path = RoguePath.instances[self.path_id]
|
||||
return path.path_name
|
||||
|
||||
@property
|
||||
def blessing_name(self):
|
||||
return [self.__getattribute__(f"{server}_parsed")
|
||||
for server in UI_LANGUAGES if hasattr(self, f"{server}_parsed")]
|
||||
|
||||
|
||||
@dataclass(repr=False)
|
||||
class RoguePath(Keyword):
|
||||
instances: ClassVar = {}
|
||||
|
||||
@property
|
||||
def path_name(self):
|
||||
return [self.__getattribute__(f"{server}_parsed").replace("the", '')
|
||||
for server in UI_LANGUAGES if hasattr(self, f"{server}_parsed")]
|
||||
|
||||
|
||||
@dataclass(repr=False)
|
||||
class RogueResonance(Keyword):
|
||||
instances: ClassVar = {}
|
||||
path_id: int
|
||||
rarity: int
|
||||
|
||||
@property
|
||||
def resonance_name(self):
|
||||
return [self.__getattribute__(f"{server}_parsed")
|
||||
for server in UI_LANGUAGES if hasattr(self, f"{server}_parsed")]
|
||||
|
||||
|
||||
@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")]
|
||||
|
||||
|
||||
@dataclass(repr=False)
|
||||
class RogueBonus(Keyword):
|
||||
instances: ClassVar = {}
|
||||
|
||||
|
||||
@dataclass(repr=False)
|
||||
class RogueEnhancement(Keyword):
|
||||
instances: ClassVar = {}
|
||||
|
||||
@property
|
||||
def enhancement_keyword(self):
|
||||
return [self.__getattribute__(f"{server}_parsed")
|
||||
for server in UI_LANGUAGES if hasattr(self, f"{server}_parsed")]
|
381
tasks/rogue/keywords/curio.py
Normal file
@ -0,0 +1,381 @@
|
||||
from .classes import RogueCurio
|
||||
|
||||
# This file was auto-generated, do not modify it manually. To generate:
|
||||
# ``` python -m dev_tools.keyword_extract ```
|
||||
|
||||
Dimension_Reduction_Dice = RogueCurio(
|
||||
id=1,
|
||||
name='Dimension_Reduction_Dice',
|
||||
cn='降维骰子',
|
||||
cht='降維骰子',
|
||||
en='Dimension Reduction Dice',
|
||||
jp='次元削減ダイス',
|
||||
)
|
||||
Chaos_Trametes = RogueCurio(
|
||||
id=2,
|
||||
name='Chaos_Trametes',
|
||||
cn='混沌云芝',
|
||||
cht='混沌雲芝',
|
||||
en='Chaos Trametes',
|
||||
jp='混沌の雲芝',
|
||||
)
|
||||
Warping_Compound_Eye = RogueCurio(
|
||||
id=3,
|
||||
name='Warping_Compound_Eye',
|
||||
cn='跃迁复眼',
|
||||
cht='躍遷複眼',
|
||||
en='Warping Compound Eye',
|
||||
jp='跳躍複眼',
|
||||
)
|
||||
Fruit_of_the_Alien_Tree = RogueCurio(
|
||||
id=4,
|
||||
name='Fruit_of_the_Alien_Tree',
|
||||
cn='异木果实',
|
||||
cht='異木果實',
|
||||
en='Fruit of the Alien Tree',
|
||||
jp='異木の果実',
|
||||
)
|
||||
Casket_of_Inaccuracy = RogueCurio(
|
||||
id=5,
|
||||
name='Casket_of_Inaccuracy',
|
||||
cn='测不准匣',
|
||||
cht='測不準匣',
|
||||
en='Casket of Inaccuracy',
|
||||
jp='不確定の匣',
|
||||
)
|
||||
Ambergris_Cheese = RogueCurio(
|
||||
id=6,
|
||||
name='Ambergris_Cheese',
|
||||
cn='香涎干酪',
|
||||
cht='香涎乾酪',
|
||||
en='Ambergris Cheese',
|
||||
jp='香涎チーズ',
|
||||
)
|
||||
Fortune_Glue = RogueCurio(
|
||||
id=7,
|
||||
name='Fortune_Glue',
|
||||
cn='福灵胶',
|
||||
cht='福靈膠',
|
||||
en='Fortune Glue',
|
||||
jp='幸福クリーム',
|
||||
)
|
||||
The_Parchment_That_Always_Eats = RogueCurio(
|
||||
id=8,
|
||||
name='The_Parchment_That_Always_Eats',
|
||||
cn='永不停嘴的羊皮卷',
|
||||
cht='永不停嘴的羊皮卷',
|
||||
en='The Parchment That Always Eats',
|
||||
jp='おしゃべり羊皮紙',
|
||||
)
|
||||
Broken_Cuckoo_Clock = RogueCurio(
|
||||
id=9,
|
||||
name='Broken_Cuckoo_Clock',
|
||||
cn='破碎咕咕钟',
|
||||
cht='破碎咕咕鐘',
|
||||
en='Broken Cuckoo Clock',
|
||||
jp='壊れた鳩時計',
|
||||
)
|
||||
Mechanical_Cuckoo_Clock = RogueCurio(
|
||||
id=10,
|
||||
name='Mechanical_Cuckoo_Clock',
|
||||
cn='机械咕咕钟',
|
||||
cht='機械咕咕鐘',
|
||||
en='Mechanical Cuckoo Clock',
|
||||
jp='機械式鳩時計',
|
||||
)
|
||||
The_Doctor_Robe = RogueCurio(
|
||||
id=11,
|
||||
name='The_Doctor_Robe',
|
||||
cn='博士之袍',
|
||||
cht='博士之袍',
|
||||
en="The Doctor's Robe",
|
||||
jp='博士のローブ',
|
||||
)
|
||||
Society_Ticket = RogueCurio(
|
||||
id=12,
|
||||
name='Society_Ticket',
|
||||
cn='俱乐部券',
|
||||
cht='俱樂部券',
|
||||
en='Society Ticket',
|
||||
jp='クラブチケット',
|
||||
)
|
||||
Faith_Bond = RogueCurio(
|
||||
id=13,
|
||||
name='Faith_Bond',
|
||||
cn='信仰债券',
|
||||
cht='信仰債券',
|
||||
en='Faith Bond',
|
||||
jp='信仰債券',
|
||||
)
|
||||
Robe_of_The_Beauty = RogueCurio(
|
||||
id=14,
|
||||
name='Robe_of_The_Beauty',
|
||||
cn='纯美之袍',
|
||||
cht='純美之袍',
|
||||
en='Robe of The Beauty',
|
||||
jp='純美のローブ',
|
||||
)
|
||||
Gold_Coin_of_Discord = RogueCurio(
|
||||
id=15,
|
||||
name='Gold_Coin_of_Discord',
|
||||
cn='分裂金币',
|
||||
cht='分裂金幣',
|
||||
en='Gold Coin of Discord',
|
||||
jp='分裂金貨',
|
||||
)
|
||||
Useless_Typewriter = RogueCurio(
|
||||
id=16,
|
||||
name='Useless_Typewriter',
|
||||
cn='无效文字打印机',
|
||||
cht='無效文字印表機',
|
||||
en='Useless Typewriter',
|
||||
jp='無効文字タイプライター',
|
||||
)
|
||||
Void_Wick_Trimmer = RogueCurio(
|
||||
id=17,
|
||||
name='Void_Wick_Trimmer',
|
||||
cn='空无烛剪',
|
||||
cht='空無燭剪',
|
||||
en='Void Wick Trimmer',
|
||||
jp='空無の芯切り',
|
||||
)
|
||||
Omniscient_Capsule = RogueCurio(
|
||||
id=18,
|
||||
name='Omniscient_Capsule',
|
||||
cn='万识囊',
|
||||
cht='萬識囊',
|
||||
en='Omniscient Capsule',
|
||||
jp='全知袋',
|
||||
)
|
||||
Record_from_Beyond_the_Sky = RogueCurio(
|
||||
id=19,
|
||||
name='Record_from_Beyond_the_Sky',
|
||||
cn='天外重声大碟',
|
||||
cht='天外合唱專輯',
|
||||
en='Record from Beyond the Sky',
|
||||
jp='天外聖歌隊のレコード',
|
||||
)
|
||||
Entropic_Die = RogueCurio(
|
||||
id=20,
|
||||
name='Entropic_Die',
|
||||
cn='万象无常骰',
|
||||
cht='萬象無常骰',
|
||||
en='Entropic Die',
|
||||
jp='万象無常のサイコロ',
|
||||
)
|
||||
Shining_Trapezohedron_Die = RogueCurio(
|
||||
id=21,
|
||||
name='Shining_Trapezohedron_Die',
|
||||
cn='闪耀的偏方三八面骰',
|
||||
cht='閃耀的偏方三八面骰',
|
||||
en='Shining Trapezohedron Die',
|
||||
jp='輝くトラペゾヘドロンサイコロ',
|
||||
)
|
||||
Sealing_Wax_of_Preservation = RogueCurio(
|
||||
id=22,
|
||||
name='Sealing_Wax_of_Preservation',
|
||||
cn='存护火漆',
|
||||
cht='存護火漆',
|
||||
en='Sealing Wax of Preservation',
|
||||
jp='存護の封蝋',
|
||||
)
|
||||
Sealing_Wax_of_Elation = RogueCurio(
|
||||
id=23,
|
||||
name='Sealing_Wax_of_Elation',
|
||||
cn='欢愉火漆',
|
||||
cht='歡愉火漆',
|
||||
en='Sealing Wax of Elation',
|
||||
jp='愉悦の封蝋',
|
||||
)
|
||||
Sealing_Wax_of_The_Hunt = RogueCurio(
|
||||
id=24,
|
||||
name='Sealing_Wax_of_The_Hunt',
|
||||
cn='巡猎火漆',
|
||||
cht='巡獵火漆',
|
||||
en='Sealing Wax of The Hunt',
|
||||
jp='巡狩の封蝋',
|
||||
)
|
||||
Sealing_Wax_of_Destruction = RogueCurio(
|
||||
id=25,
|
||||
name='Sealing_Wax_of_Destruction',
|
||||
cn='毁灭火漆',
|
||||
cht='毀滅火漆',
|
||||
en='Sealing Wax of Destruction',
|
||||
jp='壊滅の封蝋',
|
||||
)
|
||||
Sealing_Wax_of_Remembrance = RogueCurio(
|
||||
id=26,
|
||||
name='Sealing_Wax_of_Remembrance',
|
||||
cn='记忆火漆',
|
||||
cht='記憶火漆',
|
||||
en='Sealing Wax of Remembrance',
|
||||
jp='記憶の封蝋',
|
||||
)
|
||||
Sealing_Wax_of_Nihility = RogueCurio(
|
||||
id=27,
|
||||
name='Sealing_Wax_of_Nihility',
|
||||
cn='虚无火漆',
|
||||
cht='虛無火漆',
|
||||
en='Sealing Wax of Nihility',
|
||||
jp='虚無の封蝋',
|
||||
)
|
||||
Sealing_Wax_of_Abundance = RogueCurio(
|
||||
id=28,
|
||||
name='Sealing_Wax_of_Abundance',
|
||||
cn='丰饶火漆',
|
||||
cht='豐饒火漆',
|
||||
en='Sealing Wax of Abundance',
|
||||
jp='豊穣の封蝋',
|
||||
)
|
||||
Corrupted_Code = RogueCurio(
|
||||
id=29,
|
||||
name='Corrupted_Code',
|
||||
cn='乱七八糟的代码',
|
||||
cht='亂七八糟的程式碼',
|
||||
en='Corrupted Code',
|
||||
jp='ぐちゃぐちゃなコード',
|
||||
)
|
||||
Odd_Code = RogueCurio(
|
||||
id=30,
|
||||
name='Odd_Code',
|
||||
cn='有点蹊跷的代码',
|
||||
cht='有點蹊蹺的程式碼',
|
||||
en='Odd Code',
|
||||
jp='少し怪しげなコード',
|
||||
)
|
||||
Normal_Code = RogueCurio(
|
||||
id=31,
|
||||
name='Normal_Code',
|
||||
cn='中规中矩的代码',
|
||||
cht='中規中矩的程式碼',
|
||||
en='Normal Code',
|
||||
jp='杓子定規なコード',
|
||||
)
|
||||
Elegant_Code = RogueCurio(
|
||||
id=32,
|
||||
name='Elegant_Code',
|
||||
cn='精确优雅的代码',
|
||||
cht='精確優雅的程式碼',
|
||||
en='Elegant Code',
|
||||
jp='正確で完璧なコード',
|
||||
)
|
||||
Mysterious_Code = RogueCurio(
|
||||
id=33,
|
||||
name='Mysterious_Code',
|
||||
cn='没有注释的代码',
|
||||
cht='沒有註解的程式碼',
|
||||
en='Mysterious Code',
|
||||
jp='注釈がないコード',
|
||||
)
|
||||
Infinitely_Recursive_Code = RogueCurio(
|
||||
id=34,
|
||||
name='Infinitely_Recursive_Code',
|
||||
cn='无限递归的代码',
|
||||
cht='無限遞迴的程式碼',
|
||||
en='Infinitely Recursive Code',
|
||||
jp='無限再帰するコード',
|
||||
)
|
||||
Shattered_Star_Bait = RogueCurio(
|
||||
id=35,
|
||||
name='Shattered_Star_Bait',
|
||||
cn='碎星芳饵',
|
||||
cht='碎星芳餌',
|
||||
en='Shattered Star Bait',
|
||||
jp='砕けた星の釣り餌',
|
||||
)
|
||||
Obliteration_Wick_Trimmer = RogueCurio(
|
||||
id=36,
|
||||
name='Obliteration_Wick_Trimmer',
|
||||
cn='湮灭烛剪',
|
||||
cht='湮滅燭剪',
|
||||
en='Obliteration Wick Trimmer',
|
||||
jp='湮滅の芯切り',
|
||||
)
|
||||
Insect_Web = RogueCurio(
|
||||
id=37,
|
||||
name='Insect_Web',
|
||||
cn='虫网',
|
||||
cht='蟲網',
|
||||
en='Insect Web',
|
||||
jp='虫網',
|
||||
)
|
||||
Angel_type_I_O_U_Dispenser = RogueCurio(
|
||||
id=38,
|
||||
name='Angel_type_I_O_U_Dispenser',
|
||||
cn='天使型谢债发行机',
|
||||
cht='天使型謝債發行機',
|
||||
en='Angel-type I.O.U. Dispenser',
|
||||
jp='天使型謝債発行機',
|
||||
)
|
||||
Laurel_Crown_of_Planar_Shifts = RogueCurio(
|
||||
id=39,
|
||||
name='Laurel_Crown_of_Planar_Shifts',
|
||||
cn='换境桂冠',
|
||||
cht='換境桂冠',
|
||||
en='Laurel Crown of Planar Shifts',
|
||||
jp='換境桂冠',
|
||||
)
|
||||
Space_Time_Prism = RogueCurio(
|
||||
id=40,
|
||||
name='Space_Time_Prism',
|
||||
cn='时空棱镜',
|
||||
cht='時空稜鏡',
|
||||
en='Space-Time Prism',
|
||||
jp='時空のプリズム',
|
||||
)
|
||||
Galactic_Big_Lotto = RogueCurio(
|
||||
id=41,
|
||||
name='Galactic_Big_Lotto',
|
||||
cn='银河大乐透',
|
||||
cht='銀河大樂透',
|
||||
en='Galactic Big Lotto',
|
||||
jp='銀河ビッグロッタリー',
|
||||
)
|
||||
Divination_Cuckoo_Clock = RogueCurio(
|
||||
id=42,
|
||||
name='Divination_Cuckoo_Clock',
|
||||
cn='卜筮咕咕钟',
|
||||
cht='卜筮咕咕鐘',
|
||||
en='Divination Cuckoo Clock',
|
||||
jp='占い鳩時計',
|
||||
)
|
||||
Black_Forest_Cuckoo_Clock = RogueCurio(
|
||||
id=43,
|
||||
name='Black_Forest_Cuckoo_Clock',
|
||||
cn='黑森林咕咕钟',
|
||||
cht='黑森林咕咕鐘',
|
||||
en='Black Forest Cuckoo Clock',
|
||||
jp='黒森鳩時計',
|
||||
)
|
||||
Perpetual_Motion_Cuckoo_Clock = RogueCurio(
|
||||
id=44,
|
||||
name='Perpetual_Motion_Cuckoo_Clock',
|
||||
cn='永动咕咕钟',
|
||||
cht='永動咕咕鐘',
|
||||
en='Perpetual Motion Cuckoo Clock',
|
||||
jp='永久鳩時計',
|
||||
)
|
||||
Punklorde_Mentality = RogueCurio(
|
||||
id=45,
|
||||
name='Punklorde_Mentality',
|
||||
cn='朋克洛德精神',
|
||||
cht='龐克洛德精神',
|
||||
en='Punklorde Mentality',
|
||||
jp='パンクロードの精神',
|
||||
)
|
||||
Beacon_Coloring_Paste = RogueCurio(
|
||||
id=46,
|
||||
name='Beacon_Coloring_Paste',
|
||||
cn='信标着色剂',
|
||||
cht='信標著色劑',
|
||||
en='Beacon Coloring Paste',
|
||||
jp='ビーコン着色剤',
|
||||
)
|
||||
IPC_Cuckoo_Clock = RogueCurio(
|
||||
id=47,
|
||||
name='IPC_Cuckoo_Clock',
|
||||
cn='公司咕咕钟',
|
||||
cht='公司咕咕鐘',
|
||||
en='IPC Cuckoo Clock',
|
||||
jp='カンパニー鳩時計',
|
||||
)
|
13
tasks/rogue/keywords/enhancement.py
Normal file
@ -0,0 +1,13 @@
|
||||
from .classes import RogueEnhancement
|
||||
|
||||
# This file was auto-generated, do not modify it manually. To generate:
|
||||
# ``` python -m dev_tools.keyword_extract ```
|
||||
|
||||
Already_Enhanced = RogueEnhancement(
|
||||
id=1,
|
||||
name='Already_Enhanced',
|
||||
cn='已强化',
|
||||
cht='已強化',
|
||||
en='Already Enhanced',
|
||||
jp='強化済み',
|
||||
)
|
61
tasks/rogue/keywords/path.py
Normal file
@ -0,0 +1,61 @@
|
||||
from .classes import RoguePath
|
||||
|
||||
# This file was auto-generated, do not modify it manually. To generate:
|
||||
# ``` python -m dev_tools.keyword_extract ```
|
||||
|
||||
Preservation = RoguePath(
|
||||
id=1,
|
||||
name='Preservation',
|
||||
cn='存护',
|
||||
cht='存護',
|
||||
en='Preservation',
|
||||
jp='存護',
|
||||
)
|
||||
Remembrance = RoguePath(
|
||||
id=2,
|
||||
name='Remembrance',
|
||||
cn='记忆',
|
||||
cht='記憶',
|
||||
en='Remembrance',
|
||||
jp='記憶',
|
||||
)
|
||||
Nihility = RoguePath(
|
||||
id=3,
|
||||
name='Nihility',
|
||||
cn='虚无',
|
||||
cht='虛無',
|
||||
en='Nihility',
|
||||
jp='虚無',
|
||||
)
|
||||
Abundance = RoguePath(
|
||||
id=4,
|
||||
name='Abundance',
|
||||
cn='丰饶',
|
||||
cht='豐饒',
|
||||
en='Abundance',
|
||||
jp='豊穣',
|
||||
)
|
||||
The_Hunt = RoguePath(
|
||||
id=5,
|
||||
name='The_Hunt',
|
||||
cn='巡猎',
|
||||
cht='巡獵',
|
||||
en='The Hunt',
|
||||
jp='巡狩',
|
||||
)
|
||||
Destruction = RoguePath(
|
||||
id=6,
|
||||
name='Destruction',
|
||||
cn='毁灭',
|
||||
cht='毀滅',
|
||||
en='Destruction',
|
||||
jp='壊滅',
|
||||
)
|
||||
Elation = RoguePath(
|
||||
id=7,
|
||||
name='Elation',
|
||||
cn='欢愉',
|
||||
cht='歡愉',
|
||||
en='Elation',
|
||||
jp='愉悦',
|
||||
)
|
285
tasks/rogue/keywords/resonance.py
Normal file
@ -0,0 +1,285 @@
|
||||
from .classes import RogueResonance
|
||||
|
||||
# This file was auto-generated, do not modify it manually. To generate:
|
||||
# ``` python -m dev_tools.keyword_extract ```
|
||||
|
||||
Path_Resonance_Preservation = RogueResonance(
|
||||
id=1,
|
||||
name='Path_Resonance_Preservation',
|
||||
cn='命途回响:「存护」',
|
||||
cht='命途迴響:「存護」',
|
||||
en='Path Resonance: Preservation',
|
||||
jp='運命の反響:「存護」',
|
||||
path_id=1,
|
||||
rarity=3,
|
||||
)
|
||||
Resonance_Formation_Zero_Dimensional_Reinforcement = RogueResonance(
|
||||
id=2,
|
||||
name='Resonance_Formation_Zero_Dimensional_Reinforcement',
|
||||
cn='回响构音:零维强化',
|
||||
cht='迴響構音:零維強化',
|
||||
en='Resonance Formation: Zero-Dimensional Reinforcement',
|
||||
jp='反響構音:析出硬化',
|
||||
path_id=1,
|
||||
rarity=3,
|
||||
)
|
||||
Resonance_Formation_Eutectic_Reaction = RogueResonance(
|
||||
id=3,
|
||||
name='Resonance_Formation_Eutectic_Reaction',
|
||||
cn='回响构音:共晶反应',
|
||||
cht='迴響構音:共晶反應',
|
||||
en='Resonance Formation: Eutectic Reaction',
|
||||
jp='反響構音:共晶反応',
|
||||
path_id=1,
|
||||
rarity=3,
|
||||
)
|
||||
Resonance_Formation_Isomorphous_Reaction = RogueResonance(
|
||||
id=4,
|
||||
name='Resonance_Formation_Isomorphous_Reaction',
|
||||
cn='回响构音:均晶转变',
|
||||
cht='迴響構音:均晶轉變',
|
||||
en='Resonance Formation: Isomorphous Reaction',
|
||||
jp='反響構音:全率固溶体',
|
||||
path_id=1,
|
||||
rarity=3,
|
||||
)
|
||||
Path_Resonance_Remembrance = RogueResonance(
|
||||
id=5,
|
||||
name='Path_Resonance_Remembrance',
|
||||
cn='命途回响:「记忆」',
|
||||
cht='命途迴響:「記憶」',
|
||||
en='Path Resonance: Remembrance',
|
||||
jp='運命の反響:「記憶」',
|
||||
path_id=2,
|
||||
rarity=3,
|
||||
)
|
||||
Resonance_Formation_Total_Recall = RogueResonance(
|
||||
id=6,
|
||||
name='Resonance_Formation_Total_Recall',
|
||||
cn='回响构音:全面回忆',
|
||||
cht='迴響構音:全面回憶',
|
||||
en='Resonance Formation: Total Recall',
|
||||
jp='反響構音:全面追憶',
|
||||
path_id=2,
|
||||
rarity=3,
|
||||
)
|
||||
Resonance_Formation_Rich_Experience = RogueResonance(
|
||||
id=7,
|
||||
name='Resonance_Formation_Rich_Experience',
|
||||
cn='回响构音:体验的富翁',
|
||||
cht='迴響構音:體驗的富翁',
|
||||
en='Resonance Formation: Rich Experience',
|
||||
jp='反響構音:体験の富豪',
|
||||
path_id=2,
|
||||
rarity=3,
|
||||
)
|
||||
Resonance_Formation_First_Love_Once_More = RogueResonance(
|
||||
id=8,
|
||||
name='Resonance_Formation_First_Love_Once_More',
|
||||
cn='回响构音:第二次初恋',
|
||||
cht='迴響構音:第二次初戀',
|
||||
en='Resonance Formation: First Love Once More',
|
||||
jp='反響構音:二度目の初恋',
|
||||
path_id=2,
|
||||
rarity=3,
|
||||
)
|
||||
Path_Resonance_Nihility = RogueResonance(
|
||||
id=9,
|
||||
name='Path_Resonance_Nihility',
|
||||
cn='命途回响:「虚无」',
|
||||
cht='命途迴響:「虛無」',
|
||||
en='Path Resonance: Nihility',
|
||||
jp='運命の反響:「虚無」',
|
||||
path_id=3,
|
||||
rarity=3,
|
||||
)
|
||||
Resonance_Formation_The_Doubtful_Fourfold_Root = RogueResonance(
|
||||
id=10,
|
||||
name='Resonance_Formation_The_Doubtful_Fourfold_Root',
|
||||
cn='回响构音:怀疑的四重根',
|
||||
cht='迴響構音:懷疑的四重根',
|
||||
en='Resonance Formation: The Doubtful Fourfold Root',
|
||||
jp='反響構音:疑いの四つの根',
|
||||
path_id=3,
|
||||
rarity=3,
|
||||
)
|
||||
Resonance_Formation_Suffering_and_Sunshine = RogueResonance(
|
||||
id=11,
|
||||
name='Resonance_Formation_Suffering_and_Sunshine',
|
||||
cn='回响构音:苦难与阳光',
|
||||
cht='迴響構音:苦難與陽光',
|
||||
en='Resonance Formation: Suffering and Sunshine',
|
||||
jp='反響構音:苦難と陽光',
|
||||
path_id=3,
|
||||
rarity=3,
|
||||
)
|
||||
Resonance_Formation_Outsider = RogueResonance(
|
||||
id=12,
|
||||
name='Resonance_Formation_Outsider',
|
||||
cn='回响构音:局外人',
|
||||
cht='迴響構音:局外人',
|
||||
en='Resonance Formation: Outsider',
|
||||
jp='反響構音:異邦人',
|
||||
path_id=3,
|
||||
rarity=3,
|
||||
)
|
||||
Path_Resonance_Abundance = RogueResonance(
|
||||
id=13,
|
||||
name='Path_Resonance_Abundance',
|
||||
cn='命途回响:「丰饶」',
|
||||
cht='命途迴響:「豐饒」',
|
||||
en='Path Resonance: Abundance',
|
||||
jp='運命の反響:「豊穣」',
|
||||
path_id=4,
|
||||
rarity=3,
|
||||
)
|
||||
Resonance_Formation_Terminal_Nirvana = RogueResonance(
|
||||
id=14,
|
||||
name='Resonance_Formation_Terminal_Nirvana',
|
||||
cn='回响构音:无余涅槃',
|
||||
cht='迴響構音:無餘涅槃',
|
||||
en='Resonance Formation: Terminal Nirvana',
|
||||
jp='反響構音:無余涅槃',
|
||||
path_id=4,
|
||||
rarity=3,
|
||||
)
|
||||
Resonance_Formation_Anicca = RogueResonance(
|
||||
id=15,
|
||||
name='Resonance_Formation_Anicca',
|
||||
cn='回响构音:诸行无常',
|
||||
cht='迴響構音:諸行無常',
|
||||
en='Resonance Formation: Anicca',
|
||||
jp='反響構音:諸行無常',
|
||||
path_id=4,
|
||||
rarity=3,
|
||||
)
|
||||
Resonance_Formation_Anatta = RogueResonance(
|
||||
id=16,
|
||||
name='Resonance_Formation_Anatta',
|
||||
cn='回响构音:诸法无我',
|
||||
cht='迴響構音:諸法無我',
|
||||
en='Resonance Formation: Anatta',
|
||||
jp='反響構音:諸法無我',
|
||||
path_id=4,
|
||||
rarity=3,
|
||||
)
|
||||
Path_Resonance_The_Hunt = RogueResonance(
|
||||
id=17,
|
||||
name='Path_Resonance_The_Hunt',
|
||||
cn='命途回响:「巡猎」',
|
||||
cht='命途迴響:「巡獵」',
|
||||
en='Path Resonance: The Hunt',
|
||||
jp='運命の反響:「巡狩」',
|
||||
path_id=5,
|
||||
rarity=3,
|
||||
)
|
||||
Resonance_Formation_Star_Hunter = RogueResonance(
|
||||
id=18,
|
||||
name='Resonance_Formation_Star_Hunter',
|
||||
cn='回响构音:狩星巡日',
|
||||
cht='迴響構音:狩星巡日',
|
||||
en='Resonance Formation: Star Hunter',
|
||||
jp='反響構音:星を狩りて日を巡る',
|
||||
path_id=5,
|
||||
rarity=3,
|
||||
)
|
||||
Resonance_Formation_Bow_and_Arrow = RogueResonance(
|
||||
id=19,
|
||||
name='Resonance_Formation_Bow_and_Arrow',
|
||||
cn='回响构音:柘弓危矢',
|
||||
cht='迴響構音:柘弓危矢',
|
||||
en='Resonance Formation: Bow and Arrow',
|
||||
jp='反響構音:柘弓に疾矢',
|
||||
path_id=5,
|
||||
rarity=3,
|
||||
)
|
||||
Resonance_Formation_Perfect_Aim = RogueResonance(
|
||||
id=20,
|
||||
name='Resonance_Formation_Perfect_Aim',
|
||||
cn='回响构音:射不主皮',
|
||||
cht='迴響構音:射不主皮',
|
||||
en='Resonance Formation: Perfect Aim',
|
||||
jp='反響構音:射は皮を主とせず',
|
||||
path_id=5,
|
||||
rarity=3,
|
||||
)
|
||||
Path_Resonance_Destruction = RogueResonance(
|
||||
id=21,
|
||||
name='Path_Resonance_Destruction',
|
||||
cn='命途回响:「毁灭」',
|
||||
cht='命途迴響:「毀滅」',
|
||||
en='Path Resonance: Destruction',
|
||||
jp='運命の反響:「壊滅」',
|
||||
path_id=6,
|
||||
rarity=3,
|
||||
)
|
||||
Resonance_Formation_Cataclysmic_Variable = RogueResonance(
|
||||
id=22,
|
||||
name='Resonance_Formation_Cataclysmic_Variable',
|
||||
cn='回响构音:激变变星',
|
||||
cht='迴響構音:激變變星',
|
||||
en='Resonance Formation: Cataclysmic Variable',
|
||||
jp='反響構音:激変星',
|
||||
path_id=6,
|
||||
rarity=3,
|
||||
)
|
||||
Resonance_Formation_Extreme_Helium_Flash = RogueResonance(
|
||||
id=23,
|
||||
name='Resonance_Formation_Extreme_Helium_Flash',
|
||||
cn='回响构音:极端氦闪',
|
||||
cht='迴響構音:極端氦閃',
|
||||
en='Resonance Formation: Extreme Helium Flash',
|
||||
jp='反響構音:ヘリウムフラッシュ',
|
||||
path_id=6,
|
||||
rarity=3,
|
||||
)
|
||||
Resonance_Formation_Event_Horizon = RogueResonance(
|
||||
id=24,
|
||||
name='Resonance_Formation_Event_Horizon',
|
||||
cn='回响构音:事件视界',
|
||||
cht='迴響構音:事件視界',
|
||||
en='Resonance Formation: Event Horizon',
|
||||
jp='反響構音:事象の地平線',
|
||||
path_id=6,
|
||||
rarity=3,
|
||||
)
|
||||
Path_Resonance_Elation = RogueResonance(
|
||||
id=25,
|
||||
name='Path_Resonance_Elation',
|
||||
cn='命途回响:「欢愉」',
|
||||
cht='命途迴響:「歡愉」',
|
||||
en='Path Resonance: Elation',
|
||||
jp='運命の反響:「愉悦」',
|
||||
path_id=7,
|
||||
rarity=3,
|
||||
)
|
||||
Resonance_Formation_Doomsday_Carnival = RogueResonance(
|
||||
id=26,
|
||||
name='Resonance_Formation_Doomsday_Carnival',
|
||||
cn='回响构音:末日狂欢',
|
||||
cht='迴響構音:末日狂歡',
|
||||
en='Resonance Formation: Doomsday Carnival',
|
||||
jp='反響構音:終末の狂宴',
|
||||
path_id=7,
|
||||
rarity=3,
|
||||
)
|
||||
Resonance_Formation_Dance_of_Growth = RogueResonance(
|
||||
id=27,
|
||||
name='Resonance_Formation_Dance_of_Growth',
|
||||
cn='回响构音:树苗长高舞',
|
||||
cht='迴響構音:樹苗長高舞',
|
||||
en='Resonance Formation: Dance of Growth',
|
||||
jp='反響構音:苗木が育つ踊り',
|
||||
path_id=7,
|
||||
rarity=3,
|
||||
)
|
||||
Resonance_Formation_Instant_Win = RogueResonance(
|
||||
id=28,
|
||||
name='Resonance_Formation_Instant_Win',
|
||||
cn='回响构音:开盖有奖',
|
||||
cht='迴響構音:開蓋有獎',
|
||||
en='Resonance Formation: Instant Win',
|
||||
jp='反響構音:もう1本',
|
||||
path_id=7,
|
||||
rarity=3,
|
||||
)
|
10
tasks/rogue/preset.py
Normal file
@ -0,0 +1,10 @@
|
||||
BLESSING_PRESET_1 = ("巡猎-3 > 《冠军晚餐•猫的摇篮》 > 丰饶众生,一法界心 > 毁灭-3 "
|
||||
"> 火堆外的夜 > 巡猎-2 > 戒律性闪变 > 巡猎 > 存护-2 > reset > random")
|
||||
RESONANCE_PRESET_1 = ("回响构音:均晶转变 > 回响构音:零维强化"
|
||||
"> 回响构音:第二次初恋 > 回响构音:体验的富翁"
|
||||
"> 回响构音:局外人 > 回响构音:怀疑的四重根"
|
||||
"> 回响构音:诸法无我 > 回响构音:诸行无常"
|
||||
"> 回响构音:射不主皮 > 回响构音:柘弓危矢"
|
||||
"> 回响构音:激变变星 > 回响构音:极端氦闪"
|
||||
"> 回响构音:末日狂欢 > 回响构音:树苗长高舞")
|
||||
CURIO_PRESET_1 = "博士之袍 > 福灵胶 > 分裂金币 > 信仰债券 > 换境桂冠 > 俱乐部券 > 碎星芳饵 > random"
|
@ -0,0 +1,67 @@
|
||||
import numpy as np
|
||||
|
||||
from module.logger import logger
|
||||
from module.ocr.keyword import Keyword
|
||||
from module.ocr.ocr import OcrResultButton
|
||||
from tasks.rogue.ui import RogueUI
|
||||
|
||||
|
||||
class RogueSelector:
|
||||
"""
|
||||
An Interface used in blessing, curio, and other ui selection in rogue
|
||||
"""
|
||||
|
||||
def __init__(self, main: RogueUI):
|
||||
self.main = main
|
||||
self.filter_ = None
|
||||
self.ocr_results = []
|
||||
|
||||
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)
|
58
tasks/rogue/ui.py
Normal file
@ -0,0 +1,58 @@
|
||||
import re
|
||||
|
||||
from module.base.utils import area_offset
|
||||
from module.ocr.ocr import Digit, Ocr, OcrResultButton
|
||||
from tasks.base.ui import UI
|
||||
from tasks.rogue.assets.assets_rogue_ui import *
|
||||
from tasks.rogue.keywords import *
|
||||
|
||||
|
||||
class RogueBonusOcr(Ocr):
|
||||
def after_process(self, result):
|
||||
result = super().after_process(result)
|
||||
if self.lang == 'ch':
|
||||
replace_pattern_dict = {
|
||||
"[宇宝][宙审]": "宇宙",
|
||||
}
|
||||
for pat, replace in replace_pattern_dict.items():
|
||||
result = re.sub(pat, replace, result)
|
||||
return result
|
||||
|
||||
|
||||
class RogueUI(UI):
|
||||
path: RoguePath
|
||||
|
||||
@property
|
||||
def cosmic_fragment(self):
|
||||
"""
|
||||
Return valid result only when template appear
|
||||
"""
|
||||
if self.appear(COSMIC_FRAGMENT):
|
||||
return Digit(OCR_COSMIC_FRAGMENT).ocr_single_line(self.device.image)
|
||||
return 0
|
||||
|
||||
def is_page_choose_blessing(self):
|
||||
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)
|
||||
|
||||
def is_page_choose_bonus(self):
|
||||
return self.appear(PAGE_CHOOSE_BONUS)
|
||||
|
||||
def is_page_event(self):
|
||||
return self.appear(PAGE_EVENT)
|
||||
|
||||
def handle_obtain_item_popup(self, interval=5) -> bool:
|
||||
"""After selecting some curio (e.g. Sealing_Wax_of_*), there will be a popup after back to main page"""
|
||||
if self.appear_then_click(OBTAIN_ITEM_POPUP, interval=interval):
|
||||
return True
|
||||
return False
|
||||
|
||||
def is_unrecorded(self, target: OcrResultButton, relative_area):
|
||||
"""
|
||||
To check a rogue keyword is not record in game index by finding template
|
||||
"""
|
||||
FLAG_UNRECORD.matched_button.search = area_offset(relative_area, target.area[:2])
|
||||
return self.appear(FLAG_UNRECORD)
|
33
tasks/rogue/utils.py
Normal file
@ -0,0 +1,33 @@
|
||||
import re
|
||||
|
||||
from module.base.base import ModuleBase
|
||||
from module.base.utils import area_offset
|
||||
from module.ocr.ocr import OcrResultButton
|
||||
|
||||
REGEX_PUNCTUATION = re.compile(r'[ ,.\'"“”,。::!!??·•—/()()「」『』【】《》]')
|
||||
|
||||
|
||||
def parse_name(n):
|
||||
n = REGEX_PUNCTUATION.sub('', str(n)).lower()
|
||||
return n
|
||||
|
||||
|
||||
def get_regex_from_keyword_name(keyword, attr_name):
|
||||
string = ""
|
||||
for instance in keyword.instances.values():
|
||||
if hasattr(instance, attr_name):
|
||||
for name in instance.__getattribute__(attr_name):
|
||||
string += f"{name}|"
|
||||
# some pattern contain each other, make sure each pattern end with "-" or the end of string
|
||||
return f"(?:({string[:-1]})(?:-|$))?"
|
||||
|
||||
|
||||
def is_card_selected(main: ModuleBase, target: OcrResultButton, confirm_button):
|
||||
"""
|
||||
There is a white border if a blessing is selected.
|
||||
For the enforce case, just check the confirm button turning to white
|
||||
"""
|
||||
if not target:
|
||||
return main.image_color_count(confirm_button, (230, 230, 230))
|
||||
top_border = area_offset(target.area, (0, -180))
|
||||
return main.image_color_count(top_border, (255, 255, 255))
|