feat: SideStory Part.1

This commit is contained in:
status102
2026-05-28 19:07:46 +08:00
parent 30925621f2
commit cc19f3cec4
16 changed files with 452 additions and 4 deletions

View File

@@ -53,6 +53,19 @@
"text": ["众生行记", "谒见神祇", "见神", "息止安所"],
"next": ["MTChapterToMT"]
},
"MT-OpenTask": {
"algorithm": "JustReturn",
"next": ["MT-OpenTask@SS-Open", "MT-OpenTask@SS-OpenOcr"]
},
"MT-OpenTask@SS-Open": {
"baseTask": "SS-Open",
"template": ["StageSideStory.png", "StageActivity.png"],
"next": ["MT@SS@EnterTaskPage"]
},
"MT-OpenTask@SS-OpenOcr": {
"baseTask": "SS-OpenOcr",
"next": ["MT@SS@EnterTaskPage"]
},
"MTChapterToMT": {
"algorithm": "OcrDetect",
"action": "ClickSelf",
@@ -60,5 +73,10 @@
"preDelay": 4000,
"roi": [622, 588, 234, 132],
"next": ["#self", "ChapterSwipeToTheRight"]
},
"MT@SS@EnterTaskPage": {
"text": ["哄睡", "指标"],
"roi": [1100, 175, 140, 40],
"ocrReplace": [["指标", "指示"]]
}
}

View File

@@ -87,5 +87,26 @@
"next": ["SS@Store@ClickItem", "#self"],
"maxTimes": 10,
"exceededNext": ["Stop"]
},
"SS@EnterTaskPage": {
"algorithm": "OcrDetect",
"action": "ClickSelf",
"text": [],
"preDelay": 4000,
"onErrorNext": ["Return"],
"next": ["SS@ClaimTask", "#self"]
},
"SS@ClaimTask": {
"algorithm": "OcrDetect",
"action": "ClickSelf",
"text": ["领取"],
"postDelay": 2000,
"roi": [980, 140, 240, 70],
"next": ["SS@ClaimTaskSuccess", "#self"]
},
"SS@ClaimTaskSuccess": {
"baseTask": "CreditShop-Bought",
"template": "CreditShop-Bought.png",
"next": ["ReturnButtonCheck", "#self"]
}
}

View File

@@ -1082,6 +1082,13 @@
],
"onErrorNext": ["SwitchTheme@ToggleSettingsMenu"]
},
"ReturnButtonCheck": {
"baseTask": "ReturnButton",
"template": ["Return.png", "Return-White.png"],
"action": "DoNothing",
"next": [],
"onErrorNext": []
},
"FromStageSN": {
"template": "StageSNReturnFlag.png",
"action": "ClickRect",

View File

@@ -0,0 +1,90 @@
#include "SideStoryTask.h"
#include <ranges>
#include <utility>
#include "Config/TaskData.h"
#include "Task/Fight/SideStoryReopenTask.h"
#include "Task/Fight/StageDropsTaskPlugin.h"
#include "Task/Fight/StageNavigationTask.h"
#include "Task/ProcessTask.h"
#include "Utils/Logger.hpp"
asst::SideStoryTask::SideStoryTask(const AsstCallback& callback, Assistant* inst) :
InterfaceTask(callback, inst, TaskType),
m_start_up_task_ptr(std::make_shared<ProcessTask>(m_callback, m_inst, TaskType)),
m_stage_navigation_task_ptr(std::make_shared<StageNavigationTask>(m_callback, m_inst, TaskType)),
m_sidestory_reopen_task_ptr(std::make_shared<SideStoryReopenTask>(m_callback, m_inst, TaskType)),
m_claim_task_task_ptr(std::make_shared<ProcessTask>(m_callback, m_inst, TaskType))
{
LogTraceFunction;
// 进入选关界面
// 对于指定关卡,就是主界面的“终端”点进去
// 对于当前/上次,就是点到 蓝色开始行动 为止。
m_start_up_task_ptr->set_tasks({ "StageBegin" })
.set_times_limit("GoLastBattle", 0)
.set_times_limit("StartButton1", 0)
.set_times_limit("StartButton2", 0)
.set_times_limit("StoneConfirm", 0)
.set_times_limit("StageSNReturnFlag", 0)
.set_times_limit("PRTS1", 0)
.set_times_limit("PRTS2", 0)
.set_times_limit("PRTS3", 0)
.set_times_limit("EndOfAction", 0)
.set_retry_times(5);
m_start_up_task2_ptr->set_tasks({ "StageBegin" })
.set_times_limit("GoLastBattle", 0)
.set_times_limit("StartButton1", 0)
.set_times_limit("StartButton2", 0)
.set_times_limit("StoneConfirm", 0)
.set_times_limit("StageSNReturnFlag", 0)
.set_times_limit("PRTS1", 0)
.set_times_limit("PRTS2", 0)
.set_times_limit("PRTS3", 0)
.set_times_limit("EndOfAction", 0)
.set_retry_times(5);
m_stage_navigation_task_ptr->set_retry_times(0);
m_stage_navigation_task2_ptr->set_retry_times(0);
m_sidestory_reopen_task_ptr->set_enable(false).set_retry_times(0);
m_subtasks.emplace_back(m_start_up_task_ptr);
m_subtasks.emplace_back(m_stage_navigation_task_ptr);
m_subtasks.emplace_back(m_sidestory_reopen_task_ptr);
m_subtasks.emplace_back(m_start_up_task2_ptr);
m_subtasks.emplace_back(m_stage_navigation_task2_ptr);
m_subtasks.emplace_back(m_claim_task_task_ptr);
}
bool asst::SideStoryTask::set_params(const json::value& params)
{
LogTraceFunction;
const std::string code = params.get("code", "");
if (!Task.get(code + "-OpenOpt")) {
return false;
}
const bool stage_replay = params.get("stage_replay", false);
m_start_up_task_ptr->set_enable(stage_replay);
m_stage_navigation_task_ptr->set_enable(stage_replay);
m_sidestory_reopen_task_ptr->set_enable(stage_replay);
if (stage_replay) {
m_stage_navigation_task_ptr->set_stage_name(code + "-OpenOpt");
}
const bool award = params.get("award", false);
if (award) {
if (!Task.get(code + "-OpenTask")) {
LogError << "claim task not exists:" << code + "-OpenTask";
return false;
}
m_claim_task_task_ptr->set_tasks({ code + "-OpenTask" }).set_retry_times(20);
}
m_start_up_task2_ptr->set_enable(award);
m_stage_navigation_task2_ptr->set_enable(award);
m_claim_task_task_ptr->set_enable(award);
return true;
}

View File

@@ -0,0 +1,30 @@
#pragma once
#include "Task/InterfaceTask.h"
#include <memory>
namespace asst
{
class ProcessTask;
class StageNavigationTask;
class SideStoryReopenTask;
class SideStoryTask final : public InterfaceTask
{
public:
inline static constexpr std::string_view TaskType = "SideStory";
SideStoryTask(const AsstCallback& callback, Assistant* inst);
virtual ~SideStoryTask() override = default;
virtual bool set_params(const json::value& params) override;
protected:
std::shared_ptr<ProcessTask> m_start_up_task_ptr = nullptr;
std::shared_ptr<ProcessTask> m_start_up_task2_ptr = nullptr;
std::shared_ptr<StageNavigationTask> m_stage_navigation_task_ptr = nullptr;
std::shared_ptr<StageNavigationTask> m_stage_navigation_task2_ptr = nullptr;
std::shared_ptr<SideStoryReopenTask> m_sidestory_reopen_task_ptr = nullptr;
std::shared_ptr<ProcessTask> m_claim_task_task_ptr = nullptr;
};
}

View File

@@ -0,0 +1,26 @@
// <copyright file="SideStoryTask.cs" company="MaaAssistantArknights">
// Part of the MaaWpfGui project, maintained by the MaaAssistantArknights team (Maa Team)
// Copyright (C) 2021-2025 MaaAssistantArknights Contributors
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU Affero General Public License v3.0 only as published by
// the Free Software Foundation, either version 3 of the License, or
// any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY
// </copyright>
#nullable enable
using static MaaWpfGui.Main.AsstProxy;
namespace MaaWpfGui.Configuration.Single.MaaTask;
public class SideStoryTask : BaseTask
{
public SideStoryTask() => TaskType = TaskType.SideStory;
/// <summary>
/// Gets or sets 上次活动的StageCode, 用于判断活动是否更新
/// </summary>
public string StageCode { get; set; } = string.Empty;
}

View File

@@ -2862,10 +2862,13 @@ public class AsstProxy
/// <summary>更新用户数据</summary>
UserDataUpdate,
/// <summary>Side Story</summary>
SideStory,
/// <summary>小游戏</summary>
MiniGame,
/// <summary>自定义任务s</summary>
/// <summary>自定义任务</summary>
Custom,
}

View File

@@ -0,0 +1,34 @@
// <copyright file="AsstSideStoryTask.cs" company="MaaAssistantArknights">
// Part of the MaaWpfGui project, maintained by the MaaAssistantArknights team (Maa Team)
// Copyright (C) 2021-2025 MaaAssistantArknights Contributors
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU Affero General Public License v3.0 only as published by
// the Free Software Foundation, either version 3 of the License, or
// any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY
// </copyright>
using MaaWpfGui.Services;
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
namespace MaaWpfGui.Models.AsstTasks;
public class AsstSideStoryTask : AsstBaseTask
{
public override AsstTaskType TaskType => AsstTaskType.SideStory;
/// <summary>
/// Gets or sets 客户端版本
/// </summary>
[JsonProperty("stage")]
public string StageCode { get; set; } = string.Empty;
public override (AsstTaskType TaskType, JObject Params) Serialize()
{
return (TaskType, JObject.FromObject(this));
}
}

View File

@@ -54,6 +54,8 @@ public class TaskSettingVisibilityInfo : PropertyChangedBase
public bool UserDataUpdate { get => field; set => SetAndNotify(ref field, value); }
public bool SideStory { get => field; set => SetAndNotify(ref field, value); }
public bool Custom { get => field; set => SetAndNotify(ref field, value); }
public bool PostAction { get => field; set => SetAndNotify(ref field, value); }
@@ -148,6 +150,7 @@ public class TaskSettingVisibilityInfo : PropertyChangedBase
RoguelikeTask => Roguelike = enable,
ReclamationTask => Reclamation = enable,
UserDataUpdateTask => UserDataUpdate = enable,
SideStoryTask => SideStory = enable,
CustomTask => Custom = enable,
_ => throw new NotImplementedException(),
};
@@ -188,6 +191,7 @@ public class TaskSettingVisibilityInfo : PropertyChangedBase
Roguelike = false;
Reclamation = false;
UserDataUpdate = false;
SideStory = false;
Custom = false;
}

View File

@@ -859,6 +859,9 @@ C:\\leidian\\LDPlayer9。\n
<system:String x:Key="Pormpt1">周一了,可以打剿灭了~</system:String>
<system:String x:Key="Pormpt2">周日了,记得打剿灭哦~</system:String>
<!-- !战斗设置 -->
<!-- SideStory任务 -->
<system:String x:Key="SideStoryReopen">活动复刻: 「{0}」</system:String>
<!-- !SideStory任务 -->
<!-- 日志 -->
<system:String x:Key="VersionMismatch">UI 和 Core 版本不一致: {0} 和 {1},可能导致不可预测的行为,请勿手动替换文件或者在更新时占用文件。\n\n{key=FullPackageUpgradeTips}</system:String>
<system:String x:Key="FullPackageUpgradeTips">请下载完整包并解压到新的文件夹,切勿直接覆盖原文件夹。\n可将原有的 config、data 与 debug 文件夹复制到新文件夹中,以保留原有配置和日志。</system:String>

View File

@@ -185,6 +185,11 @@ public enum AsstTaskType : byte
/// </summary>
Reclamation,
/// <summary>
/// SideStory
/// </summary>
SideStory,
/// <summary>
/// 自定义任务
/// </summary>

View File

@@ -29,7 +29,6 @@ using System.Windows;
using System.Windows.Controls;
using System.Windows.Media.Imaging;
using JetBrains.Annotations;
using MaaWpfGui.Configuration;
using MaaWpfGui.Configuration.Factory;
using MaaWpfGui.Configuration.Single.MaaTask;
using MaaWpfGui.Constants;
@@ -134,7 +133,12 @@ public class TaskQueueViewModel : Screen
public static UserDataUpdateSettingsUserControlModel UserDataUpdateTask => UserDataUpdateSettingsUserControlModel.Instance;
/// <summary>
/// Gets 生稀盐酸任务Model
/// Gets SideStory任务Model
/// </summary>
public static SideStorySettingsUserControlModel SideStoryTask => SideStorySettingsUserControlModel.Instance;
/// <summary>
/// Gets 自定任务Model
/// </summary>
public static CustomSettingsUserControlModel CustomTask => CustomSettingsUserControlModel.Instance;
@@ -1332,6 +1336,7 @@ public class TaskQueueViewModel : Screen
new GenericCombinedData<Type> { Display = LocalizationHelper.GetString("Roguelike"), Value = typeof(RoguelikeTask) },
new GenericCombinedData<Type> { Display = LocalizationHelper.GetString("Reclamation"), Value = typeof(ReclamationTask) },
new GenericCombinedData<Type> { Display = LocalizationHelper.GetString("UserDataUpdate"), Value = typeof(UserDataUpdateTask) },
new GenericCombinedData<Type> { Display = LocalizationHelper.GetString("SideStoryTask"), Value = typeof(SideStoryTask) },
new GenericCombinedData<Type> { Display = LocalizationHelper.GetString("Custom"), Value = typeof(CustomTask) },
]);

View File

@@ -0,0 +1,87 @@
// <copyright file="SideStorySettingsUserControlModel.cs" company="MaaAssistantArknights">
// Part of the MaaWpfGui project, maintained by the MaaAssistantArknights team (Maa Team)
// Copyright (C) 2021-2025 MaaAssistantArknights Contributors
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU Affero General Public License v3.0 only as published by
// the Free Software Foundation, either version 3 of the License, or
// any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY
// </copyright>
#nullable enable
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Linq;
using MaaWpfGui.Configuration.Single.MaaTask;
using MaaWpfGui.Helper;
using MaaWpfGui.Models.AsstTasks;
using Stylet;
using static MaaWpfGui.Main.AsstProxy;
namespace MaaWpfGui.ViewModels.UserControl.TaskQueue;
public class SideStorySettingsUserControlModel : TaskSettingsViewModel, SideStorySettingsUserControlModel.ISerialize
{
static SideStorySettingsUserControlModel()
{
Instance = new();
}
public static SideStorySettingsUserControlModel Instance { get; }
public bool TaskAward { get => field; set => SetAndNotify(ref field, value); } = true;
public bool StageReopen { get => field; set => SetAndNotify(ref field, value); } = true;
public ObservableCollection<StageItem> StageList { get; set; } = [.. Enumerable.Range(1, 10).Select(i => new StageItem(i))];
public bool IsSideStoryReopenEnable { get => field; set => SetAndNotify(ref field, value); }
public string ActivityInfo { get => field; private set => SetAndNotify(ref field, value); } = string.Empty;
public override void RefreshUI(BaseTask baseTask)
{
if (Instances.StageManager.ActivityList.TryGetValue("SSReopen", out var activity))
{
IsSideStoryReopenEnable = true;
ActivityInfo = $"{LocalizationHelper.GetStringFormat("SideStoryReopen", activity.Info.StageName)}";
}
else
{
ActivityInfo = LocalizationHelper.GetString("NoActivity");
IsSideStoryReopenEnable = false;
}
}
public override (bool? IsSuccess, IEnumerable<int> TaskId) SerializeTask(BaseTask? baseTask, int? taskId = null) => (this as ISerialize).Serialize(baseTask, taskId);
public class StageItem(int stage) : PropertyChangedBase
{
private int Stage = stage;
public string Display => "MT-" + Stage.ToString();
public bool Value { get => field; set => SetAndNotify(ref field, value); } = true;
}
private interface ISerialize : ITaskQueueModelSerialize
{
(bool? IsSuccess, IEnumerable<int> TaskId) ITaskQueueModelSerialize.Serialize(BaseTask? baseTask, int? taskId)
{
if (baseTask is not CustomTask custom)
{
return (null, []);
}
var task = new AsstCustomTask() { };
return taskId switch {
int id when id > 0 => (Instances.AsstProxy.AsstSetTaskParamsEncoded(id, task), [id]),
null => FromSingle(Instances.AsstProxy.AsstAppendTaskWithEncoding(TaskType.Custom, task)),
_ => (null, []),
};
}
}
}

View File

@@ -373,7 +373,12 @@
Padding="0,3"
Command="{s:Action AddTaskQueueTask}"
CommandParameter="{Binding TaskTypeList[9].Value}"
Header="{Binding TaskTypeList[9].Display}"
Header="{Binding TaskTypeList[9].Display}" />
<MenuItem
Padding="0,3"
Command="{s:Action AddTaskQueueTask}"
CommandParameter="{Binding TaskTypeList[10].Value}"
Header="{Binding TaskTypeList[10].Display}"
Visibility="{c:Binding ShowDebugTask}" />
</ContextMenu>
</hc:ContextMenuButton.Menu>
@@ -608,6 +613,12 @@
Visibility="{c:Binding DataContext.TaskSettingVisibilities.UserDataUpdate,
RelativeSource={RelativeSource Mode=FindAncestor,
AncestorType={x:Type UserControl}}}" />
<taskQueue:SideStorySettingsUserControl
DataContext="{Binding SideStoryTask}"
IsEnabled="{Binding DataContext.Idle, RelativeSource={RelativeSource Mode=FindAncestor, AncestorType={x:Type UserControl}}}"
Visibility="{c:Binding DataContext.TaskSettingVisibilities.SideStory,
RelativeSource={RelativeSource Mode=FindAncestor,
AncestorType={x:Type UserControl}}}" />
<taskQueue:CustomUserControl DataContext="{Binding CustomTask}" Visibility="{c:Binding DataContext.TaskSettingVisibilities.Custom, RelativeSource={RelativeSource Mode=FindAncestor, AncestorType={x:Type UserControl}}}" />
<taskQueue:PostActionUserControl DataContext="{Binding PostActionSetting}" Visibility="{c:Binding DataContext.TaskSettingVisibilities.PostAction, RelativeSource={RelativeSource Mode=FindAncestor, AncestorType={x:Type UserControl}}}" />
</hc:SimpleStackPanel>

View File

@@ -0,0 +1,76 @@
<UserControl
x:Class="MaaWpfGui.Views.UserControl.TaskQueue.SideStorySettingsUserControl"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:c="clr-namespace:CalcBinding;assembly=CalcBinding"
xmlns:controls="clr-namespace:MaaWpfGui.Styles.Controls"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:hc="https://handyorg.github.io/handycontrol"
xmlns:helper="clr-namespace:MaaWpfGui.Helper"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:s="https://github.com/canton7/Stylet"
xmlns:taskQueue_vms="clr-namespace:MaaWpfGui.ViewModels.UserControl.TaskQueue"
MaxWidth="220"
d:Background="White"
d:DataContext="{d:DesignInstance {x:Type taskQueue_vms:SideStorySettingsUserControlModel}}"
d:DesignWidth="220"
s:View.ActionTarget="{Binding}"
mc:Ignorable="d">
<StackPanel>
<!-- ="{DynamicResource HideUnavailableStage}" -->
<CheckBox
Margin="0,10"
Content="自动领取已完成任务"
IsChecked="{Binding TaskAward}" />
<CheckBox
Margin="0,10,0,6"
Content="活动复刻重打1~10关"
IsChecked="{Binding StageReopen}" />
<StackPanel
Margin="0,5,10,5"
Opacity="{c:Binding 'IsSideStoryReopenEnable ? 1 : 0.5'}"
Orientation="Horizontal">
<controls:TextBlock Margin="4,0,8,0" Text="├" />
<CheckBox Content="允许使用理智药" IsChecked="{Binding StageReopen}" />
</StackPanel>
<StackPanel
Margin="0,5,10,5"
Opacity="{c:Binding 'IsSideStoryReopenEnable ? 1 : 0.5'}"
Orientation="Horizontal">
<controls:TextBlock Margin="4,0,8,0" Text="└" />
<controls:TextBlock Text="{Binding ActivityInfo}" />
</StackPanel>
<ListBox
Margin="0,5"
HorizontalContentAlignment="Stretch"
d:ItemsSource="{d:SampleData ItemCount=3}"
IsEnabled="{c:Binding StageReopen}"
ItemsSource="{Binding Path=StageList}"
PreviewMouseWheel="{s:Action RouteMouseWheelToParent,
Target={x:Type helper:MouseWheelHelper}}"
ScrollViewer.VerticalScrollBarVisibility="Auto"
Style="{DynamicResource NoSelectedHighlightListBoxStyle}">
<ListBox.ItemsPanel>
<ItemsPanelTemplate>
<hc:FlexPanel
AlignContent="FlexStart"
AlignItems="FlexStart"
FlexDirection="Row"
FlexWrap="Wrap"
JustifyContent="FlexStart" />
</ItemsPanelTemplate>
</ListBox.ItemsPanel>
<ListBox.ItemTemplate>
<DataTemplate>
<CheckBox
Padding="6,0,4.5,0"
HorizontalAlignment="Stretch"
VerticalAlignment="Center"
HorizontalContentAlignment="Stretch"
Content="{Binding Display}"
IsChecked="{Binding Value}" />
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
</StackPanel>
</UserControl>

View File

@@ -0,0 +1,28 @@
// <copyright file="SideStorySettingsUserControl.xaml.cs" company="MaaAssistantArknights">
// Part of the MaaWpfGui project, maintained by the MaaAssistantArknights team (Maa Team)
// Copyright (C) 2021-2025 MaaAssistantArknights Contributors
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU Affero General Public License v3.0 only as published by
// the Free Software Foundation, either version 3 of the License, or
// any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY
// </copyright>
namespace MaaWpfGui.Views.UserControl.TaskQueue;
/// <summary>
/// CustomUserControl.xaml 的交互逻辑
/// </summary>
public partial class SideStorySettingsUserControl : System.Windows.Controls.UserControl
{
/// <summary>
/// Initializes a new instance of the <see cref="SideStorySettingsUserControl"/> class.
/// </summary>
public SideStorySettingsUserControl()
{
InitializeComponent();
}
}