Add: rogue buff selector

This commit is contained in:
Hengyu 2023-08-10 17:12:17 +08:00
parent e41d5b4ae4
commit 17debdfb5e
30 changed files with 2417 additions and 12 deletions

Binary file not shown.

After

Width:  |  Height:  |  Size: 39 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 13 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 8.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 10 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 135 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 9.5 KiB

View File

@ -77,5 +77,20 @@
"Name_3": "The_Invisible_Hand",
"Name_4": "Nine_Billion_Names"
}
},
"Rogue": {
"Scheduler": {
"Enable": false,
"NextRun": "2020-01-01 00:00:00",
"Command": "Rogue",
"ServerUpdate": "04:00"
},
"Rogue": {
"Path": "The Hunt",
"PresetResonanceFilter": "preset-1",
"CustomResonanceFilter": "回响构音:均晶转变 > 回响构音:零维强化\n> 回响构音:第二次初恋 > 回响构音:体验的富翁\n> 回响构音:局外人 > 回响构音:怀疑的四重根\n> 回响构音:诸法无我 > 回响构音:诸行无常\n> 回响构音:射不主皮 > 回响构音:柘弓危矢\n> 回响构音:激变变星 > 回响构音:极端氦闪\n> 回响构音:末日狂欢 > 回响构音:树苗长高舞",
"PresetBlessingFilter": "preset-1",
"CustomBlessingFilter": "巡猎-3 > 《冠军晚餐·猫的摇篮》 > 丰饶众生,一法界心 > 毁灭-3 \n> 火堆外的夜 > 巡猎-2 > 毁灭-2 > 巡猎 > reset > random"
}
}
}

View File

@ -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,41 @@ 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):
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)}
return blessings_hash, {'path_id': blessings_path_id, 'rarity': blessings_rarity}
hash_list, extra_attrs = get_blessing_infos(blessings_id)
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)
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 generate(self):
self.load_keywords(['模拟宇宙', '拟造花萼(金)', '拟造花萼(赤)', '凝滞虚影', '侵蚀隧洞', '历战余响', '忘却之庭'])
self.write_keywords(keyword_class='DungeonNav', output_file='./tasks/dungeon/keywords/nav.py')
@ -308,6 +360,7 @@ 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()
if __name__ == '__main__':

View File

@ -432,5 +432,67 @@
]
}
}
},
"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",
"The Hunt",
"Destruction",
"Elation"
]
},
"PresetResonanceFilter": {
"type": "select",
"value": "preset-1",
"option": [
"preset-1",
"custom"
]
},
"CustomResonanceFilter": {
"type": "textarea",
"value": "回响构音:均晶转变 > 回响构音:零维强化\n> 回响构音:第二次初恋 > 回响构音:体验的富翁\n> 回响构音:局外人 > 回响构音:怀疑的四重根\n> 回响构音:诸法无我 > 回响构音:诸行无常\n> 回响构音:射不主皮 > 回响构音:柘弓危矢\n> 回响构音:激变变星 > 回响构音:极端氦闪\n> 回响构音:末日狂欢 > 回响构音:树苗长高舞"
},
"PresetBlessingFilter": {
"type": "select",
"value": "preset-1",
"option": [
"preset-1",
"custom"
]
},
"CustomBlessingFilter": {
"type": "textarea",
"value": "巡猎-3 > 《冠军晚餐·猫的摇篮》 > 丰饶众生,一法界心 > 毁灭-3 \n> 火堆外的夜 > 巡猎-2 > 毁灭-2 > 巡猎 > reset > random"
}
}
}
}

View File

@ -73,7 +73,7 @@ Dungeon:
Name:
# Options will be injected in config updater
value: Calyx_Golden_Treasures
option: [Calyx_Golden_Treasures, ]
option: [ Calyx_Golden_Treasures, ]
NameAtDoubleCalyx:
# Options will be injected in config updater
value: Calyx_Golden_Treasures
@ -83,26 +83,50 @@ Dungeon:
option: [ 1, 2, 3, 4, 5, 6 ]
Support:
value: when_daily
option: [do_not_use, always_use, when_daily]
option: [ do_not_use, always_use, when_daily ]
SupportCharacter:
# Options will be injected in config updater
value: FirstCharacter
option: [FirstCharacter, ]
option: [ FirstCharacter, ]
Assignment:
Duration:
value: 20
option: [4, 8, 12, 20]
option: [ 4, 8, 12, 20 ]
# Options in Name_x will be injected in config updater
Name_1:
value: Nameless_Land_Nameless_People
option: [Nameless_Land_Nameless_People, ]
option: [ Nameless_Land_Nameless_People, ]
Name_2:
value: Akashic_Records
option: [Nameless_Land_Nameless_People, ]
option: [ Nameless_Land_Nameless_People, ]
Name_3:
value: The_Invisible_Hand
option: [Nameless_Land_Nameless_People, ]
option: [ Nameless_Land_Nameless_People, ]
Name_4:
value: Nine_Billion_Names
option: [Nameless_Land_Nameless_People, ]
option: [ Nameless_Land_Nameless_People, ]
# ==================== Rogue ====================
Rogue:
Path:
value: The Hunt
option: [ Preservation, Remembrance, Nihility, Abundance, The Hunt, Destruction, Elation ]
PresetResonanceFilter:
value: preset-1
option: [ preset-1, custom ]
CustomResonanceFilter: |-
回响构音:均晶转变 > 回响构音:零维强化
> 回响构音:第二次初恋 > 回响构音:体验的富翁
> 回响构音:局外人 > 回响构音:怀疑的四重根
> 回响构音:诸法无我 > 回响构音:诸行无常
> 回响构音:射不主皮 > 回响构音:柘弓危矢
> 回响构音:激变变星 > 回响构音:极端氦闪
> 回响构音:末日狂欢 > 回响构音:树苗长高舞
PresetBlessingFilter:
value: preset-1
option: [ preset-1, custom ]
CustomBlessingFilter: |-
巡猎-3 > 《冠军晚餐·猫的摇篮》 > 丰饶众生,一法界心 > 毁灭-3
> 火堆外的夜 > 巡猎-2 > 毁灭-2 > 巡猎 > reset > random

View File

@ -16,5 +16,12 @@
"BattlePass",
"Assignment"
]
},
"Rogue": {
"menu": "list",
"page": "setting",
"tasks": [
"Rogue"
]
}
}

View File

@ -32,3 +32,13 @@ Daily:
Assignment:
- Scheduler
- Assignment
# ==================== Rogue ====================
Rogue:
menu: 'list'
page: 'setting'
tasks:
Rogue:
- Scheduler
- Rogue

View File

@ -51,3 +51,10 @@ class GeneratedConfig:
Assignment_Name_2 = 'Akashic_Records' # 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
Assignment_Name_3 = 'The_Invisible_Hand' # 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
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
# Group `Rogue`
Rogue_Path = 'The Hunt' # Preservation, Remembrance, Nihility, Abundance, The Hunt, Destruction, Elation
Rogue_PresetResonanceFilter = 'preset-1' # preset-1, custom
Rogue_CustomResonanceFilter = '回响构音:均晶转变 > 回响构音:零维强化\n> 回响构音:第二次初恋 > 回响构音:体验的富翁\n> 回响构音:局外人 > 回响构音:怀疑的四重根\n> 回响构音:诸法无我 > 回响构音:诸行无常\n> 回响构音:射不主皮 > 回响构音:柘弓危矢\n> 回响构音:激变变星 > 回响构音:极端氦闪\n> 回响构音:末日狂欢 > 回响构音:树苗长高舞'
Rogue_PresetBlessingFilter = 'preset-1' # preset-1, custom
Rogue_CustomBlessingFilter = '巡猎-3 > 《冠军晚餐·猫的摇篮》 > 丰饶众生,一法界心 > 毁灭-3 \n> 火堆外的夜 > 巡猎-2 > 毁灭-2 > 巡猎 > reset > random'

View File

@ -7,6 +7,10 @@
"Daily": {
"name": "Daily",
"help": ""
},
"Rogue": {
"name": "Menu.Rogue.name",
"help": "Menu.Rogue.help"
}
},
"Task": {
@ -33,6 +37,10 @@
"Assignment": {
"name": "Assignment",
"help": ""
},
"Rogue": {
"name": "Task.Rogue.name",
"help": "Task.Rogue.help"
}
},
"Scheduler": {
@ -359,6 +367,43 @@
"The_Blossom_in_the_Storm": "Gaseous Liquid & Seed (The Blossom in the Storm)"
}
},
"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",
"The Hunt": "The Hunt",
"Destruction": "Destruction",
"Elation": "Elation"
},
"PresetResonanceFilter": {
"name": "Rogue.PresetResonanceFilter.name",
"help": "Rogue.PresetResonanceFilter.help",
"preset-1": "preset-1",
"custom": "custom"
},
"CustomResonanceFilter": {
"name": "Rogue.CustomResonanceFilter.name",
"help": "Rogue.CustomResonanceFilter.help"
},
"PresetBlessingFilter": {
"name": "Rogue.PresetBlessingFilter.name",
"help": "Rogue.PresetBlessingFilter.help",
"preset-1": "preset-1",
"custom": "custom"
},
"CustomBlessingFilter": {
"name": "Rogue.CustomBlessingFilter.name",
"help": "Rogue.CustomBlessingFilter.help"
}
},
"Gui": {
"Aside": {
"Install": "Install",

View File

@ -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": {
@ -359,6 +367,43 @@
"The_Blossom_in_the_Storm": "気態流体と種子(嵐の中で咲き誇る花)"
}
},
"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",
"The Hunt": "The Hunt",
"Destruction": "Destruction",
"Elation": "Elation"
},
"PresetResonanceFilter": {
"name": "Rogue.PresetResonanceFilter.name",
"help": "Rogue.PresetResonanceFilter.help",
"preset-1": "preset-1",
"custom": "custom"
},
"CustomResonanceFilter": {
"name": "Rogue.CustomResonanceFilter.name",
"help": "Rogue.CustomResonanceFilter.help"
},
"PresetBlessingFilter": {
"name": "Rogue.PresetBlessingFilter.name",
"help": "Rogue.PresetBlessingFilter.help",
"preset-1": "preset-1",
"custom": "custom"
},
"CustomBlessingFilter": {
"name": "Rogue.CustomBlessingFilter.name",
"help": "Rogue.CustomBlessingFilter.help"
}
},
"Gui": {
"Aside": {
"Install": "インストール",

View File

@ -7,6 +7,10 @@
"Daily": {
"name": "每日",
"help": ""
},
"Rogue": {
"name": "模拟宇宙",
"help": ""
}
},
"Task": {
@ -33,6 +37,10 @@
"Assignment": {
"name": "委托设置",
"help": ""
},
"Rogue": {
"name": "模拟宇宙",
"help": ""
}
},
"Scheduler": {
@ -359,6 +367,43 @@
"The_Blossom_in_the_Storm": "气态流体&种子(风暴中怒放的花)"
}
},
"Rogue": {
"_info": {
"name": "模拟宇宙",
"help": ""
},
"Path": {
"name": "命途",
"help": "",
"Preservation": "存护",
"Remembrance": "记忆",
"Nihility": "虚无",
"Abundance": "丰饶",
"The Hunt": "巡猎",
"Destruction": "毁灭",
"Elation": "欢愉"
},
"PresetResonanceFilter": {
"name": "命途回响过滤器",
"help": "",
"preset-1": "预设 1",
"custom": "自定义"
},
"CustomResonanceFilter": {
"name": "自定义命途回响过滤器",
"help": ""
},
"PresetBlessingFilter": {
"name": "祝福过滤器",
"help": "",
"preset-1": "预设 1",
"custom": "自定义"
},
"CustomBlessingFilter": {
"name": "自定义祝福过滤器",
"help": ""
}
},
"Gui": {
"Aside": {
"Install": "安装",

View File

@ -7,6 +7,10 @@
"Daily": {
"name": "每日",
"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": {
@ -359,6 +367,43 @@
"The_Blossom_in_the_Storm": "氣態流體&種子(風暴中怒放的花)"
}
},
"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",
"The Hunt": "The Hunt",
"Destruction": "Destruction",
"Elation": "Elation"
},
"PresetResonanceFilter": {
"name": "Rogue.PresetResonanceFilter.name",
"help": "Rogue.PresetResonanceFilter.help",
"preset-1": "preset-1",
"custom": "custom"
},
"CustomResonanceFilter": {
"name": "Rogue.CustomResonanceFilter.name",
"help": "Rogue.CustomResonanceFilter.help"
},
"PresetBlessingFilter": {
"name": "Rogue.PresetBlessingFilter.name",
"help": "Rogue.PresetBlessingFilter.help",
"preset-1": "preset-1",
"custom": "custom"
},
"CustomBlessingFilter": {
"name": "Rogue.CustomBlessingFilter.name",
"help": "Rogue.CustomBlessingFilter.help"
}
},
"Gui": {
"Aside": {
"Install": "安裝",

View File

@ -0,0 +1,65 @@
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),
),
)
CONFIRM = ButtonWrapper(
name='CONFIRM',
share=Button(
file='./assets/share/rogue/blessing/CONFIRM.png',
area=(960, 629, 1233, 677),
search=(940, 609, 1253, 697),
color=(217, 218, 218),
button=(960, 629, 1233, 677),
),
)
OCR_RESET_COUNT = ButtonWrapper(
name='OCR_RESET_COUNT',
share=Button(
file='./assets/share/rogue/blessing/OCR_RESET_COUNT.png',
area=(714, 595, 824, 620),
search=(694, 575, 844, 640),
color=(37, 37, 41),
button=(714, 595, 824, 620),
),
)
OCR_ROGUE_BUFF = ButtonWrapper(
name='OCR_ROGUE_BUFF',
share=Button(
file='./assets/share/rogue/blessing/OCR_ROGUE_BUFF.png',
area=(155, 139, 1125, 337),
search=(135, 119, 1145, 357),
color=(79, 86, 104),
button=(155, 139, 1125, 337),
),
)

View 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 ```
PAGE_CHOOSE_BUFF = ButtonWrapper(
name='PAGE_CHOOSE_BUFF',
share=Button(
file='./assets/share/rogue/ui/PAGE_CHOOSE_BUFF.png',
area=(1105, 95, 1154, 113),
search=(1085, 75, 1174, 133),
color=(81, 82, 83),
button=(1105, 95, 1154, 113),
),
)
PAGE_CHOOSE_MIRACLE = ButtonWrapper(
name='PAGE_CHOOSE_MIRACLE',
share=Button(
file='./assets/share/rogue/ui/PAGE_CHOOSE_MIRACLE.png',
area=(988, 17, 1028, 57),
search=(968, 0, 1048, 77),
color=(40, 39, 34),
button=(988, 17, 1028, 57),
),
)

295
tasks/rogue/blessing.py Normal file
View File

@ -0,0 +1,295 @@
import re
import numpy as np
from dev_tools.keyword_extract import UI_LANGUAGES
from module.base.filter import Filter
from module.base.timer import Timer
from module.base.utils import area_offset
from module.logger import logger
from module.ocr.ocr import Ocr, OcrResultButton, DigitCounter
from tasks.rogue.assets.assets_rogue_blessing import *
from tasks.rogue.keywords import *
from tasks.rogue.preset import *
from tasks.rogue.ui import RogueUI
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):
regex_pat = ""
attrs = tuple()
for server in UI_LANGUAGES:
string = ""
for path in keyword.instances.values():
string += f"{parse_name(getattr(path, server))}|"
# some pattern contain each other, make sure each pattern end with "-" or the end of string
regex_pat += f"(?:({string[:-1]})(?:-|$))?"
attrs += (f"{attr_name}_{server}",)
return regex_pat, attrs
# normal blessing
pattern = ""
BLESSING_FILTER_ATTR = tuple()
PATH_ATTR_NAME = 'path'
path_regex, path_attr = get_regex_from_keyword_name(RoguePath, PATH_ATTR_NAME)
pattern += path_regex
BLESSING_FILTER_ATTR += path_attr
pattern += "([123])?-?"
BLESSING_FILTER_ATTR += ("rarity",)
BLESSING_ATTR_NAME = 'blessing'
blessing_regex, blessing_attr = get_regex_from_keyword_name(RogueBlessing, BLESSING_ATTR_NAME)
pattern += blessing_regex
BLESSING_FILTER_ATTR += blessing_attr
FILETER_REGEX = re.compile(pattern)
BLESSING_FILTER_PRESET = ("reset", "same_path", "random")
BLESSING_FILTER = Filter(FILETER_REGEX, BLESSING_FILTER_ATTR, BLESSING_FILTER_PRESET)
# resonance
RESONANCE_ATTR_NAME = 'resonance'
pattern, RESONANCE_FILTER_ATTR = get_regex_from_keyword_name(RogueResonance, 'resonance')
FILETER_REGEX = re.compile(pattern)
RESONANCE_FILTER_PRESET = ("random",)
RESONANCE_FILTER = Filter(FILETER_REGEX, RESONANCE_FILTER_ATTR, RESONANCE_FILTER_PRESET)
class RogueBuffOcr(Ocr):
merge_thres_x = 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 RogueBlessingUI(RogueUI):
def buffs_recognition(self):
ocr = RogueBuffOcr(OCR_ROGUE_BUFF)
results = ocr.matched_ocr(self.device.image, [RogueBlessing, RogueResonance])
if results:
logger.info(f"Buffs recognized: {len(results)}")
else:
logger.warning("No buff recognized")
self.blessings = results
return results
def ui_select_blessing(self, blessing: OcrResultButton | None, skip_first_screenshot=True, enforce=False):
"""
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_blessing_selected():
"""
There is a white border if a blessing is selected.
"""
top_border = area_offset(blessing.area, (0, -180))
return self.image_color_count(top_border, (255, 255, 255))
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
"""
return (self.is_in_main() or self.is_page_choose_curio()
or (self.is_page_choose_blessing() and not is_blessing_selected()))
interval = Timer(1)
if not blessing:
enforce = True
# start -> selected
while 1:
if skip_first_screenshot:
skip_first_screenshot = False
else:
self.device.screenshot()
if is_blessing_selected():
if enforce:
logger.info("Buff selected (enforce)")
else:
logger.info(f"Buff {blessing} selected")
break
if interval.reached():
if enforce:
self.device.click(BLESSING_ENFORCE)
else:
self.device.click(blessing)
interval.reset()
skip_first_screenshot = True
# selected -> confirm
while 1:
if skip_first_screenshot:
skip_first_screenshot = False
else:
self.device.screenshot()
if is_select_blessing_complete():
break
if interval.reached():
self.device.click(CONFIRM)
interval.reset()
def get_reset_count(self):
current, _, _ = DigitCounter(OCR_RESET_COUNT).ocr_single_line(self.device.image)
return current
def wait_until_blessing_loaded(self, skip_first_screenshot=True):
timeout = Timer(2, count=4).start()
while 1:
if skip_first_screenshot:
skip_first_screenshot = False
else:
self.device.screenshot()
if timeout.reached():
logger.warning('Wait blessing page loaded timeout')
return False
if self.image_color_count(BLESSING_STABLE_FLAG, (255, 255, 255)):
logger.info("Blessing page loaded")
return True
def reset_blessing_list(self, skip_first_screenshot=True):
if not self.is_page_choose_blessing():
return False
reset_count = self.get_reset_count()
if not reset_count:
return False
interval = Timer(1)
while 1:
if skip_first_screenshot:
skip_first_screenshot = False
else:
self.device.screenshot()
new_count = self.get_reset_count()
if reset_count - new_count == 1:
logger.info("Reset once")
break
if interval.reached():
self.device.click(BLESSING_RESET)
interval.reset()
return True
class RogueBlessingSelector(RogueBlessingUI):
"""
Usage:
self = RogueBlessingSelector('alas')
self.device.screenshot()
self.buff_recognition()
self.select_blessing(self.)
"""
def apply_filter(self):
paths = RoguePath.instances
if not self.blessings:
return []
if isinstance(self.blessings[0].matched_keyword, RogueBlessing):
for blessing in self.blessings:
path = paths[blessing.matched_keyword.path_id]
for server in UI_LANGUAGES:
setattr(blessing, f"{PATH_ATTR_NAME}_{server}", parse_name(getattr(path, server)))
setattr(blessing, f"{BLESSING_ATTR_NAME}_{server}",
parse_name(getattr(blessing.matched_keyword, server)))
setattr(blessing, "rarity", getattr(blessing.matched_keyword, "rarity"))
if self.config.Rogue_PresetBlessingFilter == 'preset-1':
BLESSING_FILTER.load(parse_name(BLESSING_PRESET_1))
if self.config.Rogue_PresetBlessingFilter == 'custom':
BLESSING_FILTER.load(parse_name(self.config.Rogue_CustomBlessingFilter))
if isinstance(self.blessings[0].matched_keyword, RogueResonance):
if len(self.blessings) == 1: # resonance can not be reset. So have not choice when there's only one option
return self.blessings
for blessing in self.blessings:
for server in UI_LANGUAGES:
setattr(blessing, f"{RESONANCE_ATTR_NAME}_{server}",
parse_name(getattr(blessing.matched_keyword, server)))
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))
priority = BLESSING_FILTER.apply(self.blessings)
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
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
if option.lower() == 'same_path':
chosen = False
for blessing in self.blessings:
if blessing.path_id == self.path.id:
self.ui_select_blessing(blessing)
chosen = True
if chosen:
return
else:
continue
if option.lower() == 'random':
choose = np.random.choice(self.blessings)
self.ui_select_blessing(choose)
return
if isinstance(option, OcrResultButton):
self.ui_select_blessing(option)
return

View File

@ -0,0 +1,5 @@
import tasks.rogue.keywords.blessing as KEYWORDS_ROGUE_BLESSING
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, RoguePath, RogueResonance

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,23 @@
from dataclasses import dataclass
from typing import ClassVar
from module.ocr.keyword import Keyword
@dataclass(repr=False)
class RogueBlessing(Keyword):
instances: ClassVar = {}
path_id: int
rarity: int
@dataclass(repr=False)
class RoguePath(Keyword):
instances: ClassVar = {}
@dataclass(repr=False)
class RogueResonance(Keyword):
instances: ClassVar = {}
path_id: int
rarity: int

View 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='愉悦',
)

View 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,
)

9
tasks/rogue/preset.py Normal file
View File

@ -0,0 +1,9 @@
BLESSING_PRESET_1 = ("巡猎-3 > 《冠军晚餐•猫的摇篮》 > 丰饶众生,一法界心 > 毁灭-3 "
"> 火堆外的夜 > 巡猎-2 > 戒律性闪变 > 巡猎 > 存护-2 > reset > random")
RESONANCE_PRESET_1 = ("回响构音:均晶转变 > 回响构音:零维强化"
"> 回响构音:第二次初恋 > 回响构音:体验的富翁"
"> 回响构音:局外人 > 回响构音:怀疑的四重根"
"> 回响构音:诸法无我 > 回响构音:诸行无常"
"> 回响构音:射不主皮 > 回响构音:柘弓危矢"
"> 回响构音:激变变星 > 回响构音:极端氦闪"
"> 回响构音:末日狂欢 > 回响构音:树苗长高舞")

14
tasks/rogue/ui.py Normal file
View File

@ -0,0 +1,14 @@
from tasks.base.ui import UI
from tasks.rogue.assets.assets_rogue_ui import *
from tasks.rogue.keywords import *
class RogueUI(UI):
path: RoguePath
blessings: list
def is_page_choose_blessing(self):
return self.image_color_count(PAGE_CHOOSE_BUFF, (245, 245, 245))
def is_page_choose_curio(self):
return self.appear(PAGE_CHOOSE_MIRACLE)