Merge pull request #626 from LmeSzinc/dev

Bug fix
This commit is contained in:
LmeSzinc 2024-09-11 00:23:47 +08:00 committed by GitHub
commit 75da44f910
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
54 changed files with 3087 additions and 1594 deletions

Binary file not shown.

After

Width:  |  Height:  |  Size: 21 KiB

BIN
assets/character/Moze.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 18 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 6.7 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 6.6 KiB

After

Width:  |  Height:  |  Size: 6.0 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 6.8 KiB

After

Width:  |  Height:  |  Size: 5.9 KiB

View File

Before

Width:  |  Height:  |  Size: 69 KiB

After

Width:  |  Height:  |  Size: 69 KiB

View File

Before

Width:  |  Height:  |  Size: 154 KiB

After

Width:  |  Height:  |  Size: 154 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 42 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 19 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 46 KiB

View File

@ -65,6 +65,8 @@
"Item_IPC_Work_Permit": {},
"Item_Raging_Heart": {},
"Item_Dream_Fridge": {},
"Item_Nail_of_the_Beast_Coffin": {},
"Item_A_Glass_of_the_Besotted_Era": {},
"Item_Dream_Flamer": {},
"Item_Worldbreaker_Blade": {},
"Item_Arrow_of_the_Starchaser": {},
@ -86,6 +88,7 @@
"Item_Regret_of_Infinite_Ochema": {},
"Item_Past_Evils_of_the_Borehole_Planet_Disaster": {},
"Item_Lost_Echo_of_the_Shared_Wish": {},
"Item_Auspice_Sliver": {},
"Item_Squirming_Core": {},
"Item_Conqueror_Will": {},
"Item_Silvermane_Medal": {},

View File

@ -73,6 +73,12 @@ class GenerateDungeonList(GenerateKeyword):
# Add plane suffix
from tasks.map.keywords import MapPlane
if text.startswith('Calyx_Golden'):
plane = MapPlane.find_plane_id(keyword['plane_id'])
if plane is not None:
text = f'{text}_{plane.world.name}'
else:
text = f'{text}_unknown_world'
if text.startswith('Calyx_Crimson'):
plane = MapPlane.find_plane_id(keyword['plane_id'])
if plane is not None:
@ -110,16 +116,33 @@ class GenerateDungeonList(GenerateKeyword):
dungeons = [d for d in dungeons if not condition(d)]
dungeons = calyx + dungeons
# Reverse Divergent_Universe
# 2024.09.10, v2.5, add genre prefix
for dungeon in dungeons:
if 230 <= dungeon['dungeon_id'] < 1000:
dungeon['name'] = 'Divergent_Universe_' + dungeon['name']
if 100 < dungeon['dungeon_id'] < 200:
dungeon['name'] = 'Simulated_Universe_' + dungeon['name']
# Reverse dungeon list, latest at top
def reverse_on_name(d, prefix):
start = 0
end = 0
for index, dungeon in enumerate(dungeons):
if dungeon['name'].startswith('Divergent_Universe'):
for index, dungeon in enumerate(d):
if dungeon['name'].startswith(prefix):
if start == 0:
start = index
end = index + 1
if start > 0 and end > 0:
dungeons = dungeons[:start] + dungeons[start:end][::-1] + dungeons[end:]
d = d[:start] + d[start:end][::-1] + d[end:]
return d
dungeons = reverse_on_name(dungeons, 'Divergent_Universe')
dungeons = reverse_on_name(dungeons, 'Cavern_of_Corrosion')
dungeons = reverse_on_name(dungeons, 'Echo_of_War')
# Reverse Calyx_Golden, sort by world
# Poor sort
dungeons[0:3], dungeons[6:9] = dungeons[6:9], dungeons[0:3]
# Re-sort ID
self.keyword_index = 0

View File

@ -340,6 +340,18 @@
"display": "display",
"stored": "StoredPlanner"
},
"Item_Nail_of_the_Beast_Coffin": {
"type": "planner",
"value": {},
"display": "display",
"stored": "StoredPlanner"
},
"Item_A_Glass_of_the_Besotted_Era": {
"type": "planner",
"value": {},
"display": "display",
"stored": "StoredPlanner"
},
"Item_Dream_Flamer": {
"type": "planner",
"value": {},
@ -466,6 +478,12 @@
"display": "display",
"stored": "StoredPlanner"
},
"Item_Auspice_Sliver": {
"type": "planner",
"value": {},
"display": "display",
"stored": "StoredPlanner"
},
"Item_Squirming_Core": {
"type": "planner",
"value": {},
@ -554,8 +572,10 @@
"Stagnant_Shadow_Nectar",
"Stagnant_Shadow_Fulmination",
"Stagnant_Shadow_Doom",
"Stagnant_Shadow_Mechwolf",
"Stagnant_Shadow_Gust",
"Stagnant_Shadow_Celestial",
"Stagnant_Shadow_Gloam",
"Stagnant_Shadow_Quanta",
"Stagnant_Shadow_Abomination",
"Stagnant_Shadow_Roast",
@ -662,6 +682,7 @@
"DanHeng",
"DanHengImbibitorLunae",
"DrRatio",
"Feixiao",
"Firefly",
"FuXuan",
"Gallagher",
@ -683,6 +704,7 @@
"March7thPreservation",
"March7thTheHunt",
"Misha",
"Moze",
"Natasha",
"Pela",
"Qingque",
@ -795,6 +817,7 @@
"type": "select",
"value": "Divergent_Universe_Eternal_Comedy",
"option": [
"Divergent_Universe_Famished_Worker",
"Divergent_Universe_Eternal_Comedy",
"Divergent_Universe_To_Sweet_Dreams",
"Divergent_Universe_Pouring_Blades",
@ -858,6 +881,7 @@
"DanHeng",
"DanHengImbibitorLunae",
"DrRatio",
"Feixiao",
"Firefly",
"FuXuan",
"Gallagher",
@ -879,6 +903,7 @@
"March7thPreservation",
"March7thTheHunt",
"Misha",
"Moze",
"Natasha",
"Pela",
"Qingque",
@ -1345,7 +1370,8 @@
"Echo_of_War_End_of_the_Eternal_Freeze",
"Echo_of_War_Divine_Seed",
"Echo_of_War_Borehole_Planet_Old_Crater",
"Echo_of_War_Salutations_of_Ashen_Dreams"
"Echo_of_War_Salutations_of_Ashen_Dreams",
"Echo_of_War_Inner_Beast_Battlefield"
]
},
"Team": {
@ -1392,6 +1418,7 @@
"DanHeng",
"DanHengImbibitorLunae",
"DrRatio",
"Feixiao",
"Firefly",
"FuXuan",
"Gallagher",
@ -1413,6 +1440,7 @@
"March7thPreservation",
"March7thTheHunt",
"Misha",
"Moze",
"Natasha",
"Pela",
"Qingque",

View File

@ -343,6 +343,28 @@
"order": 0,
"color": "#777777"
},
"Item_Nail_of_the_Beast_Coffin": {
"name": "Item_Nail_of_the_Beast_Coffin",
"path": "Dungeon.Planner.Item_Nail_of_the_Beast_Coffin",
"i18n": "Planner.Item_Nail_of_the_Beast_Coffin.name",
"stored": "StoredPlanner",
"attrs": {
"time": "2020-01-01 00:00:00"
},
"order": 0,
"color": "#777777"
},
"Item_A_Glass_of_the_Besotted_Era": {
"name": "Item_A_Glass_of_the_Besotted_Era",
"path": "Dungeon.Planner.Item_A_Glass_of_the_Besotted_Era",
"i18n": "Planner.Item_A_Glass_of_the_Besotted_Era.name",
"stored": "StoredPlanner",
"attrs": {
"time": "2020-01-01 00:00:00"
},
"order": 0,
"color": "#777777"
},
"Item_Dream_Flamer": {
"name": "Item_Dream_Flamer",
"path": "Dungeon.Planner.Item_Dream_Flamer",
@ -574,6 +596,17 @@
"order": 0,
"color": "#777777"
},
"Item_Auspice_Sliver": {
"name": "Item_Auspice_Sliver",
"path": "Dungeon.Planner.Item_Auspice_Sliver",
"i18n": "Planner.Item_Auspice_Sliver.name",
"stored": "StoredPlanner",
"attrs": {
"time": "2020-01-01 00:00:00"
},
"order": 0,
"color": "#777777"
},
"Item_Squirming_Core": {
"name": "Item_Squirming_Core",
"path": "Dungeon.Planner.Item_Squirming_Core",

View File

@ -41,7 +41,7 @@ class GeneratedConfig:
Optimization_WhenTaskQueueEmpty = 'goto_main' # stay_there, goto_main, close_game
# Group `Dungeon`
Dungeon_Name = 'Calyx_Golden_Treasures_Jarilo_VI' # Calyx_Golden_Memories_Jarilo_VI, Calyx_Golden_Memories_The_Xianzhou_Luofu, Calyx_Golden_Memories_Penacony, Calyx_Golden_Aether_Jarilo_VI, Calyx_Golden_Aether_The_Xianzhou_Luofu, Calyx_Golden_Aether_Penacony, Calyx_Golden_Treasures_Jarilo_VI, Calyx_Golden_Treasures_The_Xianzhou_Luofu, Calyx_Golden_Treasures_Penacony, Calyx_Crimson_Destruction_Herta_StorageZone, Calyx_Crimson_Destruction_Luofu_ScalegorgeWaterscape, Calyx_Crimson_Preservation_Herta_SupplyZone, Calyx_Crimson_Preservation_Penacony_ClockStudiosThemePark, Calyx_Crimson_The_Hunt_Jarilo_OutlyingSnowPlains, Calyx_Crimson_The_Hunt_Penacony_SoulGladScorchsandAuditionVenue, Calyx_Crimson_Abundance_Jarilo_BackwaterPass, Calyx_Crimson_Abundance_Luofu_FyxestrollGarden, Calyx_Crimson_Erudition_Jarilo_RivetTown, Calyx_Crimson_Erudition_Penacony_PenaconyGrandTheater, Calyx_Crimson_Harmony_Jarilo_RobotSettlement, Calyx_Crimson_Harmony_Penacony_TheReverieDreamscape, Calyx_Crimson_Nihility_Jarilo_GreatMine, Calyx_Crimson_Nihility_Luofu_AlchemyCommission, Stagnant_Shadow_Spike, Stagnant_Shadow_Perdition, Stagnant_Shadow_Duty, Stagnant_Shadow_Blaze, Stagnant_Shadow_Scorch, Stagnant_Shadow_Ire, Stagnant_Shadow_Rime, Stagnant_Shadow_Icicle, Stagnant_Shadow_Nectar, Stagnant_Shadow_Fulmination, Stagnant_Shadow_Doom, Stagnant_Shadow_Gust, Stagnant_Shadow_Celestial, Stagnant_Shadow_Quanta, Stagnant_Shadow_Abomination, Stagnant_Shadow_Roast, Stagnant_Shadow_Mirage, Stagnant_Shadow_Puppetry, Cavern_of_Corrosion_Path_of_Gelid_Wind, Cavern_of_Corrosion_Path_of_Jabbing_Punch, Cavern_of_Corrosion_Path_of_Drifting, Cavern_of_Corrosion_Path_of_Providence, Cavern_of_Corrosion_Path_of_Holy_Hymn, Cavern_of_Corrosion_Path_of_Conflagration, Cavern_of_Corrosion_Path_of_Elixir_Seekers, Cavern_of_Corrosion_Path_of_Darkness, Cavern_of_Corrosion_Path_of_Dreamdive, Cavern_of_Corrosion_Path_of_Cavalier
Dungeon_Name = 'Calyx_Golden_Treasures_Jarilo_VI' # Calyx_Golden_Memories_Jarilo_VI, Calyx_Golden_Memories_The_Xianzhou_Luofu, Calyx_Golden_Memories_Penacony, Calyx_Golden_Aether_Jarilo_VI, Calyx_Golden_Aether_The_Xianzhou_Luofu, Calyx_Golden_Aether_Penacony, Calyx_Golden_Treasures_Jarilo_VI, Calyx_Golden_Treasures_The_Xianzhou_Luofu, Calyx_Golden_Treasures_Penacony, Calyx_Crimson_Destruction_Herta_StorageZone, Calyx_Crimson_Destruction_Luofu_ScalegorgeWaterscape, Calyx_Crimson_Preservation_Herta_SupplyZone, Calyx_Crimson_Preservation_Penacony_ClockStudiosThemePark, Calyx_Crimson_The_Hunt_Jarilo_OutlyingSnowPlains, Calyx_Crimson_The_Hunt_Penacony_SoulGladScorchsandAuditionVenue, Calyx_Crimson_Abundance_Jarilo_BackwaterPass, Calyx_Crimson_Abundance_Luofu_FyxestrollGarden, Calyx_Crimson_Erudition_Jarilo_RivetTown, Calyx_Crimson_Erudition_Penacony_PenaconyGrandTheater, Calyx_Crimson_Harmony_Jarilo_RobotSettlement, Calyx_Crimson_Harmony_Penacony_TheReverieDreamscape, Calyx_Crimson_Nihility_Jarilo_GreatMine, Calyx_Crimson_Nihility_Luofu_AlchemyCommission, Stagnant_Shadow_Spike, Stagnant_Shadow_Perdition, Stagnant_Shadow_Duty, Stagnant_Shadow_Blaze, Stagnant_Shadow_Scorch, Stagnant_Shadow_Ire, Stagnant_Shadow_Rime, Stagnant_Shadow_Icicle, Stagnant_Shadow_Nectar, Stagnant_Shadow_Fulmination, Stagnant_Shadow_Doom, Stagnant_Shadow_Mechwolf, Stagnant_Shadow_Gust, Stagnant_Shadow_Celestial, Stagnant_Shadow_Gloam, Stagnant_Shadow_Quanta, Stagnant_Shadow_Abomination, Stagnant_Shadow_Roast, Stagnant_Shadow_Mirage, Stagnant_Shadow_Puppetry, Cavern_of_Corrosion_Path_of_Gelid_Wind, Cavern_of_Corrosion_Path_of_Jabbing_Punch, Cavern_of_Corrosion_Path_of_Drifting, Cavern_of_Corrosion_Path_of_Providence, Cavern_of_Corrosion_Path_of_Holy_Hymn, Cavern_of_Corrosion_Path_of_Conflagration, Cavern_of_Corrosion_Path_of_Elixir_Seekers, Cavern_of_Corrosion_Path_of_Darkness, Cavern_of_Corrosion_Path_of_Dreamdive, Cavern_of_Corrosion_Path_of_Cavalier
Dungeon_NameAtDoubleCalyx = 'Calyx_Golden_Treasures_Jarilo_VI' # Calyx_Golden_Memories_Jarilo_VI, Calyx_Golden_Memories_The_Xianzhou_Luofu, Calyx_Golden_Memories_Penacony, Calyx_Golden_Aether_Jarilo_VI, Calyx_Golden_Aether_The_Xianzhou_Luofu, Calyx_Golden_Aether_Penacony, Calyx_Golden_Treasures_Jarilo_VI, Calyx_Golden_Treasures_The_Xianzhou_Luofu, Calyx_Golden_Treasures_Penacony, Calyx_Crimson_Destruction_Herta_StorageZone, Calyx_Crimson_Destruction_Luofu_ScalegorgeWaterscape, Calyx_Crimson_Preservation_Herta_SupplyZone, Calyx_Crimson_Preservation_Penacony_ClockStudiosThemePark, Calyx_Crimson_The_Hunt_Jarilo_OutlyingSnowPlains, Calyx_Crimson_The_Hunt_Penacony_SoulGladScorchsandAuditionVenue, Calyx_Crimson_Abundance_Jarilo_BackwaterPass, Calyx_Crimson_Abundance_Luofu_FyxestrollGarden, Calyx_Crimson_Erudition_Jarilo_RivetTown, Calyx_Crimson_Erudition_Penacony_PenaconyGrandTheater, Calyx_Crimson_Harmony_Jarilo_RobotSettlement, Calyx_Crimson_Harmony_Penacony_TheReverieDreamscape, Calyx_Crimson_Nihility_Jarilo_GreatMine, Calyx_Crimson_Nihility_Luofu_AlchemyCommission
Dungeon_NameAtDoubleRelic = 'Cavern_of_Corrosion_Path_of_Providence' # Cavern_of_Corrosion_Path_of_Gelid_Wind, Cavern_of_Corrosion_Path_of_Jabbing_Punch, Cavern_of_Corrosion_Path_of_Drifting, Cavern_of_Corrosion_Path_of_Providence, Cavern_of_Corrosion_Path_of_Holy_Hymn, Cavern_of_Corrosion_Path_of_Conflagration, Cavern_of_Corrosion_Path_of_Elixir_Seekers, Cavern_of_Corrosion_Path_of_Darkness, Cavern_of_Corrosion_Path_of_Dreamdive, Cavern_of_Corrosion_Path_of_Cavalier
Dungeon_Team = 1 # 1, 2, 3, 4, 5, 6, 7, 8, 9
@ -53,7 +53,7 @@ class GeneratedConfig:
# Group `DungeonSupport`
DungeonSupport_Use = 'when_daily' # always_use, when_daily, do_not_use
DungeonSupport_Character = 'FirstCharacter' # FirstCharacter, Acheron, Argenti, Arlan, Asta, Aventurine, Bailu, BlackSwan, Blade, Boothill, Bronya, Clara, DanHeng, DanHengImbibitorLunae, DrRatio, Firefly, FuXuan, Gallagher, Gepard, Guinaifen, Hanya, Herta, Himeko, Hook, Huohuo, Jade, Jiaoqiu, JingYuan, Jingliu, Kafka, Luka, Luocha, Lynx, March7thPreservation, March7thTheHunt, Misha, Natasha, Pela, Qingque, Robin, RuanMei, Sampo, Seele, Serval, SilverWolf, Sparkle, Sushang, Tingyun, TopazNumby, TrailblazerDestruction, TrailblazerHarmony, TrailblazerPreservation, Welt, Xueyi, Yanqing, Yukong, Yunli
DungeonSupport_Character = 'FirstCharacter' # FirstCharacter, Acheron, Argenti, Arlan, Asta, Aventurine, Bailu, BlackSwan, Blade, Boothill, Bronya, Clara, DanHeng, DanHengImbibitorLunae, DrRatio, Feixiao, Firefly, FuXuan, Gallagher, Gepard, Guinaifen, Hanya, Herta, Himeko, Hook, Huohuo, Jade, Jiaoqiu, JingYuan, Jingliu, Kafka, Luka, Luocha, Lynx, March7thPreservation, March7thTheHunt, Misha, Moze, Natasha, Pela, Qingque, Robin, RuanMei, Sampo, Seele, Serval, SilverWolf, Sparkle, Sushang, Tingyun, TopazNumby, TrailblazerDestruction, TrailblazerHarmony, TrailblazerPreservation, Welt, Xueyi, Yanqing, Yukong, Yunli
# Group `DungeonStorage`
DungeonStorage_TrailblazePower = {}
@ -90,6 +90,8 @@ class GeneratedConfig:
Planner_Item_IPC_Work_Permit = {}
Planner_Item_Raging_Heart = {}
Planner_Item_Dream_Fridge = {}
Planner_Item_Nail_of_the_Beast_Coffin = {}
Planner_Item_A_Glass_of_the_Besotted_Era = {}
Planner_Item_Dream_Flamer = {}
Planner_Item_Worldbreaker_Blade = {}
Planner_Item_Arrow_of_the_Starchaser = {}
@ -111,6 +113,7 @@ class GeneratedConfig:
Planner_Item_Regret_of_Infinite_Ochema = {}
Planner_Item_Past_Evils_of_the_Borehole_Planet_Disaster = {}
Planner_Item_Lost_Echo_of_the_Shared_Wish = {}
Planner_Item_Auspice_Sliver = {}
Planner_Item_Squirming_Core = {}
Planner_Item_Conqueror_Will = {}
Planner_Item_Silvermane_Medal = {}
@ -121,7 +124,7 @@ class GeneratedConfig:
Planner_Item_Shards_of_Desires = {}
# Group `Weekly`
Weekly_Name = 'Echo_of_War_Divine_Seed' # Echo_of_War_Destruction_Beginning, Echo_of_War_End_of_the_Eternal_Freeze, Echo_of_War_Divine_Seed, Echo_of_War_Borehole_Planet_Old_Crater, Echo_of_War_Salutations_of_Ashen_Dreams
Weekly_Name = 'Echo_of_War_Divine_Seed' # Echo_of_War_Destruction_Beginning, Echo_of_War_End_of_the_Eternal_Freeze, Echo_of_War_Divine_Seed, Echo_of_War_Borehole_Planet_Old_Crater, Echo_of_War_Salutations_of_Ashen_Dreams, Echo_of_War_Inner_Beast_Battlefield
Weekly_Team = 1 # 1, 2, 3, 4, 5, 6, 7, 8, 9
# Group `DailyStorage`
@ -182,7 +185,7 @@ class GeneratedConfig:
RogueDebug_DebugMode = False
# Group `Ornament`
Ornament_Dungeon = 'Divergent_Universe_Eternal_Comedy' # Divergent_Universe_Eternal_Comedy, Divergent_Universe_To_Sweet_Dreams, Divergent_Universe_Pouring_Blades, Divergent_Universe_Fruit_of_Evil, Divergent_Universe_Permafrost, Divergent_Universe_Gentle_Words, Divergent_Universe_Smelted_Heart, Divergent_Universe_Untoppled_Walls
Ornament_Dungeon = 'Divergent_Universe_Eternal_Comedy' # Divergent_Universe_Famished_Worker, Divergent_Universe_Eternal_Comedy, Divergent_Universe_To_Sweet_Dreams, Divergent_Universe_Pouring_Blades, Divergent_Universe_Fruit_of_Evil, Divergent_Universe_Permafrost, Divergent_Universe_Gentle_Words, Divergent_Universe_Smelted_Heart, Divergent_Universe_Untoppled_Walls
Ornament_UseImmersifier = True # True
Ornament_DoubleEvent = True # True
Ornament_UseStamina = False

View File

@ -100,7 +100,7 @@ class ConfigGenerator:
option_add(keys='Ornament.Dungeon.option', options=ornament)
# Insert characters
from tasks.character.keywords import CharacterList
unsupported_characters = []
unsupported_characters = ['Lingsha']
characters = [character.name for character in CharacterList.instances.values()
if character.name not in unsupported_characters]
option_add(keys='DungeonSupport.Character.option', options=characters)

View File

@ -238,15 +238,15 @@
"Name": {
"name": "Dungeon Name",
"help": "Default dungeon setting",
"Calyx_Golden_Memories_Jarilo_VI": "Material: Character EXP (Bud of Memories (Jarilo-Ⅵ))",
"Calyx_Golden_Memories_The_Xianzhou_Luofu": "Material: Character EXP (Bud of Memories (The Xianzhou Luofu))",
"Calyx_Golden_Memories_Penacony": "Material: Character EXP (Bud of Memories (Penacony))",
"Calyx_Golden_Aether_Jarilo_VI": "Material: Light Cone EXP (Bud of Aether (Jarilo-Ⅵ))",
"Calyx_Golden_Aether_The_Xianzhou_Luofu": "Material: Light Cone EXP (Bud of Aether (The Xianzhou Luofu))",
"Calyx_Golden_Aether_Penacony": "Material: Light Cone EXP (Bud of Aether (Penacony))",
"Calyx_Golden_Treasures_Jarilo_VI": "Material: Credit (Bud of Treasures (Jarilo-Ⅵ))",
"Calyx_Golden_Treasures_The_Xianzhou_Luofu": "Material: Credit (Bud of Treasures (The Xianzhou Luofu))",
"Calyx_Golden_Treasures_Penacony": "Material: Credit (Bud of Treasures (Penacony))",
"Calyx_Golden_Memories_Jarilo_VI": "Material: Character EXP (Bud of Memories)",
"Calyx_Golden_Memories_The_Xianzhou_Luofu": "Material: Character EXP (Bud of Memories)",
"Calyx_Golden_Memories_Penacony": "Material: Character EXP (Bud of Memories)",
"Calyx_Golden_Aether_Jarilo_VI": "Material: Light Cone EXP (Bud of Aether)",
"Calyx_Golden_Aether_The_Xianzhou_Luofu": "Material: Light Cone EXP (Bud of Aether)",
"Calyx_Golden_Aether_Penacony": "Material: Light Cone EXP (Bud of Aether)",
"Calyx_Golden_Treasures_Jarilo_VI": "Material: Credit (Bud of Treasures)",
"Calyx_Golden_Treasures_The_Xianzhou_Luofu": "Material: Credit (Bud of Treasures)",
"Calyx_Golden_Treasures_Penacony": "Material: Credit (Bud of Treasures)",
"Calyx_Crimson_Destruction_Herta_StorageZone": "Trace: Destruction (Storage Zone)",
"Calyx_Crimson_Destruction_Luofu_ScalegorgeWaterscape": "Trace: Destruction (Scalegorge Waterscape)",
"Calyx_Crimson_Preservation_Herta_SupplyZone": "Trace: Preservation (Supply Zone)",
@ -266,14 +266,16 @@
"Stagnant_Shadow_Duty": "Ascension: Physical (Boothill / Robin / Yunli)",
"Stagnant_Shadow_Blaze": "Ascension: Fire (Himeko / Asta / Hook)",
"Stagnant_Shadow_Scorch": "Ascension: Fire (Guinaifen / Topaz & Numby)",
"Stagnant_Shadow_Ire": "Ascension: Fire (Firefly / Gallagher / Jiaoqiu)",
"Stagnant_Shadow_Ire": "Ascension: Fire (Firefly / Gallagher / Jiaoqiu / Lingsha)",
"Stagnant_Shadow_Rime": "Ascension: Ice (March 7th / Herta / Gepard / Pela)",
"Stagnant_Shadow_Icicle": "Ascension: Ice (Yanqing / Jingliu / Ruan Mei)",
"Stagnant_Shadow_Nectar": "Ascension: Ice (Misha)",
"Stagnant_Shadow_Fulmination": "Ascension: Lightning (Arlan / Serval / Tingyun / Bailu)",
"Stagnant_Shadow_Doom": "Ascension: Lightning (Kafka / Jing Yuan / Acheron)",
"Stagnant_Shadow_Mechwolf": "Ascension: Lightning (Moze)",
"Stagnant_Shadow_Gust": "Ascension: Wind (Dan Heng / Bronya / Sampo)",
"Stagnant_Shadow_Celestial": "Ascension: Wind (Blade / Huohuo / Black Swan)",
"Stagnant_Shadow_Gloam": "Ascension: Wind (Feixiao)",
"Stagnant_Shadow_Quanta": "Ascension: Quantum (Silver Wolf / Seele / Qingque)",
"Stagnant_Shadow_Abomination": "Ascension: Quantum (Lynx / Fu Xuan / Xueyi)",
"Stagnant_Shadow_Roast": "Ascension: Quantum (Jade / Sparkle)",
@ -293,15 +295,15 @@
"NameAtDoubleCalyx": {
"name": "At Double Calyx Event, choose dungeon",
"help": "Return to the default dungeon settings after double times exhausted",
"Calyx_Golden_Memories_Jarilo_VI": "Material: Character EXP (Bud of Memories (Jarilo-Ⅵ))",
"Calyx_Golden_Memories_The_Xianzhou_Luofu": "Material: Character EXP (Bud of Memories (The Xianzhou Luofu))",
"Calyx_Golden_Memories_Penacony": "Material: Character EXP (Bud of Memories (Penacony))",
"Calyx_Golden_Aether_Jarilo_VI": "Material: Light Cone EXP (Bud of Aether (Jarilo-Ⅵ))",
"Calyx_Golden_Aether_The_Xianzhou_Luofu": "Material: Light Cone EXP (Bud of Aether (The Xianzhou Luofu))",
"Calyx_Golden_Aether_Penacony": "Material: Light Cone EXP (Bud of Aether (Penacony))",
"Calyx_Golden_Treasures_Jarilo_VI": "Material: Credit (Bud of Treasures (Jarilo-Ⅵ))",
"Calyx_Golden_Treasures_The_Xianzhou_Luofu": "Material: Credit (Bud of Treasures (The Xianzhou Luofu))",
"Calyx_Golden_Treasures_Penacony": "Material: Credit (Bud of Treasures (Penacony))",
"Calyx_Golden_Memories_Jarilo_VI": "Material: Character EXP (Bud of Memories)",
"Calyx_Golden_Memories_The_Xianzhou_Luofu": "Material: Character EXP (Bud of Memories)",
"Calyx_Golden_Memories_Penacony": "Material: Character EXP (Bud of Memories)",
"Calyx_Golden_Aether_Jarilo_VI": "Material: Light Cone EXP (Bud of Aether)",
"Calyx_Golden_Aether_The_Xianzhou_Luofu": "Material: Light Cone EXP (Bud of Aether)",
"Calyx_Golden_Aether_Penacony": "Material: Light Cone EXP (Bud of Aether)",
"Calyx_Golden_Treasures_Jarilo_VI": "Material: Credit (Bud of Treasures)",
"Calyx_Golden_Treasures_The_Xianzhou_Luofu": "Material: Credit (Bud of Treasures)",
"Calyx_Golden_Treasures_Penacony": "Material: Credit (Bud of Treasures)",
"Calyx_Crimson_Destruction_Herta_StorageZone": "Trace: Destruction (Storage Zone)",
"Calyx_Crimson_Destruction_Luofu_ScalegorgeWaterscape": "Trace: Destruction (Scalegorge Waterscape)",
"Calyx_Crimson_Preservation_Herta_SupplyZone": "Trace: Preservation (Supply Zone)",
@ -393,6 +395,7 @@
"DanHeng": "Dan Heng",
"DanHengImbibitorLunae": "Dan Heng • Imbibitor Lunae",
"DrRatio": "Dr. Ratio",
"Feixiao": "Feixiao",
"Firefly": "Firefly",
"FuXuan": "Fu Xuan",
"Gallagher": "Gallagher",
@ -414,6 +417,7 @@
"March7thPreservation": "March 7th: Preservation",
"March7thTheHunt": "March 7th: The Hunt",
"Misha": "Misha",
"Moze": "Moze",
"Natasha": "Natasha",
"Pela": "Pela",
"Qingque": "Qingque",
@ -567,13 +571,21 @@
"help": ""
},
"Item_Raging_Heart": {
"name": "Ascension: Fire (Firefly / Gallagher / Jiaoqiu)",
"name": "Ascension: Fire (Firefly / Gallagher / Jiaoqiu / Lingsha)",
"help": ""
},
"Item_Dream_Fridge": {
"name": "Ascension: Ice (Misha)",
"help": ""
},
"Item_Nail_of_the_Beast_Coffin": {
"name": "Ascension: Lightning (Moze)",
"help": ""
},
"Item_A_Glass_of_the_Besotted_Era": {
"name": "Ascension: Wind (Feixiao)",
"help": ""
},
"Item_Dream_Flamer": {
"name": "Ascension: Quantum (Jade / Sparkle)",
"help": ""
@ -658,6 +670,10 @@
"name": "Salutations of Ashen Dreams (Penacony)",
"help": ""
},
"Item_Auspice_Sliver": {
"name": "Inner Beast's Battlefield (The Xianzhou Luofu)",
"help": ""
},
"Item_Squirming_Core": {
"name": "Squirming Core",
"help": ""
@ -703,7 +719,8 @@
"Echo_of_War_End_of_the_Eternal_Freeze": "End of the Eternal Freeze (Jarilo-VI)",
"Echo_of_War_Divine_Seed": "Divine Seed (The Xianzhou Luofu)",
"Echo_of_War_Borehole_Planet_Old_Crater": "Borehole Planet's Old Crater (Herta Space Station)",
"Echo_of_War_Salutations_of_Ashen_Dreams": "Salutations of Ashen Dreams (Penacony)"
"Echo_of_War_Salutations_of_Ashen_Dreams": "Salutations of Ashen Dreams (Penacony)",
"Echo_of_War_Inner_Beast_Battlefield": "Inner Beast's Battlefield (The Xianzhou Luofu)"
},
"Team": {
"name": "Dungeon Team",
@ -933,11 +950,11 @@
"World": {
"name": "World",
"help": "",
"Simulated_Universe_World_3": "Simulated Universe: World 3",
"Simulated_Universe_World_4": "Simulated Universe: World 4",
"Simulated_Universe_World_5": "Simulated Universe: World 5",
"Simulated_Universe_World_6": "Simulated Universe: World 6",
"Simulated_Universe_World_8": "Simulated Universe: World 8"
"Simulated_Universe_World_3": "World 3",
"Simulated_Universe_World_4": "World 4",
"Simulated_Universe_World_5": "World 5",
"Simulated_Universe_World_6": "World 6",
"Simulated_Universe_World_8": "World 8"
},
"Path": {
"name": "Path",
@ -1047,6 +1064,7 @@
"Dungeon": {
"name": "Dungeon Name",
"help": "",
"Divergent_Universe_Famished_Worker": "Divergent_Universe_Famished_Worker (Famished Worker)",
"Divergent_Universe_Eternal_Comedy": "Running Wolves & Kalpagni Lantern (Eternal Comedy)",
"Divergent_Universe_To_Sweet_Dreams": "Sigonia & Izumo Gensei (To Sweet Dreams)",
"Divergent_Universe_Pouring_Blades": "Firmament & Penacony (Pouring Blades)",

View File

@ -238,15 +238,15 @@
"Name": {
"name": "Nombre de la Mazmorra",
"help": "Ajustes predeterminados de las mazmorras",
"Calyx_Golden_Memories_Jarilo_VI": "Material: EXP de personaje (Flor de los recuerdos (Jarilo-Ⅵ))",
"Calyx_Golden_Memories_The_Xianzhou_Luofu": "Material: EXP de personaje (Flor de los recuerdos (El Luofu de Xianzhou))",
"Calyx_Golden_Memories_Penacony": "Material: EXP de personaje (Flor de los recuerdos (Colonipenal))",
"Calyx_Golden_Aether_Jarilo_VI": "Material: EXP de conos de luz (Flor de éter (Jarilo-Ⅵ))",
"Calyx_Golden_Aether_The_Xianzhou_Luofu": "Material: EXP de conos de luz (Flor de éter (El Luofu de Xianzhou))",
"Calyx_Golden_Aether_Penacony": "Material: EXP de conos de luz (Flor de éter (Colonipenal))",
"Calyx_Golden_Treasures_Jarilo_VI": "Material: Créditos (Flor de tesoros (Jarilo-Ⅵ))",
"Calyx_Golden_Treasures_The_Xianzhou_Luofu": "Material: Créditos (Flor de tesoros (El Luofu de Xianzhou))",
"Calyx_Golden_Treasures_Penacony": "Material: Créditos (Flor de tesoros (Colonipenal))",
"Calyx_Golden_Memories_Jarilo_VI": "Material: EXP de personaje (Flor de los recuerdos)",
"Calyx_Golden_Memories_The_Xianzhou_Luofu": "Material: EXP de personaje (Flor de los recuerdos)",
"Calyx_Golden_Memories_Penacony": "Material: EXP de personaje (Flor de los recuerdos)",
"Calyx_Golden_Aether_Jarilo_VI": "Material: EXP de conos de luz (Flor de éter)",
"Calyx_Golden_Aether_The_Xianzhou_Luofu": "Material: EXP de conos de luz (Flor de éter)",
"Calyx_Golden_Aether_Penacony": "Material: EXP de conos de luz (Flor de éter)",
"Calyx_Golden_Treasures_Jarilo_VI": "Material: Créditos (Flor de tesoros)",
"Calyx_Golden_Treasures_The_Xianzhou_Luofu": "Material: Créditos (Flor de tesoros)",
"Calyx_Golden_Treasures_Penacony": "Material: Créditos (Flor de tesoros)",
"Calyx_Crimson_Destruction_Herta_StorageZone": "Rastros: Destrucción (Zona de almacenamiento)",
"Calyx_Crimson_Destruction_Luofu_ScalegorgeWaterscape": "Rastros: Destrucción (Desfiladero de Escamas)",
"Calyx_Crimson_Preservation_Herta_SupplyZone": "Rastros: Conservación (Zona de suministros)",
@ -266,14 +266,16 @@
"Stagnant_Shadow_Duty": "Ascension: Físico (Boothill / Robin / Yunli)",
"Stagnant_Shadow_Blaze": "Ascension: Fuego (Himeko / Asta / Hook)",
"Stagnant_Shadow_Scorch": "Ascension: Fuego (Guinaifen / Topaz y Conti)",
"Stagnant_Shadow_Ire": "Ascension: Fuego (Luciérnaga / Gallagher / Jiaoqiu)",
"Stagnant_Shadow_Ire": "Ascension: Fuego (Luciérnaga / Gallagher / Jiaoqiu / Lingsha)",
"Stagnant_Shadow_Rime": "Ascension: Hielo (Siete de Marzo / Herta / Gepard / Pela)",
"Stagnant_Shadow_Icicle": "Ascension: Hielo (Yanqing / Jingliu / Ruan Mei)",
"Stagnant_Shadow_Nectar": "Ascension: Hielo (Misha)",
"Stagnant_Shadow_Fulmination": "Ascension: Rayo (Arlan / Serval / Tingyun / Bailu)",
"Stagnant_Shadow_Doom": "Ascension: Rayo (Kafka / Jing Yuan / Acheron)",
"Stagnant_Shadow_Mechwolf": "Ascension: Rayo (Moze)",
"Stagnant_Shadow_Gust": "Ascension: Viento (Dan Heng / Bronya / Sampo)",
"Stagnant_Shadow_Celestial": "Ascension: Viento (Blade / Huohuo / Cisne Negro)",
"Stagnant_Shadow_Gloam": "Ascension: Viento (Feixiao)",
"Stagnant_Shadow_Quanta": "Ascension: Cuántico (Silver Wolf / Seele / Qingque)",
"Stagnant_Shadow_Abomination": "Ascension: Cuántico (Lynx / Fu Xuan / Xueyi)",
"Stagnant_Shadow_Roast": "Ascension: Cuántico (Jade / Sparkle)",
@ -293,15 +295,15 @@
"NameAtDoubleCalyx": {
"name": "En los eventos de x2 de Cáliz",
"help": "Se volverán a los ajustes predeterminados una vez se acaben los intentos del evento",
"Calyx_Golden_Memories_Jarilo_VI": "Material: EXP de personaje (Flor de los recuerdos (Jarilo-Ⅵ))",
"Calyx_Golden_Memories_The_Xianzhou_Luofu": "Material: EXP de personaje (Flor de los recuerdos (El Luofu de Xianzhou))",
"Calyx_Golden_Memories_Penacony": "Material: EXP de personaje (Flor de los recuerdos (Colonipenal))",
"Calyx_Golden_Aether_Jarilo_VI": "Material: EXP de conos de luz (Flor de éter (Jarilo-Ⅵ))",
"Calyx_Golden_Aether_The_Xianzhou_Luofu": "Material: EXP de conos de luz (Flor de éter (El Luofu de Xianzhou))",
"Calyx_Golden_Aether_Penacony": "Material: EXP de conos de luz (Flor de éter (Colonipenal))",
"Calyx_Golden_Treasures_Jarilo_VI": "Material: Créditos (Flor de tesoros (Jarilo-Ⅵ))",
"Calyx_Golden_Treasures_The_Xianzhou_Luofu": "Material: Créditos (Flor de tesoros (El Luofu de Xianzhou))",
"Calyx_Golden_Treasures_Penacony": "Material: Créditos (Flor de tesoros (Colonipenal))",
"Calyx_Golden_Memories_Jarilo_VI": "Material: EXP de personaje (Flor de los recuerdos)",
"Calyx_Golden_Memories_The_Xianzhou_Luofu": "Material: EXP de personaje (Flor de los recuerdos)",
"Calyx_Golden_Memories_Penacony": "Material: EXP de personaje (Flor de los recuerdos)",
"Calyx_Golden_Aether_Jarilo_VI": "Material: EXP de conos de luz (Flor de éter)",
"Calyx_Golden_Aether_The_Xianzhou_Luofu": "Material: EXP de conos de luz (Flor de éter)",
"Calyx_Golden_Aether_Penacony": "Material: EXP de conos de luz (Flor de éter)",
"Calyx_Golden_Treasures_Jarilo_VI": "Material: Créditos (Flor de tesoros)",
"Calyx_Golden_Treasures_The_Xianzhou_Luofu": "Material: Créditos (Flor de tesoros)",
"Calyx_Golden_Treasures_Penacony": "Material: Créditos (Flor de tesoros)",
"Calyx_Crimson_Destruction_Herta_StorageZone": "Rastros: Destrucción (Zona de almacenamiento)",
"Calyx_Crimson_Destruction_Luofu_ScalegorgeWaterscape": "Rastros: Destrucción (Desfiladero de Escamas)",
"Calyx_Crimson_Preservation_Herta_SupplyZone": "Rastros: Conservación (Zona de suministros)",
@ -393,6 +395,7 @@
"DanHeng": "Dan Heng",
"DanHengImbibitorLunae": "Dan Heng - Imbibitor Lunae",
"DrRatio": "Dr. Ratio",
"Feixiao": "Feixiao",
"Firefly": "Luciérnaga",
"FuXuan": "Fu Xuan",
"Gallagher": "Gallagher",
@ -414,6 +417,7 @@
"March7thPreservation": "Siete de Marzo: Conservación",
"March7thTheHunt": "Siete de Marzo: Cacería",
"Misha": "Misha",
"Moze": "Moze",
"Natasha": "Natasha",
"Pela": "Pela",
"Qingque": "Qingque",
@ -567,13 +571,21 @@
"help": ""
},
"Item_Raging_Heart": {
"name": "Ascension: Fuego (Luciérnaga / Gallagher / Jiaoqiu)",
"name": "Ascension: Fuego (Luciérnaga / Gallagher / Jiaoqiu / Lingsha)",
"help": ""
},
"Item_Dream_Fridge": {
"name": "Ascension: Hielo (Misha)",
"help": ""
},
"Item_Nail_of_the_Beast_Coffin": {
"name": "Ascension: Rayo (Moze)",
"help": ""
},
"Item_A_Glass_of_the_Besotted_Era": {
"name": "Ascension: Viento (Feixiao)",
"help": ""
},
"Item_Dream_Flamer": {
"name": "Ascension: Cuántico (Jade / Sparkle)",
"help": ""
@ -658,6 +670,10 @@
"name": "Tributo del sueño ceniciento (Colonipenal)",
"help": ""
},
"Item_Auspice_Sliver": {
"name": "Campo de batalla de la bestia interior (El Luofu de Xianzhou)",
"help": ""
},
"Item_Squirming_Core": {
"name": "Núcleo serpenteante",
"help": ""
@ -703,7 +719,8 @@
"Echo_of_War_End_of_the_Eternal_Freeze": "El fin del Hielo Eterno (Jarilo-VI)",
"Echo_of_War_Divine_Seed": "Semilla divina (El Luofu de Xianzhou)",
"Echo_of_War_Borehole_Planet_Old_Crater": "Cráter del planeta devorado (Estación Espacial Herta)",
"Echo_of_War_Salutations_of_Ashen_Dreams": "Tributo del sueño ceniciento (Colonipenal)"
"Echo_of_War_Salutations_of_Ashen_Dreams": "Tributo del sueño ceniciento (Colonipenal)",
"Echo_of_War_Inner_Beast_Battlefield": "Campo de batalla de la bestia interior (El Luofu de Xianzhou)"
},
"Team": {
"name": "Equipo de mazmorra",
@ -1047,6 +1064,7 @@
"Dungeon": {
"name": "Nombre de la Mazmorra",
"help": "",
"Divergent_Universe_Famished_Worker": "Divergent_Universe_Famished_Worker (Obrero famélico)",
"Divergent_Universe_Eternal_Comedy": " (Comedia eterna)",
"Divergent_Universe_To_Sweet_Dreams": " (Hasta los dulces sueños)",
"Divergent_Universe_Pouring_Blades": " (Lluvia de espadas)",

View File

@ -238,15 +238,15 @@
"Name": {
"name": "Dungeon.Name.name",
"help": "Dungeon.Name.help",
"Calyx_Golden_Memories_Jarilo_VI": "素材:役割経験(回憶の蕾・ヤリーロ-Ⅵ",
"Calyx_Golden_Memories_The_Xianzhou_Luofu": "素材:役割経験(回憶の蕾・仙舟羅浮",
"Calyx_Golden_Memories_Penacony": "素材:役割経験(回憶の蕾・ピノコニー",
"Calyx_Golden_Aether_Jarilo_VI": "素材:武器経験(エーテルの蕾・ヤリーロ-Ⅵ",
"Calyx_Golden_Aether_The_Xianzhou_Luofu": "素材:武器経験(エーテルの蕾・仙舟羅浮",
"Calyx_Golden_Aether_Penacony": "素材:武器経験(エーテルの蕾・ピノコニー",
"Calyx_Golden_Treasures_Jarilo_VI": "素材:クレジット(秘蔵の蕾・ヤリーロ-Ⅵ",
"Calyx_Golden_Treasures_The_Xianzhou_Luofu": "素材:クレジット(秘蔵の蕾・仙舟羅浮",
"Calyx_Golden_Treasures_Penacony": "素材:クレジット(秘蔵の蕾・ピノコニー",
"Calyx_Golden_Memories_Jarilo_VI": "素材:役割経験(回憶の蕾",
"Calyx_Golden_Memories_The_Xianzhou_Luofu": "素材:役割経験(回憶の蕾",
"Calyx_Golden_Memories_Penacony": "素材:役割経験(回憶の蕾",
"Calyx_Golden_Aether_Jarilo_VI": "素材:武器経験(エーテルの蕾",
"Calyx_Golden_Aether_The_Xianzhou_Luofu": "素材:武器経験(エーテルの蕾",
"Calyx_Golden_Aether_Penacony": "素材:武器経験(エーテルの蕾",
"Calyx_Golden_Treasures_Jarilo_VI": "素材:クレジット(秘蔵の蕾",
"Calyx_Golden_Treasures_The_Xianzhou_Luofu": "素材:クレジット(秘蔵の蕾",
"Calyx_Golden_Treasures_Penacony": "素材:クレジット(秘蔵の蕾",
"Calyx_Crimson_Destruction_Herta_StorageZone": "軌跡素材:壊滅(収容部分)",
"Calyx_Crimson_Destruction_Luofu_ScalegorgeWaterscape": "軌跡素材:壊滅(鱗淵境)",
"Calyx_Crimson_Preservation_Herta_SupplyZone": "軌跡素材:存護(サポート部分)",
@ -266,42 +266,44 @@
"Stagnant_Shadow_Duty": "キャラクター昇格素材:物理(ブートヒル / ロビン / 雲璃)",
"Stagnant_Shadow_Blaze": "キャラクター昇格素材:炎(姫子 / アスター / フック)",
"Stagnant_Shadow_Scorch": "キャラクター昇格素材:炎(桂乃芬 / トパーズ&カブ)",
"Stagnant_Shadow_Ire": "キャラクター昇格素材:炎(ホタル / ギャラガー / 椒丘",
"Stagnant_Shadow_Ire": "キャラクター昇格素材:炎(ホタル / ギャラガー / 椒丘 / 霊砂",
"Stagnant_Shadow_Rime": "キャラクター昇格素材:氷(三月なのか / ヘルタ / ジェパード / ペラ)",
"Stagnant_Shadow_Icicle": "キャラクター昇格素材:氷(彦卿 / 鏡流 / ルアン・メェイ)",
"Stagnant_Shadow_Nectar": "キャラクター昇格素材:氷(ミーシャ)",
"Stagnant_Shadow_Fulmination": "キャラクター昇格素材:雷(アーラン / セーバル / 停雲 / 白露)",
"Stagnant_Shadow_Doom": "キャラクター昇格素材:雷(カフカ / 景元 / 黄泉)",
"Stagnant_Shadow_Mechwolf": "キャラクター昇格素材:雷(モゼ)",
"Stagnant_Shadow_Gust": "キャラクター昇格素材:風(丹恒 / ブローニャ / サンポ)",
"Stagnant_Shadow_Celestial": "キャラクター昇格素材:風(刃 / フォフォ / ブラックスワン)",
"Stagnant_Shadow_Gloam": "キャラクター昇格素材:風(飛霄)",
"Stagnant_Shadow_Quanta": "キャラクター昇格素材:量子(銀狼 / ゼーレ / 青雀)",
"Stagnant_Shadow_Abomination": "キャラクター昇格素材:量子(リンクス / 符玄 / 雪衣)",
"Stagnant_Shadow_Roast": "キャラクター昇格素材:量子(ジェイド / 花火)",
"Stagnant_Shadow_Mirage": "キャラクター昇格素材:虚数(ヴェルト / 羅刹 / 御空)",
"Stagnant_Shadow_Puppetry": "キャラクター昇格素材:虚数(丹恒・飲月 / アベンチュリン / Dr.レイシオ)",
"Cavern_of_Corrosion_Path_of_Gelid_Wind": "侵蝕トンネル・霜風の路(侵蝕トンネル・霜風の路)",
"Cavern_of_Corrosion_Path_of_Jabbing_Punch": "侵蝕トンネル・迅拳の路(侵蝕トンネル・迅拳の路)",
"Cavern_of_Corrosion_Path_of_Drifting": "侵蝕トンネル・漂泊の路(侵蝕トンネル・漂泊の路)",
"Cavern_of_Corrosion_Path_of_Providence": "侵蝕トンネル・睿治の路(侵蝕トンネル・睿治の路)",
"Cavern_of_Corrosion_Path_of_Holy_Hymn": "侵蝕トンネル・聖頌の路(侵蝕トンネル・聖頌の路)",
"Cavern_of_Corrosion_Path_of_Conflagration": "侵蝕トンネル・野焔の路(侵蝕トンネル・野焔の路)",
"Cavern_of_Corrosion_Path_of_Elixir_Seekers": "侵蝕トンネル・薬使の路(侵蝕トンネル・薬使の路)",
"Cavern_of_Corrosion_Path_of_Darkness": "侵蝕トンネル・幽冥の路(侵蝕トンネル・幽冥の路)",
"Cavern_of_Corrosion_Path_of_Dreamdive": "侵蝕トンネル・夢潜の路(侵蝕トンネル・夢潜の路)",
"Cavern_of_Corrosion_Path_of_Cavalier": "侵蝕トンネル・勇騎の路(侵蝕トンネル・勇騎の路)"
"Cavern_of_Corrosion_Path_of_Gelid_Wind": "侵蝕トンネル・霜風の路(霜風の路)",
"Cavern_of_Corrosion_Path_of_Jabbing_Punch": "侵蝕トンネル・迅拳の路(迅拳の路)",
"Cavern_of_Corrosion_Path_of_Drifting": "侵蝕トンネル・漂泊の路(漂泊の路)",
"Cavern_of_Corrosion_Path_of_Providence": "侵蝕トンネル・睿治の路(睿治の路)",
"Cavern_of_Corrosion_Path_of_Holy_Hymn": "侵蝕トンネル・聖頌の路(聖頌の路)",
"Cavern_of_Corrosion_Path_of_Conflagration": "侵蝕トンネル・野焔の路(野焔の路)",
"Cavern_of_Corrosion_Path_of_Elixir_Seekers": "侵蝕トンネル・薬使の路(薬使の路)",
"Cavern_of_Corrosion_Path_of_Darkness": "侵蝕トンネル・幽冥の路(幽冥の路)",
"Cavern_of_Corrosion_Path_of_Dreamdive": "侵蝕トンネル・夢潜の路(夢潜の路)",
"Cavern_of_Corrosion_Path_of_Cavalier": "侵蝕トンネル・勇騎の路(勇騎の路)"
},
"NameAtDoubleCalyx": {
"name": "Dungeon.NameAtDoubleCalyx.name",
"help": "Dungeon.NameAtDoubleCalyx.help",
"Calyx_Golden_Memories_Jarilo_VI": "素材:役割経験(回憶の蕾・ヤリーロ-Ⅵ",
"Calyx_Golden_Memories_The_Xianzhou_Luofu": "素材:役割経験(回憶の蕾・仙舟羅浮",
"Calyx_Golden_Memories_Penacony": "素材:役割経験(回憶の蕾・ピノコニー",
"Calyx_Golden_Aether_Jarilo_VI": "素材:武器経験(エーテルの蕾・ヤリーロ-Ⅵ",
"Calyx_Golden_Aether_The_Xianzhou_Luofu": "素材:武器経験(エーテルの蕾・仙舟羅浮",
"Calyx_Golden_Aether_Penacony": "素材:武器経験(エーテルの蕾・ピノコニー",
"Calyx_Golden_Treasures_Jarilo_VI": "素材:クレジット(秘蔵の蕾・ヤリーロ-Ⅵ",
"Calyx_Golden_Treasures_The_Xianzhou_Luofu": "素材:クレジット(秘蔵の蕾・仙舟羅浮",
"Calyx_Golden_Treasures_Penacony": "素材:クレジット(秘蔵の蕾・ピノコニー",
"Calyx_Golden_Memories_Jarilo_VI": "素材:役割経験(回憶の蕾",
"Calyx_Golden_Memories_The_Xianzhou_Luofu": "素材:役割経験(回憶の蕾",
"Calyx_Golden_Memories_Penacony": "素材:役割経験(回憶の蕾",
"Calyx_Golden_Aether_Jarilo_VI": "素材:武器経験(エーテルの蕾",
"Calyx_Golden_Aether_The_Xianzhou_Luofu": "素材:武器経験(エーテルの蕾",
"Calyx_Golden_Aether_Penacony": "素材:武器経験(エーテルの蕾",
"Calyx_Golden_Treasures_Jarilo_VI": "素材:クレジット(秘蔵の蕾",
"Calyx_Golden_Treasures_The_Xianzhou_Luofu": "素材:クレジット(秘蔵の蕾",
"Calyx_Golden_Treasures_Penacony": "素材:クレジット(秘蔵の蕾",
"Calyx_Crimson_Destruction_Herta_StorageZone": "軌跡素材:壊滅(収容部分)",
"Calyx_Crimson_Destruction_Luofu_ScalegorgeWaterscape": "軌跡素材:壊滅(鱗淵境)",
"Calyx_Crimson_Preservation_Herta_SupplyZone": "軌跡素材:存護(サポート部分)",
@ -320,16 +322,16 @@
"NameAtDoubleRelic": {
"name": "Dungeon.NameAtDoubleRelic.name",
"help": "Dungeon.NameAtDoubleRelic.help",
"Cavern_of_Corrosion_Path_of_Gelid_Wind": "侵蝕トンネル・霜風の路(侵蝕トンネル・霜風の路)",
"Cavern_of_Corrosion_Path_of_Jabbing_Punch": "侵蝕トンネル・迅拳の路(侵蝕トンネル・迅拳の路)",
"Cavern_of_Corrosion_Path_of_Drifting": "侵蝕トンネル・漂泊の路(侵蝕トンネル・漂泊の路)",
"Cavern_of_Corrosion_Path_of_Providence": "侵蝕トンネル・睿治の路(侵蝕トンネル・睿治の路)",
"Cavern_of_Corrosion_Path_of_Holy_Hymn": "侵蝕トンネル・聖頌の路(侵蝕トンネル・聖頌の路)",
"Cavern_of_Corrosion_Path_of_Conflagration": "侵蝕トンネル・野焔の路(侵蝕トンネル・野焔の路)",
"Cavern_of_Corrosion_Path_of_Elixir_Seekers": "侵蝕トンネル・薬使の路(侵蝕トンネル・薬使の路)",
"Cavern_of_Corrosion_Path_of_Darkness": "侵蝕トンネル・幽冥の路(侵蝕トンネル・幽冥の路)",
"Cavern_of_Corrosion_Path_of_Dreamdive": "侵蝕トンネル・夢潜の路(侵蝕トンネル・夢潜の路)",
"Cavern_of_Corrosion_Path_of_Cavalier": "侵蝕トンネル・勇騎の路(侵蝕トンネル・勇騎の路)"
"Cavern_of_Corrosion_Path_of_Gelid_Wind": "侵蝕トンネル・霜風の路(霜風の路)",
"Cavern_of_Corrosion_Path_of_Jabbing_Punch": "侵蝕トンネル・迅拳の路(迅拳の路)",
"Cavern_of_Corrosion_Path_of_Drifting": "侵蝕トンネル・漂泊の路(漂泊の路)",
"Cavern_of_Corrosion_Path_of_Providence": "侵蝕トンネル・睿治の路(睿治の路)",
"Cavern_of_Corrosion_Path_of_Holy_Hymn": "侵蝕トンネル・聖頌の路(聖頌の路)",
"Cavern_of_Corrosion_Path_of_Conflagration": "侵蝕トンネル・野焔の路(野焔の路)",
"Cavern_of_Corrosion_Path_of_Elixir_Seekers": "侵蝕トンネル・薬使の路(薬使の路)",
"Cavern_of_Corrosion_Path_of_Darkness": "侵蝕トンネル・幽冥の路(幽冥の路)",
"Cavern_of_Corrosion_Path_of_Dreamdive": "侵蝕トンネル・夢潜の路(夢潜の路)",
"Cavern_of_Corrosion_Path_of_Cavalier": "侵蝕トンネル・勇騎の路(勇騎の路)"
},
"Team": {
"name": "Dungeon.Team.name",
@ -393,6 +395,7 @@
"DanHeng": "丹恒",
"DanHengImbibitorLunae": "丹恒・飲月",
"DrRatio": "Dr.レイシオ",
"Feixiao": "飛霄",
"Firefly": "ホタル",
"FuXuan": "符玄",
"Gallagher": "ギャラガー",
@ -414,6 +417,7 @@
"March7thPreservation": "三月なのか・存護",
"March7thTheHunt": "三月なのか・巡狩",
"Misha": "ミーシャ",
"Moze": "モゼ",
"Natasha": "ナターシャ",
"Pela": "ペラ",
"Qingque": "青雀",
@ -567,13 +571,21 @@
"help": ""
},
"Item_Raging_Heart": {
"name": "キャラクター昇格素材:炎(ホタル / ギャラガー / 椒丘",
"name": "キャラクター昇格素材:炎(ホタル / ギャラガー / 椒丘 / 霊砂",
"help": ""
},
"Item_Dream_Fridge": {
"name": "キャラクター昇格素材:氷(ミーシャ)",
"help": ""
},
"Item_Nail_of_the_Beast_Coffin": {
"name": "キャラクター昇格素材:雷(モゼ)",
"help": ""
},
"Item_A_Glass_of_the_Besotted_Era": {
"name": "キャラクター昇格素材:風(飛霄)",
"help": ""
},
"Item_Dream_Flamer": {
"name": "キャラクター昇格素材:量子(ジェイド / 花火)",
"help": ""
@ -658,6 +670,10 @@
"name": "歴戦余韻・現世の夢の礼賛 (ピノコニー)",
"help": ""
},
"Item_Auspice_Sliver": {
"name": "歴戦余韻・心獣の戦場 (仙舟「羅浮」)",
"help": ""
},
"Item_Squirming_Core": {
"name": "脈動する原核",
"help": ""
@ -703,7 +719,8 @@
"Echo_of_War_End_of_the_Eternal_Freeze": "歴戦余韻・寒波の幕切れ (ヤリーロ-VI)",
"Echo_of_War_Divine_Seed": "歴戦余韻・不死の神実 (仙舟「羅浮」)",
"Echo_of_War_Borehole_Planet_Old_Crater": "歴戦余韻・星を蝕む往日の面影 (宇宙ステーション「ヘルタ」)",
"Echo_of_War_Salutations_of_Ashen_Dreams": "歴戦余韻・現世の夢の礼賛 (ピノコニー)"
"Echo_of_War_Salutations_of_Ashen_Dreams": "歴戦余韻・現世の夢の礼賛 (ピノコニー)",
"Echo_of_War_Inner_Beast_Battlefield": "歴戦余韻・心獣の戦場 (仙舟「羅浮」)"
},
"Team": {
"name": "Weekly.Team.name",
@ -933,11 +950,11 @@
"World": {
"name": "RogueWorld.World.name",
"help": "RogueWorld.World.help",
"Simulated_Universe_World_3": "第三世界・模擬宇宙",
"Simulated_Universe_World_4": "第四世界・模擬宇宙",
"Simulated_Universe_World_5": "第五世界・模擬宇宙",
"Simulated_Universe_World_6": "第六世界・模擬宇宙",
"Simulated_Universe_World_8": "第八世界・模擬宇宙"
"Simulated_Universe_World_3": "第三世界",
"Simulated_Universe_World_4": "第四世界",
"Simulated_Universe_World_5": "第五世界",
"Simulated_Universe_World_6": "第六世界",
"Simulated_Universe_World_8": "第八世界"
},
"Path": {
"name": "RogueWorld.Path.name",
@ -1047,6 +1064,7 @@
"Dungeon": {
"name": "Ornament.Dungeon.name",
"help": "Ornament.Dungeon.help",
"Divergent_Universe_Famished_Worker": "Divergent_Universe_Famished_Worker飢えた虫卒",
"Divergent_Universe_Eternal_Comedy": "(永遠の喜劇)",
"Divergent_Universe_To_Sweet_Dreams": "(寄り添い眠る)",
"Divergent_Universe_Pouring_Blades": "(剣の雨)",

View File

@ -238,15 +238,15 @@
"Name": {
"name": "副本名称",
"help": "默认打本设置",
"Calyx_Golden_Memories_Jarilo_VI": "材料:角色经验(回忆之蕾•雅利洛-Ⅵ",
"Calyx_Golden_Memories_The_Xianzhou_Luofu": "材料:角色经验(回忆之蕾•仙舟罗浮",
"Calyx_Golden_Memories_Penacony": "材料:角色经验(回忆之蕾•匹诺康尼",
"Calyx_Golden_Aether_Jarilo_VI": "材料:武器经验(以太之蕾•雅利洛-Ⅵ",
"Calyx_Golden_Aether_The_Xianzhou_Luofu": "材料:武器经验(以太之蕾•仙舟罗浮",
"Calyx_Golden_Aether_Penacony": "材料:武器经验(以太之蕾•匹诺康尼",
"Calyx_Golden_Treasures_Jarilo_VI": "材料:信用点(藏珍之蕾•雅利洛-Ⅵ",
"Calyx_Golden_Treasures_The_Xianzhou_Luofu": "材料:信用点(藏珍之蕾•仙舟罗浮",
"Calyx_Golden_Treasures_Penacony": "材料:信用点(藏珍之蕾•匹诺康尼",
"Calyx_Golden_Memories_Jarilo_VI": "材料:角色经验(回忆之蕾",
"Calyx_Golden_Memories_The_Xianzhou_Luofu": "材料:角色经验(回忆之蕾",
"Calyx_Golden_Memories_Penacony": "材料:角色经验(回忆之蕾",
"Calyx_Golden_Aether_Jarilo_VI": "材料:武器经验(以太之蕾",
"Calyx_Golden_Aether_The_Xianzhou_Luofu": "材料:武器经验(以太之蕾",
"Calyx_Golden_Aether_Penacony": "材料:武器经验(以太之蕾",
"Calyx_Golden_Treasures_Jarilo_VI": "材料:信用点(藏珍之蕾",
"Calyx_Golden_Treasures_The_Xianzhou_Luofu": "材料:信用点(藏珍之蕾",
"Calyx_Golden_Treasures_Penacony": "材料:信用点(藏珍之蕾",
"Calyx_Crimson_Destruction_Herta_StorageZone": "行迹材料:毁灭(收容舱段)",
"Calyx_Crimson_Destruction_Luofu_ScalegorgeWaterscape": "行迹材料:毁灭(鳞渊境)",
"Calyx_Crimson_Preservation_Herta_SupplyZone": "行迹材料:存护(支援舱段)",
@ -266,42 +266,44 @@
"Stagnant_Shadow_Duty": "角色晋阶材料:物理(波提欧 / 知更鸟 / 云璃)",
"Stagnant_Shadow_Blaze": "角色晋阶材料:火(姬子 / 艾丝妲 / 虎克)",
"Stagnant_Shadow_Scorch": "角色晋阶材料:火(桂乃芬 / 托帕&账账)",
"Stagnant_Shadow_Ire": "角色晋阶材料:火(流萤 / 加拉赫 / 椒丘",
"Stagnant_Shadow_Ire": "角色晋阶材料:火(流萤 / 加拉赫 / 椒丘 / 灵砂",
"Stagnant_Shadow_Rime": "角色晋阶材料:冰(三月七 / 黑塔 / 杰帕德 / 佩拉)",
"Stagnant_Shadow_Icicle": "角色晋阶材料:冰(彦卿 / 镜流 / 阮•梅)",
"Stagnant_Shadow_Nectar": "角色晋阶材料:冰(米沙)",
"Stagnant_Shadow_Fulmination": "角色晋阶材料:雷(阿兰 / 希露瓦 / 停云 / 白露)",
"Stagnant_Shadow_Doom": "角色晋阶材料:雷(卡芙卡 / 景元 / 黄泉)",
"Stagnant_Shadow_Mechwolf": "角色晋阶材料:雷(貊泽)",
"Stagnant_Shadow_Gust": "角色晋阶材料:风(丹恒 / 布洛妮娅 / 桑博)",
"Stagnant_Shadow_Celestial": "角色晋阶材料:风(刃 / 藿藿 / 黑天鹅)",
"Stagnant_Shadow_Gloam": "角色晋阶材料:风(飞霄)",
"Stagnant_Shadow_Quanta": "角色晋阶材料:量子(银狼 / 希儿 / 青雀)",
"Stagnant_Shadow_Abomination": "角色晋阶材料:量子(玲可 / 符玄 / 雪衣)",
"Stagnant_Shadow_Roast": "角色晋阶材料:量子(翡翠 / 花火)",
"Stagnant_Shadow_Mirage": "角色晋阶材料:虚数(瓦尔特 / 罗刹 / 驭空)",
"Stagnant_Shadow_Puppetry": "角色晋阶材料:虚数(丹恒•饮月 / 砂金 / 真理医生)",
"Cavern_of_Corrosion_Path_of_Gelid_Wind": "遗器:冰套+风套(霜风之径•侵蚀隧洞",
"Cavern_of_Corrosion_Path_of_Jabbing_Punch": "遗器:物理套+击破套(迅拳之径•侵蚀隧洞",
"Cavern_of_Corrosion_Path_of_Drifting": "遗器:治疗套+快枪手(漂泊之径•侵蚀隧洞",
"Cavern_of_Corrosion_Path_of_Providence": "遗器:铁卫套+量子套(睿治之径•侵蚀隧洞",
"Cavern_of_Corrosion_Path_of_Holy_Hymn": "遗器:防御套+雷套(圣颂之径•侵蚀隧洞",
"Cavern_of_Corrosion_Path_of_Conflagration": "遗器:火套+虚数套(野焰之径•侵蚀隧洞",
"Cavern_of_Corrosion_Path_of_Elixir_Seekers": "遗器:生命套+速度套(药使之径•侵蚀隧洞",
"Cavern_of_Corrosion_Path_of_Darkness": "遗器:追击套+dot套幽冥之径•侵蚀隧洞",
"Cavern_of_Corrosion_Path_of_Dreamdive": "遗器:负面套+击破套(梦潜之径•侵蚀隧洞",
"Cavern_of_Corrosion_Path_of_Cavalier": "遗器:超击破套+终追套(勇骑之径•侵蚀隧洞"
"Cavern_of_Corrosion_Path_of_Gelid_Wind": "遗器:冰套+风套(霜风之径",
"Cavern_of_Corrosion_Path_of_Jabbing_Punch": "遗器:物理套+击破套(迅拳之径",
"Cavern_of_Corrosion_Path_of_Drifting": "遗器:治疗套+快枪手(漂泊之径",
"Cavern_of_Corrosion_Path_of_Providence": "遗器:铁卫套+量子套(睿治之径",
"Cavern_of_Corrosion_Path_of_Holy_Hymn": "遗器:防御套+雷套(圣颂之径",
"Cavern_of_Corrosion_Path_of_Conflagration": "遗器:火套+虚数套(野焰之径",
"Cavern_of_Corrosion_Path_of_Elixir_Seekers": "遗器:生命套+速度套(药使之径",
"Cavern_of_Corrosion_Path_of_Darkness": "遗器:追击套+dot套幽冥之径",
"Cavern_of_Corrosion_Path_of_Dreamdive": "遗器:负面套+击破套(梦潜之径",
"Cavern_of_Corrosion_Path_of_Cavalier": "遗器:超击破套+终追套(勇骑之径"
},
"NameAtDoubleCalyx": {
"name": "有双倍花活动时,选择副本",
"help": "次数耗尽后回退到默认打本设置",
"Calyx_Golden_Memories_Jarilo_VI": "材料:角色经验(回忆之蕾•雅利洛-Ⅵ",
"Calyx_Golden_Memories_The_Xianzhou_Luofu": "材料:角色经验(回忆之蕾•仙舟罗浮",
"Calyx_Golden_Memories_Penacony": "材料:角色经验(回忆之蕾•匹诺康尼",
"Calyx_Golden_Aether_Jarilo_VI": "材料:武器经验(以太之蕾•雅利洛-Ⅵ",
"Calyx_Golden_Aether_The_Xianzhou_Luofu": "材料:武器经验(以太之蕾•仙舟罗浮",
"Calyx_Golden_Aether_Penacony": "材料:武器经验(以太之蕾•匹诺康尼",
"Calyx_Golden_Treasures_Jarilo_VI": "材料:信用点(藏珍之蕾•雅利洛-Ⅵ",
"Calyx_Golden_Treasures_The_Xianzhou_Luofu": "材料:信用点(藏珍之蕾•仙舟罗浮",
"Calyx_Golden_Treasures_Penacony": "材料:信用点(藏珍之蕾•匹诺康尼",
"Calyx_Golden_Memories_Jarilo_VI": "材料:角色经验(回忆之蕾",
"Calyx_Golden_Memories_The_Xianzhou_Luofu": "材料:角色经验(回忆之蕾",
"Calyx_Golden_Memories_Penacony": "材料:角色经验(回忆之蕾",
"Calyx_Golden_Aether_Jarilo_VI": "材料:武器经验(以太之蕾",
"Calyx_Golden_Aether_The_Xianzhou_Luofu": "材料:武器经验(以太之蕾",
"Calyx_Golden_Aether_Penacony": "材料:武器经验(以太之蕾",
"Calyx_Golden_Treasures_Jarilo_VI": "材料:信用点(藏珍之蕾",
"Calyx_Golden_Treasures_The_Xianzhou_Luofu": "材料:信用点(藏珍之蕾",
"Calyx_Golden_Treasures_Penacony": "材料:信用点(藏珍之蕾",
"Calyx_Crimson_Destruction_Herta_StorageZone": "行迹材料:毁灭(收容舱段)",
"Calyx_Crimson_Destruction_Luofu_ScalegorgeWaterscape": "行迹材料:毁灭(鳞渊境)",
"Calyx_Crimson_Preservation_Herta_SupplyZone": "行迹材料:存护(支援舱段)",
@ -320,16 +322,16 @@
"NameAtDoubleRelic": {
"name": "有遗器活动时,选择副本",
"help": "次数耗尽后回退到默认打本设置",
"Cavern_of_Corrosion_Path_of_Gelid_Wind": "遗器:冰套+风套(霜风之径•侵蚀隧洞",
"Cavern_of_Corrosion_Path_of_Jabbing_Punch": "遗器:物理套+击破套(迅拳之径•侵蚀隧洞",
"Cavern_of_Corrosion_Path_of_Drifting": "遗器:治疗套+快枪手(漂泊之径•侵蚀隧洞",
"Cavern_of_Corrosion_Path_of_Providence": "遗器:铁卫套+量子套(睿治之径•侵蚀隧洞",
"Cavern_of_Corrosion_Path_of_Holy_Hymn": "遗器:防御套+雷套(圣颂之径•侵蚀隧洞",
"Cavern_of_Corrosion_Path_of_Conflagration": "遗器:火套+虚数套(野焰之径•侵蚀隧洞",
"Cavern_of_Corrosion_Path_of_Elixir_Seekers": "遗器:生命套+速度套(药使之径•侵蚀隧洞",
"Cavern_of_Corrosion_Path_of_Darkness": "遗器:追击套+dot套幽冥之径•侵蚀隧洞",
"Cavern_of_Corrosion_Path_of_Dreamdive": "遗器:负面套+击破套(梦潜之径•侵蚀隧洞",
"Cavern_of_Corrosion_Path_of_Cavalier": "遗器:超击破套+终追套(勇骑之径•侵蚀隧洞"
"Cavern_of_Corrosion_Path_of_Gelid_Wind": "遗器:冰套+风套(霜风之径",
"Cavern_of_Corrosion_Path_of_Jabbing_Punch": "遗器:物理套+击破套(迅拳之径",
"Cavern_of_Corrosion_Path_of_Drifting": "遗器:治疗套+快枪手(漂泊之径",
"Cavern_of_Corrosion_Path_of_Providence": "遗器:铁卫套+量子套(睿治之径",
"Cavern_of_Corrosion_Path_of_Holy_Hymn": "遗器:防御套+雷套(圣颂之径",
"Cavern_of_Corrosion_Path_of_Conflagration": "遗器:火套+虚数套(野焰之径",
"Cavern_of_Corrosion_Path_of_Elixir_Seekers": "遗器:生命套+速度套(药使之径",
"Cavern_of_Corrosion_Path_of_Darkness": "遗器:追击套+dot套幽冥之径",
"Cavern_of_Corrosion_Path_of_Dreamdive": "遗器:负面套+击破套(梦潜之径",
"Cavern_of_Corrosion_Path_of_Cavalier": "遗器:超击破套+终追套(勇骑之径"
},
"Team": {
"name": "打本队伍",
@ -393,6 +395,7 @@
"DanHeng": "丹恒",
"DanHengImbibitorLunae": "丹恒•饮月",
"DrRatio": "真理医生",
"Feixiao": "飞霄",
"Firefly": "流萤",
"FuXuan": "符玄",
"Gallagher": "加拉赫",
@ -414,6 +417,7 @@
"March7thPreservation": "三月七•存护",
"March7thTheHunt": "三月七•巡猎",
"Misha": "米沙",
"Moze": "貊泽",
"Natasha": "娜塔莎",
"Pela": "佩拉",
"Qingque": "青雀",
@ -567,13 +571,21 @@
"help": ""
},
"Item_Raging_Heart": {
"name": "角色晋阶材料:火(流萤 / 加拉赫 / 椒丘",
"name": "角色晋阶材料:火(流萤 / 加拉赫 / 椒丘 / 灵砂",
"help": ""
},
"Item_Dream_Fridge": {
"name": "角色晋阶材料:冰(米沙)",
"help": ""
},
"Item_Nail_of_the_Beast_Coffin": {
"name": "角色晋阶材料:雷(貊泽)",
"help": ""
},
"Item_A_Glass_of_the_Besotted_Era": {
"name": "角色晋阶材料:风(飞霄)",
"help": ""
},
"Item_Dream_Flamer": {
"name": "角色晋阶材料:量子(翡翠 / 花火)",
"help": ""
@ -658,6 +670,10 @@
"name": "尘梦的赞礼•历战余响 (匹诺康尼)",
"help": ""
},
"Item_Auspice_Sliver": {
"name": "心兽的战场•历战余响 (仙舟「罗浮」)",
"help": ""
},
"Item_Squirming_Core": {
"name": "蠢动原核",
"help": ""
@ -703,7 +719,8 @@
"Echo_of_War_End_of_the_Eternal_Freeze": "寒潮的落幕•历战余响 (雅利洛-Ⅵ)",
"Echo_of_War_Divine_Seed": "不死的神实•历战余响 (仙舟「罗浮」)",
"Echo_of_War_Borehole_Planet_Old_Crater": "蛀星的旧靥•历战余响 (空间站「黑塔」)",
"Echo_of_War_Salutations_of_Ashen_Dreams": "尘梦的赞礼•历战余响 (匹诺康尼)"
"Echo_of_War_Salutations_of_Ashen_Dreams": "尘梦的赞礼•历战余响 (匹诺康尼)",
"Echo_of_War_Inner_Beast_Battlefield": "心兽的战场•历战余响 (仙舟「罗浮」)"
},
"Team": {
"name": "打本队伍",
@ -933,11 +950,11 @@
"World": {
"name": "模拟宇宙关卡",
"help": "",
"Simulated_Universe_World_3": "第三世界•模拟宇宙",
"Simulated_Universe_World_4": "第四世界•模拟宇宙",
"Simulated_Universe_World_5": "第五世界•模拟宇宙",
"Simulated_Universe_World_6": "第六世界•模拟宇宙",
"Simulated_Universe_World_8": "第八世界•模拟宇宙"
"Simulated_Universe_World_3": "第三世界",
"Simulated_Universe_World_4": "第四世界",
"Simulated_Universe_World_5": "第五世界",
"Simulated_Universe_World_6": "第六世界",
"Simulated_Universe_World_8": "第八世界"
},
"Path": {
"name": "命途",
@ -1047,6 +1064,7 @@
"Dungeon": {
"name": "副本名称",
"help": "",
"Divergent_Universe_Famished_Worker": "Divergent_Universe_Famished_Worker蠹役饥肠",
"Divergent_Universe_Eternal_Comedy": "奔狼+火宫(永恒笑剧)",
"Divergent_Universe_To_Sweet_Dreams": "茨冈尼亚+出云神国(伴你入眠)",
"Divergent_Universe_Pouring_Blades": "苍穹+匹诺康尼(天剑如雨)",

View File

@ -238,15 +238,15 @@
"Name": {
"name": "副本名稱",
"help": "默認打本設定",
"Calyx_Golden_Memories_Jarilo_VI": "材料:角色經驗(回憶之蕾•雅利洛-Ⅵ",
"Calyx_Golden_Memories_The_Xianzhou_Luofu": "材料:角色經驗(回憶之蕾•仙舟羅浮",
"Calyx_Golden_Memories_Penacony": "材料:角色經驗(回憶之蕾•匹諾康尼",
"Calyx_Golden_Aether_Jarilo_VI": "材料:武器經驗(乙太之蕾•雅利洛-Ⅵ",
"Calyx_Golden_Aether_The_Xianzhou_Luofu": "材料:武器經驗(乙太之蕾•仙舟羅浮",
"Calyx_Golden_Aether_Penacony": "材料:武器經驗(乙太之蕾•匹諾康尼",
"Calyx_Golden_Treasures_Jarilo_VI": "材料:信用點(藏珍之蕾•雅利洛-Ⅵ",
"Calyx_Golden_Treasures_The_Xianzhou_Luofu": "材料:信用點(藏珍之蕾•仙舟羅浮",
"Calyx_Golden_Treasures_Penacony": "材料:信用點(藏珍之蕾•匹諾康尼",
"Calyx_Golden_Memories_Jarilo_VI": "材料:角色經驗(回憶之蕾",
"Calyx_Golden_Memories_The_Xianzhou_Luofu": "材料:角色經驗(回憶之蕾",
"Calyx_Golden_Memories_Penacony": "材料:角色經驗(回憶之蕾",
"Calyx_Golden_Aether_Jarilo_VI": "材料:武器經驗(乙太之蕾",
"Calyx_Golden_Aether_The_Xianzhou_Luofu": "材料:武器經驗(乙太之蕾",
"Calyx_Golden_Aether_Penacony": "材料:武器經驗(乙太之蕾",
"Calyx_Golden_Treasures_Jarilo_VI": "材料:信用點(藏珍之蕾",
"Calyx_Golden_Treasures_The_Xianzhou_Luofu": "材料:信用點(藏珍之蕾",
"Calyx_Golden_Treasures_Penacony": "材料:信用點(藏珍之蕾",
"Calyx_Crimson_Destruction_Herta_StorageZone": "行跡材料:毀滅(收容艙段)",
"Calyx_Crimson_Destruction_Luofu_ScalegorgeWaterscape": "行跡材料:毀滅(鱗淵境)",
"Calyx_Crimson_Preservation_Herta_SupplyZone": "行跡材料:存護(支援艙段)",
@ -266,42 +266,44 @@
"Stagnant_Shadow_Duty": "角色晉階材料:物理(波提歐 / 知更鳥 / 雲璃)",
"Stagnant_Shadow_Blaze": "角色晉階材料:火(姬子 / 艾絲妲 / 虎克)",
"Stagnant_Shadow_Scorch": "角色晉階材料:火(桂乃芬 / 托帕&帳帳)",
"Stagnant_Shadow_Ire": "角色晉階材料:火(流螢 / 加拉赫 / 椒丘",
"Stagnant_Shadow_Ire": "角色晉階材料:火(流螢 / 加拉赫 / 椒丘 / 靈砂",
"Stagnant_Shadow_Rime": "角色晉階材料:冰(三月七 / 黑塔 / 傑帕德 / 佩拉)",
"Stagnant_Shadow_Icicle": "角色晉階材料:冰(彥卿 / 鏡流 / 阮•梅)",
"Stagnant_Shadow_Nectar": "角色晉階材料:冰(米沙)",
"Stagnant_Shadow_Fulmination": "角色晉階材料:雷(阿蘭 / 希露瓦 / 停雲 / 白露)",
"Stagnant_Shadow_Doom": "角色晉階材料:雷(卡芙卡 / 景元 / 黃泉)",
"Stagnant_Shadow_Mechwolf": "角色晉階材料:雷(貊澤)",
"Stagnant_Shadow_Gust": "角色晉階材料:風(丹恆 / 布洛妮婭 / 桑博)",
"Stagnant_Shadow_Celestial": "角色晉階材料:風(刃 / 藿藿 / 黑天鵝)",
"Stagnant_Shadow_Gloam": "角色晉階材料:風(飛霄)",
"Stagnant_Shadow_Quanta": "角色晉階材料:量子(銀狼 / 希兒 / 青雀)",
"Stagnant_Shadow_Abomination": "角色晉階材料:量子(玲可 / 符玄 / 雪衣)",
"Stagnant_Shadow_Roast": "角色晉階材料:量子(翡翠 / 花火)",
"Stagnant_Shadow_Mirage": "角色晉階材料:虛數(瓦爾特 / 羅剎 / 馭空)",
"Stagnant_Shadow_Puppetry": "角色晉階材料:虛數(丹恆•飲月 / 砂金 / 真理醫生)",
"Cavern_of_Corrosion_Path_of_Gelid_Wind": "遺器:冰套+風套(霜風之徑•侵蝕隧洞",
"Cavern_of_Corrosion_Path_of_Jabbing_Punch": "遺器:物理套+擊破套(迅拳之徑•侵蝕隧洞",
"Cavern_of_Corrosion_Path_of_Drifting": "遺器:治療套+快槍手(漂泊之徑•侵蝕隧洞",
"Cavern_of_Corrosion_Path_of_Providence": "遺器:鐵衛套+量子套(睿治之徑•侵蝕隧洞",
"Cavern_of_Corrosion_Path_of_Holy_Hymn": "遺器:防禦套+雷套(聖頌之徑•侵蝕隧洞",
"Cavern_of_Corrosion_Path_of_Conflagration": "遺器:火套+虛數套(野焰之徑•侵蝕隧洞",
"Cavern_of_Corrosion_Path_of_Elixir_Seekers": "遺器:生命套+速度套(藥使之徑•侵蝕隧洞",
"Cavern_of_Corrosion_Path_of_Darkness": "遺器:追擊套+dot套幽冥之徑•侵蝕隧洞",
"Cavern_of_Corrosion_Path_of_Dreamdive": "遺器:負面套+擊破套(夢潛之徑•侵蝕隧洞",
"Cavern_of_Corrosion_Path_of_Cavalier": "遺器:超擊破套+終追套(勇騎之徑•侵蝕隧洞"
"Cavern_of_Corrosion_Path_of_Gelid_Wind": "遺器:冰套+風套(霜風之徑",
"Cavern_of_Corrosion_Path_of_Jabbing_Punch": "遺器:物理套+擊破套(迅拳之徑",
"Cavern_of_Corrosion_Path_of_Drifting": "遺器:治療套+快槍手(漂泊之徑",
"Cavern_of_Corrosion_Path_of_Providence": "遺器:鐵衛套+量子套(睿治之徑",
"Cavern_of_Corrosion_Path_of_Holy_Hymn": "遺器:防禦套+雷套(聖頌之徑",
"Cavern_of_Corrosion_Path_of_Conflagration": "遺器:火套+虛數套(野焰之徑",
"Cavern_of_Corrosion_Path_of_Elixir_Seekers": "遺器:生命套+速度套(藥使之徑",
"Cavern_of_Corrosion_Path_of_Darkness": "遺器:追擊套+dot套幽冥之徑",
"Cavern_of_Corrosion_Path_of_Dreamdive": "遺器:負面套+擊破套(夢潛之徑)",
"Cavern_of_Corrosion_Path_of_Cavalier": "遺器:超擊破套+終追套(勇騎之徑"
},
"NameAtDoubleCalyx": {
"name": "有雙倍花活動時,選擇副本",
"help": "次數耗儘後回退到默認打本設定",
"Calyx_Golden_Memories_Jarilo_VI": "材料:角色經驗(回憶之蕾•雅利洛-Ⅵ",
"Calyx_Golden_Memories_The_Xianzhou_Luofu": "材料:角色經驗(回憶之蕾•仙舟羅浮",
"Calyx_Golden_Memories_Penacony": "材料:角色經驗(回憶之蕾•匹諾康尼",
"Calyx_Golden_Aether_Jarilo_VI": "材料:武器經驗(乙太之蕾•雅利洛-Ⅵ",
"Calyx_Golden_Aether_The_Xianzhou_Luofu": "材料:武器經驗(乙太之蕾•仙舟羅浮",
"Calyx_Golden_Aether_Penacony": "材料:武器經驗(乙太之蕾•匹諾康尼",
"Calyx_Golden_Treasures_Jarilo_VI": "材料:信用點(藏珍之蕾•雅利洛-Ⅵ",
"Calyx_Golden_Treasures_The_Xianzhou_Luofu": "材料:信用點(藏珍之蕾•仙舟羅浮",
"Calyx_Golden_Treasures_Penacony": "材料:信用點(藏珍之蕾•匹諾康尼",
"Calyx_Golden_Memories_Jarilo_VI": "材料:角色經驗(回憶之蕾",
"Calyx_Golden_Memories_The_Xianzhou_Luofu": "材料:角色經驗(回憶之蕾",
"Calyx_Golden_Memories_Penacony": "材料:角色經驗(回憶之蕾",
"Calyx_Golden_Aether_Jarilo_VI": "材料:武器經驗(乙太之蕾",
"Calyx_Golden_Aether_The_Xianzhou_Luofu": "材料:武器經驗(乙太之蕾",
"Calyx_Golden_Aether_Penacony": "材料:武器經驗(乙太之蕾",
"Calyx_Golden_Treasures_Jarilo_VI": "材料:信用點(藏珍之蕾",
"Calyx_Golden_Treasures_The_Xianzhou_Luofu": "材料:信用點(藏珍之蕾",
"Calyx_Golden_Treasures_Penacony": "材料:信用點(藏珍之蕾",
"Calyx_Crimson_Destruction_Herta_StorageZone": "行跡材料:毀滅(收容艙段)",
"Calyx_Crimson_Destruction_Luofu_ScalegorgeWaterscape": "行跡材料:毀滅(鱗淵境)",
"Calyx_Crimson_Preservation_Herta_SupplyZone": "行跡材料:存護(支援艙段)",
@ -320,16 +322,16 @@
"NameAtDoubleRelic": {
"name": "有遺器活動時,選擇副本",
"help": "次數耗儘後回退到默認打本設定",
"Cavern_of_Corrosion_Path_of_Gelid_Wind": "遺器:冰套+風套(霜風之徑•侵蝕隧洞",
"Cavern_of_Corrosion_Path_of_Jabbing_Punch": "遺器:物理套+擊破套(迅拳之徑•侵蝕隧洞",
"Cavern_of_Corrosion_Path_of_Drifting": "遺器:治療套+快槍手(漂泊之徑•侵蝕隧洞",
"Cavern_of_Corrosion_Path_of_Providence": "遺器:鐵衛套+量子套(睿治之徑•侵蝕隧洞",
"Cavern_of_Corrosion_Path_of_Holy_Hymn": "遺器:防禦套+雷套(聖頌之徑•侵蝕隧洞",
"Cavern_of_Corrosion_Path_of_Conflagration": "遺器:火套+虛數套(野焰之徑•侵蝕隧洞",
"Cavern_of_Corrosion_Path_of_Elixir_Seekers": "遺器:生命套+速度套(藥使之徑•侵蝕隧洞",
"Cavern_of_Corrosion_Path_of_Darkness": "遺器:追擊套+dot套幽冥之徑•侵蝕隧洞",
"Cavern_of_Corrosion_Path_of_Dreamdive": "遺器:負面套+擊破套(夢潛之徑•侵蝕隧洞",
"Cavern_of_Corrosion_Path_of_Cavalier": "遺器:超擊破套+終追套(勇騎之徑•侵蝕隧洞"
"Cavern_of_Corrosion_Path_of_Gelid_Wind": "遺器:冰套+風套(霜風之徑",
"Cavern_of_Corrosion_Path_of_Jabbing_Punch": "遺器:物理套+擊破套(迅拳之徑",
"Cavern_of_Corrosion_Path_of_Drifting": "遺器:治療套+快槍手(漂泊之徑",
"Cavern_of_Corrosion_Path_of_Providence": "遺器:鐵衛套+量子套(睿治之徑",
"Cavern_of_Corrosion_Path_of_Holy_Hymn": "遺器:防禦套+雷套(聖頌之徑",
"Cavern_of_Corrosion_Path_of_Conflagration": "遺器:火套+虛數套(野焰之徑",
"Cavern_of_Corrosion_Path_of_Elixir_Seekers": "遺器:生命套+速度套(藥使之徑",
"Cavern_of_Corrosion_Path_of_Darkness": "遺器:追擊套+dot套幽冥之徑",
"Cavern_of_Corrosion_Path_of_Dreamdive": "遺器:負面套+擊破套(夢潛之徑)",
"Cavern_of_Corrosion_Path_of_Cavalier": "遺器:超擊破套+終追套(勇騎之徑"
},
"Team": {
"name": "打本隊伍",
@ -393,6 +395,7 @@
"DanHeng": "丹恆",
"DanHengImbibitorLunae": "丹恆•飲月",
"DrRatio": "真理醫生",
"Feixiao": "飛霄",
"Firefly": "流螢",
"FuXuan": "符玄",
"Gallagher": "加拉赫",
@ -414,6 +417,7 @@
"March7thPreservation": "三月七•存護",
"March7thTheHunt": "三月七•巡獵",
"Misha": "米沙",
"Moze": "貊澤",
"Natasha": "娜塔莎",
"Pela": "佩拉",
"Qingque": "青雀",
@ -567,13 +571,21 @@
"help": ""
},
"Item_Raging_Heart": {
"name": "角色晉階材料:火(流螢 / 加拉赫 / 椒丘",
"name": "角色晉階材料:火(流螢 / 加拉赫 / 椒丘 / 靈砂",
"help": ""
},
"Item_Dream_Fridge": {
"name": "角色晉階材料:冰(米沙)",
"help": ""
},
"Item_Nail_of_the_Beast_Coffin": {
"name": "角色晉階材料:雷(貊澤)",
"help": ""
},
"Item_A_Glass_of_the_Besotted_Era": {
"name": "角色晉階材料:風(飛霄)",
"help": ""
},
"Item_Dream_Flamer": {
"name": "角色晉階材料:量子(翡翠 / 花火)",
"help": ""
@ -658,6 +670,10 @@
"name": "塵夢的讚禮•歷戰餘響 (匹諾康尼)",
"help": ""
},
"Item_Auspice_Sliver": {
"name": "心獸的戰場•歷戰餘響 (仙舟「羅浮」)",
"help": ""
},
"Item_Squirming_Core": {
"name": "蠢動原核",
"help": ""
@ -703,7 +719,8 @@
"Echo_of_War_End_of_the_Eternal_Freeze": "寒潮的落幕•歷戰餘響 (雅利洛-Ⅵ)",
"Echo_of_War_Divine_Seed": "不死的神實•歷戰餘響 (仙舟「羅浮」)",
"Echo_of_War_Borehole_Planet_Old_Crater": "蛀星的舊靨•歷戰餘響 (太空站「黑塔」)",
"Echo_of_War_Salutations_of_Ashen_Dreams": "塵夢的讚禮•歷戰餘響 (匹諾康尼)"
"Echo_of_War_Salutations_of_Ashen_Dreams": "塵夢的讚禮•歷戰餘響 (匹諾康尼)",
"Echo_of_War_Inner_Beast_Battlefield": "心獸的戰場•歷戰餘響 (仙舟「羅浮」)"
},
"Team": {
"name": "打本隊伍",
@ -933,11 +950,11 @@
"World": {
"name": "模拟宇宙关卡",
"help": "",
"Simulated_Universe_World_3": "第三世界•模擬宇宙",
"Simulated_Universe_World_4": "第四世界•模擬宇宙",
"Simulated_Universe_World_5": "第五世界•模擬宇宙",
"Simulated_Universe_World_6": "第六世界•模擬宇宙",
"Simulated_Universe_World_8": "第八世界•模擬宇宙"
"Simulated_Universe_World_3": "第三世界",
"Simulated_Universe_World_4": "第四世界",
"Simulated_Universe_World_5": "第五世界",
"Simulated_Universe_World_6": "第六世界",
"Simulated_Universe_World_8": "第八世界"
},
"Path": {
"name": "命途",
@ -1047,6 +1064,7 @@
"Dungeon": {
"name": "副本名稱",
"help": "",
"Divergent_Universe_Famished_Worker": "Divergent_Universe_Famished_Worker蠹役飢腸",
"Divergent_Universe_Eternal_Comedy": "奔狼+火宮(永恆笑劇)",
"Divergent_Universe_To_Sweet_Dreams": "茨岡尼亞+出雲神國(伴你入眠)",
"Divergent_Universe_Pouring_Blades": "天空+匹諾康尼(天劍如雨)",

View File

@ -56,6 +56,8 @@ class StoredGenerated:
Item_IPC_Work_Permit = StoredPlanner("Dungeon.Planner.Item_IPC_Work_Permit")
Item_Raging_Heart = StoredPlanner("Dungeon.Planner.Item_Raging_Heart")
Item_Dream_Fridge = StoredPlanner("Dungeon.Planner.Item_Dream_Fridge")
Item_Nail_of_the_Beast_Coffin = StoredPlanner("Dungeon.Planner.Item_Nail_of_the_Beast_Coffin")
Item_A_Glass_of_the_Besotted_Era = StoredPlanner("Dungeon.Planner.Item_A_Glass_of_the_Besotted_Era")
Item_Dream_Flamer = StoredPlanner("Dungeon.Planner.Item_Dream_Flamer")
Item_Worldbreaker_Blade = StoredPlanner("Dungeon.Planner.Item_Worldbreaker_Blade")
Item_Arrow_of_the_Starchaser = StoredPlanner("Dungeon.Planner.Item_Arrow_of_the_Starchaser")
@ -77,6 +79,7 @@ class StoredGenerated:
Item_Regret_of_Infinite_Ochema = StoredPlanner("Dungeon.Planner.Item_Regret_of_Infinite_Ochema")
Item_Past_Evils_of_the_Borehole_Planet_Disaster = StoredPlanner("Dungeon.Planner.Item_Past_Evils_of_the_Borehole_Planet_Disaster")
Item_Lost_Echo_of_the_Shared_Wish = StoredPlanner("Dungeon.Planner.Item_Lost_Echo_of_the_Shared_Wish")
Item_Auspice_Sliver = StoredPlanner("Dungeon.Planner.Item_Auspice_Sliver")
Item_Squirming_Core = StoredPlanner("Dungeon.Planner.Item_Squirming_Core")
Item_Conqueror_Will = StoredPlanner("Dungeon.Planner.Item_Conqueror_Will")
Item_Silvermane_Medal = StoredPlanner("Dungeon.Planner.Item_Silvermane_Medal")

View File

@ -2,6 +2,7 @@ import json
import os
import random
import string
from collections import deque
from datetime import datetime, timedelta, timezone
import yaml
@ -190,57 +191,95 @@ def alas_instance():
def deep_get(d, keys, default=None):
"""
Get values in dictionary safely.
https://stackoverflow.com/questions/25833613/safe-method-to-get-value-of-nested-dictionary
Args:
d (dict):
keys (str, list): Such as `Scheduler.NextRun.value`
default: Default return if key not found.
Returns:
"""
if isinstance(keys, str):
# 240 + 30 * depth (ns)
if type(keys) is str:
keys = keys.split('.')
assert type(keys) is list
if d is None:
return default
if not keys:
try:
for k in keys:
d = d[k]
return d
return deep_get(d.get(keys[0]), keys[1:], default)
# No such key
except KeyError:
return default
# Input `keys` is not iterable or input `d` is not dict
except TypeError:
return default
def deep_set(d, keys, value):
"""
Set value into dictionary safely, imitating deep_get().
"""
if isinstance(keys, str):
# 150 * depth (ns)
if type(keys) is str:
keys = keys.split('.')
assert type(keys) is list
if not keys:
return value
if not isinstance(d, dict):
first = True
exist = True
prev_d = None
prev_k = None
prev_k2 = None
try:
for k in keys:
if first:
prev_d = d
prev_k = k
first = False
continue
try:
# if key in dict: dict[key] > dict.get > dict.setdefault > try dict[key] except
if exist and prev_k in d:
prev_d = d
d = d[prev_k]
else:
exist = False
new = {}
d[prev_k] = new
d = new
except TypeError:
# `d` is not dict
exist = False
d = {}
d[keys[0]] = deep_set(d.get(keys[0], {}), keys[1:], value)
return d
prev_d[prev_k2] = {prev_k: d}
prev_k2 = prev_k
prev_k = k
# prev_k2, prev_k = prev_k, k
# Input `keys` is not iterable
except TypeError:
return
# Last key, set value
try:
d[prev_k] = value
return
# Last value `d` is not dict
except TypeError:
prev_d[prev_k2] = {prev_k: value}
return
def deep_pop(d, keys, default=None):
"""
Pop value from dictionary safely, imitating deep_get().
"""
if isinstance(keys, str):
if type(keys) is str:
keys = keys.split('.')
assert type(keys) is list
if not isinstance(d, dict):
try:
for k in keys[:-1]:
d = d[k]
return d.pop(keys[-1], default)
# No such key
except KeyError:
return default
if not keys:
# Input `keys` is not iterable or input `d` is not dict
except TypeError:
return default
# Input `keys` out of index
except IndexError:
return default
# Last `d` is not dict
except AttributeError:
return default
elif len(keys) == 1:
return d.pop(keys[0], default)
return deep_pop(d.get(keys[0]), keys[1:], default)
def deep_default(d, keys, value):
@ -262,26 +301,75 @@ def deep_default(d, keys, value):
return d
def deep_iter(data, depth=0, current_depth=1):
def deep_iter(data, min_depth=None, depth=3):
"""
Iter a dictionary safely.
300us on alas.json depth=3 (530+ rows)
Args:
data (dict):
depth (int): Maximum depth to iter
current_depth (int):
data:
min_depth:
depth:
Returns:
list: Key path
Any:
"""
if isinstance(data, dict) \
and (depth and current_depth <= depth):
for key, value in data.items():
for child_path, child_value in deep_iter(value, depth=depth, current_depth=current_depth + 1):
yield [key] + child_path, child_value
if min_depth is None:
min_depth = depth
assert 1 <= min_depth <= depth
# Equivalent to dict.items()
try:
if depth == 1:
for k, v in data.items():
yield [k], v
return
# Iter first depth
elif min_depth == 1:
q = deque()
for k, v in data.items():
key = [k]
if type(v) is dict:
q.append((key, v))
else:
yield [], data
yield key, v
# Iter target depth only
else:
q = deque()
for k, v in data.items():
key = [k]
if type(v) is dict:
q.append((key, v))
except AttributeError:
# `data` is not dict
return
# Iter depths
current = 2
while current <= depth:
new_q = deque()
# max depth
if current == depth:
for key, data in q:
for k, v in data.items():
yield key + [k], v
# in target depth
elif min_depth <= current < depth:
for key, data in q:
for k, v in data.items():
subkey = key + [k]
if type(v) is dict:
new_q.append((subkey, v))
else:
yield subkey, v
# Haven't reached min depth
else:
for key, data in q:
for k, v in data.items():
subkey = key + [k]
if type(v) is dict:
new_q.append((subkey, v))
q = new_q
current += 1
def parse_value(value, data):

View File

@ -721,7 +721,12 @@ class Connection(ConnectionAttr):
serial_list (list[str]):
"""
import asyncio
from concurrent.futures import ThreadPoolExecutor
ev = asyncio.new_event_loop()
pool = ThreadPoolExecutor(
max_workers=len(serial_list),
thread_name_prefix='adb_brute_force_connect',
)
def _connect(serial):
msg = self.adb_client.connect(serial)
@ -729,10 +734,12 @@ class Connection(ConnectionAttr):
return msg
async def connect():
tasks = [ev.run_in_executor(None, _connect, serial) for serial in serial_list]
tasks = [ev.run_in_executor(pool, _connect, serial) for serial in serial_list]
await asyncio.gather(*tasks)
ev.run_until_complete(connect())
pool.shutdown(wait=False)
ev.close()
@Config.when(DEVICE_OVER_HTTP=True)
def adb_connect(self):

View File

@ -275,11 +275,25 @@ class NemuIpcImpl:
def __exit__(self, exc_type, exc_val, exc_tb):
self.disconnect()
if has_cached_property(self, '_ev'):
self._ev.close()
del_cached_property(self, '_ev')
if has_cached_property(self, '_pool'):
self._pool.shutdown(wait=False)
del_cached_property(self, '_pool')
@cached_property
def _ev(self):
return asyncio.new_event_loop()
@cached_property
def _pool(self):
from concurrent.futures import ThreadPoolExecutor
return ThreadPoolExecutor(
max_workers=1,
thread_name_prefix='NemuIpc',
)
async def ev_run_async(self, func, *args, timeout=0.15, **kwargs):
"""
Args:
@ -294,7 +308,7 @@ class NemuIpcImpl:
func_wrapped = partial(func, *args, **kwargs)
# Increased timeout for slow PCs
# Default screenshot interval is 0.2s, so a 0.15s timeout would have a fast retry without extra time costs
result = await asyncio.wait_for(self._ev.run_in_executor(None, func_wrapped), timeout=timeout)
result = await asyncio.wait_for(self._ev.run_in_executor(self._pool, func_wrapped), timeout=timeout)
return result
def ev_run_sync(self, func, *args, **kwargs):

View File

@ -129,8 +129,17 @@ DrRatio = CharacterList(
jp='Dr.レイシオ',
es='Dr. Ratio',
)
Firefly = CharacterList(
Feixiao = CharacterList(
id=15,
name='Feixiao',
cn='飞霄',
cht='飛霄',
en='Feixiao',
jp='飛霄',
es='Feixiao',
)
Firefly = CharacterList(
id=16,
name='Firefly',
cn='流萤',
cht='流螢',
@ -139,7 +148,7 @@ Firefly = CharacterList(
es='Luciérnaga',
)
FuXuan = CharacterList(
id=16,
id=17,
name='FuXuan',
cn='符玄',
cht='符玄',
@ -148,7 +157,7 @@ FuXuan = CharacterList(
es='Fu Xuan',
)
Gallagher = CharacterList(
id=17,
id=18,
name='Gallagher',
cn='加拉赫',
cht='加拉赫',
@ -157,7 +166,7 @@ Gallagher = CharacterList(
es='Gallagher',
)
Gepard = CharacterList(
id=18,
id=19,
name='Gepard',
cn='杰帕德',
cht='傑帕德',
@ -166,7 +175,7 @@ Gepard = CharacterList(
es='Gepard',
)
Guinaifen = CharacterList(
id=19,
id=20,
name='Guinaifen',
cn='桂乃芬',
cht='桂乃芬',
@ -175,7 +184,7 @@ Guinaifen = CharacterList(
es='Guinaifen',
)
Hanya = CharacterList(
id=20,
id=21,
name='Hanya',
cn='寒鸦',
cht='寒鴉',
@ -184,7 +193,7 @@ Hanya = CharacterList(
es='Hanya',
)
Herta = CharacterList(
id=21,
id=22,
name='Herta',
cn='黑塔',
cht='黑塔',
@ -193,7 +202,7 @@ Herta = CharacterList(
es='Herta',
)
Himeko = CharacterList(
id=22,
id=23,
name='Himeko',
cn='姬子',
cht='姬子',
@ -202,7 +211,7 @@ Himeko = CharacterList(
es='Himeko',
)
Hook = CharacterList(
id=23,
id=24,
name='Hook',
cn='虎克',
cht='虎克',
@ -211,7 +220,7 @@ Hook = CharacterList(
es='Hook',
)
Huohuo = CharacterList(
id=24,
id=25,
name='Huohuo',
cn='藿藿',
cht='藿藿',
@ -220,7 +229,7 @@ Huohuo = CharacterList(
es='Huohuo',
)
Jade = CharacterList(
id=25,
id=26,
name='Jade',
cn='翡翠',
cht='翡翠',
@ -229,7 +238,7 @@ Jade = CharacterList(
es='Jade',
)
Jiaoqiu = CharacterList(
id=26,
id=27,
name='Jiaoqiu',
cn='椒丘',
cht='椒丘',
@ -238,7 +247,7 @@ Jiaoqiu = CharacterList(
es='Jiaoqiu',
)
JingYuan = CharacterList(
id=27,
id=28,
name='JingYuan',
cn='景元',
cht='景元',
@ -247,7 +256,7 @@ JingYuan = CharacterList(
es='Jing Yuan',
)
Jingliu = CharacterList(
id=28,
id=29,
name='Jingliu',
cn='镜流',
cht='鏡流',
@ -256,7 +265,7 @@ Jingliu = CharacterList(
es='Jingliu',
)
Kafka = CharacterList(
id=29,
id=30,
name='Kafka',
cn='卡芙卡',
cht='卡芙卡',
@ -264,8 +273,17 @@ Kafka = CharacterList(
jp='カフカ',
es='Kafka',
)
Lingsha = CharacterList(
id=31,
name='Lingsha',
cn='灵砂',
cht='靈砂',
en='Lingsha',
jp='霊砂',
es='Lingsha',
)
Luka = CharacterList(
id=30,
id=32,
name='Luka',
cn='卢卡',
cht='盧卡',
@ -274,7 +292,7 @@ Luka = CharacterList(
es='Luka',
)
Luocha = CharacterList(
id=31,
id=33,
name='Luocha',
cn='罗刹',
cht='羅剎',
@ -283,7 +301,7 @@ Luocha = CharacterList(
es='Luocha',
)
Lynx = CharacterList(
id=32,
id=34,
name='Lynx',
cn='玲可',
cht='玲可',
@ -292,7 +310,7 @@ Lynx = CharacterList(
es='Lynx',
)
March7thPreservation = CharacterList(
id=33,
id=35,
name='March7thPreservation',
cn='三月七•存护',
cht='三月七•存護',
@ -301,7 +319,7 @@ March7thPreservation = CharacterList(
es='Siete de Marzo: Conservación',
)
March7thTheHunt = CharacterList(
id=34,
id=36,
name='March7thTheHunt',
cn='三月七•巡猎',
cht='三月七•巡獵',
@ -310,7 +328,7 @@ March7thTheHunt = CharacterList(
es='Siete de Marzo: Cacería',
)
Misha = CharacterList(
id=35,
id=37,
name='Misha',
cn='米沙',
cht='米沙',
@ -318,8 +336,17 @@ Misha = CharacterList(
jp='ミーシャ',
es='Misha',
)
Moze = CharacterList(
id=38,
name='Moze',
cn='貊泽',
cht='貊澤',
en='Moze',
jp='モゼ',
es='Moze',
)
Natasha = CharacterList(
id=36,
id=39,
name='Natasha',
cn='娜塔莎',
cht='娜塔莎',
@ -328,7 +355,7 @@ Natasha = CharacterList(
es='Natasha',
)
Pela = CharacterList(
id=37,
id=40,
name='Pela',
cn='佩拉',
cht='佩拉',
@ -337,7 +364,7 @@ Pela = CharacterList(
es='Pela',
)
Qingque = CharacterList(
id=38,
id=41,
name='Qingque',
cn='青雀',
cht='青雀',
@ -346,7 +373,7 @@ Qingque = CharacterList(
es='Qingque',
)
Robin = CharacterList(
id=39,
id=42,
name='Robin',
cn='知更鸟',
cht='知更鳥',
@ -355,7 +382,7 @@ Robin = CharacterList(
es='Robin',
)
RuanMei = CharacterList(
id=40,
id=43,
name='RuanMei',
cn='阮•梅',
cht='阮•梅',
@ -364,7 +391,7 @@ RuanMei = CharacterList(
es='Ruan Mei',
)
Sampo = CharacterList(
id=41,
id=44,
name='Sampo',
cn='桑博',
cht='桑博',
@ -373,7 +400,7 @@ Sampo = CharacterList(
es='Sampo',
)
Seele = CharacterList(
id=42,
id=45,
name='Seele',
cn='希儿',
cht='希兒',
@ -382,7 +409,7 @@ Seele = CharacterList(
es='Seele',
)
Serval = CharacterList(
id=43,
id=46,
name='Serval',
cn='希露瓦',
cht='希露瓦',
@ -391,7 +418,7 @@ Serval = CharacterList(
es='Serval',
)
SilverWolf = CharacterList(
id=44,
id=47,
name='SilverWolf',
cn='银狼',
cht='銀狼',
@ -400,7 +427,7 @@ SilverWolf = CharacterList(
es='Silver Wolf',
)
Sparkle = CharacterList(
id=45,
id=48,
name='Sparkle',
cn='花火',
cht='花火',
@ -409,7 +436,7 @@ Sparkle = CharacterList(
es='Sparkle',
)
Sushang = CharacterList(
id=46,
id=49,
name='Sushang',
cn='素裳',
cht='素裳',
@ -418,7 +445,7 @@ Sushang = CharacterList(
es='Sushang',
)
Tingyun = CharacterList(
id=47,
id=50,
name='Tingyun',
cn='停云',
cht='停雲',
@ -427,7 +454,7 @@ Tingyun = CharacterList(
es='Tingyun',
)
TopazNumby = CharacterList(
id=48,
id=51,
name='TopazNumby',
cn='托帕&账账',
cht='托帕&帳帳',
@ -436,7 +463,7 @@ TopazNumby = CharacterList(
es='Topaz y Conti',
)
TrailblazerDestruction = CharacterList(
id=49,
id=52,
name='TrailblazerDestruction',
cn='Trailblazer•毁灭',
cht='Trailblazer•毀滅',
@ -445,7 +472,7 @@ TrailblazerDestruction = CharacterList(
es='Trailblazer: Destrucción',
)
TrailblazerHarmony = CharacterList(
id=50,
id=53,
name='TrailblazerHarmony',
cn='Trailblazer•同谐',
cht='Trailblazer•同諧',
@ -454,7 +481,7 @@ TrailblazerHarmony = CharacterList(
es='Trailblazer: Armonía',
)
TrailblazerPreservation = CharacterList(
id=51,
id=54,
name='TrailblazerPreservation',
cn='Trailblazer•存护',
cht='Trailblazer•存護',
@ -463,7 +490,7 @@ TrailblazerPreservation = CharacterList(
es='Trailblazer: Conservación',
)
Welt = CharacterList(
id=52,
id=55,
name='Welt',
cn='瓦尔特',
cht='瓦爾特',
@ -472,7 +499,7 @@ Welt = CharacterList(
es='Welt',
)
Xueyi = CharacterList(
id=53,
id=56,
name='Xueyi',
cn='雪衣',
cht='雪衣',
@ -481,7 +508,7 @@ Xueyi = CharacterList(
es='Xueyi',
)
Yanqing = CharacterList(
id=54,
id=57,
name='Yanqing',
cn='彦卿',
cht='彥卿',
@ -490,7 +517,7 @@ Yanqing = CharacterList(
es='Yanqing',
)
Yukong = CharacterList(
id=55,
id=58,
name='Yukong',
cn='驭空',
cht='馭空',
@ -499,7 +526,7 @@ Yukong = CharacterList(
es='Yukong',
)
Yunli = CharacterList(
id=56,
id=59,
name='Yunli',
cn='云璃',
cht='雲璃',

View File

@ -324,6 +324,9 @@ class Combat(CombatInteract, CombatPrepare, CombatState, CombatTeam, CombatSuppo
if self.is_in_main():
logger.info('Combat finishes at page_main')
return True
if self.appear(COMBAT_PREPARE):
logger.info('Combat finishes at COMBAT_PREPARE')
return True
if self.is_combat_executing():
logger.info('Combat finishes at another combat')
return False
@ -427,6 +430,7 @@ class Combat(CombatInteract, CombatPrepare, CombatState, CombatTeam, CombatSuppo
if self._combat_should_reenter():
continue
if finish:
self.combat_exit()
break
# Reset combat_wave_cost, so handle_combat_interact() won't activate before handle_combat_prepare()
self.combat_wave_cost = 10

View File

@ -21,7 +21,7 @@ from tasks.daily.synthesize import SynthesizeMaterialUI
from tasks.daily.use_technique import UseTechniqueUI
from tasks.dungeon.assets.assets_dungeon_ui import DAILY_TRAINING_CHECK
from tasks.dungeon.keywords import KEYWORDS_DUNGEON_TAB
from tasks.dungeon.ui import DungeonUI
from tasks.dungeon.ui.ui import DungeonUI
from tasks.item.consumable_usage import ConsumableUsageUI
from tasks.item.relics import RelicsUI
from tasks.map.route.loader import RouteLoader

View File

@ -3,36 +3,6 @@ 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 ```
CALYX_WORLD_1 = ButtonWrapper(
name='CALYX_WORLD_1',
share=Button(
file='./assets/share/dungeon/ui/CALYX_WORLD_1.png',
area=(490, 185, 540, 230),
search=(470, 165, 560, 250),
color=(197, 196, 196),
button=(490, 185, 540, 230),
),
)
CALYX_WORLD_2 = ButtonWrapper(
name='CALYX_WORLD_2',
share=Button(
file='./assets/share/dungeon/ui/CALYX_WORLD_2.png',
area=(590, 185, 640, 230),
search=(570, 165, 660, 250),
color=(199, 198, 198),
button=(590, 185, 640, 230),
),
)
CALYX_WORLD_3 = ButtonWrapper(
name='CALYX_WORLD_3',
share=Button(
file='./assets/share/dungeon/ui/CALYX_WORLD_3.png',
area=(689, 186, 739, 231),
search=(669, 166, 759, 251),
color=(158, 158, 158),
button=(689, 186, 739, 231),
),
)
DAILY_TRAINING_CHECK = ButtonWrapper(
name='DAILY_TRAINING_CHECK',
share=Button(
@ -73,16 +43,6 @@ LIST_LOADED_CHECK = ButtonWrapper(
button=(576, 606, 951, 664),
),
)
OCR_DUNGEON_LIST = ButtonWrapper(
name='OCR_DUNGEON_LIST',
share=Button(
file='./assets/share/dungeon/ui/OCR_DUNGEON_LIST.png',
area=(581, 176, 1165, 661),
search=(561, 156, 1185, 681),
color=(212, 214, 220),
button=(440, 176, 588, 656),
),
)
OCR_DUNGEON_NAV = ButtonWrapper(
name='OCR_DUNGEON_NAV',
share=Button(

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 ```
LIST_ASCENDING = ButtonWrapper(
name='LIST_ASCENDING',
share=Button(
file='./assets/share/dungeon/ui_list/LIST_ASCENDING.png',
area=(1125, 643, 1143, 661),
search=(1105, 623, 1163, 681),
color=(195, 194, 196),
button=(1125, 643, 1143, 661),
),
)
LIST_DESCENDING = ButtonWrapper(
name='LIST_DESCENDING',
share=Button(
file='./assets/share/dungeon/ui_list/LIST_DESCENDING.png',
area=(1125, 643, 1143, 661),
search=(1105, 623, 1163, 681),
color=(195, 194, 196),
button=(1125, 643, 1143, 661),
),
)
OCR_DUNGEON_LIST = ButtonWrapper(
name='OCR_DUNGEON_LIST',
share=Button(
file='./assets/share/dungeon/ui_list/OCR_DUNGEON_LIST.png',
area=(581, 176, 1165, 661),
search=(561, 156, 1185, 681),
color=(212, 214, 220),
button=(440, 176, 588, 656),
),
)
OCR_DUNGEON_NAME = ButtonWrapper(
name='OCR_DUNGEON_NAME',
share=Button(
file='./assets/share/dungeon/ui_list/OCR_DUNGEON_NAME.png',
area=(563, 172, 788, 624),
search=(543, 152, 808, 644),
color=(245, 243, 245),
button=(563, 172, 788, 624),
),
)
OCR_DUNGEON_NAME_ROGUE = ButtonWrapper(
name='OCR_DUNGEON_NAME_ROGUE',
share=Button(
file='./assets/share/dungeon/ui_list/OCR_DUNGEON_NAME_ROGUE.png',
area=(563, 292, 788, 624),
search=(543, 272, 808, 644),
color=(249, 247, 249),
button=(563, 292, 788, 624),
),
)
OCR_DUNGEON_TELEPORT = ButtonWrapper(
name='OCR_DUNGEON_TELEPORT',
share=Button(
file='./assets/share/dungeon/ui_list/OCR_DUNGEON_TELEPORT.png',
area=(1013, 172, 1163, 624),
search=(993, 152, 1183, 644),
color=(231, 234, 230),
button=(1013, 172, 1163, 624),
),
)

View File

@ -250,10 +250,10 @@ class Dungeon(DungeonStamina, DungeonEvent, Combat):
if self.has_double_rogue_event():
rogue = self.get_double_rogue_remain()
if self.has_double_calyx_event():
self._dungeon_nav_goto(KEYWORDS_DUNGEON_NAV.Calyx_Golden)
self.dungeon_nav_goto(KEYWORDS_DUNGEON_NAV.Calyx_Golden)
calyx = self.get_double_event_remain()
if self.has_double_relic_event():
self._dungeon_nav_goto(KEYWORDS_DUNGEON_NAV.Cavern_of_Corrosion)
self.dungeon_nav_goto(KEYWORDS_DUNGEON_NAV.Cavern_of_Corrosion)
relic = self.get_double_rogue_remain()
with self.config.multi_set():
self.config.stored.DungeonDouble.calyx = calyx

File diff suppressed because it is too large Load Diff

View File

@ -150,11 +150,11 @@ Stagnant_Shadow_Roast = DungeonDetailed(
Stagnant_Shadow_Ire = DungeonDetailed(
id=17,
name='Stagnant_Shadow_Ire',
cn='角色晋阶材料:火(流萤 / 加拉赫 / 椒丘',
cht='角色晉階材料:火(流螢 / 加拉赫 / 椒丘',
en='Ascension: Fire (Firefly / Gallagher / Jiaoqiu)',
jp='キャラクター昇格素材:炎(ホタル / ギャラガー / 椒丘',
es='Ascension: Fuego (Luciérnaga / Gallagher / Jiaoqiu)',
cn='角色晋阶材料:火(流萤 / 加拉赫 / 椒丘 / 灵砂',
cht='角色晉階材料:火(流螢 / 加拉赫 / 椒丘 / 靈砂',
en='Ascension: Fire (Firefly / Gallagher / Jiaoqiu / Lingsha)',
jp='キャラクター昇格素材:炎(ホタル / ギャラガー / 椒丘 / 霊砂',
es='Ascension: Fuego (Luciérnaga / Gallagher / Jiaoqiu / Lingsha)',
)
Stagnant_Shadow_Duty = DungeonDetailed(
id=18,
@ -165,3 +165,21 @@ Stagnant_Shadow_Duty = DungeonDetailed(
jp='キャラクター昇格素材:物理(ブートヒル / ロビン / 雲璃)',
es='Ascension: Físico (Boothill / Robin / Yunli)',
)
Stagnant_Shadow_Mechwolf = DungeonDetailed(
id=19,
name='Stagnant_Shadow_Mechwolf',
cn='角色晋阶材料:雷(貊泽)',
cht='角色晉階材料:雷(貊澤)',
en='Ascension: Lightning (Moze)',
jp='キャラクター昇格素材:雷(モゼ)',
es='Ascension: Rayo (Moze)',
)
Stagnant_Shadow_Gloam = DungeonDetailed(
id=20,
name='Stagnant_Shadow_Gloam',
cn='角色晋阶材料:风(飞霄)',
cht='角色晉階材料:風(飛霄)',
en='Ascension: Wind (Feixiao)',
jp='キャラクター昇格素材:風(飛霄)',
es='Ascension: Viento (Feixiao)',
)

View File

@ -6,7 +6,7 @@ from tasks.base.page import page_guide
from tasks.combat.assets.assets_combat_stamina_status import ICON_SEARCH, IMMERSIFIER_ICON
from tasks.dungeon.assets.assets_dungeon_stamina import *
from tasks.dungeon.keywords import KEYWORDS_DUNGEON_TAB
from tasks.dungeon.ui import DungeonUI
from tasks.dungeon.ui.ui import DungeonUI
class DungeonStamina(DungeonUI):

View File

@ -1,770 +0,0 @@
import re
import cv2
import numpy as np
from module.base.base import ModuleBase
from module.base.button import ClickButton
from module.base.decorator import run_once
from module.base.timer import Timer
from module.base.utils import get_color
from module.exception import ScriptError
from module.logger import logger
from module.ocr.ocr import Ocr, OcrResultButton
from module.ocr.utils import split_and_pair_button_attr, split_and_pair_buttons
from module.ui.draggable_list import DraggableList
from module.ui.switch import Switch
from tasks.base.page import page_guide
from tasks.combat.assets.assets_combat_interact import DUNGEON_COMBAT_INTERACT, DUNGEON_COMBAT_INTERACT_TEXT
from tasks.combat.assets.assets_combat_prepare import COMBAT_PREPARE
from tasks.dungeon.assets.assets_dungeon_ui import *
from tasks.dungeon.assets.assets_dungeon_ui_rogue import *
from tasks.dungeon.keywords import (
DungeonList,
DungeonNav,
DungeonTab,
KEYWORDS_DUNGEON_ENTRANCE,
KEYWORDS_DUNGEON_LIST,
KEYWORDS_DUNGEON_NAV,
KEYWORDS_DUNGEON_TAB
)
from tasks.dungeon.keywords.classes import DungeonEntrance
from tasks.dungeon.state import DungeonState
from tasks.map.interact.aim import inrange
from tasks.map.keywords import KEYWORDS_MAP_WORLD, MapPlane
class DungeonTabSwitch(Switch):
SEARCH_BUTTON = TAB_SEARCH
def add_state(self, state, check_button, click_button=None):
# Load search
if check_button is not None:
check_button.load_search(self.__class__.SEARCH_BUTTON.area)
if click_button is not None:
click_button.load_search(self.__class__.SEARCH_BUTTON.area)
return super().add_state(state, check_button, click_button)
def click(self, state, main):
"""
Args:
state (str):
main (ModuleBase):
"""
button = self.get_data(state)['click_button']
_ = main.appear(button) # Search button to load offset
main.device.click(button)
SWITCH_DUNGEON_TAB = DungeonTabSwitch('DungeonTab', is_selector=True)
SWITCH_DUNGEON_TAB.add_state(
KEYWORDS_DUNGEON_TAB.Operation_Briefing,
check_button=OPERATION_BRIEFING_CHECK,
click_button=OPERATION_BRIEFING_CLICK
)
SWITCH_DUNGEON_TAB.add_state(
KEYWORDS_DUNGEON_TAB.Daily_Training,
check_button=DAILY_TRAINING_CHECK,
click_button=DAILY_TRAINING_CLICK
)
SWITCH_DUNGEON_TAB.add_state(
KEYWORDS_DUNGEON_TAB.Survival_Index,
check_button=SURVIVAL_INDEX_CHECK,
click_button=SURVIVAL_INDEX_CLICK
)
SWITCH_DUNGEON_TAB.add_state(
KEYWORDS_DUNGEON_TAB.Simulated_Universe,
check_button=SIMULATED_UNIVERSE_CHECK,
click_button=SIMULATED_UNIVERSE_CLICK
)
SWITCH_DUNGEON_TAB.add_state(
KEYWORDS_DUNGEON_TAB.Treasures_Lightward,
check_button=TREASURES_LIGHTWARD_CHECK,
click_button=TREASURES_LIGHTWARD_CLICK
)
class OcrDungeonNav(Ocr):
def after_process(self, result):
result = super().after_process(result)
result = result.replace('#', '')
if self.lang == 'cn':
result = result.replace('萼喜', '')
result = result.replace('', '') # 凝带虚影
return result
class OcrDungeonList(Ocr):
def after_process(self, result):
# 乙太之蕾•雅利洛-Ⅵ
result = re.sub(r'-[V][I]', '-Ⅵ', result)
# 苏乐达™热砂海选会场
result = re.sub(r'(苏乐达|蘇樂達|SoulGlad|スラーダ|FelizAlma)[rtT]*M', r'\1', result)
result = super().after_process(result)
if self.lang == 'cn':
result = result.replace('', '') # 巽风之形
result = result.replace('皖A0', '50').replace('', '')
# 燔灼之形•凝滞虚影
result = result.replace('', '')
result = re.sub('^灼之形', '燔灼之形', result)
# 偃偶之形•凝滞虚影
result = re.sub('^偶之形', '偃偶之形', result)
# 嗔怒之形•凝滞虚影
result = re.sub('^怒之形', '嗔怒之形', result)
# 蛀星的旧·历战余响
result = re.sub(r'蛀星的旧.*?历战', '蛀星的旧靥•历战', result)
# 9支援仓段
for word in 'Q9α':
result = result.removeprefix(word)
return result
class OcrDungeonListCalyxCrimson(OcrDungeonList):
def _match_result(self, *args, **kwargs):
"""
Convert MapPlane object to their corresponding DungeonList object
"""
plane = super()._match_result(*args, **kwargs)
if plane is not None:
for dungeon in DungeonList.instances.values():
if dungeon.is_Calyx_Crimson and dungeon.plane == plane:
return dungeon
return plane
class OcrDungeonListLimitEntrance(OcrDungeonList):
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
self.button = ClickButton((*self.button.area[:3], self.button.area[3] - 70))
class OcrDungeonListCalyxCrimsonLimitEntrance(OcrDungeonListCalyxCrimson, OcrDungeonListLimitEntrance):
pass
class DraggableDungeonNav(DraggableList):
# 0.5 is the magic number to reach bottom in 1 swipe
# but relax we still have retires when magic doesn't work
drag_vector = (0.50, 0.52)
class DraggableDungeonList(DraggableList):
teleports: list[OcrResultButton] = []
navigates: list[OcrResultButton] = []
# use_plane: True to use map planes to predict dungeons only.
# Can only be True in Calyx Crimson
use_plane = False
# limit_entrance: True to ensure the teleport button is insight
limit_entrance = False
def load_rows(self, main: ModuleBase, allow_early_access=False):
"""
Args:
main:
allow_early_access: True to allow dungeons that are in temporarily early access during events
"""
relative_area = (0, 0, 1280, 120)
if self.use_plane:
self.keyword_class = [MapPlane, DungeonEntrance]
if self.limit_entrance:
self.ocr_class = OcrDungeonListCalyxCrimsonLimitEntrance
else:
self.ocr_class = OcrDungeonListCalyxCrimson
else:
self.keyword_class = [DungeonList, DungeonEntrance]
if self.limit_entrance:
self.ocr_class = OcrDungeonListLimitEntrance
else:
self.ocr_class = OcrDungeonList
super().load_rows(main=main)
# Check early access dungeons
buttons = DUNGEON_LIST.cur_buttons.copy()
for name, button in split_and_pair_buttons(
DUNGEON_LIST.cur_buttons,
split_func=lambda x: x != KEYWORDS_DUNGEON_ENTRANCE.Enter,
relative_area=relative_area
):
logger.warning(f'Early access dungeon: {name}')
buttons.remove(name)
buttons.remove(button)
# Remove early access dungeons
if not allow_early_access:
DUNGEON_LIST.cur_buttons = buttons
# From super.load_rows(), re-calculate indexes
indexes = [self.keyword2index(row.matched_keyword)
for row in self.cur_buttons]
indexes = [index for index in indexes if index]
if not indexes:
logger.warning(f'No valid rows loaded into {self}')
return
self.cur_min = min(indexes)
self.cur_max = max(indexes)
logger.attr(self.name, f'{self.cur_min} - {self.cur_max}')
# Replace dungeon.button with teleport
self.teleports = list(split_and_pair_button_attr(
DUNGEON_LIST.cur_buttons,
split_func=lambda x: x != KEYWORDS_DUNGEON_ENTRANCE.Teleport and x != KEYWORDS_DUNGEON_ENTRANCE.Enter,
relative_area=relative_area
))
self.navigates = list(split_and_pair_button_attr(
DUNGEON_LIST.cur_buttons,
split_func=lambda x: x != KEYWORDS_DUNGEON_ENTRANCE.Navigate,
relative_area=relative_area
))
DUNGEON_NAV_LIST = DraggableDungeonNav(
'DungeonNavList', keyword_class=DungeonNav, ocr_class=OcrDungeonNav, search_button=OCR_DUNGEON_NAV)
DUNGEON_LIST = DraggableDungeonList(
'DungeonList', keyword_class=[DungeonList, DungeonEntrance, MapPlane],
ocr_class=OcrDungeonList, search_button=OCR_DUNGEON_LIST)
class DungeonUI(DungeonState):
def dungeon_tab_goto(self, state: DungeonTab):
"""
Args:
state:
Returns:
bool: If UI switched
Examples:
self = DungeonUI('alas')
self.device.screenshot()
self.dungeon_tab_goto(KEYWORDS_DUNGEON_TAB.Operation_Briefing)
self.dungeon_tab_goto(KEYWORDS_DUNGEON_TAB.Daily_Training)
self.dungeon_tab_goto(KEYWORDS_DUNGEON_TAB.Survival_Index)
"""
logger.hr('Dungeon tab goto', level=2)
ui_switched = self.ui_ensure(page_guide)
tab_switched = SWITCH_DUNGEON_TAB.set(state, main=self)
if ui_switched or tab_switched:
if state == KEYWORDS_DUNGEON_TAB.Daily_Training:
logger.info(f'Tab goto {state}, wait until loaded')
self._dungeon_wait_daily_training_loaded()
elif state == KEYWORDS_DUNGEON_TAB.Survival_Index:
logger.info(f'Tab goto {state}, wait until loaded')
self._dungeon_wait_survival_index_loaded()
elif state == KEYWORDS_DUNGEON_TAB.Treasures_Lightward:
logger.info(f'Tab goto {state}, wait until loaded')
self._dungeon_wait_treasures_lightward_loaded()
return True
else:
return False
def _dungeon_wait_daily_training_loaded(self, skip_first_screenshot=True):
"""
Returns:
bool: True if wait success, False if wait timeout.
Pages:
in: page_guide, Daily_Training
"""
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 daily training loaded timeout')
return False
color = get_color(self.device.image, DAILY_TRAINING_LOADED.area)
if np.mean(color) < 128:
logger.info('Daily training loaded')
return True
def _dungeon_wait_survival_index_loaded(self, skip_first_screenshot=True):
"""
Returns:
bool: True if wait success, False if wait timeout.
Pages:
in: page_guide, Survival_Index
"""
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 survival index loaded timeout')
return False
if self.appear(SURVIVAL_INDEX_SU_LOADED):
logger.info('Survival index loaded, SURVIVAL_INDEX_SU_LOADED')
return True
if self.appear(SURVIVAL_INDEX_OE_LOADED):
logger.info('Survival index loaded, SURVIVAL_INDEX_OE_LOADED')
return True
def _dungeon_survival_index_top_appear(self):
if self.appear(SURVIVAL_INDEX_SU_LOADED):
return True
if self.appear(SURVIVAL_INDEX_OE_LOADED):
return True
return False
def _dungeon_wait_treasures_lightward_loaded(self, skip_first_screenshot=True):
"""
Returns:
bool: True if wait success, False if wait timeout.
Pages:
in: page_guide, Survival_Index
"""
timeout = Timer(2, count=4).start()
TREASURES_LIGHTWARD_LOADED.set_search_offset((5, 5))
TREASURES_LIGHTWARD_LOCKED.set_search_offset((5, 5))
while 1:
if skip_first_screenshot:
skip_first_screenshot = False
else:
self.device.screenshot()
if timeout.reached():
logger.warning('Wait treasures lightward loaded timeout')
return False
if self.appear(TREASURES_LIGHTWARD_LOADED):
logger.info('Treasures lightward loaded (event unlocked)')
return True
if self.appear(TREASURES_LIGHTWARD_LOCKED):
logger.info('Treasures lightward loaded (event locked)')
return True
def _dungeon_list_button_has_content(self):
# Check if having any content
# List background: 254, guild border: 225
r, g, b = cv2.split(self.image_crop(LIST_LOADED_CHECK, copy=False))
minimum = cv2.min(cv2.min(r, g), b)
minimum = inrange(minimum, lower=0, upper=180)
if minimum.size > 100:
return True
else:
return False
def _dungeon_wait_until_dungeon_list_loaded(self, skip_first_screenshot=True):
timeout = Timer(1, count=3).start()
while 1:
if skip_first_screenshot:
skip_first_screenshot = False
else:
self.device.screenshot()
# End
if timeout.reached():
logger.warning('Wait until dungeon list loaded timeout')
return False
if self._dungeon_list_button_has_content():
logger.info('Dungeon list loaded')
return True
def _dungeon_wait_until_echo_or_war_stabled(self, skip_first_screenshot=True):
"""
Returns:
bool: True if wait success, False if wait timeout.
Pages:
in: page_guide, Survival_Index
"""
# Wait until Forgotten_Hall stabled
timeout = Timer(2, count=4).start()
while 1:
if skip_first_screenshot:
skip_first_screenshot = False
else:
self.device.screenshot()
# End
if timeout.reached():
logger.warning('Wait until Echo_of_War stabled timeout')
return False
DUNGEON_NAV_LIST.load_rows(main=self)
# End
button = DUNGEON_NAV_LIST.keyword2button(KEYWORDS_DUNGEON_NAV.Echo_of_War, show_warning=False)
if button:
# 513 is the top of the last row of DungeonNav
if button.area[1] > 513:
logger.info('DungeonNav row Echo_of_War stabled')
return True
else:
logger.info('No Echo_of_War in list skip waiting')
return False
def _dungeon_nav_goto(self, nav: DungeonNav, skip_first_screenshot=True):
"""
Equivalent to `DUNGEON_NAV_LIST.select_row(dungeon.dungeon_nav, main=self)`
but with tricks to be faster
Args:
nav:
skip_first_screenshot:
"""
logger.hr('Dungeon nav goto', level=2)
logger.info(f'Dungeon nav goto {nav}')
# Wait rows
while 1:
if skip_first_screenshot:
skip_first_screenshot = False
else:
self.device.screenshot()
DUNGEON_NAV_LIST.load_rows(main=self)
if DUNGEON_NAV_LIST.cur_buttons:
break
# Wait first row selected
timeout = Timer(0.5, count=2).start()
skip_first_screenshot = True
while 1:
if skip_first_screenshot:
skip_first_screenshot = False
else:
self.device.screenshot()
if timeout.reached():
logger.info('DUNGEON_NAV_LIST not selected')
break
if button := DUNGEON_NAV_LIST.get_selected_row(main=self):
logger.info(f'DUNGEON_NAV_LIST selected at {button}')
break
# Check if it's at the first page.
if DUNGEON_NAV_LIST.keyword2button(KEYWORDS_DUNGEON_NAV.Simulated_Universe, show_warning=False) \
or DUNGEON_NAV_LIST.keyword2button(KEYWORDS_DUNGEON_NAV.Ornament_Extraction, show_warning=False):
# Going to use a faster method to navigate but can only start from list top
logger.info('DUNGEON_NAV_LIST at top')
# Update points if possible
# 2.3, No longer weekly points after Divergent Universe unlocked
# if DUNGEON_NAV_LIST.is_row_selected(button, main=self):
# self.dungeon_update_simuni()
# Treasures lightward is always at top
elif DUNGEON_NAV_LIST.keyword2button(KEYWORDS_DUNGEON_NAV.Forgotten_Hall, show_warning=False) \
or DUNGEON_NAV_LIST.keyword2button(KEYWORDS_DUNGEON_NAV.Pure_Fiction, show_warning=False):
logger.info('DUNGEON_NAV_LIST at top')
else:
# To start from any list states.
logger.info('DUNGEON_NAV_LIST not at top')
DUNGEON_NAV_LIST.select_row(nav, main=self)
return True
# Check the first page
if nav in [
KEYWORDS_DUNGEON_NAV.Simulated_Universe,
KEYWORDS_DUNGEON_NAV.Divergent_Universe,
KEYWORDS_DUNGEON_NAV.Ornament_Extraction,
KEYWORDS_DUNGEON_NAV.Calyx_Golden,
KEYWORDS_DUNGEON_NAV.Calyx_Crimson,
KEYWORDS_DUNGEON_NAV.Stagnant_Shadow,
KEYWORDS_DUNGEON_NAV.Cavern_of_Corrosion,
KEYWORDS_DUNGEON_NAV.Forgotten_Hall,
KEYWORDS_DUNGEON_NAV.Pure_Fiction,
]:
button = DUNGEON_NAV_LIST.keyword2button(nav)
if button:
DUNGEON_NAV_LIST.select_row(nav, main=self, insight=False)
return True
# Check the second page
while 1:
DUNGEON_NAV_LIST.drag_page('down', main=self)
# No skip_first_screenshot since drag_page is just called
if self._dungeon_wait_until_echo_or_war_stabled(skip_first_screenshot=False):
DUNGEON_NAV_LIST.select_row(nav, main=self, insight=False)
return True
def _dungeon_world_set(self, dungeon: DungeonList, skip_first_screenshot=True):
"""
Switch worlds in Calyx_Golden
Returns:
bool: True if success to set
"""
logger.hr('Dungeon world set', level=2)
if not dungeon.is_Calyx_Golden:
logger.warning(f'Dungeon {dungeon} is not Calyx Golden, no need to set world')
return False
if dungeon.world is None:
logger.error(f'Dungeon {dungeon} does not belongs to any world')
return False
dic_world_button = {
KEYWORDS_MAP_WORLD.Jarilo_VI: CALYX_WORLD_1,
KEYWORDS_MAP_WORLD.The_Xianzhou_Luofu: CALYX_WORLD_2,
KEYWORDS_MAP_WORLD.Penacony: CALYX_WORLD_3,
}
button = dic_world_button.get(dungeon.world)
if button is None:
logger.error(f'Dungeon {dungeon} with world {dungeon.world} has no corresponding world button')
return False
logger.info(f'Dungeon world set {dungeon.world}')
while 1:
if skip_first_screenshot:
skip_first_screenshot = False
else:
self.device.screenshot()
# End
if self.image_color_count(button, color=(18, 18, 18), threshold=180, count=50):
logger.info(f'Dungeon world at {dungeon.world}')
return True
# Click
if self.ui_page_appear(page_guide, interval=2):
self.device.click(button)
continue
def _dungeon_world_set_wrapper(self, dungeon: DungeonList, skip_first_screenshot=True):
"""
Switch worlds in Calyx_Golden with error handling
If world tab is not unlocked, fallback to Jarilo dungeons
"""
# Wait world tab
button = CALYX_WORLD_1
tab = False
timeout = Timer(0.6, count=3).start()
while 1:
if skip_first_screenshot:
skip_first_screenshot = False
else:
self.device.screenshot()
# End
if timeout.reached():
break
# Selected tab
if self.image_color_count(button, color=(18, 18, 18), threshold=180, count=50):
tab = True
break
# Unselected tab
if self.image_color_count(button, color=(134, 134, 134), threshold=180, count=50):
tab = True
break
logger.attr('WorldTab', tab)
if not tab:
logger.warning('World tab is not unlocked, fallback to Jarilo dungeons')
if dungeon.is_Calyx_Golden_Memories:
dungeon = KEYWORDS_DUNGEON_LIST.Calyx_Golden_Treasures_Jarilo_VI
if dungeon.is_Calyx_Golden_Aether:
dungeon = KEYWORDS_DUNGEON_LIST.Calyx_Golden_Aether_Jarilo_VI
if dungeon.is_Calyx_Golden_Treasures:
dungeon = KEYWORDS_DUNGEON_LIST.Calyx_Golden_Treasures_Jarilo_VI
self._dungeon_world_set(dungeon, skip_first_screenshot=skip_first_screenshot)
return dungeon
def _dungeon_insight(self, dungeon: DungeonList):
"""
Pages:
in: page_guide, Survival_Index, nav including dungeon
out: page_guide, Survival_Index, nav including dungeon, dungeon insight
"""
logger.hr('Dungeon insight', level=2)
DUNGEON_LIST.use_plane = bool(dungeon.is_Calyx_Crimson)
# Insight dungeon
DUNGEON_LIST.insight_row(dungeon, main=self)
self.device.click_record_clear()
# Check if dungeon unlocked
for entrance in DUNGEON_LIST.navigates:
entrance: OcrResultButton = entrance
logger.warning(f'Teleport {entrance.matched_keyword} is not unlocked')
if entrance == dungeon:
logger.error(f'Trying to enter dungeon {dungeon}, but teleport is not unlocked')
return False
# Find teleport button
if dungeon not in [tp.matched_keyword for tp in DUNGEON_LIST.teleports]:
# Dungeon name is insight but teleport button is not
logger.info('Dungeon name is insight, swipe down a little bit to find the teleport button')
if dungeon.is_Forgotten_Hall:
DUNGEON_LIST.drag_vector = (-0.4, -0.2) # Keyword loaded is reversed
else:
DUNGEON_LIST.drag_vector = (0.2, 0.4)
DUNGEON_LIST.limit_entrance = True
DUNGEON_LIST.insight_row(dungeon, main=self)
self.device.click_record_clear()
DUNGEON_LIST.drag_vector = DraggableList.drag_vector
DUNGEON_LIST.limit_entrance = False
DUNGEON_LIST.load_rows(main=self)
# Check if dungeon unlocked
for entrance in DUNGEON_LIST.navigates:
if entrance == dungeon:
logger.error(f'Trying to enter dungeon {dungeon}, but teleport is not unlocked')
return False
return True
def _dungeon_enter(self, dungeon, enter_check_button=COMBAT_PREPARE, skip_first_screenshot=True):
"""
Pages:
in: page_guide, Survival_Index, nav including dungeon
out: COMBAT_PREPARE, FORGOTTEN_HALL_CHECK
"""
logger.hr('Dungeon enter', level=2)
DUNGEON_LIST.use_plane = bool(dungeon.is_Calyx_Crimson)
skip_first_load = skip_first_screenshot
@run_once
def screenshot_interval_set():
self.device.screenshot_interval_set('combat')
while 1:
if skip_first_screenshot:
skip_first_screenshot = False
else:
self.device.screenshot()
# End
if self.appear(enter_check_button):
logger.info(f'Arrive {enter_check_button.name}')
self.device.screenshot_interval_set()
break
# Additional
# Popup that confirm character switch
if self.handle_popup_confirm():
self.interval_reset(page_guide.check_button)
continue
# Click teleport
if self.appear(page_guide.check_button, interval=1):
if skip_first_load:
skip_first_load = False
else:
DUNGEON_LIST.load_rows(main=self)
entrance = DUNGEON_LIST.keyword2button(dungeon)
if entrance is not None:
self.device.click(entrance)
screenshot_interval_set()
self.interval_reset(page_guide.check_button)
continue
else:
logger.warning(f'Cannot find dungeon entrance of {dungeon}')
continue
def get_dungeon_interact(self) -> DungeonList | None:
"""
Pages:
in: page_main
"""
if not self.appear(DUNGEON_COMBAT_INTERACT):
logger.info('No dungeon interact')
return None
self.acquire_lang_checked()
ocr = OcrDungeonList(DUNGEON_COMBAT_INTERACT_TEXT)
result = ocr.detect_and_ocr(self.device.image)
dungeon = None
# Special match names in English
# Second row must have at least 3 characters which is the shortest name "Ire"
# Stangnant Shadow: Shape of
# Quanta
if len(result) == 2 and len(result[1].ocr_text) >= 3:
first, second = result[0].ocr_text, result[1].ocr_text
if re.search(r'Stagnant\s*Shadow', first):
dungeon = DungeonList.find_dungeon_by_string(en=second, is_Stagnant_Shadow=True)
elif re.search(r'Cavern\s*of\s*Corrosion', first):
dungeon = DungeonList.find_dungeon_by_string(en=second, is_Cavern_of_Corrosion=True)
elif re.search(r'Echo\s*of\s*War', first):
dungeon = DungeonList.find_dungeon_by_string(en=second, is_Echo_of_War=True)
elif re.search(r'Calyx[\s(]+Golden', first):
dungeon = DungeonList.find_dungeon_by_string(en=second, is_Calyx_Golden=True, world=self.plane.world)
elif re.search(r'Calyx[\s(]+Crimson', first):
dungeon = DungeonList.find_dungeon_by_string(en=second, is_Calyx_Crimson=True, plane=self.plane)
if dungeon is not None:
logger.attr('DungeonInteract', dungeon)
return dungeon
# Join
result = ' '.join([row.ocr_text for row in result])
# Special match names in Chinese
# Only calyxes need spacial match
if res := re.search(r'(^.+之蕾)', result):
dungeon = DungeonList.find_dungeon_by_string(cn=res.group(1), is_Calyx_Crimson=True, plane=self.plane)
if dungeon is not None:
logger.attr('DungeonInteract', dungeon)
return dungeon
dungeon = DungeonList.find_dungeon_by_string(cn=res.group(1), is_Calyx_Golden=True, world=self.plane.world)
if dungeon is not None:
logger.attr('DungeonInteract', dungeon)
return dungeon
# Dungeons
try:
dungeon = DungeonList.find(result)
logger.attr('DungeonInteract', dungeon)
return dungeon
except ScriptError:
pass
# Simulated Universe returns Simulated_Universe_World_1
try:
dungeon = DungeonNav.find(result)
if dungeon == KEYWORDS_DUNGEON_NAV.Simulated_Universe:
dungeon = KEYWORDS_DUNGEON_LIST.Simulated_Universe_World_1
logger.attr('DungeonInteract', dungeon)
return dungeon
except ScriptError:
pass
# Unknown
logger.attr('DungeonInteract', None)
return None
def dungeon_goto(self, dungeon: DungeonList):
"""
Returns:
bool: If success
Pages:
in: page_guide, Survival_Index
out: COMBAT_PREPARE if success
page_guide if failed
Examples:
from tasks.dungeon.keywords import KEYWORDS_DUNGEON_LIST
self = DungeonUI('src')
self.device.screenshot()
self.dungeon_tab_goto(KEYWORDS_DUNGEON_TAB.Survival_Index)
self.dungeon_goto(KEYWORDS_DUNGEON_LIST.Calyx_Crimson_Harmony)
"""
# Reset search button
DUNGEON_LIST.search_button = OCR_DUNGEON_LIST
if dungeon.is_Calyx_Crimson \
or dungeon.is_Stagnant_Shadow \
or dungeon.is_Cavern_of_Corrosion \
or dungeon.is_Echo_of_War \
or dungeon.is_Ornament_Extraction:
self._dungeon_nav_goto(dungeon.dungeon_nav)
self._dungeon_wait_until_dungeon_list_loaded()
self._dungeon_insight(dungeon)
self._dungeon_enter(dungeon)
return True
if dungeon.is_Calyx_Golden:
self._dungeon_nav_goto(dungeon.dungeon_nav)
self._dungeon_wait_until_dungeon_list_loaded()
dungeon = self._dungeon_world_set_wrapper(dungeon)
self._dungeon_wait_until_dungeon_list_loaded()
self._dungeon_insight(dungeon)
self._dungeon_enter(dungeon)
return True
logger.error(f'Goto dungeon {dungeon} is not supported')
return False

View File

@ -0,0 +1,85 @@
import re
from module.exception import ScriptError
from module.logger import logger
from tasks.base.ui import UI
from tasks.combat.assets.assets_combat_interact import DUNGEON_COMBAT_INTERACT, DUNGEON_COMBAT_INTERACT_TEXT
from tasks.dungeon.keywords import (
DungeonList,
DungeonNav,
KEYWORDS_DUNGEON_LIST,
KEYWORDS_DUNGEON_NAV
)
from tasks.dungeon.ui.llist import OcrDungeonName
class DungeonUIInteract(UI):
def get_dungeon_interact(self) -> DungeonList | None:
"""
Pages:
in: page_main
"""
if not self.appear(DUNGEON_COMBAT_INTERACT):
logger.info('No dungeon interact')
return None
self.acquire_lang_checked()
ocr = OcrDungeonName(DUNGEON_COMBAT_INTERACT_TEXT)
result = ocr.detect_and_ocr(self.device.image)
dungeon = None
# Special match names in English
# Second row must have at least 3 characters which is the shortest name "Ire"
# Stangnant Shadow: Shape of
# Quanta
if len(result) == 2 and len(result[1].ocr_text) >= 3:
first, second = result[0].ocr_text, result[1].ocr_text
if re.search(r'Stagnant\s*Shadow', first):
dungeon = DungeonList.find_dungeon_by_string(en=second, is_Stagnant_Shadow=True)
elif re.search(r'Cavern\s*of\s*Corrosion', first):
dungeon = DungeonList.find_dungeon_by_string(en=second, is_Cavern_of_Corrosion=True)
elif re.search(r'Echo\s*of\s*War', first):
dungeon = DungeonList.find_dungeon_by_string(en=second, is_Echo_of_War=True)
elif re.search(r'Calyx[\s(]+Golden', first):
dungeon = DungeonList.find_dungeon_by_string(en=second, is_Calyx_Golden=True, world=self.plane.world)
elif re.search(r'Calyx[\s(]+Crimson', first):
dungeon = DungeonList.find_dungeon_by_string(en=second, is_Calyx_Crimson=True, plane=self.plane)
if dungeon is not None:
logger.attr('DungeonInteract', dungeon)
return dungeon
# Join
result = ' '.join([row.ocr_text for row in result])
# Special match names in Chinese
# Only calyxes need spacial match
if res := re.search(r'(^.+之蕾)', result):
dungeon = DungeonList.find_dungeon_by_string(cn=res.group(1), is_Calyx_Crimson=True, plane=self.plane)
if dungeon is not None:
logger.attr('DungeonInteract', dungeon)
return dungeon
dungeon = DungeonList.find_dungeon_by_string(cn=res.group(1), is_Calyx_Golden=True, world=self.plane.world)
if dungeon is not None:
logger.attr('DungeonInteract', dungeon)
return dungeon
# Dungeons
try:
dungeon = DungeonList.find(result)
logger.attr('DungeonInteract', dungeon)
return dungeon
except ScriptError:
pass
# Simulated Universe returns Simulated_Universe_World_1
try:
dungeon = DungeonNav.find(result)
if dungeon == KEYWORDS_DUNGEON_NAV.Simulated_Universe:
dungeon = KEYWORDS_DUNGEON_LIST.Simulated_Universe_World_1
logger.attr('DungeonInteract', dungeon)
return dungeon
except ScriptError:
pass
# Unknown
logger.attr('DungeonInteract', None)
return None

398
tasks/dungeon/ui/llist.py Normal file
View File

@ -0,0 +1,398 @@
import re
import cv2
from pponnxcr.predict_system import BoxedResult
from module.base.base import ModuleBase
from module.base.button import ClickButton
from module.base.decorator import run_once
from module.base.timer import Timer
from module.base.utils import area_center, area_limit, area_offset, crop, image_size
from module.logger import logger
from module.ocr.ocr import Ocr, OcrResultButton
from module.ocr.utils import split_and_pair_button_attr, split_and_pair_buttons
from module.ui.draggable_list import DraggableList
from module.ui.switch import Switch
from tasks.base.page import page_guide
from tasks.base.ui import UI
from tasks.combat.assets.assets_combat_prepare import COMBAT_PREPARE
from tasks.dungeon.assets.assets_dungeon_ui_list import *
from tasks.dungeon.keywords import (
DungeonList,
KEYWORDS_DUNGEON_ENTRANCE,
KEYWORDS_DUNGEON_LIST
)
from tasks.dungeon.keywords.classes import DungeonEntrance
from tasks.map.keywords import MapPlane
LIST_SORTING = Switch('DUNGEON_LIST_SORTING', is_selector=True)
LIST_SORTING.add_state('Ascending', check_button=LIST_ASCENDING)
LIST_SORTING.add_state('Descending', check_button=LIST_DESCENDING)
LIST_SORTING.Ascending = 'Ascending'
LIST_SORTING.Descending = 'Descending'
class OcrDungeonName(Ocr):
def after_process(self, result):
# 乙太之蕾•雅利洛-Ⅵ
result = re.sub(r'-[V][I]', '-Ⅵ', result)
# 苏乐达™热砂海选会场
result = re.sub(r'(苏乐达|蘇樂達|SoulGlad|スラーダ|FelizAlma)[rtT]*M*', r'\1', result)
result = re.sub(r'["\']', '', result)
result = super().after_process(result)
if self.lang == 'cn':
result = result.replace('', '') # 巽风之形
result = result.replace('皖A0', '50').replace('', '')
# 燔灼之形•凝滞虚影
result = result.replace('', '')
result = re.sub('^灼之形', '燔灼之形', result)
# 偃偶之形•凝滞虚影
result = re.sub('^偶之形', '偃偶之形', result)
# 嗔怒之形•凝滞虚影
result = re.sub('^怒之形', '嗔怒之形', result)
# 蛀星的旧·历战余响
result = re.sub(r'蛀星的旧.*?历战', '蛀星的旧靥•历战', result)
# 9支援仓段
for word in 'Q9α':
result = result.removeprefix(word)
return result
class OcrDungeonList(OcrDungeonName):
# Keep __init__ parameter unused
def __init__(self, button: ButtonWrapper = None, lang=None, name=None):
super().__init__(button=button, lang=lang, name='OcrDungeonList')
# target_dungeon: Dungeon attribute to use map planes to predict dungeons only.
self.target_dungeon = None
# limit_entrance: True to ensure the teleport button is insight
self.limit_entrance = False
def detect_and_ocr(self, image, direct_ocr=False) -> list[BoxedResult]:
if self.button != OCR_DUNGEON_NAME:
if self.limit_entrance:
self.button = ClickButton((*self.button.area[:3], self.button.area[3] - 70))
return super().detect_and_ocr(image, direct_ocr=direct_ocr)
# Concat OCR_DUNGEON_NAME and OCR_DUNGEON_TELEPORT
# so they can be OCRed at one time
left = crop(image, OCR_DUNGEON_NAME.area, copy=False)
right = crop(image, OCR_DUNGEON_TELEPORT.area, copy=False)
lw, lh = image_size(left)
rw, rh = image_size(right)
if lh != rh:
logger.error('OCR_DUNGEON_NAME and OCR_DUNGEON_TELEPORT does not have same height, image cannot concat')
image = cv2.hconcat([left, right])
if self.limit_entrance:
w, h = image_size(image)
image = crop(image, (0, 0, w, h - 70), copy=False)
results = super().detect_and_ocr(image, direct_ocr=True)
# Move box
for result in results:
x, _ = area_center(result.box)
# Belongs to right image
if x >= lw:
result.box = area_offset(result.box, offset=(-lw, 0))
result.box = area_offset(result.box, offset=OCR_DUNGEON_TELEPORT.area[:2])
# Belongs to left image
else:
result.box = area_offset(result.box, offset=OCR_DUNGEON_NAME.area[:2])
return results
def _match_result(self, *args, **kwargs):
"""
Convert MapPlane object to their corresponding DungeonList object
"""
matched = super()._match_result(*args, **kwargs)
if self.target_dungeon is not None and matched is not None:
if self.target_dungeon.is_Calyx_Golden:
# convert MapPlane and ignore DungeonList
if isinstance(matched, DungeonList):
return
for dungeon in DungeonList.instances.values():
if dungeon.is_Calyx_Golden and dungeon.plane == matched:
return dungeon
if self.target_dungeon.is_Calyx_Crimson:
if isinstance(matched, DungeonList):
return
for dungeon in DungeonList.instances.values():
if dungeon.is_Calyx_Crimson and dungeon.plane == matched:
return dungeon
else:
if isinstance(matched, MapPlane):
return
return matched
class DraggableDungeonList(DraggableList):
teleports: list[OcrResultButton] = []
navigates: list[OcrResultButton] = []
# target_dungeon: Dungeon attribute to use map planes to predict dungeons only.
target_dungeon = None
# limit_entrance: True to ensure the teleport button is insight
limit_entrance = False
def load_rows(self, main: ModuleBase, allow_early_access=False):
"""
Args:
main:
allow_early_access: True to allow dungeons that are in temporarily early access during events
"""
relative_area = (0, -40, 1280, 120)
def create_ocr_class(*args, **kwargs):
# Passing to OcrDungeonList
obj = OcrDungeonList(*args, **kwargs)
obj.target_dungeon = self.target_dungeon
obj.limit_entrance = self.limit_entrance
return obj
self.ocr_class = create_ocr_class
super().load_rows(main=main)
# Check early access dungeons
buttons = DUNGEON_LIST.cur_buttons.copy()
for name, button in split_and_pair_buttons(
DUNGEON_LIST.cur_buttons,
split_func=lambda x: x != KEYWORDS_DUNGEON_ENTRANCE.Enter,
relative_area=relative_area
):
logger.warning(f'Early access dungeon: {name}')
buttons.remove(name)
buttons.remove(button)
# Remove early access dungeons
if not allow_early_access:
DUNGEON_LIST.cur_buttons = buttons
# From super.load_rows(), re-calculate indexes
indexes = [self.keyword2index(row.matched_keyword)
for row in self.cur_buttons]
indexes = [index for index in indexes if index]
if not indexes:
logger.warning(f'No valid rows loaded into {self}')
return
self.cur_min = min(indexes)
self.cur_max = max(indexes)
logger.attr(self.name, f'{self.cur_min} - {self.cur_max}')
# Replace dungeon.button with teleport
self.teleports = list(split_and_pair_button_attr(
self.cur_buttons,
split_func=lambda x: x != KEYWORDS_DUNGEON_ENTRANCE.Teleport and x != KEYWORDS_DUNGEON_ENTRANCE.Enter,
relative_area=relative_area
))
self.navigates = list(split_and_pair_button_attr(
self.cur_buttons,
split_func=lambda x: x != KEYWORDS_DUNGEON_ENTRANCE.Navigate,
relative_area=relative_area
))
DUNGEON_LIST = DraggableDungeonList(
'DungeonList', keyword_class=[DungeonList, DungeonEntrance, MapPlane],
ocr_class=OcrDungeonList, search_button=OCR_DUNGEON_NAME)
class DungeonUIList(UI):
def _dungeon_list_reset(self):
"""
Reset list to top
Returns:
bool: If success
"""
logger.info('Dungeon list reset')
current = LIST_SORTING.get(main=self)
if current == LIST_SORTING.Descending:
another = LIST_SORTING.Ascending
elif current == LIST_SORTING.Ascending:
another = LIST_SORTING.Descending
else:
logger.warning('Unknown dungeon LIST_SORTING')
return False
LIST_SORTING.set(another, main=self)
LIST_SORTING.set(current, main=self)
return True
def _dungeon_insight_index(self, dungeon: DungeonList):
"""
Insight a dungeon using pre-defined dungeon indexes from DUNGEON_LIST
Pages:
in: page_guide, Survival_Index, nav including dungeon
out: page_guide, Survival_Index, nav including dungeon, dungeon insight
"""
logger.hr('Dungeon insight (index)', level=2)
if dungeon.is_Ornament_Extraction:
# Limit drag area in iOrnament_Extraction
DUNGEON_LIST.search_button = OCR_DUNGEON_NAME_ROGUE
elif dungeon.is_Echo_of_War:
DUNGEON_LIST.search_button = OCR_DUNGEON_LIST
else:
DUNGEON_LIST.search_button = OCR_DUNGEON_NAME
# Predict dungeon by plane name in calyxes where dungeons share the same names
DUNGEON_LIST.target_dungeon = dungeon
DUNGEON_LIST.check_row_order = True
# Insight dungeon
DUNGEON_LIST.insight_row(dungeon, main=self)
self.device.click_record_clear()
# Check if dungeon unlocked
for entrance in DUNGEON_LIST.navigates:
entrance: OcrResultButton = entrance
logger.warning(f'Teleport {entrance.matched_keyword} is not unlocked')
if entrance == dungeon:
logger.error(f'Trying to enter dungeon {dungeon}, but teleport is not unlocked')
return False
# Find teleport button
if dungeon not in [tp.matched_keyword for tp in DUNGEON_LIST.teleports]:
# Dungeon name is insight but teleport button is not
logger.info('Dungeon name is insight, swipe down a little bit to find the teleport button')
if dungeon.is_Forgotten_Hall:
DUNGEON_LIST.drag_vector = (-0.4, -0.2) # Keyword loaded is reversed
else:
DUNGEON_LIST.drag_vector = (0.2, 0.4)
DUNGEON_LIST.limit_entrance = True
DUNGEON_LIST.insight_row(dungeon, main=self)
self.device.click_record_clear()
DUNGEON_LIST.drag_vector = DraggableList.drag_vector
DUNGEON_LIST.limit_entrance = False
DUNGEON_LIST.load_rows(main=self)
# Check if dungeon unlocked
for entrance in DUNGEON_LIST.navigates:
if entrance.matched_keyword == dungeon:
logger.error(f'Trying to enter dungeon {dungeon}, but teleport is not unlocked')
return False
return True
def _dungeon_insight_sort(self, dungeon: DungeonList):
"""
Insight a dungeon using sorter and plain drag, reset list on error
"""
logger.hr('Dungeon insight (sort)', level=2)
logger.info(f'Dungeon insight: {dungeon}')
DUNGEON_LIST.search_button = OCR_DUNGEON_NAME
DUNGEON_LIST.target_dungeon = dungeon
DUNGEON_LIST.check_row_order = False
for _ in range(3):
visited = set()
end_count = 0
self.device.click_record_clear()
while 1:
visited_count = len(visited)
# Load
DUNGEON_LIST.load_rows(main=self, allow_early_access=True)
for entrance in DUNGEON_LIST.teleports:
if entrance.matched_keyword == dungeon:
logger.info(f'Found dungeon {dungeon}')
return True
for entrance in DUNGEON_LIST.navigates:
if entrance.matched_keyword == dungeon:
logger.error(f'Trying to enter dungeon {dungeon}, but teleport is not unlocked')
return False
# Check end
for entrance in DUNGEON_LIST.cur_buttons:
visited.add(entrance.matched_keyword.name)
if len(visited) <= visited_count:
logger.warning('No more rows loaded')
end_count += 1
if end_count >= 3:
logger.error('Dungeon list reached end but target dungeon not found')
break
# Drag down
DUNGEON_LIST.drag_page('down', main=self)
self.wait_until_stable(DUNGEON_LIST.search_button, timer=Timer(
0, count=0), timeout=Timer(1.5, count=5))
self._dungeon_list_reset()
logger.error('Failed to insight dungeon after 3 trial')
return False
def dungeon_insight(self, dungeon: DungeonList):
"""
Insight a dungeon
Pages:
in: page_guide, Survival_Index, nav including dungeon
out: page_guide, Survival_Index, nav including dungeon, dungeon insight
"""
if dungeon.is_Calyx_Crimson or dungeon.is_Stagnant_Shadow:
# Having dungeon sorting and early access
self._dungeon_insight_sort(dungeon)
else:
self._dungeon_insight_index(dungeon)
def _dungeon_enter(self, dungeon, enter_check_button=COMBAT_PREPARE, skip_first_screenshot=True):
"""
Pages:
in: page_guide, Survival_Index, nav including dungeon
out: COMBAT_PREPARE, FORGOTTEN_HALL_CHECK
"""
logger.hr('Dungeon enter', level=2)
DUNGEON_LIST.target_dungeon = dungeon
skip_first_load = skip_first_screenshot
@run_once
def screenshot_interval_set():
self.device.screenshot_interval_set('combat')
while 1:
if skip_first_screenshot:
skip_first_screenshot = False
else:
self.device.screenshot()
# End
if self.appear(enter_check_button):
logger.info(f'Arrive {enter_check_button.name}')
break
# Additional
# Popup that confirm character switch
if self.handle_popup_confirm():
self.interval_reset(page_guide.check_button)
continue
# Click teleport
if self.appear(page_guide.check_button, interval=1):
if skip_first_load:
skip_first_load = False
else:
DUNGEON_LIST.load_rows(main=self)
entrance = DUNGEON_LIST.keyword2button(dungeon)
if entrance is not None:
# Avoid clicking the soring button
entrance.button = area_limit(entrance.button, OCR_DUNGEON_TELEPORT.area)
self.device.click(entrance)
screenshot_interval_set()
self.interval_reset(page_guide.check_button)
continue
else:
logger.warning(f'Cannot find dungeon entrance of {dungeon}')
continue
self.device.screenshot_interval_set()
if __name__ == '__main__':
self = DungeonUIList('src')
self.device.screenshot()
self.dungeon_insight(KEYWORDS_DUNGEON_LIST.Echo_of_War_Divine_Seed)

351
tasks/dungeon/ui/nav.py Normal file
View File

@ -0,0 +1,351 @@
import cv2
import numpy as np
from module.base.base import ModuleBase
from module.base.timer import Timer
from module.base.utils import get_color
from module.logger import logger
from module.ocr.ocr import Ocr
from module.ui.draggable_list import DraggableList
from module.ui.switch import Switch
from tasks.base.page import page_guide
from tasks.base.ui import UI
from tasks.dungeon.assets.assets_dungeon_ui import *
from tasks.dungeon.assets.assets_dungeon_ui_rogue import *
from tasks.dungeon.keywords import (
DungeonNav,
DungeonTab,
KEYWORDS_DUNGEON_NAV,
KEYWORDS_DUNGEON_TAB
)
from tasks.map.interact.aim import inrange
class DungeonTabSwitch(Switch):
SEARCH_BUTTON = TAB_SEARCH
def add_state(self, state, check_button, click_button=None):
# Load search
if check_button is not None:
check_button.load_search(self.__class__.SEARCH_BUTTON.area)
if click_button is not None:
click_button.load_search(self.__class__.SEARCH_BUTTON.area)
return super().add_state(state, check_button, click_button)
def click(self, state, main):
"""
Args:
state (str):
main (ModuleBase):
"""
button = self.get_data(state)['click_button']
_ = main.appear(button) # Search button to load offset
main.device.click(button)
SWITCH_DUNGEON_TAB = DungeonTabSwitch('DungeonTab', is_selector=True)
SWITCH_DUNGEON_TAB.add_state(
KEYWORDS_DUNGEON_TAB.Operation_Briefing,
check_button=OPERATION_BRIEFING_CHECK,
click_button=OPERATION_BRIEFING_CLICK
)
SWITCH_DUNGEON_TAB.add_state(
KEYWORDS_DUNGEON_TAB.Daily_Training,
check_button=DAILY_TRAINING_CHECK,
click_button=DAILY_TRAINING_CLICK
)
SWITCH_DUNGEON_TAB.add_state(
KEYWORDS_DUNGEON_TAB.Survival_Index,
check_button=SURVIVAL_INDEX_CHECK,
click_button=SURVIVAL_INDEX_CLICK
)
SWITCH_DUNGEON_TAB.add_state(
KEYWORDS_DUNGEON_TAB.Simulated_Universe,
check_button=SIMULATED_UNIVERSE_CHECK,
click_button=SIMULATED_UNIVERSE_CLICK
)
SWITCH_DUNGEON_TAB.add_state(
KEYWORDS_DUNGEON_TAB.Treasures_Lightward,
check_button=TREASURES_LIGHTWARD_CHECK,
click_button=TREASURES_LIGHTWARD_CLICK
)
class OcrDungeonNav(Ocr):
def after_process(self, result):
result = super().after_process(result)
result = result.replace('#', '')
if self.lang == 'cn':
result = result.replace('萼喜', '')
result = result.replace('', '') # 凝带虚影
return result
class DraggableDungeonNav(DraggableList):
# 0.5 is the magic number to reach bottom in 1 swipe
# but relax we still have retires when magic doesn't work
drag_vector = (0.50, 0.52)
DUNGEON_NAV_LIST = DraggableDungeonNav(
'DungeonNavList', keyword_class=DungeonNav, ocr_class=OcrDungeonNav, search_button=OCR_DUNGEON_NAV)
class DungeonUINav(UI):
def dungeon_tab_goto(self, state: DungeonTab):
"""
Args:
state:
Returns:
bool: If UI switched
Examples:
self = DungeonUI('alas')
self.device.screenshot()
self.dungeon_tab_goto(KEYWORDS_DUNGEON_TAB.Operation_Briefing)
self.dungeon_tab_goto(KEYWORDS_DUNGEON_TAB.Daily_Training)
self.dungeon_tab_goto(KEYWORDS_DUNGEON_TAB.Survival_Index)
"""
logger.hr('Dungeon tab goto', level=2)
ui_switched = self.ui_ensure(page_guide)
tab_switched = SWITCH_DUNGEON_TAB.set(state, main=self)
if ui_switched or tab_switched:
if state == KEYWORDS_DUNGEON_TAB.Daily_Training:
logger.info(f'Tab goto {state}, wait until loaded')
self._dungeon_wait_daily_training_loaded()
elif state == KEYWORDS_DUNGEON_TAB.Survival_Index:
logger.info(f'Tab goto {state}, wait until loaded')
self._dungeon_wait_survival_index_loaded()
elif state == KEYWORDS_DUNGEON_TAB.Treasures_Lightward:
logger.info(f'Tab goto {state}, wait until loaded')
self._dungeon_wait_treasures_lightward_loaded()
return True
else:
return False
def _dungeon_wait_daily_training_loaded(self, skip_first_screenshot=True):
"""
Returns:
bool: True if wait success, False if wait timeout.
Pages:
in: page_guide, Daily_Training
"""
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 daily training loaded timeout')
return False
color = get_color(self.device.image, DAILY_TRAINING_LOADED.area)
if np.mean(color) < 128:
logger.info('Daily training loaded')
return True
def _dungeon_wait_survival_index_loaded(self, skip_first_screenshot=True):
"""
Returns:
bool: True if wait success, False if wait timeout.
Pages:
in: page_guide, Survival_Index
"""
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 survival index loaded timeout')
return False
if self.appear(SURVIVAL_INDEX_SU_LOADED):
logger.info('Survival index loaded, SURVIVAL_INDEX_SU_LOADED')
return True
if self.appear(SURVIVAL_INDEX_OE_LOADED):
logger.info('Survival index loaded, SURVIVAL_INDEX_OE_LOADED')
return True
def _dungeon_survival_index_top_appear(self):
if self.appear(SURVIVAL_INDEX_SU_LOADED):
return True
if self.appear(SURVIVAL_INDEX_OE_LOADED):
return True
return False
def _dungeon_wait_treasures_lightward_loaded(self, skip_first_screenshot=True):
"""
Returns:
bool: True if wait success, False if wait timeout.
Pages:
in: page_guide, Survival_Index
"""
timeout = Timer(2, count=4).start()
TREASURES_LIGHTWARD_LOADED.set_search_offset((5, 5))
TREASURES_LIGHTWARD_LOCKED.set_search_offset((5, 5))
while 1:
if skip_first_screenshot:
skip_first_screenshot = False
else:
self.device.screenshot()
if timeout.reached():
logger.warning('Wait treasures lightward loaded timeout')
return False
if self.appear(TREASURES_LIGHTWARD_LOADED):
logger.info('Treasures lightward loaded (event unlocked)')
return True
if self.appear(TREASURES_LIGHTWARD_LOCKED):
logger.info('Treasures lightward loaded (event locked)')
return True
def _dungeon_list_button_has_content(self):
# Check if having any content
# List background: 254, guild border: 225
r, g, b = cv2.split(self.image_crop(LIST_LOADED_CHECK, copy=False))
minimum = cv2.min(cv2.min(r, g), b)
minimum = inrange(minimum, lower=0, upper=180)
if minimum.size > 100:
return True
else:
return False
def _dungeon_wait_until_dungeon_list_loaded(self, skip_first_screenshot=True):
timeout = Timer(1, count=3).start()
while 1:
if skip_first_screenshot:
skip_first_screenshot = False
else:
self.device.screenshot()
# End
if timeout.reached():
logger.warning('Wait until dungeon list loaded timeout')
return False
if self._dungeon_list_button_has_content():
logger.info('Dungeon list loaded')
return True
def _dungeon_wait_until_echo_or_war_stabled(self, skip_first_screenshot=True):
"""
Returns:
bool: True if wait success, False if wait timeout.
Pages:
in: page_guide, Survival_Index
"""
# Wait until Forgotten_Hall stabled
timeout = Timer(2, count=4).start()
while 1:
if skip_first_screenshot:
skip_first_screenshot = False
else:
self.device.screenshot()
# End
if timeout.reached():
logger.warning('Wait until Echo_of_War stabled timeout')
return False
DUNGEON_NAV_LIST.load_rows(main=self)
# End
button = DUNGEON_NAV_LIST.keyword2button(KEYWORDS_DUNGEON_NAV.Echo_of_War, show_warning=False)
if button:
# 513 is the top of the last row of DungeonNav
if button.area[1] > 513:
logger.info('DungeonNav row Echo_of_War stabled')
return True
else:
logger.info('No Echo_of_War in list skip waiting')
return False
def dungeon_nav_goto(self, nav: DungeonNav, skip_first_screenshot=True):
"""
Equivalent to `DUNGEON_NAV_LIST.select_row(dungeon.dungeon_nav, main=self)`
but with tricks to be faster
Args:
nav:
skip_first_screenshot:
"""
logger.hr('Dungeon nav goto', level=2)
logger.info(f'Dungeon nav goto {nav}')
# Wait rows
while 1:
if skip_first_screenshot:
skip_first_screenshot = False
else:
self.device.screenshot()
DUNGEON_NAV_LIST.load_rows(main=self)
if DUNGEON_NAV_LIST.cur_buttons:
break
# Wait first row selected
timeout = Timer(0.5, count=2).start()
skip_first_screenshot = True
while 1:
if skip_first_screenshot:
skip_first_screenshot = False
else:
self.device.screenshot()
if timeout.reached():
logger.info('DUNGEON_NAV_LIST not selected')
break
if button := DUNGEON_NAV_LIST.get_selected_row(main=self):
logger.info(f'DUNGEON_NAV_LIST selected at {button}')
break
# Check if it's at the first page.
if DUNGEON_NAV_LIST.keyword2button(KEYWORDS_DUNGEON_NAV.Simulated_Universe, show_warning=False) \
or DUNGEON_NAV_LIST.keyword2button(KEYWORDS_DUNGEON_NAV.Ornament_Extraction, show_warning=False):
# Going to use a faster method to navigate but can only start from list top
logger.info('DUNGEON_NAV_LIST at top')
# Update points if possible
# 2.3, No longer weekly points after Divergent Universe unlocked
# if DUNGEON_NAV_LIST.is_row_selected(button, main=self):
# self.dungeon_update_simuni()
# Treasures lightward is always at top
elif DUNGEON_NAV_LIST.keyword2button(KEYWORDS_DUNGEON_NAV.Forgotten_Hall, show_warning=False) \
or DUNGEON_NAV_LIST.keyword2button(KEYWORDS_DUNGEON_NAV.Pure_Fiction, show_warning=False):
logger.info('DUNGEON_NAV_LIST at top')
else:
# To start from any list states.
logger.info('DUNGEON_NAV_LIST not at top')
DUNGEON_NAV_LIST.select_row(nav, main=self)
return True
# Check the first page
if nav in [
KEYWORDS_DUNGEON_NAV.Simulated_Universe,
KEYWORDS_DUNGEON_NAV.Divergent_Universe,
KEYWORDS_DUNGEON_NAV.Ornament_Extraction,
KEYWORDS_DUNGEON_NAV.Calyx_Golden,
KEYWORDS_DUNGEON_NAV.Calyx_Crimson,
KEYWORDS_DUNGEON_NAV.Stagnant_Shadow,
KEYWORDS_DUNGEON_NAV.Cavern_of_Corrosion,
KEYWORDS_DUNGEON_NAV.Forgotten_Hall,
KEYWORDS_DUNGEON_NAV.Pure_Fiction,
]:
button = DUNGEON_NAV_LIST.keyword2button(nav)
if button:
DUNGEON_NAV_LIST.select_row(nav, main=self, insight=False)
return True
# Check the second page
while 1:
DUNGEON_NAV_LIST.drag_page('down', main=self)
# No skip_first_screenshot since drag_page is just called
if self._dungeon_wait_until_echo_or_war_stabled(skip_first_screenshot=False):
DUNGEON_NAV_LIST.select_row(nav, main=self, insight=False)
return True

41
tasks/dungeon/ui/ui.py Normal file
View File

@ -0,0 +1,41 @@
from module.logger import logger
from tasks.dungeon.keywords import DungeonList
from tasks.dungeon.ui.interact import DungeonUIInteract
from tasks.dungeon.ui.llist import DungeonUIList
from tasks.dungeon.ui.nav import DungeonUINav
from tasks.dungeon.ui.state import DungeonState
class DungeonUI(DungeonState, DungeonUINav, DungeonUIList, DungeonUIInteract):
def dungeon_goto(self, dungeon: DungeonList):
"""
Returns:
bool: If success
Pages:
in: page_guide, Survival_Index
out: COMBAT_PREPARE if success
page_guide if failed
Examples:
from tasks.dungeon.keywords import KEYWORDS_DUNGEON_LIST
self = DungeonUI('src')
self.device.screenshot()
self.dungeon_tab_goto(KEYWORDS_DUNGEON_TAB.Survival_Index)
self.dungeon_goto(KEYWORDS_DUNGEON_LIST.Calyx_Crimson_Harmony)
"""
# Reset search button
if dungeon.is_Calyx_Golden \
or dungeon.is_Calyx_Crimson \
or dungeon.is_Stagnant_Shadow \
or dungeon.is_Cavern_of_Corrosion \
or dungeon.is_Echo_of_War \
or dungeon.is_Ornament_Extraction:
self.dungeon_nav_goto(dungeon.dungeon_nav)
self._dungeon_wait_until_dungeon_list_loaded()
self.dungeon_insight(dungeon)
self._dungeon_enter(dungeon)
return True
logger.error(f'Goto dungeon {dungeon} is not supported')
return False

View File

@ -3,9 +3,11 @@ from module.base.utils import random_rectangle_vector
from module.logger import logger
from tasks.base.page import page_guide
from tasks.dungeon.assets.assets_dungeon_ui import *
from tasks.dungeon.assets.assets_dungeon_ui_list import OCR_DUNGEON_LIST
from tasks.dungeon.assets.assets_dungeon_ui_rogue import *
from tasks.dungeon.keywords import KEYWORDS_DUNGEON_NAV, KEYWORDS_DUNGEON_TAB
from tasks.dungeon.ui import DungeonUI, SWITCH_DUNGEON_TAB
from tasks.dungeon.ui.nav import SWITCH_DUNGEON_TAB
from tasks.dungeon.ui.ui import DungeonUI
from tasks.forgotten_hall.assets.assets_forgotten_hall_ui import TELEPORT
@ -41,7 +43,7 @@ class DungeonRogueUI(DungeonUI):
logger.info(f'Tab goto {state}, wait until loaded')
self._dungeon_wait_until_rogue_loaded()
# Switch nav
self._dungeon_nav_goto(KEYWORDS_DUNGEON_NAV.Simulated_Universe)
self.dungeon_nav_goto(KEYWORDS_DUNGEON_NAV.Simulated_Universe)
# No idea how to wait list loaded
# List is not able to swipe without fully loaded
self.wait_until_stable(LIST_LOADED_CHECK)
@ -59,7 +61,7 @@ class DungeonRogueUI(DungeonUI):
if self.appear(SURVIVAL_INDEX_SU_LOADED):
logger.info('Already at nav Simulated_Universe')
else:
self._dungeon_nav_goto(KEYWORDS_DUNGEON_NAV.Simulated_Universe)
self.dungeon_nav_goto(KEYWORDS_DUNGEON_NAV.Simulated_Universe)
def _dungeon_wait_until_rogue_loaded(self, skip_first_screenshot=True):
"""

View File

@ -2,10 +2,9 @@ from module.config.utils import get_server_next_monday_update
from module.logger import logger
from module.ocr.ocr import DigitCounter
from tasks.daily.keywords import KEYWORDS_DAILY_QUEST
from tasks.dungeon.assets.assets_dungeon_ui import OCR_DUNGEON_LIST, OCR_WEEKLY_LIMIT
from tasks.dungeon.assets.assets_dungeon_ui import OCR_WEEKLY_LIMIT
from tasks.dungeon.dungeon import Dungeon
from tasks.dungeon.keywords import DungeonList, KEYWORDS_DUNGEON_NAV, KEYWORDS_DUNGEON_TAB
from tasks.dungeon.ui import DUNGEON_LIST
class OcrWeeklyLimit(DigitCounter):
@ -78,8 +77,7 @@ class WeeklyDungeon(Dungeon):
# UI switches
self.dungeon_tab_goto(KEYWORDS_DUNGEON_TAB.Survival_Index)
# Equivalent to self.dungeon_goto(dungeon), but check limit remains
DUNGEON_LIST.search_button = OCR_DUNGEON_LIST
self._dungeon_nav_goto(KEYWORDS_DUNGEON_NAV.Echo_of_War)
self.dungeon_nav_goto(KEYWORDS_DUNGEON_NAV.Echo_of_War)
self._dungeon_wait_until_dungeon_list_loaded()
monday = get_server_next_monday_update(self.config.Scheduler_ServerUpdate)
@ -94,7 +92,7 @@ class WeeklyDungeon(Dungeon):
self.config.task_delay(target=monday)
self.config.task_stop()
self._dungeon_insight(dungeon)
self.dungeon_insight(dungeon)
self._dungeon_enter(dungeon)
# Combat

View File

@ -10,8 +10,8 @@ from module.ocr.keyword import Keyword
from module.ocr.ocr import Ocr, OcrResultButton
from module.ui.draggable_list import DraggableList
from tasks.base.assets.assets_base_page import FORGOTTEN_HALL_CHECK, MAP_EXIT
from tasks.dungeon.ui.ui import DungeonUI
from tasks.dungeon.keywords import DungeonList, KEYWORDS_DUNGEON_LIST, KEYWORDS_DUNGEON_NAV, KEYWORDS_DUNGEON_TAB
from tasks.dungeon.ui import DungeonUI
from tasks.forgotten_hall.assets.assets_forgotten_hall_nav import *
from tasks.forgotten_hall.assets.assets_forgotten_hall_ui import *
from tasks.forgotten_hall.keywords import ForgottenHallStage, KEYWORDS_FORGOTTEN_HALL_STAGE
@ -187,7 +187,7 @@ class ForgottenHallUI(DungeonUI, ForgottenHallTeam):
logger.info('Already in forgotten hall')
else:
self.dungeon_tab_goto(KEYWORDS_DUNGEON_TAB.Treasures_Lightward)
self._dungeon_nav_goto(KEYWORDS_DUNGEON_NAV.Forgotten_Hall)
self.dungeon_nav_goto(KEYWORDS_DUNGEON_NAV.Forgotten_Hall)
self.stage_choose(dungeon)
logger.info(f'Stage list select: {stage_keyword}')

View File

@ -465,8 +465,19 @@ Luofu_TheShacklingPrison = MapPlane(
world_id=2,
plane_id=2024101,
)
Penacony_TheReverieReality = MapPlane(
Luofu_Skysplitter = MapPlane(
id=43,
name='Luofu_Skysplitter',
cn='竞锋舰',
cht='競鋒艦',
en='Skysplitter',
jp='競鋒艦',
es='Bifurcacielos',
world_id=2,
plane_id=2024201,
)
Penacony_TheReverieReality = MapPlane(
id=44,
name='Penacony_TheReverieReality',
cn='「白日梦」酒店-现实',
cht='「白日夢」飯店-現實',
@ -477,7 +488,7 @@ Penacony_TheReverieReality = MapPlane(
plane_id=1030501,
)
Penacony_GoldenHour = MapPlane(
id=44,
id=45,
name='Penacony_GoldenHour',
cn='黄金的时刻',
cht='黃金的時刻',
@ -488,7 +499,7 @@ Penacony_GoldenHour = MapPlane(
plane_id=1030101,
)
Penacony_DreamEdge = MapPlane(
id=45,
id=46,
name='Penacony_DreamEdge',
cn='筑梦边境',
cht='築夢邊境',
@ -499,7 +510,7 @@ Penacony_DreamEdge = MapPlane(
plane_id=2031301,
)
Penacony_AChildDream = MapPlane(
id=46,
id=47,
name='Penacony_AChildDream',
cn='稚子的梦',
cht='稚子的夢',
@ -510,7 +521,7 @@ Penacony_AChildDream = MapPlane(
plane_id=2031201,
)
Penacony_TheReverieDreamscape = MapPlane(
id=47,
id=48,
name='Penacony_TheReverieDreamscape',
cn='「白日梦」酒店-梦境',
cht='「白日夢」飯店-夢境',
@ -521,7 +532,7 @@ Penacony_TheReverieDreamscape = MapPlane(
plane_id=2031101,
)
Penacony_DewlightPavilion = MapPlane(
id=48,
id=49,
name='Penacony_DewlightPavilion',
cn='朝露公馆',
cht='朝露公館',
@ -532,7 +543,7 @@ Penacony_DewlightPavilion = MapPlane(
plane_id=2032201,
)
Penacony_ClockStudiosThemePark = MapPlane(
id=49,
id=50,
name='Penacony_ClockStudiosThemePark',
cn='克劳克影视乐园',
cht='克勞克影視樂園',
@ -543,7 +554,7 @@ Penacony_ClockStudiosThemePark = MapPlane(
plane_id=2032101,
)
Penacony_DreamfluxReef = MapPlane(
id=50,
id=51,
name='Penacony_DreamfluxReef',
cn='流梦礁',
cht='流夢礁',
@ -554,7 +565,7 @@ Penacony_DreamfluxReef = MapPlane(
plane_id=1030401,
)
Penacony_SoulGladScorchsandAuditionVenue = MapPlane(
id=51,
id=52,
name='Penacony_SoulGladScorchsandAuditionVenue',
cn='苏乐达热砂海选会场',
cht='蘇樂達熱砂海選會場',
@ -565,7 +576,7 @@ Penacony_SoulGladScorchsandAuditionVenue = MapPlane(
plane_id=2033101,
)
Penacony_PenaconyGrandTheater = MapPlane(
id=52,
id=53,
name='Penacony_PenaconyGrandTheater',
cn='匹诺康尼大剧院',
cht='匹諾康尼大劇院',

View File

@ -6,7 +6,7 @@ from tasks.base.assets.assets_base_popup import POPUP_CANCEL
from tasks.combat.assets.assets_combat_prepare import COMBAT_PREPARE
from tasks.combat.assets.assets_combat_support import COMBAT_SUPPORT_LIST
from tasks.dungeon.dungeon import Dungeon
from tasks.dungeon.state import DungeonState
from tasks.dungeon.ui.state import DungeonState
from tasks.map.route.loader import RouteLoader
from tasks.map.route.route.daily import OrnamentExtraction__route
from tasks.ornament.assets.assets_ornament_combat import *

View File

@ -224,8 +224,34 @@ Dream_Fridge = ItemAscension(
item_group=1100,
dungeon_id=1115,
)
Dream_Flamer = ItemAscension(
Nail_of_the_Beast_Coffin = ItemAscension(
id=18,
name='Nail_of_the_Beast_Coffin',
cn='兽棺之钉',
cht='獸棺之釘',
en='Nail of the Beast Coffin',
jp='獣棺の釘',
es='Clavo del ataúd bestial',
rarity='VeryRare',
item_id=110424,
item_group=1100,
dungeon_id=1120,
)
A_Glass_of_the_Besotted_Era = ItemAscension(
id=19,
name='A_Glass_of_the_Besotted_Era',
cn='一杯酩酊的时代',
cht='一杯酩酊的時代',
en='A Glass of the Besotted Era',
jp='酩酊する時代の一杯',
es='Copa de la era embriagada',
rarity='VeryRare',
item_id=110425,
item_group=1100,
dungeon_id=1121,
)
Dream_Flamer = ItemAscension(
id=20,
name='Dream_Flamer',
cn='炙梦喷枪',
cht='炙夢噴槍',

View File

@ -81,3 +81,16 @@ Lost_Echo_of_the_Shared_Wish = ItemWeekly(
item_group=1310,
dungeon_id=1305,
)
Auspice_Sliver = ItemWeekly(
id=7,
name='Auspice_Sliver',
cn='吉光片羽',
cht='吉光片羽',
en='Auspice Sliver',
jp='吉光の羽',
es='Pluma auspiciosa',
rarity='VeryRare',
item_id=110506,
item_group=1310,
dungeon_id=1306,
)

View File

@ -37,6 +37,8 @@ class OcrItemName(Ocr):
# Error words on blank background
result = re.sub('^[國東]', '', result)
result = re.sub('時$', '', result)
# 一杯酩酊的时代
result = re.sub('一杯[酪酩酊酐]*的', '一杯酩酊的', result)
return result

View File

@ -14,8 +14,8 @@ from tasks.base.assets.assets_base_page import MAP_EXIT
from tasks.base.page import page_guide, page_item, page_main, page_rogue
from tasks.dungeon.keywords import DungeonList
from tasks.dungeon.keywords.dungeon import Simulated_Universe_World_1
from tasks.dungeon.state import OcrSimUniPoint
from tasks.dungeon.ui_rogue import DungeonRogueUI
from tasks.dungeon.ui.state import OcrSimUniPoint
from tasks.dungeon.ui.ui_rogue import DungeonRogueUI
from tasks.forgotten_hall.assets.assets_forgotten_hall_ui import TELEPORT
from tasks.rogue.assets.assets_rogue_entry import (
LEVEL_CONFIRM,

View File

@ -123,8 +123,8 @@ STRATEGY_COMMON = {
KEYWORDS_ROGUE_EVENT_OPTION.Leave_3c49
],
KEYWORDS_ROGUE_EVENT_TITLE.Robot_Sales_Terminal: [
KEYWORDS_ROGUE_EVENT_OPTION.Purchase_a_1_3_star_Blessing,
KEYWORDS_ROGUE_EVENT_OPTION.Purchase_a_1_2_star_Blessing,
KEYWORDS_ROGUE_EVENT_OPTION.Purchase_1_Blessing_of_1_to_3_star_rarity,
KEYWORDS_ROGUE_EVENT_OPTION.Purchase_1_Blessing_of_1_to_3_star_rarity,
KEYWORDS_ROGUE_EVENT_OPTION.Leave_3c49
],
KEYWORDS_ROGUE_EVENT_TITLE.History_Fictionologists: [

View File

@ -4,7 +4,7 @@ from module.base.timer import Timer
from module.logger import logger
from tasks.base.assets.assets_base_popup import GET_REWARD
from tasks.combat.interact import CombatInteract
from tasks.dungeon.state import DungeonState
from tasks.dungeon.ui.state import DungeonState
from tasks.rogue.assets.assets_rogue_reward import REWARD_CLOSE, USE_IMMERSIFIER, USE_STAMINA
from tasks.rogue.blessing.ui import RogueUI

View File

@ -75,32 +75,32 @@ Equilibrium_Universe = RogueBonus(
jp='均衡な宇宙',
es='Universo equilibrado',
)
Path_of_Preservation = RogueBonus(
Mechanic = RogueBonus(
id=9,
name='Path_of_Preservation',
cn='存护之路',
cht='存護之路',
en='Path of Preservation',
jp='存護の道',
es='Camino de la Conservación',
name='Mechanic',
cn='机修工',
cht='機修工',
en='Mechanic',
jp='機械修理工',
es='Mecánic',
)
Path_of_Remembrance = RogueBonus(
Surveyor = RogueBonus(
id=10,
name='Path_of_Remembrance',
cn='记忆之路',
cht='記憶之路',
en='Path of Remembrance',
jp='記憶の道',
es='Camino de la Reminiscencia',
name='Surveyor',
cn='测绘师',
cht='測繪師',
en='Surveyor',
jp='測量士',
es='Topógraf',
)
Path_of_Nihility = RogueBonus(
Adventurer = RogueBonus(
id=11,
name='Path_of_Nihility',
cn='虚无之路',
cht='虛無之路',
en='Path of Nihility',
jp='虚無の道',
es='Camino de la Nihilidad',
name='Adventurer',
cn='冒险家',
cht='冒險家',
en='Adventurer',
jp='冒険家',
es='Aventurero',
)
Path_of_Abundance = RogueBonus(
id=12,
@ -246,3 +246,39 @@ Lying_Cap = RogueBonus(
jp='ペテンハット',
es='Sombrero mentiroso',
)
Case_Folder = RogueBonus(
id=28,
name='Case_Folder',
cn='案件簿',
cht='案件簿',
en='Case Folder',
jp='事件簿',
es='Expediente de casos',
)
Bloodguilt_Tome = RogueBonus(
id=29,
name='Bloodguilt_Tome',
cn='血罪书',
cht='血罪書',
en='Bloodguilt Tome',
jp='血罪書',
es='Tomo de la culpa sangrienta',
)
Shuttle_Boat = RogueBonus(
id=30,
name='Shuttle_Boat',
cn='梭子船',
cht='渡船',
en='Shuttle Boat',
jp='杼船',
es='Nave lanzadera',
)
Consciousness_Cluster = RogueBonus(
id=31,
name='Consciousness_Cluster',
cn='意识群',
cht='意識群',
en='Consciousness Cluster',
jp='意識群',
es='Grupo de conciencia',
)

View File

@ -1218,21 +1218,21 @@ Let_the_sleeping_soldiers_wake_up_again = RogueEventOption(
jp='熟睡する兵士を「再び目覚めさせる」',
es='Dejas que los soldados dormidos despierten nuevamente.',
)
Purchase_a_1_2_star_Blessing = RogueEventOption(
Purchase_1_Blessing_of_1_to_2_star_rarity = RogueEventOption(
id=136,
name='Purchase_a_1_2_star_Blessing',
name='Purchase_1_Blessing_of_1_to_2_star_rarity',
cn='购买1个1-2星祝福',
cht='購買1個一至二星祝福',
en='Purchase a 12 star Blessing',
en='Purchase 1 Blessing of 1- to 2-star rarity',
jp='★12の祝福を1個購入する',
es='Compra 1 bendición de 1-2 estrellas.',
)
Purchase_a_1_3_star_Blessing = RogueEventOption(
Purchase_1_Blessing_of_1_to_3_star_rarity = RogueEventOption(
id=137,
name='Purchase_a_1_3_star_Blessing',
name='Purchase_1_Blessing_of_1_to_3_star_rarity',
cn='购买1个1-3星祝福',
cht='購買1個一至三星祝福',
en='Purchase a 1-3 star Blessing',
en='Purchase 1 Blessing of 1- to 3-star rarity',
jp='★13の祝福を1個購入する',
es='Compra 1 bendición de 1-3 estrellas.',
)
@ -2892,12 +2892,12 @@ Charge_head_on = RogueEventOption(
jp='正面から突入する!',
es='¡A la carga de frente!',
)
It_is_an_all_or_nothing_move = RogueEventOption(
It_is_a_daring_move_that_risks_it_all = RogueEventOption(
id=322,
name='It_is_an_all_or_nothing_move',
name='It_is_a_daring_move_that_risks_it_all',
cn='这是一场孤注一掷的行动。',
cht='這是一場孤注一擲的行動。',
en='It is an all-or-nothing move.',
en='It is a daring move that risks it all.',
jp='これは一か八かの作戦だ',
es='Es una acción desesperada.',
)
@ -3549,3 +3549,723 @@ Increase_experimental_samples = RogueEventOption(
jp='実験サンプルを増やす。',
es='Aumentas las muestras experimentales.',
)
The_vending_machine_displays_a_discount = RogueEventOption(
id=395,
name='The_vending_machine_displays_a_discount',
cn='售货机亮出了折扣。',
cht='販賣機亮出了折扣。',
en='The vending machine displays a discount.',
jp='自動販売機が割引と表示した',
es='La máquina expendedora muestra un descuento.',
)
It_too_expensive = RogueEventOption(
id=396,
name='It_too_expensive',
cn='太贵了。',
cht='太貴了。',
en="It's too expensive.",
jp='高すぎる',
es='Es muy caro.',
)
The_vending_machine_displays_the_price = RogueEventOption(
id=397,
name='The_vending_machine_displays_the_price',
cn='售货机亮出了售价。',
cht='販賣機亮出了售價。',
en='The vending machine displays the price.',
jp='自動販売機が販売価格を表示した',
es='La máquina expendedora muestra el precio.',
)
I_want_freebies = RogueEventOption(
id=398,
name='I_want_freebies',
cn='我要免费的!',
cht='我要免費的!',
en='I want freebies!',
jp='無料がいい!',
es='¡Quiero cosas gratis!',
)
You_better_reconsider = RogueEventOption(
id=399,
name='You_better_reconsider',
cn='你最好再想想。',
cht='你最好再想想。',
en='You better reconsider.',
jp='考え直したほうがいい',
es='Será mejor que lo reconsideres.',
)
Is_this_enough = RogueEventOption(
id=400,
name='Is_this_enough',
cn='这个够了吗?',
cht='這個夠了嗎?',
en='Is this enough?',
jp='これでいい?',
es='¿Acaso es suficiente?',
)
Do_me_a_favor = RogueEventOption(
id=401,
name='Do_me_a_favor',
cn='给我个面子。',
cht='給我一個面子。',
en='Do me a favor.',
jp='顔を立ててほしい',
es='Hazme un favor.',
)
The_vending_machine_spits_out_the_product = RogueEventOption(
id=402,
name='The_vending_machine_spits_out_the_product',
cn='售货机吐出了商品。',
cht='販賣機吐出了商品。',
en='The vending machine spits out the product.',
jp='自動販売機が商品を吐き出した',
es='La máquina expendedora escupe el producto.',
)
Show_it_how_strong_you_are = RogueEventOption(
id=403,
name='Show_it_how_strong_you_are',
cn='让它看看你有多强。',
cht='讓它看看你有多強。',
en='Show it how strong you are.',
jp='強さを見せつける',
es='Demuéstrale lo fuerte que eres.',
)
Can_t_beat_it_Time_to_run = RogueEventOption(
id=404,
name='Can_t_beat_it_Time_to_run',
cn='打不过,溜了溜了。',
cht='打不過,溜了溜了。',
en="Can't beat it. Time to run!",
jp='勝てないから逃げる',
es='Si no puedes con él, sal pitando.',
)
Listen_to_him_speak = RogueEventOption(
id=405,
name='Listen_to_him_speak',
cn='听他说下去。',
cht='聽他說下去。',
en='Listen to him speak.',
jp='彼の話を聞き続ける',
es='Escucha lo que dice.',
)
Leave_after_tasting = RogueEventOption(
id=406,
name='Leave_after_tasting',
cn='试吃后离开。',
cht='試吃後離開。',
en='Leave after tasting.',
jp='試食して立ち去る',
es='Vete después de probarlo.',
)
Is_there_anything_else = RogueEventOption(
id=407,
name='Is_there_anything_else',
cn='还有别的吗?',
cht='還有別的嗎?',
en='Is there anything else?',
jp='まだ他に何かある?',
es='¿Hay algo más?',
)
Take_away_the_sample_testers = RogueEventOption(
id=408,
name='Take_away_the_sample_testers',
cn='带走试吃品。',
cht='帶走試吃品。',
en='Take away the sample testers.',
jp='試食品を持ち帰る',
es='Llévate las muestras.',
)
I_wanna_buy_em_all = RogueEventOption(
id=409,
name='I_wanna_buy_em_all',
cn='我全买了!',
cht='我全買了!',
en="I wanna buy em' all!",
jp='全部もらう!',
es='¡Quiero comprarlos todos!',
)
Stop_his_imperial_worshiping_behavior = RogueEventOption(
id=410,
name='Stop_his_imperial_worshiping_behavior',
cn='制止他的帝国崇拜行为。',
cht='制止他的帝國崇拜行為。',
en='Stop his imperial worshiping behavior.',
jp='帝国を崇拝する彼の行為を止める',
es='Detén su comportamiento de adoración imperialista.',
)
Find_a_excuse_and_leave_this_place = RogueEventOption(
id=411,
name='Find_a_excuse_and_leave_this_place',
cn='找借口离开这里。',
cht='找藉口離開這裡。',
en='Find a excuse and leave this place.',
jp='言い訳を見つけてここを離れる',
es='Encuentra una excusa y deja este lugar.',
)
Pale_gold = RogueEventOption(
id=412,
name='Pale_gold',
cn='淡金色。',
cht='淡金色。',
en='Pale gold.',
jp='淡い金色',
es='Oro pálido.',
)
Blood_red = RogueEventOption(
id=413,
name='Blood_red',
cn='血红色。',
cht='血紅色。',
en='Blood red.',
jp='血のような赤色',
es='Rojo sangre.',
)
Dark_gray = RogueEventOption(
id=414,
name='Dark_gray',
cn='深灰色。',
cht='深灰色。',
en='Dark gray.',
jp='濃い灰色',
es='Gris oscuro.',
)
Remove_the_creation = RogueEventOption(
id=415,
name='Remove_the_creation',
cn='取出造物。',
cht='取出造物。',
en='Remove the creation.',
jp='造物を取り出す',
es='Retira la creación.',
)
Security_Verification_Failed_Leave_for_now = RogueEventOption(
id=416,
name='Security_Verification_Failed_Leave_for_now',
cn='密保验证失败,先离开吧。',
cht='驗證失敗,先離開吧。',
en='Security Verification Failed. Leave for now.',
jp='セキュリティ認証失敗、一旦離れよう',
es='Verificación de seguridad fallida. Vete por ahora.',
)
Device_IX_unit_compound = RogueEventOption(
id=417,
name='Device_IX_unit_compound',
cn='第Ⅸ机关单位大院。',
cht='第Ⅸ機關單位大院。',
en='Device IX unit compound.',
jp='第IX機関の敷地内',
es='Recinto de la unidad Dispositivo IX.',
)
Herta_Space_Station = RogueEventOption(
id=418,
name='Herta_Space_Station',
cn='黑塔空间站。',
cht='黑塔太空站。',
en='Herta Space Station.',
jp='宇宙ステーション「ヘルタ」',
es='Estación Espacial Herta.',
)
Superalloy_concrete = RogueEventOption(
id=419,
name='Superalloy_concrete',
cn='超合金混凝土。',
cht='超合金混凝土。',
en='Superalloy concrete.',
jp='超合金コンクリート',
es='Cemento superaleado.',
)
Homo_sapiens = RogueEventOption(
id=420,
name='Homo_sapiens',
cn='智人。',
cht='智人。',
en='Homo sapiens.',
jp='ホモ・サピエンス',
es='Homo sapiens.',
)
Insect_eating_fungi = RogueEventOption(
id=421,
name='Insect_eating_fungi',
cn='食虫菌毯。',
cht='食蟲菌毯。',
en='Insect-eating fungi.',
jp='食虫微生物マット',
es='Hongos que se alimentan de insectos.',
)
Retrieve_the_bank_card = RogueEventOption(
id=422,
name='Retrieve_the_bank_card',
cn='取走银行卡。',
cht='拿走銀行卡。',
en='Retrieve the bank card.',
jp='キャッシュカードを取る',
es='Recupera la tarjeta de banco.',
)
Withdraw_investment = RogueEventOption(
id=423,
name='Withdraw_investment',
cn='提取本金。',
cht='提取本金。',
en='Withdraw investment.',
jp='元金を引き出す',
es='Retira el efectivo.',
)
Withdraw_interest = RogueEventOption(
id=424,
name='Withdraw_interest',
cn='提取利息。',
cht='提取利息。',
en='Withdraw interest.',
jp='利息を引き出す',
es='Retira los intereses.',
)
Withdraw_knowledge = RogueEventOption(
id=425,
name='Withdraw_knowledge',
cn='提取知识。',
cht='提取知識。',
en='Withdraw knowledge.',
jp='知識を引き出す',
es='Retira el conocimiento.',
)
Withdraw_memories = RogueEventOption(
id=426,
name='Withdraw_memories',
cn='提取记忆。',
cht='提取記憶。',
en='Withdraw memories.',
jp='記憶を引き出す',
es='Retira los recuerdos.',
)
The_extremity_of_a_tomato = RogueEventOption(
id=427,
name='The_extremity_of_a_tomato',
cn='西红柿的末端。',
cht='蕃茄的末端。',
en='The extremity of a tomato.',
jp='トマトのヘタの部分',
es='La extremidad de un tomate.',
)
Press_it = RogueEventOption(
id=428,
name='Press_it',
cn='按下它。',
cht='按下它。',
en='Press it.',
jp='それを押す',
es='Presiona.',
)
Remove_your_hand = RogueEventOption(
id=429,
name='Remove_your_hand',
cn='把手拿开。',
cht='把手拿開。',
en='Remove your hand.',
jp='手を離す',
es='Quita la mano.',
)
You_re_teaching_me_how_to_do_my_job = RogueEventOption(
id=430,
name='You_re_teaching_me_how_to_do_my_job',
cn='你在教我做事?',
cht='你在教我做事?',
en="You're teaching me how to do my job?",
jp='に指図するの?',
es='¿Me estás diciendo cómo hacer mi trabajo?',
)
Be_receptive_to_feedback = RogueEventOption(
id=431,
name='Be_receptive_to_feedback',
cn='要善于听取意见。',
cht='要善於聽取意見。',
en='Be receptive to feedback.',
jp='意見をよく聞くべきだ',
es='Mantente abiert a los comentarios.',
)
I_told_you_to_stop_pressing_the_button = RogueEventOption(
id=432,
name='I_told_you_to_stop_pressing_the_button',
cn='都叫你别按按钮了。',
cht='都叫你別按按鈕了。',
en='I told you to stop pressing the button.',
jp='もうボタンを押すなと言っているのに',
es='Te dije que no presionaras el botón.',
)
Xianzhou_collab_set_meal = RogueEventOption(
id=433,
name='Xianzhou_collab_set_meal',
cn='仙舟联名套餐。',
cht='仙舟聯名套餐。',
en='Xianzhou collab set meal.',
jp='仙舟同盟コラボセット',
es='Menú de colaboración de Xianzhou.',
)
Terrorbird_fruit_stew = RogueEventOption(
id=434,
name='Terrorbird_fruit_stew',
cn='骇鸟水果乱炖。',
cht='駭鳥水果亂燉。',
en='Terrorbird-fruit stew.',
jp='フォルスラコスフルーツのごった煮',
es='Estofado de fruta terrorpájaro.',
)
The_big_data_will_provide_the_answers = RogueEventOption(
id=435,
name='The_big_data_will_provide_the_answers',
cn='大数据会给出答案。',
cht='大資料會給出答案。',
en='The big data will provide the answers.',
jp='ビッグデータが答えを出してくれる',
es='Los macrodatos darán las respuestas.',
)
Awesome_big_W = RogueEventOption(
id=436,
name='Awesome_big_W',
cn='真好,赚到。',
cht='真好,賺到。',
en='Awesome, big W.',
jp='よかった、得した',
es='Genial, una buena ganancia.',
)
Life_support_meal_combo = RogueEventOption(
id=437,
name='Life_support_meal_combo',
cn='生命维持套餐。',
cht='生命維持套餐。',
en='Life support meal combo.',
jp='生命維持セット',
es='Comida de soporte vital.',
)
Challenge_A_sentence_of_ten_words = RogueEventOption(
id=438,
name='Challenge_A_sentence_of_ten_words',
cn='挑战十个字的句子。',
cht='挑戰十個字的句子。',
en='Challenge: A sentence of ten words.',
jp='10文字の文章に挑戦する',
es='Desafío: una frase de diez palabras.',
)
Challenge_Two_short_sentences_of_five_words_each = RogueEventOption(
id=439,
name='Challenge_Two_short_sentences_of_five_words_each',
cn='挑战两个五字短语。',
cht='挑戰兩個五字短語。',
en='Challenge: Two short sentences of five words each.',
jp='5文字の短文2つに挑戦する',
es='Desafío: dos frases cortas de cinco palabras cada una.',
)
Disassemble_the_characters_it_carries = RogueEventOption(
id=440,
name='Disassemble_the_characters_it_carries',
cn='拆散它携带的字符。',
cht='拆散它攜帶的字元。',
en='Disassemble the characters it carries.',
jp='持っている文字をバラバラにする',
es='Desmonta las letras que lleva.',
)
Choose_Pineapple = RogueEventOption(
id=441,
name='Choose_Pineapple',
cn='选择菠萝。',
cht='選擇鳳梨。',
en='Choose Pineapple.',
jp='パイナップルを選ぶ',
es='Elige la piña.',
)
Choose_Bread = RogueEventOption(
id=442,
name='Choose_Bread',
cn='选择面包。',
cht='選擇麵包。',
en='Choose Bread.',
jp='パンを選ぶ',
es='Elige el pan.',
)
Take_a_drink_and_calm_down = RogueEventOption(
id=443,
name='Take_a_drink_and_calm_down',
cn='喝瓶水冷静冷静。',
cht='喝瓶水冷靜一下。',
en='Take a drink and calm down.',
jp='水を飲んで落ち着こう',
es='Tómate una bebida y cálmate.',
)
I_will_not_turn_my_back_on_humanity = RogueEventOption(
id=444,
name='I_will_not_turn_my_back_on_humanity',
cn='我绝不会背叛人类。',
cht='我絕不會背叛人類。',
en='I will not turn my back on humanity.',
jp='絶対に人を裏切ったりしない',
es='Nunca traicionaré a la humanidad.',
)
I_am_the_king_of_trashcans = RogueEventOption(
id=445,
name='I_am_the_king_of_trashcans',
cn='我才是垃圾桶之王!',
cht='我才是垃圾桶之王!',
en='I am the king of trashcans!',
jp='ゴミ箱の王はこのだ!',
es='¡Soy el rey de los cubos de basura!',
)
Reforge_weapon = RogueEventOption(
id=446,
name='Reforge_weapon',
cn='重铸武器。',
cht='重鑄武器。',
en='Reforge weapon.',
jp='武器を鋳造し直す',
es='Vuelve a forjar un arma.',
)
Smelt_weapon = RogueEventOption(
id=447,
name='Smelt_weapon',
cn='熔炼武器。',
cht='熔鍊武器。',
en='Smelt weapon.',
jp='武器を溶解し、製錬する',
es='Funde un arma.',
)
Precision_forge_weapon = RogueEventOption(
id=448,
name='Precision_forge_weapon',
cn='精锻武器。',
cht='精鍛武器。',
en='Precision-forge weapon.',
jp='武器を精密鍛造する',
es='Refina un arma de calidad.',
)
There_something_hidden_in_its_fur = RogueEventOption(
id=449,
name='There_something_hidden_in_its_fur',
cn='有什么藏在毛茸茸里。',
cht='有什麼藏在茸毛裡?',
en="There's something hidden in its fur.",
jp='ふわふわに何かが隠れている',
es='Hay algo oculto en su pelaje.',
)
Reel_in_the_line = RogueEventOption(
id=450,
name='Reel_in_the_line',
cn='收线。',
cht='收線。',
en='Reel in the line.',
jp='引き上げる',
es='Recoge el sedal.',
)
Offer_blood = RogueEventOption(
id=451,
name='Offer_blood',
cn='献上鲜血。',
cht='獻上鮮血。',
en='Offer blood.',
jp='血を捧げる',
es='Ofrece sangre.',
)
Offer_money = RogueEventOption(
id=452,
name='Offer_money',
cn='献上金钱。',
cht='獻上金錢。',
en='Offer money.',
jp='信用ポイントを捧げる',
es='Ofrece dinero.',
)
Offer_the_past = RogueEventOption(
id=453,
name='Offer_the_past',
cn='献上过去。',
cht='獻上過去。',
en='Offer the past.',
jp='過去を捧げる',
es='Ofrece el pasado.',
)
Offer_the_future = RogueEventOption(
id=454,
name='Offer_the_future',
cn='献上未来。',
cht='獻上未來。',
en='Offer the future.',
jp='未来を捧げる',
es='Ofrece el futuro.',
)
I_want_to_get_rich = RogueEventOption(
id=455,
name='I_want_to_get_rich',
cn='我想获得财富。',
cht='我想獲得財富。',
en='I want to get rich.',
jp='富を手に入れたい',
es='Quiero ser millonari.',
)
I_want_to_receive_benedictions = RogueEventOption(
id=456,
name='I_want_to_receive_benedictions',
cn='我想获得恩赐。',
cht='我想獲得恩賜。',
en='I want to receive benedictions.',
jp='恩恵を受けたい',
es='Quiero recibir bendiciones.',
)
I_want_to_touch_upon_the_unknown = RogueEventOption(
id=457,
name='I_want_to_touch_upon_the_unknown',
cn='我想触及未知。',
cht='我想觸及未知。',
en='I want to touch upon the unknown.',
jp='未知に触れたい',
es='Quiero tocar lo desconocido.',
)
I_want_to_obtain_wisdom = RogueEventOption(
id=458,
name='I_want_to_obtain_wisdom',
cn='我想触及智慧。',
cht='我想觸及智慧。',
en='I want to obtain wisdom.',
jp='知恵に触れたい',
es='Quiero sabiduría.',
)
Give_up_on_fishing = RogueEventOption(
id=459,
name='Give_up_on_fishing',
cn='放弃垂钓。',
cht='放棄垂釣。',
en='Give up on fishing.',
jp='釣りを諦める',
es='Deja de pescar.',
)
A_primordial_bloodthirsty_beast = RogueEventOption(
id=460,
name='A_primordial_bloodthirsty_beast',
cn='远古的渴血巨兽。',
cht='遠古的渴血巨獸。',
en='A primordial, bloodthirsty beast.',
jp='血に飢えた古代の巨獣',
es='Una antigua bestia sedienta de sangre.',
)
A_cooking_Lordly_Trashcan = RogueEventOption(
id=461,
name='A_cooking_Lordly_Trashcan',
cn='下厨的王下一桶。',
cht='下廚的王下一桶。',
en='A cooking Lordly Trashcan.',
jp='料理をする王のゴミ箱',
es='Un Cubo de basura señorial cocinillas.',
)
A_game_of_Rock_Paper_Scissors_with_the_calculator = RogueEventOption(
id=462,
name='A_game_of_Rock_Paper_Scissors_with_the_calculator',
cn='计算机的猜拳游戏。',
cht='電腦的猜拳遊戲。',
en='A game of Rock, Paper, Scissors with the calculator.',
jp='コンピュータのじゃんけんゲーム',
es='Una ronda de piedra, papel o tijera de la calculadora.',
)
Last_night_dream = RogueEventOption(
id=463,
name='Last_night_dream',
cn='昨晚的梦。',
cht='昨晚的夢。',
en="Last night's dream.",
jp='昨日の夢',
es='El sueño de anoche.',
)
Pom_Pom_tail = RogueEventOption(
id=464,
name='Pom_Pom_tail',
cn='帕姆的尾巴。',
cht='帕姆的尾巴。',
en="Pom-Pom's tail.",
jp='パムの尻尾',
es='La cola de Pom-Pom.',
)
Himeko_coffee = RogueEventOption(
id=465,
name='Himeko_coffee',
cn='姬子的咖啡。',
cht='姬子的咖啡。',
en="Himeko's coffee.",
jp='姫子のコーヒー',
es='El café de Himeko.',
)
Bounty_Hunter_of_the_Snow_Plains = RogueEventOption(
id=466,
name='Bounty_Hunter_of_the_Snow_Plains',
cn='雪原的赏金猎人。',
cht='雪原的賞金獵人。',
en='Bounty Hunter of the Snow Plains.',
jp='雪原の賞金稼ぎ',
es='Cazarrecompensas de las llanuras nevadas.',
)
An_Aha_Stuffed_Toy_asking_to_be_hit = RogueEventOption(
id=467,
name='An_Aha_Stuffed_Toy_asking_to_be_hit',
cn='欠揍的阿哈玩偶。',
cht='欠揍的阿哈玩偶。',
en='An Aha Stuffed Toy asking to be hit.',
jp='ムカつくアッハ人形',
es='Un muñeco de Aha que quiere que lo golpeen.',
)
The_library_History_Fictionologist = RogueEventOption(
id=468,
name='The_library_History_Fictionologist',
cn='图书馆的虚构史学家。',
cht='圖書館的虛構史學家。',
en="The library's History Fictionologist.",
jp='図書館にいる虚構歴史学者',
es='Los Historiadores Espurios de la biblioteca.',
)
Describe_a_colorful_journey = RogueEventOption(
id=469,
name='Describe_a_colorful_journey',
cn='讲述多彩的旅途。',
cht='講述多彩的旅途。',
en='Describe a colorful journey.',
jp='多彩な旅の話をする',
es='Describe un viaje extravagante.',
)
Describe_a_wondrous_adventure = RogueEventOption(
id=470,
name='Describe_a_wondrous_adventure',
cn='讲述惊奇的冒险。',
cht='講述驚奇的冒險。',
en='Describe a wondrous adventure.',
jp='不思議な冒険の話をする',
es='Describe una aventura maravillosa.',
)
Describe_a_simple_life = RogueEventOption(
id=471,
name='Describe_a_simple_life',
cn='讲述朴实的生活。',
cht='講述樸實的生活。',
en='Describe a simple life.',
jp='素朴な生活の話をする',
es='Describe una vida simple.',
)
Recount_your_empty_past = RogueEventOption(
id=472,
name='Recount_your_empty_past',
cn='讲述空白的过往。',
cht='講述空白的過往。',
en='Recount your empty past.',
jp='空っぽな過去を語る',
es='Describe tu vacío pasado.',
)
Chasing_excitement = RogueEventOption(
id=473,
name='Chasing_excitement',
cn='玩的就是一个刺激。',
cht='越刺激就會越好玩。',
en='Chasing excitement.',
jp='エキサイティングであればあるほどいい',
es='Divertirse es emocionante.',
)
Consider_it_as_helping_out_the_Guild_business = RogueEventOption(
id=474,
name='Consider_it_as_helping_out_the_Guild_business',
cn='就当照顾学会的生意。',
cht='就當關照學會的生意。',
en="Consider it as helping out the Guild's business.",
jp='学会のビジネスを贔屓するってことで',
es='Considéralo como un apoyo a los negocios de la Sociedad.',
)

View File

@ -1383,3 +1383,173 @@ Ruan_Mei_III = RogueEventTitle(
es='Ruan Mei III',
option_ids=[392, 393, 394],
)
Special_Discount = RogueEventTitle(
id=139,
name='Special_Discount',
cn='特别优惠',
cht='特別優惠',
en='Special Discount',
jp='特別割引',
es='Descuento especial',
option_ids=[395, 396, 397, 398, 399, 400, 401, 402, 403, 404],
)
Metal_Life = RogueEventTitle(
id=140,
name='Metal_Life',
cn='金属生活',
cht='金屬生活',
en='Metal Life',
jp='金属生活',
es='Vida metálica',
option_ids=[405, 406, 407, 408, 409, 410, 411],
)
A_Dash_of_Color = RogueEventTitle(
id=141,
name='A_Dash_of_Color',
cn='一抹色彩',
cht='一抹色彩',
en='A Dash of Color',
jp='一抹の色彩',
es='Una pizca de color',
option_ids=[412, 413, 414],
)
Creation_Unit = RogueEventTitle(
id=142,
name='Creation_Unit',
cn='造物单元',
cht='造物單元',
en='Creation Unit',
jp='造物ユニット',
es='Unidad de creación',
option_ids=[415],
)
Time_Bank_I = RogueEventTitle(
id=143,
name='Time_Bank_I',
cn='时间银行(其一)',
cht='時間銀行(其一)',
en='Time Bank (I)',
jp='タイムバンクその1',
es='Banco del tiempo (I)',
option_ids=[416, 417, 418, 419, 420, 421, 422, 423, 424, 425, 426, 427],
)
Time_Bank_II = RogueEventTitle(
id=144,
name='Time_Bank_II',
cn='时间银行(其二)',
cht='時間銀行(其二)',
en='Time Bank (II)',
jp='タイムバンクその2',
es='Banco del tiempo (II)',
option_ids=[426, 427],
)
Red_Temptation = RogueEventTitle(
id=145,
name='Red_Temptation',
cn='红色诱惑',
cht='紅色誘惑',
en='Red Temptation',
jp='赤い誘惑',
es='Tentación roja',
option_ids=[428, 429, 430, 431, 432],
)
Selection_Difficulties_I = RogueEventTitle(
id=146,
name='Selection_Difficulties_I',
cn='选择困难(其一)',
cht='選擇困難(其一)',
en='Selection Difficulties (I)',
jp='選択困難その1',
es='Dificultad de elección (I)',
option_ids=[433, 434, 435, 436, 437],
)
Selection_Difficulties_II = RogueEventTitle(
id=147,
name='Selection_Difficulties_II',
cn='选择困难(其二)',
cht='選擇困難(其二)',
en='Selection Difficulties (II)',
jp='選択困難その2',
es='Dificultad de elección (II)',
option_ids=[434, 435, 436, 437],
)
Semantic_Mismatch = RogueEventTitle(
id=148,
name='Semantic_Mismatch',
cn='语义不符',
cht='語義不符',
en='Semantic Mismatch',
jp='本義の不一致',
es='Inconsistencia semántica',
option_ids=[438, 439, 440],
)
Pineapple_Bread = RogueEventTitle(
id=149,
name='Pineapple_Bread',
cn='菠萝面包',
cht='鳳梨麵包',
en='Pineapple Bread',
jp='パイナップルパン',
es='Pan de piña',
option_ids=[441, 442, 443],
)
Trash_Symphony = RogueEventTitle(
id=150,
name='Trash_Symphony',
cn='垃圾交响曲',
cht='垃圾交響曲',
en='Trash Symphony',
jp='トラッシュシンフォニー',
es='Sinfonía de la basura',
option_ids=[444, 445],
)
Lava = RogueEventTitle(
id=151,
name='Lava',
cn='熔岩',
cht='熔岩',
en='Lava',
jp='溶岩',
es='Lava',
option_ids=[446, 447, 448],
)
Apes_Such_As_You = RogueEventTitle(
id=152,
name='Apes_Such_As_You',
cn='像你这样的苍猿',
cht='像你這樣的蒼猿',
en='Apes Such As You',
jp='あなたのような蒼猿は',
es='Simios como tú',
option_ids=[449],
)
Fishing_Ceremony = RogueEventTitle(
id=153,
name='Fishing_Ceremony',
cn='垂钓仪式',
cht='垂釣儀式',
en='Fishing Ceremony',
jp='釣りの儀式',
es='Ceremonia de pesca',
option_ids=[450, 451, 452, 453, 454, 455, 456, 457, 458, 459],
)
Flea_Market = RogueEventTitle(
id=154,
name='Flea_Market',
cn='跳蚤市场',
cht='跳蚤市場',
en='Flea Market',
jp='蚤の市',
es='Mercadillo',
option_ids=[460, 461, 462, 463, 464, 465, 466, 467, 468, 469, 470, 471, 472],
)
Collab_Product = RogueEventTitle(
id=155,
name='Collab_Product',
cn='联名产品',
cht='聯名產品',
en='Collab Product',
jp='コラボ商品',
es='Producto de colaboración',
option_ids=[5, 473, 474],
)