diff --git a/.gitignore b/.gitignore index fcbdca7c1..f2d8ffb46 100644 --- a/.gitignore +++ b/.gitignore @@ -19,6 +19,14 @@ config/reloadflag config/reloadalas test.py test/ +resources/ +locales/ +*.pak +*.dll +*.dat +v8_context_snapshot.bin +snapshot_blob.bin +vk_swiftshader_icd.json # Created by .ignore support plugin (hsz.mobi) diff --git a/assets/character/Acheron.png b/assets/character/Acheron.png new file mode 100644 index 000000000..291378acd Binary files /dev/null and b/assets/character/Acheron.png differ diff --git a/assets/character/Gallagher.png b/assets/character/Gallagher.png new file mode 100644 index 000000000..dfea049b3 Binary files /dev/null and b/assets/character/Gallagher.png differ diff --git a/assets/cn/assignment/dispatch/ASSIGNMENT_START.SEARCH.png b/assets/cn/assignment/dispatch/ASSIGNMENT_START.SEARCH.png index cfe8dcbba..5123c6c94 100644 Binary files a/assets/cn/assignment/dispatch/ASSIGNMENT_START.SEARCH.png and b/assets/cn/assignment/dispatch/ASSIGNMENT_START.SEARCH.png differ diff --git a/assets/cn/assignment/dispatch/ASSIGNMENT_START.png b/assets/cn/assignment/dispatch/ASSIGNMENT_START.png index efd15ed00..94ecc6051 100644 Binary files a/assets/cn/assignment/dispatch/ASSIGNMENT_START.png and b/assets/cn/assignment/dispatch/ASSIGNMENT_START.png differ diff --git a/assets/en/assignment/dispatch/ASSIGNMENT_START.SEARCH.png b/assets/en/assignment/dispatch/ASSIGNMENT_START.SEARCH.png index 8104994df..6b625836c 100644 Binary files a/assets/en/assignment/dispatch/ASSIGNMENT_START.SEARCH.png and b/assets/en/assignment/dispatch/ASSIGNMENT_START.SEARCH.png differ diff --git a/assets/en/assignment/dispatch/ASSIGNMENT_START.png b/assets/en/assignment/dispatch/ASSIGNMENT_START.png index 2f7857c82..09815003f 100644 Binary files a/assets/en/assignment/dispatch/ASSIGNMENT_START.png and b/assets/en/assignment/dispatch/ASSIGNMENT_START.png differ diff --git a/assets/en/rogue/ui/CURIO_OBTAINED.2.png b/assets/en/rogue/ui/CURIO_OBTAINED.2.png new file mode 100644 index 000000000..c168c6400 Binary files /dev/null and b/assets/en/rogue/ui/CURIO_OBTAINED.2.png differ diff --git a/assets/share/assignment/dispatch/CHARACTER_1.png b/assets/share/assignment/dispatch/CHARACTER_1.png index ed0fa0469..a64234004 100644 Binary files a/assets/share/assignment/dispatch/CHARACTER_1.png and b/assets/share/assignment/dispatch/CHARACTER_1.png differ diff --git a/assets/share/assignment/dispatch/CHARACTER_1_SELECTED.png b/assets/share/assignment/dispatch/CHARACTER_1_SELECTED.png index c8ed4441b..2cf101dc3 100644 Binary files a/assets/share/assignment/dispatch/CHARACTER_1_SELECTED.png and b/assets/share/assignment/dispatch/CHARACTER_1_SELECTED.png differ diff --git a/assets/share/assignment/dispatch/CHARACTER_2.png b/assets/share/assignment/dispatch/CHARACTER_2.png index cb5cbbbe4..96ca4fe2a 100644 Binary files a/assets/share/assignment/dispatch/CHARACTER_2.png and b/assets/share/assignment/dispatch/CHARACTER_2.png differ diff --git a/assets/share/assignment/dispatch/CHARACTER_2_SELECTED.png b/assets/share/assignment/dispatch/CHARACTER_2_SELECTED.png index 2c784891e..0980134cc 100644 Binary files a/assets/share/assignment/dispatch/CHARACTER_2_SELECTED.png and b/assets/share/assignment/dispatch/CHARACTER_2_SELECTED.png differ diff --git a/assets/share/base/daemon/DUNGEON_EXIT.png b/assets/share/base/daemon/DUNGEON_EXIT.png new file mode 100644 index 000000000..44b396976 Binary files /dev/null and b/assets/share/base/daemon/DUNGEON_EXIT.png differ diff --git a/assets/share/base/daemon/TUTORIAL_CHECK.png b/assets/share/base/daemon/TUTORIAL_CHECK.png new file mode 100644 index 000000000..6d5698c99 Binary files /dev/null and b/assets/share/base/daemon/TUTORIAL_CHECK.png differ diff --git a/assets/share/base/daemon/TUTORIAL_CLOSE.png b/assets/share/base/daemon/TUTORIAL_CLOSE.png new file mode 100644 index 000000000..b3971bc63 Binary files /dev/null and b/assets/share/base/daemon/TUTORIAL_CLOSE.png differ diff --git a/assets/share/base/daemon/TUTORIAL_NEXT.png b/assets/share/base/daemon/TUTORIAL_NEXT.png new file mode 100644 index 000000000..80810a88b Binary files /dev/null and b/assets/share/base/daemon/TUTORIAL_NEXT.png differ diff --git a/assets/share/daily/synthesize_consumable/SYNTHESIZE_SCROLL.png b/assets/share/daily/synthesize_consumable/SYNTHESIZE_SCROLL.png index d3f240e78..fd5cb945f 100644 Binary files a/assets/share/daily/synthesize_consumable/SYNTHESIZE_SCROLL.png and b/assets/share/daily/synthesize_consumable/SYNTHESIZE_SCROLL.png differ diff --git a/assets/share/dungeon/event/OCR_DOUBLE_EVENT_REMAIN.png b/assets/share/dungeon/event/OCR_DOUBLE_EVENT_REMAIN.png index 216c47be3..0d923be6b 100644 Binary files a/assets/share/dungeon/event/OCR_DOUBLE_EVENT_REMAIN.png and b/assets/share/dungeon/event/OCR_DOUBLE_EVENT_REMAIN.png differ diff --git a/assets/share/item/consumable_usage/ITEM_CONSUMABLE_SCROLL.png b/assets/share/item/consumable_usage/ITEM_CONSUMABLE_SCROLL.png index a22564196..0c2afd50c 100644 Binary files a/assets/share/item/consumable_usage/ITEM_CONSUMABLE_SCROLL.png and b/assets/share/item/consumable_usage/ITEM_CONSUMABLE_SCROLL.png differ diff --git a/assets/share/login/LOGIN_CONFIRM.2.png b/assets/share/login/LOGIN_CONFIRM.2.png new file mode 100644 index 000000000..0a57da31e Binary files /dev/null and b/assets/share/login/LOGIN_CONFIRM.2.png differ diff --git a/assets/share/map/control/TECHNIQUE_POINT_0.SEARCH.png b/assets/share/map/control/TECHNIQUE_POINT_0.SEARCH.png new file mode 100644 index 000000000..114720cc9 Binary files /dev/null and b/assets/share/map/control/TECHNIQUE_POINT_0.SEARCH.png differ diff --git a/assets/share/map/control/TECHNIQUE_POINT_0.png b/assets/share/map/control/TECHNIQUE_POINT_0.png new file mode 100644 index 000000000..d1bab5e85 Binary files /dev/null and b/assets/share/map/control/TECHNIQUE_POINT_0.png differ diff --git a/assets/share/map/control/TECHNIQUE_POINT_1.SEARCH.png b/assets/share/map/control/TECHNIQUE_POINT_1.SEARCH.png new file mode 100644 index 000000000..e2c0b68e1 Binary files /dev/null and b/assets/share/map/control/TECHNIQUE_POINT_1.SEARCH.png differ diff --git a/assets/share/map/control/TECHNIQUE_POINT_1.png b/assets/share/map/control/TECHNIQUE_POINT_1.png index ea6201eaa..6f98d1bf9 100644 Binary files a/assets/share/map/control/TECHNIQUE_POINT_1.png and b/assets/share/map/control/TECHNIQUE_POINT_1.png differ diff --git a/assets/share/map/control/TECHNIQUE_POINT_2.png b/assets/share/map/control/TECHNIQUE_POINT_2.png index 1c8b28ae6..94f46fcc2 100644 Binary files a/assets/share/map/control/TECHNIQUE_POINT_2.png and b/assets/share/map/control/TECHNIQUE_POINT_2.png differ diff --git a/assets/share/map/control/TECHNIQUE_POINT_3.png b/assets/share/map/control/TECHNIQUE_POINT_3.png index d388277ab..7214bac51 100644 Binary files a/assets/share/map/control/TECHNIQUE_POINT_3.png and b/assets/share/map/control/TECHNIQUE_POINT_3.png differ diff --git a/assets/share/map/control/TECHNIQUE_POINT_4.png b/assets/share/map/control/TECHNIQUE_POINT_4.png index d6d9e5bf3..5037e1bd0 100644 Binary files a/assets/share/map/control/TECHNIQUE_POINT_4.png and b/assets/share/map/control/TECHNIQUE_POINT_4.png differ diff --git a/assets/share/map/control/TECHNIQUE_POINT_5.png b/assets/share/map/control/TECHNIQUE_POINT_5.png index f22c60117..9599b127a 100644 Binary files a/assets/share/map/control/TECHNIQUE_POINT_5.png and b/assets/share/map/control/TECHNIQUE_POINT_5.png differ diff --git a/config/template.json b/config/template.json index 1ef395cea..4c2aaf5d8 100644 --- a/config/template.json +++ b/config/template.json @@ -2,6 +2,7 @@ "Alas": { "Emulator": { "Serial": "auto", + "GameClient": "android", "PackageName": "auto", "GameLanguage": "auto", "ScreenshotMethod": "scrcpy", @@ -23,6 +24,11 @@ "ScreenshotInterval": 0.2, "CombatScreenshotInterval": 1.0, "WhenTaskQueueEmpty": "goto_main" + }, + "CloudStorage": { + "CloudRemainSeasonPass": {}, + "CloudRemainPaid": {}, + "CloudRemainFree": {} } }, "Restart": { diff --git a/dev_tools/button_extract.py b/dev_tools/button_extract.py index a45325055..67a623acc 100644 --- a/dev_tools/button_extract.py +++ b/dev_tools/button_extract.py @@ -92,8 +92,9 @@ def iter_images(): for server in ASSET_SERVER: for path, folders, files in os.walk(os.path.join(AzurLaneConfig.ASSETS_FOLDER, server)): for file in files: - file = os.path.join(path, file).replace('\\', '/') - yield AssetsImage(file) + if not file.startswith('.'): + file = os.path.join(path, file).replace('\\', '/') + yield AssetsImage(file) @dataclass diff --git a/dev_tools/keyword_extract.py b/dev_tools/keyword_extract.py index 5b2cc2947..d98d6a865 100644 --- a/dev_tools/keyword_extract.py +++ b/dev_tools/keyword_extract.py @@ -525,12 +525,14 @@ class KeywordExtract: ) try: from tasks.rogue.event.event import OcrRogueEventOption - except AttributeError: + except AttributeError as e: + logger.error(e) logger.critical( f'Importing OcrRogueEventOption fails, probably due to changes in {output_file}') try: from tasks.rogue.event.preset import STRATEGIES - except AttributeError: + except AttributeError as e: + logger.error(e) logger.critical( f'Importing preset strategies fails, probably due to changes in {output_file}') diff --git a/module/alas.py b/module/alas.py index 5abfd0ae7..34d1d7b53 100644 --- a/module/alas.py +++ b/module/alas.py @@ -62,6 +62,18 @@ class AzurLaneAutoScript: logger.exception(e) exit(1) + def restart(self): + raise NotImplemented + + def start(self): + raise NotImplemented + + def stop(self): + raise NotImplemented + + def goto_main(self): + raise NotImplemented + def run(self, command): try: self.device.screenshot() @@ -211,7 +223,7 @@ class AzurLaneAutoScript: method = self.config.Optimization_WhenTaskQueueEmpty if method == 'close_game': logger.info('Close game during wait') - self.device.app_stop() + self.run('stop') release_resources() self.device.release_during_wait() if not self.wait_until(task.next_run): diff --git a/module/base/base.py b/module/base/base.py index 7ecfff3c0..9a1dc41cb 100644 --- a/module/base/base.py +++ b/module/base/base.py @@ -6,6 +6,7 @@ from module.base.timer import Timer from module.base.utils import * from module.config.config import AzurLaneConfig from module.device.device import Device +from module.device.method.utils import HierarchyButton from module.logger import logger from module.webui.setting import cached_class_property @@ -132,9 +133,56 @@ class ModuleBase: return appear - appear = match_template + def xpath(self, xpath) -> HierarchyButton: + if isinstance(xpath, str): + return HierarchyButton(self.device.hierarchy, xpath) + else: + return xpath + + def xpath_appear(self, xpath: str, interval=0): + button = self.xpath(xpath) + + self.device.stuck_record_add(button) + + if interval and not self.interval_is_reached(button, interval=interval): + return False + + appear = bool(button) + + if appear and interval: + self.interval_reset(button, interval=interval) + + return appear + + def appear(self, button, interval=0, similarity=0.85): + """ + Args: + button (Button, ButtonWrapper, HierarchyButton, str): + interval (int, float): interval between two active events. + + Returns: + bool: + + Examples: + Template match: + ``` + self.device.screenshot() + self.appear(POPUP_CONFIRM) + ``` + + Hierarchy detection (detect elements with xpath): + ``` + self.device.dump_hierarchy() + self.appear('//*[@resource-id="..."]') + ``` + """ + if isinstance(button, (HierarchyButton, str)): + return self.xpath_appear(button, interval=interval) + else: + return self.match_template(button, interval=interval, similarity=similarity) def appear_then_click(self, button, interval=5, similarity=0.85): + button = self.xpath(button) appear = self.appear(button, interval=interval, similarity=similarity) if appear: self.device.click(button) diff --git a/module/config/argument/args.json b/module/config/argument/args.json index e06a570af..42a530a31 100644 --- a/module/config/argument/args.json +++ b/module/config/argument/args.json @@ -6,6 +6,14 @@ "value": "auto", "valuetype": "str" }, + "GameClient": { + "type": "select", + "value": "android", + "option": [ + "android", + "cloud_android" + ] + }, "PackageName": { "type": "select", "value": "auto", @@ -131,6 +139,26 @@ "close_game" ] } + }, + "CloudStorage": { + "CloudRemainSeasonPass": { + "type": "stored", + "value": {}, + "display": "hide", + "stored": "StoredInt" + }, + "CloudRemainPaid": { + "type": "stored", + "value": {}, + "display": "hide", + "stored": "StoredInt" + }, + "CloudRemainFree": { + "type": "stored", + "value": {}, + "display": "hide", + "stored": "StoredInt" + } } }, "Restart": { @@ -165,11 +193,13 @@ "Dungeon": { "Scheduler": { "Enable": { - "type": "checkbox", + "type": "state", "value": true, "option": [ - true, - false + true + ], + "option_bold": [ + true ] }, "NextRun": { @@ -205,8 +235,10 @@ "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_Abundance_Jarilo_BackwaterPass", + "Calyx_Crimson_Abundance_Luofu_FyxestrollGarden", "Calyx_Crimson_Erudition_Jarilo_RivetTown", "Calyx_Crimson_Harmony_Jarilo_RobotSettlement", "Calyx_Crimson_Harmony_Penacony_TheReverieDreamscape", @@ -216,6 +248,7 @@ "Stagnant_Shadow_Perdition", "Stagnant_Shadow_Blaze", "Stagnant_Shadow_Scorch", + "Stagnant_Shadow_Ire", "Stagnant_Shadow_Rime", "Stagnant_Shadow_Icicle", "Stagnant_Shadow_Nectar", @@ -243,7 +276,6 @@ "type": "select", "value": "Calyx_Golden_Treasures", "option": [ - "do_not_participate", "Calyx_Golden_Memories_Jarilo_VI", "Calyx_Golden_Memories_The_Xianzhou_Luofu", "Calyx_Golden_Memories_Penacony", @@ -256,8 +288,10 @@ "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_Abundance_Jarilo_BackwaterPass", + "Calyx_Crimson_Abundance_Luofu_FyxestrollGarden", "Calyx_Crimson_Erudition_Jarilo_RivetTown", "Calyx_Crimson_Harmony_Jarilo_RobotSettlement", "Calyx_Crimson_Harmony_Penacony_TheReverieDreamscape", @@ -269,7 +303,6 @@ "type": "select", "value": "Cavern_of_Corrosion_Path_of_Providence", "option": [ - "do_not_participate", "Cavern_of_Corrosion_Path_of_Gelid_Wind", "Cavern_of_Corrosion_Path_of_Jabbing_Punch", "Cavern_of_Corrosion_Path_of_Drifting", @@ -322,8 +355,10 @@ "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_Abundance_Jarilo_BackwaterPass", + "Calyx_Crimson_Abundance_Luofu_FyxestrollGarden", "Calyx_Crimson_Erudition_Jarilo_RivetTown", "Calyx_Crimson_Harmony_Jarilo_RobotSettlement", "Calyx_Crimson_Harmony_Penacony_TheReverieDreamscape", @@ -340,6 +375,7 @@ "Stagnant_Shadow_Perdition", "Stagnant_Shadow_Blaze", "Stagnant_Shadow_Scorch", + "Stagnant_Shadow_Ire", "Stagnant_Shadow_Rime", "Stagnant_Shadow_Icicle", "Stagnant_Shadow_Nectar", @@ -386,6 +422,7 @@ "value": "FirstCharacter", "option": [ "FirstCharacter", + "Acheron", "Argenti", "Arlan", "Asta", @@ -398,6 +435,7 @@ "DanHengImbibitorLunae", "DrRatio", "FuXuan", + "Gallagher", "Gepard", "Guinaifen", "Hanya", @@ -476,11 +514,13 @@ "DailyQuest": { "Scheduler": { "Enable": { - "type": "checkbox", + "type": "state", "value": true, "option": [ - true, - false + true + ], + "option_bold": [ + true ] }, "NextRun": { @@ -911,11 +951,13 @@ "BattlePass": { "Scheduler": { "Enable": { - "type": "checkbox", + "type": "state", "value": true, "option": [ - true, - false + true + ], + "option_bold": [ + true ] }, "NextRun": { @@ -996,11 +1038,13 @@ "Assignment": { "Scheduler": { "Enable": { - "type": "checkbox", + "type": "state", "value": true, "option": [ - true, - false + true + ], + "option_bold": [ + true ] }, "NextRun": { @@ -1292,6 +1336,7 @@ "value": "FirstCharacter", "option": [ "FirstCharacter", + "Acheron", "Argenti", "Arlan", "Asta", @@ -1304,6 +1349,7 @@ "DanHengImbibitorLunae", "DrRatio", "FuXuan", + "Gallagher", "Gepard", "Guinaifen", "Hanya", diff --git a/module/config/argument/argument.yaml b/module/config/argument/argument.yaml index 9e0274401..51c228e9a 100644 --- a/module/config/argument/argument.yaml +++ b/module/config/argument/argument.yaml @@ -18,6 +18,9 @@ Emulator: Serial: value: auto valuetype: str + GameClient: + value: android + option: [ android, cloud_android ] PackageName: value: auto option: [ auto, ] @@ -72,6 +75,13 @@ Optimization: WhenTaskQueueEmpty: value: goto_main option: [ stay_there, goto_main, close_game ] +CloudStorage: + CloudRemainSeasonPass: + stored: StoredInt + CloudRemainPaid: + stored: StoredInt + CloudRemainFree: + stored: StoredInt # ==================== Daily ==================== @@ -82,10 +92,10 @@ Dungeon: option: [ ] NameAtDoubleCalyx: value: Calyx_Golden_Treasures - option: [ do_not_participate, ] + option: [ ] NameAtDoubleRelic: value: Cavern_of_Corrosion_Path_of_Providence - option: [ do_not_participate, ] + option: [ ] Team: value: 1 option: [ 1, 2, 3, 4, 5, 6, 7, 8, 9 ] diff --git a/module/config/argument/override.yaml b/module/config/argument/override.yaml index bb458f39e..b38bca2a5 100644 --- a/module/config/argument/override.yaml +++ b/module/config/argument/override.yaml @@ -23,6 +23,34 @@ Restart: # ==================== Daily ==================== +Dungeon: + Scheduler: + Enable: + type: state + value: true + option: [ true, ] + option_bold: [ true, ] +DailyQuest: + Scheduler: + Enable: + type: state + value: true + option: [ true, ] + option_bold: [ true, ] +BattlePass: + Scheduler: + Enable: + type: state + value: true + option: [ true, ] + option_bold: [ true, ] +Assignment: + Scheduler: + Enable: + type: state + value: true + option: [ true, ] + option_bold: [ true, ] DataUpdate: Scheduler: Enable: diff --git a/module/config/argument/stored.json b/module/config/argument/stored.json index 55599ae90..f984b47e4 100644 --- a/module/config/argument/stored.json +++ b/module/config/argument/stored.json @@ -101,6 +101,42 @@ "order": 8, "color": "#fc8f8b" }, + "CloudRemainSeasonPass": { + "name": "CloudRemainSeasonPass", + "path": "Alas.CloudStorage.CloudRemainSeasonPass", + "i18n": "CloudStorage.CloudRemainSeasonPass.name", + "stored": "StoredInt", + "attrs": { + "time": "2020-01-01 00:00:00", + "value": 0 + }, + "order": 0, + "color": "#777777" + }, + "CloudRemainPaid": { + "name": "CloudRemainPaid", + "path": "Alas.CloudStorage.CloudRemainPaid", + "i18n": "CloudStorage.CloudRemainPaid.name", + "stored": "StoredInt", + "attrs": { + "time": "2020-01-01 00:00:00", + "value": 0 + }, + "order": 0, + "color": "#777777" + }, + "CloudRemainFree": { + "name": "CloudRemainFree", + "path": "Alas.CloudStorage.CloudRemainFree", + "i18n": "CloudStorage.CloudRemainFree.name", + "stored": "StoredInt", + "attrs": { + "time": "2020-01-01 00:00:00", + "value": 0 + }, + "order": 0, + "color": "#777777" + }, "Immersifier": { "name": "Immersifier", "path": "Dungeon.DungeonStorage.Immersifier", diff --git a/module/config/argument/task.yaml b/module/config/argument/task.yaml index 34a1a102c..5e10c85ea 100644 --- a/module/config/argument/task.yaml +++ b/module/config/argument/task.yaml @@ -13,6 +13,7 @@ Alas: - EmulatorInfo - Error - Optimization + - CloudStorage Restart: - Scheduler diff --git a/module/config/config.py b/module/config/config.py index 8a276ff90..6ba4e6d5a 100644 --- a/module/config/config.py +++ b/module/config/config.py @@ -176,6 +176,12 @@ class AzurLaneConfig(ConfigUpdater, ManualConfig, GeneratedConfig, ConfigWatcher self.data, keys="Alas.Optimization.CloseGameDuringWait", default=False ) + @property + def is_cloud_game(self): + return deep_get( + self.data, keys="Alas.Emulator.GameClient" + ) == 'cloud_android' + @cached_property def stored(self) -> StoredGenerated: stored = StoredGenerated() diff --git a/module/config/config_generated.py b/module/config/config_generated.py index 450762d34..3c5aedb2c 100644 --- a/module/config/config_generated.py +++ b/module/config/config_generated.py @@ -17,6 +17,7 @@ class GeneratedConfig: # Group `Emulator` Emulator_Serial = 'auto' + Emulator_GameClient = 'android' # android, cloud_android Emulator_PackageName = 'auto' # auto, CN-Official, CN-Bilibili, OVERSEA-America, OVERSEA-Asia, OVERSEA-Europe, OVERSEA-TWHKMO Emulator_GameLanguage = 'auto' # auto, cn, en Emulator_ScreenshotMethod = 'auto' # auto, ADB, ADB_nc, uiautomator2, aScreenCap, aScreenCap_nc, DroidCast, DroidCast_raw, scrcpy @@ -39,21 +40,26 @@ class GeneratedConfig: Optimization_CombatScreenshotInterval = 1.0 Optimization_WhenTaskQueueEmpty = 'goto_main' # stay_there, goto_main, close_game + # Group `CloudStorage` + CloudStorage_CloudRemainSeasonPass = {} + CloudStorage_CloudRemainPaid = {} + CloudStorage_CloudRemainFree = {} + # Group `Dungeon` - Dungeon_Name = 'Calyx_Golden_Treasures' # 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_The_Hunt_Jarilo_OutlyingSnowPlains, Calyx_Crimson_Abundance_Jarilo_BackwaterPass, Calyx_Crimson_Erudition_Jarilo_RivetTown, 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_Blaze, Stagnant_Shadow_Scorch, 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 - Dungeon_NameAtDoubleCalyx = 'Calyx_Golden_Treasures' # do_not_participate, 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_The_Hunt_Jarilo_OutlyingSnowPlains, Calyx_Crimson_Abundance_Jarilo_BackwaterPass, Calyx_Crimson_Erudition_Jarilo_RivetTown, 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' # do_not_participate, 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 + Dungeon_Name = 'Calyx_Golden_Treasures' # 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_Abundance_Jarilo_BackwaterPass, Calyx_Crimson_Abundance_Luofu_FyxestrollGarden, Calyx_Crimson_Erudition_Jarilo_RivetTown, 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_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 + Dungeon_NameAtDoubleCalyx = 'Calyx_Golden_Treasures' # 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_Abundance_Jarilo_BackwaterPass, Calyx_Crimson_Abundance_Luofu_FyxestrollGarden, Calyx_Crimson_Erudition_Jarilo_RivetTown, 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 Dungeon_Team = 1 # 1, 2, 3, 4, 5, 6, 7, 8, 9 # Group `DungeonDaily` DungeonDaily_CalyxGolden = 'Calyx_Golden_Treasures_Jarilo_VI' # do_not_achieve, 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 - DungeonDaily_CalyxCrimson = 'Calyx_Crimson_Destruction_Herta_StorageZone' # do_not_achieve, Calyx_Crimson_Destruction_Herta_StorageZone, Calyx_Crimson_Destruction_Luofu_ScalegorgeWaterscape, Calyx_Crimson_Preservation_Herta_SupplyZone, Calyx_Crimson_The_Hunt_Jarilo_OutlyingSnowPlains, Calyx_Crimson_Abundance_Jarilo_BackwaterPass, Calyx_Crimson_Erudition_Jarilo_RivetTown, Calyx_Crimson_Harmony_Jarilo_RobotSettlement, Calyx_Crimson_Harmony_Penacony_TheReverieDreamscape, Calyx_Crimson_Nihility_Jarilo_GreatMine, Calyx_Crimson_Nihility_Luofu_AlchemyCommission - DungeonDaily_StagnantShadow = 'Stagnant_Shadow_Quanta' # do_not_achieve, Stagnant_Shadow_Spike, Stagnant_Shadow_Perdition, Stagnant_Shadow_Blaze, Stagnant_Shadow_Scorch, 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 + DungeonDaily_CalyxCrimson = 'Calyx_Crimson_Destruction_Herta_StorageZone' # do_not_achieve, 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_Abundance_Jarilo_BackwaterPass, Calyx_Crimson_Abundance_Luofu_FyxestrollGarden, Calyx_Crimson_Erudition_Jarilo_RivetTown, Calyx_Crimson_Harmony_Jarilo_RobotSettlement, Calyx_Crimson_Harmony_Penacony_TheReverieDreamscape, Calyx_Crimson_Nihility_Jarilo_GreatMine, Calyx_Crimson_Nihility_Luofu_AlchemyCommission + DungeonDaily_StagnantShadow = 'Stagnant_Shadow_Quanta' # do_not_achieve, Stagnant_Shadow_Spike, Stagnant_Shadow_Perdition, 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 DungeonDaily_CavernOfCorrosion = 'Cavern_of_Corrosion_Path_of_Providence' # do_not_achieve, 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 # Group `DungeonSupport` DungeonSupport_Use = 'when_daily' # always_use, when_daily, do_not_use - DungeonSupport_Character = 'FirstCharacter' # FirstCharacter, Argenti, Arlan, Asta, Bailu, BlackSwan, Blade, Bronya, Clara, DanHeng, DanHengImbibitorLunae, DrRatio, FuXuan, Gepard, Guinaifen, Hanya, Herta, Himeko, Hook, Huohuo, JingYuan, Jingliu, Kafka, Luka, Luocha, Lynx, March7th, Misha, Natasha, Pela, Qingque, RuanMei, Sampo, Seele, Serval, SilverWolf, Sparkle, Sushang, Tingyun, TopazNumby, TrailblazerDestruction, TrailblazerPreservation, Welt, Xueyi, Yanqing, Yukong + DungeonSupport_Character = 'FirstCharacter' # FirstCharacter, Acheron, Argenti, Arlan, Asta, Bailu, BlackSwan, Blade, Bronya, Clara, DanHeng, DanHengImbibitorLunae, DrRatio, FuXuan, Gallagher, Gepard, Guinaifen, Hanya, Herta, Himeko, Hook, Huohuo, JingYuan, Jingliu, Kafka, Luka, Luocha, Lynx, March7th, Misha, Natasha, Pela, Qingque, RuanMei, Sampo, Seele, Serval, SilverWolf, Sparkle, Sushang, Tingyun, TopazNumby, TrailblazerDestruction, TrailblazerPreservation, Welt, Xueyi, Yanqing, Yukong # Group `DungeonStorage` DungeonStorage_TrailblazePower = {} diff --git a/module/config/config_updater.py b/module/config/config_updater.py index 0f10f4d41..3b83ed950 100644 --- a/module/config/config_updater.py +++ b/module/config/config_updater.py @@ -100,7 +100,7 @@ class ConfigGenerator: options=[dungeon.name for dungeon in DungeonList.instances.values() if dungeon.is_Echo_of_War]) # Insert characters from tasks.character.keywords import CharacterList - unsupported_characters = [] + unsupported_characters = ['Aventurine'] characters = [character.name for character in CharacterList.instances.values() if character.name not in unsupported_characters] option_add(keys='DungeonSupport.Character.option', options=characters) @@ -795,6 +795,9 @@ class ConfigUpdater: # Store immersifier in dungeon task if deep_get(data, keys='Rogue.RogueWorld.UseImmersifier') is True: deep_set(data, keys='Dungeon.Scheduler.Enable', value=True) + # Cloud settings + if deep_get(data, keys='Alas.Emulator.GameClient') == 'cloud_android': + deep_set(data, keys='Alas.Emulator.PackageName', value='CN-Official') return data @@ -842,6 +845,9 @@ class ConfigUpdater: yield 'Rogue.RogueWorld.UseImmersifier', True elif key == 'Rogue.RogueWorld.DoubleEvent' and value is True: yield 'Rogue.RogueWorld.UseImmersifier', True + elif key == 'Alas.Emulator.GameClient' and value == 'cloud_android': + yield 'Alas.Emulator.PackageName', 'CN-Official' + yield 'Alas.Optimization.WhenTaskQueueEmpty', 'close_game' def iter_hidden_args(self, data) -> t.Iterator[str]: """ diff --git a/module/config/i18n/en-US.json b/module/config/i18n/en-US.json index af3f38303..f42961a16 100644 --- a/module/config/i18n/en-US.json +++ b/module/config/i18n/en-US.json @@ -96,6 +96,12 @@ "name": "Serial", "help": "Common emulator Serial can be queried in the list below\nUse \"auto\" to auto-detect emulators, but if multiple emulators are running or use emulators that do not support auto-detect, \"auto\" cannot be used and serial must be filled in manually\nDefault serial for select emulators:\n- BlueStacks 127.0.0.1:5555\n- BlueStacks4 Hyper-V use \"bluestacks4-hyperv\", \"bluestacks4-hyperv-2\" for multi instance, and so on\n- BlueStacks5 Hyper-V use \"bluestacks5-hyperv\", \"bluestacks5-hyperv-1\" for multi instance, and so on\n- NoxPlayer 127.0.0.1:62001\n- NoxPlayer64bit 127.0.0.1:59865\n- MuMuPlayer/MuMuPlayer X 127.0.0.1:7555\n- MuMuPlayer12 127.0.0.1:16384\n- MemuPlayer 127.0.0.1:21503\n- LDPlayer emulator-5554 or 127.0.0.1:5555\n- WSA use \"wsa-0\" to make the game run in the background, which needs to be controlled or closed by third-party software\nIf there are multiple emulator instances running, the default is reserved for one of them and the others will use different serials to avoid conflicts\nOpen console.bat and run `adb devices` to find them or follow the emulator's official tutorial" }, + "GameClient": { + "name": "Game Client", + "help": "When using cloud, you will be automatically queued to log in. Cloud game is available in CN only", + "android": "Android client", + "cloud_android": "Cloud game android client" + }, "PackageName": { "name": "Game Server", "help": "Can't distinguish different regions of oversea servers, please select the server manually.", @@ -215,6 +221,24 @@ "close_game": "Close Game" } }, + "CloudStorage": { + "_info": { + "name": "CloudStorage._info.name", + "help": "CloudStorage._info.help" + }, + "CloudRemainSeasonPass": { + "name": "CloudStorage.CloudRemainSeasonPass.name", + "help": "CloudStorage.CloudRemainSeasonPass.help" + }, + "CloudRemainPaid": { + "name": "CloudStorage.CloudRemainPaid.name", + "help": "CloudStorage.CloudRemainPaid.help" + }, + "CloudRemainFree": { + "name": "CloudStorage.CloudRemainFree.name", + "help": "CloudStorage.CloudRemainFree.help" + } + }, "Dungeon": { "_info": { "name": "Dungeon Settings", @@ -235,8 +259,10 @@ "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)", + "Calyx_Crimson_Preservation_Penacony_ClockStudiosThemePark": "Trace: Preservation (Clock Studios Theme Park)", "Calyx_Crimson_The_Hunt_Jarilo_OutlyingSnowPlains": "Trace: The Hunt (Outlying Snow Plains)", "Calyx_Crimson_Abundance_Jarilo_BackwaterPass": "Trace: Abundance (Backwater Pass)", + "Calyx_Crimson_Abundance_Luofu_FyxestrollGarden": "Trace: Abundance (Fyxestroll Garden)", "Calyx_Crimson_Erudition_Jarilo_RivetTown": "Trace: Erudition (Rivet Town)", "Calyx_Crimson_Harmony_Jarilo_RobotSettlement": "Trace: The Harmony (Robot Settlement)", "Calyx_Crimson_Harmony_Penacony_TheReverieDreamscape": "Trace: The Harmony (The Reverie (Dreamscape))", @@ -246,18 +272,19 @@ "Stagnant_Shadow_Perdition": "Ascension: Physical (Hanya / Argenti)", "Stagnant_Shadow_Blaze": "Ascension: Fire (Himeko / Asta / Hook)", "Stagnant_Shadow_Scorch": "Ascension: Fire (Guinaifen / Topaz & Numby)", + "Stagnant_Shadow_Ire": "Ascension: Fire (Gallagher)", "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)", + "Stagnant_Shadow_Doom": "Ascension: Lightning (Kafka / Jing Yuan / Acheron)", "Stagnant_Shadow_Gust": "Ascension: Wind (Dan Heng / Bronya / Sampo)", "Stagnant_Shadow_Celestial": "Ascension: Wind (Blade / Huohuo / Black Swan)", "Stagnant_Shadow_Quanta": "Ascension: Quantum (Silver Wolf / Seele / Qingque)", "Stagnant_Shadow_Abomination": "Ascension: Quantum (Lynx / Fu Xuan / Xueyi)", "Stagnant_Shadow_Roast": "Ascension: Quantum (Sparkle)", "Stagnant_Shadow_Mirage": "Ascension: Imaginary (Welt / Luocha / Yukong)", - "Stagnant_Shadow_Puppetry": "Ascension: Imaginary (Dan Heng • Imbibitor Lunae / Dr. Ratio)", + "Stagnant_Shadow_Puppetry": "Ascension: Imaginary (Dan Heng • Imbibitor Lunae / Aventurine / Dr. Ratio)", "Cavern_of_Corrosion_Path_of_Gelid_Wind": "Relics: Ice Set & Wind Set (Path of Gelid Wind)", "Cavern_of_Corrosion_Path_of_Jabbing_Punch": "Relics: Physical Set & Break Effect Set (Path of Jabbing Punch)", "Cavern_of_Corrosion_Path_of_Drifting": "Relics: Healing Set & Musketeer Set (Path of Drifting)", @@ -271,7 +298,6 @@ "NameAtDoubleCalyx": { "name": "At Double Calyx Event, choose dungeon", "help": "Return to the default dungeon settings after double times exhausted", - "do_not_participate": "Dont participate in event", "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))", @@ -284,8 +310,10 @@ "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)", + "Calyx_Crimson_Preservation_Penacony_ClockStudiosThemePark": "Trace: Preservation (Clock Studios Theme Park)", "Calyx_Crimson_The_Hunt_Jarilo_OutlyingSnowPlains": "Trace: The Hunt (Outlying Snow Plains)", "Calyx_Crimson_Abundance_Jarilo_BackwaterPass": "Trace: Abundance (Backwater Pass)", + "Calyx_Crimson_Abundance_Luofu_FyxestrollGarden": "Trace: Abundance (Fyxestroll Garden)", "Calyx_Crimson_Erudition_Jarilo_RivetTown": "Trace: Erudition (Rivet Town)", "Calyx_Crimson_Harmony_Jarilo_RobotSettlement": "Trace: The Harmony (Robot Settlement)", "Calyx_Crimson_Harmony_Penacony_TheReverieDreamscape": "Trace: The Harmony (The Reverie (Dreamscape))", @@ -295,7 +323,6 @@ "NameAtDoubleRelic": { "name": "At Double Relic Event, choose dungeon", "help": "Return to the default dungeon settings after double times exhausted", - "do_not_participate": "Dont participate in event", "Cavern_of_Corrosion_Path_of_Gelid_Wind": "Relics: Ice Set & Wind Set (Path of Gelid Wind)", "Cavern_of_Corrosion_Path_of_Jabbing_Punch": "Relics: Physical Set & Break Effect Set (Path of Jabbing Punch)", "Cavern_of_Corrosion_Path_of_Drifting": "Relics: Healing Set & Musketeer Set (Path of Drifting)", @@ -346,8 +373,10 @@ "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)", + "Calyx_Crimson_Preservation_Penacony_ClockStudiosThemePark": "Trace: Preservation (Clock Studios Theme Park)", "Calyx_Crimson_The_Hunt_Jarilo_OutlyingSnowPlains": "Trace: The Hunt (Outlying Snow Plains)", "Calyx_Crimson_Abundance_Jarilo_BackwaterPass": "Trace: Abundance (Backwater Pass)", + "Calyx_Crimson_Abundance_Luofu_FyxestrollGarden": "Trace: Abundance (Fyxestroll Garden)", "Calyx_Crimson_Erudition_Jarilo_RivetTown": "Trace: Erudition (Rivet Town)", "Calyx_Crimson_Harmony_Jarilo_RobotSettlement": "Trace: The Harmony (Robot Settlement)", "Calyx_Crimson_Harmony_Penacony_TheReverieDreamscape": "Trace: The Harmony (The Reverie (Dreamscape))", @@ -362,18 +391,19 @@ "Stagnant_Shadow_Perdition": "Ascension: Physical (Hanya / Argenti)", "Stagnant_Shadow_Blaze": "Ascension: Fire (Himeko / Asta / Hook)", "Stagnant_Shadow_Scorch": "Ascension: Fire (Guinaifen / Topaz & Numby)", + "Stagnant_Shadow_Ire": "Ascension: Fire (Gallagher)", "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)", + "Stagnant_Shadow_Doom": "Ascension: Lightning (Kafka / Jing Yuan / Acheron)", "Stagnant_Shadow_Gust": "Ascension: Wind (Dan Heng / Bronya / Sampo)", "Stagnant_Shadow_Celestial": "Ascension: Wind (Blade / Huohuo / Black Swan)", "Stagnant_Shadow_Quanta": "Ascension: Quantum (Silver Wolf / Seele / Qingque)", "Stagnant_Shadow_Abomination": "Ascension: Quantum (Lynx / Fu Xuan / Xueyi)", "Stagnant_Shadow_Roast": "Ascension: Quantum (Sparkle)", "Stagnant_Shadow_Mirage": "Ascension: Imaginary (Welt / Luocha / Yukong)", - "Stagnant_Shadow_Puppetry": "Ascension: Imaginary (Dan Heng • Imbibitor Lunae / Dr. Ratio)" + "Stagnant_Shadow_Puppetry": "Ascension: Imaginary (Dan Heng • Imbibitor Lunae / Aventurine / Dr. Ratio)" }, "CavernOfCorrosion": { "name": "Clear Cavern of Corrosion 1 times", @@ -406,6 +436,7 @@ "name": "Support Character", "help": "Select a friend support character, if not found, select the default (first) role\nSupport character should not be the same as the character in the team, recommended to prioritize friends.", "FirstCharacter": "First Character", + "Acheron": "Acheron", "Argenti": "Argenti", "Arlan": "Arlan", "Asta": "Asta", @@ -418,6 +449,7 @@ "DanHengImbibitorLunae": "Dan Heng • Imbibitor Lunae", "DrRatio": "Dr. Ratio", "FuXuan": "Fu Xuan", + "Gallagher": "Gallagher", "Gepard": "Gepard", "Guinaifen": "Guinaifen", "Hanya": "Hanya", diff --git a/module/config/i18n/es-ES.json b/module/config/i18n/es-ES.json index 22be96fa2..2bcadc64c 100644 --- a/module/config/i18n/es-ES.json +++ b/module/config/i18n/es-ES.json @@ -96,6 +96,12 @@ "name": "Serial", "help": "Los serial de emuladores comunes pueden ser consultados aquí:\nUsa \"auto\" para detectar automáticamente el emulador, pero si hay varios ejecutando a la vez o no se puede detectar de forma automática, \"auto\" no podrá ser usado y tendrás que ajustarlo manualmente.\nSerial comunes de algunos emuladores:\n- BlueStacks 127.0.0.1:5555\n- BlueStacks4 Hyper-V usa \"bluestacks4-hyperv\", \"bluestacks4-hyperv-2\" para multi-instancia, etc...\n- BlueStacks5 Hyper-V usa \"bluestacks5-hyperv\", \"bluestacks5-hyperv-1\" para multi-instancia, etc...\n- NoxPlayer 127.0.0.1:62001\n- NoxPlayer64bit 127.0.0.1:59865\n- MuMuPlayer/MuMuPlayer X 127.0.0.1:7555\n- MuMuPlayer12 127.0.0.1:16384\n- MemuPlayer 127.0.0.1:21503\n- LDPlayer emulator-5554 or 127.0.0.1:5555\n- WSA usa \"wsa-0\" para ejecutar el juego en segundo plano, que será cerrado/controlado por software externo.\nSi hay varias instancias ejecutándose a la vez, se usará la predeterminada para la primera y las demás se reajustarán.\nAbre console.bat y ejecuta `adb devices` para encontrarlas o usa la guía oficial del emulador." }, + "GameClient": { + "name": "Cliente del juego", + "help": "Al usar la nube, automáticamente se pondrá en cola para iniciar sesión. El juego en la nube está disponible solo en CN", + "android": "Cliente Android", + "cloud_android": "Cliente de juego en la nube para Android" + }, "PackageName": { "name": "Región del juego", "help": "No es posible detectar regiones que no sean de China, por tanto, ajústalo manualmente si se da la situación.", @@ -215,6 +221,24 @@ "close_game": "Cerrar el juego" } }, + "CloudStorage": { + "_info": { + "name": "CloudStorage._info.name", + "help": "CloudStorage._info.help" + }, + "CloudRemainSeasonPass": { + "name": "CloudStorage.CloudRemainSeasonPass.name", + "help": "CloudStorage.CloudRemainSeasonPass.help" + }, + "CloudRemainPaid": { + "name": "CloudStorage.CloudRemainPaid.name", + "help": "CloudStorage.CloudRemainPaid.help" + }, + "CloudRemainFree": { + "name": "CloudStorage.CloudRemainFree.name", + "help": "CloudStorage.CloudRemainFree.help" + } + }, "Dungeon": { "_info": { "name": "Ajustes de Mazmorra", @@ -235,8 +259,10 @@ "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)", + "Calyx_Crimson_Preservation_Penacony_ClockStudiosThemePark": "Rastros: Conservación (Parque temático de los Estudios Reloj)", "Calyx_Crimson_The_Hunt_Jarilo_OutlyingSnowPlains": "Rastros: Cacería (Llanuras nevadas de las afueras)", "Calyx_Crimson_Abundance_Jarilo_BackwaterPass": "Rastros: Abundancia (Paso del Remanso)", + "Calyx_Crimson_Abundance_Luofu_FyxestrollGarden": "Rastros: Abundancia (Jardín del Sosiego)", "Calyx_Crimson_Erudition_Jarilo_RivetTown": "Rastros: Erudición (Villarremache)", "Calyx_Crimson_Harmony_Jarilo_RobotSettlement": "Rastros: Armonía (Asentamiento robot)", "Calyx_Crimson_Harmony_Penacony_TheReverieDreamscape": "Rastros: Armonía (Hotel Fantasía (paisaje onírico))", @@ -246,18 +272,19 @@ "Stagnant_Shadow_Perdition": "Ascension: Físico (Hanya / Argenti)", "Stagnant_Shadow_Blaze": "Ascension: Fuego (Himeko / Asta / Hook)", "Stagnant_Shadow_Scorch": "Ascension: Fuego (Guinaifen / Topaz y Conti)", + "Stagnant_Shadow_Ire": "Ascension: Fuego (Gallagher)", "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)", + "Stagnant_Shadow_Doom": "Ascension: Rayo (Kafka / Jing Yuan / Acheron)", "Stagnant_Shadow_Gust": "Ascension: Viento (Dan Heng / Bronya / Sampo)", "Stagnant_Shadow_Celestial": "Ascension: Viento (Blade / Huohuo / Cisne Negro)", "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 (Sparkle)", "Stagnant_Shadow_Mirage": "Ascension: Imaginario (Welt / Luocha / Yukong)", - "Stagnant_Shadow_Puppetry": "Ascension: Imaginario (Dan Heng - Imbibitor Lunae / Dr. Ratio)", + "Stagnant_Shadow_Puppetry": "Ascension: Imaginario (Dan Heng - Imbibitor Lunae / Aventurino / Dr. Ratio)", "Cavern_of_Corrosion_Path_of_Gelid_Wind": "Artefactos: Hielo y Viento (Senda del viento gélido)", "Cavern_of_Corrosion_Path_of_Jabbing_Punch": "Artefactos: Físico y Efecto de Ruptura (Senda de los puños rápidos)", "Cavern_of_Corrosion_Path_of_Drifting": "Artefactos: Curación y Pistolera de la espiga silvestre (Senda de la deriva)", @@ -271,7 +298,6 @@ "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", - "do_not_participate": "No participar en el 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))", @@ -284,8 +310,10 @@ "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)", + "Calyx_Crimson_Preservation_Penacony_ClockStudiosThemePark": "Rastros: Conservación (Parque temático de los Estudios Reloj)", "Calyx_Crimson_The_Hunt_Jarilo_OutlyingSnowPlains": "Rastros: Cacería (Llanuras nevadas de las afueras)", "Calyx_Crimson_Abundance_Jarilo_BackwaterPass": "Rastros: Abundancia (Paso del Remanso)", + "Calyx_Crimson_Abundance_Luofu_FyxestrollGarden": "Rastros: Abundancia (Jardín del Sosiego)", "Calyx_Crimson_Erudition_Jarilo_RivetTown": "Rastros: Erudición (Villarremache)", "Calyx_Crimson_Harmony_Jarilo_RobotSettlement": "Rastros: Armonía (Asentamiento robot)", "Calyx_Crimson_Harmony_Penacony_TheReverieDreamscape": "Rastros: Armonía (Hotel Fantasía (paisaje onírico))", @@ -295,7 +323,6 @@ "NameAtDoubleRelic": { "name": "En los eventos de x2 de Caverna de la corrosión", "help": "Se volverán a los ajustes predeterminados una vez se acaben los intentos del evento", - "do_not_participate": "No participar en el evento", "Cavern_of_Corrosion_Path_of_Gelid_Wind": "Artefactos: Hielo y Viento (Senda del viento gélido)", "Cavern_of_Corrosion_Path_of_Jabbing_Punch": "Artefactos: Físico y Efecto de Ruptura (Senda de los puños rápidos)", "Cavern_of_Corrosion_Path_of_Drifting": "Artefactos: Curación y Pistolera de la espiga silvestre (Senda de la deriva)", @@ -346,8 +373,10 @@ "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)", + "Calyx_Crimson_Preservation_Penacony_ClockStudiosThemePark": "Rastros: Conservación (Parque temático de los Estudios Reloj)", "Calyx_Crimson_The_Hunt_Jarilo_OutlyingSnowPlains": "Rastros: Cacería (Llanuras nevadas de las afueras)", "Calyx_Crimson_Abundance_Jarilo_BackwaterPass": "Rastros: Abundancia (Paso del Remanso)", + "Calyx_Crimson_Abundance_Luofu_FyxestrollGarden": "Rastros: Abundancia (Jardín del Sosiego)", "Calyx_Crimson_Erudition_Jarilo_RivetTown": "Rastros: Erudición (Villarremache)", "Calyx_Crimson_Harmony_Jarilo_RobotSettlement": "Rastros: Armonía (Asentamiento robot)", "Calyx_Crimson_Harmony_Penacony_TheReverieDreamscape": "Rastros: Armonía (Hotel Fantasía (paisaje onírico))", @@ -362,18 +391,19 @@ "Stagnant_Shadow_Perdition": "Ascension: Físico (Hanya / Argenti)", "Stagnant_Shadow_Blaze": "Ascension: Fuego (Himeko / Asta / Hook)", "Stagnant_Shadow_Scorch": "Ascension: Fuego (Guinaifen / Topaz y Conti)", + "Stagnant_Shadow_Ire": "Ascension: Fuego (Gallagher)", "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)", + "Stagnant_Shadow_Doom": "Ascension: Rayo (Kafka / Jing Yuan / Acheron)", "Stagnant_Shadow_Gust": "Ascension: Viento (Dan Heng / Bronya / Sampo)", "Stagnant_Shadow_Celestial": "Ascension: Viento (Blade / Huohuo / Cisne Negro)", "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 (Sparkle)", "Stagnant_Shadow_Mirage": "Ascension: Imaginario (Welt / Luocha / Yukong)", - "Stagnant_Shadow_Puppetry": "Ascension: Imaginario (Dan Heng - Imbibitor Lunae / Dr. Ratio)" + "Stagnant_Shadow_Puppetry": "Ascension: Imaginario (Dan Heng - Imbibitor Lunae / Aventurino / Dr. Ratio)" }, "CavernOfCorrosion": { "name": "Completar Caverna de la corrosión 1 vez", @@ -406,6 +436,7 @@ "name": "Personaje de apoyo", "help": "Selecciona qué personaje de apoyo de un amigo se usará. Si no se encuentra, se seleccionará al predeterminado.\nEl personaje de apoyo no debe ser el mismo que el personaje del equipo, se recomienda priorizar a los amigos.", "FirstCharacter": "Primer personaje", + "Acheron": "Acheron", "Argenti": "Argenti", "Arlan": "Arlan", "Asta": "Asta", @@ -418,6 +449,7 @@ "DanHengImbibitorLunae": "Dan Heng - Imbibitor Lunae", "DrRatio": "Dr. Ratio", "FuXuan": "Fu Xuan", + "Gallagher": "Gallagher", "Gepard": "Gepard", "Guinaifen": "Guinaifen", "Hanya": "Hanya", diff --git a/module/config/i18n/ja-JP.json b/module/config/i18n/ja-JP.json index be59b56d2..1a02dc908 100644 --- a/module/config/i18n/ja-JP.json +++ b/module/config/i18n/ja-JP.json @@ -96,6 +96,12 @@ "name": "Emulator.Serial.name", "help": "Emulator.Serial.help" }, + "GameClient": { + "name": "Emulator.GameClient.name", + "help": "Emulator.GameClient.help", + "android": "android", + "cloud_android": "cloud_android" + }, "PackageName": { "name": "Emulator.PackageName.name", "help": "Emulator.PackageName.help", @@ -215,6 +221,24 @@ "close_game": "close_game" } }, + "CloudStorage": { + "_info": { + "name": "CloudStorage._info.name", + "help": "CloudStorage._info.help" + }, + "CloudRemainSeasonPass": { + "name": "CloudStorage.CloudRemainSeasonPass.name", + "help": "CloudStorage.CloudRemainSeasonPass.help" + }, + "CloudRemainPaid": { + "name": "CloudStorage.CloudRemainPaid.name", + "help": "CloudStorage.CloudRemainPaid.help" + }, + "CloudRemainFree": { + "name": "CloudStorage.CloudRemainFree.name", + "help": "CloudStorage.CloudRemainFree.help" + } + }, "Dungeon": { "_info": { "name": "Dungeon._info.name", @@ -235,8 +259,10 @@ "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_Abundance_Jarilo_BackwaterPass": "軌跡素材:豊穣(外縁通路)", + "Calyx_Crimson_Abundance_Luofu_FyxestrollGarden": "軌跡素材:豊穣(綏園)", "Calyx_Crimson_Erudition_Jarilo_RivetTown": "軌跡素材:知恵(リベットタウン)", "Calyx_Crimson_Harmony_Jarilo_RobotSettlement": "軌跡素材:調和(機械集落)", "Calyx_Crimson_Harmony_Penacony_TheReverieDreamscape": "軌跡素材:調和(ホテル・レバリー-夢境)", @@ -246,18 +272,19 @@ "Stagnant_Shadow_Perdition": "キャラクター昇格素材:物理(寒鴉 / アルジェンティ)", "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_Doom": "キャラクター昇格素材:雷(カフカ / 景元 / 黄泉)", "Stagnant_Shadow_Gust": "キャラクター昇格素材:風(丹恒 / ブローニャ / サンポ)", "Stagnant_Shadow_Celestial": "キャラクター昇格素材:風(刃 / フォフォ / ブラックスワン)", "Stagnant_Shadow_Quanta": "キャラクター昇格素材:量子(銀狼 / ゼーレ / 青雀)", "Stagnant_Shadow_Abomination": "キャラクター昇格素材:量子(リンクス / 符玄 / 雪衣)", "Stagnant_Shadow_Roast": "キャラクター昇格素材:量子(花火)", "Stagnant_Shadow_Mirage": "キャラクター昇格素材:虚数(ヴェルト / 羅刹 / 御空)", - "Stagnant_Shadow_Puppetry": "キャラクター昇格素材:虚数(丹恒・飲月 / Dr.レイシオ)", + "Stagnant_Shadow_Puppetry": "キャラクター昇格素材:虚数(丹恒・飲月 / アベンチュリン / Dr.レイシオ)", "Cavern_of_Corrosion_Path_of_Gelid_Wind": "侵蝕トンネル・霜風の路(侵蝕トンネル・霜風の路)", "Cavern_of_Corrosion_Path_of_Jabbing_Punch": "侵蝕トンネル・迅拳の路(侵蝕トンネル・迅拳の路)", "Cavern_of_Corrosion_Path_of_Drifting": "侵蝕トンネル・漂泊の路(侵蝕トンネル・漂泊の路)", @@ -271,7 +298,6 @@ "NameAtDoubleCalyx": { "name": "Dungeon.NameAtDoubleCalyx.name", "help": "Dungeon.NameAtDoubleCalyx.help", - "do_not_participate": "do_not_participate", "Calyx_Golden_Memories_Jarilo_VI": "素材:役割経験(回憶の蕾・ヤリーロ-Ⅵ):", "Calyx_Golden_Memories_The_Xianzhou_Luofu": "素材:役割経験(回憶の蕾・仙舟羅浮):", "Calyx_Golden_Memories_Penacony": "素材:役割経験(回憶の蕾・ピノコニー):", @@ -284,8 +310,10 @@ "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_Abundance_Jarilo_BackwaterPass": "軌跡素材:豊穣(外縁通路)", + "Calyx_Crimson_Abundance_Luofu_FyxestrollGarden": "軌跡素材:豊穣(綏園)", "Calyx_Crimson_Erudition_Jarilo_RivetTown": "軌跡素材:知恵(リベットタウン)", "Calyx_Crimson_Harmony_Jarilo_RobotSettlement": "軌跡素材:調和(機械集落)", "Calyx_Crimson_Harmony_Penacony_TheReverieDreamscape": "軌跡素材:調和(ホテル・レバリー-夢境)", @@ -295,7 +323,6 @@ "NameAtDoubleRelic": { "name": "Dungeon.NameAtDoubleRelic.name", "help": "Dungeon.NameAtDoubleRelic.help", - "do_not_participate": "do_not_participate", "Cavern_of_Corrosion_Path_of_Gelid_Wind": "侵蝕トンネル・霜風の路(侵蝕トンネル・霜風の路)", "Cavern_of_Corrosion_Path_of_Jabbing_Punch": "侵蝕トンネル・迅拳の路(侵蝕トンネル・迅拳の路)", "Cavern_of_Corrosion_Path_of_Drifting": "侵蝕トンネル・漂泊の路(侵蝕トンネル・漂泊の路)", @@ -346,8 +373,10 @@ "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_Abundance_Jarilo_BackwaterPass": "軌跡素材:豊穣(外縁通路)", + "Calyx_Crimson_Abundance_Luofu_FyxestrollGarden": "軌跡素材:豊穣(綏園)", "Calyx_Crimson_Erudition_Jarilo_RivetTown": "軌跡素材:知恵(リベットタウン)", "Calyx_Crimson_Harmony_Jarilo_RobotSettlement": "軌跡素材:調和(機械集落)", "Calyx_Crimson_Harmony_Penacony_TheReverieDreamscape": "軌跡素材:調和(ホテル・レバリー-夢境)", @@ -362,18 +391,19 @@ "Stagnant_Shadow_Perdition": "キャラクター昇格素材:物理(寒鴉 / アルジェンティ)", "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_Doom": "キャラクター昇格素材:雷(カフカ / 景元 / 黄泉)", "Stagnant_Shadow_Gust": "キャラクター昇格素材:風(丹恒 / ブローニャ / サンポ)", "Stagnant_Shadow_Celestial": "キャラクター昇格素材:風(刃 / フォフォ / ブラックスワン)", "Stagnant_Shadow_Quanta": "キャラクター昇格素材:量子(銀狼 / ゼーレ / 青雀)", "Stagnant_Shadow_Abomination": "キャラクター昇格素材:量子(リンクス / 符玄 / 雪衣)", "Stagnant_Shadow_Roast": "キャラクター昇格素材:量子(花火)", "Stagnant_Shadow_Mirage": "キャラクター昇格素材:虚数(ヴェルト / 羅刹 / 御空)", - "Stagnant_Shadow_Puppetry": "キャラクター昇格素材:虚数(丹恒・飲月 / Dr.レイシオ)" + "Stagnant_Shadow_Puppetry": "キャラクター昇格素材:虚数(丹恒・飲月 / アベンチュリン / Dr.レイシオ)" }, "CavernOfCorrosion": { "name": "DungeonDaily.CavernOfCorrosion.name", @@ -406,6 +436,7 @@ "name": "DungeonSupport.Character.name", "help": "DungeonSupport.Character.help", "FirstCharacter": "FirstCharacter", + "Acheron": "黄泉", "Argenti": "アルジェンティ", "Arlan": "アーラン", "Asta": "アスター", @@ -418,6 +449,7 @@ "DanHengImbibitorLunae": "丹恒・飲月", "DrRatio": "Dr.レイシオ", "FuXuan": "符玄", + "Gallagher": "ギャラガー", "Gepard": "ジェパード", "Guinaifen": "桂乃芬", "Hanya": "寒鴉", diff --git a/module/config/i18n/zh-CN.json b/module/config/i18n/zh-CN.json index 2658d658f..5423d4ba5 100644 --- a/module/config/i18n/zh-CN.json +++ b/module/config/i18n/zh-CN.json @@ -96,6 +96,12 @@ "name": "模拟器 Serial", "help": "常见的模拟器 Serial 可以查询下方列表\n填 \"auto\" 自动检测模拟器,多个模拟器正在运行或使用不支持自动检测的模拟器时无法使用 \"auto\",必须手动填写\n\n模拟器默认 Serial:\n- 蓝叠模拟器 127.0.0.1:5555\n- 蓝叠模拟器4 Hyper-v版,填\"bluestacks4-hyperv\"自动连接,多开填\"bluestacks4-hyperv-2\"以此类推\n- 蓝叠模拟器5 Hyper-v版,填\"bluestacks5-hyperv\"自动连接,多开填\"bluestacks5-hyperv-1\"以此类推\n- 夜神模拟器 127.0.0.1:62001\n- 夜神模拟器64位 127.0.0.1:59865\n- MuMu模拟器/MuMu模拟器X 127.0.0.1:7555\n- MuMu模拟器12 127.0.0.1:16384\n- 逍遥模拟器 127.0.0.1:21503\n- 雷电模拟器 emulator-5554 或 127.0.0.1:5555\n- WSA,填\"wsa-0\"使游戏在后台运行,需要使用第三方软件操控或关闭(建议使用scrcpy操控)\n如果你使用了模拟器的多开功能,它们的 Serial 将不是默认的,可以在 console.bat 中执行 `adb devices` 查询,或根据模拟器官方的教程填写" }, + "GameClient": { + "name": "游戏客户端", + "help": "选择云游戏时,将自动排队登录,云游戏目前仅有国服", + "android": "安卓端", + "cloud_android": "云游戏安卓端" + }, "PackageName": { "name": "游戏服务器", "help": "无法区分国际服的不同地区,请手动选择服务器", @@ -215,6 +221,24 @@ "close_game": "关闭游戏" } }, + "CloudStorage": { + "_info": { + "name": "", + "help": "" + }, + "CloudRemainSeasonPass": { + "name": "畅玩卡剩余 X 天", + "help": "" + }, + "CloudRemainPaid": { + "name": "星云币剩余 X 分钟", + "help": "" + }, + "CloudRemainFree": { + "name": "免费时长剩余 X 分钟", + "help": "" + } + }, "Dungeon": { "_info": { "name": "每日副本设置", @@ -235,8 +259,10 @@ "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_Abundance_Jarilo_BackwaterPass": "行迹材料:丰饶(边缘通路)", + "Calyx_Crimson_Abundance_Luofu_FyxestrollGarden": "行迹材料:丰饶(绥园)", "Calyx_Crimson_Erudition_Jarilo_RivetTown": "行迹材料:智识(铆钉镇)", "Calyx_Crimson_Harmony_Jarilo_RobotSettlement": "行迹材料:同谐(机械聚落)", "Calyx_Crimson_Harmony_Penacony_TheReverieDreamscape": "行迹材料:同谐(白日梦酒店-梦境)", @@ -246,18 +272,19 @@ "Stagnant_Shadow_Perdition": "角色晋阶材料:物理(寒鸦 / 银枝)", "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_Doom": "角色晋阶材料:雷(卡芙卡 / 景元 / 黄泉)", "Stagnant_Shadow_Gust": "角色晋阶材料:风(丹恒 / 布洛妮娅 / 桑博)", "Stagnant_Shadow_Celestial": "角色晋阶材料:风(刃 / 藿藿 / 黑天鹅)", "Stagnant_Shadow_Quanta": "角色晋阶材料:量子(银狼 / 希儿 / 青雀)", "Stagnant_Shadow_Abomination": "角色晋阶材料:量子(玲可 / 符玄 / 雪衣)", "Stagnant_Shadow_Roast": "角色晋阶材料:量子(花火)", "Stagnant_Shadow_Mirage": "角色晋阶材料:虚数(瓦尔特 / 罗刹 / 驭空)", - "Stagnant_Shadow_Puppetry": "角色晋阶材料:虚数(丹恒•饮月 / 真理医生)", + "Stagnant_Shadow_Puppetry": "角色晋阶材料:虚数(丹恒•饮月 / 砂金 / 真理医生)", "Cavern_of_Corrosion_Path_of_Gelid_Wind": "遗器:冰套+风套(霜风之径•侵蚀隧洞)", "Cavern_of_Corrosion_Path_of_Jabbing_Punch": "遗器:物理套+击破套(迅拳之径•侵蚀隧洞)", "Cavern_of_Corrosion_Path_of_Drifting": "遗器:治疗套+快枪手(漂泊之径•侵蚀隧洞)", @@ -271,7 +298,6 @@ "NameAtDoubleCalyx": { "name": "有双倍花活动时,选择副本", "help": "次数耗尽后回退到默认打本设置", - "do_not_participate": "不参与活动", "Calyx_Golden_Memories_Jarilo_VI": "材料:角色经验(回忆之蕾•雅利洛-Ⅵ)", "Calyx_Golden_Memories_The_Xianzhou_Luofu": "材料:角色经验(回忆之蕾•仙舟罗浮)", "Calyx_Golden_Memories_Penacony": "材料:角色经验(回忆之蕾•匹诺康尼)", @@ -284,8 +310,10 @@ "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_Abundance_Jarilo_BackwaterPass": "行迹材料:丰饶(边缘通路)", + "Calyx_Crimson_Abundance_Luofu_FyxestrollGarden": "行迹材料:丰饶(绥园)", "Calyx_Crimson_Erudition_Jarilo_RivetTown": "行迹材料:智识(铆钉镇)", "Calyx_Crimson_Harmony_Jarilo_RobotSettlement": "行迹材料:同谐(机械聚落)", "Calyx_Crimson_Harmony_Penacony_TheReverieDreamscape": "行迹材料:同谐(白日梦酒店-梦境)", @@ -295,7 +323,6 @@ "NameAtDoubleRelic": { "name": "有遗器活动时,选择副本", "help": "次数耗尽后回退到默认打本设置", - "do_not_participate": "不参与活动", "Cavern_of_Corrosion_Path_of_Gelid_Wind": "遗器:冰套+风套(霜风之径•侵蚀隧洞)", "Cavern_of_Corrosion_Path_of_Jabbing_Punch": "遗器:物理套+击破套(迅拳之径•侵蚀隧洞)", "Cavern_of_Corrosion_Path_of_Drifting": "遗器:治疗套+快枪手(漂泊之径•侵蚀隧洞)", @@ -346,8 +373,10 @@ "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_Abundance_Jarilo_BackwaterPass": "行迹材料:丰饶(边缘通路)", + "Calyx_Crimson_Abundance_Luofu_FyxestrollGarden": "行迹材料:丰饶(绥园)", "Calyx_Crimson_Erudition_Jarilo_RivetTown": "行迹材料:智识(铆钉镇)", "Calyx_Crimson_Harmony_Jarilo_RobotSettlement": "行迹材料:同谐(机械聚落)", "Calyx_Crimson_Harmony_Penacony_TheReverieDreamscape": "行迹材料:同谐(白日梦酒店-梦境)", @@ -362,18 +391,19 @@ "Stagnant_Shadow_Perdition": "角色晋阶材料:物理(寒鸦 / 银枝)", "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_Doom": "角色晋阶材料:雷(卡芙卡 / 景元 / 黄泉)", "Stagnant_Shadow_Gust": "角色晋阶材料:风(丹恒 / 布洛妮娅 / 桑博)", "Stagnant_Shadow_Celestial": "角色晋阶材料:风(刃 / 藿藿 / 黑天鹅)", "Stagnant_Shadow_Quanta": "角色晋阶材料:量子(银狼 / 希儿 / 青雀)", "Stagnant_Shadow_Abomination": "角色晋阶材料:量子(玲可 / 符玄 / 雪衣)", "Stagnant_Shadow_Roast": "角色晋阶材料:量子(花火)", "Stagnant_Shadow_Mirage": "角色晋阶材料:虚数(瓦尔特 / 罗刹 / 驭空)", - "Stagnant_Shadow_Puppetry": "角色晋阶材料:虚数(丹恒•饮月 / 真理医生)" + "Stagnant_Shadow_Puppetry": "角色晋阶材料:虚数(丹恒•饮月 / 砂金 / 真理医生)" }, "CavernOfCorrosion": { "name": "完成1次侵蚀隧洞", @@ -406,6 +436,7 @@ "name": "好友支援角色", "help": "选择好友支援角色,未找到则选择默认(第一个)角色\n支援角色不要与队伍中的角色重复,建议置顶好友角色", "FirstCharacter": "支援列表第一个角色", + "Acheron": "黄泉", "Argenti": "银枝", "Arlan": "阿兰", "Asta": "艾丝妲", @@ -418,6 +449,7 @@ "DanHengImbibitorLunae": "丹恒•饮月", "DrRatio": "真理医生", "FuXuan": "符玄", + "Gallagher": "加拉赫", "Gepard": "杰帕德", "Guinaifen": "桂乃芬", "Hanya": "寒鸦", diff --git a/module/config/i18n/zh-TW.json b/module/config/i18n/zh-TW.json index 6af71b5f5..086ec5a46 100644 --- a/module/config/i18n/zh-TW.json +++ b/module/config/i18n/zh-TW.json @@ -96,6 +96,12 @@ "name": "模擬器 Serial", "help": "常見的模擬器 Serial 可以查詢下方列表\n填 \"auto\" 自動檢測模擬器,多個模擬器正在運行或使用不支援自動檢測的模擬器時無法使用 \"auto\",必須手動填寫\n模擬器預設 Serial:\n- 藍疊模擬器 127.0.0.1:5555\n- 藍疊模擬器4 Hyper-v版,填\"bluestacks4-hyperv\"自動連接,多開填\"bluestacks4-hyperv-2\"以此類推\n- 藍疊模擬器5 Hyper-v版,填\"bluestacks5-hyperv\"自動連接,多開填\"bluestacks5-hyperv-1\"以此類推\n- 夜神模擬器 127.0.0.1:62001\n- 夜神模擬器64位元 127.0.0.1:59865\n- MuMu模擬器/MuMu模擬器X 127.0.0.1:7555\n- MuMu模擬器12 127.0.0.1:16384\n- 逍遙模擬器 127.0.0.1:21503\n- 雷電模擬器 emulator-5554 或 127.0.0.1:5555\n- WSA,填\"wsa-0\"使遊戲在後臺運行,需要使用第三方軟件操控或關閉\n如果你使用了模擬器的多開功能,他們的 Serial 將不是預設的,可以在 console.bat 中執行 `adb devices` 查詢,或根據模擬器官方的教程填寫" }, + "GameClient": { + "name": "遊戲客戶端", + "help": "選擇雲端遊戲時,將自動排隊登入,雲端遊戲目前僅有國服", + "android": "安卓端", + "cloud_android": "雲端遊戲安卓端" + }, "PackageName": { "name": "遊戲伺服器", "help": "無法區分國際服的不同地區,請手動選擇伺服器", @@ -215,6 +221,24 @@ "close_game": "關閉遊戲" } }, + "CloudStorage": { + "_info": { + "name": "CloudStorage._info.name", + "help": "CloudStorage._info.help" + }, + "CloudRemainSeasonPass": { + "name": "CloudStorage.CloudRemainSeasonPass.name", + "help": "CloudStorage.CloudRemainSeasonPass.help" + }, + "CloudRemainPaid": { + "name": "CloudStorage.CloudRemainPaid.name", + "help": "CloudStorage.CloudRemainPaid.help" + }, + "CloudRemainFree": { + "name": "CloudStorage.CloudRemainFree.name", + "help": "CloudStorage.CloudRemainFree.help" + } + }, "Dungeon": { "_info": { "name": "每日副本設定", @@ -235,8 +259,10 @@ "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_Abundance_Jarilo_BackwaterPass": "行跡材料:豐饒(邊緣通道)", + "Calyx_Crimson_Abundance_Luofu_FyxestrollGarden": "行跡材料:豐饒(綏園)", "Calyx_Crimson_Erudition_Jarilo_RivetTown": "行跡材料:智識(鉚釘鎮)", "Calyx_Crimson_Harmony_Jarilo_RobotSettlement": "行跡材料:同諧(機械聚落)", "Calyx_Crimson_Harmony_Penacony_TheReverieDreamscape": "行跡材料:同諧(白日夢飯店-夢境)", @@ -246,18 +272,19 @@ "Stagnant_Shadow_Perdition": "角色晉階材料:物理(寒鴉 / 銀枝)", "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_Doom": "角色晉階材料:雷(卡芙卡 / 景元 / 黃泉)", "Stagnant_Shadow_Gust": "角色晉階材料:風(丹恆 / 布洛妮婭 / 桑博)", "Stagnant_Shadow_Celestial": "角色晉階材料:風(刃 / 藿藿 / 黑天鵝)", "Stagnant_Shadow_Quanta": "角色晉階材料:量子(銀狼 / 希兒 / 青雀)", "Stagnant_Shadow_Abomination": "角色晉階材料:量子(玲可 / 符玄 / 雪衣)", "Stagnant_Shadow_Roast": "角色晉階材料:量子(花火)", "Stagnant_Shadow_Mirage": "角色晉階材料:虛數(瓦爾特 / 羅剎 / 馭空)", - "Stagnant_Shadow_Puppetry": "角色晉階材料:虛數(丹恆•飲月 / 真理醫生)", + "Stagnant_Shadow_Puppetry": "角色晉階材料:虛數(丹恆•飲月 / 砂金 / 真理醫生)", "Cavern_of_Corrosion_Path_of_Gelid_Wind": "遺器:冰套+風套(霜風之徑•侵蝕隧洞)", "Cavern_of_Corrosion_Path_of_Jabbing_Punch": "遺器:物理套+擊破套(迅拳之徑•侵蝕隧洞)", "Cavern_of_Corrosion_Path_of_Drifting": "遺器:治療套+快槍手(漂泊之徑•侵蝕隧洞)", @@ -271,7 +298,6 @@ "NameAtDoubleCalyx": { "name": "有雙倍花活動時,選擇副本", "help": "次數耗儘後回退到默認打本設定", - "do_not_participate": "不參與活動", "Calyx_Golden_Memories_Jarilo_VI": "材料:角色經驗(回憶之蕾•雅利洛-Ⅵ)", "Calyx_Golden_Memories_The_Xianzhou_Luofu": "材料:角色經驗(回憶之蕾•仙舟羅浮)", "Calyx_Golden_Memories_Penacony": "材料:角色經驗(回憶之蕾•匹諾康尼)", @@ -284,8 +310,10 @@ "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_Abundance_Jarilo_BackwaterPass": "行跡材料:豐饒(邊緣通道)", + "Calyx_Crimson_Abundance_Luofu_FyxestrollGarden": "行跡材料:豐饒(綏園)", "Calyx_Crimson_Erudition_Jarilo_RivetTown": "行跡材料:智識(鉚釘鎮)", "Calyx_Crimson_Harmony_Jarilo_RobotSettlement": "行跡材料:同諧(機械聚落)", "Calyx_Crimson_Harmony_Penacony_TheReverieDreamscape": "行跡材料:同諧(白日夢飯店-夢境)", @@ -295,7 +323,6 @@ "NameAtDoubleRelic": { "name": "有遺器活動時,選擇副本", "help": "次數耗儘後回退到默認打本設定", - "do_not_participate": "不參與活動", "Cavern_of_Corrosion_Path_of_Gelid_Wind": "遺器:冰套+風套(霜風之徑•侵蝕隧洞)", "Cavern_of_Corrosion_Path_of_Jabbing_Punch": "遺器:物理套+擊破套(迅拳之徑•侵蝕隧洞)", "Cavern_of_Corrosion_Path_of_Drifting": "遺器:治療套+快槍手(漂泊之徑•侵蝕隧洞)", @@ -346,8 +373,10 @@ "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_Abundance_Jarilo_BackwaterPass": "行跡材料:豐饒(邊緣通道)", + "Calyx_Crimson_Abundance_Luofu_FyxestrollGarden": "行跡材料:豐饒(綏園)", "Calyx_Crimson_Erudition_Jarilo_RivetTown": "行跡材料:智識(鉚釘鎮)", "Calyx_Crimson_Harmony_Jarilo_RobotSettlement": "行跡材料:同諧(機械聚落)", "Calyx_Crimson_Harmony_Penacony_TheReverieDreamscape": "行跡材料:同諧(白日夢飯店-夢境)", @@ -362,18 +391,19 @@ "Stagnant_Shadow_Perdition": "角色晉階材料:物理(寒鴉 / 銀枝)", "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_Doom": "角色晉階材料:雷(卡芙卡 / 景元 / 黃泉)", "Stagnant_Shadow_Gust": "角色晉階材料:風(丹恆 / 布洛妮婭 / 桑博)", "Stagnant_Shadow_Celestial": "角色晉階材料:風(刃 / 藿藿 / 黑天鵝)", "Stagnant_Shadow_Quanta": "角色晉階材料:量子(銀狼 / 希兒 / 青雀)", "Stagnant_Shadow_Abomination": "角色晉階材料:量子(玲可 / 符玄 / 雪衣)", "Stagnant_Shadow_Roast": "角色晉階材料:量子(花火)", "Stagnant_Shadow_Mirage": "角色晉階材料:虛數(瓦爾特 / 羅剎 / 馭空)", - "Stagnant_Shadow_Puppetry": "角色晉階材料:虛數(丹恆•飲月 / 真理醫生)" + "Stagnant_Shadow_Puppetry": "角色晉階材料:虛數(丹恆•飲月 / 砂金 / 真理醫生)" }, "CavernOfCorrosion": { "name": "完成1次侵蝕隧洞", @@ -406,6 +436,7 @@ "name": "好友支援角色", "help": "選擇好友支援角色,未找到則選擇默認(第一個)角色\n支援角色不要與隊伍中的角色重複,建議置頂好友角色", "FirstCharacter": "支援列表第一個角色", + "Acheron": "黃泉", "Argenti": "銀枝", "Arlan": "阿蘭", "Asta": "艾絲妲", @@ -418,6 +449,7 @@ "DanHengImbibitorLunae": "丹恆•飲月", "DrRatio": "真理醫生", "FuXuan": "符玄", + "Gallagher": "加拉赫", "Gepard": "傑帕德", "Guinaifen": "桂乃芬", "Hanya": "寒鴉", diff --git a/module/config/server.py b/module/config/server.py index 2049e3c47..ee3fc23f0 100644 --- a/module/config/server.py +++ b/module/config/server.py @@ -15,6 +15,10 @@ VALID_SERVER = { 'OVERSEA-TWHKMO': 'com.HoYoverse.hkrpgoversea', } VALID_PACKAGE = set(list(VALID_SERVER.values())) +VALID_CLOUD_SERVER = { + 'CN-Official': 'com.miHoYo.cloudgames.hkrpg', +} +VALID_CLOUD_PACKAGE = set(list(VALID_SERVER.values())) def set_lang(lang_: str): @@ -47,18 +51,30 @@ def to_server(package_or_server: str) -> str: return key if key == package_or_server: return key + for key, value in VALID_CLOUD_SERVER.items(): + if value == package_or_server: + return key + if key == package_or_server: + return key raise ValueError(f'Package invalid: {package_or_server}') -def to_package(package_or_server: str) -> str: +def to_package(package_or_server: str, is_cloud=False) -> str: """ Convert package/server to package. """ - for key, value in VALID_SERVER.items(): - if value == package_or_server: - return value - if key == package_or_server: - return value + if is_cloud: + for key, value in VALID_CLOUD_SERVER.items(): + if value == package_or_server: + return value + if key == package_or_server: + return value + else: + for key, value in VALID_SERVER.items(): + if value == package_or_server: + return value + if key == package_or_server: + return value raise ValueError(f'Server invalid: {package_or_server}') diff --git a/module/config/stored/stored_generated.py b/module/config/stored/stored_generated.py index 1280f1e19..bc8f2c526 100644 --- a/module/config/stored/stored_generated.py +++ b/module/config/stored/stored_generated.py @@ -28,6 +28,9 @@ from module.config.stored.classes import ( # ``` python -m module/config/config_updater.py ``` class StoredGenerated: + CloudRemainSeasonPass = StoredInt("Alas.CloudStorage.CloudRemainSeasonPass") + CloudRemainPaid = StoredInt("Alas.CloudStorage.CloudRemainPaid") + CloudRemainFree = StoredInt("Alas.CloudStorage.CloudRemainFree") TrailblazePower = StoredTrailblazePower("Dungeon.DungeonStorage.TrailblazePower") Immersifier = StoredImmersifier("Dungeon.DungeonStorage.Immersifier") DungeonDouble = StoredDungeonDouble("Dungeon.DungeonStorage.DungeonDouble") diff --git a/module/device/app_control.py b/module/device/app_control.py index 390c50516..cf6c3a529 100644 --- a/module/device/app_control.py +++ b/module/device/app_control.py @@ -49,11 +49,14 @@ class AppControl(Adb, WSA, Uiautomator2): Returns: etree._Element: Select elements with `self.hierarchy.xpath('//*[@text="Hermit"]')` for example. """ - method = self.config.Emulator_ControlMethod - if method in AppControl._app_u2_family: - self.hierarchy = self.dump_hierarchy_uiautomator2() - else: - self.hierarchy = self.dump_hierarchy_adb() + # method = self.config.Emulator_ControlMethod + # if method in AppControl._app_u2_family: + # self.hierarchy = self.dump_hierarchy_uiautomator2() + # else: + # self.hierarchy = self.dump_hierarchy_adb() + + # Using uiautomator2 + self.hierarchy = self.dump_hierarchy_uiautomator2() return self.hierarchy def xpath_to_button(self, xpath: str) -> HierarchyButton: diff --git a/module/device/connection.py b/module/device/connection.py index 4b2094815..e84c66946 100644 --- a/module/device/connection.py +++ b/module/device/connection.py @@ -84,6 +84,11 @@ class AdbDeviceWithStatus(AdbDevice): def __bool__(self): return True + @cached_property + def may_mumu12_family(self): + # 127.0.0.1:16XXX + return len(self.serial) == 15 and self.serial.startswith('127.0.0.1:16') + class Connection(ConnectionAttr): def __init__(self, config): @@ -100,7 +105,9 @@ class Connection(ConnectionAttr): logger.attr('AdbDevice', self.adb) # Package - if self.config.Emulator_PackageName == 'auto': + if self.config.is_cloud_game: + self.package = server_.to_package(self.config.Emulator_PackageName, is_cloud=True) + elif self.config.Emulator_PackageName == 'auto': self.detect_package() else: self.package = server_.to_package(self.config.Emulator_PackageName) @@ -778,7 +785,16 @@ class Connection(ConnectionAttr): raise RequestHumanTakeover elif available.count == 1: logger.info(f'Auto device detection found only one device, using it') - self.serial = devices[0].serial + self.serial = available[0].serial + del_cached_property(self, 'adb') + elif available.count == 2 \ + and available.select(serial='127.0.0.1:7555') \ + and available.select(may_mumu12_family=True): + logger.info(f'Auto device detection found MuMu12 device, using it') + # For MuMu12 serials like 127.0.0.1:7555 and 127.0.0.1:16384 + # ignore 7555 use 16384 + remain = available.select(may_mumu12_family=True).first_or_none() + self.serial = remain.serial del_cached_property(self, 'adb') else: logger.critical('Multiple devices found, auto device detection cannot decide which to choose, ' diff --git a/module/device/method/utils.py b/module/device/method/utils.py index 67bd65451..36d6bbd49 100644 --- a/module/device/method/utils.py +++ b/module/device/method/utils.py @@ -18,9 +18,11 @@ except ImportError: # We expect `screencap | nc 192.168.0.1 20298` instead of `screencap '|' nc 192.168.80.1 20298` import adbutils import subprocess + adbutils._utils.list2cmdline = subprocess.list2cmdline adbutils._device.list2cmdline = subprocess.list2cmdline + # BaseDevice.shell() is missing a check_okay() call before reading output, # resulting in an `OKAY` prefix in output. def shell(self, @@ -40,6 +42,7 @@ except ImportError: output = c.read_until_close() return output.rstrip() if rstrip else output + adbutils._device.BaseDevice.shell = shell from module.base.decorator import cached_property @@ -323,7 +326,7 @@ class HierarchyButton: if res: return res[0] else: - return 'HierarchyButton' + return self.xpath @cached_property def count(self): @@ -333,15 +336,30 @@ class HierarchyButton: def exist(self): return self.count == 1 + @cached_property + def attrib(self): + if self.exist: + return self.nodes[0].attrib + else: + return {} + @cached_property def area(self): if self.exist: - bounds = self.nodes[0].attrib.get("bounds") + bounds = self.attrib.get("bounds") lx, ly, rx, ry = map(int, re.findall(r"\d+", bounds)) return lx, ly, rx, ry else: return None + @cached_property + def size(self): + if self.area is not None: + lx, ly, rx, ry = self.area + return rx - lx, ry - ly + else: + return None + @cached_property def button(self): return self.area @@ -352,9 +370,82 @@ class HierarchyButton: def __str__(self): return self.name + """ + Element props + """ + def _get_bool_prop(self, prop: str) -> bool: + return self.attrib.get(prop, "").lower() == 'true' + @cached_property - def focused(self): - if self.exist: - return self.nodes[0].attrib.get("focused").lower() == 'true' - else: - return False + def index(self) -> int: + try: + return int(self.attrib.get("index", 0)) + except IndexError: + return 0 + + @cached_property + def text(self) -> str: + return self.attrib.get("text", "").strip() + + @cached_property + def resourceId(self) -> str: + return self.attrib.get("resourceId", "").strip() + + @cached_property + def package(self) -> str: + return self.attrib.get("resourceId", "").strip() + + @cached_property + def description(self) -> str: + return self.attrib.get("resourceId", "").strip() + + @cached_property + def checkable(self) -> bool: + return self._get_bool_prop('checkable') + + @cached_property + def clickable(self) -> bool: + return self._get_bool_prop('clickable') + + @cached_property + def enabled(self) -> bool: + return self._get_bool_prop('enabled') + + @cached_property + def fucusable(self) -> bool: + return self._get_bool_prop('fucusable') + + @cached_property + def focused(self) -> bool: + return self._get_bool_prop('focused') + + @cached_property + def scrollable(self) -> bool: + return self._get_bool_prop('scrollable') + + @cached_property + def longClickable(self) -> bool: + return self._get_bool_prop('longClickable') + + @cached_property + def password(self) -> bool: + return self._get_bool_prop('password') + + @cached_property + def selected(self) -> bool: + return self._get_bool_prop('selected') + + +class AreaButton: + def __init__(self, area, name='AREA_BUTTON'): + self.area = area + self.color = () + self.name = name + self.button = area + + def __str__(self): + return self.name + + def __bool__(self): + # Cannot appear + return False diff --git a/module/ui/scroll.py b/module/ui/scroll.py index 7500e9c35..358e6a01f 100644 --- a/module/ui/scroll.py +++ b/module/ui/scroll.py @@ -1,9 +1,10 @@ import numpy as np +from scipy import signal from module.base.base import ModuleBase from module.base.button import Button, ButtonWrapper from module.base.timer import Timer -from module.base.utils import color_similarity_2d, random_rectangle_point +from module.base.utils import color_similarity_2d, random_rectangle_point, rgb2gray from module.logger import logger @@ -46,7 +47,7 @@ class Scroll: Returns: np.ndarray: Shape (n,), dtype bool. """ - image = main.image_crop(self.area) + image = main.image_crop(self.area, copy=False) image = color_similarity_2d(image, color=self.color) mask = np.max(image, axis=1 if self.is_vertical else 0) > self.color_threshold self.length = np.sum(mask) @@ -210,3 +211,49 @@ class Scroll: def prev_page(self, main, page=0.8, random_range=(-0.01, 0.01), skip_first_screenshot=True): return self.drag_page(-page, main=main, random_range=random_range, skip_first_screenshot=skip_first_screenshot) + + +class AdaptiveScroll(Scroll): + def __init__(self, area, parameters: dict = None, background=5, is_vertical=True, name='Scroll'): + """ + Args: + area (Button, tuple): A button or area of the whole scroll. + prominence (dict): Parameters passing to scipy.find_peaks + background (int): + is_vertical (bool): True if vertical, false if horizontal. + name (str): + """ + if parameters is None: + parameters = {} + self.parameters = parameters + self.background = background + super().__init__(area, color=(255, 255, 255), is_vertical=is_vertical, name=name) + + def match_color(self, main): + if self.is_vertical: + area = (self.area[0] - self.background, self.area[1], self.area[2] + self.background, self.area[3]) + image = main.image_crop(area, copy=False) + image = rgb2gray(image) + image = image.flatten() + wlen = area[2] - area[0] + else: + area = (self.area[0], self.area[1] - self.background, self.area[2], self.area[3] + self.background) + image = main.image_crop(area, copy=False) + image = rgb2gray(image) + image = image.flatten('F') + wlen = area[3] - area[1] + + parameters = { + 'height': 128, + 'prominence': 30, + 'wlen': wlen, + 'width': 2, + } + parameters.update(self.parameters) + peaks, _ = signal.find_peaks(image, **parameters) + peaks //= wlen + + self.length = len(peaks) + mask = np.zeros((self.total,), dtype=np.bool_) + mask[peaks] = 1 + return mask diff --git a/route/rogue/Combat/Jarilo_CorridorofFadingEchoes_F1.py b/route/rogue/Combat/Jarilo_CorridorofFadingEchoes_F1.py index ddef500f4..562f5c057 100644 --- a/route/rogue/Combat/Jarilo_CorridorofFadingEchoes_F1.py +++ b/route/rogue/Combat/Jarilo_CorridorofFadingEchoes_F1.py @@ -216,6 +216,7 @@ class Route(RouteBase): | -------- | ------------------------- | --------- | -------- | | spawn | Waypoint((463.3, 123.5)), | 96.7 | 91 | | item | Waypoint((476.9, 129.9)), | 116.8 | 114 | + | node1 | Waypoint((524.8, 122.6)), | 94.2 | 271 | | enemy1 | Waypoint((544.4, 128.5)), | 129.9 | 128 | | node2 | Waypoint((554.6, 141.6)), | 166.6 | 158 | | enemy2 | Waypoint((556.4, 206.8)), | 190.1 | 184 | @@ -228,6 +229,7 @@ class Route(RouteBase): Waypoint((556.4, 206.8)), end_rotation=184, left_door=Waypoint((563.1, 211.9)), right_door=Waypoint((544.4, 211.7))) item = Waypoint((476.9, 129.9)) + node1 = Waypoint((524.8, 122.6)) enemy1 = Waypoint((544.4, 128.5)) node2 = Waypoint((554.6, 141.6)) enemy2 = Waypoint((556.4, 206.8)) @@ -235,7 +237,11 @@ class Route(RouteBase): self.rotation_set(120) self.clear_item(item) - self.clear_enemy(enemy1) + # Avoid the ice sculpture at corner + self.clear_enemy( + node1.set_threshold(5), + enemy1, + ) self.rotation_set(180) self.clear_enemy( node2.set_threshold(5), diff --git a/route/rogue/Combat/Luofu_Cloudford_F1.py b/route/rogue/Combat/Luofu_Cloudford_F1.py index a89d53f6e..a8c5fde6e 100644 --- a/route/rogue/Combat/Luofu_Cloudford_F1.py +++ b/route/rogue/Combat/Luofu_Cloudford_F1.py @@ -168,6 +168,7 @@ class Route(RouteBase): enemy2 = Waypoint((273.9, 584.9)) # ===== End of generated waypoints ===== + self.rotation_set(270) # 1 self.clear_item( item1.straight_run(), @@ -179,6 +180,41 @@ class Route(RouteBase): self.clear_item(item2) self.clear_enemy(enemy2) + def Luofu_Cloudford_F1_X433Y617(self): + """ + | Waypoint | Position | Direction | Rotation | + | -------- | ------------------------- | --------- | -------- | + | spawn | Waypoint((433.5, 616.8)), | 358.2 | 4 | + | node1 | Waypoint((431.5, 593.4)), | 2.7 | 357 | + | item1 | Waypoint((371.8, 592.8)), | 263.8 | 267 | + | enemy1 | Waypoint((341.2, 586.8)), | 274.2 | 274 | + | item2 | Waypoint((310.4, 582.2)), | 289.0 | 288 | + | enemy2 | Waypoint((273.9, 584.9)), | 274.1 | 271 | + | exit_ | Waypoint((273.9, 584.9)), | 274.1 | 271 | + """ + self.map_init(plane=Luofu_Cloudford, floor="F1", position=(433.5, 616.8)) + self.register_domain_exit(Waypoint((273.9, 584.9)), end_rotation=271) + node1 = Waypoint((431.5, 593.4)) + item1 = Waypoint((371.8, 592.8)) + enemy1 = Waypoint((341.2, 586.8)) + item2 = Waypoint((310.4, 582.2)) + enemy2 = Waypoint((273.9, 584.9)) + # ===== End of generated waypoints ===== + + # Similar to Luofu_Cloudford_F1_X431Y593, but has different spawn point + self.rotation_set(270) + # 1 + self.clear_item( + node1.set_threshold(3), + item1.straight_run(), + ) + self.clear_enemy( + enemy1.straight_run(), + ) + # 2 + self.clear_item(item2) + self.clear_enemy(enemy2) + def Luofu_Cloudford_F1_X435Y669(self): """ | Waypoint | Position | Direction | Rotation | diff --git a/route/rogue/Elite/Luofu_AlchemyCommission_F2.py b/route/rogue/Elite/Luofu_AlchemyCommission_F2.py index 84b0c2e61..1f3cd0cfa 100644 --- a/route/rogue/Elite/Luofu_AlchemyCommission_F2.py +++ b/route/rogue/Elite/Luofu_AlchemyCommission_F2.py @@ -1,6 +1,5 @@ from tasks.map.control.waypoint import Waypoint from tasks.map.keywords.plane import Luofu_AlchemyCommission -from tasks.map.route.base import locked_position from tasks.rogue.route.base import RouteBase @@ -24,3 +23,30 @@ class Route(RouteBase): self.domain_reward(reward) self.domain_single_exit(exit_) # ===== End of generated waypoints ===== + + def Luofu_AlchemyCommission_F2_X664Y545(self): + """ + | Waypoint | Position | Direction | Rotation | + | -------- | ------------------------- | --------- | -------- | + | spawn | Waypoint((623.1, 590.0)), | 282.2 | 274 | + | enemy | Waypoint((571.6, 589.5)), | 282.0 | 274 | + | reward | Waypoint((563.5, 581.4)), | 281.9 | 274 | + | exit_ | Waypoint((555.5, 597.3)), | 267.8 | 264 | + """ + self.map_init(plane=Luofu_AlchemyCommission, floor="F2", position=(664.2, 546.8)) + enemy = Waypoint((571.6, 589.5)) + reward = Waypoint((563.5, 581.4)) + exit_ = Waypoint((555.5, 597.3)) + + self.clear_elite(enemy) + self.domain_reward(reward) + self.domain_single_exit(exit_) + # ===== End of generated waypoints ===== + + """ + Notes + Luofu_AlchemyCommission_F2_X664Y545 is the same as Luofu_AlchemyCommission_F2_X625Y590 + but for wrong spawn point detected + + Spawn point is too far from the correct result but should be fine in Boss room + """ diff --git a/route/rogue/Respite/Jarilo_BackwaterPass_F1.py b/route/rogue/Respite/Jarilo_BackwaterPass_F1.py index 280810fda..fcea0253f 100644 --- a/route/rogue/Respite/Jarilo_BackwaterPass_F1.py +++ b/route/rogue/Respite/Jarilo_BackwaterPass_F1.py @@ -1,10 +1,12 @@ from tasks.map.control.waypoint import Waypoint from tasks.map.keywords.plane import Jarilo_BackwaterPass +from tasks.map.route.base import locked_position from tasks.rogue.route.base import RouteBase class Route(RouteBase): + @locked_position def Jarilo_BackwaterPass_F1_X581Y403(self): """ | Waypoint | Position | Direction | Rotation | diff --git a/route/rogue/route.json b/route/rogue/route.json index 6d3506c3e..198c9be88 100644 --- a/route/rogue/route.json +++ b/route/rogue/route.json @@ -868,6 +868,17 @@ ], "domain": "Combat" }, + { + "name": "Combat_Luofu_Cloudford_F1_X433Y617", + "route": "route.rogue.Combat.Luofu_Cloudford_F1:Luofu_Cloudford_F1_X433Y617", + "plane": "Luofu_Cloudford", + "floor": "F1", + "position": [ + 433.5, + 616.8 + ], + "domain": "Combat" + }, { "name": "Combat_Luofu_Cloudford_F1_X435Y669", "route": "route.rogue.Combat.Luofu_Cloudford_F1:Luofu_Cloudford_F1_X435Y669", @@ -1330,6 +1341,17 @@ ], "domain": "Elite" }, + { + "name": "Elite_Luofu_AlchemyCommission_F2_X664Y545", + "route": "route.rogue.Elite.Luofu_AlchemyCommission_F2:Luofu_AlchemyCommission_F2_X664Y545", + "plane": "Luofu_AlchemyCommission", + "floor": "F2", + "position": [ + 664.2, + 546.8 + ], + "domain": "Elite" + }, { "name": "Elite_Luofu_ArtisanshipCommission_F1_X385Y494", "route": "route.rogue.Elite.Luofu_ArtisanshipCommission_F1:Luofu_ArtisanshipCommission_F1_X385Y494", diff --git a/src.py b/src.py index 5cb317b84..3027bd28e 100644 --- a/src.py +++ b/src.py @@ -11,6 +11,10 @@ class StarRailCopilot(AzurLaneAutoScript): from tasks.login.login import Login Login(self.config, device=self.device).app_start() + def stop(self): + from tasks.login.login import Login + Login(self.config, device=self.device).app_stop() + def goto_main(self): from tasks.login.login import Login from tasks.base.ui import UI diff --git a/tasks/assignment/assets/assets_assignment_dispatch.py b/tasks/assignment/assets/assets_assignment_dispatch.py index e56611e6e..38a32e5d0 100644 --- a/tasks/assignment/assets/assets_assignment_dispatch.py +++ b/tasks/assignment/assets/assets_assignment_dispatch.py @@ -7,17 +7,17 @@ ASSIGNMENT_START = ButtonWrapper( name='ASSIGNMENT_START', cn=Button( file='./assets/cn/assignment/dispatch/ASSIGNMENT_START.png', - area=(581, 321, 699, 349), - search=(573, 299, 707, 412), - color=(93, 84, 66), - button=(581, 321, 699, 349), + area=(563, 341, 716, 376), + search=(552, 299, 725, 412), + color=(103, 92, 72), + button=(563, 341, 716, 376), ), en=Button( file='./assets/en/assignment/dispatch/ASSIGNMENT_START.png', - area=(679, 323, 784, 347), - search=(669, 297, 794, 416), - color=(93, 83, 65), - button=(679, 323, 784, 347), + area=(693, 343, 831, 374), + search=(669, 297, 831, 416), + color=(95, 86, 67), + button=(693, 343, 831, 374), ), ) ASSIGNMENT_STARTED_CHECK = ButtonWrapper( @@ -34,40 +34,40 @@ CHARACTER_1 = ButtonWrapper( name='CHARACTER_1', share=Button( file='./assets/share/assignment/dispatch/CHARACTER_1.png', - area=(116, 212, 206, 312), - search=(96, 192, 226, 332), - color=(149, 134, 123), - button=(116, 212, 206, 312), + area=(110, 202, 202, 309), + search=(90, 182, 222, 329), + color=(153, 141, 159), + button=(110, 202, 202, 309), ), ) CHARACTER_1_SELECTED = ButtonWrapper( name='CHARACTER_1_SELECTED', share=Button( file='./assets/share/assignment/dispatch/CHARACTER_1_SELECTED.png', - area=(114, 207, 134, 225), - search=(94, 187, 154, 245), - color=(192, 204, 193), - button=(114, 207, 134, 225), + area=(107, 199, 126, 217), + search=(87, 179, 146, 237), + color=(217, 218, 216), + button=(107, 199, 126, 217), ), ) CHARACTER_2 = ButtonWrapper( name='CHARACTER_2', share=Button( file='./assets/share/assignment/dispatch/CHARACTER_2.png', - area=(228, 211, 318, 311), - search=(208, 191, 338, 331), - color=(184, 161, 172), - button=(228, 211, 318, 311), + area=(222, 202, 314, 309), + search=(202, 182, 334, 329), + color=(120, 120, 138), + button=(222, 202, 314, 309), ), ) CHARACTER_2_SELECTED = ButtonWrapper( name='CHARACTER_2_SELECTED', share=Button( file='./assets/share/assignment/dispatch/CHARACTER_2_SELECTED.png', - area=(226, 207, 245, 225), - search=(206, 187, 265, 245), - color=(179, 194, 187), - button=(226, 207, 245, 225), + area=(219, 199, 238, 217), + search=(199, 179, 258, 237), + color=(206, 207, 204), + button=(219, 199, 238, 217), ), ) CHARACTER_LIST = ButtonWrapper( diff --git a/tasks/assignment/ui.py b/tasks/assignment/ui.py index f46fa5ae4..895fe0c38 100644 --- a/tasks/assignment/ui.py +++ b/tasks/assignment/ui.py @@ -67,7 +67,12 @@ class AssignmentOcr(Ocr): def after_process(self, result: str): result = super().after_process(result) - + # Born to ObeyCurrently Owned:7781 -> Born to Obey + for splitter in ['Currently', 'currently', '当前持有']: + try: + result = result.split(splitter)[0] + except IndexError: + pass if self.ocr_regex is None: return result matched = self.ocr_regex.fullmatch(result) diff --git a/tasks/base/assets/assets_base_daemon.py b/tasks/base/assets/assets_base_daemon.py index 700ea2eb5..71732ebec 100644 --- a/tasks/base/assets/assets_base_daemon.py +++ b/tasks/base/assets/assets_base_daemon.py @@ -23,6 +23,16 @@ CHAT_OPTION = ButtonWrapper( button=(649, 496, 1129, 525), ), ) +DUNGEON_EXIT = ButtonWrapper( + name='DUNGEON_EXIT', + share=Button( + file='./assets/share/base/daemon/DUNGEON_EXIT.png', + area=(582, 598, 606, 622), + search=(562, 578, 626, 642), + color=(106, 99, 89), + button=(582, 598, 606, 622), + ), +) INTERACT_COLLECT = ButtonWrapper( name='INTERACT_COLLECT', share=Button( @@ -73,3 +83,33 @@ STORY_OPTION = ButtonWrapper( button=(813, 453, 1069, 488), ), ) +TUTORIAL_CHECK = ButtonWrapper( + name='TUTORIAL_CHECK', + share=Button( + file='./assets/share/base/daemon/TUTORIAL_CHECK.png', + area=(628, 43, 653, 65), + search=(608, 23, 673, 85), + color=(90, 155, 145), + button=(628, 43, 653, 65), + ), +) +TUTORIAL_CLOSE = ButtonWrapper( + name='TUTORIAL_CLOSE', + share=Button( + file='./assets/share/base/daemon/TUTORIAL_CLOSE.png', + area=(579, 634, 700, 669), + search=(559, 614, 720, 689), + color=(215, 213, 215), + button=(579, 634, 700, 669), + ), +) +TUTORIAL_NEXT = ButtonWrapper( + name='TUTORIAL_NEXT', + share=Button( + file='./assets/share/base/daemon/TUTORIAL_NEXT.png', + area=(1190, 303, 1240, 365), + search=(1170, 283, 1260, 385), + color=(45, 45, 49), + button=(1190, 303, 1240, 365), + ), +) diff --git a/tasks/base/daemon.py b/tasks/base/daemon.py index 537d6e5b5..deb483fa4 100644 --- a/tasks/base/daemon.py +++ b/tasks/base/daemon.py @@ -59,7 +59,7 @@ class Daemon(RouteBase, DaemonBase, AimDetectorMixin): else: logger.warning(f'Maatouch contact on {builder.contact}, may cause interruptions') - STORY_OPTION.set_search_offset((-5, -5, 32, 5)) + STORY_OPTION.set_search_offset((-5, -10, 32, 5)) INTERACT_COLLECT.set_search_offset((-5, -5, 32, 5)) INTERACT_INVESTIGATE.set_search_offset((-5, -5, 32, 5)) INTERACT_TREASURE.set_search_offset((-5, -5, 32, 5)) @@ -107,6 +107,16 @@ class Daemon(RouteBase, DaemonBase, AimDetectorMixin): continue if self.handle_ui_close(PICTURE_TAKEN, interval=1): continue + if self.appear_then_click(DUNGEON_EXIT, interval=1.5): + continue + # Tutorial popup + if self.appear(TUTORIAL_CHECK, interval=0.2): + if self.image_color_count(TUTORIAL_CLOSE, color=(255, 255, 255), threshold=180, count=400): + self.device.click(TUTORIAL_CLOSE) + continue + if self.image_color_count(TUTORIAL_NEXT, color=(255, 255, 255), threshold=180, count=50): + self.device.click(TUTORIAL_NEXT) + continue # Rogue if self.handle_blessing(): continue diff --git a/tasks/base/main_page.py b/tasks/base/main_page.py index 07aa90278..4ea355919 100644 --- a/tasks/base/main_page.py +++ b/tasks/base/main_page.py @@ -40,6 +40,8 @@ class OcrPlaneName(OcrWhiteLetterOnComplexBackground): result = re.sub(r'区域.*战$', '区域战斗', result) # 区域-事 result = re.sub(r'区域.*事$', '区域事件', result) + # 区域-战 + result = re.sub(r'区域.*交$', '区域交易', result) # 区域-事伴, 区域-事祥 result = re.sub(r'事[伴祥]', '事件', result) # 医域-战斗 diff --git a/tasks/character/keywords/character_list.py b/tasks/character/keywords/character_list.py index 3470b79e4..fefdb2a7e 100644 --- a/tasks/character/keywords/character_list.py +++ b/tasks/character/keywords/character_list.py @@ -3,8 +3,17 @@ from .classes import CharacterList # This file was auto-generated, do not modify it manually. To generate: # ``` python -m dev_tools.keyword_extract ``` -Argenti = CharacterList( +Acheron = CharacterList( id=1, + name='Acheron', + cn='黄泉', + cht='黃泉', + en='Acheron', + jp='黄泉', + es='Acheron', +) +Argenti = CharacterList( + id=2, name='Argenti', cn='银枝', cht='銀枝', @@ -13,7 +22,7 @@ Argenti = CharacterList( es='Argenti', ) Arlan = CharacterList( - id=2, + id=3, name='Arlan', cn='阿兰', cht='阿蘭', @@ -22,7 +31,7 @@ Arlan = CharacterList( es='Arlan', ) Asta = CharacterList( - id=3, + id=4, name='Asta', cn='艾丝妲', cht='艾絲妲', @@ -30,8 +39,17 @@ Asta = CharacterList( jp='アスター', es='Asta', ) +Aventurine = CharacterList( + id=5, + name='Aventurine', + cn='砂金', + cht='砂金', + en='Aventurine', + jp='アベンチュリン', + es='Aventurino', +) Bailu = CharacterList( - id=4, + id=6, name='Bailu', cn='白露', cht='白露', @@ -40,7 +58,7 @@ Bailu = CharacterList( es='Bailu', ) BlackSwan = CharacterList( - id=5, + id=7, name='BlackSwan', cn='黑天鹅', cht='黑天鵝', @@ -49,7 +67,7 @@ BlackSwan = CharacterList( es='Cisne Negro', ) Blade = CharacterList( - id=6, + id=8, name='Blade', cn='刃', cht='刃', @@ -58,7 +76,7 @@ Blade = CharacterList( es='Blade', ) Bronya = CharacterList( - id=7, + id=9, name='Bronya', cn='布洛妮娅', cht='布洛妮婭', @@ -67,7 +85,7 @@ Bronya = CharacterList( es='Bronya', ) Clara = CharacterList( - id=8, + id=10, name='Clara', cn='克拉拉', cht='克拉拉', @@ -76,7 +94,7 @@ Clara = CharacterList( es='Clara', ) DanHeng = CharacterList( - id=9, + id=11, name='DanHeng', cn='丹恒', cht='丹恆', @@ -85,7 +103,7 @@ DanHeng = CharacterList( es='Dan Heng', ) DanHengImbibitorLunae = CharacterList( - id=10, + id=12, name='DanHengImbibitorLunae', cn='丹恒•饮月', cht='丹恆•飲月', @@ -94,7 +112,7 @@ DanHengImbibitorLunae = CharacterList( es='Dan Heng - Imbibitor Lunae', ) DrRatio = CharacterList( - id=11, + id=13, name='DrRatio', cn='真理医生', cht='真理醫生', @@ -103,7 +121,7 @@ DrRatio = CharacterList( es='Dr. Ratio', ) FuXuan = CharacterList( - id=12, + id=14, name='FuXuan', cn='符玄', cht='符玄', @@ -111,8 +129,17 @@ FuXuan = CharacterList( jp='符玄', es='Fu Xuan', ) +Gallagher = CharacterList( + id=15, + name='Gallagher', + cn='加拉赫', + cht='加拉赫', + en='Gallagher', + jp='ギャラガー', + es='Gallagher', +) Gepard = CharacterList( - id=13, + id=16, name='Gepard', cn='杰帕德', cht='傑帕德', @@ -121,7 +148,7 @@ Gepard = CharacterList( es='Gepard', ) Guinaifen = CharacterList( - id=14, + id=17, name='Guinaifen', cn='桂乃芬', cht='桂乃芬', @@ -130,7 +157,7 @@ Guinaifen = CharacterList( es='Guinaifen', ) Hanya = CharacterList( - id=15, + id=18, name='Hanya', cn='寒鸦', cht='寒鴉', @@ -139,7 +166,7 @@ Hanya = CharacterList( es='Hanya', ) Herta = CharacterList( - id=16, + id=19, name='Herta', cn='黑塔', cht='黑塔', @@ -148,7 +175,7 @@ Herta = CharacterList( es='Herta', ) Himeko = CharacterList( - id=17, + id=20, name='Himeko', cn='姬子', cht='姬子', @@ -157,7 +184,7 @@ Himeko = CharacterList( es='Himeko', ) Hook = CharacterList( - id=18, + id=21, name='Hook', cn='虎克', cht='虎克', @@ -166,7 +193,7 @@ Hook = CharacterList( es='Hook', ) Huohuo = CharacterList( - id=19, + id=22, name='Huohuo', cn='藿藿', cht='藿藿', @@ -175,7 +202,7 @@ Huohuo = CharacterList( es='Huohuo', ) JingYuan = CharacterList( - id=20, + id=23, name='JingYuan', cn='景元', cht='景元', @@ -184,7 +211,7 @@ JingYuan = CharacterList( es='Jing Yuan', ) Jingliu = CharacterList( - id=21, + id=24, name='Jingliu', cn='镜流', cht='鏡流', @@ -193,7 +220,7 @@ Jingliu = CharacterList( es='Jingliu', ) Kafka = CharacterList( - id=22, + id=25, name='Kafka', cn='卡芙卡', cht='卡芙卡', @@ -202,7 +229,7 @@ Kafka = CharacterList( es='Kafka', ) Luka = CharacterList( - id=23, + id=26, name='Luka', cn='卢卡', cht='盧卡', @@ -211,7 +238,7 @@ Luka = CharacterList( es='Luka', ) Luocha = CharacterList( - id=24, + id=27, name='Luocha', cn='罗刹', cht='羅剎', @@ -220,7 +247,7 @@ Luocha = CharacterList( es='Luocha', ) Lynx = CharacterList( - id=25, + id=28, name='Lynx', cn='玲可', cht='玲可', @@ -229,7 +256,7 @@ Lynx = CharacterList( es='Lynx', ) March7th = CharacterList( - id=26, + id=29, name='March7th', cn='三月七', cht='三月七', @@ -238,7 +265,7 @@ March7th = CharacterList( es='Siete de Marzo', ) Misha = CharacterList( - id=27, + id=30, name='Misha', cn='米沙', cht='米沙', @@ -247,7 +274,7 @@ Misha = CharacterList( es='Misha', ) Natasha = CharacterList( - id=28, + id=31, name='Natasha', cn='娜塔莎', cht='娜塔莎', @@ -256,7 +283,7 @@ Natasha = CharacterList( es='Natasha', ) Pela = CharacterList( - id=29, + id=32, name='Pela', cn='佩拉', cht='佩拉', @@ -265,7 +292,7 @@ Pela = CharacterList( es='Pela', ) Qingque = CharacterList( - id=30, + id=33, name='Qingque', cn='青雀', cht='青雀', @@ -274,7 +301,7 @@ Qingque = CharacterList( es='Qingque', ) RuanMei = CharacterList( - id=31, + id=34, name='RuanMei', cn='阮•梅', cht='阮•梅', @@ -283,7 +310,7 @@ RuanMei = CharacterList( es='Ruan Mei', ) Sampo = CharacterList( - id=32, + id=35, name='Sampo', cn='桑博', cht='桑博', @@ -292,7 +319,7 @@ Sampo = CharacterList( es='Sampo', ) Seele = CharacterList( - id=33, + id=36, name='Seele', cn='希儿', cht='希兒', @@ -301,7 +328,7 @@ Seele = CharacterList( es='Seele', ) Serval = CharacterList( - id=34, + id=37, name='Serval', cn='希露瓦', cht='希露瓦', @@ -310,7 +337,7 @@ Serval = CharacterList( es='Serval', ) SilverWolf = CharacterList( - id=35, + id=38, name='SilverWolf', cn='银狼', cht='銀狼', @@ -319,7 +346,7 @@ SilverWolf = CharacterList( es='Silver Wolf', ) Sparkle = CharacterList( - id=36, + id=39, name='Sparkle', cn='花火', cht='花火', @@ -328,7 +355,7 @@ Sparkle = CharacterList( es='Sparkle', ) Sushang = CharacterList( - id=37, + id=40, name='Sushang', cn='素裳', cht='素裳', @@ -337,7 +364,7 @@ Sushang = CharacterList( es='Sushang', ) Tingyun = CharacterList( - id=38, + id=41, name='Tingyun', cn='停云', cht='停雲', @@ -346,7 +373,7 @@ Tingyun = CharacterList( es='Tingyun', ) TopazNumby = CharacterList( - id=39, + id=42, name='TopazNumby', cn='托帕&账账', cht='托帕&帳帳', @@ -355,7 +382,7 @@ TopazNumby = CharacterList( es='Topaz y Conti', ) TrailblazerDestruction = CharacterList( - id=40, + id=43, name='TrailblazerDestruction', cn='Trailblazer•毁灭', cht='Trailblazer•毀滅', @@ -364,7 +391,7 @@ TrailblazerDestruction = CharacterList( es='Trailblazer: Destrucción', ) TrailblazerPreservation = CharacterList( - id=41, + id=44, name='TrailblazerPreservation', cn='Trailblazer•存护', cht='Trailblazer•存護', @@ -373,7 +400,7 @@ TrailblazerPreservation = CharacterList( es='Trailblazer: Conservación', ) Welt = CharacterList( - id=42, + id=45, name='Welt', cn='瓦尔特', cht='瓦爾特', @@ -382,7 +409,7 @@ Welt = CharacterList( es='Welt', ) Xueyi = CharacterList( - id=43, + id=46, name='Xueyi', cn='雪衣', cht='雪衣', @@ -391,7 +418,7 @@ Xueyi = CharacterList( es='Xueyi', ) Yanqing = CharacterList( - id=44, + id=47, name='Yanqing', cn='彦卿', cht='彥卿', @@ -400,7 +427,7 @@ Yanqing = CharacterList( es='Yanqing', ) Yukong = CharacterList( - id=45, + id=48, name='Yukong', cn='驭空', cht='馭空', diff --git a/tasks/combat/combat.py b/tasks/combat/combat.py index ab97419ce..9767615cd 100644 --- a/tasks/combat/combat.py +++ b/tasks/combat/combat.py @@ -81,7 +81,15 @@ class Combat(CombatInteract, CombatPrepare, CombatState, CombatTeam, CombatSuppo """ logger.hr('Combat prepare') skip_first_screenshot = True - pre_set_team = bool(support_character) + if support_character: + # To set team before support set + pre_set_team = True + # Block COMBAT_TEAM_PREPARE before support set + support_set = False + else: + pre_set_team = False + support_set = True + logger.info([support_character, pre_set_team, support_set]) trial = 0 while 1: if skip_first_screenshot: @@ -99,14 +107,15 @@ class Combat(CombatInteract, CombatPrepare, CombatState, CombatTeam, CombatSuppo raise RequestHumanTakeover # Click - if self.appear(COMBAT_TEAM_SUPPORT) and support_character: + if support_character and self.appear(COMBAT_TEAM_SUPPORT): if pre_set_team: self.team_set(team) pre_set_team = False continue self.support_set(support_character) + support_set = True continue - if self.appear(COMBAT_TEAM_PREPARE, interval=2): + if support_set and self.appear(COMBAT_TEAM_PREPARE, interval=2): self.team_set(team) self.device.click(COMBAT_TEAM_PREPARE) self.interval_reset(COMBAT_TEAM_PREPARE) diff --git a/tasks/combat/state.py b/tasks/combat/state.py index 3884a94a9..cac86c67c 100644 --- a/tasks/combat/state.py +++ b/tasks/combat/state.py @@ -2,7 +2,7 @@ import cv2 from scipy import signal from module.base.timer import Timer -from module.base.utils import rgb2gray +from module.base.utils import rgb2luma from module.logger import logger from tasks.base.ui import UI from tasks.combat.assets.assets_combat_state import COMBAT_AUTO, COMBAT_PAUSE, COMBAT_SPEED_2X @@ -22,7 +22,7 @@ class CombatState(UI): return False def _is_combat_button_active(self, button): - image = rgb2gray(self.image_crop(button)) + image = rgb2luma(self.image_crop(button)) lines = cv2.reduce(image, 1, cv2.REDUCE_AVG).flatten() # [122 122 122 182 141 127 139 135 130 135 136 141 147 149 149 150 147 145 # 148 150 150 150 150 150 144 138 134 141 136 133 173 183 130 128 127 126] diff --git a/tasks/combat/support.py b/tasks/combat/support.py index ff628217d..568b74b68 100644 --- a/tasks/combat/support.py +++ b/tasks/combat/support.py @@ -1,12 +1,11 @@ import cv2 import numpy as np -from scipy import signal from module.base.button import ClickButton from module.base.timer import Timer -from module.base.utils import area_offset, area_size, crop, load_image, rgb2luma +from module.base.utils import area_offset, crop, load_image from module.logger import logger -from module.ui.scroll import Scroll +from module.ui.scroll import AdaptiveScroll from tasks.base.assets.assets_base_popup import POPUP_CANCEL from tasks.base.ui import UI from tasks.combat.assets.assets_combat_support import COMBAT_SUPPORT_ADD, COMBAT_SUPPORT_LIST, \ @@ -116,41 +115,6 @@ class NextSupportCharacter: return SUPPORT_SELECTED.match_template(image, similarity=0.75, direct_match=True) -class SupportListScroll(Scroll): - def cal_position(self, main): - """ - Args: - main (ModuleBase): - - Returns: - float: 0 to 1. - """ - image = main.device.image - - temp_area = list(self.area) - temp_area[0] = int(temp_area[0] * 0.98) - temp_area[2] = int(temp_area[2] * 1.02) - - line = rgb2luma(crop(image, temp_area)).flatten() - width = area_size(temp_area)[0] - parameters = { - "height": 180, - "prominence": 30, - "distance": width * 0.75, - } - peaks, _ = signal.find_peaks(line, **parameters) - peaks //= width - self.length = len(peaks) - middle = np.mean(peaks) - - position = (middle - self.length / 2) / (self.total - self.length) - position = position if position > 0 else 0.0 - position = position if position < 1 else 1.0 - logger.attr( - self.name, f"{position:.2f} ({middle}-{self.length / 2})/({self.total}-{self.length})") - return position - - class CombatSupport(UI): def support_set(self, support_character_name: str = "FirstCharacter"): """ @@ -212,8 +176,8 @@ class CombatSupport(UI): out: COMBAT_SUPPORT_LIST """ logger.hr("Combat support search") - scroll = SupportListScroll(area=COMBAT_SUPPORT_LIST_SCROLL.area, color=(194, 196, 205), - name=COMBAT_SUPPORT_LIST_SCROLL.name) + scroll = AdaptiveScroll(area=COMBAT_SUPPORT_LIST_SCROLL.area, + name=COMBAT_SUPPORT_LIST_SCROLL.name) if scroll.appear(main=self): if not scroll.at_bottom(main=self): # Dropdown to load the entire support list, so large threshold is acceptable @@ -311,8 +275,8 @@ class CombatSupport(UI): out: COMBAT_SUPPORT_LIST """ skip_first_screenshot = True - scroll = SupportListScroll(area=COMBAT_SUPPORT_LIST_SCROLL.area, color=(194, 196, 205), - name=COMBAT_SUPPORT_LIST_SCROLL.name) + scroll = AdaptiveScroll(area=COMBAT_SUPPORT_LIST_SCROLL.area, + name=COMBAT_SUPPORT_LIST_SCROLL.name) interval = Timer(1) next_support = None if scroll.appear(main=self): diff --git a/tasks/daily/assets/assets_daily_synthesize_consumable.py b/tasks/daily/assets/assets_daily_synthesize_consumable.py index 87043b768..fc349da7d 100644 --- a/tasks/daily/assets/assets_daily_synthesize_consumable.py +++ b/tasks/daily/assets/assets_daily_synthesize_consumable.py @@ -141,9 +141,9 @@ SYNTHESIZE_SCROLL = ButtonWrapper( name='SYNTHESIZE_SCROLL', share=Button( file='./assets/share/daily/synthesize_consumable/SYNTHESIZE_SCROLL.png', - area=(458, 80, 464, 628), - search=(438, 60, 484, 648), - color=(134, 130, 144), - button=(458, 80, 464, 628), + area=(460, 90, 464, 618), + search=(440, 70, 484, 638), + color=(167, 165, 177), + button=(460, 90, 464, 618), ), ) diff --git a/tasks/daily/synthesize.py b/tasks/daily/synthesize.py index 718b60bba..28309cf15 100644 --- a/tasks/daily/synthesize.py +++ b/tasks/daily/synthesize.py @@ -1,5 +1,5 @@ from module.ocr.ocr import * -from module.ui.scroll import Scroll +from module.ui.scroll import AdaptiveScroll, Scroll from tasks.base.assets.assets_base_page import MENU_CHECK, MENU_SCROLL, SYNTHESIZE_CHECK from tasks.base.assets.assets_base_popup import POPUP_CONFIRM from tasks.base.page import Page, page_menu, page_synthesize @@ -32,7 +32,7 @@ class SynthesizeUI(UI): scroll = Scroll(MENU_SCROLL.button, color=(191, 191, 191), name=MENU_SCROLL.name) case page_synthesize.name: check_image = SYNTHESIZE_CHECK - scroll = Scroll(SYNTHESIZE_SCROLL.button, color=(210, 210, 210), name=SYNTHESIZE_SCROLL.name) + scroll = AdaptiveScroll(SYNTHESIZE_SCROLL.button, name=SYNTHESIZE_SCROLL.name) case _: logger.info(f'No page matched, just skip') return @@ -109,7 +109,7 @@ class SynthesizeUI(UI): else self.__class__.default_candidate_items # Search target button from top to bottom - scroll = Scroll(SYNTHESIZE_SCROLL.button, color=(210, 210, 210), name=SYNTHESIZE_SCROLL.name) + scroll = AdaptiveScroll(SYNTHESIZE_SCROLL.button, name=SYNTHESIZE_SCROLL.name) if scroll.appear(main=self): skip_first_screenshot = True while 1: diff --git a/tasks/dungeon/assets/assets_dungeon_event.py b/tasks/dungeon/assets/assets_dungeon_event.py index ca29c1110..e330b7808 100644 --- a/tasks/dungeon/assets/assets_dungeon_event.py +++ b/tasks/dungeon/assets/assets_dungeon_event.py @@ -37,10 +37,10 @@ OCR_DOUBLE_EVENT_REMAIN = ButtonWrapper( name='OCR_DOUBLE_EVENT_REMAIN', share=Button( file='./assets/share/dungeon/event/OCR_DOUBLE_EVENT_REMAIN.png', - area=(513, 181, 1103, 203), - search=(493, 161, 1123, 223), - color=(201, 164, 88), - button=(513, 181, 1103, 203), + area=(517, 239, 1081, 261), + search=(497, 219, 1101, 281), + color=(198, 161, 90), + button=(517, 239, 1081, 261), ), ) OCR_DOUBLE_EVENT_REMAIN_AT_COMBAT = ButtonWrapper( diff --git a/tasks/dungeon/dungeon.py b/tasks/dungeon/dungeon.py index 6c7e5a60a..8bf32a05b 100644 --- a/tasks/dungeon/dungeon.py +++ b/tasks/dungeon/dungeon.py @@ -226,8 +226,7 @@ class Dungeon(DungeonStamina, DungeonEvent, Combat): ran_calyx_crimson = False ran_cavern_of_corrosion = False # Double calyx - if self.config.Dungeon_NameAtDoubleCalyx != 'do_not_participate' \ - and self.config.stored.DungeonDouble.calyx > 0: + if self.config.stored.DungeonDouble.calyx > 0: logger.info('Run double calyx') dungeon = DungeonList.find(self.config.Dungeon_NameAtDoubleCalyx) self.running_double = True @@ -237,8 +236,7 @@ class Dungeon(DungeonStamina, DungeonEvent, Combat): if dungeon.is_Calyx_Crimson: ran_calyx_crimson = True # Double relic - if self.config.Dungeon_NameAtDoubleRelic != 'do_not_participate' \ - and self.config.stored.DungeonDouble.relic > 0: + if self.config.stored.DungeonDouble.relic > 0: logger.info('Run double relic') dungeon = DungeonList.find(self.config.Dungeon_NameAtDoubleRelic) self.running_double = True diff --git a/tasks/dungeon/keywords/dungeon.py b/tasks/dungeon/keywords/dungeon.py index 52ef19cf1..35ee6a29a 100644 --- a/tasks/dungeon/keywords/dungeon.py +++ b/tasks/dungeon/keywords/dungeon.py @@ -123,8 +123,18 @@ Calyx_Crimson_Preservation_Herta_SupplyZone = DungeonList( es='Flor de la Conservación', plane_id=2000301, ) -Calyx_Crimson_The_Hunt_Jarilo_OutlyingSnowPlains = DungeonList( +Calyx_Crimson_Preservation_Penacony_ClockStudiosThemePark = DungeonList( id=13, + name='Calyx_Crimson_Preservation_Penacony_ClockStudiosThemePark', + cn='存护之蕾•拟造花萼(赤)', + cht='存護之蕾•擬造花萼(赤)', + en='Bud of Preservation', + jp='疑似花萼(赤)・存護の蕾', + es='Flor de la Conservación', + plane_id=2032101, +) +Calyx_Crimson_The_Hunt_Jarilo_OutlyingSnowPlains = DungeonList( + id=14, name='Calyx_Crimson_The_Hunt_Jarilo_OutlyingSnowPlains', cn='巡猎之蕾•拟造花萼(赤)', cht='巡獵之蕾•擬造花萼(赤)', @@ -134,7 +144,7 @@ Calyx_Crimson_The_Hunt_Jarilo_OutlyingSnowPlains = DungeonList( plane_id=2010101, ) Calyx_Crimson_Abundance_Jarilo_BackwaterPass = DungeonList( - id=14, + id=15, name='Calyx_Crimson_Abundance_Jarilo_BackwaterPass', cn='丰饶之蕾•拟造花萼(赤)', cht='豐饒之蕾•擬造花萼(赤)', @@ -143,8 +153,18 @@ Calyx_Crimson_Abundance_Jarilo_BackwaterPass = DungeonList( es='Flor de la Abundancia', plane_id=2011101, ) +Calyx_Crimson_Abundance_Luofu_FyxestrollGarden = DungeonList( + id=16, + name='Calyx_Crimson_Abundance_Luofu_FyxestrollGarden', + cn='丰饶之蕾•拟造花萼(赤)', + cht='豐饒之蕾•擬造花萼(赤)', + en='Bud of Abundance', + jp='疑似花萼(赤)・豊穣の蕾', + es='Flor de la Abundancia', + plane_id=2022301, +) Calyx_Crimson_Erudition_Jarilo_RivetTown = DungeonList( - id=15, + id=17, name='Calyx_Crimson_Erudition_Jarilo_RivetTown', cn='智识之蕾•拟造花萼(赤)', cht='智識之蕾•擬造花萼(赤)', @@ -154,7 +174,7 @@ Calyx_Crimson_Erudition_Jarilo_RivetTown = DungeonList( plane_id=2012201, ) Calyx_Crimson_Harmony_Jarilo_RobotSettlement = DungeonList( - id=16, + id=18, name='Calyx_Crimson_Harmony_Jarilo_RobotSettlement', cn='同谐之蕾•拟造花萼(赤)', cht='同諧之蕾•擬造花萼(赤)', @@ -164,7 +184,7 @@ Calyx_Crimson_Harmony_Jarilo_RobotSettlement = DungeonList( plane_id=2012301, ) Calyx_Crimson_Harmony_Penacony_TheReverieDreamscape = DungeonList( - id=17, + id=19, name='Calyx_Crimson_Harmony_Penacony_TheReverieDreamscape', cn='同谐之蕾•拟造花萼(赤)', cht='同諧之蕾•擬造花萼(赤)', @@ -174,7 +194,7 @@ Calyx_Crimson_Harmony_Penacony_TheReverieDreamscape = DungeonList( plane_id=2031101, ) Calyx_Crimson_Nihility_Jarilo_GreatMine = DungeonList( - id=18, + id=20, name='Calyx_Crimson_Nihility_Jarilo_GreatMine', cn='虚无之蕾•拟造花萼(赤)', cht='虛無之蕾•擬造花萼(赤)', @@ -184,7 +204,7 @@ Calyx_Crimson_Nihility_Jarilo_GreatMine = DungeonList( plane_id=2012101, ) Calyx_Crimson_Nihility_Luofu_AlchemyCommission = DungeonList( - id=19, + id=21, name='Calyx_Crimson_Nihility_Luofu_AlchemyCommission', cn='虚无之蕾•拟造花萼(赤)', cht='虛無之蕾•擬造花萼(赤)', @@ -194,7 +214,7 @@ Calyx_Crimson_Nihility_Luofu_AlchemyCommission = DungeonList( plane_id=2023101, ) Stagnant_Shadow_Quanta = DungeonList( - id=20, + id=22, name='Stagnant_Shadow_Quanta', cn='空海之形•凝滞虚影', cht='空海之形•凝滯虛影', @@ -204,7 +224,7 @@ Stagnant_Shadow_Quanta = DungeonList( plane_id=2000101, ) Stagnant_Shadow_Gust = DungeonList( - id=21, + id=23, name='Stagnant_Shadow_Gust', cn='巽风之形•凝滞虚影', cht='巽風之形•凝滯虛影', @@ -214,7 +234,7 @@ Stagnant_Shadow_Gust = DungeonList( plane_id=2012201, ) Stagnant_Shadow_Fulmination = DungeonList( - id=22, + id=24, name='Stagnant_Shadow_Fulmination', cn='鸣雷之形•凝滞虚影', cht='鳴雷之形•凝滯虛影', @@ -224,7 +244,7 @@ Stagnant_Shadow_Fulmination = DungeonList( plane_id=2013201, ) Stagnant_Shadow_Blaze = DungeonList( - id=23, + id=25, name='Stagnant_Shadow_Blaze', cn='炎华之形•凝滞虚影', cht='炎華之形•凝滯虛影', @@ -234,7 +254,7 @@ Stagnant_Shadow_Blaze = DungeonList( plane_id=2013101, ) Stagnant_Shadow_Spike = DungeonList( - id=24, + id=26, name='Stagnant_Shadow_Spike', cn='锋芒之形•凝滞虚影', cht='鋒芒之形•凝滯虛影', @@ -244,7 +264,7 @@ Stagnant_Shadow_Spike = DungeonList( plane_id=2012101, ) Stagnant_Shadow_Rime = DungeonList( - id=25, + id=27, name='Stagnant_Shadow_Rime', cn='霜晶之形•凝滞虚影', cht='霜晶之形•凝滯虛影', @@ -254,7 +274,7 @@ Stagnant_Shadow_Rime = DungeonList( plane_id=2013201, ) Stagnant_Shadow_Mirage = DungeonList( - id=26, + id=28, name='Stagnant_Shadow_Mirage', cn='幻光之形•凝滞虚影', cht='幻光之形•凝滯虛影', @@ -264,7 +284,7 @@ Stagnant_Shadow_Mirage = DungeonList( plane_id=2011101, ) Stagnant_Shadow_Icicle = DungeonList( - id=27, + id=29, name='Stagnant_Shadow_Icicle', cn='冰棱之形•凝滞虚影', cht='冰稜之形•凝滯虛影', @@ -274,7 +294,7 @@ Stagnant_Shadow_Icicle = DungeonList( plane_id=2021101, ) Stagnant_Shadow_Doom = DungeonList( - id=28, + id=30, name='Stagnant_Shadow_Doom', cn='震厄之形•凝滞虚影', cht='震厄之形•凝滯虛影', @@ -284,7 +304,7 @@ Stagnant_Shadow_Doom = DungeonList( plane_id=2021201, ) Stagnant_Shadow_Puppetry = DungeonList( - id=29, + id=31, name='Stagnant_Shadow_Puppetry', cn='偃偶之形•凝滞虚影', cht='偃偶之形•凝滯虛影', @@ -294,7 +314,7 @@ Stagnant_Shadow_Puppetry = DungeonList( plane_id=2022201, ) Stagnant_Shadow_Abomination = DungeonList( - id=30, + id=32, name='Stagnant_Shadow_Abomination', cn='孽兽之形•凝滞虚影', cht='孽獸之形•凝滯虛影', @@ -304,7 +324,7 @@ Stagnant_Shadow_Abomination = DungeonList( plane_id=2023201, ) Stagnant_Shadow_Scorch = DungeonList( - id=31, + id=33, name='Stagnant_Shadow_Scorch', cn='燔灼之形•凝滞虚影', cht='燔灼之形•凝滯虛影', @@ -314,7 +334,7 @@ Stagnant_Shadow_Scorch = DungeonList( plane_id=2012101, ) Stagnant_Shadow_Celestial = DungeonList( - id=32, + id=34, name='Stagnant_Shadow_Celestial', cn='天人之形•凝滞虚影', cht='天人之形•凝滯虛影', @@ -324,7 +344,7 @@ Stagnant_Shadow_Celestial = DungeonList( plane_id=2023101, ) Stagnant_Shadow_Perdition = DungeonList( - id=33, + id=35, name='Stagnant_Shadow_Perdition', cn='幽府之形•凝滞虚影', cht='幽府之形•凝滯虛影', @@ -334,7 +354,7 @@ Stagnant_Shadow_Perdition = DungeonList( plane_id=2022301, ) Stagnant_Shadow_Nectar = DungeonList( - id=34, + id=36, name='Stagnant_Shadow_Nectar', cn='冰酿之形•凝滞虚影', cht='冰釀之形•凝滯虛影', @@ -344,7 +364,7 @@ Stagnant_Shadow_Nectar = DungeonList( plane_id=2031101, ) Stagnant_Shadow_Roast = DungeonList( - id=35, + id=37, name='Stagnant_Shadow_Roast', cn='焦炙之形•凝滞虚影', cht='焦炙之形•凝滯虛影', @@ -353,8 +373,18 @@ Stagnant_Shadow_Roast = DungeonList( es='Forma del agostamiento', plane_id=2031301, ) +Stagnant_Shadow_Ire = DungeonList( + id=38, + name='Stagnant_Shadow_Ire', + cn='嗔怒之形•凝滞虚影', + cht='嗔怒之形•凝滯虛影', + en='Shape of Ire', + jp='凝結虚影・憤怒の形', + es='Forma de la ira', + plane_id=2032201, +) Cavern_of_Corrosion_Path_of_Gelid_Wind = DungeonList( - id=36, + id=39, name='Cavern_of_Corrosion_Path_of_Gelid_Wind', cn='霜风之径•侵蚀隧洞', cht='霜風之徑•侵蝕隧洞', @@ -364,7 +394,7 @@ Cavern_of_Corrosion_Path_of_Gelid_Wind = DungeonList( plane_id=2000201, ) Cavern_of_Corrosion_Path_of_Jabbing_Punch = DungeonList( - id=37, + id=40, name='Cavern_of_Corrosion_Path_of_Jabbing_Punch', cn='迅拳之径•侵蚀隧洞', cht='迅拳之徑•侵蝕隧洞', @@ -374,7 +404,7 @@ Cavern_of_Corrosion_Path_of_Jabbing_Punch = DungeonList( plane_id=2013101, ) Cavern_of_Corrosion_Path_of_Drifting = DungeonList( - id=38, + id=41, name='Cavern_of_Corrosion_Path_of_Drifting', cn='漂泊之径•侵蚀隧洞', cht='漂泊之徑•侵蝕隧洞', @@ -384,7 +414,7 @@ Cavern_of_Corrosion_Path_of_Drifting = DungeonList( plane_id=2013201, ) Cavern_of_Corrosion_Path_of_Providence = DungeonList( - id=39, + id=42, name='Cavern_of_Corrosion_Path_of_Providence', cn='睿治之径•侵蚀隧洞', cht='睿治之徑•侵蝕隧洞', @@ -394,7 +424,7 @@ Cavern_of_Corrosion_Path_of_Providence = DungeonList( plane_id=2013401, ) Cavern_of_Corrosion_Path_of_Holy_Hymn = DungeonList( - id=40, + id=43, name='Cavern_of_Corrosion_Path_of_Holy_Hymn', cn='圣颂之径•侵蚀隧洞', cht='聖頌之徑•侵蝕隧洞', @@ -404,7 +434,7 @@ Cavern_of_Corrosion_Path_of_Holy_Hymn = DungeonList( plane_id=2021101, ) Cavern_of_Corrosion_Path_of_Conflagration = DungeonList( - id=41, + id=44, name='Cavern_of_Corrosion_Path_of_Conflagration', cn='野焰之径•侵蚀隧洞', cht='野焰之徑•侵蝕隧洞', @@ -414,7 +444,7 @@ Cavern_of_Corrosion_Path_of_Conflagration = DungeonList( plane_id=2021201, ) Cavern_of_Corrosion_Path_of_Elixir_Seekers = DungeonList( - id=42, + id=45, name='Cavern_of_Corrosion_Path_of_Elixir_Seekers', cn='药使之径•侵蚀隧洞', cht='藥使之徑•侵蝕隧洞', @@ -424,7 +454,7 @@ Cavern_of_Corrosion_Path_of_Elixir_Seekers = DungeonList( plane_id=2023101, ) Cavern_of_Corrosion_Path_of_Darkness = DungeonList( - id=43, + id=46, name='Cavern_of_Corrosion_Path_of_Darkness', cn='幽冥之径•侵蚀隧洞', cht='幽冥之徑•侵蝕隧洞', @@ -434,7 +464,7 @@ Cavern_of_Corrosion_Path_of_Darkness = DungeonList( plane_id=2022301, ) Cavern_of_Corrosion_Path_of_Dreamdive = DungeonList( - id=44, + id=47, name='Cavern_of_Corrosion_Path_of_Dreamdive', cn='梦潜之径•侵蚀隧洞', cht='夢潛之徑•侵蝕隧洞', @@ -444,7 +474,7 @@ Cavern_of_Corrosion_Path_of_Dreamdive = DungeonList( plane_id=2031101, ) Echo_of_War_Destruction_Beginning = DungeonList( - id=45, + id=48, name='Echo_of_War_Destruction_Beginning', cn='毁灭的开端•历战余响', cht='毀滅的開端•歷戰餘響', @@ -454,7 +484,7 @@ Echo_of_War_Destruction_Beginning = DungeonList( plane_id=2000301, ) Echo_of_War_End_of_the_Eternal_Freeze = DungeonList( - id=46, + id=49, name='Echo_of_War_End_of_the_Eternal_Freeze', cn='寒潮的落幕•历战余响', cht='寒潮的落幕•歷戰餘響', @@ -464,7 +494,7 @@ Echo_of_War_End_of_the_Eternal_Freeze = DungeonList( plane_id=2013401, ) Echo_of_War_Divine_Seed = DungeonList( - id=47, + id=50, name='Echo_of_War_Divine_Seed', cn='不死的神实•历战余响', cht='不死的神實•歷戰餘響', @@ -474,7 +504,7 @@ Echo_of_War_Divine_Seed = DungeonList( plane_id=2023201, ) Echo_of_War_Borehole_Planet_Old_Crater = DungeonList( - id=48, + id=51, name='Echo_of_War_Borehole_Planet_Old_Crater', cn='蛀星的旧靥•历战余响', cht='蛀星的舊靨•歷戰餘響', @@ -484,7 +514,7 @@ Echo_of_War_Borehole_Planet_Old_Crater = DungeonList( plane_id=2000401, ) Simulated_Universe_World_1 = DungeonList( - id=49, + id=52, name='Simulated_Universe_World_1', cn='第一世界•模拟宇宙', cht='第一世界•模擬宇宙', @@ -494,7 +524,7 @@ Simulated_Universe_World_1 = DungeonList( plane_id=100000104, ) Simulated_Universe_World_3 = DungeonList( - id=50, + id=53, name='Simulated_Universe_World_3', cn='第三世界•模拟宇宙', cht='第三世界•模擬宇宙', @@ -504,7 +534,7 @@ Simulated_Universe_World_3 = DungeonList( plane_id=100000104, ) Simulated_Universe_World_4 = DungeonList( - id=51, + id=54, name='Simulated_Universe_World_4', cn='第四世界•模拟宇宙', cht='第四世界•模擬宇宙', @@ -514,7 +544,7 @@ Simulated_Universe_World_4 = DungeonList( plane_id=100000104, ) Simulated_Universe_World_5 = DungeonList( - id=52, + id=55, name='Simulated_Universe_World_5', cn='第五世界•模拟宇宙', cht='第五世界•模擬宇宙', @@ -524,7 +554,7 @@ Simulated_Universe_World_5 = DungeonList( plane_id=100000104, ) Simulated_Universe_World_6 = DungeonList( - id=53, + id=56, name='Simulated_Universe_World_6', cn='第六世界•模拟宇宙', cht='第六世界•模擬宇宙', @@ -534,7 +564,7 @@ Simulated_Universe_World_6 = DungeonList( plane_id=100000104, ) Simulated_Universe_World_7 = DungeonList( - id=54, + id=57, name='Simulated_Universe_World_7', cn='第七世界•模拟宇宙', cht='第七世界•模擬宇宙', @@ -544,7 +574,7 @@ Simulated_Universe_World_7 = DungeonList( plane_id=100000104, ) Simulated_Universe_World_8 = DungeonList( - id=55, + id=58, name='Simulated_Universe_World_8', cn='第八世界•模拟宇宙', cht='第八世界•模擬宇宙', @@ -553,8 +583,18 @@ Simulated_Universe_World_8 = DungeonList( es='Mundo 8', plane_id=100000104, ) +Simulated_Universe_World_9 = DungeonList( + id=59, + name='Simulated_Universe_World_9', + cn='第九世界•模拟宇宙', + cht='第九世界•模擬宇宙', + en='Simulated Universe: World 9', + jp='第九世界・模擬宇宙', + es='Mundo 9', + plane_id=100000104, +) Simulated_Universe_The_Swarm_Disaster = DungeonList( - id=56, + id=60, name='Simulated_Universe_The_Swarm_Disaster', cn='寰宇蝗灾', cht='寰宇蝗災', @@ -564,7 +604,7 @@ Simulated_Universe_The_Swarm_Disaster = DungeonList( plane_id=-1, ) Simulated_Universe_Gold_and_Gears = DungeonList( - id=57, + id=61, name='Simulated_Universe_Gold_and_Gears', cn='黄金与机械', cht='黃金與機械', @@ -574,7 +614,7 @@ Simulated_Universe_Gold_and_Gears = DungeonList( plane_id=-1, ) Memory_of_Chaos = DungeonList( - id=58, + id=62, name='Memory_of_Chaos', cn='混沌回忆', cht='混沌回憶', @@ -584,7 +624,7 @@ Memory_of_Chaos = DungeonList( plane_id=-1, ) The_Voyage_of_Navis_Astriger = DungeonList( - id=59, + id=63, name='The_Voyage_of_Navis_Astriger', cn='天艟求仙迷航录', cht='天艟求仙迷航錄', @@ -594,7 +634,7 @@ The_Voyage_of_Navis_Astriger = DungeonList( plane_id=-1, ) The_Last_Vestiges_of_Towering_Citadel = DungeonList( - id=60, + id=64, 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 89a905750..4258f6e68 100644 --- a/tasks/dungeon/keywords/dungeon_detailed.py +++ b/tasks/dungeon/keywords/dungeon_detailed.py @@ -78,20 +78,20 @@ Stagnant_Shadow_Icicle = DungeonDetailed( Stagnant_Shadow_Doom = DungeonDetailed( id=9, name='Stagnant_Shadow_Doom', - cn='角色晋阶材料:雷(卡芙卡 / 景元)', - cht='角色晉階材料:雷(卡芙卡 / 景元)', - en='Ascension: Lightning (Kafka / Jing Yuan)', - jp='キャラクター昇格素材:雷(カフカ / 景元)', - es='Ascension: Rayo (Kafka / Jing Yuan)', + cn='角色晋阶材料:雷(卡芙卡 / 景元 / 黄泉)', + cht='角色晉階材料:雷(卡芙卡 / 景元 / 黃泉)', + en='Ascension: Lightning (Kafka / Jing Yuan / Acheron)', + jp='キャラクター昇格素材:雷(カフカ / 景元 / 黄泉)', + es='Ascension: Rayo (Kafka / Jing Yuan / Acheron)', ) Stagnant_Shadow_Puppetry = DungeonDetailed( id=10, name='Stagnant_Shadow_Puppetry', - cn='角色晋阶材料:虚数(丹恒•饮月 / 真理医生)', - cht='角色晉階材料:虛數(丹恆•飲月 / 真理醫生)', - en='Ascension: Imaginary (Dan Heng • Imbibitor Lunae / Dr. Ratio)', - jp='キャラクター昇格素材:虚数(丹恒・飲月 / Dr.レイシオ)', - es='Ascension: Imaginario (Dan Heng - Imbibitor Lunae / Dr. Ratio)', + cn='角色晋阶材料:虚数(丹恒•饮月 / 砂金 / 真理医生)', + cht='角色晉階材料:虛數(丹恆•飲月 / 砂金 / 真理醫生)', + en='Ascension: Imaginary (Dan Heng • Imbibitor Lunae / Aventurine / Dr. Ratio)', + jp='キャラクター昇格素材:虚数(丹恒・飲月 / アベンチュリン / Dr.レイシオ)', + es='Ascension: Imaginario (Dan Heng - Imbibitor Lunae / Aventurino / Dr. Ratio)', ) Stagnant_Shadow_Abomination = DungeonDetailed( id=11, @@ -147,3 +147,12 @@ Stagnant_Shadow_Roast = DungeonDetailed( jp='キャラクター昇格素材:量子(花火)', es='Ascension: Cuántico (Sparkle)', ) +Stagnant_Shadow_Ire = DungeonDetailed( + id=17, + name='Stagnant_Shadow_Ire', + cn='角色晋阶材料:火(加拉赫)', + cht='角色晉階材料:火(加拉赫)', + en='Ascension: Fire (Gallagher)', + jp='キャラクター昇格素材:炎(ギャラガー)', + es='Ascension: Fuego (Gallagher)', +) diff --git a/tasks/item/assets/assets_item_consumable_usage.py b/tasks/item/assets/assets_item_consumable_usage.py index 1670c72b3..12549bf8c 100644 --- a/tasks/item/assets/assets_item_consumable_usage.py +++ b/tasks/item/assets/assets_item_consumable_usage.py @@ -7,10 +7,10 @@ ITEM_CONSUMABLE_SCROLL = ButtonWrapper( name='ITEM_CONSUMABLE_SCROLL', share=Button( file='./assets/share/item/consumable_usage/ITEM_CONSUMABLE_SCROLL.png', - area=(837, 89, 843, 615), - search=(817, 69, 863, 635), - color=(118, 117, 121), - button=(837, 89, 843, 615), + area=(838, 90, 842, 614), + search=(818, 70, 862, 634), + color=(141, 141, 153), + button=(838, 90, 842, 614), ), ) SIMPLE_PROTECTIVE_GEAR = ButtonWrapper( diff --git a/tasks/item/consumable_usage.py b/tasks/item/consumable_usage.py index 6df481dc5..e1d67180b 100644 --- a/tasks/item/consumable_usage.py +++ b/tasks/item/consumable_usage.py @@ -1,5 +1,5 @@ from module.ocr.ocr import * -from module.ui.scroll import Scroll +from module.ui.scroll import AdaptiveScroll from tasks.base.assets.assets_base_popup import POPUP_CONFIRM from tasks.base.page import page_item from tasks.daily.assets.assets_daily_synthesize_consumable import \ @@ -54,7 +54,7 @@ class ConsumableUsageUI(ItemUI): # Determine if there is a scroll bar. If there is a scroll bar, # pull it down and check if the consumable to be used can be found - scroll = Scroll(area=ITEM_CONSUMABLE_SCROLL.button, color=(200, 200, 200), name=ITEM_CONSUMABLE_SCROLL.name) + scroll = AdaptiveScroll(area=ITEM_CONSUMABLE_SCROLL.button, name=ITEM_CONSUMABLE_SCROLL.name) if scroll.appear(main=self): if not scroll.at_top(main=self): scroll.set_top(main=self) diff --git a/tasks/login/assets/assets_login.py b/tasks/login/assets/assets_login.py index 5352a9c6a..e7f36c8f0 100644 --- a/tasks/login/assets/assets_login.py +++ b/tasks/login/assets/assets_login.py @@ -5,13 +5,22 @@ from module.base.button import Button, ButtonWrapper LOGIN_CONFIRM = ButtonWrapper( name='LOGIN_CONFIRM', - share=Button( - file='./assets/share/login/LOGIN_CONFIRM.png', - area=(1188, 44, 1220, 74), - search=(1168, 24, 1240, 94), - color=(140, 124, 144), - button=(683, 327, 1143, 620), - ), + share=[ + Button( + file='./assets/share/login/LOGIN_CONFIRM.png', + area=(1188, 44, 1220, 74), + search=(1168, 24, 1240, 94), + color=(140, 124, 144), + button=(683, 327, 1143, 620), + ), + Button( + file='./assets/share/login/LOGIN_CONFIRM.2.png', + area=(1109, 48, 1139, 73), + search=(1089, 28, 1159, 93), + color=(149, 145, 164), + button=(683, 327, 1143, 620), + ), + ], ) LOGIN_LOADING = ButtonWrapper( name='LOGIN_LOADING', diff --git a/tasks/login/cloud.py b/tasks/login/cloud.py new file mode 100644 index 000000000..d4339e34a --- /dev/null +++ b/tasks/login/cloud.py @@ -0,0 +1,389 @@ +import re + +from module.base.base import ModuleBase +from module.base.timer import Timer +from module.base.utils import area_offset, random_rectangle_vector_opted +from module.device.method.utils import AreaButton +from module.exception import GameNotRunningError, RequestHumanTakeover +from module.logger import logger + + +class XPath: + """ + xpath 元素,元素可通过 uiautomator2 内的 weditor.exe 查找 + """ + + """ + 登录界面元素 + """ + # 帐号登录界面的进入游戏按钮,有这按钮说明帐号没登录 + ACCOUNT_LOGIN = '//*[@text="进入游戏"]' + # 登录后的弹窗,获得免费时长 + GET_REWARD = '//*[@text="点击空白区域关闭"]' + # 用户协议和隐私政策更新提示 + # - 拒绝 - 接受 + AGREEMENT_ACCEPT = '//*[@text="接受"]' + # 版本更新 + # - 立即更新 + UPDATE_CONFIRM = '//*[@resource-id="com.miHoYo.cloudgames.hkrpg:id/mUpgradeDialogOK"]' + # 新版本已下载完成 + # - 开始安装 + UPDATE_INSTALL = '//*[@resource-id="com.miHoYo.cloudgames.hkrpg:id/mBtnConfirm"]' + # 安卓系统弹窗 + # 要更新此应用吗?- 取消 - 更新 + # 已完成安装应用。-完成 -打开 + ANDROID_UPDATE_CONFIRM = '//*[@resource-id="android:id/button1"]' + # 补丁资源已更新,重启游戏可活动更好的游玩体验 + # - 下次再说 - 关闭游戏 + POPUP_TITLE = '//*[@resource-id="com.miHoYo.cloudgames.hkrpg:id/titleTv"]' + POPUP_CONFIRM = '//*[@resource-id="com.miHoYo.cloudgames.hkrpg:id/confirmTv"]' + POPUP_CANCEL = '//*[@resource-id="com.miHoYo.cloudgames.hkrpg:id/cancelTv"]' + # 畅玩卡的剩余时间 + REMAIN_SEASON_PASS = '//*[@resource-id="com.miHoYo.cloudgames.hkrpg:id/tvCardStatus"]' + # 星云币时长:0 分钟 + REMAIN_PAID = '//*[@resource-id="com.miHoYo.cloudgames.hkrpg:id/tvMiCoinDuration"]' + # 免费时长: 600 分钟 + REMAIN_FREE = '//*[@resource-id="com.miHoYo.cloudgames.hkrpg:id/tvRemainingFreeTime"]' + # 主界面的开始游戏按钮 + START_GAME = '//*[@resource-id="com.miHoYo.cloudgames.hkrpg:id/btnLauncher"]' + # 排队剩余时间 + QUEUE_REMAIN = '//*[@resource-id="com.miHoYo.cloudgames.hkrpg:id/tvQueueInfoWaitTimeContent"]' + + """ + 游戏界面元素 + """ + # 网络状态 简洁 + FLOAT_STATE_SIMPLE = '//*[@resource-id="com.miHoYo.cloudgames.hkrpg:id/tvSimpleNetStateMode"]' + # 网络状态 详细 + FLOAT_STATE_DETAIL = '//*[@resource-id="com.miHoYo.cloudgames.hkrpg:id/tv_ping_value"]' + """ + 悬浮窗及侧边栏元素 + """ + # 悬浮窗 + FLOAT_WINDOW = '//*[@class="android.widget.ImageView"]' + # 弹出侧边栏的 节点信息 + # 将这个区域向右偏移作为退出悬浮窗的按钮 + FLOAT_DELAY = '//*[@resource-id="com.miHoYo.cloudgames.hkrpg:id/tv_node_region"]' + # 弹出侧边栏的滚动区域 + SCROLL_VIEW = '//*[@resource-id="com.miHoYo.cloudgames.hkrpg:id/innerScrollView"]' + # 画质选择 超高清 + # 选中时selected=True + SETTING_BITRATE_UHD = '//*[@text="超高清"]' + # 网络状态 开关 + SETTING_NET_STATE_TOGGLE = '//*[@resource-id="com.miHoYo.cloudgames.hkrpg:id/sw_net_state"]' + SETTING_NET_STATE_SIMPLE = '//*[@resource-id="com.miHoYo.cloudgames.hkrpg:id/mTvTitleOfSimpleMode"]' + SETTING_NET_STATE_DETAIL = '//*[@resource-id="com.miHoYo.cloudgames.hkrpg:id/mTvTitleOfDetailMode"]' + # 问题反馈 + SETTING_PROBLEM = '//*[@resource-id="com.miHoYo.cloudgames.hkrpg:id/tv_problem"]' + # 下载游戏 + SETTING_DOWNLOAD = '//*[@resource-id="com.miHoYo.cloudgames.hkrpg:id/tv_downloadGame"]' + + +class LoginAndroidCloud(ModuleBase): + def _cloud_start(self, skip_first=False): + """ + Pages: + out: START_GAME + """ + logger.hr('Cloud start') + update_checker = Timer(2) + while 1: + if skip_first: + skip_first = False + else: + self.device.dump_hierarchy() + + # End + if self.appear(XPath.START_GAME): + logger.info('Login to cloud main page') + break + if self.appear(XPath.ACCOUNT_LOGIN): + logger.critical('Account not login, you must have login once before running') + raise RequestHumanTakeover + if update_checker.started() and update_checker.reached(): + if not self.device.app_is_running(): + logger.error('Detected hot fixes from game server, game died') + raise GameNotRunningError('Game not running') + update_checker.clear() + + # Click + if self.appear_then_click(XPath.GET_REWARD): + continue + if self.appear_then_click(XPath.POPUP_CONFIRM): + update_checker.start() + continue + # Update + if self.appear_then_click(XPath.AGREEMENT_ACCEPT): + continue + if self.appear_then_click(XPath.UPDATE_CONFIRM): + continue + button = self.xpath(XPath.UPDATE_INSTALL) + if button.text == '开始安装': + if self.appear_then_click(button): + continue + button = self.xpath(XPath.ANDROID_UPDATE_CONFIRM) + if button.text in ['更新', '打开']: + if self.appear_then_click(button): + continue + + def _cloud_get_remain(self): + """ + Pages: + in: START_GAME + """ + regex = re.compile(r'(\d+)') + + text = self.xpath(XPath.REMAIN_SEASON_PASS).text + logger.info(f'Remain season pass: {text}') + if res := regex.search(text): + season_pass = int(res.group(1)) + else: + season_pass = 0 + + text = self.xpath(XPath.REMAIN_PAID).text + logger.info(f'Remain paid: {text}') + if res := regex.search(text): + paid = int(res.group(1)) + else: + paid = 0 + + text = self.xpath(XPath.REMAIN_FREE).text + logger.info(f'Remain free: {text}') + if res := regex.search(text): + free = int(res.group(1)) + else: + free = 0 + + logger.info(f'Cloud remain: season pass {season_pass} days, {paid} min paid, {free} min free') + with self.config.multi_set(): + self.config.stored.CloudRemainSeasonPass = season_pass + self.config.stored.CloudRemainPaid = paid + self.config.stored.CloudRemainFree = free + + def _cloud_enter(self, skip_first=False): + """ + Pages: + in: START_GAME + out: page_main + """ + logger.hr('Cloud enter') + while 1: + if skip_first: + skip_first = False + else: + self.device.dump_hierarchy() + + # End + button = self.xpath(XPath.FLOAT_WINDOW) + if self.appear(button): + # Confirm float window size + width, height = button.size + if (width < 120 and height < 120) and (width / height < 0.6 or height / width < 0.6): + logger.info('Cloud game entered') + break + + # Queue daemon + button = self.xpath(XPath.QUEUE_REMAIN) + if self.appear(button): + remain = button.text + logger.info(f'Queue remain: {remain}') + self.device.stuck_record_clear() + + # Click + if self.appear_then_click(XPath.GET_REWARD): + continue + if self.appear_then_click(XPath.START_GAME): + continue + if self.appear(XPath.POPUP_CONFIRM, interval=5): + title = self.xpath(XPath.POPUP_TITLE).text + logger.info(f'Popup: {title}') + # 计费提示 + # 本次游戏将使用畅玩卡无限畅玩 + # - 进入游戏(9s) - 退出游戏 + if title == '计费提示': + self.device.click(self.xpath(XPath.POPUP_CONFIRM)) + continue + # 是否使用星云币时长进入游戏 + # 使用后可优先排队进入游戏,本次游戏仅可使用星云币时长,无法消耗免费时长 + # - 确认使用 - 暂不使用 + if title == '是否使用星云币时长进入游戏': + self.device.click(self.xpath(XPath.POPUP_CONFIRM)) + continue + # 连接中断 + # 因为您长时间未操作游戏,已中断连接,错误码: -1022 + # - 退出游戏 + if title == '连接中断': + self.device.click(self.xpath(XPath.POPUP_CONFIRM)) + continue + + # Disable net state display + if self._cloud_net_state_appear(): + self._cloud_setting_disable_net_state() + # Login to game + from tasks.login.login import Login + Login(config=self.config, device=self.device).handle_app_login() + + def _cloud_setting_enter(self, skip_first=True): + while 1: + if skip_first: + skip_first = False + else: + self.device.dump_hierarchy() + + if self.appear(XPath.FLOAT_DELAY): + break + + if self.appear_then_click(XPath.FLOAT_WINDOW, interval=3): + continue + + def _cloud_setting_exit(self, skip_first=True): + while 1: + if skip_first: + skip_first = False + else: + self.device.dump_hierarchy() + + if self.appear(XPath.FLOAT_WINDOW): + break + + if self.appear(XPath.FLOAT_DELAY, interval=3): + area = self.xpath(XPath.FLOAT_DELAY).area + area = area_offset(area, offset=(150, 0)) + button = AreaButton(area=area, name='CLOUD_SETTING_EXIT') + self.device.click(button) + continue + + def _cloud_setting_disable_net_state(self, skip_first=True): + """ + Pages: + in: page_main + out: page_main + """ + self._cloud_setting_enter(skip_first=skip_first) + + skip_first = True + while 1: + if skip_first: + skip_first = False + else: + self.device.dump_hierarchy() + + button = self.xpath(XPath.SETTING_BITRATE_UHD) + if self.appear(button, interval=3): + if not button.selected: + logger.info('Set bitrate to UHD') + self.device.click(button) + continue + if self.appear(XPath.SETTING_NET_STATE_TOGGLE): + if self.appear(XPath.SETTING_NET_STATE_SIMPLE) or self.appear(XPath.SETTING_NET_STATE_DETAIL): + logger.info('Set net state to disabled') + self.appear_then_click(XPath.SETTING_NET_STATE_TOGGLE, interval=3) + continue + else: + logger.info('Net state display disabled') + break + # Scroll down + if not self.appear(XPath.SETTING_PROBLEM): + area = self.xpath(XPath.SCROLL_VIEW).area + # An area safe to swipe + area = (area[0], area[1], area[0] + 25, area[3]) + p1, p2 = random_rectangle_vector_opted( + (0, -450), box=area, random_range=(-10, -30, 10, 30), padding=2) + self.device.swipe(p1, p2, name='SETTING_SCROLL') + continue + + self._cloud_setting_exit(skip_first=True) + + def _cloud_net_state_appear(self): + """ + Returns: + bool: True if net state display is enabled + """ + if self.appear(XPath.FLOAT_STATE_SIMPLE): + logger.attr('Net state', 'FLOAT_STATE_SIMPLE') + return True + if self.appear(XPath.FLOAT_STATE_DETAIL): + logger.attr('Net state', 'FLOAT_STATE_DETAIL') + return True + logger.attr('Net state', None) + return False + + def cloud_ensure_ingame(self): + """ + Pages: + in: Any + out: page_main + """ + logger.hr('Cloud ensure ingame', level=1) + + with self.config.multi_set(): + if self.config.Emulator_GameClient != 'cloud_android': + self.config.Emulator_GameClient = 'cloud_android' + if self.config.Emulator_PackageName != 'CN-Official': + self.config.Emulator_PackageName = 'CN-Official' + if self.config.Optimization_WhenTaskQueueEmpty != 'close_game': + self.config.Optimization_WhenTaskQueueEmpty = 'close_game' + + for _ in range(3): + if self.device.app_is_running(): + logger.info('Cloud game is already running') + self.device.dump_hierarchy() + + if self.appear(XPath.START_GAME): + logger.info('Cloud game is in main page') + self._cloud_get_remain() + self._cloud_enter() + return True + elif self.appear(XPath.FLOAT_WINDOW): + logger.info('Cloud game is in game') + return True + elif self.appear(XPath.FLOAT_DELAY): + logger.info('Cloud game is in game with float window expanded') + self._cloud_setting_exit() + return True + elif self.appear(XPath.POPUP_CONFIRM): + logger.info('Cloud game have a popup') + self._cloud_enter() + return True + else: + try: + self._cloud_start() + except GameNotRunningError: + continue + self._cloud_get_remain() + self._cloud_enter() + return True + else: + logger.info('Cloud game is not running') + self.device.app_start() + try: + self._cloud_start() + except GameNotRunningError: + continue + self._cloud_get_remain() + self._cloud_enter() + return True + + logger.error('Failed to enter cloud game after 3 trials') + return False + + def cloud_keep_alive(self): + """ + Randomly do something to prevent being kicked + + WARNING: + this may cause extra fee + """ + logger.hr('cloud_keep_alive', level=2) + while 1: + self.device.sleep((45, 60)) + + logger.info('cloud_keep_alive') + self._cloud_setting_enter(skip_first=False) + self._cloud_setting_exit(skip_first=True) + + +if __name__ == '__main__': + self = LoginAndroidCloud('src') + self.cloud_ensure_ingame() + self.cloud_keep_alive() diff --git a/tasks/login/login.py b/tasks/login/login.py index 967f956ae..7bc6b0905 100644 --- a/tasks/login/login.py +++ b/tasks/login/login.py @@ -3,10 +3,11 @@ from module.exception import GameNotRunningError from module.logger import logger from tasks.base.page import page_main from tasks.base.ui import UI -from tasks.login.assets.assets_login import LOGIN_CONFIRM, USER_AGREEMENT_ACCEPT, LOGIN_LOADING +from tasks.login.assets.assets_login import LOGIN_CONFIRM, LOGIN_LOADING, USER_AGREEMENT_ACCEPT +from tasks.login.cloud import LoginAndroidCloud -class Login(UI): +class Login(UI, LoginAndroidCloud): def _handle_app_login(self): """ Pages: @@ -86,12 +87,33 @@ class Login(UI): def app_start(self): logger.hr('App start') - self.device.app_start() + if self.config.is_cloud_game: + self.cloud_ensure_ingame() + else: + self.device.app_start() self.handle_app_login() def app_restart(self): logger.hr('App restart') self.device.app_stop() - self.device.app_start() + if self.config.is_cloud_game: + self.cloud_ensure_ingame() + else: + self.device.app_start() self.handle_app_login() self.config.task_delay(server_update=True) + + def cloud_start(self): + if not self.config.is_cloud_game: + return + + logger.hr('Cloud start') + self.cloud_ensure_ingame() + self.handle_app_login() + + def cloud_stop(self): + if not self.config.is_cloud_game: + return + + logger.hr('Cloud stop') + self.app_stop() diff --git a/tasks/map/assets/assets_map_control.py b/tasks/map/assets/assets_map_control.py index 6aaa78af9..659f100a7 100644 --- a/tasks/map/assets/assets_map_control.py +++ b/tasks/map/assets/assets_map_control.py @@ -53,53 +53,63 @@ RUN_BUTTON = ButtonWrapper( button=(1147, 591, 1195, 639), ), ) +TECHNIQUE_POINT_0 = ButtonWrapper( + name='TECHNIQUE_POINT_0', + share=Button( + file='./assets/share/map/control/TECHNIQUE_POINT_0.png', + area=(884, 597, 891, 604), + search=(831, 589, 944, 612), + color=(56, 56, 56), + button=(884, 597, 891, 604), + ), +) TECHNIQUE_POINT_1 = ButtonWrapper( name='TECHNIQUE_POINT_1', share=Button( file='./assets/share/map/control/TECHNIQUE_POINT_1.png', - area=(881, 594, 894, 607), - search=(861, 574, 914, 627), - color=(149, 141, 186), - button=(881, 594, 894, 607), + area=(884, 597, 891, 604), + search=(831, 589, 944, 612), + color=(222, 213, 253), + button=(884, 597, 891, 604), ), ) TECHNIQUE_POINT_2 = ButtonWrapper( name='TECHNIQUE_POINT_2', share=Button( file='./assets/share/map/control/TECHNIQUE_POINT_2.png', - area=(889, 578, 903, 592), - search=(869, 558, 923, 612), - color=(139, 132, 174), - button=(889, 578, 903, 592), + area=(892, 581, 900, 589), + search=(872, 561, 920, 609), + color=(213, 203, 249), + button=(892, 581, 900, 589), ), ) TECHNIQUE_POINT_3 = ButtonWrapper( name='TECHNIQUE_POINT_3', share=Button( file='./assets/share/map/control/TECHNIQUE_POINT_3.png', - area=(902, 566, 916, 580), - search=(882, 546, 936, 600), - color=(138, 130, 173), - button=(902, 566, 916, 580), + area=(905, 569, 913, 577), + search=(885, 549, 933, 597), + color=(207, 195, 249), + button=(905, 569, 913, 577), ), ) TECHNIQUE_POINT_4 = ButtonWrapper( name='TECHNIQUE_POINT_4', share=Button( file='./assets/share/map/control/TECHNIQUE_POINT_4.png', - area=(918, 559, 932, 573), - search=(898, 539, 952, 593), - color=(138, 130, 173), - button=(918, 559, 932, 573), + area=(921, 562, 929, 570), + search=(901, 542, 949, 590), + color=(210, 198, 248), + button=(921, 562, 929, 570), ), ) TECHNIQUE_POINT_5 = ButtonWrapper( name='TECHNIQUE_POINT_5', share=Button( file='./assets/share/map/control/TECHNIQUE_POINT_5.png', - area=(935, 559, 948, 573), - search=(915, 539, 968, 593), - color=(71, 72, 77), - button=(935, 559, 948, 573), + area=(938, 562, 945, 570), + search=(918, 542, 965, 590), + color=(215, 203, 250), + button=(938, 562, 945, 570), ), ) diff --git a/tasks/map/control/joystick.py b/tasks/map/control/joystick.py index 86480a934..1d1372e07 100644 --- a/tasks/map/control/joystick.py +++ b/tasks/map/control/joystick.py @@ -5,6 +5,7 @@ import cv2 import numpy as np from module.base.timer import Timer +from module.base.utils import area_offset from module.device.method.maatouch import MaatouchBuilder from module.device.method.minitouch import CommandBuilder, insert_swipe, random_normal_distribution from module.exception import ScriptError @@ -195,18 +196,35 @@ class MapControlJoystick(UI): def map_get_technique_points(self): """ Returns: - int: 0 to 5. + int: 0 to 5 """ - points = [ - self.image_color_count(button, color=(255, 255, 255), threshold=221, count=20) - for button in [ - TECHNIQUE_POINT_1, - TECHNIQUE_POINT_2, - TECHNIQUE_POINT_3, - TECHNIQUE_POINT_4, - TECHNIQUE_POINT_5, - ] - ] + confirm = Timer(3, count=0).start() + while 1: + matched = TECHNIQUE_POINT_1.match_template(self.device.image) + if matched: + matched_button = TECHNIQUE_POINT_1 + break + matched = TECHNIQUE_POINT_0.match_template(self.device.image) + if matched: + matched_button = TECHNIQUE_POINT_0 + break + if confirm.reached(): + logger.warning('Can not match technique points.') + return 0 + else: + self.device.screenshot() + points = [] + for button in [ + TECHNIQUE_POINT_1, + TECHNIQUE_POINT_2, + TECHNIQUE_POINT_3, + TECHNIQUE_POINT_4, + TECHNIQUE_POINT_5, + ]: + if matched_button is not None: + button.load_offset(matched_button) + points.append(self.image_color_count(area_offset(button.area, button.button_offset), color=(255, 255, 255), + threshold=221, count=20)) count = sum(points) logger.attr('TechniquePoints', count) return count diff --git a/tasks/map/keywords/plane.py b/tasks/map/keywords/plane.py index 7e2fc76c7..b77c5adc6 100644 --- a/tasks/map/keywords/plane.py +++ b/tasks/map/keywords/plane.py @@ -465,3 +465,25 @@ Penacony_TheReverieDreamscape = MapPlane( world_id=3, plane_id=2031101, ) +Penacony_DewlightPavilion = MapPlane( + id=43, + name='Penacony_DewlightPavilion', + cn='朝露公馆', + cht='朝露公館', + en='Dewlight Pavilion', + jp='朝露の館', + es='Pabellón del Rocío Matutino', + world_id=3, + plane_id=2032201, +) +Penacony_ClockStudiosThemePark = MapPlane( + id=44, + name='Penacony_ClockStudiosThemePark', + cn='克劳克影视乐园', + cht='克勞克影視樂園', + en='Clock Studios Theme Park', + jp='クラークフィルムランド', + es='Parque temático de los Estudios Reloj', + world_id=3, + plane_id=2032101, +) diff --git a/tasks/rogue/assets/assets_rogue_ui.py b/tasks/rogue/assets/assets_rogue_ui.py index 8e55115ac..253b5598a 100644 --- a/tasks/rogue/assets/assets_rogue_ui.py +++ b/tasks/rogue/assets/assets_rogue_ui.py @@ -86,13 +86,22 @@ CURIO_OBTAINED = ButtonWrapper( color=(125, 126, 134), button=(643, 86, 708, 117), ), - en=Button( - file='./assets/en/rogue/ui/CURIO_OBTAINED.png', - area=(511, 88, 600, 116), - search=(491, 68, 620, 136), - color=(93, 95, 102), - button=(511, 88, 600, 116), - ), + en=[ + Button( + file='./assets/en/rogue/ui/CURIO_OBTAINED.png', + area=(511, 88, 600, 116), + search=(491, 68, 620, 136), + color=(93, 95, 102), + button=(511, 88, 600, 116), + ), + Button( + file='./assets/en/rogue/ui/CURIO_OBTAINED.2.png', + area=(526, 46, 605, 71), + search=(506, 26, 625, 91), + color=(103, 91, 66), + button=(526, 46, 605, 71), + ), + ], ) FLAG_UNRECORD = ButtonWrapper( name='FLAG_UNRECORD', diff --git a/tasks/rogue/event/event.py b/tasks/rogue/event/event.py index c2f44e709..97daf9ccc 100644 --- a/tasks/rogue/event/event.py +++ b/tasks/rogue/event/event.py @@ -92,10 +92,10 @@ class OcrRogueEventOption(OcrRogueEvent): (KEYWORDS_ROGUE_EVENT_OPTION.Deposit_2_Cosmic_Fragments, '存入\d+.*'), (KEYWORDS_ROGUE_EVENT_OPTION.Withdraw_2_Cosmic_Fragments, '取出\d+.*'), (KEYWORDS_ROGUE_EVENT_OPTION.Record_of_the_Aeon_of_1, '^关于.*'), - (KEYWORDS_ROGUE_EVENT_OPTION.Wait_for_them, '^等待.*'), + (KEYWORDS_ROGUE_EVENT_OPTION.Wait_for_THEM, '^等待.*'), (KEYWORDS_ROGUE_EVENT_OPTION.Choose_number_two_It_snores_like_Andatur_Zazzalo, '.*二号.*安达.*'), (KEYWORDS_ROGUE_EVENT_OPTION.Choose_number_three_Its_teeth_are_rusted, '.*三号.*牙齿.*'), - (KEYWORDS_ROGUE_EVENT_OPTION.Believe_in_them_with_pure_devotion, '虔诚信仰'), + (KEYWORDS_ROGUE_EVENT_OPTION.Believe_in_THEM_with_pure_devotion, '虔诚信仰'), ], 'en': [ (KEYWORDS_ROGUE_EVENT_OPTION.Deposit_2_Cosmic_Fragments, 'Deposit \d+.*'), diff --git a/tasks/rogue/event/preset.py b/tasks/rogue/event/preset.py index 0d93e5488..7aab20a89 100644 --- a/tasks/rogue/event/preset.py +++ b/tasks/rogue/event/preset.py @@ -41,7 +41,7 @@ STRATEGY_COMMON = { ] ], KEYWORDS_ROGUE_EVENT_TITLE.Statue: [ - KEYWORDS_ROGUE_EVENT_OPTION.Believe_in_them_with_pure_devotion, + KEYWORDS_ROGUE_EVENT_OPTION.Believe_in_THEM_with_pure_devotion, KEYWORDS_ROGUE_EVENT_OPTION.Discard_the_statue_Be_decisive ], KEYWORDS_ROGUE_EVENT_TITLE.Unending_Darkness: [ @@ -82,7 +82,7 @@ STRATEGY_COMMON = { ], KEYWORDS_ROGUE_EVENT_TITLE.The_Cremators: [ KEYWORDS_ROGUE_EVENT_OPTION.Bear_ten_carats_of_trash, - KEYWORDS_ROGUE_EVENT_OPTION.Give_everything_to_them, + KEYWORDS_ROGUE_EVENT_OPTION.Give_everything_to_THEM, ], KEYWORDS_ROGUE_EVENT_TITLE.Pixel_World: [ KEYWORDS_ROGUE_EVENT_OPTION.Jump_onto_the_bricks_to_the_right, @@ -145,7 +145,7 @@ STRATEGY_COMBAT = { ], KEYWORDS_ROGUE_EVENT_TITLE.Insect_Nest: [ KEYWORDS_ROGUE_EVENT_OPTION.Go_deeper_into_the_insect_nest, - KEYWORDS_ROGUE_EVENT_OPTION.Wait_for_them, + KEYWORDS_ROGUE_EVENT_OPTION.Wait_for_THEM, KEYWORDS_ROGUE_EVENT_OPTION.Stop_at_the_entrance_of_the_nest, KEYWORDS_ROGUE_EVENT_OPTION.Hug_it ], @@ -174,7 +174,7 @@ STRATEGY_OCCURRENCE = { KEYWORDS_ROGUE_EVENT_TITLE.Insect_Nest: [ KEYWORDS_ROGUE_EVENT_OPTION.Go_deeper_into_the_insect_nest, KEYWORDS_ROGUE_EVENT_OPTION.Hug_it, - KEYWORDS_ROGUE_EVENT_OPTION.Wait_for_them, + KEYWORDS_ROGUE_EVENT_OPTION.Wait_for_THEM, KEYWORDS_ROGUE_EVENT_OPTION.Stop_at_the_entrance_of_the_nest ] } diff --git a/tasks/rogue/keywords/curio.py b/tasks/rogue/keywords/curio.py index 87407f3d2..bfd7fedf3 100644 --- a/tasks/rogue/keywords/curio.py +++ b/tasks/rogue/keywords/curio.py @@ -486,7 +486,7 @@ Fissured_Cuckoo_Clock = RogueCurio( cn='分裂咕咕钟', cht='分裂咕咕鐘', en='Fissured Cuckoo Clock', - jp='機械式鳩時計', + jp='分裂鳩時計', es='Reloj de cuco agrietado', ) Typical_Genius_Society_Gossip = RogueCurio( diff --git a/tasks/rogue/keywords/event_option.py b/tasks/rogue/keywords/event_option.py index f18d18677..f391cec2c 100644 --- a/tasks/rogue/keywords/event_option.py +++ b/tasks/rogue/keywords/event_option.py @@ -237,12 +237,12 @@ Smash_this_television = RogueEventOption( jp='そのテレビを破壊する!', es='¡Destruye este televisor!', ) -Give_everything_to_them = RogueEventOption( +Give_everything_to_THEM = RogueEventOption( id=27, - name='Give_everything_to_them', + name='Give_everything_to_THEM', cn='将一切奉献给「祂」。', cht='將一切奉獻給「祂」。', - en='Give everything to "them."', + en='Give everything to "THEM."', jp='すべてを「其」に捧げる', es='Dedícalo todo a "ellos".', ) @@ -525,12 +525,12 @@ Discard_the_statue_Be_decisive = RogueEventOption( jp='彫像を捨てよう!きっぱりと!', es='¡Suelta la estatua! Con decisión.', ) -Believe_in_them_with_pure_devotion = RogueEventOption( +Believe_in_THEM_with_pure_devotion = RogueEventOption( id=59, - name='Believe_in_them_with_pure_devotion', + name='Believe_in_THEM_with_pure_devotion', cn='对「祂」虔诚信仰,身心无垢。', cht='對「祂」虔誠信仰,身心無垢。', - en='Believe in "them" with pure devotion.', + en='Believe in "THEM" with pure devotion.', jp='「其」に対する敬虔な信仰は、無垢である', es='Cree en "ellos" con gran devoción.', ) @@ -570,12 +570,12 @@ Hug_it = RogueEventOption( jp='抱擁する', es='Abrázalo.', ) -Wait_for_them = RogueEventOption( +Wait_for_THEM = RogueEventOption( id=64, - name='Wait_for_them', + name='Wait_for_THEM', cn='等待「祂」。', cht='等待「祂」。', - en='Wait for "them."', + en='Wait for "THEM."', jp='「其」を待つ', es='Espéralos.', ) @@ -1803,12 +1803,12 @@ Pretend_to_not_notice_that_something_was_off = RogueEventOption( jp='違和感を覚えていないフリをする', es='Finge que no te das cuenta de que algo anda mal.', ) -They_re_here = RogueEventOption( +THEY_re_here = RogueEventOption( id=201, - name='They_re_here', + name='THEY_re_here', cn='祂出现了!', cht='祂出現了!', - en="They're here!", + en="THEY're here!", jp='其が現れた!', es='¡Está aquí!', ) diff --git a/tasks/rogue/keywords/event_title.py b/tasks/rogue/keywords/event_title.py index 86490d346..2f8b375d7 100644 --- a/tasks/rogue/keywords/event_title.py +++ b/tasks/rogue/keywords/event_title.py @@ -943,22 +943,22 @@ Ka_ching_IPC_Banking_Part_2 = RogueEventTitle( es='El banco de la Corporación II', option_ids=[142, 277, 278, 279, 280, 281], ) -Loneliness_Costic_Beauty_Bugs_Simulated_Universe_Part_1 = RogueEventTitle( +Loneliness_Cosmic_Beauty_Bugs_Simulated_Universe_Part_1 = RogueEventTitle( id=95, - name='Loneliness_Costic_Beauty_Bugs_Simulated_Universe_Part_1', + name='Loneliness_Cosmic_Beauty_Bugs_Simulated_Universe_Part_1', cn='孤独,太空美虫,模拟宇宙(其一)', cht='孤獨,太空美蟲,模擬宇宙(其一)', - en='Loneliness, Costic Beauty Bugs, Simulated Universe (Part 1)', + en='Loneliness, Cosmic Beauty Bugs, Simulated Universe (Part 1)', jp='孤独、宇宙の美虫、模擬宇宙(1)', es='Soledad, gusanos espaciales y el Universo Simulado I', option_ids=[77, 282, 283, 284, 285, 286, 287, 288, 289], ) -Loneliness_Costic_Beauty_Bugs_Simulated_Universe_Part_2 = RogueEventTitle( +Loneliness_Cosmic_Beauty_Bugs_Simulated_Universe_Part_2 = RogueEventTitle( id=96, - name='Loneliness_Costic_Beauty_Bugs_Simulated_Universe_Part_2', + name='Loneliness_Cosmic_Beauty_Bugs_Simulated_Universe_Part_2', cn='孤独,太空美虫,模拟宇宙(其二)', cht='孤獨,太空美蟲,模擬宇宙(其二)', - en='Loneliness, Costic Beauty Bugs, Simulated Universe (Part 2)', + en='Loneliness, Cosmic Beauty Bugs, Simulated Universe (Part 2)', jp='孤独、宇宙の美虫、模擬宇宙(2)', es='Soledad, gusanos espaciales y el Universo Simulado II', option_ids=[77, 283, 284, 285, 286, 287, 288, 289], @@ -1120,7 +1120,7 @@ Insights_from_the_Universal_Dancer = RogueEventTitle( cht='寰宇舞者的啟示', en='Insights from the Universal Dancer', jp='世界の踊り手の啓示', - es='Reflexiones del bailarín universal', + es='Reflexiones de la bailarina universal', option_ids=[311, 312], ) Pixel_World_Hidden_Stage = RogueEventTitle( diff --git a/tasks/rogue/route/base.py b/tasks/rogue/route/base.py index 54d1f766b..7807aeda5 100644 --- a/tasks/rogue/route/base.py +++ b/tasks/rogue/route/base.py @@ -300,6 +300,11 @@ class RouteBase(RouteBase_, RogueExit, RogueEvent, RogueReward): """ logger.hr('Domain single exit', level=1) waypoints = ensure_waypoints(waypoints) + + for point in waypoints: + if 'item' not in point.expected_enroute: + point.expected_enroute.append('item') + end_point = waypoints[-1] end_point.min_speed = 'run' end_point.interact_radius = 5 diff --git a/tasks/rogue/route/loader.py b/tasks/rogue/route/loader.py index 588a9a447..b60be3d64 100644 --- a/tasks/rogue/route/loader.py +++ b/tasks/rogue/route/loader.py @@ -165,7 +165,13 @@ class RouteLoader(RogueUI, MinimapWrapper, RouteLoader_, CharacterSwitch): # return True # Before Combat_Luofu_Cloudford_F1_X281Y873 - if route.name == [ + if route.name in [ + 'Occurrence_Jarilo_BackwaterPass_F1_X553Y643', + 'Combat_Jarilo_GreatMine_F1_X545Y513', + 'Combat_Herta_SupplyZone_F2_X45Y369', + ] and similarity > 0.20: + return True + if route.name in [ 'Combat_Herta_StorageZone_F1_X273Y92', 'Occurrence_Herta_StorageZone_F1_X273Y93', 'Occurrence_Jarilo_RivetTown_F1_X289Y97', @@ -173,12 +179,20 @@ class RouteLoader(RogueUI, MinimapWrapper, RouteLoader_, CharacterSwitch): 'Occurrence_Luofu_ArtisanshipCommission_F1_X169Y491', ] and similarity > 0.1: return True + # Luofu_Cloudford_F1_X283Y865 and its equivalents # INFO 21:27:00.816 │ Best 3 nearby predictions: [ # ('Combat_Herta_SupplyZone_F2_X45Y369', 0.184, (41.0, 369.1)), # ('Combat_Luofu_Cloudford_F1_X281Y873', 0.149, (281.8, 869.6)), # ('Combat_Luofu_Cloudford_F1_X283Y865', 0.149, (281.8, 869.6))] - if route.name in ['Combat_Luofu_Cloudford_F1_X283Y865', 'Occurrence_Luofu_Cloudford_F1_X283Y865'] \ - and similarity > 0.05: + # INFO | Best 3 predictions: [('Combat_Herta_SupplyZone_F2_X45Y369', 0.149, (43.4, 369.3)), + # ('Combat_Luofu_Cloudford_F1_X241Y947', 0.138, (198.6, 956.8)), + # ('Combat_Luofu_Cloudford_F1Rogue_X59Y405', 0.134, (81.0, 397.4))] + if route.name in [ + 'Combat_Luofu_Cloudford_F1_X283Y865', + 'Occurrence_Luofu_Cloudford_F1_X283Y865', + 'Combat_Luofu_Cloudford_F1_X281Y873', + 'Occurrence_Luofu_Cloudford_F1_X281Y873', + ] and similarity > 0.05: return True return False