diff --git a/MeoAsstMac/Configuration Views/FightSettingsView.swift b/MeoAsstMac/Configuration Views/FightSettingsView.swift index 694ea72d1..280dda6a5 100644 --- a/MeoAsstMac/Configuration Views/FightSettingsView.swift +++ b/MeoAsstMac/Configuration Views/FightSettingsView.swift @@ -16,27 +16,75 @@ struct FightSettingsView: View { var body: some View { Form { Section { - HStack(spacing: 20) { - if useCustomStage || stageNotListed { - TextField("关卡名", text: $config.stage) - } else { - Picker("关卡选择", selection: $config.stage) { - Text("当前/上次").tag("") - Text("1-7").tag("1-7") - Text("CE-6").tag("CE-6") - Text("AP-5").tag("AP-5") - Text("CA-5").tag("CA-5") - Text("LS-6").tag("LS-6") - Text("剿灭模式").tag("Annihilation") + Toggle("使用备选关卡", isOn: $config.useOptionalStage) + .onChange(of: config.useOptionalStage) { enabled in + if enabled, config.stagePlan.count < 2 { + config.stagePlan = [config.stage, ""] } } - Toggle("手动输入关卡名", isOn: isUsingCustomStage) - } - .animation(.default, value: config.stage) - } - if useCustomStage || stageNotListed { - Text("<无忧梦呓>请使用特殊关卡名,如AveMujica-8").foregroundStyle(.secondary) + if config.useOptionalStage { + ForEach(config.stagePlan.indices, id: \.self) { index in + let stageName = config.stagePlan[index] + let isOpen = !stageName.isEmpty && FightConfiguration.isStageOpenToday(stageName) + HStack(spacing: 8) { + if planListedStages.contains(stageName) { + Picker("关卡 \(index + 1)", selection: $config.stagePlan[index]) { + Text("当前/上次").tag("") + Text("1-7").tag("1-7") + Text("CE-6").tag("CE-6") + Text("AP-5").tag("AP-5") + Text("CA-5").tag("CA-5") + Text("LS-6").tag("LS-6") + Text("SK-5").tag("SK-5") + Text("剿灭模式").tag("Annihilation") + } + } else { + TextField("关卡 \(index + 1)", text: $config.stagePlan[index]) + } + if !stageName.isEmpty { + Image(systemName: isOpen ? "checkmark.circle.fill" : "clock.fill") + .foregroundColor(isOpen ? .green : .orange) + .help(isOpen ? "今天开放" : "今天不开放") + } + Button { + config.stagePlan.remove(at: index) + } label: { + Image(systemName: "minus.circle.fill").foregroundColor(.red) + } + .buttonStyle(.plain) + .disabled(config.stagePlan.count <= 1) + } + } + Button { + config.stagePlan.append("") + } label: { + Label("添加备选关卡", systemImage: "plus.circle") + } + Text("从上往下选择今天第一个开放的关卡执行").foregroundStyle(.secondary).font(.caption) + } else { + HStack(spacing: 20) { + if useCustomStage || stageNotListed { + TextField("关卡名", text: $config.stage) + } else { + Picker("关卡选择", selection: $config.stage) { + Text("当前/上次").tag("") + Text("1-7").tag("1-7") + Text("CE-6").tag("CE-6") + Text("AP-5").tag("AP-5") + Text("CA-5").tag("CA-5") + Text("LS-6").tag("LS-6") + Text("剿灭模式").tag("Annihilation") + } + } + Toggle("手动输入关卡名", isOn: isUsingCustomStage) + } + .animation(.default, value: config.stage) + + if useCustomStage || stageNotListed { + Text("<无忧梦呓>请使用特殊关卡名,如AveMujica-8").foregroundStyle(.secondary) + } + } } Divider() @@ -212,6 +260,7 @@ struct FightSettingsView: View { private var stageNotListed: Bool { !listedStages.contains(config.stage) } private let listedStages = ["", "1-7", "CE-6", "AP-5", "CA-5", "LS-6", "Annihilation"] + private let planListedStages: Set = ["", "1-7", "CE-6", "AP-5", "CA-5", "LS-6", "SK-5", "Annihilation"] } struct FightSettingsView_Previews: PreviewProvider { diff --git a/MeoAsstMac/Task Configurations/FightConfiguration.swift b/MeoAsstMac/Task Configurations/FightConfiguration.swift index fab513e5b..cd2436bdf 100644 --- a/MeoAsstMac/Task Configurations/FightConfiguration.swift +++ b/MeoAsstMac/Task Configurations/FightConfiguration.swift @@ -11,6 +11,9 @@ struct FightConfiguration: MAATaskConfiguration { var type: MAATaskType { .Fight } var stage: String + var stagePlan: [String] + var useOptionalStage: Bool + var medicine: Int? var expiring_medicine: Int? var stone: Int? @@ -29,6 +32,10 @@ struct FightConfiguration: MAATaskConfiguration { } var subtitle: String { + if useOptionalStage { + let stages = stagePlan.filter { !$0.isEmpty } + return stages.isEmpty ? NSLocalizedString("当前/上次", comment: "") : stages.joined(separator: " / ") + } if stage == "" { return NSLocalizedString("当前/上次", comment: "") } else { @@ -58,10 +65,67 @@ struct FightConfiguration: MAATaskConfiguration { .fight(self) } - typealias Params = Self + // MARK: - Params sent to MAA Core + + struct CoreParams: Encodable { + var stage: String + var medicine: Int? + var expiring_medicine: Int? + var stone: Int? + var times: Int? + var series: Int? + var drops: [String: Int]? + var report_to_penguin: Bool + var penguin_id: String + var server: String + var client_type: String + var DrGrandet: Bool + } + + typealias Params = CoreParams + + var params: CoreParams { + let activeStage: String + if useOptionalStage { + activeStage = stagePlan.first { Self.isStageOpenToday($0) } ?? stagePlan.first ?? "" + } else { + activeStage = stage + } + return CoreParams( + stage: activeStage, + medicine: medicine, + expiring_medicine: expiring_medicine, + stone: stone, + times: times, + series: series, + drops: drops, + report_to_penguin: report_to_penguin, + penguin_id: penguin_id, + server: server, + client_type: client_type, + DrGrandet: DrGrandet + ) + } - var params: Self { - self + // MARK: - Stage Open Days + // Calendar.weekday: 1=Sun, 2=Mon, 3=Tue, 4=Wed, 5=Thu, 6=Fri, 7=Sat + private static let stageOpenDays: [String: Set] = [ + "CE-6": [3, 5, 7, 1], // Tue, Thu, Sat, Sun + "AP-5": [2, 5, 7, 1], // Mon, Thu, Sat, Sun + "CA-5": [3, 4, 6, 1], // Tue, Wed, Fri, Sun + "SK-5": [2, 4, 6, 7], // Mon, Wed, Fri, Sat + "PR-A-1": [2, 5, 6, 1], "PR-A-2": [2, 5, 6, 1], // Mon, Thu, Fri, Sun + "PR-B-1": [2, 3, 6, 7], "PR-B-2": [2, 3, 6, 7], // Mon, Tue, Fri, Sat + "PR-C-1": [4, 5, 7, 1], "PR-C-2": [4, 5, 7, 1], // Wed, Thu, Sat, Sun + "PR-D-1": [3, 4, 7, 1], "PR-D-2": [3, 4, 7, 1], // Tue, Wed, Sat, Sun + ] + + /// 判断关卡今天是否开放(未在列表中的关卡视为全天开放) + static func isStageOpenToday(_ stage: String) -> Bool { + guard !stage.isEmpty else { return true } + guard let days = stageOpenDays[stage] else { return true } + let weekday = Calendar.current.component(.weekday, from: Date()) + return days.contains(weekday) } // 掉落物品列表 @@ -130,6 +194,8 @@ extension FightConfiguration { init(from decoder: any Decoder) throws { let container = try decoder.container(keyedBy: CodingKeys.self) self.stage = try container.decodeIfPresent(String.self, forKey: .stage) ?? "" + self.useOptionalStage = try container.decodeIfPresent(Bool.self, forKey: .useOptionalStage) ?? false + self.stagePlan = try container.decodeIfPresent([String].self, forKey: .stagePlan) ?? [self.stage] self.medicine = try container.decodeIfPresent(Int.self, forKey: .medicine) self.expiring_medicine = try container.decodeIfPresent(Int.self, forKey: .expiring_medicine) self.stone = try container.decodeIfPresent(Int.self, forKey: .stone) diff --git a/MeoAsstMac/Task Configurations/LegacyConfigurations.swift b/MeoAsstMac/Task Configurations/LegacyConfigurations.swift index 6ee0baad5..f6f406171 100644 --- a/MeoAsstMac/Task Configurations/LegacyConfigurations.swift +++ b/MeoAsstMac/Task Configurations/LegacyConfigurations.swift @@ -89,6 +89,8 @@ extension InfrastConfiguration { extension FightConfiguration { fileprivate init(migrating config: LegacyFightConfiguration) { self.stage = config.stage + self.stagePlan = [config.stage] + self.useOptionalStage = false self.medicine = config.medicine self.expiring_medicine = config.expiring_medicine self.stone = config.stone diff --git a/Resources/Localizable.xcstrings b/Resources/Localizable.xcstrings index 5549a0405..011f4e862 100644 --- a/Resources/Localizable.xcstrings +++ b/Resources/Localizable.xcstrings @@ -1484,6 +1484,9 @@ } } } + }, + "SK-5" : { + }, "SSSGamePass" : { "localizations" : { @@ -1874,6 +1877,15 @@ } } } + }, + "今天不开放" : { + + }, + "今天开放" : { + + }, + "从上往下选择今天第一个开放的关卡执行" : { + }, "从剪贴板读取" : { "localizations" : { @@ -1997,6 +2009,9 @@ } } } + }, + "使用备选关卡" : { + }, "使用密文板" : { "localizations" : { @@ -2177,6 +2192,9 @@ } } } + }, + "关卡 %lld" : { + }, "关卡名" : { "localizations" : { @@ -3808,6 +3826,9 @@ } } } + }, + "添加备选关卡" : { + }, "游戏设置" : { "localizations" : {