diff --git a/alas.py b/alas.py index 8ef498d45..04eca6090 100644 --- a/alas.py +++ b/alas.py @@ -180,6 +180,10 @@ class AzurLaneAutoScript: from module.event.campaign_ab import CampaignAB CampaignAB(config=self.config, device=self.device).run() + def event_cd(self): + from module.event.campaign_ab import CampaignAB + CampaignAB(config=self.config, device=self.device).run() + def event_sp(self): from module.event.campaign_sp import CampaignSP CampaignSP(config=self.config, device=self.device).run() diff --git a/config/template.json b/config/template.json index cb81e8aa0..62665ecc5 100644 --- a/config/template.json +++ b/config/template.json @@ -963,6 +963,78 @@ "LowHpRetreatThreshold": 0.3 } }, + "EventCd": { + "Scheduler": { + "Enable": false, + "NextRun": "2020-01-01 00:00:00", + "Command": "EventCd", + "SuccessInterval": 30, + "FailureInterval": 30, + "ServerUpdate": "00:00" + }, + "EventCd": { + "StageFilter": "C1 > C2 > C3 > D1 > D2 > D3", + "LastStage": 0 + }, + "Campaign": { + "Name": "dynamic", + "Event": "campaign_main", + "Mode": "normal", + "UseClearMode": true, + "UseFleetLock": true, + "UseAutoSearch": false, + "Use2xBook": false, + "AmbushEvade": true + }, + "StopCondition": { + "RunCount": 0, + "OilLimit": 1000, + "MapAchievement": "non_stop", + "StageIncrease": false, + "GetNewShip": false, + "ReachLevel120": false + }, + "Fleet": { + "Fleet1": 1, + "Fleet1Formation": "double_line", + "Fleet1Mode": "combat_auto", + "Fleet1Step": 3, + "Fleet2": 2, + "Fleet2Formation": "double_line", + "Fleet2Mode": "combat_auto", + "Fleet2Step": 2, + "FleetOrder": "fleet1_mob_fleet2_boss", + "AutoSearchFleetOrder": "fleet1_mob_fleet2_boss" + }, + "Submarine": { + "Fleet": 0, + "Mode": "do_not_use" + }, + "Emotion": { + "CalculateEmotion": true, + "IgnoreLowEmotionWarn": false, + "Fleet1Value": 119, + "Fleet1Record": "2020-01-01 00:00:00", + "Fleet1Control": "prevent_yellow_face", + "Fleet1Recover": "not_in_dormitory", + "Fleet1Oath": false, + "Fleet2Value": 119, + "Fleet2Record": "2020-01-01 00:00:00", + "Fleet2Control": "prevent_yellow_face", + "Fleet2Recover": "not_in_dormitory", + "Fleet2Oath": false + }, + "HpControl": { + "UseHpBalance": false, + "UseEmergencyRepair": false, + "UseLowHpRetreat": false, + "HpBalanceThreshold": 0.2, + "HpBalanceWeight": "1000, 1000, 1000", + "RepairUseSingleThreshold": 0.3, + "RepairUseMultiThreshold": 0.6, + "LowHpRetreatThreshold": 0.3 + } + }, "EventSp": { "Scheduler": { "Enable": false, diff --git a/module/config/argument/args.json b/module/config/argument/args.json index 29dd53a2e..596c873e6 100644 --- a/module/config/argument/args.json +++ b/module/config/argument/args.json @@ -4400,6 +4400,390 @@ } } }, + "EventCd": { + "Scheduler": { + "Enable": { + "type": "checkbox", + "value": false + }, + "NextRun": { + "type": "input", + "value": "2020-01-01 00:00:00" + }, + "Command": { + "type": "disable", + "value": "EventCd" + }, + "SuccessInterval": { + "type": "disable", + "value": 30 + }, + "FailureInterval": { + "type": "disable", + "value": 30 + }, + "ServerUpdate": { + "type": "disable", + "value": "00:00" + } + }, + "EventCd": { + "StageFilter": { + "type": "textarea", + "value": "C1 > C2 > C3 > D1 > D2 > D3" + }, + "LastStage": { + "type": "input", + "value": 0 + } + }, + "Campaign": { + "Name": { + "type": "disable", + "value": "dynamic" + }, + "Event": { + "type": "select", + "value": "campaign_main", + "option": [ + "event_20211028_tw", + "event_20211028_cn", + "event_20201012_cn", + "event_20200917_cn", + "event_20210916_cn", + "event_20210722_cn", + "event_20210819_cn", + "event_20200806_cn", + "event_20200723_cn", + "event_20200903_en", + "event_20210624_cn", + "event_20210624_tw", + "event_20210610_tw", + "event_20210527_cn", + "event_20210527_tw", + "event_20210429_tw", + "event_20210422_cn", + "event_20210415_tw", + "event_20210325_cn", + "event_20210225_tw", + "event_20210225_cn", + "event_20210121_cn", + "event_20201229_cn", + "event_20201126_cn", + "event_20200312_cn", + "event_20201029_cn", + "event_20201002_en", + "event_20200820_cn", + "event_20200716_en", + "event_20200611_en", + "event_20200603_en", + "event_20200603_cn", + "event_20200521_en", + "event_20200521_cn", + "event_20200507_cn", + "event_20200423_cn", + "event_20200326_cn", + "event_20200227_cn" + ], + "tw": "event_20211028_tw", + "cn": "event_20211028_cn", + "en": "event_20211028_cn", + "jp": "event_20211028_cn" + }, + "Mode": { + "type": "disable", + "value": "normal", + "option": [ + "normal", + "hard" + ] + }, + "UseClearMode": { + "type": "checkbox", + "value": true + }, + "UseFleetLock": { + "type": "checkbox", + "value": true + }, + "UseAutoSearch": { + "type": "checkbox", + "value": false + }, + "Use2xBook": { + "type": "disable", + "value": false + }, + "AmbushEvade": { + "type": "disable", + "value": true + } + }, + "StopCondition": { + "RunCount": { + "type": "disable", + "value": 0 + }, + "OilLimit": { + "type": "input", + "value": 1000 + }, + "MapAchievement": { + "type": "disable", + "value": "non_stop", + "option": [ + "non_stop", + "100_percent_clear", + "map_3_stars", + "threat_safe", + "threat_safe_without_3_stars" + ] + }, + "StageIncrease": { + "type": "disable", + "value": false + }, + "GetNewShip": { + "type": "disable", + "value": false + }, + "ReachLevel120": { + "type": "disable", + "value": false + } + }, + "Fleet": { + "Fleet1": { + "type": "select", + "value": 1, + "option": [ + 1, + 2, + 3, + 4, + 5, + 6 + ] + }, + "Fleet1Formation": { + "type": "select", + "value": "double_line", + "option": [ + "line_ahead", + "double_line", + "diamond" + ] + }, + "Fleet1Mode": { + "type": "select", + "value": "combat_auto", + "option": [ + "combat_auto", + "combat_manual", + "stand_still_in_the_middle", + "hide_in_bottom_left" + ] + }, + "Fleet1Step": { + "type": "select", + "value": 3, + "option": [ + 2, + 3, + 4, + 5 + ] + }, + "Fleet2": { + "type": "select", + "value": 2, + "option": [ + 0, + 1, + 2, + 3, + 4, + 5, + 6 + ] + }, + "Fleet2Formation": { + "type": "select", + "value": "double_line", + "option": [ + "line_ahead", + "double_line", + "diamond" + ] + }, + "Fleet2Mode": { + "type": "select", + "value": "combat_auto", + "option": [ + "combat_auto", + "combat_manual", + "stand_still_in_the_middle", + "hide_in_bottom_left" + ] + }, + "Fleet2Step": { + "type": "select", + "value": 2, + "option": [ + 2, + 3, + 4, + 5 + ] + }, + "FleetOrder": { + "type": "select", + "value": "fleet1_mob_fleet2_boss", + "option": [ + "fleet1_mob_fleet2_boss", + "fleet1_boss_fleet2_mob", + "fleet1_all_fleet2_standby", + "fleet1_standby_fleet2_all" + ] + }, + "AutoSearchFleetOrder": { + "type": "select", + "value": "fleet1_mob_fleet2_boss", + "option": [ + "fleet1_mob_fleet2_boss", + "fleet1_boss_fleet2_mob", + "fleet1_all_fleet2_standby", + "fleet1_standby_fleet2_all" + ] + } + }, + "Submarine": { + "Fleet": { + "type": "select", + "value": 0, + "option": [ + 0, + 1, + 2 + ] + }, + "Mode": { + "type": "select", + "value": "do_not_use", + "option": [ + "do_not_use", + "hunt_only", + "every_combat" + ] + } + }, + "Emotion": { + "CalculateEmotion": { + "type": "checkbox", + "value": true + }, + "IgnoreLowEmotionWarn": { + "type": "checkbox", + "value": false + }, + "Fleet1Value": { + "type": "input", + "value": 119 + }, + "Fleet1Record": { + "type": "input", + "value": "2020-01-01 00:00:00" + }, + "Fleet1Control": { + "type": "select", + "value": "prevent_yellow_face", + "option": [ + "keep_exp_bonus", + "prevent_green_face", + "prevent_yellow_face", + "prevent_red_face" + ] + }, + "Fleet1Recover": { + "type": "select", + "value": "not_in_dormitory", + "option": [ + "not_in_dormitory", + "dormitory_floor_1", + "dormitory_floor_2" + ] + }, + "Fleet1Oath": { + "type": "checkbox", + "value": false + }, + "Fleet2Value": { + "type": "input", + "value": 119 + }, + "Fleet2Record": { + "type": "input", + "value": "2020-01-01 00:00:00" + }, + "Fleet2Control": { + "type": "select", + "value": "prevent_yellow_face", + "option": [ + "keep_exp_bonus", + "prevent_green_face", + "prevent_yellow_face", + "prevent_red_face" + ] + }, + "Fleet2Recover": { + "type": "select", + "value": "not_in_dormitory", + "option": [ + "not_in_dormitory", + "dormitory_floor_1", + "dormitory_floor_2" + ] + }, + "Fleet2Oath": { + "type": "checkbox", + "value": false + } + }, + "HpControl": { + "UseHpBalance": { + "type": "checkbox", + "value": false + }, + "UseEmergencyRepair": { + "type": "checkbox", + "value": false + }, + "UseLowHpRetreat": { + "type": "checkbox", + "value": false + }, + "HpBalanceThreshold": { + "type": "input", + "value": 0.2 + }, + "HpBalanceWeight": { + "type": "input", + "value": "1000, 1000, 1000" + }, + "RepairUseSingleThreshold": { + "type": "input", + "value": 0.3 + }, + "RepairUseMultiThreshold": { + "type": "input", + "value": 0.6 + }, + "LowHpRetreatThreshold": { + "type": "input", + "value": 0.3 + } + } + }, "EventSp": { "Scheduler": { "Enable": { diff --git a/module/config/argument/argument.yaml b/module/config/argument/argument.yaml index 328de835c..27a4056d3 100644 --- a/module/config/argument/argument.yaml +++ b/module/config/argument/argument.yaml @@ -373,6 +373,10 @@ EventAb: StageFilter: |- A1 > A2 > A3 > B1 > B2 > B3 LastStage: 0 +EventCd: + StageFilter: |- + C1 > C2 > C3 > D1 > D2 > D3 + LastStage: 0 RaidDaily: StageFilter: |- hard > normal > easy diff --git a/module/config/argument/menu.json b/module/config/argument/menu.json index 7ae4ba68d..31cee5263 100644 --- a/module/config/argument/menu.json +++ b/module/config/argument/menu.json @@ -35,6 +35,7 @@ "Exercise", "Sos", "EventAb", + "EventCd", "EventSp", "RaidDaily", "WarArchives" diff --git a/module/config/argument/override.yaml b/module/config/argument/override.yaml index 0e9376bd2..758e6e247 100644 --- a/module/config/argument/override.yaml +++ b/module/config/argument/override.yaml @@ -231,6 +231,22 @@ EventAb: StageIncrease: false GetNewShip: false ReachLevel120: false +EventCd: + Scheduler: + SuccessInterval: 30 + FailureInterval: 30 + ServerUpdate: 00:00 + Campaign: + Name: dynamic + Mode: normal + Use2xBook: false + AmbushEvade: true + StopCondition: + RunCount: 0 + MapAchievement: non_stop + StageIncrease: false + GetNewShip: false + ReachLevel120: false EventSp: Scheduler: SuccessInterval: 30 diff --git a/module/config/argument/task.yaml b/module/config/argument/task.yaml index f2494f7c6..b708a7d54 100644 --- a/module/config/argument/task.yaml +++ b/module/config/argument/task.yaml @@ -151,6 +151,15 @@ EventAb: - Submarine - Emotion - HpControl +EventCd: + - Scheduler + - EventCd + - Campaign + - StopCondition + - Fleet + - Submarine + - Emotion + - HpControl EventSp: - Scheduler - Campaign diff --git a/module/config/config_generated.py b/module/config/config_generated.py index 2d0fb3c50..b228b9e3e 100644 --- a/module/config/config_generated.py +++ b/module/config/config_generated.py @@ -249,6 +249,10 @@ class GeneratedConfig: EventAb_StageFilter = 'A1 > A2 > A3 > B1 > B2 > B3' EventAb_LastStage = 0 + # Group `EventCd` + EventCd_StageFilter = 'C1 > C2 > C3 > D1 > D2 > D3' + EventCd_LastStage = 0 + # Group `RaidDaily` RaidDaily_StageFilter = 'hard > normal > easy' diff --git a/module/config/config_manual.py b/module/config/config_manual.py index 97ed0b041..00709153d 100644 --- a/module/config/config_manual.py +++ b/module/config/config_manual.py @@ -10,7 +10,7 @@ class ManualConfig: > Gacha > ShopFrequent > ShopOnce > Shipyard > DataKey > OpsiExplore > OpsiObscure > Exercise > Daily > Hard > OpsiAshAssist - > Sos > EventSp > EventAb > RaidDaily > WarArchives + > Sos > EventSp > EventAb > EventCd > RaidDaily > WarArchives > OpsiDaily > OpsiMeowfficerFarming > Event > Raid > Main > C124LargeLeveling > C122MediumLeveling > C11AffinityFarming > C72MysteryFarming > GemsFarming diff --git a/module/config/config_updater.py b/module/config/config_updater.py index 6d4446229..ddc46ead5 100644 --- a/module/config/config_updater.py +++ b/module/config/config_updater.py @@ -317,11 +317,12 @@ class ConfigGenerator: else: insert('Event') insert('EventAb') + insert('EventCd') insert('EventSp') insert('GemsFarming') # Remove campaign_main from event list - for task in ['Event', 'EventAb', 'EventSp', 'Raid', 'RaidDaily', 'WarArchives']: + for task in ['Event', 'EventAb', 'EventCd', 'EventSp', 'Raid', 'RaidDaily', 'WarArchives']: options = deep_get(self.args, keys=f'{task}.Campaign.Event.option') options = [option for option in options if option != 'campaign_main'] deep_set(self.args, keys=f'{task}.Campaign.Event.option', value=options) @@ -377,7 +378,7 @@ class ConfigUpdater: # Update to latest event server_ = deep_get(new, 'Alas.Emulator.Server', 'cn') if not is_template: - for task in ['Event', 'EventAb', 'EventSp', 'Raid', 'RaidDaily']: + for task in ['Event', 'EventAb', 'EventCd', 'EventSp', 'Raid', 'RaidDaily']: deep_set(new, keys=f'{task}.Campaign.Event', value=deep_get(self.args, f'{task}.Campaign.Event.{server_}')) diff --git a/module/config/i18n/en-US.json b/module/config/i18n/en-US.json index 7167b1722..6338dff19 100644 --- a/module/config/i18n/en-US.json +++ b/module/config/i18n/en-US.json @@ -142,6 +142,10 @@ "name": "EventAB", "help": "" }, + "EventCd": { + "name": "EventCd", + "help": "" + }, "EventSp": { "name": "EventSP", "help": "" @@ -1366,6 +1370,20 @@ "help": "Automatically updated, skips completed levels in the filter, and resets at server reset time (00:00)" } }, + "EventCd": { + "_info": { + "name": "EventCD Settings", + "help": "" + }, + "StageFilter": { + "name": "EventCD Stage Filter", + "help": "" + }, + "LastStage": { + "name": "Last EventCD Stage", + "help": "Automatically updated, skips completed levels in the filter, and resets at server reset time (00:00)" + } + }, "RaidDaily": { "_info": { "name": "Raid Daily Settings", diff --git a/module/config/i18n/ja-JP.json b/module/config/i18n/ja-JP.json index a3608f597..0a9831672 100644 --- a/module/config/i18n/ja-JP.json +++ b/module/config/i18n/ja-JP.json @@ -142,6 +142,10 @@ "name": "Task.EventAb.name", "help": "Task.EventAb.help" }, + "EventCd": { + "name": "Task.EventCd.name", + "help": "Task.EventCd.help" + }, "EventSp": { "name": "Task.EventSp.name", "help": "Task.EventSp.help" @@ -1366,6 +1370,20 @@ "help": "EventAb.LastStage.help" } }, + "EventCd": { + "_info": { + "name": "EventCd._info.name", + "help": "EventCd._info.help" + }, + "StageFilter": { + "name": "EventCd.StageFilter.name", + "help": "EventCd.StageFilter.help" + }, + "LastStage": { + "name": "EventCd.LastStage.name", + "help": "EventCd.LastStage.help" + } + }, "RaidDaily": { "_info": { "name": "RaidDaily._info.name", diff --git a/module/config/i18n/zh-CN.json b/module/config/i18n/zh-CN.json index 49bfcf87b..a71f3641f 100644 --- a/module/config/i18n/zh-CN.json +++ b/module/config/i18n/zh-CN.json @@ -142,6 +142,10 @@ "name": "活动每日AB图", "help": "" }, + "EventCd": { + "name": "活动每日CD图", + "help": "" + }, "EventSp": { "name": "活动每日SP图", "help": "" @@ -1366,6 +1370,20 @@ "help": "自动更新的数值,将跳过过滤器中已完成的关卡,过0点重置" } }, + "EventCd": { + "_info": { + "name": "活动每日CD图", + "help": "" + }, + "StageFilter": { + "name": "活动每日过滤器", + "help": "按过滤器顺序出击" + }, + "LastStage": { + "name": "上一个完成的关卡", + "help": "自动更新的数值,将跳过过滤器中已完成的关卡,过0点重置" + } + }, "RaidDaily": { "_info": { "name": "共斗每日", diff --git a/module/config/i18n/zh-TW.json b/module/config/i18n/zh-TW.json index 801e315a5..de6dbc4c2 100644 --- a/module/config/i18n/zh-TW.json +++ b/module/config/i18n/zh-TW.json @@ -142,6 +142,10 @@ "name": "活動每日AB圖", "help": "" }, + "EventCd": { + "name": "活動每日CD圖", + "help": "" + }, "EventSp": { "name": "活動每日SP圖", "help": "" @@ -1366,6 +1370,20 @@ "help": "自動更新的數值,將跳過過濾器中已完成的地圖,過0點重置" } }, + "EventCd": { + "_info": { + "name": "活動每日CD圖", + "help": "" + }, + "StageFilter": { + "name": "活動每日過濾器", + "help": "按活動過濾器順序出擊" + }, + "LastStage": { + "name": "上一個完成的地圖", + "help": "自動更新的數值,將跳過過濾器中已完成的地圖,過0點重置" + } + }, "RaidDaily": { "_info": { "name": "共鬥每日", diff --git a/module/event/campaign_cd.py b/module/event/campaign_cd.py new file mode 100644 index 000000000..0f21fe21a --- /dev/null +++ b/module/event/campaign_cd.py @@ -0,0 +1,73 @@ +import os +import re + +from module.base.filter import Filter +from module.campaign.run import CampaignRun +from module.config.config import TaskEnd +from module.config.utils import get_server_last_update +from module.logger import logger + +STAGE_FILTER = Filter(regex=re.compile('^(.*?)$'), attr=('stage',)) + + +class EventStage: + def __init__(self, filename): + self.filename = filename + self.stage = 'unknown' + if filename[-3:] == '.py': + self.stage = filename[:-3] + + def __str__(self): + return self.stage + + def __eq__(self, other): + return str(self) == str(other) + + +class CampaignCD(CampaignRun): + def run(self): + # Filter map files + stages = [EventStage(file) for file in os.listdir(f'./campaign/{self.config.Campaign_Event}')] + logger.attr('Stage', [str(stage) for stage in stages]) + logger.attr('StageFilter', self.config.EventCd_StageFilter) + STAGE_FILTER.load(self.config.EventCd_StageFilter) + stages = [str(stage) for stage in STAGE_FILTER.apply(stages)] + logger.attr('Filter sort', ' > '.join(stages)) + + if not stages: + logger.warning('No stage satisfy current filter') + self.config.Scheduler_Enable = False + self.config.task_stop() + + # Start from last stage + logger.info(f'LastStage {self.config.EventCd_LastStage}, recorded at {self.config.Scheduler_NextRun}') + if get_server_last_update(self.config.Scheduler_ServerUpdate) >= self.config.Scheduler_NextRun: + logger.info('LastStage outdated, reset') + self.config.EventCd_LastStage = 0 + else: + last = str(self.config.EventCd_LastStage).lower() + if last in stages: + stages = stages[stages.index(last) + 1:] + logger.attr('Filter sort', ' > '.join(stages)) + else: + logger.info('Start from the beginning') + + # Run + for stage in stages: + stage = str(stage) + try: + super().run(name=stage, folder=self.config.Campaign_Event, total=1) + except TaskEnd: + # Catch task switch + pass + if self.run_count > 0: + with self.config.multi_set(): + self.config.EventCd_LastStage = stage + self.config.task_delay(minute=0) + else: + self.config.task_stop() + if self.config.task_switched(): + self.config.task_stop() + + # Scheduler + self.config.task_delay(server_update=True)