From ce7d971485d21787019893f5ef09656eedc78efb Mon Sep 17 00:00:00 2001 From: LmeSzinc <37934724+LmeSzinc@users.noreply.github.com> Date: Tue, 10 Sep 2024 00:23:40 +0800 Subject: [PATCH 1/7] Fix: [ALAS] Limit pool size when using run_in_executor() (cherry picked from commit e1bb483aaafa293a14e2faec7c9baadb236e1a01) --- module/device/connection.py | 9 ++++++++- module/device/method/nemu_ipc.py | 16 +++++++++++++++- 2 files changed, 23 insertions(+), 2 deletions(-) diff --git a/module/device/connection.py b/module/device/connection.py index 59c64e9b4..bd88548e4 100644 --- a/module/device/connection.py +++ b/module/device/connection.py @@ -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): diff --git a/module/device/method/nemu_ipc.py b/module/device/method/nemu_ipc.py index cdb159f48..0fde50d51 100644 --- a/module/device/method/nemu_ipc.py +++ b/module/device/method/nemu_ipc.py @@ -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): From 0ef39164ee3d1594cdac3d1cae886923117dc269 Mon Sep 17 00:00:00 2001 From: LmeSzinc <37934724+LmeSzinc@users.noreply.github.com> Date: Tue, 10 Sep 2024 16:08:07 +0800 Subject: [PATCH 2/7] Upd: Keywords in 2.5 --- config/template.json | 3 + dev_tools/keywords/dungeon_list.py | 12 + module/config/argument/args.json | 33 +- module/config/argument/stored.json | 33 + module/config/config_generated.py | 11 +- module/config/i18n/en-US.json | 71 +- module/config/i18n/es-ES.json | 61 +- module/config/i18n/ja-JP.json | 111 ++-- module/config/i18n/zh-CN.json | 111 ++-- module/config/i18n/zh-TW.json | 111 ++-- module/config/stored/stored_generated.py | 3 + module/config/utils.py | 188 ++++-- tasks/character/keywords/character_list.py | 111 ++-- tasks/dungeon/keywords/dungeon.py | 670 ++++++++++--------- tasks/dungeon/keywords/dungeon_detailed.py | 28 +- tasks/map/keywords/plane.py | 31 +- tasks/planner/keywords/item_ascension.py | 28 +- tasks/planner/keywords/item_weekly.py | 13 + tasks/rogue/event/preset.py | 4 +- tasks/rogue/keywords/bonus.py | 78 ++- tasks/rogue/keywords/event_option.py | 738 ++++++++++++++++++++- tasks/rogue/keywords/event_title.py | 170 +++++ 22 files changed, 1976 insertions(+), 643 deletions(-) diff --git a/config/template.json b/config/template.json index 393ec9360..83476d5ab 100644 --- a/config/template.json +++ b/config/template.json @@ -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": {}, diff --git a/dev_tools/keywords/dungeon_list.py b/dev_tools/keywords/dungeon_list.py index 658ef4bdf..f9f67a902 100644 --- a/dev_tools/keywords/dungeon_list.py +++ b/dev_tools/keywords/dungeon_list.py @@ -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,6 +116,12 @@ class GenerateDungeonList(GenerateKeyword): dungeons = [d for d in dungeons if not condition(d)] dungeons = calyx + dungeons + # 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 Divergent_Universe start = 0 end = 0 diff --git a/module/config/argument/args.json b/module/config/argument/args.json index 120a5c862..7cfb52a5e 100644 --- a/module/config/argument/args.json +++ b/module/config/argument/args.json @@ -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", @@ -677,12 +698,14 @@ "JingYuan", "Jingliu", "Kafka", + "Lingsha", "Luka", "Luocha", "Lynx", "March7thPreservation", "March7thTheHunt", "Misha", + "Moze", "Natasha", "Pela", "Qingque", @@ -795,6 +818,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 +882,7 @@ "DanHeng", "DanHengImbibitorLunae", "DrRatio", + "Feixiao", "Firefly", "FuXuan", "Gallagher", @@ -873,12 +898,14 @@ "JingYuan", "Jingliu", "Kafka", + "Lingsha", "Luka", "Luocha", "Lynx", "March7thPreservation", "March7thTheHunt", "Misha", + "Moze", "Natasha", "Pela", "Qingque", @@ -1345,7 +1372,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 +1420,7 @@ "DanHeng", "DanHengImbibitorLunae", "DrRatio", + "Feixiao", "Firefly", "FuXuan", "Gallagher", @@ -1407,12 +1436,14 @@ "JingYuan", "Jingliu", "Kafka", + "Lingsha", "Luka", "Luocha", "Lynx", "March7thPreservation", "March7thTheHunt", "Misha", + "Moze", "Natasha", "Pela", "Qingque", diff --git a/module/config/argument/stored.json b/module/config/argument/stored.json index 33511775d..060c4cb1a 100644 --- a/module/config/argument/stored.json +++ b/module/config/argument/stored.json @@ -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", diff --git a/module/config/config_generated.py b/module/config/config_generated.py index e6a45728f..4969ea5d5 100644 --- a/module/config/config_generated.py +++ b/module/config/config_generated.py @@ -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, Lingsha, 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 diff --git a/module/config/i18n/en-US.json b/module/config/i18n/en-US.json index 95253347d..b33349a42 100644 --- a/module/config/i18n/en-US.json +++ b/module/config/i18n/en-US.json @@ -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", @@ -408,12 +411,14 @@ "JingYuan": "Jing Yuan", "Jingliu": "Jingliu", "Kafka": "Kafka", + "Lingsha": "Lingsha", "Luka": "Luka", "Luocha": "Luocha", "Lynx": "Lynx", "March7thPreservation": "March 7th: Preservation", "March7thTheHunt": "March 7th: The Hunt", "Misha": "Misha", + "Moze": "Moze", "Natasha": "Natasha", "Pela": "Pela", "Qingque": "Qingque", @@ -567,13 +572,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 +671,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 +720,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 +951,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 +1065,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)", diff --git a/module/config/i18n/es-ES.json b/module/config/i18n/es-ES.json index 7170aceb6..f3581312f 100644 --- a/module/config/i18n/es-ES.json +++ b/module/config/i18n/es-ES.json @@ -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", @@ -408,12 +411,14 @@ "JingYuan": "Jing Yuan", "Jingliu": "Jingliu", "Kafka": "Kafka", + "Lingsha": "Lingsha", "Luka": "Luka", "Luocha": "Luocha", "Lynx": "Lynx", "March7thPreservation": "Siete de Marzo: Conservación", "March7thTheHunt": "Siete de Marzo: Cacería", "Misha": "Misha", + "Moze": "Moze", "Natasha": "Natasha", "Pela": "Pela", "Qingque": "Qingque", @@ -567,13 +572,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 +671,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 +720,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 +1065,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)", diff --git a/module/config/i18n/ja-JP.json b/module/config/i18n/ja-JP.json index d95edbcc6..157858c18 100644 --- a/module/config/i18n/ja-JP.json +++ b/module/config/i18n/ja-JP.json @@ -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": "ギャラガー", @@ -408,12 +411,14 @@ "JingYuan": "景元", "Jingliu": "鏡流", "Kafka": "カフカ", + "Lingsha": "霊砂", "Luka": "ルカ", "Luocha": "羅刹", "Lynx": "リンクス", "March7thPreservation": "三月なのか・存護", "March7thTheHunt": "三月なのか・巡狩", "Misha": "ミーシャ", + "Moze": "モゼ", "Natasha": "ナターシャ", "Pela": "ペラ", "Qingque": "青雀", @@ -567,13 +572,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 +671,10 @@ "name": "歴戦余韻・現世の夢の礼賛 (ピノコニー)", "help": "" }, + "Item_Auspice_Sliver": { + "name": "歴戦余韻・心獣の戦場 (仙舟「羅浮」)", + "help": "" + }, "Item_Squirming_Core": { "name": "脈動する原核", "help": "" @@ -703,7 +720,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 +951,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 +1065,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": "(剣の雨)", diff --git a/module/config/i18n/zh-CN.json b/module/config/i18n/zh-CN.json index e52a9b40d..24bebf6cd 100644 --- a/module/config/i18n/zh-CN.json +++ b/module/config/i18n/zh-CN.json @@ -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": "加拉赫", @@ -408,12 +411,14 @@ "JingYuan": "景元", "Jingliu": "镜流", "Kafka": "卡芙卡", + "Lingsha": "灵砂", "Luka": "卢卡", "Luocha": "罗刹", "Lynx": "玲可", "March7thPreservation": "三月七•存护", "March7thTheHunt": "三月七•巡猎", "Misha": "米沙", + "Moze": "貊泽", "Natasha": "娜塔莎", "Pela": "佩拉", "Qingque": "青雀", @@ -567,13 +572,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 +671,10 @@ "name": "尘梦的赞礼•历战余响 (匹诺康尼)", "help": "" }, + "Item_Auspice_Sliver": { + "name": "心兽的战场•历战余响 (仙舟「罗浮」)", + "help": "" + }, "Item_Squirming_Core": { "name": "蠢动原核", "help": "" @@ -703,7 +720,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 +951,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 +1065,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": "苍穹+匹诺康尼(天剑如雨)", diff --git a/module/config/i18n/zh-TW.json b/module/config/i18n/zh-TW.json index 3965da095..d9581a686 100644 --- a/module/config/i18n/zh-TW.json +++ b/module/config/i18n/zh-TW.json @@ -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": "加拉赫", @@ -408,12 +411,14 @@ "JingYuan": "景元", "Jingliu": "鏡流", "Kafka": "卡芙卡", + "Lingsha": "靈砂", "Luka": "盧卡", "Luocha": "羅剎", "Lynx": "玲可", "March7thPreservation": "三月七•存護", "March7thTheHunt": "三月七•巡獵", "Misha": "米沙", + "Moze": "貊澤", "Natasha": "娜塔莎", "Pela": "佩拉", "Qingque": "青雀", @@ -567,13 +572,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 +671,10 @@ "name": "塵夢的讚禮•歷戰餘響 (匹諾康尼)", "help": "" }, + "Item_Auspice_Sliver": { + "name": "心獸的戰場•歷戰餘響 (仙舟「羅浮」)", + "help": "" + }, "Item_Squirming_Core": { "name": "蠢動原核", "help": "" @@ -703,7 +720,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 +951,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 +1065,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": "天空+匹諾康尼(天劍如雨)", diff --git a/module/config/stored/stored_generated.py b/module/config/stored/stored_generated.py index 7a4c52f93..47900dae0 100644 --- a/module/config/stored/stored_generated.py +++ b/module/config/stored/stored_generated.py @@ -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") diff --git a/module/config/utils.py b/module/config/utils.py index af05bb18d..cb61a028b 100644 --- a/module/config/utils.py +++ b/module/config/utils.py @@ -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): - d = {} - d[keys[0]] = deep_set(d.get(keys[0], {}), keys[1:], value) - return d + + 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 = {} + 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 - else: - yield [], data + 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 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): diff --git a/tasks/character/keywords/character_list.py b/tasks/character/keywords/character_list.py index 269c219dd..84793a534 100644 --- a/tasks/character/keywords/character_list.py +++ b/tasks/character/keywords/character_list.py @@ -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='雲璃', diff --git a/tasks/dungeon/keywords/dungeon.py b/tasks/dungeon/keywords/dungeon.py index 90c4c95f9..48e14fa7e 100644 --- a/tasks/dungeon/keywords/dungeon.py +++ b/tasks/dungeon/keywords/dungeon.py @@ -6,109 +6,109 @@ from .classes import DungeonList Calyx_Golden_Memories_Jarilo_VI = DungeonList( id=1, name='Calyx_Golden_Memories_Jarilo_VI', - cn='回忆之蕾•雅利洛-Ⅵ', - cht='回憶之蕾•雅利洛-Ⅵ', - en='Bud of Memories (Jarilo-Ⅵ)', - jp='回憶の蕾・ヤリーロ-Ⅵ', - es='Flor de los recuerdos (Jarilo-Ⅵ)', + cn='回忆之蕾', + cht='回憶之蕾', + en='Bud of Memories', + jp='回憶の蕾', + es='Flor de los recuerdos', dungeon_id=1001, plane_id=2010101, ) Calyx_Golden_Aether_Jarilo_VI = DungeonList( id=2, name='Calyx_Golden_Aether_Jarilo_VI', - cn='以太之蕾•雅利洛-Ⅵ', - cht='乙太之蕾•雅利洛-Ⅵ', - en='Bud of Aether (Jarilo-Ⅵ)', - jp='エーテルの蕾・ヤリーロ-Ⅵ', - es='Flor de éter (Jarilo-Ⅵ)', + cn='以太之蕾', + cht='乙太之蕾', + en='Bud of Aether', + jp='エーテルの蕾', + es='Flor de éter', dungeon_id=1002, plane_id=2011101, ) Calyx_Golden_Treasures_Jarilo_VI = DungeonList( id=3, name='Calyx_Golden_Treasures_Jarilo_VI', - cn='藏珍之蕾•雅利洛-Ⅵ', - cht='藏珍之蕾•雅利洛-Ⅵ', - en='Bud of Treasures (Jarilo-Ⅵ)', - jp='秘蔵の蕾・ヤリーロ-Ⅵ', - es='Flor de tesoros (Jarilo-Ⅵ)', + cn='藏珍之蕾', + cht='藏珍之蕾', + en='Bud of Treasures', + jp='秘蔵の蕾', + es='Flor de tesoros', dungeon_id=1003, plane_id=2012101, ) Calyx_Golden_Memories_The_Xianzhou_Luofu = DungeonList( id=4, name='Calyx_Golden_Memories_The_Xianzhou_Luofu', - cn='回忆之蕾•仙舟「罗浮」', - cht='回憶之蕾•仙舟「羅浮」', - en='Bud of Memories (The Xianzhou Luofu)', - jp='回憶の蕾・仙舟「羅浮」', - es='Flor de los recuerdos (El Luofu de Xianzhou)', + cn='回忆之蕾', + cht='回憶之蕾', + en='Bud of Memories', + jp='回憶の蕾', + es='Flor de los recuerdos', dungeon_id=1011, plane_id=2021101, ) Calyx_Golden_Aether_The_Xianzhou_Luofu = DungeonList( id=5, name='Calyx_Golden_Aether_The_Xianzhou_Luofu', - cn='以太之蕾•仙舟「罗浮」', - cht='乙太之蕾•仙舟「羅浮」', - en='Bud of Aether (The Xianzhou Luofu)', - jp='エーテルの蕾・仙舟「羅浮」', - es='Flor de éter (El Luofu de Xianzhou)', + cn='以太之蕾', + cht='乙太之蕾', + en='Bud of Aether', + jp='エーテルの蕾', + es='Flor de éter', dungeon_id=1012, plane_id=2022101, ) Calyx_Golden_Treasures_The_Xianzhou_Luofu = DungeonList( id=6, name='Calyx_Golden_Treasures_The_Xianzhou_Luofu', - cn='藏珍之蕾•仙舟「罗浮」', - cht='藏珍之蕾•仙舟「羅浮」', - en='Bud of Treasures (The Xianzhou Luofu)', - jp='秘蔵の蕾・仙舟「羅浮」', - es='Flor de tesoros (El Luofu de Xianzhou)', + cn='藏珍之蕾', + cht='藏珍之蕾', + en='Bud of Treasures', + jp='秘蔵の蕾', + es='Flor de tesoros', dungeon_id=1013, plane_id=2022201, ) Calyx_Golden_Memories_Penacony = DungeonList( id=7, name='Calyx_Golden_Memories_Penacony', - cn='回忆之蕾•匹诺康尼', - cht='回憶之蕾•匹諾康尼', - en='Bud of Memories (Penacony)', - jp='回憶の蕾・ピノコニー', - es='Flor de los recuerdos (Colonipenal)', + cn='回忆之蕾', + cht='回憶之蕾', + en='Bud of Memories', + jp='回憶の蕾', + es='Flor de los recuerdos', dungeon_id=1014, plane_id=2031301, ) Calyx_Golden_Aether_Penacony = DungeonList( id=8, name='Calyx_Golden_Aether_Penacony', - cn='以太之蕾•匹诺康尼', - cht='乙太之蕾•匹諾康尼', - en='Bud of Aether (Penacony)', - jp='エーテルの蕾・ピノコニー', - es='Flor de éter (Colonipenal)', + cn='以太之蕾', + cht='乙太之蕾', + en='Bud of Aether', + jp='エーテルの蕾', + es='Flor de éter', dungeon_id=1015, plane_id=2031201, ) Calyx_Golden_Treasures_Penacony = DungeonList( id=9, name='Calyx_Golden_Treasures_Penacony', - cn='藏珍之蕾•匹诺康尼', - cht='藏珍之蕾•匹諾康尼', - en='Bud of Treasures (Penacony)', - jp='秘蔵の蕾・ピノコニー', - es='Flor de tesoros (Colonipenal)', + cn='藏珍之蕾', + cht='藏珍之蕾', + en='Bud of Treasures', + jp='秘蔵の蕾', + es='Flor de tesoros', dungeon_id=1016, plane_id=2031101, ) Calyx_Crimson_Destruction_Herta_StorageZone = DungeonList( id=10, name='Calyx_Crimson_Destruction_Herta_StorageZone', - cn='毁灭之蕾•拟造花萼(赤)', - cht='毀滅之蕾•擬造花萼(赤)', - en='Calyx (Crimson): Bud of Destruction', - jp='疑似花萼(赤)・壊滅の蕾', + cn='毁灭之蕾', + cht='毀滅之蕾', + en='Bud of Destruction', + jp='壊滅の蕾', es='Flor de la Destrucción', dungeon_id=1004, plane_id=2000201, @@ -116,10 +116,10 @@ Calyx_Crimson_Destruction_Herta_StorageZone = DungeonList( Calyx_Crimson_Destruction_Luofu_ScalegorgeWaterscape = DungeonList( id=11, name='Calyx_Crimson_Destruction_Luofu_ScalegorgeWaterscape', - cn='毁灭之蕾•拟造花萼(赤)', - cht='毀滅之蕾•擬造花萼(赤)', - en='Calyx (Crimson): Bud of Destruction', - jp='疑似花萼(赤)・壊滅の蕾', + cn='毁灭之蕾', + cht='毀滅之蕾', + en='Bud of Destruction', + jp='壊滅の蕾', es='Flor de la Destrucción', dungeon_id=1018, plane_id=2023201, @@ -127,10 +127,10 @@ Calyx_Crimson_Destruction_Luofu_ScalegorgeWaterscape = DungeonList( Calyx_Crimson_Preservation_Herta_SupplyZone = DungeonList( id=12, name='Calyx_Crimson_Preservation_Herta_SupplyZone', - cn='存护之蕾•拟造花萼(赤)', - cht='存護之蕾•擬造花萼(赤)', - en='Calyx (Crimson): Bud of Preservation', - jp='疑似花萼(赤)・存護の蕾', + cn='存护之蕾', + cht='存護之蕾', + en='Bud of Preservation', + jp='存護の蕾', es='Flor de la Conservación', dungeon_id=1005, plane_id=2000301, @@ -138,10 +138,10 @@ Calyx_Crimson_Preservation_Herta_SupplyZone = DungeonList( Calyx_Crimson_Preservation_Penacony_ClockStudiosThemePark = DungeonList( id=13, name='Calyx_Crimson_Preservation_Penacony_ClockStudiosThemePark', - cn='存护之蕾•拟造花萼(赤)', - cht='存護之蕾•擬造花萼(赤)', - en='Calyx (Crimson): Bud of Preservation', - jp='疑似花萼(赤)・存護の蕾', + cn='存护之蕾', + cht='存護之蕾', + en='Bud of Preservation', + jp='存護の蕾', es='Flor de la Conservación', dungeon_id=1020, plane_id=2032101, @@ -149,10 +149,10 @@ Calyx_Crimson_Preservation_Penacony_ClockStudiosThemePark = DungeonList( Calyx_Crimson_The_Hunt_Jarilo_OutlyingSnowPlains = DungeonList( id=14, name='Calyx_Crimson_The_Hunt_Jarilo_OutlyingSnowPlains', - cn='巡猎之蕾•拟造花萼(赤)', - cht='巡獵之蕾•擬造花萼(赤)', - en='Calyx (Crimson): Bud of The Hunt', - jp='疑似花萼(赤)・巡狩の蕾', + cn='巡猎之蕾', + cht='巡獵之蕾', + en='Bud of The Hunt', + jp='巡狩の蕾', es='Flor de la Cacería', dungeon_id=1006, plane_id=2010101, @@ -160,10 +160,10 @@ Calyx_Crimson_The_Hunt_Jarilo_OutlyingSnowPlains = DungeonList( Calyx_Crimson_The_Hunt_Penacony_SoulGladScorchsandAuditionVenue = DungeonList( id=15, name='Calyx_Crimson_The_Hunt_Penacony_SoulGladScorchsandAuditionVenue', - cn='巡猎之蕾•拟造花萼(赤)', - cht='巡獵之蕾•擬造花萼(赤)', - en='Calyx (Crimson): Bud of The Hunt', - jp='疑似花萼(赤)・巡狩の蕾', + cn='巡猎之蕾', + cht='巡獵之蕾', + en='Bud of The Hunt', + jp='巡狩の蕾', es='Flor de la Cacería', dungeon_id=1022, plane_id=2033101, @@ -171,10 +171,10 @@ Calyx_Crimson_The_Hunt_Penacony_SoulGladScorchsandAuditionVenue = DungeonList( Calyx_Crimson_Abundance_Jarilo_BackwaterPass = DungeonList( id=16, name='Calyx_Crimson_Abundance_Jarilo_BackwaterPass', - cn='丰饶之蕾•拟造花萼(赤)', - cht='豐饒之蕾•擬造花萼(赤)', - en='Calyx (Crimson): Bud of Abundance', - jp='疑似花萼(赤)・豊穣の蕾', + cn='丰饶之蕾', + cht='豐饒之蕾', + en='Bud of Abundance', + jp='豊穣の蕾', es='Flor de la Abundancia', dungeon_id=1007, plane_id=2011101, @@ -182,10 +182,10 @@ Calyx_Crimson_Abundance_Jarilo_BackwaterPass = DungeonList( Calyx_Crimson_Abundance_Luofu_FyxestrollGarden = DungeonList( id=17, name='Calyx_Crimson_Abundance_Luofu_FyxestrollGarden', - cn='丰饶之蕾•拟造花萼(赤)', - cht='豐饒之蕾•擬造花萼(赤)', - en='Calyx (Crimson): Bud of Abundance', - jp='疑似花萼(赤)・豊穣の蕾', + cn='丰饶之蕾', + cht='豐饒之蕾', + en='Bud of Abundance', + jp='豊穣の蕾', es='Flor de la Abundancia', dungeon_id=1021, plane_id=2022301, @@ -193,10 +193,10 @@ Calyx_Crimson_Abundance_Luofu_FyxestrollGarden = DungeonList( Calyx_Crimson_Erudition_Jarilo_RivetTown = DungeonList( id=18, name='Calyx_Crimson_Erudition_Jarilo_RivetTown', - cn='智识之蕾•拟造花萼(赤)', - cht='智識之蕾•擬造花萼(赤)', - en='Calyx (Crimson): Bud of Erudition', - jp='疑似花萼(赤)・知恵の蕾', + cn='智识之蕾', + cht='智識之蕾', + en='Bud of Erudition', + jp='知恵の蕾', es='Flor de la Erudición', dungeon_id=1008, plane_id=2012201, @@ -204,10 +204,10 @@ Calyx_Crimson_Erudition_Jarilo_RivetTown = DungeonList( Calyx_Crimson_Erudition_Penacony_PenaconyGrandTheater = DungeonList( id=19, name='Calyx_Crimson_Erudition_Penacony_PenaconyGrandTheater', - cn='智识之蕾•拟造花萼(赤)', - cht='智識之蕾•擬造花萼(赤)', - en='Calyx (Crimson): Bud of Erudition', - jp='疑似花萼(赤)・知恵の蕾', + cn='智识之蕾', + cht='智識之蕾', + en='Bud of Erudition', + jp='知恵の蕾', es='Flor de la Erudición', dungeon_id=1023, plane_id=2033201, @@ -215,10 +215,10 @@ Calyx_Crimson_Erudition_Penacony_PenaconyGrandTheater = DungeonList( Calyx_Crimson_Harmony_Jarilo_RobotSettlement = DungeonList( id=20, name='Calyx_Crimson_Harmony_Jarilo_RobotSettlement', - cn='同谐之蕾•拟造花萼(赤)', - cht='同諧之蕾•擬造花萼(赤)', - en='Calyx (Crimson): Bud of Harmony', - jp='疑似花萼(赤)・調和の蕾', + cn='同谐之蕾', + cht='同諧之蕾', + en='Bud of Harmony', + jp='調和の蕾', es='Flor de la Armonía', dungeon_id=1009, plane_id=2012301, @@ -226,10 +226,10 @@ Calyx_Crimson_Harmony_Jarilo_RobotSettlement = DungeonList( Calyx_Crimson_Harmony_Penacony_TheReverieDreamscape = DungeonList( id=21, name='Calyx_Crimson_Harmony_Penacony_TheReverieDreamscape', - cn='同谐之蕾•拟造花萼(赤)', - cht='同諧之蕾•擬造花萼(赤)', - en='Calyx (Crimson): Bud of Harmony', - jp='疑似花萼(赤)・調和の蕾', + cn='同谐之蕾', + cht='同諧之蕾', + en='Bud of Harmony', + jp='調和の蕾', es='Flor de la Armonía', dungeon_id=1019, plane_id=2031101, @@ -237,10 +237,10 @@ Calyx_Crimson_Harmony_Penacony_TheReverieDreamscape = DungeonList( Calyx_Crimson_Nihility_Jarilo_GreatMine = DungeonList( id=22, name='Calyx_Crimson_Nihility_Jarilo_GreatMine', - cn='虚无之蕾•拟造花萼(赤)', - cht='虛無之蕾•擬造花萼(赤)', - en='Calyx (Crimson): Bud of Nihility', - jp='疑似花萼(赤)・虚無の蕾', + cn='虚无之蕾', + cht='虛無之蕾', + en='Bud of Nihility', + jp='虚無の蕾', es='Flor de la Nihilidad', dungeon_id=1010, plane_id=2012101, @@ -248,10 +248,10 @@ Calyx_Crimson_Nihility_Jarilo_GreatMine = DungeonList( Calyx_Crimson_Nihility_Luofu_AlchemyCommission = DungeonList( id=23, name='Calyx_Crimson_Nihility_Luofu_AlchemyCommission', - cn='虚无之蕾•拟造花萼(赤)', - cht='虛無之蕾•擬造花萼(赤)', - en='Calyx (Crimson): Bud of Nihility', - jp='疑似花萼(赤)・虚無の蕾', + cn='虚无之蕾', + cht='虛無之蕾', + en='Bud of Nihility', + jp='虚無の蕾', es='Flor de la Nihilidad', dungeon_id=1017, plane_id=2023101, @@ -259,10 +259,10 @@ Calyx_Crimson_Nihility_Luofu_AlchemyCommission = DungeonList( Stagnant_Shadow_Quanta = DungeonList( id=24, name='Stagnant_Shadow_Quanta', - cn='空海之形•凝滞虚影', - cht='空海之形•凝滯虛影', - en='Stagnant Shadow: Shape of Quanta', - jp='凝結虚影・虚海の形', + cn='空海之形', + cht='空海之形', + en='Shape of Quanta', + jp='虚海の形', es='Forma del cuanto', dungeon_id=1101, plane_id=2000101, @@ -270,10 +270,10 @@ Stagnant_Shadow_Quanta = DungeonList( Stagnant_Shadow_Gust = DungeonList( id=25, name='Stagnant_Shadow_Gust', - cn='巽风之形•凝滞虚影', - cht='巽風之形•凝滯虛影', - en='Stagnant Shadow: Shape of Gust', - jp='凝結虚影・薫風の形', + cn='巽风之形', + cht='巽風之形', + en='Shape of Gust', + jp='薫風の形', es='Forma del aire', dungeon_id=1102, plane_id=2012201, @@ -281,10 +281,10 @@ Stagnant_Shadow_Gust = DungeonList( Stagnant_Shadow_Fulmination = DungeonList( id=26, name='Stagnant_Shadow_Fulmination', - cn='鸣雷之形•凝滞虚影', - cht='鳴雷之形•凝滯虛影', - en='Stagnant Shadow: Shape of Fulmination', - jp='凝結虚影・鳴雷の形', + cn='鸣雷之形', + cht='鳴雷之形', + en='Shape of Fulmination', + jp='鳴雷の形', es='Forma del trueno', dungeon_id=1103, plane_id=2013201, @@ -292,10 +292,10 @@ Stagnant_Shadow_Fulmination = DungeonList( Stagnant_Shadow_Blaze = DungeonList( id=27, name='Stagnant_Shadow_Blaze', - cn='炎华之形•凝滞虚影', - cht='炎華之形•凝滯虛影', - en='Stagnant Shadow: Shape of Blaze', - jp='凝結虚影・炎華の形', + cn='炎华之形', + cht='炎華之形', + en='Shape of Blaze', + jp='炎華の形', es='Forma de las llamas', dungeon_id=1104, plane_id=2013101, @@ -303,10 +303,10 @@ Stagnant_Shadow_Blaze = DungeonList( Stagnant_Shadow_Spike = DungeonList( id=28, name='Stagnant_Shadow_Spike', - cn='锋芒之形•凝滞虚影', - cht='鋒芒之形•凝滯虛影', - en='Stagnant Shadow: Shape of Spike', - jp='凝結虚影・切先の形', + cn='锋芒之形', + cht='鋒芒之形', + en='Shape of Spike', + jp='切先の形', es='Forma afilada', dungeon_id=1105, plane_id=2012101, @@ -314,10 +314,10 @@ Stagnant_Shadow_Spike = DungeonList( Stagnant_Shadow_Rime = DungeonList( id=29, name='Stagnant_Shadow_Rime', - cn='霜晶之形•凝滞虚影', - cht='霜晶之形•凝滯虛影', - en='Stagnant Shadow: Shape of Rime', - jp='凝結虚影・霜晶の形', + cn='霜晶之形', + cht='霜晶之形', + en='Shape of Rime', + jp='霜晶の形', es='Forma de la escarcha', dungeon_id=1106, plane_id=2013201, @@ -325,10 +325,10 @@ Stagnant_Shadow_Rime = DungeonList( Stagnant_Shadow_Mirage = DungeonList( id=30, name='Stagnant_Shadow_Mirage', - cn='幻光之形•凝滞虚影', - cht='幻光之形•凝滯虛影', - en='Stagnant Shadow: Shape of Mirage', - jp='凝結虚影・幻光の形', + cn='幻光之形', + cht='幻光之形', + en='Shape of Mirage', + jp='幻光の形', es='Forma del espejismo', dungeon_id=1107, plane_id=2011101, @@ -336,10 +336,10 @@ Stagnant_Shadow_Mirage = DungeonList( Stagnant_Shadow_Icicle = DungeonList( id=31, name='Stagnant_Shadow_Icicle', - cn='冰棱之形•凝滞虚影', - cht='冰稜之形•凝滯虛影', - en='Stagnant Shadow: Shape of Icicle', - jp='凝結虚影・氷柱の形', + cn='冰棱之形', + cht='冰稜之形', + en='Shape of Icicle', + jp='氷柱の形', es='Forma del témpano', dungeon_id=1108, plane_id=2021101, @@ -347,10 +347,10 @@ Stagnant_Shadow_Icicle = DungeonList( Stagnant_Shadow_Doom = DungeonList( id=32, name='Stagnant_Shadow_Doom', - cn='震厄之形•凝滞虚影', - cht='震厄之形•凝滯虛影', - en='Stagnant Shadow: Shape of Doom', - jp='凝結虚影・震厄の形', + cn='震厄之形', + cht='震厄之形', + en='Shape of Doom', + jp='震厄の形', es='Forma de la perdición', dungeon_id=1109, plane_id=2021201, @@ -358,10 +358,10 @@ Stagnant_Shadow_Doom = DungeonList( Stagnant_Shadow_Puppetry = DungeonList( id=33, name='Stagnant_Shadow_Puppetry', - cn='偃偶之形•凝滞虚影', - cht='偃偶之形•凝滯虛影', - en='Stagnant Shadow: Shape of Puppetry', - jp='凝結虚影・傀儡の形', + cn='偃偶之形', + cht='偃偶之形', + en='Shape of Puppetry', + jp='傀儡の形', es='Forma de las marionetas', dungeon_id=1110, plane_id=2022201, @@ -369,10 +369,10 @@ Stagnant_Shadow_Puppetry = DungeonList( Stagnant_Shadow_Abomination = DungeonList( id=34, name='Stagnant_Shadow_Abomination', - cn='孽兽之形•凝滞虚影', - cht='孽獸之形•凝滯虛影', - en='Stagnant Shadow: Shape of Abomination', - jp='凝結虚影・厄獣の形', + cn='孽兽之形', + cht='孽獸之形', + en='Shape of Abomination', + jp='厄獣の形', es='Forma de la abominación', dungeon_id=1111, plane_id=2023201, @@ -380,10 +380,10 @@ Stagnant_Shadow_Abomination = DungeonList( Stagnant_Shadow_Scorch = DungeonList( id=35, name='Stagnant_Shadow_Scorch', - cn='燔灼之形•凝滞虚影', - cht='燔灼之形•凝滯虛影', - en='Stagnant Shadow: Shape of Scorch', - jp='凝結虚影・燔灼の形', + cn='燔灼之形', + cht='燔灼之形', + en='Shape of Scorch', + jp='燔灼の形', es='Forma abrasada', dungeon_id=1112, plane_id=2012101, @@ -391,10 +391,10 @@ Stagnant_Shadow_Scorch = DungeonList( Stagnant_Shadow_Celestial = DungeonList( id=36, name='Stagnant_Shadow_Celestial', - cn='天人之形•凝滞虚影', - cht='天人之形•凝滯虛影', - en='Stagnant Shadow: Shape of Celestial', - jp='凝結虚影・天人の形', + cn='天人之形', + cht='天人之形', + en='Shape of Celestial', + jp='天人の形', es='Forma de lo celestial', dungeon_id=1113, plane_id=2023101, @@ -402,10 +402,10 @@ Stagnant_Shadow_Celestial = DungeonList( Stagnant_Shadow_Perdition = DungeonList( id=37, name='Stagnant_Shadow_Perdition', - cn='幽府之形•凝滞虚影', - cht='幽府之形•凝滯虛影', - en='Stagnant Shadow: Shape of Perdition', - jp='凝結虚影・幽府の形', + cn='幽府之形', + cht='幽府之形', + en='Shape of Perdition', + jp='幽府の形', es='Forma del aislamiento', dungeon_id=1114, plane_id=2022301, @@ -413,10 +413,10 @@ Stagnant_Shadow_Perdition = DungeonList( Stagnant_Shadow_Nectar = DungeonList( id=38, name='Stagnant_Shadow_Nectar', - cn='冰酿之形•凝滞虚影', - cht='冰釀之形•凝滯虛影', - en='Stagnant Shadow: Shape of Nectar', - jp='凝結虚影・氷醸の形', + cn='冰酿之形', + cht='冰釀之形', + en='Shape of Nectar', + jp='氷醸の形', es='Forma del néctar', dungeon_id=1115, plane_id=2031101, @@ -424,10 +424,10 @@ Stagnant_Shadow_Nectar = DungeonList( Stagnant_Shadow_Roast = DungeonList( id=39, name='Stagnant_Shadow_Roast', - cn='焦炙之形•凝滞虚影', - cht='焦炙之形•凝滯虛影', - en='Stagnant Shadow: Shape of Roast', - jp='凝結虚影・焦灼の形', + cn='焦炙之形', + cht='焦炙之形', + en='Shape of Roast', + jp='焦灼の形', es='Forma del agostamiento', dungeon_id=1116, plane_id=2031301, @@ -435,10 +435,10 @@ Stagnant_Shadow_Roast = DungeonList( Stagnant_Shadow_Ire = DungeonList( id=40, name='Stagnant_Shadow_Ire', - cn='嗔怒之形•凝滞虚影', - cht='嗔怒之形•凝滯虛影', - en='Stagnant Shadow: Shape of Ire', - jp='凝結虚影・憤怒の形', + cn='嗔怒之形', + cht='嗔怒之形', + en='Shape of Ire', + jp='憤怒の形', es='Forma de la ira', dungeon_id=1117, plane_id=2032201, @@ -446,126 +446,148 @@ Stagnant_Shadow_Ire = DungeonList( Stagnant_Shadow_Duty = DungeonList( id=41, name='Stagnant_Shadow_Duty', - cn='职司之形•凝滞虚影', - cht='職司之形•凝滯虛影', - en='Stagnant Shadow: Shape of Duty', - jp='凝結虚影・職掌の形', + cn='职司之形', + cht='職司之形', + en='Shape of Duty', + jp='職掌の形', es='Forma del deber', dungeon_id=1118, plane_id=2032101, ) -Cavern_of_Corrosion_Path_of_Gelid_Wind = DungeonList( +Stagnant_Shadow_Mechwolf = DungeonList( id=42, + name='Stagnant_Shadow_Mechwolf', + cn='机狼之形', + cht='機狼之形', + en='Shape of Mechwolf', + jp='機狼の形', + es='Forma del lobo mecánico', + dungeon_id=1120, + plane_id=2024101, +) +Stagnant_Shadow_Gloam = DungeonList( + id=43, + name='Stagnant_Shadow_Gloam', + cn='今宵之形', + cht='今宵之形', + en='Shape of Gloam', + jp='今宵の形', + es='Forma del ocaso', + dungeon_id=1121, + plane_id=2033201, +) +Cavern_of_Corrosion_Path_of_Gelid_Wind = DungeonList( + id=44, name='Cavern_of_Corrosion_Path_of_Gelid_Wind', - cn='霜风之径•侵蚀隧洞', - cht='霜風之徑•侵蝕隧洞', - en='Cavern of Corrosion: Path of Gelid Wind', - jp='侵蝕トンネル・霜風の路', + cn='霜风之径', + cht='霜風之徑', + en='Path of Gelid Wind', + jp='霜風の路', es='Senda del viento gélido', dungeon_id=1201, plane_id=2000201, ) Cavern_of_Corrosion_Path_of_Jabbing_Punch = DungeonList( - id=43, + id=45, name='Cavern_of_Corrosion_Path_of_Jabbing_Punch', - cn='迅拳之径•侵蚀隧洞', - cht='迅拳之徑•侵蝕隧洞', - en='Cavern of Corrosion: Path of Jabbing Punch', - jp='侵蝕トンネル・迅拳の路', + cn='迅拳之径', + cht='迅拳之徑', + en='Path of Jabbing Punch', + jp='迅拳の路', es='Senda de los puños rápidos', dungeon_id=1202, plane_id=2013101, ) Cavern_of_Corrosion_Path_of_Drifting = DungeonList( - id=44, + id=46, name='Cavern_of_Corrosion_Path_of_Drifting', - cn='漂泊之径•侵蚀隧洞', - cht='漂泊之徑•侵蝕隧洞', - en='Cavern of Corrosion: Path of Drifting', - jp='侵蝕トンネル・漂泊の路', + cn='漂泊之径', + cht='漂泊之徑', + en='Path of Drifting', + jp='漂泊の路', es='Senda de la deriva', dungeon_id=1203, plane_id=2013201, ) Cavern_of_Corrosion_Path_of_Providence = DungeonList( - id=45, + id=47, name='Cavern_of_Corrosion_Path_of_Providence', - cn='睿治之径•侵蚀隧洞', - cht='睿治之徑•侵蝕隧洞', - en='Cavern of Corrosion: Path of Providence', - jp='侵蝕トンネル・睿治の路', + cn='睿治之径', + cht='睿治之徑', + en='Path of Providence', + jp='睿治の路', es='Senda de la providencia', dungeon_id=1204, plane_id=2013401, ) Cavern_of_Corrosion_Path_of_Holy_Hymn = DungeonList( - id=46, + id=48, name='Cavern_of_Corrosion_Path_of_Holy_Hymn', - cn='圣颂之径•侵蚀隧洞', - cht='聖頌之徑•侵蝕隧洞', - en='Cavern of Corrosion: Path of Holy Hymn', - jp='侵蝕トンネル・聖頌の路', + cn='圣颂之径', + cht='聖頌之徑', + en='Path of Holy Hymn', + jp='聖頌の路', es='Senda del himno sagrado', dungeon_id=1205, plane_id=2021101, ) Cavern_of_Corrosion_Path_of_Conflagration = DungeonList( - id=47, + id=49, name='Cavern_of_Corrosion_Path_of_Conflagration', - cn='野焰之径•侵蚀隧洞', - cht='野焰之徑•侵蝕隧洞', - en='Cavern of Corrosion: Path of Conflagration', - jp='侵蝕トンネル・野焔の路', + cn='野焰之径', + cht='野焰之徑', + en='Path of Conflagration', + jp='野焔の路', es='Senda de la conflagración', dungeon_id=1206, plane_id=2021201, ) Cavern_of_Corrosion_Path_of_Elixir_Seekers = DungeonList( - id=48, + id=50, name='Cavern_of_Corrosion_Path_of_Elixir_Seekers', - cn='药使之径•侵蚀隧洞', - cht='藥使之徑•侵蝕隧洞', - en='Cavern of Corrosion: Path of Elixir Seekers', - jp='侵蝕トンネル・薬使の路', + cn='药使之径', + cht='藥使之徑', + en='Path of Elixir Seekers', + jp='薬使の路', es='Senda de los elixires', dungeon_id=1207, plane_id=2023101, ) Cavern_of_Corrosion_Path_of_Darkness = DungeonList( - id=49, + id=51, name='Cavern_of_Corrosion_Path_of_Darkness', - cn='幽冥之径•侵蚀隧洞', - cht='幽冥之徑•侵蝕隧洞', - en='Cavern of Corrosion: Path of Darkness', - jp='侵蝕トンネル・幽冥の路', + cn='幽冥之径', + cht='幽冥之徑', + en='Path of Darkness', + jp='幽冥の路', es='Senda de la oscuridad', dungeon_id=1208, plane_id=2022301, ) Cavern_of_Corrosion_Path_of_Dreamdive = DungeonList( - id=50, + id=52, name='Cavern_of_Corrosion_Path_of_Dreamdive', - cn='梦潜之径•侵蚀隧洞', - cht='夢潛之徑•侵蝕隧洞', - en='Cavern of Corrosion: Path of Dreamdive', - jp='侵蝕トンネル・夢潜の路', + cn='梦潜之径', + cht='夢潛之徑', + en='Path of Dreamdive', + jp='夢潜の路', es='Senda de los sueños', dungeon_id=1209, plane_id=2031101, ) Cavern_of_Corrosion_Path_of_Cavalier = DungeonList( - id=51, + id=53, name='Cavern_of_Corrosion_Path_of_Cavalier', - cn='勇骑之径•侵蚀隧洞', - cht='勇騎之徑•侵蝕隧洞', - en='Cavern of Corrosion: Path of Cavalier', - jp='侵蝕トンネル・勇騎の路', + cn='勇骑之径', + cht='勇騎之徑', + en='Path of Cavalier', + jp='勇騎の路', es='Senda del caballero', dungeon_id=1210, plane_id=2033201, ) Echo_of_War_Destruction_Beginning = DungeonList( - id=52, + id=54, name='Echo_of_War_Destruction_Beginning', cn='毁灭的开端•历战余响', cht='毀滅的開端•歷戰餘響', @@ -576,7 +598,7 @@ Echo_of_War_Destruction_Beginning = DungeonList( plane_id=2000301, ) Echo_of_War_End_of_the_Eternal_Freeze = DungeonList( - id=53, + id=55, name='Echo_of_War_End_of_the_Eternal_Freeze', cn='寒潮的落幕•历战余响', cht='寒潮的落幕•歷戰餘響', @@ -587,7 +609,7 @@ Echo_of_War_End_of_the_Eternal_Freeze = DungeonList( plane_id=2013401, ) Echo_of_War_Divine_Seed = DungeonList( - id=54, + id=56, name='Echo_of_War_Divine_Seed', cn='不死的神实•历战余响', cht='不死的神實•歷戰餘響', @@ -598,7 +620,7 @@ Echo_of_War_Divine_Seed = DungeonList( plane_id=2023201, ) Echo_of_War_Borehole_Planet_Old_Crater = DungeonList( - id=55, + id=57, name='Echo_of_War_Borehole_Planet_Old_Crater', cn='蛀星的旧靥•历战余响', cht='蛀星的舊靨•歷戰餘響', @@ -609,7 +631,7 @@ Echo_of_War_Borehole_Planet_Old_Crater = DungeonList( plane_id=2000401, ) Echo_of_War_Salutations_of_Ashen_Dreams = DungeonList( - id=56, + id=58, name='Echo_of_War_Salutations_of_Ashen_Dreams', cn='尘梦的赞礼•历战余响', cht='塵夢的讚禮•歷戰餘響', @@ -619,184 +641,206 @@ Echo_of_War_Salutations_of_Ashen_Dreams = DungeonList( dungeon_id=1305, plane_id=2033201, ) +Echo_of_War_Inner_Beast_Battlefield = DungeonList( + id=59, + name='Echo_of_War_Inner_Beast_Battlefield', + cn='心兽的战场•历战余响', + cht='心獸的戰場•歷戰餘響', + en="Echo of War: Inner Beast's Battlefield", + jp='歴戦余韻・心獣の戦場', + es='Campo de batalla de la bestia interior', + dungeon_id=1306, + plane_id=2024201, +) Simulated_Universe_World_1 = DungeonList( - id=57, + id=60, name='Simulated_Universe_World_1', - cn='第一世界•模拟宇宙', - cht='第一世界•模擬宇宙', - en='Simulated Universe: World 1', - jp='第一世界・模擬宇宙', + cn='第一世界', + cht='第一世界', + en='World 1', + jp='第一世界', es='Mundo 1', dungeon_id=110, plane_id=100000104, ) Simulated_Universe_World_3 = DungeonList( - id=58, + id=61, name='Simulated_Universe_World_3', - cn='第三世界•模拟宇宙', - cht='第三世界•模擬宇宙', - en='Simulated Universe: World 3', - jp='第三世界・模擬宇宙', + cn='第三世界', + cht='第三世界', + en='World 3', + jp='第三世界', es='Mundo 3', dungeon_id=130, plane_id=100000104, ) Simulated_Universe_World_4 = DungeonList( - id=59, + id=62, name='Simulated_Universe_World_4', - cn='第四世界•模拟宇宙', - cht='第四世界•模擬宇宙', - en='Simulated Universe: World 4', - jp='第四世界・模擬宇宙', + cn='第四世界', + cht='第四世界', + en='World 4', + jp='第四世界', es='Mundo 4', dungeon_id=140, plane_id=100000104, ) Simulated_Universe_World_5 = DungeonList( - id=60, + id=63, name='Simulated_Universe_World_5', - cn='第五世界•模拟宇宙', - cht='第五世界•模擬宇宙', - en='Simulated Universe: World 5', - jp='第五世界・模擬宇宙', + cn='第五世界', + cht='第五世界', + en='World 5', + jp='第五世界', es='Mundo 5', dungeon_id=150, plane_id=100000104, ) Simulated_Universe_World_6 = DungeonList( - id=61, + id=64, name='Simulated_Universe_World_6', - cn='第六世界•模拟宇宙', - cht='第六世界•模擬宇宙', - en='Simulated Universe: World 6', - jp='第六世界・模擬宇宙', + cn='第六世界', + cht='第六世界', + en='World 6', + jp='第六世界', es='Mundo 6', dungeon_id=160, plane_id=100000104, ) Simulated_Universe_World_7 = DungeonList( - id=62, + id=65, name='Simulated_Universe_World_7', - cn='第七世界•模拟宇宙', - cht='第七世界•模擬宇宙', - en='Simulated Universe: World 7', - jp='第七世界・模擬宇宙', + cn='第七世界', + cht='第七世界', + en='World 7', + jp='第七世界', es='Mundo 7', dungeon_id=170, plane_id=100000104, ) Simulated_Universe_World_8 = DungeonList( - id=63, + id=66, name='Simulated_Universe_World_8', - cn='第八世界•模拟宇宙', - cht='第八世界•模擬宇宙', - en='Simulated Universe: World 8', - jp='第八世界・模擬宇宙', + cn='第八世界', + cht='第八世界', + en='World 8', + jp='第八世界', es='Mundo 8', dungeon_id=180, plane_id=100000104, ) Simulated_Universe_World_9 = DungeonList( - id=64, + id=67, name='Simulated_Universe_World_9', - cn='第九世界•模拟宇宙', - cht='第九世界•模擬宇宙', - en='Simulated Universe: World 9', - jp='第九世界・模擬宇宙', + cn='第九世界', + cht='第九世界', + en='World 9', + jp='第九世界', es='Mundo 9', dungeon_id=190, plane_id=100000104, ) +Divergent_Universe_Famished_Worker = DungeonList( + id=68, + name='Divergent_Universe_Famished_Worker', + cn='蠹役饥肠', + cht='蠹役飢腸', + en='Famished Worker', + jp='飢えた虫卒', + es='Obrero famélico', + dungeon_id=310, + plane_id=0, +) Divergent_Universe_Eternal_Comedy = DungeonList( - id=65, + id=69, name='Divergent_Universe_Eternal_Comedy', - cn='永恒笑剧•差分宇宙', - cht='永恆笑劇•差分宇宙', - en='Divergent Universe: Eternal Comedy', - jp='階差宇宙・永遠の喜劇', + cn='永恒笑剧', + cht='永恆笑劇', + en='Eternal Comedy', + jp='永遠の喜劇', es='Comedia eterna', dungeon_id=300, plane_id=0, ) Divergent_Universe_To_Sweet_Dreams = DungeonList( - id=66, + id=70, name='Divergent_Universe_To_Sweet_Dreams', - cn='伴你入眠•差分宇宙', - cht='伴你入眠•差分宇宙', - en='Divergent Universe: To Sweet Dreams', - jp='階差宇宙・寄り添い眠る', + cn='伴你入眠', + cht='伴你入眠', + en='To Sweet Dreams', + jp='寄り添い眠る', es='Hasta los dulces sueños', dungeon_id=290, plane_id=0, ) Divergent_Universe_Pouring_Blades = DungeonList( - id=67, + id=71, name='Divergent_Universe_Pouring_Blades', - cn='天剑如雨•差分宇宙', - cht='天劍如雨•差分宇宙', - en='Divergent Universe: Pouring Blades', - jp='階差宇宙・剣の雨', + cn='天剑如雨', + cht='天劍如雨', + en='Pouring Blades', + jp='剣の雨', es='Lluvia de espadas', dungeon_id=280, plane_id=0, ) Divergent_Universe_Fruit_of_Evil = DungeonList( - id=68, + id=72, name='Divergent_Universe_Fruit_of_Evil', - cn='孽果盘生•差分宇宙', - cht='孽果盤生•差分宇宙', - en='Divergent Universe: Fruit of Evil', - jp='階差宇宙・渦巻く罪', + cn='孽果盘生', + cht='孽果盤生', + en='Fruit of Evil', + jp='渦巻く罪', es='Fruta del desastre', dungeon_id=270, plane_id=0, ) Divergent_Universe_Permafrost = DungeonList( - id=69, + id=73, name='Divergent_Universe_Permafrost', - cn='百年冻土•差分宇宙', - cht='百年凍土•差分宇宙', - en='Divergent Universe: Permafrost', - jp='階差宇宙・永久凍土', + cn='百年冻土', + cht='百年凍土', + en='Permafrost', + jp='永久凍土', es='Permafrost', dungeon_id=260, plane_id=0, ) Divergent_Universe_Gentle_Words = DungeonList( - id=70, + id=74, name='Divergent_Universe_Gentle_Words', - cn='温柔话语•差分宇宙', - cht='溫柔話語•差分宇宙', - en='Divergent Universe: Gentle Words', - jp='階差宇宙・優しい言葉', + cn='温柔话语', + cht='溫柔話語', + en='Gentle Words', + jp='優しい言葉', es='Palabras amables', dungeon_id=250, plane_id=0, ) Divergent_Universe_Smelted_Heart = DungeonList( - id=71, + id=75, name='Divergent_Universe_Smelted_Heart', - cn='浴火钢心•差分宇宙', - cht='浴火鋼心•差分宇宙', - en='Divergent Universe: Smelted Heart', - jp='階差宇宙・鋼の意志', + cn='浴火钢心', + cht='浴火鋼心', + en='Smelted Heart', + jp='鋼の意志', es='Corazón de fundición', dungeon_id=240, plane_id=0, ) Divergent_Universe_Untoppled_Walls = DungeonList( - id=72, + id=76, name='Divergent_Universe_Untoppled_Walls', - cn='坚城不倒•差分宇宙', - cht='堅城不倒•差分宇宙', - en='Divergent Universe: Untoppled Walls', - jp='階差宇宙・不動の砦', + cn='坚城不倒', + cht='堅城不倒', + en='Untoppled Walls', + jp='不動の砦', es='Muros inquebrantables', dungeon_id=230, plane_id=0, ) Simulated_Universe_The_Swarm_Disaster = DungeonList( - id=73, + id=77, name='Simulated_Universe_The_Swarm_Disaster', cn='寰宇蝗灾', cht='寰宇蝗災', @@ -807,7 +851,7 @@ Simulated_Universe_The_Swarm_Disaster = DungeonList( plane_id=-1, ) Simulated_Universe_Gold_and_Gears = DungeonList( - id=74, + id=78, name='Simulated_Universe_Gold_and_Gears', cn='黄金与机械', cht='黃金與機械', @@ -818,7 +862,7 @@ Simulated_Universe_Gold_and_Gears = DungeonList( plane_id=-1, ) Memory_of_Chaos = DungeonList( - id=75, + id=79, name='Memory_of_Chaos', cn='混沌回忆', cht='混沌回憶', @@ -829,7 +873,7 @@ Memory_of_Chaos = DungeonList( plane_id=-1, ) The_Voyage_of_Navis_Astriger = DungeonList( - id=76, + id=80, name='The_Voyage_of_Navis_Astriger', cn='天艟求仙迷航录', cht='天艟求仙迷航錄', @@ -840,7 +884,7 @@ The_Voyage_of_Navis_Astriger = DungeonList( plane_id=-1, ) The_Last_Vestiges_of_Towering_Citadel = DungeonList( - id=77, + id=81, name='The_Last_Vestiges_of_Towering_Citadel', cn='永屹之城遗秘', cht='永屹之城遺秘', diff --git a/tasks/dungeon/keywords/dungeon_detailed.py b/tasks/dungeon/keywords/dungeon_detailed.py index ccff5bab3..f65a145a5 100644 --- a/tasks/dungeon/keywords/dungeon_detailed.py +++ b/tasks/dungeon/keywords/dungeon_detailed.py @@ -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)', +) diff --git a/tasks/map/keywords/plane.py b/tasks/map/keywords/plane.py index cd478717b..fe324b436 100644 --- a/tasks/map/keywords/plane.py +++ b/tasks/map/keywords/plane.py @@ -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='匹諾康尼大劇院', diff --git a/tasks/planner/keywords/item_ascension.py b/tasks/planner/keywords/item_ascension.py index 5bd00204b..bb7fe6d8e 100644 --- a/tasks/planner/keywords/item_ascension.py +++ b/tasks/planner/keywords/item_ascension.py @@ -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='炙夢噴槍', diff --git a/tasks/planner/keywords/item_weekly.py b/tasks/planner/keywords/item_weekly.py index 7e8c35f5c..e9b554687 100644 --- a/tasks/planner/keywords/item_weekly.py +++ b/tasks/planner/keywords/item_weekly.py @@ -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, +) diff --git a/tasks/rogue/event/preset.py b/tasks/rogue/event/preset.py index e6387b591..5bc17f567 100644 --- a/tasks/rogue/event/preset.py +++ b/tasks/rogue/event/preset.py @@ -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: [ diff --git a/tasks/rogue/keywords/bonus.py b/tasks/rogue/keywords/bonus.py index f3f5be344..a9ac05127 100644 --- a/tasks/rogue/keywords/bonus.py +++ b/tasks/rogue/keywords/bonus.py @@ -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', +) diff --git a/tasks/rogue/keywords/event_option.py b/tasks/rogue/keywords/event_option.py index 64808b8fe..ac31eb358 100644 --- a/tasks/rogue/keywords/event_option.py +++ b/tasks/rogue/keywords/event_option.py @@ -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 1–2 star Blessing', + en='Purchase 1 Blessing of 1- to 2-star rarity', jp='★1~2の祝福を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='★1~3の祝福を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.', +) diff --git a/tasks/rogue/keywords/event_title.py b/tasks/rogue/keywords/event_title.py index 6d9ea82a6..aa2236030 100644 --- a/tasks/rogue/keywords/event_title.py +++ b/tasks/rogue/keywords/event_title.py @@ -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], +) From d4606052aac75550f4dcb7a70ccb45a516e7c01b Mon Sep 17 00:00:00 2001 From: Zero <98764734+X-Zero-L@users.noreply.github.com> Date: Tue, 10 Sep 2024 16:29:10 +0800 Subject: [PATCH 3/7] Upd: Character (#625) --- assets/character/Feixiao.png | Bin 0 -> 21151 bytes assets/character/Moze.png | Bin 0 -> 18442 bytes module/config/argument/args.json | 3 --- module/config/config_generated.py | 2 +- module/config/config_updater.py | 2 +- module/config/i18n/en-US.json | 1 - module/config/i18n/es-ES.json | 1 - module/config/i18n/ja-JP.json | 1 - module/config/i18n/zh-CN.json | 1 - module/config/i18n/zh-TW.json | 1 - 10 files changed, 2 insertions(+), 10 deletions(-) create mode 100644 assets/character/Feixiao.png create mode 100644 assets/character/Moze.png diff --git a/assets/character/Feixiao.png b/assets/character/Feixiao.png new file mode 100644 index 0000000000000000000000000000000000000000..4bf1b51da9d7d7f7a21c249aa945c38ece8017ca GIT binary patch literal 21151 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 literal 0 HcmV?d00001 diff --git a/assets/character/Moze.png b/assets/character/Moze.png new file mode 100644 index 0000000000000000000000000000000000000000..c150737affb3c931aeaa9fe590f28f2e02c0df57 GIT binary patch literal 18442 zcmV)&K#aeMP)GF=mWr$%hyM1VCU+YM8>jHg+d=9A~FB~ zKmbrGw1i`fMr4T0009^P&{}aW5z!b$L_$a)ATr39iet_NA{ecKe5KX;>U5*gvZOGY z5D@@2{su$)EC_jM@06L{iCmHY8{iW5SRDLj(qq8?87OT5CjPOb`(O z5NQBrjA1NU*v4gyQYum^3cQwZ94F&+40Mj~+uhc)CtvK=Mg>g@yf_NHz;80B{qVd0 zx-xgQvvZ7d3jjD5LP#RR7&k^EA|etYk-4^(WCK(jF)jeWs8~vAj4=iPQA%5aJutLK zYt?KtD(f>U*00|m0ww?6e#b8$G6Wz>47&KaC-*4`?X?$?&&KvK3TceSC@w?w$oSFin`oeOu zFHxjDuM&n;08{L>ZoT_`Jp*H({@Bltjoxb8E@KiAbsTXn6E)XFoC_iYKmf`2QgT;h zG$J!(q>#p#PzG2~nrV>VA&A}qrg zM?|9yA|&5r$Z#&mm_&?;$bbNWF~+pkj3EIaVyqM*G@H$GeSK(j&w-ov@45cKwxO=& zvia&ifBUtUo^Guh0N}C-z%+KLa3=E4M3ExmnanoMQ^FFyx6;|a^XLBX6R$q?ndkof zk-dBGL}bduj4@*jB1`rf0SOEOBugY?kTEhQd9BUH@gbrxsQ;LB06^=gv~=1ilL!a_ z@b;s>0078&v5*s-#Y%G_jM2%-07Hn3fEeR|1OPxlM8;^wIAh!xg#d;O5i!P-BbFRe zLI^`|d2KmcEZ%tZj<>%3U2ca30HGf~_RVL%{I~z?`^{XgT?hiSkc9}yFciY_RUv3C zR?Dx3VTm!@bvqnqm?-umeD8mHcmI~{4}SI&8PQ!Vb|-cRfEaQB(po2$!4NTIh7925 zDF8sm0AOR|0WC`^r5jBz4ppL101!ude)dFi5D*cM-tl1~0>(Pp@?Z45ES zHq8?lV>q%-m0ss9jg%N>0LD32S|t|RkP%!0kueGYk@NN1mB0D?w=&sW^4%;;wQ~LU zKJ>B4bC=rMQe9nx0AN`u&Xe84blMTZW{kI5>$9^LJa4YixWrft0G8F~IAf8S9NWF? z_x|QffBND3f~wu!Jw&7#6AVCWMFgC4B6$7abC#U4#NH%ElQD(}oG~}$q+C0Wl;;IO z5CMQvK%`d|Pim!KmyRar>L>s}wcY{)#%O?Re#(Slv)L?nQTE+kZ+p1(=p3zbZl}|2 zj+0@GYon7xzNu@N?2>l;pZ)DW-8nLP%^*MdmWdb{IC-)-Ex|r>36wyvqPY#BBQ@qRe-;e)1z9$h0~C?LYnT-u-XloFgG^ z>ThBV5*^`ECi;>X&_p4wIb{G4f){cb#+dJityU1n1ON=*GPPRC$q)S5Cq8*- z_o%P{EvVG%|LZTm{<**ShmL&P`1ak!VmG&34X6Q85R;5azhD4iT9q;#?v!BApmY#)Q@i z00ELSMTlt3hDlA_s8YIIZiHc!&8BSI+Hk2P+dH=a0V87&m?Z=va3(l%A#6kjfQ@>o zympnyAW%2v_jc^{qt?2qrwH_Ve#k>}Nhw+(&#Gk@IP*#-ba z@XX`qfA8o2^w?A1*)o10*VeUhs2MWG7-vbqg2;@~VH_%>B$o_X;`Mtv_DbRQbnZX6 z=iLCnn4{Es5KN>}eUCo+ufO@gd;jZaA6l(U)%_|UP~sQ3&_)4r0$|9=7z9K>hMbH} zY&Jt~v;iUnB%pfJZ#Mm0E|tz$+(KcqOk2N@f+f*iV)>O)S}P(AM77$o=hXliM{%cn zWUCx#&-b+adRf(mv3o2%vYihiLqz6zm1<>~h&UHZOOwC&m;dq4{`r#t&}#ZmKX&X7 z{___<_uu~yV|?qb8{o$-{P8!GQGVnHQNS2yj1ieQ_S32MbgF|x`ue>e*o??5&zp6e z-ezO%qrddQTkrdMyO5rpJC`WPh64qIo1afaNu*|s1^^Zd4&V0&r(SzBj-$kY8l#DlsEch{ z9KwwlHE|wERpVla(Nbj`grHthVL2g z-!V0D!5B5txvh6}w6?nX@TqSe7`|@Tp6iU(-dc_G)N>Qxf2DVAZQd-*cv_n+V|}je zme*E`on2&JSB{NfZ1eS|;@}&Fl>}mln6}fFaEJ^LXrqHT2x8yFL94YQrF-$>SBWC6 zwK3Wlr=w$c9Jjhg_7CrP>y?vVPIHsZ77_7U1hlC#8_86X4=rh&+eiA$wZg~HawiI?W4og?DG;ti9TUv+LIXmBd!-w`9ynf;G#S3Ro zNZYbdq-@vCr%L68bImKqg4dp(divp4AM*U#VrBNKx6Xyb@mxnire)r*E%)>eF+|dO z^KQ%=V-qUlF?<-@B5JF(Ry!dRUux)+) zlx4LoEKIMhE|W?8Hj*}^jbJtsGGIuE#25$$909e8$w10USwgBppCTt4etU0{McEOT)LKP$V58ah#oi6<{!DbyZ766 zfe82R{Q&1Vr4#_T4qKgjER!CrRxf6=Tc)p`ioyVZF~%73B)hhxy9r&Y>?GzA$qE?biT{(9Ye=s{V|{(?2VZ&UQ;&Y;(wWo364&j!;p(MJ!ji?#_O{NB z*~Pi9ef#TYE}X8mEw8R#+`W7ByWf3G>y&M0e{`{LJVA-b3>m%oJBCOnR*By5kV10C z{m>@@26XMQ@rek?4GM#TQt4tozr9+W@9aFBPH*#liXzE?m&?!EZXt}TZo0o(Ti#Gd zM9u}#hJV-qs(>W702u;uE;e&-NTkDruo45#88=4fvRwdRNc~;up?@fS>$PC=+{y)V zqK=WyEqk|$JS;WWTRAzncXwxB--)%Cme}I;*B|-%*T2|kt&1Od}t6*8#fq^5O z3q;O2FR#6T$l|zOZhVMJknbd&l}2!x-^i41$GLYdQ=|0Ex?tjS01mv zy7M{?i;OWQmGU`vdwLF~)7{15cGqo-qF72%V2Q|dcWt|trce9xBkdz;nL@^pVbJn3#WpU)+?h)& zubvuZ=_kJYkd&5fXEGVDSVYd}mlnSp1_UN$RMcu*4*W$Gdt`v2KwxBIqeCKN%*H|5 zMC^#j2rfEvov!Tyg3(Ir*s+Vb+@5CRQWQ23Bm)cRnt%v^EK69H4NzWNd%0Sh<1&@a z4YzmP1mG|R)$)r$P^;C~H=+0q^ow!9nSc#{%@DaUMyV(^ zWG3D2c@+fq?aH(9RP>&;p3c4=0I*$W=WPd{|Hfla9((v)>s&o*u-=}*Oks6(w%KfT zb!{<52?2qBp;jf=?JX9!BeFQE2YN~Hlx=r1W*HL^5i$S}h)CB?6;NBcE$ieMa=`@< zXcK4LbQHA)2j4U^^DO7S>u$BI0YoH5i9hB%YBXk|sNUJNzv-8&0Tl?qkZH^J5|Qs! z0ojwKldaFS-u2G+?6_{fisLI!zx?cl=T2rzK{hW~+h981(b2zS$B{7fE?qiasjOtP z#eBX?h-Mrwt(F&nNXoqH3~-SlFhRIN6bO;#vWO_iM94OB&a|B=q>G7OIKtt~RyqKH z)zwQ<2Ho9#TJH$Mg+}A0IBqiLAhQrrt891o?nYy2W#xFwTWB>aw$qk!hnvmI9UZr= zu0Bl!wfd6QF`{Hl5E%lUcp+^R0 >tr!!VAqYz8syGmwq*97;#z7(=Lrd#OFbN1< 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 literal 0 HcmV?d00001 diff --git a/module/config/argument/args.json b/module/config/argument/args.json index 7cfb52a5e..de7767dfb 100644 --- a/module/config/argument/args.json +++ b/module/config/argument/args.json @@ -698,7 +698,6 @@ "JingYuan", "Jingliu", "Kafka", - "Lingsha", "Luka", "Luocha", "Lynx", @@ -898,7 +897,6 @@ "JingYuan", "Jingliu", "Kafka", - "Lingsha", "Luka", "Luocha", "Lynx", @@ -1436,7 +1434,6 @@ "JingYuan", "Jingliu", "Kafka", - "Lingsha", "Luka", "Luocha", "Lynx", diff --git a/module/config/config_generated.py b/module/config/config_generated.py index 4969ea5d5..c8db44b15 100644 --- a/module/config/config_generated.py +++ b/module/config/config_generated.py @@ -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, Feixiao, Firefly, FuXuan, Gallagher, Gepard, Guinaifen, Hanya, Herta, Himeko, Hook, Huohuo, Jade, Jiaoqiu, JingYuan, Jingliu, Kafka, Lingsha, 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 + 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 = {} diff --git a/module/config/config_updater.py b/module/config/config_updater.py index a8ada2eac..c820c2694 100644 --- a/module/config/config_updater.py +++ b/module/config/config_updater.py @@ -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) diff --git a/module/config/i18n/en-US.json b/module/config/i18n/en-US.json index b33349a42..16eb04767 100644 --- a/module/config/i18n/en-US.json +++ b/module/config/i18n/en-US.json @@ -411,7 +411,6 @@ "JingYuan": "Jing Yuan", "Jingliu": "Jingliu", "Kafka": "Kafka", - "Lingsha": "Lingsha", "Luka": "Luka", "Luocha": "Luocha", "Lynx": "Lynx", diff --git a/module/config/i18n/es-ES.json b/module/config/i18n/es-ES.json index f3581312f..3ba57c747 100644 --- a/module/config/i18n/es-ES.json +++ b/module/config/i18n/es-ES.json @@ -411,7 +411,6 @@ "JingYuan": "Jing Yuan", "Jingliu": "Jingliu", "Kafka": "Kafka", - "Lingsha": "Lingsha", "Luka": "Luka", "Luocha": "Luocha", "Lynx": "Lynx", diff --git a/module/config/i18n/ja-JP.json b/module/config/i18n/ja-JP.json index 157858c18..b1eace0fa 100644 --- a/module/config/i18n/ja-JP.json +++ b/module/config/i18n/ja-JP.json @@ -411,7 +411,6 @@ "JingYuan": "景元", "Jingliu": "鏡流", "Kafka": "カフカ", - "Lingsha": "霊砂", "Luka": "ルカ", "Luocha": "羅刹", "Lynx": "リンクス", diff --git a/module/config/i18n/zh-CN.json b/module/config/i18n/zh-CN.json index 24bebf6cd..22ca2e3fc 100644 --- a/module/config/i18n/zh-CN.json +++ b/module/config/i18n/zh-CN.json @@ -411,7 +411,6 @@ "JingYuan": "景元", "Jingliu": "镜流", "Kafka": "卡芙卡", - "Lingsha": "灵砂", "Luka": "卢卡", "Luocha": "罗刹", "Lynx": "玲可", diff --git a/module/config/i18n/zh-TW.json b/module/config/i18n/zh-TW.json index d9581a686..63215d961 100644 --- a/module/config/i18n/zh-TW.json +++ b/module/config/i18n/zh-TW.json @@ -411,7 +411,6 @@ "JingYuan": "景元", "Jingliu": "鏡流", "Kafka": "卡芙卡", - "Lingsha": "靈砂", "Luka": "盧卡", "Luocha": "羅剎", "Lynx": "玲可", From f81b40963d68f39db675f49ce3699e11110dd2ec Mon Sep 17 00:00:00 2001 From: LmeSzinc <37934724+LmeSzinc@users.noreply.github.com> Date: Tue, 10 Sep 2024 22:41:00 +0800 Subject: [PATCH 4/7] Fix: Dungeon list swiping in 2.5 --- assets/share/dungeon/ui/CALYX_WORLD_3.png | Bin 6900 -> 0 bytes .../LIST_ASCENDING.png} | Bin 6798 -> 6177 bytes .../LIST_DESCENDING.png} | Bin 6999 -> 6073 bytes .../OCR_DUNGEON_LIST.BUTTON.png | Bin .../{ui => ui_list}/OCR_DUNGEON_LIST.png | Bin .../dungeon/ui_list/OCR_DUNGEON_NAME.png | Bin 0 -> 43374 bytes .../ui_list/OCR_DUNGEON_NAME_ROGUE.png | Bin 0 -> 19772 bytes .../dungeon/ui_list/OCR_DUNGEON_TELEPORT.png | Bin 0 -> 47126 bytes dev_tools/keywords/dungeon_list.py | 31 +- tasks/daily/daily_quest.py | 2 +- tasks/dungeon/assets/assets_dungeon_ui.py | 40 - .../dungeon/assets/assets_dungeon_ui_list.py | 65 ++ tasks/dungeon/dungeon.py | 6 +- tasks/dungeon/keywords/dungeon.py | 346 ++++---- tasks/dungeon/stamina.py | 2 +- tasks/dungeon/ui.py | 770 ------------------ tasks/dungeon/ui/interact.py | 85 ++ tasks/dungeon/ui/llist.py | 385 +++++++++ tasks/dungeon/ui/nav.py | 351 ++++++++ tasks/dungeon/{ => ui}/state.py | 0 tasks/dungeon/ui/ui.py | 41 + tasks/dungeon/{ => ui}/ui_rogue.py | 8 +- tasks/dungeon/weekly.py | 8 +- tasks/forgotten_hall/ui.py | 4 +- tasks/ornament/combat.py | 2 +- tasks/rogue/entry/entry.py | 4 +- tasks/rogue/event/reward.py | 2 +- 27 files changed, 1140 insertions(+), 1012 deletions(-) delete mode 100644 assets/share/dungeon/ui/CALYX_WORLD_3.png rename assets/share/dungeon/{ui/CALYX_WORLD_1.png => ui_list/LIST_ASCENDING.png} (75%) rename assets/share/dungeon/{ui/CALYX_WORLD_2.png => ui_list/LIST_DESCENDING.png} (73%) rename assets/share/dungeon/{ui => ui_list}/OCR_DUNGEON_LIST.BUTTON.png (100%) rename assets/share/dungeon/{ui => ui_list}/OCR_DUNGEON_LIST.png (100%) create mode 100644 assets/share/dungeon/ui_list/OCR_DUNGEON_NAME.png create mode 100644 assets/share/dungeon/ui_list/OCR_DUNGEON_NAME_ROGUE.png create mode 100644 assets/share/dungeon/ui_list/OCR_DUNGEON_TELEPORT.png create mode 100644 tasks/dungeon/assets/assets_dungeon_ui_list.py delete mode 100644 tasks/dungeon/ui.py create mode 100644 tasks/dungeon/ui/interact.py create mode 100644 tasks/dungeon/ui/llist.py create mode 100644 tasks/dungeon/ui/nav.py rename tasks/dungeon/{ => ui}/state.py (100%) create mode 100644 tasks/dungeon/ui/ui.py rename tasks/dungeon/{ => ui}/ui_rogue.py (93%) diff --git a/assets/share/dungeon/ui/CALYX_WORLD_3.png b/assets/share/dungeon/ui/CALYX_WORLD_3.png deleted file mode 100644 index eeb73049b481bbfb72978d365a87ea12522ed2b5..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 6900 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 ZB>@h&{<71dVV<+Y+v+-Mr7E^h{sZOLLNEXT diff --git a/assets/share/dungeon/ui/CALYX_WORLD_1.png b/assets/share/dungeon/ui_list/LIST_ASCENDING.png similarity index 75% rename from assets/share/dungeon/ui/CALYX_WORLD_1.png rename to assets/share/dungeon/ui_list/LIST_ASCENDING.png index 5457292d261d6d6497a8b955c490411ba6d68717..f6f6a8d8ddc740f525e8651de56e2b16071cbb73 100644 GIT binary patch delta 846 zcmV-U1F`&$HK8!Dy$V|mPDw;TRCwC#-M?;BR}cr_JLm37fB`8K+xRUgf)FV~K}5|n zVE&{bAr^58@&YD34Soxt1iK+MCM{Kv3q~xOiD4C$ziC_Z6#qcDI_XewsP6 zO#`!06CVe&Fbg>Xe=xH`2><{94z=}mE28wznKd)}=Th2QyIZ$zt*<}3dGp6}=f3IR zueB?sojZO^>84Xr0ssJje@jgfnKhzB#NOWC`uci_h=`|8pFV!{=*6EeK7F&aC3G1D zU;qGsS(aIMcX#jKzyJLC^O~8N-F}yuyLT3W*>LE+GW;0A*#0000Emo+ywHdY_6 zzWM9TXf!%~fBJN0?!ABCf7;cqIcO1&^RS``zyJUMv*+cjmuqWlo12^S^YdrVo*fJa zHFGc=G))r`ZD}VHZ~yEjumB7I05E%Mt-CwB^YimxpE)yk{P>_9O!j*tqLdO5%|SP~ z-;Bl7at9ay0N`+=(dgpEi${(eDQ(HDU9F{*Zog|we_J!VS|g&XwcFp{@4A(hd#jIE zZ~uB*-2`9&0Du`25l4?69Umvhn-Bi_DEsvL+nqbh%gfvEwl92lLEWa75oiDafWu{G zl!y}job$(HL_N6fTWihCm6dzT%gbG@OFu7Nx^zk1rj`yc006+@V&cYcf6SWW#aC@< z2ZQ0=f4g^|{qgMW*4xFO7O!5ts%Qc*006*@X5i9H3_nk{qXbLvANM`bn2^95m5&1wQJYUpZ|8UC*0Let&<@O+aKV6>~8=70RR63 Y0BuiN6aIe*-v9sr07*qoM6N<$f(GHA`~Uy| delta 1566 zcmZ8heKga182_@$G+laeQ>3`}EYT4u)4c5trE%MI%&Y$tL1zb~9^MW;S+z)*ttr`~B;CzRz=>&+~mgpXZZrlfJ*Id2O&h z_ptjfz6m2Uqf10ze^Z_D=rcyR^Q0sE+J+bo#ESi9ir8Ym$TnA+tyNrp$ zQS@@XWT|2D+4bexmaq7Nr4UO;l=wmUVa67wuvlh~`8#Rj>sv{m1O~Ncs48t}Ty3yR z3%9>BJ>74d7~4?R#nA$met2B~fWb8_0B~RpeAP0#cFq=qDMo^8Ko57f>qJB3<;`muvg>b zgx|3S}XmP(!9~?#XWNx^f^ooyc(7f)6-xqFX34OA+(yG5hve?9hOU{QUfuZTJ1r z)N~yC=tyw}G#}{Ylk%T}f|PQJzc9dKDNwYCN|;AxJn?%7#L`qRV**BYY&c%kB1}|!|xVYq*TEe{&K$B&RH-x zH3WdR4TvxU`k{M;N+pjQWg@)P$d%6;a(jAuP$-mH3XMh+_A%8?4Zj^C5{c&0F*oy? z_cPZKIypHx@a*$S53EAv6+vBx`d`0(orp;*aJ%)xw{P=5a@)Qd;{%A#N82-)*x1s2 z&{A)Aw}1;l{JQWo-4#lFD~5)KgwfHw7IjOEO%{P6k?ffbw;ts2xo7%v-`>y8&MxCs zc=-5ky{)0y@<@DqJn~~l=Fa5gWaFa6K86=M^YiF)hBKW|NZ2ee+SZ&XK90;6-r3{3 zVMSBy7)YU#8MMxIcH+>Gtk24yP~1EJ&CobF*ClA{&4|&atj5TYQ>V;R-VDE~iWc@d zq#xS=*l|C+)MgXNPOHwx#l^{IM`beESWwFeY%WYpOzeJpd-R6e9UUE4mGe_Fg-9fV z#u|K@E~wkLZ$EJ93CW_I!wFAtQQa}Qv3li~st;NXB#Y2?=r1%HJtCiVPW*Zn8FKdQ z^x(wArz{48F*!L&Z-4G|wW*{e?A*D3f?ZVxcnjxWkHhOw>ciLo-aT; z*5cx#T`;t*T{=8G+^m%I9xf>chy$XSFpyrruB@-GsIaE@9P#$vM2VnM6?0R5A5vDW zNbC#5?fkv=v)Cd1A&s_XZ+1`DTTzVpeNXrP#5Z>*7bKhaT%;UOiR;Oik$Qks4L47s z6Sm7}O1pcWDF!Z!(=5*JUZHF)O2gbe<>>*5GCaKPApi5hq@<+ksG8#9ZkN zNd;Ozw6aT@8Lnm`BC$aiW=5c=Wy1jp(t>WC;Ad9?EjB&atf2^*iVxvj@D8F-tnKY3 zS8|zjs}{@x&ne*xE>*K_X(Sg`-P5O>=lz&8`xd>*>gwvk!ou$MLtec@+AAdz=$&WY zjdD00p*6!4GMR6~Wi?)owp^nr?+#7R?6z}MeicE9%CN&+_EfWcf+ulX^bk2G`5FQC z(GLhc(s``rq=^*@1kyHT3Wy5;L#>NRZ?_t^au{Y^>|x pW&Q6Jwq$c1)03!W1ORF^0`xJvjaRS7)xas>u*VVi3jE0%{{nZk^+5mt diff --git a/assets/share/dungeon/ui/CALYX_WORLD_2.png b/assets/share/dungeon/ui_list/LIST_DESCENDING.png similarity index 73% rename from assets/share/dungeon/ui/CALYX_WORLD_2.png rename to assets/share/dungeon/ui_list/LIST_DESCENDING.png index 3b3e3edb76e15028fa4e91d86798437e14a3c5fe..3d34041c786265c9110b588e7ef5e624b2bf4a24 100644 GIT binary patch delta 740 zcmVnRTTlHb%h3G(k$w7UxEmN`$Ez zrB9KHXGqW7U?VkF3V8$$&1-~2j(SVqA%UEM2Ag=NhXo6@7QM33_Z=*I?9LX27UGNrPdl*8fhhxPRk!rQlR&d&bscDwiP z-HkEJVk}b%A++Y3qPv|k5dZ)H{I8VC@%W;6Rus>QYUSkQb{C1sDJT zpq8rHZ%SoZPEtzGpa1r9|79vuwHQK(F<$>9x7;@(0001gn5k;HA%yXGJQxg$qL`GE zlu}A%j9D`BtsB2m0002oT!YhKFxcPQFUzu#HL4Y{D8K*!0AH2y_@XF^ot>Q+BAQK79S@_*1jh%JW=q3NQeF06@K6zx^myvUqxSdU*Ke=;P7i z;$nZZKi`@clmZL@08mR=jAcqy0Z!rHyP)5{|Lgqx^YYU2=8v20c3WHuFaQ8RU0t=` z8UOG+`7*gkUsgIRyJz1=sZ^1sbCr4(bl`|V1v*K5yfzX~t_ z0KnH(BE~p<3?Y=0va{0J*x1PPT>Djk0RRAM-FUO>PqIc9LyTFhX1}YetM|XVpXYg& zHD+#*Mgax@0H~Sjf3TL8mLIM^Tw7bK=Dpo+H_!9(@;)TvUy~sV+a2H^00030{{sLY Wz41u?XT!(<0000ewvS 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 literal 0 HcmV?d00001 diff --git a/assets/share/dungeon/ui_list/OCR_DUNGEON_NAME_ROGUE.png b/assets/share/dungeon/ui_list/OCR_DUNGEON_NAME_ROGUE.png new file mode 100644 index 0000000000000000000000000000000000000000..3dd619f0037218537f2c698c021a1e1771715b0c GIT binary patch literal 19772 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 literal 0 HcmV?d00001 diff --git a/assets/share/dungeon/ui_list/OCR_DUNGEON_TELEPORT.png b/assets/share/dungeon/ui_list/OCR_DUNGEON_TELEPORT.png new file mode 100644 index 0000000000000000000000000000000000000000..5c1c74d8aa6f5a4dbfbda13a2eb81d40782d0394 GIT binary patch literal 47126 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 literal 0 HcmV?d00001 diff --git a/dev_tools/keywords/dungeon_list.py b/dev_tools/keywords/dungeon_list.py index f9f67a902..93403a078 100644 --- a/dev_tools/keywords/dungeon_list.py +++ b/dev_tools/keywords/dungeon_list.py @@ -122,16 +122,27 @@ class GenerateDungeonList(GenerateKeyword): dungeon['name'] = 'Divergent_Universe_' + dungeon['name'] if 100 < dungeon['dungeon_id'] < 200: dungeon['name'] = 'Simulated_Universe_' + dungeon['name'] - # Reverse Divergent_Universe - start = 0 - end = 0 - for index, dungeon in enumerate(dungeons): - if dungeon['name'].startswith('Divergent_Universe'): - if start == 0: - start = index - end = index + 1 - if start > 0 and end > 0: - dungeons = dungeons[:start] + dungeons[start:end][::-1] + dungeons[end:] + + # Reverse dungeon list, latest at top + def reverse_on_name(d, prefix): + start = 0 + end = 0 + 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: + 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 diff --git a/tasks/daily/daily_quest.py b/tasks/daily/daily_quest.py index a5d7a9d7b..d60d2ad5a 100644 --- a/tasks/daily/daily_quest.py +++ b/tasks/daily/daily_quest.py @@ -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 diff --git a/tasks/dungeon/assets/assets_dungeon_ui.py b/tasks/dungeon/assets/assets_dungeon_ui.py index ba77ca705..ba4730031 100644 --- a/tasks/dungeon/assets/assets_dungeon_ui.py +++ b/tasks/dungeon/assets/assets_dungeon_ui.py @@ -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( diff --git a/tasks/dungeon/assets/assets_dungeon_ui_list.py b/tasks/dungeon/assets/assets_dungeon_ui_list.py new file mode 100644 index 000000000..275e63cb8 --- /dev/null +++ b/tasks/dungeon/assets/assets_dungeon_ui_list.py @@ -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), + ), +) diff --git a/tasks/dungeon/dungeon.py b/tasks/dungeon/dungeon.py index c628cd15e..0da8d343b 100644 --- a/tasks/dungeon/dungeon.py +++ b/tasks/dungeon/dungeon.py @@ -213,7 +213,7 @@ class Dungeon(DungeonStamina, DungeonEvent, Combat): elif require and not self.support_once: # Run with support all the way return self._dungeon_run(dungeon=dungeon, team=team, wave_limit=0, - support_character=self.config.DungeonSupport_Character) + support_character=self.config.DungeonSupport_Character) else: # Normal run @@ -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 diff --git a/tasks/dungeon/keywords/dungeon.py b/tasks/dungeon/keywords/dungeon.py index 48e14fa7e..8a8648b64 100644 --- a/tasks/dungeon/keywords/dungeon.py +++ b/tasks/dungeon/keywords/dungeon.py @@ -3,38 +3,38 @@ from .classes import DungeonList # This file was auto-generated, do not modify it manually. To generate: # ``` python -m dev_tools.keyword_extract ``` -Calyx_Golden_Memories_Jarilo_VI = DungeonList( +Calyx_Golden_Memories_Penacony = DungeonList( id=1, - name='Calyx_Golden_Memories_Jarilo_VI', + name='Calyx_Golden_Memories_Penacony', cn='回忆之蕾', cht='回憶之蕾', en='Bud of Memories', jp='回憶の蕾', es='Flor de los recuerdos', - dungeon_id=1001, - plane_id=2010101, + dungeon_id=1014, + plane_id=2031301, ) -Calyx_Golden_Aether_Jarilo_VI = DungeonList( +Calyx_Golden_Aether_Penacony = DungeonList( id=2, - name='Calyx_Golden_Aether_Jarilo_VI', + name='Calyx_Golden_Aether_Penacony', cn='以太之蕾', cht='乙太之蕾', en='Bud of Aether', jp='エーテルの蕾', es='Flor de éter', - dungeon_id=1002, - plane_id=2011101, + dungeon_id=1015, + plane_id=2031201, ) -Calyx_Golden_Treasures_Jarilo_VI = DungeonList( +Calyx_Golden_Treasures_Penacony = DungeonList( id=3, - name='Calyx_Golden_Treasures_Jarilo_VI', + name='Calyx_Golden_Treasures_Penacony', cn='藏珍之蕾', cht='藏珍之蕾', en='Bud of Treasures', jp='秘蔵の蕾', es='Flor de tesoros', - dungeon_id=1003, - plane_id=2012101, + dungeon_id=1016, + plane_id=2031101, ) Calyx_Golden_Memories_The_Xianzhou_Luofu = DungeonList( id=4, @@ -69,38 +69,38 @@ Calyx_Golden_Treasures_The_Xianzhou_Luofu = DungeonList( dungeon_id=1013, plane_id=2022201, ) -Calyx_Golden_Memories_Penacony = DungeonList( +Calyx_Golden_Memories_Jarilo_VI = DungeonList( id=7, - name='Calyx_Golden_Memories_Penacony', + name='Calyx_Golden_Memories_Jarilo_VI', cn='回忆之蕾', cht='回憶之蕾', en='Bud of Memories', jp='回憶の蕾', es='Flor de los recuerdos', - dungeon_id=1014, - plane_id=2031301, + dungeon_id=1001, + plane_id=2010101, ) -Calyx_Golden_Aether_Penacony = DungeonList( +Calyx_Golden_Aether_Jarilo_VI = DungeonList( id=8, - name='Calyx_Golden_Aether_Penacony', + name='Calyx_Golden_Aether_Jarilo_VI', cn='以太之蕾', cht='乙太之蕾', en='Bud of Aether', jp='エーテルの蕾', es='Flor de éter', - dungeon_id=1015, - plane_id=2031201, + dungeon_id=1002, + plane_id=2011101, ) -Calyx_Golden_Treasures_Penacony = DungeonList( +Calyx_Golden_Treasures_Jarilo_VI = DungeonList( id=9, - name='Calyx_Golden_Treasures_Penacony', + name='Calyx_Golden_Treasures_Jarilo_VI', cn='藏珍之蕾', cht='藏珍之蕾', en='Bud of Treasures', jp='秘蔵の蕾', es='Flor de tesoros', - dungeon_id=1016, - plane_id=2031101, + dungeon_id=1003, + plane_id=2012101, ) Calyx_Crimson_Destruction_Herta_StorageZone = DungeonList( id=10, @@ -476,107 +476,8 @@ Stagnant_Shadow_Gloam = DungeonList( dungeon_id=1121, plane_id=2033201, ) -Cavern_of_Corrosion_Path_of_Gelid_Wind = DungeonList( - id=44, - name='Cavern_of_Corrosion_Path_of_Gelid_Wind', - cn='霜风之径', - cht='霜風之徑', - en='Path of Gelid Wind', - jp='霜風の路', - es='Senda del viento gélido', - dungeon_id=1201, - plane_id=2000201, -) -Cavern_of_Corrosion_Path_of_Jabbing_Punch = DungeonList( - id=45, - name='Cavern_of_Corrosion_Path_of_Jabbing_Punch', - cn='迅拳之径', - cht='迅拳之徑', - en='Path of Jabbing Punch', - jp='迅拳の路', - es='Senda de los puños rápidos', - dungeon_id=1202, - plane_id=2013101, -) -Cavern_of_Corrosion_Path_of_Drifting = DungeonList( - id=46, - name='Cavern_of_Corrosion_Path_of_Drifting', - cn='漂泊之径', - cht='漂泊之徑', - en='Path of Drifting', - jp='漂泊の路', - es='Senda de la deriva', - dungeon_id=1203, - plane_id=2013201, -) -Cavern_of_Corrosion_Path_of_Providence = DungeonList( - id=47, - name='Cavern_of_Corrosion_Path_of_Providence', - cn='睿治之径', - cht='睿治之徑', - en='Path of Providence', - jp='睿治の路', - es='Senda de la providencia', - dungeon_id=1204, - plane_id=2013401, -) -Cavern_of_Corrosion_Path_of_Holy_Hymn = DungeonList( - id=48, - name='Cavern_of_Corrosion_Path_of_Holy_Hymn', - cn='圣颂之径', - cht='聖頌之徑', - en='Path of Holy Hymn', - jp='聖頌の路', - es='Senda del himno sagrado', - dungeon_id=1205, - plane_id=2021101, -) -Cavern_of_Corrosion_Path_of_Conflagration = DungeonList( - id=49, - name='Cavern_of_Corrosion_Path_of_Conflagration', - cn='野焰之径', - cht='野焰之徑', - en='Path of Conflagration', - jp='野焔の路', - es='Senda de la conflagración', - dungeon_id=1206, - plane_id=2021201, -) -Cavern_of_Corrosion_Path_of_Elixir_Seekers = DungeonList( - id=50, - name='Cavern_of_Corrosion_Path_of_Elixir_Seekers', - cn='药使之径', - cht='藥使之徑', - en='Path of Elixir Seekers', - jp='薬使の路', - es='Senda de los elixires', - dungeon_id=1207, - plane_id=2023101, -) -Cavern_of_Corrosion_Path_of_Darkness = DungeonList( - id=51, - name='Cavern_of_Corrosion_Path_of_Darkness', - cn='幽冥之径', - cht='幽冥之徑', - en='Path of Darkness', - jp='幽冥の路', - es='Senda de la oscuridad', - dungeon_id=1208, - plane_id=2022301, -) -Cavern_of_Corrosion_Path_of_Dreamdive = DungeonList( - id=52, - name='Cavern_of_Corrosion_Path_of_Dreamdive', - cn='梦潜之径', - cht='夢潛之徑', - en='Path of Dreamdive', - jp='夢潜の路', - es='Senda de los sueños', - dungeon_id=1209, - plane_id=2031101, -) Cavern_of_Corrosion_Path_of_Cavalier = DungeonList( - id=53, + id=44, name='Cavern_of_Corrosion_Path_of_Cavalier', cn='勇骑之径', cht='勇騎之徑', @@ -586,52 +487,118 @@ Cavern_of_Corrosion_Path_of_Cavalier = DungeonList( dungeon_id=1210, plane_id=2033201, ) -Echo_of_War_Destruction_Beginning = DungeonList( - id=54, - name='Echo_of_War_Destruction_Beginning', - cn='毁灭的开端•历战余响', - cht='毀滅的開端•歷戰餘響', - en="Echo of War: Destruction's Beginning", - jp='歴戦余韻・壊滅の始まり', - es='El principio de la Destrucción', - dungeon_id=1301, - plane_id=2000301, +Cavern_of_Corrosion_Path_of_Dreamdive = DungeonList( + id=45, + name='Cavern_of_Corrosion_Path_of_Dreamdive', + cn='梦潜之径', + cht='夢潛之徑', + en='Path of Dreamdive', + jp='夢潜の路', + es='Senda de los sueños', + dungeon_id=1209, + plane_id=2031101, ) -Echo_of_War_End_of_the_Eternal_Freeze = DungeonList( - id=55, - name='Echo_of_War_End_of_the_Eternal_Freeze', - cn='寒潮的落幕•历战余响', - cht='寒潮的落幕•歷戰餘響', - en='Echo of War: End of the Eternal Freeze', - jp='歴戦余韻・寒波の幕切れ', - es='El fin del Hielo Eterno', - dungeon_id=1302, +Cavern_of_Corrosion_Path_of_Darkness = DungeonList( + id=46, + name='Cavern_of_Corrosion_Path_of_Darkness', + cn='幽冥之径', + cht='幽冥之徑', + en='Path of Darkness', + jp='幽冥の路', + es='Senda de la oscuridad', + dungeon_id=1208, + plane_id=2022301, +) +Cavern_of_Corrosion_Path_of_Elixir_Seekers = DungeonList( + id=47, + name='Cavern_of_Corrosion_Path_of_Elixir_Seekers', + cn='药使之径', + cht='藥使之徑', + en='Path of Elixir Seekers', + jp='薬使の路', + es='Senda de los elixires', + dungeon_id=1207, + plane_id=2023101, +) +Cavern_of_Corrosion_Path_of_Conflagration = DungeonList( + id=48, + name='Cavern_of_Corrosion_Path_of_Conflagration', + cn='野焰之径', + cht='野焰之徑', + en='Path of Conflagration', + jp='野焔の路', + es='Senda de la conflagración', + dungeon_id=1206, + plane_id=2021201, +) +Cavern_of_Corrosion_Path_of_Holy_Hymn = DungeonList( + id=49, + name='Cavern_of_Corrosion_Path_of_Holy_Hymn', + cn='圣颂之径', + cht='聖頌之徑', + en='Path of Holy Hymn', + jp='聖頌の路', + es='Senda del himno sagrado', + dungeon_id=1205, + plane_id=2021101, +) +Cavern_of_Corrosion_Path_of_Providence = DungeonList( + id=50, + name='Cavern_of_Corrosion_Path_of_Providence', + cn='睿治之径', + cht='睿治之徑', + en='Path of Providence', + jp='睿治の路', + es='Senda de la providencia', + dungeon_id=1204, plane_id=2013401, ) -Echo_of_War_Divine_Seed = DungeonList( - id=56, - name='Echo_of_War_Divine_Seed', - cn='不死的神实•历战余响', - cht='不死的神實•歷戰餘響', - en='Echo of War: Divine Seed', - jp='歴戦余韻・不死の神実', - es='Semilla divina', - dungeon_id=1303, - plane_id=2023201, +Cavern_of_Corrosion_Path_of_Drifting = DungeonList( + id=51, + name='Cavern_of_Corrosion_Path_of_Drifting', + cn='漂泊之径', + cht='漂泊之徑', + en='Path of Drifting', + jp='漂泊の路', + es='Senda de la deriva', + dungeon_id=1203, + plane_id=2013201, ) -Echo_of_War_Borehole_Planet_Old_Crater = DungeonList( - id=57, - name='Echo_of_War_Borehole_Planet_Old_Crater', - cn='蛀星的旧靥•历战余响', - cht='蛀星的舊靨•歷戰餘響', - en="Echo of War: Borehole Planet's Old Crater", - jp='歴戦余韻・星を蝕む往日の面影', - es='Cráter del planeta devorado', - dungeon_id=1304, - plane_id=2000401, +Cavern_of_Corrosion_Path_of_Jabbing_Punch = DungeonList( + id=52, + name='Cavern_of_Corrosion_Path_of_Jabbing_Punch', + cn='迅拳之径', + cht='迅拳之徑', + en='Path of Jabbing Punch', + jp='迅拳の路', + es='Senda de los puños rápidos', + dungeon_id=1202, + plane_id=2013101, +) +Cavern_of_Corrosion_Path_of_Gelid_Wind = DungeonList( + id=53, + name='Cavern_of_Corrosion_Path_of_Gelid_Wind', + cn='霜风之径', + cht='霜風之徑', + en='Path of Gelid Wind', + jp='霜風の路', + es='Senda del viento gélido', + dungeon_id=1201, + plane_id=2000201, +) +Echo_of_War_Inner_Beast_Battlefield = DungeonList( + id=54, + name='Echo_of_War_Inner_Beast_Battlefield', + cn='心兽的战场•历战余响', + cht='心獸的戰場•歷戰餘響', + en="Echo of War: Inner Beast's Battlefield", + jp='歴戦余韻・心獣の戦場', + es='Campo de batalla de la bestia interior', + dungeon_id=1306, + plane_id=2024201, ) Echo_of_War_Salutations_of_Ashen_Dreams = DungeonList( - id=58, + id=55, name='Echo_of_War_Salutations_of_Ashen_Dreams', cn='尘梦的赞礼•历战余响', cht='塵夢的讚禮•歷戰餘響', @@ -641,16 +608,49 @@ Echo_of_War_Salutations_of_Ashen_Dreams = DungeonList( dungeon_id=1305, plane_id=2033201, ) -Echo_of_War_Inner_Beast_Battlefield = DungeonList( +Echo_of_War_Borehole_Planet_Old_Crater = DungeonList( + id=56, + name='Echo_of_War_Borehole_Planet_Old_Crater', + cn='蛀星的旧靥•历战余响', + cht='蛀星的舊靨•歷戰餘響', + en="Echo of War: Borehole Planet's Old Crater", + jp='歴戦余韻・星を蝕む往日の面影', + es='Cráter del planeta devorado', + dungeon_id=1304, + plane_id=2000401, +) +Echo_of_War_Divine_Seed = DungeonList( + id=57, + name='Echo_of_War_Divine_Seed', + cn='不死的神实•历战余响', + cht='不死的神實•歷戰餘響', + en='Echo of War: Divine Seed', + jp='歴戦余韻・不死の神実', + es='Semilla divina', + dungeon_id=1303, + plane_id=2023201, +) +Echo_of_War_End_of_the_Eternal_Freeze = DungeonList( + id=58, + name='Echo_of_War_End_of_the_Eternal_Freeze', + cn='寒潮的落幕•历战余响', + cht='寒潮的落幕•歷戰餘響', + en='Echo of War: End of the Eternal Freeze', + jp='歴戦余韻・寒波の幕切れ', + es='El fin del Hielo Eterno', + dungeon_id=1302, + plane_id=2013401, +) +Echo_of_War_Destruction_Beginning = DungeonList( id=59, - name='Echo_of_War_Inner_Beast_Battlefield', - cn='心兽的战场•历战余响', - cht='心獸的戰場•歷戰餘響', - en="Echo of War: Inner Beast's Battlefield", - jp='歴戦余韻・心獣の戦場', - es='Campo de batalla de la bestia interior', - dungeon_id=1306, - plane_id=2024201, + name='Echo_of_War_Destruction_Beginning', + cn='毁灭的开端•历战余响', + cht='毀滅的開端•歷戰餘響', + en="Echo of War: Destruction's Beginning", + jp='歴戦余韻・壊滅の始まり', + es='El principio de la Destrucción', + dungeon_id=1301, + plane_id=2000301, ) Simulated_Universe_World_1 = DungeonList( id=60, diff --git a/tasks/dungeon/stamina.py b/tasks/dungeon/stamina.py index 41fd56354..092cd3bd7 100644 --- a/tasks/dungeon/stamina.py +++ b/tasks/dungeon/stamina.py @@ -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): diff --git a/tasks/dungeon/ui.py b/tasks/dungeon/ui.py deleted file mode 100644 index e558d038d..000000000 --- a/tasks/dungeon/ui.py +++ /dev/null @@ -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 diff --git a/tasks/dungeon/ui/interact.py b/tasks/dungeon/ui/interact.py new file mode 100644 index 000000000..89be8ba23 --- /dev/null +++ b/tasks/dungeon/ui/interact.py @@ -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 diff --git a/tasks/dungeon/ui/llist.py b/tasks/dungeon/ui/llist.py new file mode 100644 index 000000000..b47671c16 --- /dev/null +++ b/tasks/dungeon/ui/llist.py @@ -0,0 +1,385 @@ +import re + +import cv2 +from pponnxcr.predict_system import BoxedResult + +from module.base.base import ModuleBase +from module.base.decorator import run_once +from module.base.timer import Timer +from module.base.utils import area_center, 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 = 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') + self.limit_entrance = False + + def detect_and_ocr(self, image, direct_ocr=False) -> list[BoxedResult]: + if self.button != OCR_DUNGEON_NAME: + 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 + + +class OcrDungeonListUsingPlane(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_Golden and dungeon.plane == plane: + return dungeon + return plane + + +class OcrDungeonListLimitEntrance(OcrDungeonList): + def __init__(self, *args, **kwargs): + super().__init__(*args, **kwargs) + self.limit_entrance = True + + +class OcrDungeonListUsingPlaneLimitEntrance(OcrDungeonListUsingPlane, OcrDungeonListLimitEntrance): + pass + + +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 = OcrDungeonListUsingPlaneLimitEntrance + else: + self.ocr_class = OcrDungeonListUsingPlane + 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( + 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.use_plane = bool(dungeon.is_Calyx) + 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.use_plane = bool(dungeon.is_Calyx_Golden) + 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.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}') + 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 + + self.device.screenshot_interval_set() diff --git a/tasks/dungeon/ui/nav.py b/tasks/dungeon/ui/nav.py new file mode 100644 index 000000000..c173bb883 --- /dev/null +++ b/tasks/dungeon/ui/nav.py @@ -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 diff --git a/tasks/dungeon/state.py b/tasks/dungeon/ui/state.py similarity index 100% rename from tasks/dungeon/state.py rename to tasks/dungeon/ui/state.py diff --git a/tasks/dungeon/ui/ui.py b/tasks/dungeon/ui/ui.py new file mode 100644 index 000000000..ad9c4042a --- /dev/null +++ b/tasks/dungeon/ui/ui.py @@ -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 diff --git a/tasks/dungeon/ui_rogue.py b/tasks/dungeon/ui/ui_rogue.py similarity index 93% rename from tasks/dungeon/ui_rogue.py rename to tasks/dungeon/ui/ui_rogue.py index 1d2304115..a73968cf5 100644 --- a/tasks/dungeon/ui_rogue.py +++ b/tasks/dungeon/ui/ui_rogue.py @@ -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): """ diff --git a/tasks/dungeon/weekly.py b/tasks/dungeon/weekly.py index 1fb29992e..616035a23 100644 --- a/tasks/dungeon/weekly.py +++ b/tasks/dungeon/weekly.py @@ -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 diff --git a/tasks/forgotten_hall/ui.py b/tasks/forgotten_hall/ui.py index 08b1aa7a8..98dfc1a91 100644 --- a/tasks/forgotten_hall/ui.py +++ b/tasks/forgotten_hall/ui.py @@ -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}') diff --git a/tasks/ornament/combat.py b/tasks/ornament/combat.py index c1c6c730c..5d880ea2d 100644 --- a/tasks/ornament/combat.py +++ b/tasks/ornament/combat.py @@ -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 * diff --git a/tasks/rogue/entry/entry.py b/tasks/rogue/entry/entry.py index 6a94b51b9..f18019b24 100644 --- a/tasks/rogue/entry/entry.py +++ b/tasks/rogue/entry/entry.py @@ -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, diff --git a/tasks/rogue/event/reward.py b/tasks/rogue/event/reward.py index a280c24ad..b7937005f 100644 --- a/tasks/rogue/event/reward.py +++ b/tasks/rogue/event/reward.py @@ -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 From 706c5c1f7bfaac393943db64e7ee04de30858ca1 Mon Sep 17 00:00:00 2001 From: LmeSzinc <37934724+LmeSzinc@users.noreply.github.com> Date: Tue, 10 Sep 2024 23:44:13 +0800 Subject: [PATCH 5/7] Fix: Echo of war navigation --- tasks/dungeon/ui/llist.py | 89 ++++++++++++++++++++++----------------- 1 file changed, 51 insertions(+), 38 deletions(-) diff --git a/tasks/dungeon/ui/llist.py b/tasks/dungeon/ui/llist.py index b47671c16..e11e3efe8 100644 --- a/tasks/dungeon/ui/llist.py +++ b/tasks/dungeon/ui/llist.py @@ -4,9 +4,10 @@ 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_offset, crop, image_size +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 @@ -37,7 +38,8 @@ class OcrDungeonName(Ocr): result = re.sub(r'-[VⅤ][IⅠ]', '-Ⅵ', result) # 苏乐达™热砂海选会场 - result = re.sub(r'(苏乐达|蘇樂達|SoulGlad|スラーダ|FelizAlma)[rtT]*M', r'\1', result) + result = re.sub(r'(苏乐达|蘇樂達|SoulGlad|スラーダ|FelizAlma)[rtT]*M*', r'\1', result) + result = re.sub(r'["\']', '', result) result = super().after_process(result) @@ -64,10 +66,15 @@ 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 @@ -99,37 +106,38 @@ class OcrDungeonList(OcrDungeonName): return results - -class OcrDungeonListUsingPlane(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_Golden and dungeon.plane == plane: - return dungeon - return plane + 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 - -class OcrDungeonListLimitEntrance(OcrDungeonList): - def __init__(self, *args, **kwargs): - super().__init__(*args, **kwargs) - self.limit_entrance = True - - -class OcrDungeonListUsingPlaneLimitEntrance(OcrDungeonListUsingPlane, OcrDungeonListLimitEntrance): - pass + return matched 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 + # 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 @@ -139,19 +147,16 @@ class DraggableDungeonList(DraggableList): 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 = OcrDungeonListUsingPlaneLimitEntrance - else: - self.ocr_class = OcrDungeonListUsingPlane - else: - self.keyword_class = [DungeonList, DungeonEntrance] - if self.limit_entrance: - self.ocr_class = OcrDungeonListLimitEntrance - else: - self.ocr_class = OcrDungeonList + 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 @@ -238,7 +243,7 @@ class DungeonUIList(UI): else: DUNGEON_LIST.search_button = OCR_DUNGEON_NAME # Predict dungeon by plane name in calyxes where dungeons share the same names - DUNGEON_LIST.use_plane = bool(dungeon.is_Calyx) + DUNGEON_LIST.target_dungeon = dungeon DUNGEON_LIST.check_row_order = True # Insight dungeon @@ -281,7 +286,7 @@ class DungeonUIList(UI): logger.hr('Dungeon insight (sort)', level=2) logger.info(f'Dungeon insight: {dungeon}') DUNGEON_LIST.search_button = OCR_DUNGEON_NAME - DUNGEON_LIST.use_plane = bool(dungeon.is_Calyx_Golden) + DUNGEON_LIST.target_dungeon = dungeon DUNGEON_LIST.check_row_order = False for _ in range(3): @@ -342,7 +347,7 @@ class DungeonUIList(UI): out: COMBAT_PREPARE, FORGOTTEN_HALL_CHECK """ logger.hr('Dungeon enter', level=2) - DUNGEON_LIST.use_plane = bool(dungeon.is_Calyx_Crimson) + DUNGEON_LIST.target_dungeon = dungeon skip_first_load = skip_first_screenshot @run_once @@ -374,6 +379,8 @@ class DungeonUIList(UI): 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) @@ -383,3 +390,9 @@ class DungeonUIList(UI): 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) From c034a105958a1c6541f99d3f3ce4c494d8352de8 Mon Sep 17 00:00:00 2001 From: LmeSzinc <37934724+LmeSzinc@users.noreply.github.com> Date: Wed, 11 Sep 2024 00:00:34 +0800 Subject: [PATCH 6/7] =?UTF-8?q?Fix:=20[CN]=20Ocr=20result=20on=20word=20?= =?UTF-8?q?=E9=85=A9=E9=85=8A?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- tasks/planner/scan.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/tasks/planner/scan.py b/tasks/planner/scan.py index 76b1212a6..7919f72c2 100644 --- a/tasks/planner/scan.py +++ b/tasks/planner/scan.py @@ -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 From 292b123a3dc795b4340cf6a51e5df4f912755cf9 Mon Sep 17 00:00:00 2001 From: LmeSzinc <37934724+LmeSzinc@users.noreply.github.com> Date: Wed, 11 Sep 2024 00:19:11 +0800 Subject: [PATCH 7/7] Fix: Early access dungeon exited at COMBAT_PREPARE --- tasks/combat/combat.py | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/tasks/combat/combat.py b/tasks/combat/combat.py index 55728654f..ad8e9d611 100644 --- a/tasks/combat/combat.py +++ b/tasks/combat/combat.py @@ -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