diff --git a/assets/cn/map/FLEET_SWITCH_CONFIRM.png b/assets/cn/map/FLEET_SWITCH_CONFIRM.png new file mode 100644 index 000000000..d08d60038 Binary files /dev/null and b/assets/cn/map/FLEET_SWITCH_CONFIRM.png differ diff --git a/assets/cn/map/FLEET_WITHDRAW.png b/assets/cn/map/FLEET_WITHDRAW.png new file mode 100644 index 000000000..a364d5d07 Binary files /dev/null and b/assets/cn/map/FLEET_WITHDRAW.png differ diff --git a/config/template.json b/config/template.json index 4af905b9b..f17bdd096 100644 --- a/config/template.json +++ b/config/template.json @@ -198,7 +198,8 @@ "UseAutoSearch": true, "Use2xBook": false, "AmbushEvade": true, - "UseRecommendFleet": false + "UseRecommendFleet": false, + "DefeatWithdraw": true }, "StopCondition": { "OilLimit": 1000, @@ -276,7 +277,8 @@ "UseAutoSearch": true, "Use2xBook": false, "AmbushEvade": true, - "UseRecommendFleet": false + "UseRecommendFleet": false, + "DefeatWithdraw": true }, "StopCondition": { "OilLimit": 1000, @@ -354,7 +356,8 @@ "UseAutoSearch": true, "Use2xBook": false, "AmbushEvade": true, - "UseRecommendFleet": false + "UseRecommendFleet": false, + "DefeatWithdraw": true }, "StopCondition": { "OilLimit": 1000, @@ -447,7 +450,8 @@ "UseAutoSearch": true, "Use2xBook": false, "AmbushEvade": true, - "UseRecommendFleet": false + "UseRecommendFleet": false, + "DefeatWithdraw": true }, "StopCondition": { "OilLimit": 1000, @@ -527,7 +531,8 @@ "UseAutoSearch": true, "Use2xBook": false, "AmbushEvade": true, - "UseRecommendFleet": false + "UseRecommendFleet": false, + "DefeatWithdraw": true }, "StopCondition": { "OilLimit": 1000, @@ -607,7 +612,8 @@ "UseAutoSearch": false, "Use2xBook": false, "AmbushEvade": true, - "UseRecommendFleet": false + "UseRecommendFleet": false, + "DefeatWithdraw": true }, "StopCondition": { "OilLimit": 1000, @@ -686,7 +692,8 @@ "UseAutoSearch": true, "Use2xBook": false, "AmbushEvade": true, - "UseRecommendFleet": false + "UseRecommendFleet": false, + "DefeatWithdraw": true }, "StopCondition": { "OilLimit": 1000, @@ -764,7 +771,8 @@ "UseAutoSearch": true, "Use2xBook": false, "AmbushEvade": true, - "UseRecommendFleet": false + "UseRecommendFleet": false, + "DefeatWithdraw": true }, "StopCondition": { "OilLimit": 1000, @@ -842,7 +850,8 @@ "UseAutoSearch": true, "Use2xBook": false, "AmbushEvade": true, - "UseRecommendFleet": false + "UseRecommendFleet": false, + "DefeatWithdraw": true }, "StopCondition": { "OilLimit": 1000, @@ -924,7 +933,8 @@ "UseAutoSearch": false, "Use2xBook": false, "AmbushEvade": true, - "UseRecommendFleet": false + "UseRecommendFleet": false, + "DefeatWithdraw": true }, "StopCondition": { "OilLimit": 1000, @@ -979,7 +989,8 @@ "UseAutoSearch": true, "Use2xBook": false, "AmbushEvade": true, - "UseRecommendFleet": false + "UseRecommendFleet": false, + "DefeatWithdraw": true }, "StopCondition": { "OilLimit": 1000, @@ -1084,7 +1095,8 @@ "UseAutoSearch": false, "Use2xBook": false, "AmbushEvade": true, - "UseRecommendFleet": false + "UseRecommendFleet": false, + "DefeatWithdraw": true }, "Coalition": { "Mode": "hard", @@ -1171,7 +1183,8 @@ "UseAutoSearch": true, "Use2xBook": false, "AmbushEvade": true, - "UseRecommendFleet": false + "UseRecommendFleet": false, + "DefeatWithdraw": true }, "StopCondition": { "OilLimit": 1000, @@ -1253,7 +1266,8 @@ "UseAutoSearch": true, "Use2xBook": false, "AmbushEvade": true, - "UseRecommendFleet": false + "UseRecommendFleet": false, + "DefeatWithdraw": true }, "StopCondition": { "OilLimit": 1000, @@ -1335,7 +1349,8 @@ "UseAutoSearch": true, "Use2xBook": false, "AmbushEvade": true, - "UseRecommendFleet": false + "UseRecommendFleet": false, + "DefeatWithdraw": true }, "StopCondition": { "OilLimit": 1000, @@ -1417,7 +1432,8 @@ "UseAutoSearch": true, "Use2xBook": false, "AmbushEvade": true, - "UseRecommendFleet": false + "UseRecommendFleet": false, + "DefeatWithdraw": true }, "StopCondition": { "OilLimit": 1000, @@ -1499,7 +1515,8 @@ "UseAutoSearch": true, "Use2xBook": false, "AmbushEvade": true, - "UseRecommendFleet": false + "UseRecommendFleet": false, + "DefeatWithdraw": true }, "StopCondition": { "OilLimit": 1000, @@ -1577,7 +1594,8 @@ "UseAutoSearch": true, "Use2xBook": false, "AmbushEvade": true, - "UseRecommendFleet": false + "UseRecommendFleet": false, + "DefeatWithdraw": true }, "StopCondition": { "OilLimit": 1000, @@ -1658,7 +1676,8 @@ "UseAutoSearch": false, "Use2xBook": false, "AmbushEvade": true, - "UseRecommendFleet": false + "UseRecommendFleet": false, + "DefeatWithdraw": true }, "StopCondition": { "OilLimit": 1000, @@ -1706,7 +1725,8 @@ "UseAutoSearch": false, "Use2xBook": false, "AmbushEvade": true, - "UseRecommendFleet": false + "UseRecommendFleet": false, + "DefeatWithdraw": true }, "Coalition": { "Mode": "hard", diff --git a/module/campaign/campaign_base.py b/module/campaign/campaign_base.py index cd8a403a4..21a98f15b 100644 --- a/module/campaign/campaign_base.py +++ b/module/campaign/campaign_base.py @@ -133,6 +133,7 @@ class CampaignBase(CampaignUI, Map, AutoSearchCombat): else: self.map = self.MAP self.battle_count = 0 + self.fleet_alive_multiple = self.config.Fleet_Fleet2 != 0 self.lv_reset() self.lv_get() diff --git a/module/combat/auto_search_combat.py b/module/combat/auto_search_combat.py index 07afa9656..c5978194e 100644 --- a/module/combat/auto_search_combat.py +++ b/module/combat/auto_search_combat.py @@ -5,7 +5,7 @@ from module.combat.combat import Combat from module.exception import CampaignEnd from module.handler.assets import AUTO_SEARCH_MAP_OPTION_ON, GET_MISSION from module.logger import logger -from module.map.assets import WITHDRAW +from module.map.assets import WITHDRAW, SWITCH_OVER, FLEET_WITHDRAW, FLEET_SWITCH_CONFIRM from module.map.map_operation import MapOperation @@ -285,15 +285,23 @@ class AutoSearchCombat(MapOperation, Combat, CampaignStatus): if self.handle_get_ship(): continue if self.appear_then_click(OPTS_INFO_D, offset=(30, 30), interval=2): + if emotion_reduce: + self.emotion.reduce(fleet_index, shipwreck=True) self._withdraw = True - continue + break if confirm_timer.reached(): self._withdraw = True self.device.click(OPTS_INFO_D) + if emotion_reduce: + self.emotion.reduce(fleet_index, shipwreck=True) confirm_timer.reset() - continue - if self.appear(BATTLE_STATUS_S) or self.appear(BATTLE_STATUS_A) or self.appear(BATTLE_STATUS_B) \ - or self.appear(EXP_INFO_S) or self.appear(EXP_INFO_A) or self.appear(EXP_INFO_B) \ + break + if self.appear(BATTLE_STATUS_A) or self.appear(BATTLE_STATUS_B) \ + or self.appear(EXP_INFO_A) or self.appear(EXP_INFO_B): + if emotion_reduce: + self.emotion.reduce(fleet_index, shipwreck=True) + break + if self.appear(BATTLE_STATUS_S) or self.appear(EXP_INFO_S) \ or self.appear(GET_MISSION) or self.is_auto_search_running(): self.device.screenshot_interval_set() break @@ -325,10 +333,29 @@ class AutoSearchCombat(MapOperation, Combat, CampaignStatus): raise CampaignEnd # Withdraw - if self._withdraw and get_urgent_commission and self.appear(WITHDRAW, offset=(30, 30)): + if self._withdraw: + if self.appear_then_click(FLEET_SWITCH_CONFIRM, offset=(30, 30)): + continue + if not self.appear(WITHDRAW, offset=(30, 30)): + continue + + logger.info(f'fleet_alive_multiple: {self.fleet_alive_multiple}') self._withdraw = False - self.withdraw() - break + if self.config.Campaign_DefeatWithdraw or not self.fleet_alive_multiple: + self.withdraw() + break + elif get_urgent_commission: + self.fleet_alive_multiple = False + continue + else: + while True: + self.device.screenshot() + if self.appear_then_click(FLEET_WITHDRAW, offset=(30, 30)): + break + if self.appear_then_click(SWITCH_OVER, interval=2): + continue + self.fleet_alive_multiple = False + continue # Combat status if self.handle_get_ship(): diff --git a/module/combat/emotion.py b/module/combat/emotion.py index d8ae5672e..d9de3dcb2 100644 --- a/module/combat/emotion.py +++ b/module/combat/emotion.py @@ -248,6 +248,10 @@ class Emotion: return 4 else: return 2 + + @property + def reduce_shipwreck(self): + return 10 def _check_reduce(self, battle): """ @@ -339,7 +343,7 @@ class Emotion: logger.attr('Wait until', recovered) sleep(60) - def reduce(self, fleet_index): + def reduce(self, fleet_index, shipwreck=False): """ Reduce emotion of specific fleet. Should be called after battle executing. @@ -347,6 +351,7 @@ class Emotion: Args: fleet_index (int): 1 or 2. + shipwreck (bool): Whether the fleet is at shipwreck. """ logger.hr('Emotion reduce') self.update() @@ -356,8 +361,12 @@ class Emotion: else: fleet = self.fleets[fleet_index - 1] - fleet.current -= self.reduce_per_battle - self.total_reduced += self.reduce_per_battle + if not shipwreck: + fleet.current -= self.reduce_per_battle + self.total_reduced += self.reduce_per_battle + else: + fleet.current -= self.reduce_shipwreck + self.total_reduced += self.reduce_shipwreck self.record() self.show() diff --git a/module/config/argument/args.json b/module/config/argument/args.json index 7238d22f8..60fc814b9 100644 --- a/module/config/argument/args.json +++ b/module/config/argument/args.json @@ -878,6 +878,10 @@ "UseRecommendFleet": { "type": "checkbox", "value": false + }, + "DefeatWithdraw": { + "type": "checkbox", + "value": true } }, "StopCondition": { @@ -1274,6 +1278,10 @@ "UseRecommendFleet": { "type": "checkbox", "value": false + }, + "DefeatWithdraw": { + "type": "checkbox", + "value": true } }, "StopCondition": { @@ -1670,6 +1678,10 @@ "UseRecommendFleet": { "type": "checkbox", "value": false + }, + "DefeatWithdraw": { + "type": "checkbox", + "value": true } }, "StopCondition": { @@ -2198,6 +2210,10 @@ "UseRecommendFleet": { "type": "checkbox", "value": false + }, + "DefeatWithdraw": { + "type": "checkbox", + "value": true } }, "StopCondition": { @@ -2693,6 +2709,10 @@ "UseRecommendFleet": { "type": "checkbox", "value": false + }, + "DefeatWithdraw": { + "type": "checkbox", + "value": true } }, "StopCondition": { @@ -3153,6 +3173,10 @@ "UseRecommendFleet": { "type": "checkbox", "value": false + }, + "DefeatWithdraw": { + "type": "checkbox", + "value": true } }, "StopCondition": { @@ -3589,6 +3613,10 @@ "UseRecommendFleet": { "type": "checkbox", "value": false + }, + "DefeatWithdraw": { + "type": "checkbox", + "value": true } }, "StopCondition": { @@ -4024,6 +4052,10 @@ "UseRecommendFleet": { "type": "checkbox", "value": false + }, + "DefeatWithdraw": { + "type": "checkbox", + "value": true } }, "StopCondition": { @@ -4458,6 +4490,10 @@ "UseRecommendFleet": { "type": "checkbox", "value": false + }, + "DefeatWithdraw": { + "type": "checkbox", + "value": true } }, "StopCondition": { @@ -4896,6 +4932,10 @@ "UseRecommendFleet": { "type": "checkbox", "value": false + }, + "DefeatWithdraw": { + "type": "checkbox", + "value": true } }, "StopCondition": { @@ -5167,6 +5207,10 @@ "UseRecommendFleet": { "type": "checkbox", "value": false + }, + "DefeatWithdraw": { + "type": "checkbox", + "value": true } }, "StopCondition": { @@ -5727,6 +5771,10 @@ "UseRecommendFleet": { "type": "checkbox", "value": false + }, + "DefeatWithdraw": { + "type": "checkbox", + "value": true } }, "Coalition": { @@ -6378,6 +6426,10 @@ "UseRecommendFleet": { "type": "checkbox", "value": false + }, + "DefeatWithdraw": { + "type": "checkbox", + "value": true } }, "StopCondition": { @@ -6825,6 +6877,10 @@ "UseRecommendFleet": { "type": "checkbox", "value": false + }, + "DefeatWithdraw": { + "type": "checkbox", + "value": true } }, "StopCondition": { @@ -7277,6 +7333,10 @@ "UseRecommendFleet": { "type": "checkbox", "value": false + }, + "DefeatWithdraw": { + "type": "checkbox", + "value": true } }, "StopCondition": { @@ -7729,6 +7789,10 @@ "UseRecommendFleet": { "type": "checkbox", "value": false + }, + "DefeatWithdraw": { + "type": "checkbox", + "value": true } }, "StopCondition": { @@ -8181,6 +8245,10 @@ "UseRecommendFleet": { "type": "checkbox", "value": false + }, + "DefeatWithdraw": { + "type": "checkbox", + "value": true } }, "StopCondition": { @@ -8623,6 +8691,10 @@ "UseRecommendFleet": { "type": "checkbox", "value": false + }, + "DefeatWithdraw": { + "type": "checkbox", + "value": true } }, "StopCondition": { @@ -9057,6 +9129,10 @@ "UseRecommendFleet": { "type": "checkbox", "value": false + }, + "DefeatWithdraw": { + "type": "checkbox", + "value": true } }, "StopCondition": { @@ -9302,6 +9378,10 @@ "UseRecommendFleet": { "type": "checkbox", "value": false + }, + "DefeatWithdraw": { + "type": "checkbox", + "value": true } }, "Coalition": { diff --git a/module/config/argument/argument.yaml b/module/config/argument/argument.yaml index 119b2d9c1..409de01f5 100644 --- a/module/config/argument/argument.yaml +++ b/module/config/argument/argument.yaml @@ -292,6 +292,7 @@ Campaign: Use2xBook: false AmbushEvade: true UseRecommendFleet: false + DefeatWithdraw: true StopCondition: OilLimit: 1000 CoinLimit: 0 diff --git a/module/config/config_generated.py b/module/config/config_generated.py index 18f74075d..5e54fb15e 100644 --- a/module/config/config_generated.py +++ b/module/config/config_generated.py @@ -178,6 +178,7 @@ class GeneratedConfig: Campaign_Use2xBook = False Campaign_AmbushEvade = True Campaign_UseRecommendFleet = False + Campaign_DefeatWithdraw = True # Group `StopCondition` StopCondition_OilLimit = 1000 diff --git a/module/config/i18n/en-US.json b/module/config/i18n/en-US.json index 0643aa387..4e297d13f 100644 --- a/module/config/i18n/en-US.json +++ b/module/config/i18n/en-US.json @@ -1046,6 +1046,10 @@ "UseRecommendFleet": { "name": "Auto Fleet Composition", "help": "Use the game's built-in recommended fleet to automatically compose hard mode fleets" + }, + "DefeatWithdraw": { + "name": "Retreat after defeat in Mob", + "help": "The handling method for defeat in Mob during the journey. Upon initiation, exit the sea area directly; upon termination, attempt to have another team take over the subsequent battle." } }, "StopCondition": { diff --git a/module/config/i18n/ja-JP.json b/module/config/i18n/ja-JP.json index 5a5f1bdec..c21b9bfca 100644 --- a/module/config/i18n/ja-JP.json +++ b/module/config/i18n/ja-JP.json @@ -1046,6 +1046,10 @@ "UseRecommendFleet": { "name": "自動編成", "help": "ゲーム内蔵の推奨編成を使用してハードステージの編成を自動的に完了します" + }, + "DefeatWithdraw": { + "name": "道中での戦闘で敗北し撤退", + "help": "道中戦闘で敗北した際の処理方法。オンの場合は海域から直接退出し、オフの場合は別のチームが引き継いで後続の戦闘を試みる。" } }, "StopCondition": { diff --git a/module/config/i18n/zh-CN.json b/module/config/i18n/zh-CN.json index b5fc2a632..693333d3e 100644 --- a/module/config/i18n/zh-CN.json +++ b/module/config/i18n/zh-CN.json @@ -1046,6 +1046,10 @@ "UseRecommendFleet": { "name": "自动配队", "help": "使用游戏内置的推荐阵容自动完成困难图配队" + }, + "DefeatWithdraw": { + "name": "道中战斗失败撤退", + "help": "道中战斗战败时的处理方式。开启时直接退出海域,关闭时尝试由另一队接管后续战斗。" } }, "StopCondition": { diff --git a/module/config/i18n/zh-MIAO.json b/module/config/i18n/zh-MIAO.json index 6024a69fe..cdadff9ab 100644 --- a/module/config/i18n/zh-MIAO.json +++ b/module/config/i18n/zh-MIAO.json @@ -1046,6 +1046,10 @@ "UseRecommendFleet": { "name": "自动配队困难图 (`・ω・´)ゞ", "help": "使用游戏推荐阵容自动完成困难配队喵~" + }, + "DefeatWithdraw": { + "name": "道中战斗失败撤退 (`・ω・´)", + "help": "道中战斗战败时的处理方式喵。开启时直接退出海域,关闭时尝试由另一队接管后续战斗喵。" } }, "StopCondition": { diff --git a/module/config/i18n/zh-TW.json b/module/config/i18n/zh-TW.json index dcb979b2e..a0a77d787 100644 --- a/module/config/i18n/zh-TW.json +++ b/module/config/i18n/zh-TW.json @@ -1046,6 +1046,10 @@ "UseRecommendFleet": { "name": "自動配隊", "help": "使用遊戲內建的推薦陣容自動完成困難圖配隊" + }, + "DefeatWithdraw": { + "name": "道中戰鬥失敗撤退", + "help": "道中戰鬥戰敗時的處理方式。開啟時直接退出海域,關閉時嘗試由另一隊接管後續戰鬥。" } }, "StopCondition": { diff --git a/module/map/assets.py b/module/map/assets.py index 71c717bee..f68a27dfc 100644 --- a/module/map/assets.py +++ b/module/map/assets.py @@ -22,6 +22,8 @@ FLEET_NUM_2 = Button(area={'cn': (212, 75, 226, 101), 'en': (212, 75, 226, 101), FLEET_PREPARATION = Button(area={'cn': (1013, 558, 1141, 588), 'en': (1048, 569, 1086, 595), 'jp': (1046, 558, 1107, 587), 'tw': (1014, 557, 1142, 588)}, color={'cn': (242, 211, 160), 'en': (241, 201, 148), 'jp': (241, 205, 151), 'tw': (242, 208, 157)}, button={'cn': (980, 549, 1181, 612), 'en': (988, 556, 1145, 606), 'jp': (983, 549, 1185, 612), 'tw': (980, 548, 1180, 612)}, file={'cn': './assets/cn/map/FLEET_PREPARATION.png', 'en': './assets/en/map/FLEET_PREPARATION.png', 'jp': './assets/jp/map/FLEET_PREPARATION.png', 'tw': './assets/tw/map/FLEET_PREPARATION.png'}) FLEET_PREPARATION_CHECK = Button(area={'cn': (1146, 107, 1174, 136), 'en': (1129, 111, 1158, 140), 'jp': (1146, 107, 1174, 136), 'tw': (1145, 106, 1175, 136)}, color={'cn': (180, 98, 111), 'en': (189, 105, 109), 'jp': (180, 98, 111), 'tw': (180, 90, 92)}, button={'cn': (1146, 107, 1174, 136), 'en': (1129, 111, 1158, 140), 'jp': (1146, 107, 1174, 136), 'tw': (1145, 106, 1175, 136)}, file={'cn': './assets/cn/map/FLEET_PREPARATION_CHECK.png', 'en': './assets/en/map/FLEET_PREPARATION_CHECK.png', 'jp': './assets/jp/map/FLEET_PREPARATION_CHECK.png', 'tw': './assets/tw/map/FLEET_PREPARATION_CHECK.png'}) FLEET_SUPPORT_EMPTY = Button(area={'cn': (454, 470, 538, 540), 'en': (454, 470, 538, 540), 'jp': (454, 470, 538, 540), 'tw': (454, 470, 538, 540)}, color={'cn': (47, 54, 77), 'en': (47, 54, 77), 'jp': (47, 54, 77), 'tw': (47, 54, 77)}, button={'cn': (454, 470, 538, 540), 'en': (454, 470, 538, 540), 'jp': (454, 470, 538, 540), 'tw': (454, 470, 538, 540)}, file={'cn': './assets/cn/map/FLEET_SUPPORT_EMPTY.png', 'en': './assets/cn/map/FLEET_SUPPORT_EMPTY.png', 'jp': './assets/cn/map/FLEET_SUPPORT_EMPTY.png', 'tw': './assets/cn/map/FLEET_SUPPORT_EMPTY.png'}) +FLEET_SWITCH_CONFIRM = Button(area={'cn': (553, 481, 728, 541), 'en': (553, 481, 728, 541), 'jp': (553, 481, 728, 541), 'tw': (553, 481, 728, 541)}, color={'cn': (98, 144, 201), 'en': (98, 144, 201), 'jp': (98, 144, 201), 'tw': (98, 144, 201)}, button={'cn': (553, 481, 728, 541), 'en': (553, 481, 728, 541), 'jp': (553, 481, 728, 541), 'tw': (553, 481, 728, 541)}, file={'cn': './assets/cn/map/FLEET_SWITCH_CONFIRM.png', 'en': './assets/cn/map/FLEET_SWITCH_CONFIRM.png', 'jp': './assets/cn/map/FLEET_SWITCH_CONFIRM.png', 'tw': './assets/cn/map/FLEET_SWITCH_CONFIRM.png'}) +FLEET_WITHDRAW = Button(area={'cn': (714, 356, 773, 380), 'en': (714, 356, 773, 380), 'jp': (714, 356, 773, 380), 'tw': (714, 356, 773, 380)}, color={'cn': (175, 188, 201), 'en': (175, 188, 201), 'jp': (175, 188, 201), 'tw': (175, 188, 201)}, button={'cn': (714, 356, 773, 380), 'en': (714, 356, 773, 380), 'jp': (714, 356, 773, 380), 'tw': (714, 356, 773, 380)}, file={'cn': './assets/cn/map/FLEET_WITHDRAW.png', 'en': './assets/cn/map/FLEET_WITHDRAW.png', 'jp': './assets/cn/map/FLEET_WITHDRAW.png', 'tw': './assets/cn/map/FLEET_WITHDRAW.png'}) MAP_CAT_ATTACK = Button(area={'cn': (1237, 103, 1252, 153), 'en': (1237, 103, 1252, 153), 'jp': (1237, 103, 1252, 153), 'tw': (1237, 103, 1252, 153)}, color={'cn': (43, 45, 52), 'en': (43, 45, 52), 'jp': (43, 45, 52), 'tw': (43, 45, 52)}, button={'cn': (1148, 653, 1262, 705), 'en': (1147, 651, 1263, 701), 'jp': (1149, 653, 1261, 704), 'tw': (1148, 653, 1262, 705)}, file={'cn': './assets/cn/map/MAP_CAT_ATTACK.png', 'en': './assets/en/map/MAP_CAT_ATTACK.png', 'jp': './assets/jp/map/MAP_CAT_ATTACK.png', 'tw': './assets/tw/map/MAP_CAT_ATTACK.png'}) MAP_CAT_ATTACK_MIRROR = Button(area={'cn': (147, 145, 187, 157), 'en': (147, 145, 187, 157), 'jp': (147, 145, 187, 157), 'tw': (147, 145, 187, 157)}, color={'cn': (214, 191, 99), 'en': (214, 191, 99), 'jp': (214, 191, 99), 'tw': (214, 191, 99)}, button={'cn': (147, 145, 187, 157), 'en': (147, 145, 187, 157), 'jp': (147, 145, 187, 157), 'tw': (147, 145, 187, 157)}, file={'cn': './assets/cn/map/MAP_CAT_ATTACK_MIRROR.png', 'en': './assets/en/map/MAP_CAT_ATTACK_MIRROR.png', 'jp': './assets/jp/map/MAP_CAT_ATTACK_MIRROR.png', 'tw': './assets/tw/map/MAP_CAT_ATTACK_MIRROR.png'}) MAP_MODE_SWITCH_HARD = Button(area={'cn': (341, 580, 374, 617), 'en': (341, 580, 374, 617), 'jp': (341, 580, 374, 617), 'tw': (341, 580, 374, 617)}, color={'cn': (234, 179, 179), 'en': (234, 179, 179), 'jp': (234, 179, 179), 'tw': (234, 179, 179)}, button={'cn': (341, 580, 374, 617), 'en': (341, 580, 374, 617), 'jp': (341, 580, 374, 617), 'tw': (341, 580, 374, 617)}, file={'cn': './assets/cn/map/MAP_MODE_SWITCH_HARD.png', 'en': './assets/cn/map/MAP_MODE_SWITCH_HARD.png', 'jp': './assets/cn/map/MAP_MODE_SWITCH_HARD.png', 'tw': './assets/cn/map/MAP_MODE_SWITCH_HARD.png'}) diff --git a/module/map/map_operation.py b/module/map/map_operation.py index 34d9e7427..a55569be6 100644 --- a/module/map/map_operation.py +++ b/module/map/map_operation.py @@ -378,6 +378,8 @@ class MapOperation(MysteryHandler, FleetPreparation, Retirement, FastForwardHand else: self.device.screenshot() + if self.appear_then_click(FLEET_SWITCH_CONFIRM, offset=(30, 30)): + continue if self.handle_popup_confirm('WITHDRAW'): continue if self.appear_then_click(WITHDRAW, interval=5): diff --git a/module/webui/app.py b/module/webui/app.py index 8e0e3eedb..e5ec0d17f 100644 --- a/module/webui/app.py +++ b/module/webui/app.py @@ -623,7 +623,7 @@ class AlasGUI(Frame): coins_legend_html += '紫币' chart_id = f"ap_cv_{id(self)}" - detail_controls_display = 'display:flex;' if is_detail_mode else 'display:none;' + detail_controls_display = 'display:flex;' if current_view in ('line', 'detail') else 'display:none;' html_tpl = read_webapp_template('ap_chart_panel.html') html = html_tpl.format( diff --git a/webapp/ap_chart.js b/webapp/ap_chart.js index 48d993a5d..86704a85c 100644 --- a/webapp/ap_chart.js +++ b/webapp/ap_chart.js @@ -340,123 +340,75 @@ oc.scale(dpr, dpr); if (chartType === 'line') { + var visibleStart = Math.max(0, Math.floor(panOffset)); + var visibleCount = Math.ceil(nn / zoomLevel); + var visibleEnd = Math.min(nn, visibleStart + visibleCount); + var visibleNn = visibleEnd - visibleStart; + + var dMin = Infinity, dMax = -Infinity; + for (var i = visibleStart; i < visibleEnd; i++) { + if (ap[i] < dMin) dMin = ap[i]; + if (ap[i] > dMax) dMax = ap[i]; + } + if (dMin === Infinity) dMin = 0; + if (dMax === -Infinity) dMax = 100; + var drng = dMax - dMin || 1; + dMin -= drng * 0.1; + dMax += drng * 0.1; + + var xScale = gW / Math.max(visibleNn - 1, 1); + var idx = Math.round(visibleStart + (mx_ - pad.l) / xScale); + idx = Math.max(0, Math.min(nn - 1, idx)); + var px = pad.l + (idx - visibleStart) * xScale; + var py = pad.t + gH - (ap[idx] - dMin) / (dMax - dMin) * gH; + + oc.strokeStyle = "rgba(255,255,255,0.18)"; + oc.lineWidth = 1; + oc.setLineDash([4, 3]); + oc.beginPath(); oc.moveTo(px, pad.t); oc.lineTo(px, pad.t + gH); oc.stroke(); + oc.beginPath(); oc.moveTo(pad.l, py); oc.lineTo(W - pad.r, py); oc.stroke(); + oc.setLineDash([]); + + oc.beginPath(); oc.arc(px, py, 6, 0, Math.PI * 2); + oc.fillStyle = "rgba(100,181,246,0.3)"; oc.fill(); + oc.beginPath(); oc.arc(px, py, 4, 0, Math.PI * 2); + oc.fillStyle = "#64b5f6"; oc.fill(); + oc.strokeStyle = "#fff"; oc.lineWidth = 2; oc.stroke(); + oc.setTransform(1, 0, 0, 1, 0, 0); + + var diff = idx > 0 ? (ap[idx] - ap[idx - 1]) : 0; + var isUp = diff >= 0; + var dc = isUp ? "#ef5350" : "#26a69a"; + var ds = (isUp ? "+" : "") + diff; + var tooltipRows = [ + { style: { color: "#888", marginBottom: "4px", fontWeight: "600" }, parts: [{ type: 'text', value: labels[idx] }] }, + { parts: [{ type: 'text', value: "体力: " }, { type: 'bold', value: String(ap[idx]), style: { color: "#64b5f6" } }] }, + { parts: [{ type: 'text', value: "单次变化: " }, { type: 'bold', value: ds, style: { color: dc } }] } + ]; + if (isDetailMode) { - var visibleStart = Math.max(0, Math.floor(panOffset)); - var visibleCount = Math.ceil(nn / zoomLevel); - var visibleEnd = Math.min(nn, visibleStart + visibleCount); - var visibleNn = visibleEnd - visibleStart; - - var dMin = Infinity, dMax = -Infinity; - for (var i = visibleStart; i < visibleEnd; i++) { - if (ap[i] < dMin) dMin = ap[i]; - if (ap[i] > dMax) dMax = ap[i]; - } - if (dMin === Infinity) dMin = 0; - if (dMax === -Infinity) dMax = 100; - var drng = dMax - dMin || 1; - dMin -= drng * 0.1; - dMax += drng * 0.1; - - var xScale = gW / visibleNn; - var idx = Math.floor(panOffset + (mx_ - pad.l) / xScale); - idx = Math.max(0, Math.min(nn - 1, idx)); - var px = pad.l + (idx - visibleStart) * xScale; - var py = pad.t + gH - (ap[idx] - dMin) / (dMax - dMin) * gH; - - oc.strokeStyle = "rgba(255,255,255,0.18)"; - oc.lineWidth = 1; - oc.setLineDash([4, 3]); - oc.beginPath(); oc.moveTo(px, pad.t); oc.lineTo(px, pad.t + gH); oc.stroke(); - oc.beginPath(); oc.moveTo(pad.l, py); oc.lineTo(W - pad.r, py); oc.stroke(); - oc.setLineDash([]); - - oc.beginPath(); oc.arc(px, py, 6, 0, Math.PI * 2); - oc.fillStyle = "rgba(100,181,246,0.3)"; oc.fill(); - oc.beginPath(); oc.arc(px, py, 4, 0, Math.PI * 2); - oc.fillStyle = "#64b5f6"; oc.fill(); - oc.strokeStyle = "#fff"; oc.lineWidth = 2; oc.stroke(); - oc.setTransform(1, 0, 0, 1, 0, 0); - - var diff = idx > 0 ? (ap[idx] - ap[idx - 1]) : 0; - var isUp = diff >= 0; - var dc = isUp ? "#ef5350" : "#26a69a"; - var ds = (isUp ? "+" : "") + diff; var source = sources && sources[idx] ? sources[idx] : '-'; var sourceColor = source === 'cl1' ? '#64b5f6' : (source === 'meow' ? '#ff9800' : '#888'); - - var tooltipRows = [ - { style: { color: "#888", marginBottom: "4px", fontWeight: "600" }, parts: [{ type: 'text', value: labels[idx] }] }, - { parts: [{ type: 'text', value: "体力: " }, { type: 'bold', value: String(ap[idx]), style: { color: "#64b5f6" } }] }, - { parts: [{ type: 'text', value: "单次变化: " }, { type: 'bold', value: ds, style: { color: dc } }] }, - { parts: [{ type: 'text', value: "来源: " }, { type: 'bold', value: source, style: { color: sourceColor } }] } - ]; - - if (showCoins && yellowCoinsLen > 0 && idx < yellowCoinsLen && yellowCoins[idx] !== null && yellowCoins[idx] !== undefined) { - var yc = yellowCoins[idx]; - var ycDiff = idx > 0 && yellowCoins[idx - 1] !== null && yellowCoins[idx - 1] !== undefined ? (yc - yellowCoins[idx - 1]) : 0; - var ycColor = ycDiff >= 0 ? "#ef5350" : "#26a69a"; - var ycDiffStr = (ycDiff >= 0 ? "+" : "") + ycDiff; - tooltipRows.push({ parts: [{ type: 'text', value: "黄币: " }, { type: 'bold', value: String(yc), style: { color: "#ffd54f" } }, { type: 'text', value: " (" + ycDiffStr + ")", style: { color: ycColor } }] }); - } - - if (showCoins && purpleCoinsLen > 0 && idx < purpleCoinsLen && purpleCoins[idx] !== null && purpleCoins[idx] !== undefined) { - var pc = purpleCoins[idx]; - var pcDiff = idx > 0 && purpleCoins[idx - 1] !== null && purpleCoins[idx - 1] !== undefined ? (pc - purpleCoins[idx - 1]) : 0; - var pcColor = pcDiff >= 0 ? "#ef5350" : "#26a69a"; - var pcDiffStr = (pcDiff >= 0 ? "+" : "") + pcDiff; - tooltipRows.push({ parts: [{ type: 'text', value: "紫币: " }, { type: 'bold', value: String(pc), style: { color: "#ce93d8" } }, { type: 'text', value: " (" + pcDiffStr + ")", style: { color: pcColor } }] }); - } - - setTooltipContent(tipEl, tooltipRows); - } else { - var ratio = (mx_ - pad.l) / gW; - var idx = Math.round(ratio * (nn - 1)); - idx = Math.max(0, Math.min(nn - 1, idx)); - var px = xOfLine(idx), py = yOf(ap[idx]); - - oc.strokeStyle = "rgba(255,255,255,0.18)"; - oc.lineWidth = 1; - oc.setLineDash([4, 3]); - oc.beginPath(); oc.moveTo(px, pad.t); oc.lineTo(px, pad.t + gH); oc.stroke(); - oc.beginPath(); oc.moveTo(pad.l, py); oc.lineTo(W - pad.r, py); oc.stroke(); - oc.setLineDash([]); - - oc.beginPath(); oc.arc(px, py, 6, 0, Math.PI * 2); - oc.fillStyle = "rgba(100,181,246,0.3)"; oc.fill(); - oc.beginPath(); oc.arc(px, py, 4, 0, Math.PI * 2); - oc.fillStyle = "#64b5f6"; oc.fill(); - oc.strokeStyle = "#fff"; oc.lineWidth = 2; oc.stroke(); - oc.setTransform(1, 0, 0, 1, 0, 0); - - var diff = idx > 0 ? (ap[idx] - ap[idx - 1]) : 0; - var isUp = diff >= 0; - var dc = isUp ? "#ef5350" : "#26a69a"; - var ds = (isUp ? "+" : "") + diff; - - var tooltipRows = [ - { style: { color: "#888", marginBottom: "4px", fontWeight: "600" }, parts: [{ type: 'text', value: labels[idx] }] }, - { parts: [{ type: 'text', value: "体力: " }, { type: 'bold', value: String(ap[idx]), style: { color: "#64b5f6" } }] }, - { parts: [{ type: 'text', value: "单次变化: " }, { type: 'bold', value: ds, style: { color: dc } }] } - ]; - - if (showCoins && yellowCoinsLen > 0 && idx < yellowCoinsLen && yellowCoins[idx] !== null && yellowCoins[idx] !== undefined) { - var yc = yellowCoins[idx]; - var ycDiff = idx > 0 && yellowCoins[idx - 1] !== null && yellowCoins[idx - 1] !== undefined ? (yc - yellowCoins[idx - 1]) : 0; - var ycColor = ycDiff >= 0 ? "#ef5350" : "#26a69a"; - var ycDiffStr = (ycDiff >= 0 ? "+" : "") + ycDiff; - tooltipRows.push({ parts: [{ type: 'text', value: "黄币: " }, { type: 'bold', value: String(yc), style: { color: "#ffd54f" } }, { type: 'text', value: " (" + ycDiffStr + ")", style: { color: ycColor } }] }); - } - - if (showCoins && purpleCoinsLen > 0 && idx < purpleCoinsLen && purpleCoins[idx] !== null && purpleCoins[idx] !== undefined) { - var pc = purpleCoins[idx]; - var pcDiff = idx > 0 && purpleCoins[idx - 1] !== null && purpleCoins[idx - 1] !== undefined ? (pc - purpleCoins[idx - 1]) : 0; - var pcColor = pcDiff >= 0 ? "#ef5350" : "#26a69a"; - var pcDiffStr = (pcDiff >= 0 ? "+" : "") + pcDiff; - tooltipRows.push({ parts: [{ type: 'text', value: "紫币: " }, { type: 'bold', value: String(pc), style: { color: "#ce93d8" } }, { type: 'text', value: " (" + pcDiffStr + ")", style: { color: pcColor } }] }); - } - - setTooltipContent(tipEl, tooltipRows); + tooltipRows.push({ parts: [{ type: 'text', value: "来源: " }, { type: 'bold', value: source, style: { color: sourceColor } }] }); } + + if (showCoins && yellowCoinsLen > 0 && idx < yellowCoinsLen && yellowCoins[idx] !== null && yellowCoins[idx] !== undefined) { + var yc = yellowCoins[idx]; + var ycDiff = idx > 0 && yellowCoins[idx - 1] !== null && yellowCoins[idx - 1] !== undefined ? (yc - yellowCoins[idx - 1]) : 0; + var ycColor = ycDiff >= 0 ? "#ef5350" : "#26a69a"; + var ycDiffStr = (ycDiff >= 0 ? "+" : "") + ycDiff; + tooltipRows.push({ parts: [{ type: 'text', value: "黄币: " }, { type: 'bold', value: String(yc), style: { color: "#ffd54f" } }, { type: 'text', value: " (" + ycDiffStr + ")", style: { color: ycColor } }] }); + } + + if (showCoins && purpleCoinsLen > 0 && idx < purpleCoinsLen && purpleCoins[idx] !== null && purpleCoins[idx] !== undefined) { + var pc = purpleCoins[idx]; + var pcDiff = idx > 0 && purpleCoins[idx - 1] !== null && purpleCoins[idx - 1] !== undefined ? (pc - purpleCoins[idx - 1]) : 0; + var pcColor = pcDiff >= 0 ? "#ef5350" : "#26a69a"; + var pcDiffStr = (pcDiff >= 0 ? "+" : "") + pcDiff; + tooltipRows.push({ parts: [{ type: 'text', value: "紫币: " }, { type: 'bold', value: String(pc), style: { color: "#ce93d8" } }, { type: 'text', value: " (" + pcDiffStr + ")", style: { color: pcColor } }] }); + } + + setTooltipContent(tipEl, tooltipRows); } else { var idx = Math.floor((mx_ - pad.l) / candleSpace); idx = Math.max(0, Math.min(nn - 1, idx)); @@ -529,7 +481,7 @@ oc.clearRect(0, 0, ovCv.width, ovCv.height); }); - if (isDetailMode) { + if (chartType === 'line') { var zoomLevel = 1.0; var panOffset = 0; var maxZoom = 5.0; @@ -583,7 +535,7 @@ ctx.textAlign = "center"; ctx.textBaseline = "top"; - var xScale = gW / visibleNn; + var xScale = gW / Math.max(visibleNn - 1, 1); function dxOf(i) { return pad.l + (i - visibleStart) * xScale; } function dyOf(v) { return pad.t + gH - (v - dMin) / (dMax - dMin) * gH; } @@ -650,7 +602,7 @@ if (!isDragging) return; var dx = e.clientX - dragStartX; var visibleCount = Math.ceil(nn / zoomLevel); - var xScale = gW / visibleCount; + var xScale = gW / Math.max(visibleCount - 1, 1); var newPan = dragStartPan - dx / xScale; var maxPan = Math.max(0, nn - visibleCount); panOffset = Math.max(0, Math.min(maxPan, newPan)); @@ -673,10 +625,10 @@ if (newZoom !== zoomLevel) { var visibleCountBefore = Math.ceil(nn / zoomLevel); var visibleCountAfter = Math.ceil(nn / newZoom); - var xScaleBefore = gW / visibleCountBefore; + var xScaleBefore = gW / Math.max(visibleCountBefore - 1, 1); var mouseIdx = panOffset + (mx - pad.l) / xScaleBefore; zoomLevel = newZoom; - var xScaleAfter = gW / visibleCountAfter; + var xScaleAfter = gW / Math.max(visibleCountAfter - 1, 1); panOffset = Math.max(0, mouseIdx - (mx - pad.l) / xScaleAfter); var maxPan = Math.max(0, nn - visibleCountAfter); panOffset = Math.max(0, Math.min(maxPan, panOffset));