diff --git a/docs/en-us/3.1-INTEGRATION.md b/docs/en-us/3.1-INTEGRATION.md index 1204a0d089..ee7738cdc8 100644 --- a/docs/en-us/3.1-INTEGRATION.md +++ b/docs/en-us/3.1-INTEGRATION.md @@ -105,6 +105,10 @@ Supports some of the special stages,Please refer to [autoLocalization example](. int, ... ], + "first_tags": [ // Preferred Tags, valid only if 3★ tags. Optional, by default empty + string, // When Tag is level-3, as many Tags here as possible (if any) will be selected. + ... // It's a forced selection, i.e. it ignores all "unselect 3★ Tags" settings. + ], "extra_tags_mode": int, // Select more tags, optional // 0 - default // 1 - click 3 tags anyway, even if they are in conflict diff --git a/docs/ja-jp/プロトコルドキュメント/統合ドキュメント.md b/docs/ja-jp/プロトコルドキュメント/統合ドキュメント.md index 5cfa2f744b..8134daf4b5 100644 --- a/docs/ja-jp/プロトコルドキュメント/統合ドキュメント.md +++ b/docs/ja-jp/プロトコルドキュメント/統合ドキュメント.md @@ -116,6 +116,10 @@ TaskId ASSTAPI AsstAppendTask(AsstHandle handle, const char* type, const char* p int, ... ], + "first_tags": [ // 優先タグ。タグレベルが3の場合のみ有効。 オプション、デフォルトは 空 + string, // ★3 タグの場合、可能な限り多くのタグが選択されます。 + ... // これは強制的に選択されます。つまり、「★3 タグは非選択にする」設定はすべて無視されます。 + ], "extra_tags_mode": int, // その他のタグを選択、省略可能、デフォルトは 0 // 0 - デフォルトの動作 // 1 - 競合する可能性があっても3つのTagsを選択 diff --git a/docs/ko-kr/스키마/1.통합문서.md b/docs/ko-kr/스키마/1.통합문서.md index c3b8480b7b..b1cc83848a 100644 --- a/docs/ko-kr/스키마/1.통합문서.md +++ b/docs/ko-kr/스키마/1.통합문서.md @@ -109,12 +109,14 @@ TaskId ASSTAPI AsstAppendTask(AsstHandle handle, const char* type, const char* p int, ... ], - "confirm": [ // 확인용 태그 레벨, 필수. 계산용으로만 - - 빈 배열로 설정할 수 있습니다. + "confirm": [ // 확인용 태그 레벨, 필수. 계산용으로만. 빈 배열로 설정할 수 있습니다. int, ... ], + "first_tags": [ // 기본 태그, 태그 레벨이 3인 경우에만 유효합니다. 선택 사항, 기본값은 비어 있습니다. + string, // 태그 레벨이 3이면 여기에 있는 태그(있는 경우)가 최대한 많이 선택됩니다. + ... // 또한 강제 선택이므로 '3등급 태그 선택 해제' 설정은 모두 무시됩니다. + ], "extra_tags_mode": int, "times": int, // 고용 횟수, 선택 사항, 기본값은 0입니다. 계산용으로만 0으로 설정할 수 있습니다. "set_time": bool, // 시간을 9시간으로 설정할지 여부, `times`가 0인 경우에만 사용 가능한 옵션입니다, 선택 사항, 기본값은 true입니다. diff --git a/docs/zh-tw/3.1-集成文件.md b/docs/zh-tw/3.1-集成文件.md index 3b7ef22b84..1e6a7e0409 100644 --- a/docs/zh-tw/3.1-集成文件.md +++ b/docs/zh-tw/3.1-集成文件.md @@ -112,6 +112,10 @@ AsstTaskId ASSTAPI AsstAppendTask(AsstHandle handle, const char* type, const cha int, ... ], + "first_tags": [ // 首選 Tags,僅在 Tag 等級為 3 時有效。可選,預設為空 + string, // 當 Tag 等級為 3 時,會盡可能多地選擇這裡的 Tags(如果有) + ... // 且是強制選擇,也就是會忽略所有“讓 3 星 Tags 不被選擇”的設定 + ], "extra_tags_mode": int, // 選擇更多的 Tags, 可選, 預設為 0 // 0 - 預設行為 // 1 - 選 3 個 Tags, 即使可能衝突 diff --git a/docs/协议文档/集成文档.md b/docs/协议文档/集成文档.md index 1de178fcf8..297330ae62 100644 --- a/docs/协议文档/集成文档.md +++ b/docs/协议文档/集成文档.md @@ -114,6 +114,10 @@ AsstTaskId ASSTAPI AsstAppendTask(AsstHandle handle, const char* type, const cha int, ... ], + "first_tags": [ // 首选 Tags,仅在 Tag 等级为 3 时有效。可选,默认为空 + string, // 当 Tag 等级为 3 时,会尽可能多地选择这里的 Tags(如果有) + ... // 而且是强制选择,也就是会忽略所有“让 3 星 Tag 不被选择”的设置 + ], "extra_tags_mode": int, // 选择更多的 Tags, 可选, 默认为 0 // 0 - 默认行为 // 1 - 选 3 个 Tags, 即使可能冲突 diff --git a/src/MaaCore/Task/Interface/RecruitTask.cpp b/src/MaaCore/Task/Interface/RecruitTask.cpp index 8740c3d6f7..26e919635a 100644 --- a/src/MaaCore/Task/Interface/RecruitTask.cpp +++ b/src/MaaCore/Task/Interface/RecruitTask.cpp @@ -52,6 +52,7 @@ bool asst::RecruitTask::set_params(const json::value& params) bool expedite = params.get("expedite", false); [[maybe_unused]] int expedite_times = params.get("expedite_times", 0); bool skip_robot = params.get("skip_robot", true); + std::vector first_tags = params.get("first_tags", std::vector(0)); std::unordered_map recruitment_time_map; recruitment_time_map[3] = std::clamp(params.get("recruitment_time", "3", 9 * 60), 1 * 60, 9 * 60); @@ -71,6 +72,7 @@ bool asst::RecruitTask::set_params(const json::value& params) .set_need_refresh(refresh) .set_use_expedited(expedite) .set_select_extra_tags(extra_tags_mode) + .set_first_tags(first_tags) .set_select_level(std::move(select)) .set_confirm_level(std::move(confirm)) .set_skip_robot(skip_robot) diff --git a/src/MaaCore/Task/Miscellaneous/AutoRecruitTask.cpp b/src/MaaCore/Task/Miscellaneous/AutoRecruitTask.cpp index 7880bb7123..1a7eb66831 100644 --- a/src/MaaCore/Task/Miscellaneous/AutoRecruitTask.cpp +++ b/src/MaaCore/Task/Miscellaneous/AutoRecruitTask.cpp @@ -146,6 +146,12 @@ asst::AutoRecruitTask& asst::AutoRecruitTask::set_select_extra_tags(ExtraTagsMod return *this; } +asst::AutoRecruitTask& asst::AutoRecruitTask::set_first_tags(std::vector first_tags) noexcept +{ + m_first_tags = first_tags; + return *this; +} + asst::AutoRecruitTask& asst::AutoRecruitTask::set_skip_robot(bool skip_robot) noexcept { m_skip_robot = skip_robot; @@ -361,6 +367,7 @@ asst::AutoRecruitTask::calc_task_result_type asst::AutoRecruitTask::recruit_calc bool has_special_tag = false; bool has_robot_tag = false; + bool has_preferred_tag = false; json::value info = basic_info(); info["details"]["tags"] = json::array(get_tag_names(tag_ids)); @@ -393,6 +400,21 @@ asst::AutoRecruitTask::calc_task_result_type asst::AutoRecruitTask::recruit_calc callback(AsstMsg::SubTaskExtraInfo, cb_info); } + // preferred tags + if (!m_first_tags.empty()) { + for (const RecruitConfig::TagId& tag_id : tag_ids) { + std::string tag_name = RecruitData.get_tag_name(tag_id); + for (const std::string& preferred_tag : m_first_tags) { + if (preferred_tag.empty()) continue; + // the preferred tag is the tag's substring + if (tag_name.find(preferred_tag) != std::string::npos) { + has_preferred_tag = true; + break; + } + } + } + } + std::vector result_vec = recruit_calc::get_all_combs(tag_ids); // assuming timer would be set to 09:00:00 @@ -481,8 +503,9 @@ asst::AutoRecruitTask::calc_task_result_type asst::AutoRecruitTask::recruit_calc if (need_exit()) return {}; // refresh - if (m_need_refresh && m_has_refresh && !has_special_tag && final_combination.min_level == 3 && - !(m_skip_robot && has_robot_tag)) { + if (m_need_refresh && m_has_refresh && !has_special_tag + && (final_combination.min_level == 3 && !has_preferred_tag) + && !(m_skip_robot && has_robot_tag)) { if (refresh_count > refresh_limit) [[unlikely]] { json::value cb_info = basic_info(); cb_info["what"] = "RecruitError"; @@ -536,7 +559,8 @@ asst::AutoRecruitTask::calc_task_result_type asst::AutoRecruitTask::recruit_calc if (!is_calc_only_task()) { // do not confirm, force skip - if (ranges::none_of(m_confirm_level, [&](const auto& i) { return i == final_combination.min_level; })) { + if (!(final_combination.min_level == 3 && has_preferred_tag) && + ranges::none_of(m_confirm_level, [&](const auto& i) { return i == final_combination.min_level; })) { calc_task_result_type result; result.success = true; result.force_skip = true; @@ -569,7 +593,8 @@ asst::AutoRecruitTask::calc_task_result_type asst::AutoRecruitTask::recruit_calc } // nothing to select, leave the selection empty - if (ranges::none_of(m_select_level, [&](const auto& i) { return i == final_combination.min_level; })) { + if (!(final_combination.min_level == 3 && has_preferred_tag) && + ranges::none_of(m_select_level, [&](const auto& i) { return i == final_combination.min_level; })) { calc_task_result_type result; result.success = true; result.force_skip = false; @@ -578,8 +603,7 @@ asst::AutoRecruitTask::calc_task_result_type asst::AutoRecruitTask::recruit_calc return result; } - auto final_select = - (m_select_extra_tags_mode != ExtraTagsMode::NoExtra) ? get_select_tags(result_vec) : final_combination.tags; + auto final_select = get_select_tags(result_vec, tag_ids); // select tags for (const std::string& final_tag_name : final_select) { @@ -708,13 +732,34 @@ std::vector asst::AutoRecruitTask::get_tag_names(const std::vector< return names; } -std::vector asst::AutoRecruitTask::get_select_tags(const std::vector& combinations) +std::vector asst::AutoRecruitTask::get_select_tags(const std::vector& combinations, std::vector tag_ids) { LogTraceFunction; std::unordered_set unique_tags; std::vector select; - if (m_select_extra_tags_mode == ExtraTagsMode::Extra) { + if (combinations.front().min_level == 3) { + // only run if we have certain preferred tags for level-3 tags + if (!m_first_tags.empty()) { + for (const RecruitConfig::TagId& tag_id : tag_ids) { + std::string tag_name = RecruitData.get_tag_name(tag_id); + for (const std::string& preferred_tag : m_first_tags) { + if (preferred_tag.empty()) continue; + // the preferred tag is the tag's substring + if (tag_name.find(preferred_tag) != std::string::npos) { + select.emplace_back(tag_name); + continue; + } + } + if (select.size() == 3) return select; + } + } + return select; + } + else if (m_select_extra_tags_mode == ExtraTagsMode::NoExtra) { + return combinations.front().tags; + } + else if (m_select_extra_tags_mode == ExtraTagsMode::Extra) { while (select.size() < 3) { for (const asst::RecruitCombs& comb : combinations) for (const std::string& tag : comb.tags) { diff --git a/src/MaaCore/Task/Miscellaneous/AutoRecruitTask.h b/src/MaaCore/Task/Miscellaneous/AutoRecruitTask.h index 867e2ce31b..301dcc2369 100644 --- a/src/MaaCore/Task/Miscellaneous/AutoRecruitTask.h +++ b/src/MaaCore/Task/Miscellaneous/AutoRecruitTask.h @@ -24,6 +24,7 @@ namespace asst AutoRecruitTask& set_max_times(int max_times) noexcept; AutoRecruitTask& set_use_expedited(bool use_or_not) noexcept; AutoRecruitTask& set_select_extra_tags(ExtraTagsMode select_extra_tags_mode) noexcept; + AutoRecruitTask& set_first_tags(std::vector first_tags) noexcept; AutoRecruitTask& set_skip_robot(bool skip_robot) noexcept; AutoRecruitTask& set_set_time(bool set_time) noexcept; AutoRecruitTask& set_force_refresh(bool force_refrest) noexcept; @@ -49,7 +50,7 @@ namespace asst bool hire_all(); bool initialize_dirty_slot_info(const cv::Mat&); std::vector get_tag_names(const std::vector& ids) const; - std::vector get_select_tags(const std::vector& combinations); + std::vector get_select_tags(const std::vector& combinations, std::vector tag_ids); static std::vector start_recruit_analyze(const cv::Mat& image); template @@ -77,6 +78,7 @@ namespace asst bool m_need_refresh = false; bool m_use_expedited = false; ExtraTagsMode m_select_extra_tags_mode = ExtraTagsMode::NoExtra; + std::vector m_first_tags; int m_max_times = 0; bool m_has_permit = true; bool m_has_refresh = true; diff --git a/src/MaaWpfGui/Constants/ConfigurationKeys.cs b/src/MaaWpfGui/Constants/ConfigurationKeys.cs index 0abc1470c3..58a75126c4 100644 --- a/src/MaaWpfGui/Constants/ConfigurationKeys.cs +++ b/src/MaaWpfGui/Constants/ConfigurationKeys.cs @@ -131,6 +131,7 @@ namespace MaaWpfGui.Constants public const string CreditFightSelectFormation = "Visit.CreditFightSelectFormation"; public const string RecruitMaxTimes = "AutoRecruit.MaxTimes"; + public const string AutoRecruitFirstList = "AutoRecruit.AutoRecruitFirstList"; public const string RefreshLevel3 = "AutoRecruit.RefreshLevel3"; public const string ForceRefresh = "AutoRecruit.ForceRefresh"; public const string SelectExtraTags = "AutoRecruit.SelectExtraTags"; diff --git a/src/MaaWpfGui/Main/AsstProxy.cs b/src/MaaWpfGui/Main/AsstProxy.cs index 1217c35a02..e087b664f7 100644 --- a/src/MaaWpfGui/Main/AsstProxy.cs +++ b/src/MaaWpfGui/Main/AsstProxy.cs @@ -1893,6 +1893,7 @@ namespace MaaWpfGui.Main /// 公开招募。 /// /// 加急次数,仅在 时有效。 + /// 首选 Tags,仅在 Tag 等级为 3 时有效。 /// 会去点击标签的 Tag 等级。 /// 会去点击确认的 Tag 等级。若仅公招计算,可设置为空数组。 /// 是否刷新三星 Tags。 @@ -1919,7 +1920,7 @@ namespace MaaWpfGui.Main /// 三星Tag是否使用短时间(7:40) /// 三星Tag是否使用短时间(1:00) /// 是否成功。 - public bool AsstAppendRecruit(int maxTimes, int[] selectLevel, int[] confirmLevel, bool needRefresh, bool needForceRefresh, bool useExpedited, + public bool AsstAppendRecruit(int maxTimes, string[] firstTags, int[] selectLevel, int[] confirmLevel, bool needRefresh, bool needForceRefresh, bool useExpedited, int selectExtraTagsMode, bool skipRobot, bool isLevel3UseShortTime, bool isLevel3UseShortTime2 = false) { var taskParams = new JObject @@ -1934,6 +1935,7 @@ namespace MaaWpfGui.Main ["extra_tags_mode"] = selectExtraTagsMode, ["expedite_times"] = maxTimes, ["skip_robot"] = skipRobot, + ["first_tags"] = new JArray(firstTags), }; if (isLevel3UseShortTime) { diff --git a/src/MaaWpfGui/Res/Localizations/en-us.xaml b/src/MaaWpfGui/Res/Localizations/en-us.xaml index 40bc6745c8..82948f7ac0 100644 --- a/src/MaaWpfGui/Res/Localizations/en-us.xaml +++ b/src/MaaWpfGui/Res/Localizations/en-us.xaml @@ -673,8 +673,10 @@ The video aspect ratio needs to be 16:9 without interference factors such as bla No recruitment permit, returned Strategies for Additional Tags Additional Tags are not selected by default - If higher ★ tags appear, always select 3★ tags + If higher ★ tags appear, always select 3 tags Pick as many high-star Tags as possible + Preference for 3★ Tags (split by semicolon) + Substring is sufficient, will select as many Tag preferences as possible Insufficient operators Stage recognition error Use formation diff --git a/src/MaaWpfGui/Res/Localizations/ja-jp.xaml b/src/MaaWpfGui/Res/Localizations/ja-jp.xaml index aff68668c4..ba682df756 100644 --- a/src/MaaWpfGui/Res/Localizations/ja-jp.xaml +++ b/src/MaaWpfGui/Res/Localizations/ja-jp.xaml @@ -676,6 +676,8 @@ デフォルトでは、追加のタグを選択しない タグを選択すると、常に 3 つのタグが選択されます 可能な限り多くのタグを選択し、高い星のタグのみを選択する + 優先タグ(セミコロンで区切) + サブストリングで十分です、できるだけ多くのタグの傾向を選択します 利用可能なオペレーターが不足しています ステージ認識エラー 使用編成 diff --git a/src/MaaWpfGui/Res/Localizations/ko-kr.xaml b/src/MaaWpfGui/Res/Localizations/ko-kr.xaml index 51324d0543..3fc2f6b6cb 100644 --- a/src/MaaWpfGui/Res/Localizations/ko-kr.xaml +++ b/src/MaaWpfGui/Res/Localizations/ko-kr.xaml @@ -676,6 +676,8 @@ OF-1을 해금하지 않았다면 선택하지 말아 주세요. 기본값: 추가 태그 없음 항상 3개의 태그를 선택 가능한 한 많은 태그를 선택하고 높은 등급의 태그만 선택 + 태그 경향을 세미콜론으로 구분한 3단계 태그로 표시합니다 (세미콜론으로 구분) + 하위 문자열이면 충분하며 가능한 한 많은 태그 기본 설정을 선택합니다 오퍼레이터 부족 스테이지 인식 오류 편성 사용 diff --git a/src/MaaWpfGui/Res/Localizations/zh-cn.xaml b/src/MaaWpfGui/Res/Localizations/zh-cn.xaml index 55d2370cef..2fbefb9917 100644 --- a/src/MaaWpfGui/Res/Localizations/zh-cn.xaml +++ b/src/MaaWpfGui/Res/Localizations/zh-cn.xaml @@ -675,6 +675,8 @@ 默认不选择额外 Tag 选择高星时总是选择三个 Tag 尽可能多地选且只选高星 Tag + 3 星 Tag 时的 Tag 倾向,分号分隔 + 子串即可,会尽可能多的选择倾向的 Tag 可用干员不足 关卡识别错误 使用编队 diff --git a/src/MaaWpfGui/Res/Localizations/zh-tw.xaml b/src/MaaWpfGui/Res/Localizations/zh-tw.xaml index 8febdbd73f..c0794e6abc 100644 --- a/src/MaaWpfGui/Res/Localizations/zh-tw.xaml +++ b/src/MaaWpfGui/Res/Localizations/zh-tw.xaml @@ -674,6 +674,8 @@ 默認不選擇額外的 Tags 選擇高星時總是選擇三個 Tag 盡可能多地選且只選高星 Tags + 3 星 Tags 時的 Tags 傾向,分號分隔 + 子串即可,會盡可能多的選擇傾向的 Tags 關卡辨識錯誤 使用編隊 當前 diff --git a/src/MaaWpfGui/ViewModels/UI/SettingsViewModel.cs b/src/MaaWpfGui/ViewModels/UI/SettingsViewModel.cs index f62a64cb53..622af37a63 100644 --- a/src/MaaWpfGui/ViewModels/UI/SettingsViewModel.cs +++ b/src/MaaWpfGui/ViewModels/UI/SettingsViewModel.cs @@ -2731,6 +2731,21 @@ namespace MaaWpfGui.ViewModels.UI } /* 自动公招设置 */ + private string _autoRecruitFirstList = ConfigurationHelper.GetValue(ConfigurationKeys.AutoRecruitFirstList, string.Empty); + + /// + /// Gets or sets the priority tag list of level-3 tags. + /// + public string AutoRecruitFirstList + { + get => _autoRecruitFirstList; + set + { + SetAndNotify(ref _autoRecruitFirstList, value); + ConfigurationHelper.SetValue(ConfigurationKeys.AutoRecruitFirstList, value); + } + } + private string _recruitMaxTimes = ConfigurationHelper.GetValue(ConfigurationKeys.RecruitMaxTimes, "4"); /// diff --git a/src/MaaWpfGui/ViewModels/UI/TaskQueueViewModel.cs b/src/MaaWpfGui/ViewModels/UI/TaskQueueViewModel.cs index 4f671ed481..5780c330dd 100644 --- a/src/MaaWpfGui/ViewModels/UI/TaskQueueViewModel.cs +++ b/src/MaaWpfGui/ViewModels/UI/TaskQueueViewModel.cs @@ -1362,6 +1362,9 @@ namespace MaaWpfGui.ViewModels.UI maxTimes = 0; } + var firstList = Instances.SettingsViewModel.AutoRecruitFirstList.Split(';', ';') + .Select(s => s.Trim()); + var reqList = new List(); var cfmList = new List(); @@ -1386,7 +1389,7 @@ namespace MaaWpfGui.ViewModels.UI int.TryParse(Instances.SettingsViewModel.SelectExtraTags, out var selectExtra); return Instances.AsstProxy.AsstAppendRecruit( - maxTimes, reqList.ToArray(), cfmList.ToArray(), Instances.SettingsViewModel.RefreshLevel3, Instances.SettingsViewModel.ForceRefresh, Instances.SettingsViewModel.UseExpedited, + maxTimes, firstList.ToArray(), reqList.ToArray(), cfmList.ToArray(), Instances.SettingsViewModel.RefreshLevel3, Instances.SettingsViewModel.ForceRefresh, Instances.SettingsViewModel.UseExpedited, selectExtra, Instances.SettingsViewModel.NotChooseLevel1, Instances.SettingsViewModel.IsLevel3UseShortTime, Instances.SettingsViewModel.IsLevel3UseShortTime2); } diff --git a/src/MaaWpfGui/Views/UserControl/AutoRecruitSettingsUserControl.xaml b/src/MaaWpfGui/Views/UserControl/AutoRecruitSettingsUserControl.xaml index 0fe154cef4..538bdde165 100644 --- a/src/MaaWpfGui/Views/UserControl/AutoRecruitSettingsUserControl.xaml +++ b/src/MaaWpfGui/Views/UserControl/AutoRecruitSettingsUserControl.xaml @@ -41,6 +41,12 @@ SelectedValue="{Binding SelectExtraTags}" SelectedValuePath="Value" Style="{StaticResource ComboBoxExtend}" /> +