Files
auto-solution/auto-solution-rule/src/main/resources/rules/fire-rule.drl

1033 lines
38 KiB
Plaintext
Raw Normal View History

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;
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 11:35:17 +08:00
rule "任务匹配1"
2026-03-27 10:27:04 +08:00
agenda-group "打击任务"
salience 100
2026-03-27 10:27:04 +08:00
when
2026-03-27 11:35:17 +08:00
then
// legacy 占位:旧的固定字符串匹配已停用,改由“任务自动匹配规则”统一处理。
2026-03-27 11:35:17 +08:00
end
//-------------------------------------------------------------------------------
rule "任务匹配2"
agenda-group "打击任务"
salience 100
2026-03-27 11:35:17 +08:00
when
then
// legacy 占位:旧的固定字符串匹配已停用,改由“任务自动匹配规则”统一处理。
2026-03-27 11:35:17 +08:00
end
//-------------------------------------------------------------------------------
rule "威胁等级规则"
agenda-group "打击任务"
salience 90
2026-03-27 11:35:17 +08:00
when
//如果蓝方威胁等级大于等于3则全局武器数量为3添加插入导弹发射车辆和防空导弹武器
$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固定插入导弹发射车辆
// ========== 调用函数 ==========
threatLevels($redTask, globalParams);
2026-03-27 11:35:17 +08:00
end
//-------------------------------------------------------------------------------
rule "地面类型匹配规则"
agenda-group "打击任务"
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
//-------------------------------------------------------------------------------
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
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
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
//威胁等级添加武器函数
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");
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");
weapon2.setComponents(new ArrayList<>());
2026-03-27 11:35:17 +08:00
// 添加到列表
weapons.add(weapon1);
weapons.add(weapon2);
// 设置到红方任务
redFact.getRedTask().setTaskWeapons(weapons);
}