feat: 支持编队添加干员时选择模组 (#12811)

* 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>
This commit is contained in:
travellerse
2025-07-11 23:56:37 +08:00
committed by GitHub
parent 0478306149
commit 4e3c75b17b
16 changed files with 106 additions and 1 deletions

View File

@@ -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",

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 388 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 432 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 422 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 476 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 413 B

View File

@@ -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

View File

@@ -88,6 +88,15 @@ asst::battle::copilot::OperUsageGroups asst::CopilotConfig::parse_groups(const j
oper.skill_usage = static_cast<battle::SkillUsage>(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<battle::SkillUsage>(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) });

View File

@@ -440,6 +440,8 @@ bool asst::BattleFormationTask::select_opers_in_cur_page(std::vector<OperGroup>&
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<OperGroup>&
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<OperGroup>&
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);

View File

@@ -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)

View File

@@ -756,6 +756,8 @@ Right-click to clear inactive tasks</system:String>
<system:String x:Key="Start">Start</system:String>
<system:String x:Key="VideoLink">Video Link</system:String>
<system:String x:Key="CopilotSkill">Skill</system:String>
<system:String x:Key="CopilotModule">Module</system:String>
<system:String x:Key="CopilotWithoutModule">Without Module</system:String>
<system:String x:Key="TotalOperatorsCount">Total {0} Operator(s)</system:String>
<system:String x:Key="DirectiveECTerm">Directive EC unit:&#160;</system:String>
<system:String x:Key="OtherOperators">Other operators:&#160;</system:String>

View File

@@ -760,6 +760,8 @@ C:\\leidian\\LDPlayer9
<system:String x:Key="Start">開始</system:String>
<system:String x:Key="VideoLink">映像へのハイパーリンク</system:String>
<system:String x:Key="CopilotSkill">スキル</system:String>
<system:String x:Key="CopilotModule">モジュール</system:String>
<system:String x:Key="CopilotWithoutModule">モジュールなし</system:String>
<system:String x:Key="TotalOperatorsCount">合計 {0} 名のオペレーター</system:String>
<system:String x:Key="DirectiveECTerm">拡張式戦術ユニット:</system:String>
<system:String x:Key="OtherOperators">その他のオペレーター:</system:String>

View File

@@ -759,6 +759,8 @@ C:\\leidian\\LDPlayer9
<system:String x:Key="Start">시작</system:String>
<system:String x:Key="VideoLink">영상 링크</system:String>
<system:String x:Key="CopilotSkill">스킬</system:String>
<system:String x:Key="CopilotModule">모듈</system:String>
<system:String x:Key="CopilotWithoutModule">모듈 없이 시작</system:String>
<system:String x:Key="TotalOperatorsCount">총 {0}명의 오퍼레이터</system:String>
<system:String x:Key="DirectiveECTerm">에너지 기어:</system:String>
<system:String x:Key="OtherOperators">기타 오퍼레이터:</system:String>

View File

@@ -760,6 +760,8 @@ C:\\leidian\\LDPlayer9。\n
<system:String x:Key="Start">开始</system:String>
<system:String x:Key="VideoLink">视频链接</system:String>
<system:String x:Key="CopilotSkill">技能</system:String>
<system:String x:Key="CopilotModule">模组</system:String>
<system:String x:Key="CopilotWithoutModule">不使用模组</system:String>
<system:String x:Key="TotalOperatorsCount">共 {0} 名干员</system:String>
<system:String x:Key="DirectiveECTerm">导能原件:</system:String>
<system:String x:Key="OtherOperators">编队工具人:</system:String>

View File

@@ -757,6 +757,8 @@ C:\\leidian\\LDPlayer9。\n
<system:String x:Key="Start">開始</system:String>
<system:String x:Key="VideoLink">影片連結</system:String>
<system:String x:Key="CopilotSkill">技能</system:String>
<system:String x:Key="CopilotModule">模組</system:String>
<system:String x:Key="CopilotWithoutModule">不使用模組</system:String>
<system:String x:Key="TotalOperatorsCount">共 {0} 名幹員</system:String>
<system:String x:Key="DirectiveECTerm">導能組件:</system:String>
<system:String x:Key="OtherOperators">其他幹員:</system:String>