2026-03-27 10:27:04 +08:00
|
|
|
|
package rules;
|
|
|
|
|
|
|
2026-03-27 11:35:17 +08:00
|
|
|
|
import com.solution.rule.domain.simplerulepojo.fact.FactTask;
|
|
|
|
|
|
import com.solution.rule.domain.simplerulepojo.Task;
|
|
|
|
|
|
import com.solution.rule.domain.simplerulepojo.Weapon;
|
2026-03-27 16:56:07 +08:00
|
|
|
|
import com.solution.rule.domain.simplerulepojo.SubComponents;
|
|
|
|
|
|
import com.solution.rule.domain.simplerulepojo.ComponentParam;
|
|
|
|
|
|
|
|
|
|
|
|
import java.util.List;
|
|
|
|
|
|
import java.util.Map;
|
|
|
|
|
|
import java.util.ArrayList;
|
2026-03-27 10:27:04 +08:00
|
|
|
|
|
2026-03-27 11:35:17 +08:00
|
|
|
|
global java.util.Map globalParams;
|
|
|
|
|
|
|
2026-03-27 16:56:07 +08:00
|
|
|
|
//-------------------------------------------------------------------------------
|
2026-03-27 11:35:17 +08:00
|
|
|
|
rule "任务匹配1"
|
2026-03-27 10:27:04 +08:00
|
|
|
|
agenda-group "打击任务"
|
2026-03-27 16:56:07 +08:00
|
|
|
|
salience 100
|
2026-03-27 10:27:04 +08:00
|
|
|
|
when
|
2026-03-27 11:35:17 +08:00
|
|
|
|
then
|
2026-03-27 16:56:07 +08:00
|
|
|
|
// legacy 占位:旧的固定字符串匹配已停用,改由“任务自动匹配规则”统一处理。
|
2026-03-27 11:35:17 +08:00
|
|
|
|
end
|
|
|
|
|
|
//-------------------------------------------------------------------------------
|
|
|
|
|
|
rule "任务匹配2"
|
|
|
|
|
|
agenda-group "打击任务"
|
2026-03-27 16:56:07 +08:00
|
|
|
|
salience 100
|
2026-03-27 11:35:17 +08:00
|
|
|
|
when
|
|
|
|
|
|
then
|
2026-03-27 16:56:07 +08:00
|
|
|
|
// legacy 占位:旧的固定字符串匹配已停用,改由“任务自动匹配规则”统一处理。
|
2026-03-27 11:35:17 +08:00
|
|
|
|
end
|
|
|
|
|
|
//-------------------------------------------------------------------------------
|
|
|
|
|
|
rule "威胁等级规则"
|
|
|
|
|
|
agenda-group "打击任务"
|
2026-03-27 16:56:07 +08:00
|
|
|
|
salience 90
|
2026-03-27 11:35:17 +08:00
|
|
|
|
when
|
|
|
|
|
|
//如果蓝方威胁等级大于等于3,则全局武器数量为3,添加插入导弹发射车辆和防空导弹武器
|
2026-03-27 16:56:07 +08:00
|
|
|
|
$task : FactTask(blueTask.side == "蓝方",blueTask.threatLevel >= "3")
|
2026-03-27 11:35:17 +08:00
|
|
|
|
$redTask : FactTask(redTask.side == "红方")
|
|
|
|
|
|
then
|
|
|
|
|
|
//设置平台下组件的数量
|
|
|
|
|
|
globalParams.put("platNum",3);
|
|
|
|
|
|
//威胁等级大于等于3固定插入导弹发射车辆
|
|
|
|
|
|
// ========== 调用函数 ==========
|
2026-03-27 16:56:07 +08:00
|
|
|
|
threatLevels($redTask, globalParams);
|
2026-03-27 11:35:17 +08:00
|
|
|
|
end
|
|
|
|
|
|
//-------------------------------------------------------------------------------
|
|
|
|
|
|
rule "地面类型匹配规则"
|
|
|
|
|
|
agenda-group "打击任务"
|
2026-03-27 16:56:07 +08:00
|
|
|
|
salience 80
|
2026-03-27 11:35:17 +08:00
|
|
|
|
when
|
|
|
|
|
|
//如果蓝方武器为地面类型且高度不超过500米,则使用插入空中力量打击
|
|
|
|
|
|
$task : FactTask(blueTask.side == "蓝方")
|
|
|
|
|
|
$weapons : List() from $task.blueTask.taskWeapons
|
|
|
|
|
|
$weapon : Weapon(supportType == "ground") from $weapons
|
2026-03-27 10:27:04 +08:00
|
|
|
|
then
|
2026-03-27 11:35:17 +08:00
|
|
|
|
Task redTask = $task.getRedTask();
|
|
|
|
|
|
List<Weapon> taskWeapons = redTask.getTaskWeapons();
|
|
|
|
|
|
Weapon weapon = new Weapon();
|
|
|
|
|
|
weapon.setName("F-16");
|
|
|
|
|
|
weapon.setNumber((Integer) globalParams.get("platNum"));
|
|
|
|
|
|
weapon.setSupportType("plane");
|
|
|
|
|
|
taskWeapons.add(weapon);
|
|
|
|
|
|
end
|
|
|
|
|
|
//-------------------------------------------------------------------------------
|
2026-03-27 16:56:07 +08:00
|
|
|
|
rule "空中类型匹配规则"
|
|
|
|
|
|
agenda-group "打击任务"
|
|
|
|
|
|
salience 80
|
|
|
|
|
|
when
|
|
|
|
|
|
//如果蓝方武器为地面类型且高度不超过500米,则使用插入空中力量打击
|
|
|
|
|
|
$task : FactTask(blueTask.side == "蓝方")
|
|
|
|
|
|
$weapons : List() from $task.blueTask.taskWeapons
|
|
|
|
|
|
$weapon : Weapon(supportType == "overhead") from $weapons
|
|
|
|
|
|
then
|
|
|
|
|
|
Task redTask = $task.getRedTask();
|
|
|
|
|
|
List<Weapon> taskWeapons = redTask.getTaskWeapons();
|
|
|
|
|
|
Weapon weapon = new Weapon();
|
|
|
|
|
|
weapon.setName("F-16");
|
|
|
|
|
|
weapon.setNumber((Integer) globalParams.get("platNum"));
|
|
|
|
|
|
weapon.setSupportType("plane");
|
|
|
|
|
|
taskWeapons.add(weapon);
|
|
|
|
|
|
end
|
|
|
|
|
|
//-------------------------------------------------------------------------------
|
|
|
|
|
|
rule "装备组件匹配"
|
|
|
|
|
|
agenda-group "打击任务"
|
|
|
|
|
|
salience 70
|
|
|
|
|
|
when
|
|
|
|
|
|
then
|
|
|
|
|
|
// legacy 规则已停用:完整武器库逻辑已在 //TODO 下接管。
|
|
|
|
|
|
// 保留该规则名称便于回滚和历史追踪,不再执行任何动作。
|
|
|
|
|
|
end
|
|
|
|
|
|
//-------------------------------------------------------------------------------
|
|
|
|
|
|
rule "组件参数匹配"
|
|
|
|
|
|
agenda-group "打击任务"
|
|
|
|
|
|
salience 60
|
|
|
|
|
|
when
|
|
|
|
|
|
then
|
|
|
|
|
|
// legacy 占位规则:参数处理已并入“红方武器自适应装配规则/导弹联动增强规则”。
|
|
|
|
|
|
end
|
|
|
|
|
|
//-------------------------------------------------------------------------------
|
|
|
|
|
|
//TODO
|
|
|
|
|
|
//-------------------------------------------------------------------------------
|
|
|
|
|
|
// ========================= 业务可改区(只改这里) =========================
|
|
|
|
|
|
// 说明:
|
|
|
|
|
|
// 1) 业务人员只改 buildBusinessConfig() 里的值,其他函数不要改。
|
|
|
|
|
|
// 2) 规则是“严格白名单”,未命中条件时允许不匹配(不新增红方武器)。
|
|
|
|
|
|
// 3) 可通过开关控制是否启用空中/地面/装甲/导弹联动策略。
|
|
|
|
|
|
// 4) 业务可直接配置“蓝方类型 -> 红方方案(多选)”,例如坦克可选火箭或导弹系统。
|
|
|
|
|
|
|
|
|
|
|
|
function Map buildBusinessConfig() {
|
|
|
|
|
|
Map cfg = new java.util.HashMap();
|
|
|
|
|
|
|
|
|
|
|
|
// ---------- 红方完整武器库名称映射(可改) ----------
|
|
|
|
|
|
cfg.put("redStrikeDroneName", "火力打击无人机");
|
|
|
|
|
|
cfg.put("redArmedHelicopterName", "武装直升机");
|
|
|
|
|
|
cfg.put("redHowitzerName", "迫榴炮");
|
|
|
|
|
|
cfg.put("redVehicleMortarName", "车载迫击炮");
|
|
|
|
|
|
cfg.put("redAaWeaponName", "防空导弹武器");
|
|
|
|
|
|
cfg.put("redAtRocketName", "反坦克火箭");
|
|
|
|
|
|
cfg.put("redAtMissileSystemName", "反坦克导弹系统");
|
|
|
|
|
|
cfg.put("redMissileVehicleName", "导弹发射车");
|
|
|
|
|
|
|
|
|
|
|
|
// ---------- 白名单开关(可改) ----------
|
|
|
|
|
|
cfg.put("enableAirRule", Boolean.TRUE); // 蓝方空中 -> 红方空中反制组
|
|
|
|
|
|
cfg.put("enableGroundRule", Boolean.TRUE); // 蓝方地面 -> 红方炮类反制组
|
|
|
|
|
|
cfg.put("enableArmorRule", Boolean.TRUE); // 蓝方装甲 -> 红方反坦克组
|
|
|
|
|
|
cfg.put("enableMissileVehicleRule", Boolean.FALSE); // 蓝方导弹 -> 红方导弹发射车(默认关)
|
|
|
|
|
|
cfg.put("enableMissileLinkage", Boolean.TRUE); // 导弹参数联动开关
|
|
|
|
|
|
cfg.put("allowMultiGroup", Boolean.TRUE); // true=允许多组叠加,false=命中首组即停止
|
|
|
|
|
|
cfg.put("enableArmedHelicopterOnAir", Boolean.TRUE);
|
|
|
|
|
|
|
|
|
|
|
|
// ---------- 蓝方类型 -> 红方武器方案(多选映射,可改) ----------
|
|
|
|
|
|
// 逗号分隔,示例:反坦克火箭,反坦克导弹系统
|
|
|
|
|
|
// 若为空或写了非法武器名,则该组不触发(允许不命中)
|
|
|
|
|
|
cfg.put("map_air_targets", "防空导弹武器,火力打击无人机,武装直升机");
|
|
|
|
|
|
cfg.put("map_ground_targets", "迫榴炮,车载迫击炮");
|
|
|
|
|
|
cfg.put("map_armor_targets", "反坦克火箭,反坦克导弹系统");
|
|
|
|
|
|
cfg.put("map_artillery_targets", "迫榴炮,车载迫击炮");
|
|
|
|
|
|
cfg.put("map_missile_targets", "导弹发射车");
|
|
|
|
|
|
|
|
|
|
|
|
// ---------- 数量与参数(可改) ----------
|
|
|
|
|
|
cfg.put("defaultAirNum", 1);
|
|
|
|
|
|
cfg.put("defaultGroundNum", 1);
|
|
|
|
|
|
cfg.put("defaultMissileVehicleNum", 1);
|
|
|
|
|
|
cfg.put("shellRangeDefault", "1500"); // 炮类单位固定:范围米
|
|
|
|
|
|
cfg.put("missileCountOffset", 1); // 红方导弹数量 = 蓝方 + offset
|
|
|
|
|
|
cfg.put("missileRangeOffset", 80); // 红方导弹范围增量
|
|
|
|
|
|
cfg.put("blueMissileRangeDefault", 220); // 蓝方导弹范围默认值
|
|
|
|
|
|
cfg.put("minBlueMissileCountForLinkage", 1); // 联动触发门槛
|
|
|
|
|
|
|
|
|
|
|
|
// ---------- 任务自动命名模板(可改) ----------
|
|
|
|
|
|
// 任务分类优先级:导弹突击 > 防空压制 > 反装甲打击 > 炮火压制 > 通用打击
|
|
|
|
|
|
cfg.put("taskName_missile_strike", "导弹突击打击任务");
|
|
|
|
|
|
cfg.put("taskName_air_defence", "防空压制打击任务");
|
|
|
|
|
|
cfg.put("taskName_anti_armor", "反装甲打击任务");
|
|
|
|
|
|
cfg.put("taskName_artillery", "炮火压制打击任务");
|
|
|
|
|
|
cfg.put("taskName_general", "通用打击任务");
|
|
|
|
|
|
cfg.put("taskDataType_missile_strike", "missile-strike");
|
|
|
|
|
|
cfg.put("taskDataType_air_defence", "air-defence");
|
|
|
|
|
|
cfg.put("taskDataType_anti_armor", "anti-armor");
|
|
|
|
|
|
cfg.put("taskDataType_artillery", "artillery");
|
|
|
|
|
|
cfg.put("taskDataType_general", "strike");
|
|
|
|
|
|
|
|
|
|
|
|
return cfg;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
//-------------------------------------------------------------------------------
|
|
|
|
|
|
rule "红方武器自适应装配规则"
|
|
|
|
|
|
agenda-group "打击任务"
|
|
|
|
|
|
salience 55
|
|
|
|
|
|
when
|
|
|
|
|
|
// 蓝方与红方任务都存在时触发,做“武器+组件”的基础装配
|
|
|
|
|
|
$fact : FactTask(blueTask.side == "蓝方", redTask.side == "红方")
|
|
|
|
|
|
then
|
|
|
|
|
|
Map cfg = buildBusinessConfig();
|
|
|
|
|
|
configureRedWeaponsByBlue($fact, cfg);
|
|
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
|
|
//-------------------------------------------------------------------------------
|
|
|
|
|
|
rule "导弹联动增强规则"
|
|
|
|
|
|
agenda-group "打击任务"
|
|
|
|
|
|
salience 54
|
|
|
|
|
|
when
|
|
|
|
|
|
// 在基础装配后执行:若蓝方挂载导弹,红方空中武器自动增强导弹能力
|
|
|
|
|
|
$fact : FactTask(blueTask.side == "蓝方", redTask.side == "红方")
|
|
|
|
|
|
then
|
|
|
|
|
|
Map cfg = buildBusinessConfig();
|
|
|
|
|
|
applyMissileLinkage($fact, cfg);
|
|
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
|
|
//-------------------------------------------------------------------------------
|
|
|
|
|
|
rule "任务自动匹配规则"
|
|
|
|
|
|
agenda-group "打击任务"
|
|
|
|
|
|
salience 50
|
|
|
|
|
|
when
|
|
|
|
|
|
// 以红方最终武器为主自动生成任务名,保证任务名与武器一致
|
|
|
|
|
|
$fact : FactTask(blueTask.side == "蓝方", redTask.side == "红方")
|
|
|
|
|
|
then
|
|
|
|
|
|
Map cfg = buildBusinessConfig();
|
|
|
|
|
|
assignTaskNameByRedWeapons($fact, cfg);
|
|
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
|
|
//-------------------------------------------------------------------------------
|
|
|
|
|
|
// 说明:以下函数全部是 DRL function(不是 Java 类方法)
|
|
|
|
|
|
// 目标:让不懂代码的业务同事只改“可调整常量区”即可完成策略调整
|
|
|
|
|
|
|
|
|
|
|
|
// 根据蓝方武器结构,按业务映射装配红方武器并写入基础组件
|
|
|
|
|
|
function void configureRedWeaponsByBlue(
|
|
|
|
|
|
FactTask fact,
|
|
|
|
|
|
Map cfg
|
|
|
|
|
|
) {
|
|
|
|
|
|
if (fact == null || fact.getBlueTask() == null || fact.getRedTask() == null) {
|
|
|
|
|
|
return;
|
|
|
|
|
|
}
|
|
|
|
|
|
List<Weapon> blueWeapons = fact.getBlueTask().getTaskWeapons();
|
|
|
|
|
|
if (blueWeapons == null || blueWeapons.isEmpty()) {
|
|
|
|
|
|
return;
|
|
|
|
|
|
}
|
|
|
|
|
|
Task redTask = fact.getRedTask();
|
|
|
|
|
|
List<Weapon> redWeapons = redTask.getTaskWeapons();
|
|
|
|
|
|
if (redWeapons == null) {
|
|
|
|
|
|
redWeapons = new ArrayList<>();
|
|
|
|
|
|
redTask.setTaskWeapons(redWeapons);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 蓝方组件模板(用于测试和参数联动):若蓝方没填组件,给一个合理默认值
|
|
|
|
|
|
buildBlueTestComponents(blueWeapons);
|
|
|
|
|
|
|
|
|
|
|
|
boolean hasBlueAir = false;
|
|
|
|
|
|
boolean hasBlueGround = false;
|
|
|
|
|
|
boolean hasBlueArtillery = false;
|
|
|
|
|
|
boolean hasBlueArmor = false;
|
|
|
|
|
|
boolean hasBlueMissile = false;
|
|
|
|
|
|
for (Object obj : blueWeapons) {
|
|
|
|
|
|
Weapon blueWeapon = (Weapon) obj;
|
|
|
|
|
|
if (blueWeapon == null) {
|
|
|
|
|
|
continue;
|
|
|
|
|
|
}
|
|
|
|
|
|
if (isAirWeapon(blueWeapon)) {
|
|
|
|
|
|
hasBlueAir = true;
|
|
|
|
|
|
}
|
|
|
|
|
|
if (isGroundWeapon(blueWeapon)) {
|
|
|
|
|
|
hasBlueGround = true;
|
|
|
|
|
|
}
|
|
|
|
|
|
if (isArtilleryWeapon(blueWeapon)) {
|
|
|
|
|
|
hasBlueArtillery = true;
|
|
|
|
|
|
}
|
|
|
|
|
|
if (isArmorWeapon(blueWeapon)) {
|
|
|
|
|
|
hasBlueArmor = true;
|
|
|
|
|
|
}
|
|
|
|
|
|
if (hasMissileComponent(blueWeapon)) {
|
|
|
|
|
|
hasBlueMissile = true;
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
boolean allowMultiGroup = readBooleanCfg(cfg, "allowMultiGroup", true);
|
|
|
|
|
|
boolean matchedAny = false;
|
|
|
|
|
|
|
|
|
|
|
|
// 严格白名单-1:空中目标反制组(由 map_air_targets 控制)
|
|
|
|
|
|
if (readBooleanCfg(cfg, "enableAirRule", true) && hasBlueAir && (!matchedAny || allowMultiGroup)) {
|
|
|
|
|
|
int before = redWeapons.size();
|
|
|
|
|
|
applyMappedWeapons(redWeapons, cfg, "map_air_targets", readIntCfg(cfg, "defaultAirNum", 1), readBooleanCfg(cfg, "enableArmedHelicopterOnAir", true));
|
|
|
|
|
|
if (redWeapons.size() > before) {
|
|
|
|
|
|
matchedAny = true;
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 严格白名单-2:地面目标炮类组(由 map_ground_targets 控制)
|
|
|
|
|
|
if (readBooleanCfg(cfg, "enableGroundRule", true) && hasBlueGround && (!matchedAny || allowMultiGroup)) {
|
|
|
|
|
|
int before = redWeapons.size();
|
|
|
|
|
|
applyMappedWeapons(redWeapons, cfg, "map_ground_targets", readIntCfg(cfg, "defaultGroundNum", 1), true);
|
|
|
|
|
|
if (redWeapons.size() > before) {
|
|
|
|
|
|
matchedAny = true;
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 严格白名单-3:装甲目标反坦克组(由 map_armor_targets 控制)
|
|
|
|
|
|
if (readBooleanCfg(cfg, "enableArmorRule", true) && hasBlueArmor && (!matchedAny || allowMultiGroup)) {
|
|
|
|
|
|
int before = redWeapons.size();
|
|
|
|
|
|
applyMappedWeapons(redWeapons, cfg, "map_armor_targets", readIntCfg(cfg, "defaultGroundNum", 1), true);
|
|
|
|
|
|
if (redWeapons.size() > before) {
|
|
|
|
|
|
matchedAny = true;
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 严格白名单-4:炮类目标反制组(由 map_artillery_targets 控制)
|
|
|
|
|
|
if (hasBlueArtillery && (!matchedAny || allowMultiGroup)) {
|
|
|
|
|
|
int before = redWeapons.size();
|
|
|
|
|
|
applyMappedWeapons(redWeapons, cfg, "map_artillery_targets", readIntCfg(cfg, "defaultGroundNum", 1), true);
|
|
|
|
|
|
if (redWeapons.size() > before) {
|
|
|
|
|
|
matchedAny = true;
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 严格白名单-5:导弹补充组(默认关闭,由 map_missile_targets 控制)
|
|
|
|
|
|
if (readBooleanCfg(cfg, "enableMissileVehicleRule", false) && hasBlueMissile && (!matchedAny || allowMultiGroup)) {
|
|
|
|
|
|
int before = redWeapons.size();
|
|
|
|
|
|
applyMappedWeapons(redWeapons, cfg, "map_missile_targets", readIntCfg(cfg, "defaultMissileVehicleNum", 1), true);
|
|
|
|
|
|
if (redWeapons.size() > before) {
|
|
|
|
|
|
matchedAny = true;
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 炮类限制仅对已匹配策略生效;若本轮未命中白名单,不做任何新增/补齐
|
|
|
|
|
|
if (matchedAny && hasBlueArtillery) {
|
|
|
|
|
|
limitRedArtilleryToShellOnly(redWeapons, (String) cfg.get("shellRangeDefault"));
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
function void applyMappedWeapons(List redWeapons, Map cfg, String mapKey, int defaultNum, boolean allowArmedHelicopter) {
|
|
|
|
|
|
List mappedNames = parseMappedWeaponNames(cfg, mapKey);
|
|
|
|
|
|
if (mappedNames == null || mappedNames.isEmpty()) {
|
|
|
|
|
|
return;
|
|
|
|
|
|
}
|
|
|
|
|
|
for (Object obj : mappedNames) {
|
|
|
|
|
|
String weaponName = (String) obj;
|
|
|
|
|
|
if (!allowArmedHelicopter && weaponName != null && weaponName.equals((String) cfg.get("redArmedHelicopterName"))) {
|
|
|
|
|
|
continue;
|
|
|
|
|
|
}
|
|
|
|
|
|
String supportType = inferSupportTypeByWeaponName(weaponName);
|
|
|
|
|
|
Weapon redWeapon = ensureRedWeapon(redWeapons, weaponName, supportType, defaultNum);
|
|
|
|
|
|
ensureBasicRedComponents(redWeapon);
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
function List parseMappedWeaponNames(Map cfg, String mapKey) {
|
|
|
|
|
|
List result = new ArrayList();
|
|
|
|
|
|
if (cfg == null || mapKey == null) {
|
|
|
|
|
|
return result;
|
|
|
|
|
|
}
|
|
|
|
|
|
Object raw = cfg.get(mapKey);
|
|
|
|
|
|
if (raw == null) {
|
|
|
|
|
|
return result;
|
|
|
|
|
|
}
|
|
|
|
|
|
String text = String.valueOf(raw);
|
|
|
|
|
|
if (text == null || text.trim().equals("")) {
|
|
|
|
|
|
return result;
|
|
|
|
|
|
}
|
|
|
|
|
|
String[] parts = text.split(",");
|
|
|
|
|
|
for (int i = 0; i < parts.length; i++) {
|
|
|
|
|
|
String one = parts[i];
|
|
|
|
|
|
if (one == null) {
|
|
|
|
|
|
continue;
|
|
|
|
|
|
}
|
|
|
|
|
|
String name = one.trim();
|
|
|
|
|
|
if (name.equals("")) {
|
|
|
|
|
|
continue;
|
|
|
|
|
|
}
|
|
|
|
|
|
if (isValidRedWeaponNameByConfig(cfg, name) && !containsString(result, name)) {
|
|
|
|
|
|
result.add(name);
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
return result;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
function boolean isValidRedWeaponNameByConfig(Map cfg, String weaponName) {
|
|
|
|
|
|
if (cfg == null || weaponName == null || weaponName.equals("")) {
|
|
|
|
|
|
return false;
|
|
|
|
|
|
}
|
|
|
|
|
|
return weaponName.equals((String) cfg.get("redStrikeDroneName"))
|
|
|
|
|
|
|| weaponName.equals((String) cfg.get("redArmedHelicopterName"))
|
|
|
|
|
|
|| weaponName.equals((String) cfg.get("redHowitzerName"))
|
|
|
|
|
|
|| weaponName.equals((String) cfg.get("redVehicleMortarName"))
|
|
|
|
|
|
|| weaponName.equals((String) cfg.get("redAaWeaponName"))
|
|
|
|
|
|
|| weaponName.equals((String) cfg.get("redAtRocketName"))
|
|
|
|
|
|
|| weaponName.equals((String) cfg.get("redAtMissileSystemName"))
|
|
|
|
|
|
|| weaponName.equals((String) cfg.get("redMissileVehicleName"));
|
|
|
|
|
|
}
|
2026-03-27 11:35:17 +08:00
|
|
|
|
|
2026-03-27 16:56:07 +08:00
|
|
|
|
function boolean containsString(List values, String target) {
|
|
|
|
|
|
if (values == null || target == null) {
|
|
|
|
|
|
return false;
|
|
|
|
|
|
}
|
|
|
|
|
|
for (Object obj : values) {
|
|
|
|
|
|
if (obj != null && target.equals(String.valueOf(obj))) {
|
|
|
|
|
|
return true;
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
return false;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
function String inferSupportTypeByWeaponName(String weaponName) {
|
|
|
|
|
|
if (weaponName == null) {
|
|
|
|
|
|
return "ground";
|
|
|
|
|
|
}
|
|
|
|
|
|
if (weaponName.contains("无人机") || weaponName.contains("直升机")) {
|
|
|
|
|
|
return "overhead";
|
|
|
|
|
|
}
|
|
|
|
|
|
if (weaponName.contains("防空导弹")) {
|
|
|
|
|
|
return "antiaircraft";
|
|
|
|
|
|
}
|
|
|
|
|
|
return "ground";
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 蓝方若有导弹,红方空中武器补导弹:数量 = 蓝方 + offset,范围略高
|
|
|
|
|
|
function void applyMissileLinkage(
|
|
|
|
|
|
FactTask fact,
|
|
|
|
|
|
Map cfg
|
|
|
|
|
|
) {
|
|
|
|
|
|
if (fact == null || fact.getBlueTask() == null || fact.getRedTask() == null) {
|
|
|
|
|
|
return;
|
|
|
|
|
|
}
|
|
|
|
|
|
List<Weapon> blueWeapons = fact.getBlueTask().getTaskWeapons();
|
|
|
|
|
|
List<Weapon> redWeapons = fact.getRedTask().getTaskWeapons();
|
|
|
|
|
|
if (blueWeapons == null || blueWeapons.isEmpty() || redWeapons == null || redWeapons.isEmpty()) {
|
|
|
|
|
|
return;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
if (!readBooleanCfg(cfg, "enableMissileLinkage", true)) {
|
|
|
|
|
|
return;
|
|
|
|
|
|
}
|
|
|
|
|
|
int blueMissileCount = countBlueMissileNumber(blueWeapons);
|
|
|
|
|
|
if (blueMissileCount < readIntCfg(cfg, "minBlueMissileCountForLinkage", 1)) {
|
|
|
|
|
|
return;
|
|
|
|
|
|
}
|
|
|
|
|
|
int blueMissileRange = readBlueMissileRange(blueWeapons, readIntCfg(cfg, "blueMissileRangeDefault", 220));
|
|
|
|
|
|
int redMissileTarget = blueMissileCount + readIntCfg(cfg, "missileCountOffset", 1);
|
|
|
|
|
|
int redRangeTarget = blueMissileRange + readIntCfg(cfg, "missileRangeOffset", 80);
|
|
|
|
|
|
|
|
|
|
|
|
for (Object obj : redWeapons) {
|
|
|
|
|
|
Weapon redWeapon = (Weapon) obj;
|
|
|
|
|
|
if (redWeapon == null || !isRedAirWeapon(redWeapon)) {
|
|
|
|
|
|
continue;
|
|
|
|
|
|
}
|
|
|
|
|
|
ensureMissileComponentForRedAirWeapon(redWeapon, redMissileTarget, redRangeTarget);
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
function void assignTaskNameByRedWeapons(FactTask fact, Map cfg) {
|
|
|
|
|
|
if (fact == null || fact.getRedTask() == null) {
|
|
|
|
|
|
return;
|
|
|
|
|
|
}
|
|
|
|
|
|
Task redTask = fact.getRedTask();
|
|
|
|
|
|
List<Weapon> redWeapons = redTask.getTaskWeapons();
|
|
|
|
|
|
String category = classifyTaskByRedWeapons(redWeapons);
|
|
|
|
|
|
|
|
|
|
|
|
// 一致性校验:分类与武器不一致则回落通用打击
|
|
|
|
|
|
if (!isTaskCategoryConsistent(category, redWeapons)) {
|
|
|
|
|
|
category = "general";
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
redTask.setDrawName(resolveTaskNameByCategory(cfg, category));
|
|
|
|
|
|
redTask.setDataType(resolveTaskDataTypeByCategory(cfg, category));
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
function String classifyTaskByRedWeapons(List redWeapons) {
|
|
|
|
|
|
if (redWeapons == null || redWeapons.isEmpty()) {
|
|
|
|
|
|
return "general";
|
|
|
|
|
|
}
|
|
|
|
|
|
// 符合实际的优先级:导弹突击 > 防空压制 > 反装甲 > 炮火压制 > 通用
|
|
|
|
|
|
if (hasRedWeaponName(redWeapons, "导弹发射车")) {
|
|
|
|
|
|
return "missile_strike";
|
|
|
|
|
|
}
|
|
|
|
|
|
if (hasAnyRedWeaponName(redWeapons, "防空导弹武器,火力打击无人机,武装直升机")) {
|
|
|
|
|
|
return "air_defence";
|
|
|
|
|
|
}
|
|
|
|
|
|
if (hasAnyRedWeaponName(redWeapons, "反坦克火箭,反坦克导弹系统")) {
|
|
|
|
|
|
return "anti_armor";
|
|
|
|
|
|
}
|
|
|
|
|
|
if (hasAnyRedWeaponName(redWeapons, "迫榴炮,车载迫击炮")) {
|
|
|
|
|
|
return "artillery";
|
|
|
|
|
|
}
|
|
|
|
|
|
return "general";
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
function boolean isTaskCategoryConsistent(String category, List redWeapons) {
|
|
|
|
|
|
if (category == null) {
|
|
|
|
|
|
return false;
|
|
|
|
|
|
}
|
|
|
|
|
|
if (category.equals("missile_strike")) {
|
|
|
|
|
|
return hasRedWeaponName(redWeapons, "导弹发射车");
|
|
|
|
|
|
}
|
|
|
|
|
|
if (category.equals("air_defence")) {
|
|
|
|
|
|
return hasAnyRedWeaponName(redWeapons, "防空导弹武器,火力打击无人机,武装直升机");
|
|
|
|
|
|
}
|
|
|
|
|
|
if (category.equals("anti_armor")) {
|
|
|
|
|
|
return hasAnyRedWeaponName(redWeapons, "反坦克火箭,反坦克导弹系统");
|
|
|
|
|
|
}
|
|
|
|
|
|
if (category.equals("artillery")) {
|
|
|
|
|
|
return hasAnyRedWeaponName(redWeapons, "迫榴炮,车载迫击炮");
|
|
|
|
|
|
}
|
|
|
|
|
|
return true;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
function String resolveTaskNameByCategory(Map cfg, String category) {
|
|
|
|
|
|
if (cfg == null || category == null) {
|
|
|
|
|
|
return "通用打击任务";
|
|
|
|
|
|
}
|
|
|
|
|
|
if (category.equals("missile_strike")) {
|
|
|
|
|
|
return String.valueOf(cfg.get("taskName_missile_strike"));
|
|
|
|
|
|
}
|
|
|
|
|
|
if (category.equals("air_defence")) {
|
|
|
|
|
|
return String.valueOf(cfg.get("taskName_air_defence"));
|
|
|
|
|
|
}
|
|
|
|
|
|
if (category.equals("anti_armor")) {
|
|
|
|
|
|
return String.valueOf(cfg.get("taskName_anti_armor"));
|
|
|
|
|
|
}
|
|
|
|
|
|
if (category.equals("artillery")) {
|
|
|
|
|
|
return String.valueOf(cfg.get("taskName_artillery"));
|
|
|
|
|
|
}
|
|
|
|
|
|
return String.valueOf(cfg.get("taskName_general"));
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
function String resolveTaskDataTypeByCategory(Map cfg, String category) {
|
|
|
|
|
|
if (cfg == null || category == null) {
|
|
|
|
|
|
return "strike";
|
|
|
|
|
|
}
|
|
|
|
|
|
if (category.equals("missile_strike")) {
|
|
|
|
|
|
return String.valueOf(cfg.get("taskDataType_missile_strike"));
|
|
|
|
|
|
}
|
|
|
|
|
|
if (category.equals("air_defence")) {
|
|
|
|
|
|
return String.valueOf(cfg.get("taskDataType_air_defence"));
|
|
|
|
|
|
}
|
|
|
|
|
|
if (category.equals("anti_armor")) {
|
|
|
|
|
|
return String.valueOf(cfg.get("taskDataType_anti_armor"));
|
|
|
|
|
|
}
|
|
|
|
|
|
if (category.equals("artillery")) {
|
|
|
|
|
|
return String.valueOf(cfg.get("taskDataType_artillery"));
|
|
|
|
|
|
}
|
|
|
|
|
|
return String.valueOf(cfg.get("taskDataType_general"));
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
function boolean hasAnyRedWeaponName(List redWeapons, String commaNames) {
|
|
|
|
|
|
if (redWeapons == null || redWeapons.isEmpty() || commaNames == null || commaNames.equals("")) {
|
|
|
|
|
|
return false;
|
|
|
|
|
|
}
|
|
|
|
|
|
String[] names = commaNames.split(",");
|
|
|
|
|
|
for (int i = 0; i < names.length; i++) {
|
|
|
|
|
|
String one = names[i];
|
|
|
|
|
|
if (one == null) {
|
|
|
|
|
|
continue;
|
|
|
|
|
|
}
|
|
|
|
|
|
if (hasRedWeaponName(redWeapons, one.trim())) {
|
|
|
|
|
|
return true;
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
return false;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
function boolean hasRedWeaponName(List redWeapons, String weaponName) {
|
|
|
|
|
|
if (redWeapons == null || redWeapons.isEmpty() || weaponName == null || weaponName.equals("")) {
|
|
|
|
|
|
return false;
|
|
|
|
|
|
}
|
|
|
|
|
|
for (Object obj : redWeapons) {
|
|
|
|
|
|
Weapon w = (Weapon) obj;
|
|
|
|
|
|
if (w != null && w.getName() != null && w.getName().equals(weaponName)) {
|
|
|
|
|
|
return true;
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
return false;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 蓝方组件模板:仅在组件缺失时补齐,作为规则联动测试用
|
|
|
|
|
|
function void buildBlueTestComponents(List weapons) {
|
|
|
|
|
|
if (weapons == null || weapons.isEmpty()) {
|
|
|
|
|
|
return;
|
|
|
|
|
|
}
|
|
|
|
|
|
for (Object obj : weapons) {
|
|
|
|
|
|
Weapon weapon = (Weapon) obj;
|
|
|
|
|
|
if (weapon == null) {
|
|
|
|
|
|
continue;
|
|
|
|
|
|
}
|
|
|
|
|
|
List<SubComponents> components = weapon.getComponents();
|
|
|
|
|
|
if (components == null) {
|
|
|
|
|
|
components = new ArrayList<>();
|
|
|
|
|
|
weapon.setComponents(components);
|
|
|
|
|
|
}
|
|
|
|
|
|
if (!components.isEmpty()) {
|
|
|
|
|
|
continue;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 蓝方主要用于触发规则,模板尽量简洁
|
|
|
|
|
|
if (isAirWeapon(weapon)) {
|
|
|
|
|
|
components.add(buildComponent("火控雷达", "220", "探测范围米", 1));
|
|
|
|
|
|
components.add(buildComponent("空空导弹", "220", "破坏范围米", 1));
|
|
|
|
|
|
} else if (isArtilleryWeapon(weapon)) {
|
|
|
|
|
|
components.add(buildComponent("炮弹", "1200", "范围米", 6));
|
|
|
|
|
|
} else if (isGroundWeapon(weapon)) {
|
|
|
|
|
|
components.add(buildComponent("机枪", "600", "射程米", 1));
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 红方基础组件模板:便于业务人员看懂武器都带了哪些能力
|
|
|
|
|
|
function void ensureBasicRedComponents(Weapon weapon) {
|
|
|
|
|
|
if (weapon == null) {
|
|
|
|
|
|
return;
|
|
|
|
|
|
}
|
|
|
|
|
|
String name = weapon.getName();
|
|
|
|
|
|
if (name == null) {
|
|
|
|
|
|
name = "";
|
|
|
|
|
|
}
|
|
|
|
|
|
if (name.contains("防空导弹")) {
|
|
|
|
|
|
ensureComponent(weapon, "搜索雷达", "260", "探测范围米", 1);
|
|
|
|
|
|
ensureComponent(weapon, "防空导弹", "300", "破坏范围米", 1);
|
|
|
|
|
|
} else if (name.contains("无人机")) {
|
|
|
|
|
|
ensureComponent(weapon, "光电吊舱", "180", "识别范围米", 1);
|
|
|
|
|
|
ensureComponent(weapon, "空地导弹", "260", "破坏范围米", 1);
|
|
|
|
|
|
} else if (name.contains("武装直升机")) {
|
|
|
|
|
|
ensureComponent(weapon, "火控雷达", "220", "探测范围米", 1);
|
|
|
|
|
|
ensureComponent(weapon, "机载导弹", "280", "破坏范围米", 2);
|
|
|
|
|
|
} else if (name.contains("反坦克火箭")) {
|
|
|
|
|
|
ensureComponent(weapon, "火箭弹", "200", "破坏范围米", 4);
|
|
|
|
|
|
} else if (name.contains("反坦克导弹系统")) {
|
|
|
|
|
|
ensureComponent(weapon, "反坦克导弹", "320", "破坏范围米", 2);
|
|
|
|
|
|
ensureComponent(weapon, "激光测距", "180", "测距米", 1);
|
|
|
|
|
|
} else if (name.contains("迫榴炮") || name.contains("迫击炮")) {
|
|
|
|
|
|
ensureComponent(weapon, "炮弹", "1500", "范围米", 8);
|
|
|
|
|
|
} else if (name.contains("导弹发射车")) {
|
|
|
|
|
|
ensureComponent(weapon, "导弹发射架", "260", "破坏范围米", 1);
|
|
|
|
|
|
ensureComponent(weapon, "制导雷达", "240", "探测范围米", 1);
|
|
|
|
|
|
} else {
|
|
|
|
|
|
// 兜底组件,避免出现完全无组件的武器
|
|
|
|
|
|
ensureComponent(weapon, "火控系统", "100", "作用范围米", 1);
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 炮类限制:武器组件只能保留“炮弹”,并固定参数单位“范围米”
|
|
|
|
|
|
function void limitRedArtilleryToShellOnly(List redWeapons, String shellRangeDefault) {
|
|
|
|
|
|
if (redWeapons == null || redWeapons.isEmpty()) {
|
|
|
|
|
|
return;
|
|
|
|
|
|
}
|
|
|
|
|
|
for (Object obj : redWeapons) {
|
|
|
|
|
|
Weapon redWeapon = (Weapon) obj;
|
|
|
|
|
|
if (redWeapon == null || !isArtilleryWeapon(redWeapon)) {
|
|
|
|
|
|
continue;
|
|
|
|
|
|
}
|
|
|
|
|
|
List<SubComponents> onlyShell = new ArrayList<>();
|
|
|
|
|
|
onlyShell.add(buildComponent("炮弹", shellRangeDefault, "范围米", 8));
|
|
|
|
|
|
redWeapon.setComponents(onlyShell);
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
function Weapon ensureRedWeapon(List redWeapons, String name, String supportType, int number) {
|
|
|
|
|
|
for (Object obj : redWeapons) {
|
|
|
|
|
|
Weapon w = (Weapon) obj;
|
|
|
|
|
|
if (w != null && w.getName() != null && w.getName().equals(name)) {
|
|
|
|
|
|
if (w.getSupportType() == null || w.getSupportType().equals("")) {
|
|
|
|
|
|
w.setSupportType(supportType);
|
|
|
|
|
|
}
|
|
|
|
|
|
if (w.getNumber() == null || w.getNumber() <= 0) {
|
|
|
|
|
|
w.setNumber(number);
|
|
|
|
|
|
}
|
|
|
|
|
|
if (w.getComponents() == null) {
|
|
|
|
|
|
w.setComponents(new ArrayList<>());
|
|
|
|
|
|
}
|
|
|
|
|
|
return w;
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
Weapon w = new Weapon();
|
|
|
|
|
|
w.setName(name);
|
|
|
|
|
|
w.setSupportType(supportType);
|
|
|
|
|
|
w.setNumber(number);
|
|
|
|
|
|
w.setComponents(new ArrayList<>());
|
|
|
|
|
|
redWeapons.add(w);
|
|
|
|
|
|
return w;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
function void ensureMissileComponentForRedAirWeapon(Weapon redWeapon, int missileNumber, int missileRange) {
|
|
|
|
|
|
List<SubComponents> components = redWeapon.getComponents();
|
|
|
|
|
|
if (components == null) {
|
|
|
|
|
|
components = new ArrayList<>();
|
|
|
|
|
|
redWeapon.setComponents(components);
|
|
|
|
|
|
}
|
|
|
|
|
|
for (SubComponents c : components) {
|
|
|
|
|
|
if (c != null && c.getDeviceName() != null && c.getDeviceName().contains("导弹")) {
|
|
|
|
|
|
ensureOrUpdateParam(c, String.valueOf(missileRange), "破坏范围米", missileNumber);
|
|
|
|
|
|
return;
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
components.add(buildComponent("联动导弹", String.valueOf(missileRange), "破坏范围米", missileNumber));
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
function void ensureComponent(Weapon weapon, String deviceName, String value, String unit, int number) {
|
|
|
|
|
|
List<SubComponents> components = weapon.getComponents();
|
|
|
|
|
|
if (components == null) {
|
|
|
|
|
|
components = new ArrayList<>();
|
|
|
|
|
|
weapon.setComponents(components);
|
|
|
|
|
|
}
|
|
|
|
|
|
for (SubComponents c : components) {
|
|
|
|
|
|
if (c != null && c.getDeviceName() != null && c.getDeviceName().equals(deviceName)) {
|
|
|
|
|
|
ensureOrUpdateParam(c, value, unit, number);
|
|
|
|
|
|
return;
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
components.add(buildComponent(deviceName, value, unit, number));
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
function SubComponents buildComponent(String deviceName, String value, String unit, int number) {
|
|
|
|
|
|
SubComponents component = new SubComponents();
|
|
|
|
|
|
component.setDeviceName(deviceName);
|
|
|
|
|
|
List<ComponentParam> params = new ArrayList<>();
|
|
|
|
|
|
ComponentParam param = new ComponentParam();
|
|
|
|
|
|
param.setAttDefaultValue(value);
|
|
|
|
|
|
param.setAttExplain(unit);
|
|
|
|
|
|
param.setNumber(number);
|
|
|
|
|
|
params.add(param);
|
|
|
|
|
|
component.setComponentParams(params);
|
|
|
|
|
|
return component;
|
|
|
|
|
|
}
|
2026-03-27 11:35:17 +08:00
|
|
|
|
|
2026-03-27 16:56:07 +08:00
|
|
|
|
function void ensureOrUpdateParam(SubComponents component, String value, String unit, int number) {
|
|
|
|
|
|
List<ComponentParam> params = component.getComponentParams();
|
|
|
|
|
|
if (params == null) {
|
|
|
|
|
|
params = new ArrayList<>();
|
|
|
|
|
|
component.setComponentParams(params);
|
|
|
|
|
|
}
|
|
|
|
|
|
if (params.isEmpty()) {
|
|
|
|
|
|
ComponentParam param = new ComponentParam();
|
|
|
|
|
|
param.setAttDefaultValue(value);
|
|
|
|
|
|
param.setAttExplain(unit);
|
|
|
|
|
|
param.setNumber(number);
|
|
|
|
|
|
params.add(param);
|
|
|
|
|
|
return;
|
|
|
|
|
|
}
|
|
|
|
|
|
ComponentParam first = params.get(0);
|
|
|
|
|
|
first.setAttDefaultValue(value);
|
|
|
|
|
|
first.setAttExplain(unit);
|
|
|
|
|
|
first.setNumber(number);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
function int countBlueMissileNumber(List weapons) {
|
|
|
|
|
|
int total = 0;
|
|
|
|
|
|
for (Object obj : weapons) {
|
|
|
|
|
|
Weapon w = (Weapon) obj;
|
|
|
|
|
|
if (w == null || w.getComponents() == null) {
|
|
|
|
|
|
continue;
|
|
|
|
|
|
}
|
|
|
|
|
|
for (SubComponents c : w.getComponents()) {
|
|
|
|
|
|
if (c == null || c.getDeviceName() == null || !c.getDeviceName().contains("导弹")) {
|
|
|
|
|
|
continue;
|
|
|
|
|
|
}
|
|
|
|
|
|
int n = 1;
|
|
|
|
|
|
if (c.getComponentParams() != null && !c.getComponentParams().isEmpty() && c.getComponentParams().get(0) != null && c.getComponentParams().get(0).getNumber() != null) {
|
|
|
|
|
|
n = c.getComponentParams().get(0).getNumber();
|
|
|
|
|
|
}
|
|
|
|
|
|
total = total + n;
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
return total;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
function int readBlueMissileRange(List weapons, int fallback) {
|
|
|
|
|
|
int best = 0;
|
|
|
|
|
|
for (Object obj : weapons) {
|
|
|
|
|
|
Weapon w = (Weapon) obj;
|
|
|
|
|
|
if (w == null || w.getComponents() == null) {
|
|
|
|
|
|
continue;
|
|
|
|
|
|
}
|
|
|
|
|
|
for (SubComponents c : w.getComponents()) {
|
|
|
|
|
|
if (c == null || c.getDeviceName() == null || !c.getDeviceName().contains("导弹")) {
|
|
|
|
|
|
continue;
|
|
|
|
|
|
}
|
|
|
|
|
|
if (c.getComponentParams() == null || c.getComponentParams().isEmpty() || c.getComponentParams().get(0) == null) {
|
|
|
|
|
|
continue;
|
|
|
|
|
|
}
|
|
|
|
|
|
String value = c.getComponentParams().get(0).getAttDefaultValue();
|
|
|
|
|
|
int parsed = parseIntSafe(value, fallback);
|
|
|
|
|
|
if (parsed > best) {
|
|
|
|
|
|
best = parsed;
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
if (best <= 0) {
|
|
|
|
|
|
return fallback;
|
|
|
|
|
|
}
|
|
|
|
|
|
return best;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
function int parseIntSafe(String text, int fallback) {
|
|
|
|
|
|
if (text == null || text.equals("")) {
|
|
|
|
|
|
return fallback;
|
|
|
|
|
|
}
|
|
|
|
|
|
try {
|
|
|
|
|
|
return Integer.parseInt(text.trim());
|
|
|
|
|
|
} catch (Exception ex) {
|
|
|
|
|
|
return fallback;
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
function int readIntCfg(Map cfg, String key, int fallback) {
|
|
|
|
|
|
if (cfg == null || key == null) {
|
|
|
|
|
|
return fallback;
|
|
|
|
|
|
}
|
|
|
|
|
|
Object value = cfg.get(key);
|
|
|
|
|
|
if (value == null) {
|
|
|
|
|
|
return fallback;
|
|
|
|
|
|
}
|
|
|
|
|
|
if (value instanceof Integer) {
|
|
|
|
|
|
return ((Integer) value).intValue();
|
|
|
|
|
|
}
|
|
|
|
|
|
return parseIntSafe(String.valueOf(value), fallback);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
function boolean readBooleanCfg(Map cfg, String key, boolean fallback) {
|
|
|
|
|
|
if (cfg == null || key == null) {
|
|
|
|
|
|
return fallback;
|
|
|
|
|
|
}
|
|
|
|
|
|
Object value = cfg.get(key);
|
|
|
|
|
|
if (value == null) {
|
|
|
|
|
|
return fallback;
|
|
|
|
|
|
}
|
|
|
|
|
|
if (value instanceof Boolean) {
|
|
|
|
|
|
return ((Boolean) value).booleanValue();
|
|
|
|
|
|
}
|
|
|
|
|
|
String text = String.valueOf(value);
|
|
|
|
|
|
if (text == null) {
|
|
|
|
|
|
return fallback;
|
|
|
|
|
|
}
|
|
|
|
|
|
return "true".equalsIgnoreCase(text.trim());
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
function boolean isRedAirWeapon(Weapon weapon) {
|
|
|
|
|
|
if (weapon == null) {
|
|
|
|
|
|
return false;
|
|
|
|
|
|
}
|
|
|
|
|
|
String supportType = weapon.getSupportType();
|
|
|
|
|
|
String name = weapon.getName();
|
|
|
|
|
|
return (supportType != null && (supportType.equals("overhead") || supportType.equals("plane")))
|
|
|
|
|
|
|| (name != null && (name.contains("无人机") || name.contains("直升机")));
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
function boolean isAirWeapon(Weapon weapon) {
|
|
|
|
|
|
if (weapon == null) {
|
|
|
|
|
|
return false;
|
|
|
|
|
|
}
|
|
|
|
|
|
String supportType = weapon.getSupportType();
|
|
|
|
|
|
String name = weapon.getName();
|
|
|
|
|
|
return (supportType != null && (supportType.equals("overhead") || supportType.equals("plane")))
|
|
|
|
|
|
|| (name != null && (
|
|
|
|
|
|
name.contains("直升机")
|
|
|
|
|
|
|| name.contains("地空导弹")
|
|
|
|
|
|
|| name.contains("单兵防空导弹")
|
|
|
|
|
|
|| name.contains("制导导弹")
|
|
|
|
|
|
|| name.contains("无人机")
|
|
|
|
|
|
));
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
function boolean isGroundWeapon(Weapon weapon) {
|
|
|
|
|
|
if (weapon == null) {
|
|
|
|
|
|
return false;
|
|
|
|
|
|
}
|
|
|
|
|
|
String supportType = weapon.getSupportType();
|
|
|
|
|
|
String name = weapon.getName();
|
|
|
|
|
|
return (supportType != null && supportType.equals("ground"))
|
|
|
|
|
|
|| (name != null && (
|
|
|
|
|
|
name.contains("坦克")
|
|
|
|
|
|
|| name.contains("装甲车")
|
|
|
|
|
|
|| name.contains("迫击炮")
|
|
|
|
|
|
|| name.contains("迫榴炮")
|
|
|
|
|
|
|| name.contains("车载迫击炮")
|
|
|
|
|
|
|| name.contains("导弹发射车")
|
|
|
|
|
|
|| name.contains("反坦克")
|
|
|
|
|
|
));
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
function boolean isArtilleryWeapon(Weapon weapon) {
|
|
|
|
|
|
if (weapon == null || weapon.getName() == null) {
|
|
|
|
|
|
return false;
|
|
|
|
|
|
}
|
|
|
|
|
|
String name = weapon.getName();
|
|
|
|
|
|
return name.contains("迫榴炮")
|
|
|
|
|
|
|| name.contains("迫击炮")
|
|
|
|
|
|
|| name.contains("车载迫击炮")
|
|
|
|
|
|
|| name.contains("120mm");
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
function boolean isArmorWeapon(Weapon weapon) {
|
|
|
|
|
|
if (weapon == null || weapon.getName() == null) {
|
|
|
|
|
|
return false;
|
|
|
|
|
|
}
|
|
|
|
|
|
String name = weapon.getName();
|
|
|
|
|
|
return name.contains("主战坦克")
|
|
|
|
|
|
|| name.contains("坦克")
|
|
|
|
|
|
|| name.contains("装甲车");
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
function boolean hasMissileComponent(Weapon weapon) {
|
|
|
|
|
|
if (weapon == null || weapon.getComponents() == null) {
|
|
|
|
|
|
return false;
|
|
|
|
|
|
}
|
|
|
|
|
|
for (SubComponents c : weapon.getComponents()) {
|
|
|
|
|
|
if (c != null && c.getDeviceName() != null && c.getDeviceName().contains("导弹")) {
|
|
|
|
|
|
return true;
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
return false;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// ========== legacy 函数区(保留仅供回滚,不参与当前业务规则) ==========
|
|
|
|
|
|
function void matchLauncherComponents(
|
|
|
|
|
|
FactTask blueFact,
|
|
|
|
|
|
FactTask redFact,
|
|
|
|
|
|
String launcherName,
|
|
|
|
|
|
String redPlaneSupportType,
|
|
|
|
|
|
String redMissileVehicleKeyword,
|
|
|
|
|
|
String redMissileVehicleEnKeyword,
|
|
|
|
|
|
int redMoreThanBlueOffset,
|
|
|
|
|
|
int triggerBlueLauncherCount
|
|
|
|
|
|
) {
|
|
|
|
|
|
Task blueTask = blueFact.getBlueTask();
|
|
|
|
|
|
Task redTask = redFact.getRedTask();
|
|
|
|
|
|
if (blueTask == null || redTask == null) {
|
|
|
|
|
|
return;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
List<Weapon> blueWeapons = blueTask.getTaskWeapons();
|
|
|
|
|
|
List<Weapon> redWeapons = redTask.getTaskWeapons();
|
|
|
|
|
|
if (blueWeapons == null || redWeapons == null || redWeapons.isEmpty()) {
|
|
|
|
|
|
return;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
int blueLauncherCount = countLauncherComponents(blueWeapons, launcherName);
|
|
|
|
|
|
if (blueLauncherCount <= 0) {
|
|
|
|
|
|
return;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 规则1:红方若存在 plane 或导弹发射车,则这些武器都需要具备发射架
|
|
|
|
|
|
List<Weapon> candidateRedWeapons = new ArrayList<>();
|
|
|
|
|
|
for (Weapon redWeapon : redWeapons) {
|
|
|
|
|
|
if (isRedWeaponNeedLauncher(redWeapon, redPlaneSupportType, redMissileVehicleKeyword, redMissileVehicleEnKeyword)) {
|
|
|
|
|
|
candidateRedWeapons.add(redWeapon);
|
|
|
|
|
|
ensureWeaponHasLauncher(redWeapon, launcherName);
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
if (candidateRedWeapons.isEmpty()) {
|
|
|
|
|
|
return;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 规则2:当蓝方发射架数量达到触发值时,红方发射架数量 = 蓝方 + 可配置偏移量
|
|
|
|
|
|
if (blueLauncherCount == triggerBlueLauncherCount) {
|
|
|
|
|
|
int targetRedLauncherCount = blueLauncherCount + redMoreThanBlueOffset;
|
|
|
|
|
|
int currentRedLauncherCount = countLauncherComponents(redWeapons, launcherName);
|
|
|
|
|
|
int needAdd = targetRedLauncherCount - currentRedLauncherCount;
|
|
|
|
|
|
if (needAdd > 0) {
|
|
|
|
|
|
Weapon fallbackWeapon = candidateRedWeapons.get(0);
|
|
|
|
|
|
for (int i = 0; i < needAdd; i++) {
|
|
|
|
|
|
addLauncherToWeapon(fallbackWeapon, launcherName);
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
function boolean isRedWeaponNeedLauncher(
|
|
|
|
|
|
Weapon weapon,
|
|
|
|
|
|
String redPlaneSupportType,
|
|
|
|
|
|
String redMissileVehicleKeyword,
|
|
|
|
|
|
String redMissileVehicleEnKeyword
|
|
|
|
|
|
) {
|
|
|
|
|
|
if (weapon == null) {
|
|
|
|
|
|
return false;
|
|
|
|
|
|
}
|
|
|
|
|
|
String supportType = weapon.getSupportType();
|
|
|
|
|
|
String weaponName = weapon.getName();
|
|
|
|
|
|
return (supportType != null && supportType.equals(redPlaneSupportType))
|
|
|
|
|
|
|| (weaponName != null && (weaponName.contains(redMissileVehicleKeyword) || weaponName.contains(redMissileVehicleEnKeyword)));
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
function void ensureWeaponHasLauncher(Weapon weapon, String launcherName) {
|
|
|
|
|
|
if (weapon == null) {
|
|
|
|
|
|
return;
|
|
|
|
|
|
}
|
|
|
|
|
|
List<SubComponents> components = weapon.getComponents();
|
|
|
|
|
|
if (components == null) {
|
|
|
|
|
|
components = new ArrayList<>();
|
|
|
|
|
|
weapon.setComponents(components);
|
|
|
|
|
|
}
|
|
|
|
|
|
for (SubComponents component : components) {
|
|
|
|
|
|
if (component != null && component.getDeviceName() != null && component.getDeviceName().contains(launcherName)) {
|
|
|
|
|
|
return;
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
addLauncherToWeapon(weapon, launcherName);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
function void addLauncherToWeapon(Weapon weapon, String launcherName) {
|
|
|
|
|
|
List<SubComponents> components = weapon.getComponents();
|
|
|
|
|
|
if (components == null) {
|
|
|
|
|
|
components = new ArrayList<>();
|
|
|
|
|
|
weapon.setComponents(components);
|
|
|
|
|
|
}
|
|
|
|
|
|
SubComponents launcher = new SubComponents();
|
|
|
|
|
|
launcher.setDeviceName(launcherName);
|
|
|
|
|
|
components.add(launcher);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
function int countLauncherComponents(List weapons, String launcherName) {
|
|
|
|
|
|
if (weapons == null || weapons.isEmpty()) {
|
|
|
|
|
|
return 0;
|
|
|
|
|
|
}
|
|
|
|
|
|
int count = 0;
|
|
|
|
|
|
for (Object weaponObj : weapons) {
|
|
|
|
|
|
Weapon weapon = (Weapon) weaponObj;
|
|
|
|
|
|
if (weapon == null || weapon.getComponents() == null) {
|
|
|
|
|
|
continue;
|
|
|
|
|
|
}
|
|
|
|
|
|
for (SubComponents component : weapon.getComponents()) {
|
|
|
|
|
|
if (component != null && component.getDeviceName() != null && component.getDeviceName().contains(launcherName)) {
|
|
|
|
|
|
count++;
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
return count;
|
|
|
|
|
|
}
|
2026-03-27 11:35:17 +08:00
|
|
|
|
|
|
|
|
|
|
//威胁等级添加武器函数
|
2026-03-27 16:56:07 +08:00
|
|
|
|
function void threatLevels(FactTask redFact, Map params) {
|
2026-03-27 11:35:17 +08:00
|
|
|
|
// 创建武器列表
|
|
|
|
|
|
List<Weapon> weapons = new ArrayList<>();
|
|
|
|
|
|
|
|
|
|
|
|
// 创建导弹发射车
|
|
|
|
|
|
Weapon weapon1 = new Weapon();
|
|
|
|
|
|
weapon1.setNumber((Integer) params.get("platNum"));
|
|
|
|
|
|
weapon1.setSupportType("ground");
|
|
|
|
|
|
weapon1.setEquipmentId("1");
|
|
|
|
|
|
weapon1.setName("missile-launching-vehicle");
|
2026-03-27 16:56:07 +08:00
|
|
|
|
weapon1.setComponents(new ArrayList<>());
|
2026-03-27 11:35:17 +08:00
|
|
|
|
|
|
|
|
|
|
// 创建防空导弹武器
|
|
|
|
|
|
Weapon weapon2 = new Weapon();
|
|
|
|
|
|
weapon2.setNumber((Integer) params.get("platNum"));
|
|
|
|
|
|
weapon2.setSupportType("antiaircraft");
|
|
|
|
|
|
weapon2.setEquipmentId("2");
|
|
|
|
|
|
weapon2.setName("Anti-aircraft-missile-weapon");
|
2026-03-27 16:56:07 +08:00
|
|
|
|
weapon2.setComponents(new ArrayList<>());
|
2026-03-27 11:35:17 +08:00
|
|
|
|
|
|
|
|
|
|
// 添加到列表
|
|
|
|
|
|
weapons.add(weapon1);
|
|
|
|
|
|
weapons.add(weapon2);
|
|
|
|
|
|
|
|
|
|
|
|
// 设置到红方任务
|
|
|
|
|
|
redFact.getRedTask().setTaskWeapons(weapons);
|
|
|
|
|
|
}
|