From 4e3c75b17bbc9b5164f88d3de79ea3b79e8973b0 Mon Sep 17 00:00:00 2001 From: travellerse <58685479+travellerse@users.noreply.github.com> Date: Fri, 11 Jul 2025 23:56:37 +0800 Subject: [PATCH] =?UTF-8?q?feat:=20=E6=94=AF=E6=8C=81=E7=BC=96=E9=98=9F?= =?UTF-8?q?=E6=B7=BB=E5=8A=A0=E5=B9=B2=E5=91=98=E6=97=B6=E9=80=89=E6=8B=A9?= =?UTF-8?q?=E6=A8=A1=E7=BB=84=20(#12811)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * feat: 支持编队添加干员时选择模组 * chore: Auto update by pre-commit hooks [skip changelog] * feat: 更新模组编号和本地化字符串以支持新模组 * fix: 统一使用激活时的模组字符图像,将识别阈值下降至0.8以识别未激活时的模组字符 * perf: 省略不必要的参数 * perf: 修改模组默认值为`-1: 不修改` * fix: 修复不使用模组时的点击区域, 使用模板图替换 * fix: roi * chore: Auto update by pre-commit hooks [skip changelog] * perf: 优化部分文本 * chore: Auto update by pre-commit hooks [skip changelog] * fix: 选择模组失败时反选干员 * fix: 选择模组失败时继续检查同组其他干员 * perf: 过个Rgb Co-authored-by: status102<102887808+status102@users.noreply.github.com> * chore: 不过灰度 * fix: 添加模板图片以匹配y模组字母的两种形式 --------- Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com> Co-authored-by: status102 <102887808+status102@users.noreply.github.com> Co-authored-by: uye <99072975+ABA2396@users.noreply.github.com> --- resource/tasks/tasks.json | 31 ++++++++++++++++++ .../template/BattleQuickFormationModule-0.png | Bin 0 -> 1290 bytes .../template/BattleQuickFormationModule-1.png | Bin 0 -> 388 bytes .../BattleQuickFormationModule-2-A.png | Bin 0 -> 432 bytes .../BattleQuickFormationModule-2-B.png | Bin 0 -> 422 bytes .../template/BattleQuickFormationModule-3.png | Bin 0 -> 476 bytes .../template/BattleQuickFormationModule-4.png | Bin 0 -> 413 bytes src/MaaCore/Common/AsstBattleDef.h | 11 +++++++ .../Config/Miscellaneous/CopilotConfig.cpp | 19 +++++++++++ .../Miscellaneous/BattleFormationTask.cpp | 16 +++++++++ src/MaaWpfGui/Models/Copilot/CopilotModel.cs | 20 ++++++++++- src/MaaWpfGui/Res/Localizations/en-us.xaml | 2 ++ src/MaaWpfGui/Res/Localizations/ja-jp.xaml | 2 ++ src/MaaWpfGui/Res/Localizations/ko-kr.xaml | 2 ++ src/MaaWpfGui/Res/Localizations/zh-cn.xaml | 2 ++ src/MaaWpfGui/Res/Localizations/zh-tw.xaml | 2 ++ 16 files changed, 106 insertions(+), 1 deletion(-) create mode 100644 resource/template/BattleQuickFormationModule-0.png create mode 100644 resource/template/BattleQuickFormationModule-1.png create mode 100644 resource/template/BattleQuickFormationModule-2-A.png create mode 100644 resource/template/BattleQuickFormationModule-2-B.png create mode 100644 resource/template/BattleQuickFormationModule-3.png create mode 100644 resource/template/BattleQuickFormationModule-4.png diff --git a/resource/tasks/tasks.json b/resource/tasks/tasks.json index 3aa6e0ff96..7e3d2cb7b3 100644 --- a/resource/tasks/tasks.json +++ b/resource/tasks/tasks.json @@ -3629,6 +3629,37 @@ "action": "ClickRect", "specificRect": [15, 650, 80, 30] }, + "BattleQuickFormationModulePage": { + "algorithm": "OcrDetect", + "action": "ClickSelf", + "text": ["分支"], + "roi": [185, 320, 180, 40], + "postDelay": 500 + }, + "BattleQuickFormationModule-Item": { + "template": "empty.png", + "action": "ClickSelf", + "roi": [5, 370, 80, 350], + "postDelay": 300 + }, + "BattleQuickFormationModule-0": { + "baseTask": "BattleQuickFormationModule-Item" + }, + "BattleQuickFormationModule-1": { + "baseTask": "BattleQuickFormationModule-Item" + }, + "BattleQuickFormationModule-2": { + "doc": "y模组匹配,由于y模组的字母有两种形式,所以需要两个模板", + "baseTask": "BattleQuickFormationModule-Item", + "template": ["BattleQuickFormationModule-2-A.png", "BattleQuickFormationModule-2-B.png"], + "templThreshold": [0.92, 0.92] + }, + "BattleQuickFormationModule-3": { + "baseTask": "BattleQuickFormationModule-Item" + }, + "BattleQuickFormationModule-4": { + "baseTask": "BattleQuickFormationModule-Item" + }, "BattleQuickFormationSkill-SwipeToTheDown": { "algorithm": "JustReturn", "action": "Swipe", diff --git a/resource/template/BattleQuickFormationModule-0.png b/resource/template/BattleQuickFormationModule-0.png new file mode 100644 index 0000000000000000000000000000000000000000..f061637bb02de99846d86915dac813670b526d11 GIT binary patch literal 1290 zcmV+l1@-!gP)Px#32;bRa{vGi!vFvd!vV){sAK>D0u4}1R7JbHyX@@j>+9?4>gws~>FDU_=jZ3< z=H}()<>ch#(^($dk<(a_M)&(F`!&d$xv&CJZq%gf8k%F4;f$;ima$H&LU#>U0P#l*zK z!^6YE!otD9!N9=4zrVk}zP`P^y}Z1r>3T+rKP2$q@<&xqoSgsp`oFmprD_h zpPrtcot>SWoSd7Ro0^)Mn3$NCmzR{3l#`Q_l9G~XJ=++W@Tk%WMpJxV`E}s zVqsxnU|?WhUteBcUR_;XTwGjRTU%OMT3A?ES65e7R#sJ2RZ~+_Qc_Y;QBhD(P)|=! zPEJluO-)NnOG!ydNJvOWM@L3RMny$MLqkJCLP9q;H#RmlH8nLfG&D0aGcqzVF)=YP zFfc7GEh;K1A0HnY8X6fH85kHC7Z(>678Vl|69fbV00014RLWfd00NdtL_t(|+O<<{ zOB7KQe(s$acilF1tz5Iz(%IHsLt4c})Gac|mmn-Fgo=phTc7&kZ;0?8^aCpBO)3%s z$rSQKEohlWTH*TAX1cMuyQ9v%IXi=IiyI^K+IW2`G@fcuZ2fr1hW0#hK2b4FnfoUd+9VV=g)_#)fWKmqgKcEZATc@dH}R!+^N zWguN%W>_=@g0{AJ7PrK8i*Y@4@T4@-&rHwC#J@mxRxh&I*Rr}E6Of`TZH{vSF@DlU}|2z0OP za+TV}gKk$L-QzBE?I!y?9@$oy0SLt+V39Kcd!E6{s15ik8~oNlV|De3<{WS9IZr`b zeO)ju)@64Nd>emTG5_$vV@u^= zf22!swCsoA6k+kL)KJ)R4VDm(#A4wki6<5oXCqQVQQ~4Kx-i!lQerEM?B|yz2>|Tn zFLH~J`iGL$;&3R2ky9KGL4(qhT>=1wc=xp`m1U{DcH>eaWLzIUbAd^6z8USl!IIw;x%m4&;5l{r+PRAhFE zDblhaQjq}B*GEN?kIv3JAKefnNfHUge5|?Sbkoc%p!CkPII6s!nhAef>-nNlZ+%|l z2*5^1GDLTHaxOgL7ml>Ix1Y6%h`y?j_*gIzoJYK;?1MbW)lVqmzx&5rp$WC*O$^K3 zlYhpCRbXi4d#?znAn@sPg0%zP)~pQx+b}7A0Sy#C8e*Fa1poj507*qoM6N<$g6fBW As{jB1 literal 0 HcmV?d00001 diff --git a/resource/template/BattleQuickFormationModule-1.png b/resource/template/BattleQuickFormationModule-1.png new file mode 100644 index 0000000000000000000000000000000000000000..133698dc78af621fbf5ff18bb6ccf76aecf9b67d GIT binary patch literal 388 zcmV-~0ek+5P)qBxF|BuUdW%d$Mr zKkF1lQI=&@RbO?Gw`hu@9*>78ij7tj1;a3!rd#y!cpQyJv)RmX9MG=oE|<&UaJbv; zTC}EVEX($Kz3cVr`~LlY?{>Qk!|1x+-nVI*`~4p3;W$1XkGI>cVHnS*vg-`oB>eWO{dc|O+`^8U&yi?hT&u~ znayTM77CBYW4T;{g5x-FjN@1kgnqyOd_G^VSM~<*ABEh~@pue^;C8zKqiGrxaJSom z&(UavJ}H~idcB4_p65a2e!sU`t?hP;w?E1XpRHCa&-1{ZuIrHTd_J#MDL>?BHk*gT z0o;Rc-}fOJ1WWzFq!F9V25REEZWKlP{T>=z=?_hkgfIZ#m&*mD+U<6p02^Jk1U3{! zu`CO|2XCEDhrPur6)+6rd_G^V*TrISI-STbaHeTC8jbpd;^ZRp;V~`LW!E}iYFs_K aKC^#>D*;tl;Q7J;0000pVec3>5w_p& z;Zss!GMn=;#MN#JS`D8LN z41=x~uK_F;3;2OU)*g(5~MNms=-VqlVC6y zjYhNCY$A~WYqeV8aJXD9a|mDmK{A<)L?ZZOoM*LKrPFDb%LRr{cx_BxG#J0%Unmst zo=Y1H1|kB0uWXG>o;Cc==kryoRc;JzHXDFcD#aZbqd@a|y^ThLmj|%jZUKtLqPaOt zo-_bVz)oH@%vmfJ060AtZJ0c2Fj!G8m%|^^)M_;VoO`$1T^o7OVDkAqhIG4KOdE|x z@VH2))7j~C*6TIzDN>-}l-R7>?e=&)_+2Oz>h*f@csvjY)a!Ngyve;rvs^AQq1kM< z+wJ*$ZdulFIPCZP)9KVaa$;%5@H}SM=C%?bxzh}zK>&=#FxhLjb2y4~uFW4WJp%b8 S-c{rP00004%P)SIo|QyF1@E$?$2KavaCMfe^wa4Pb@@abxs- zkK>pjARoTIBMgFrc^5^|;c(dR_hA@9$teFR(BB-#Da*2|DoB_sT7f{*wE29#SS(ak z?YfQ@A1UDIx~^^8kH_Qre1bv{1grwxpss6KmY2)r<#M^*ZmZQw5CkCcE&Bnx_dM@- zJZ?6d^?H3eouITVi*`XQHBF=II^@^ubvBz#r&G|GOeQc%+qQ#eGIXBjps?L;&*wAl z0?BT-gORc<`!IuPny@CKC_-=C3=&C_fHVwaFv2HEf(vjAQBf3x5WPaL*9#Kg_c8M` zC=^8j@qWK^U%|(5j5{#^lG$9Gqy7zg3+Tx3Wa$5U_R-QWd;b0iT}G8700000NkvXX Hu0mjf1iP}( literal 0 HcmV?d00001 diff --git a/src/MaaCore/Common/AsstBattleDef.h b/src/MaaCore/Common/AsstBattleDef.h index 9cf878ffcf..4a80d861c7 100644 --- a/src/MaaCore/Common/AsstBattleDef.h +++ b/src/MaaCore/Common/AsstBattleDef.h @@ -23,12 +23,23 @@ enum class SkillUsage // 技能用法 TimesUsed // 已经使用了 X 次 }; +// 干员练度需求 +struct OperatorRequirements +{ + // int elite = -1; // 精英化等级 + // int level = -1; // 干员等级 + // int skill_level = -1; // 技能等级 + int module = -1; // 模组编号 -1: 不切换模组 / 无要求, 0: 不使用模组, 1: 模组Χ, 2: 模组Y, 3: 模组α, 4: 模组Δ + // int potentiality = -1; // 潜能要求 +}; + struct OperUsage // 干员用法 { std::string name; int skill = 0; // 技能序号,取值范围 [0, 3],0时使用默认技能 或 上次编队时使用的技能 SkillUsage skill_usage = SkillUsage::NotUse; int skill_times = 1; // 使用技能的次数,默认为 1,兼容曾经的作业 + asst::battle::OperatorRequirements requirements; // 练度需求 }; enum class DeployDirection diff --git a/src/MaaCore/Config/Miscellaneous/CopilotConfig.cpp b/src/MaaCore/Config/Miscellaneous/CopilotConfig.cpp index 74f74e0c92..7c8f52e501 100644 --- a/src/MaaCore/Config/Miscellaneous/CopilotConfig.cpp +++ b/src/MaaCore/Config/Miscellaneous/CopilotConfig.cpp @@ -88,6 +88,15 @@ asst::battle::copilot::OperUsageGroups asst::CopilotConfig::parse_groups(const j oper.skill_usage = static_cast(oper_info.get("skill_usage", 0)); oper.skill_times = oper_info.get("skill_times", 1); // 使用技能的次数,默认为 1,兼容曾经的作业 + // 解析练度需求 + if (auto req_opt = oper_info.find("requirements")) { + // oper.requirements.elite = req_opt->get("elite", 0); + // oper.requirements.level = req_opt->get("level", 0); + // oper.requirements.skill_level = req_opt->get("skill_level", 0); + oper.requirements.module = req_opt->get("module", -1); + // oper.requirements.potentiality = req_opt->get("potentiality", 0); + } + // 单个干员的,干员名直接作为组名 std::string group_name = oper.name; groups.emplace_back(OperUsageGroup { std::move(group_name), std::vector { std::move(oper) } }); @@ -104,6 +113,16 @@ asst::battle::copilot::OperUsageGroups asst::CopilotConfig::parse_groups(const j oper.skill = oper_info.get("skill", 1); oper.skill_usage = static_cast(oper_info.get("skill_usage", 0)); oper.skill_times = oper_info.get("skill_times", 1); // 使用技能的次数,默认为 1,兼容曾经的作业 + + // 解析练度需求 + if (auto req_opt = oper_info.find("requirements")) { + // oper.requirements.elite = req_opt->get("elite", 0); + // oper.requirements.level = req_opt->get("level", 0); + // oper.requirements.skill_level = req_opt->get("skill_level", 0); + oper.requirements.module = req_opt->get("module", -1); + // oper.requirements.potentiality = req_opt->get("potentiality", 0); + } + oper_vec.emplace_back(std::move(oper)); } groups.emplace_back(OperUsageGroup { std::move(group_name), std::move(oper_vec) }); diff --git a/src/MaaCore/Task/Miscellaneous/BattleFormationTask.cpp b/src/MaaCore/Task/Miscellaneous/BattleFormationTask.cpp index e084adcd3f..b38ed42f5b 100644 --- a/src/MaaCore/Task/Miscellaneous/BattleFormationTask.cpp +++ b/src/MaaCore/Task/Miscellaneous/BattleFormationTask.cpp @@ -440,6 +440,8 @@ bool asst::BattleFormationTask::select_opers_in_cur_page(std::vector& int delay = Task.get("BattleQuickFormationOCR")->post_delay; int skill = 0; + int module = -1; + bool ret = true; for (const auto& res : opers_result | views::filter([](const QuickFormationOper& oper) { return !oper.is_selected; })) { const std::string& name = res.text; @@ -450,6 +452,7 @@ bool asst::BattleFormationTask::select_opers_in_cur_page(std::vector& if (oper.name == name) { found = true; skill = oper.skill; + module = oper.requirements.module; m_opers_in_formation->emplace(name, iter->first); ++m_size_of_operators_in_formation; @@ -474,6 +477,19 @@ bool asst::BattleFormationTask::select_opers_in_cur_page(std::vector& ctrler()->click(SkillRectArray.at(skill - 1ULL)); sleep(delay); } + if (module >= 0 && module <= 4) { + ret = ProcessTask(*this, { "BattleQuickFormationModulePage" }).run(); + ret = ret && ProcessTask(*this, { "BattleQuickFormationModule-" + std::to_string(module) }).run(); + if (!ret) { + LogError << __FUNCTION__ << "| Module " << std::to_string(module) + << "not found, please check the module number"; + ctrler()->click(res.flag_rect); // 选择模组失败时反选干员 + sleep(delay); + // 继续检查同组其他干员 + continue; + } + sleep(delay); + } auto group_name = iter->first; groups.erase(iter); diff --git a/src/MaaWpfGui/Models/Copilot/CopilotModel.cs b/src/MaaWpfGui/Models/Copilot/CopilotModel.cs index 7a960bcb11..3f24c981ec 100644 --- a/src/MaaWpfGui/Models/Copilot/CopilotModel.cs +++ b/src/MaaWpfGui/Models/Copilot/CopilotModel.cs @@ -73,7 +73,25 @@ public class CopilotModel : CopilotBase { count++; var localizedName = DataHelper.GetLocalizedCharacterName(oper.Name); - output.Add(($"{localizedName}, {LocalizationHelper.GetString("CopilotSkill")} {oper.Skill}", UiLogColor.Message)); + var log = $"{localizedName} {LocalizationHelper.GetString("CopilotSkill")} {oper.Skill}"; + if (oper.Requirements is not null) + { + if (oper.Requirements.Module >= 0) + { + // 模组编号 -1: 不切换模组 / 无要求, 0: 不使用模组, 1: 模组Χ, 2: 模组Y, 3: 模组α, 4: 模组Δ + log += oper.Requirements.Module switch + { + 0 => $" {LocalizationHelper.GetString("CopilotWithoutModule")}", + 1 => $" {LocalizationHelper.GetString("CopilotModule")} Χ", + 2 => $" {LocalizationHelper.GetString("CopilotModule")} Y", + 3 => $" {LocalizationHelper.GetString("CopilotModule")} α", + 4 => $" {LocalizationHelper.GetString("CopilotModule")} Δ", + _ => string.Empty, + }; + } + } + + output.Add((log, UiLogColor.Message)); } foreach (var group in Groups) diff --git a/src/MaaWpfGui/Res/Localizations/en-us.xaml b/src/MaaWpfGui/Res/Localizations/en-us.xaml index d87da6f49f..62b9b1193c 100644 --- a/src/MaaWpfGui/Res/Localizations/en-us.xaml +++ b/src/MaaWpfGui/Res/Localizations/en-us.xaml @@ -756,6 +756,8 @@ Right-click to clear inactive tasks Start Video Link Skill + Module + Without Module Total {0} Operator(s) Directive EC unit:  Other operators:  diff --git a/src/MaaWpfGui/Res/Localizations/ja-jp.xaml b/src/MaaWpfGui/Res/Localizations/ja-jp.xaml index d611a0ba55..4cb323b10a 100644 --- a/src/MaaWpfGui/Res/Localizations/ja-jp.xaml +++ b/src/MaaWpfGui/Res/Localizations/ja-jp.xaml @@ -760,6 +760,8 @@ C:\\leidian\\LDPlayer9 開始 映像へのハイパーリンク スキル + モジュール + モジュールなし 合計 {0} 名のオペレーター 拡張式戦術ユニット: その他のオペレーター: diff --git a/src/MaaWpfGui/Res/Localizations/ko-kr.xaml b/src/MaaWpfGui/Res/Localizations/ko-kr.xaml index 73b16800db..e223d4563a 100644 --- a/src/MaaWpfGui/Res/Localizations/ko-kr.xaml +++ b/src/MaaWpfGui/Res/Localizations/ko-kr.xaml @@ -759,6 +759,8 @@ C:\\leidian\\LDPlayer9 시작 영상 링크 스킬 + 모듈 + 모듈 없이 시작 총 {0}명의 오퍼레이터 에너지 기어: 기타 오퍼레이터: diff --git a/src/MaaWpfGui/Res/Localizations/zh-cn.xaml b/src/MaaWpfGui/Res/Localizations/zh-cn.xaml index 7b639e27f4..3a89d1f1b6 100644 --- a/src/MaaWpfGui/Res/Localizations/zh-cn.xaml +++ b/src/MaaWpfGui/Res/Localizations/zh-cn.xaml @@ -760,6 +760,8 @@ C:\\leidian\\LDPlayer9。\n 开始 视频链接 技能 + 模组 + 不使用模组 共 {0} 名干员 导能原件: 编队工具人: diff --git a/src/MaaWpfGui/Res/Localizations/zh-tw.xaml b/src/MaaWpfGui/Res/Localizations/zh-tw.xaml index 2eaca1d661..deed6a9f98 100644 --- a/src/MaaWpfGui/Res/Localizations/zh-tw.xaml +++ b/src/MaaWpfGui/Res/Localizations/zh-tw.xaml @@ -757,6 +757,8 @@ C:\\leidian\\LDPlayer9。\n 開始 影片連結 技能 + 模組 + 不使用模組 共 {0} 名幹員 導能組件: 其他幹員: