Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix 6240: era-illegal asf bombs [Note: breaks MHQ] #6254

Open
wants to merge 9 commits into
base: master
Choose a base branch
from
123 changes: 90 additions & 33 deletions megamek/src/megamek/client/generator/TeamLoadOutGenerator.java
Original file line number Diff line number Diff line change
Expand Up @@ -340,6 +340,11 @@ public boolean checkLegality(AmmoType aType, String faction, String techBase, bo
boolean legal = false;
boolean clan = techBase.equals("CL");

// Null-type is illegal!
if (null == aType) {
return false;
}

// Check if tech exists at all (or is explicitly allowed despite being extinct)
// and whether it is available at the current tech level.
legal = aType.isAvailableIn(allowedYear, showExtinct)
Expand Down Expand Up @@ -1111,7 +1116,9 @@ public void reconfigureEntities(ArrayList<Entity> entities, String faction, Muni
reconfigurationParameters.groundMap
|| reconfigurationParameters.enemyCount > reconfigurationParameters.enemyFliers,
reconfigurationParameters.friendlyQuality,
reconfigurationParameters.isPirate);
reconfigurationParameters.isPirate,
faction
);
}

/**
Expand Down Expand Up @@ -1388,11 +1395,14 @@ private static String getRandomBin(String binName, boolean trueRandom) {
* @param quality IUnitRating enum for force quality (A/A* through F)
* @param isPirate true to use specific pirate ordnance loadouts
*/
public static void populateAeroBombs(List<Entity> entityList,
int year,
boolean hasGroundTargets,
int quality,
boolean isPirate) {
public void populateAeroBombs(
List<Entity> entityList,
int year,
boolean hasGroundTargets,
int quality,
boolean isPirate,
String faction
) {

// Get all valid bombers, and sort unarmed ones to the front
// Ignore VTOLs for now, as they suffer extra penalties for mounting bomb
Expand Down Expand Up @@ -1438,6 +1448,8 @@ public static void populateAeroBombs(List<Entity> entityList,

Entity curBomber = bomberList.get(i);
boolean isUnarmed = curBomber.getIndividualWeaponList().isEmpty();
String techBase = (curBomber.isClan()) ? "CL" : "IS";
boolean mixedTech = curBomber.isMixedTech();

// Some fighters on ground attack may be flying air cover rather than strictly
// air-to-ground
Expand Down Expand Up @@ -1477,7 +1489,11 @@ public static void populateAeroBombs(List<Entity> entityList,
isCAP,
isPirate,
quality,
year);
year,
faction,
techBase,
mixedTech
);
// Whoops, go yell at the ordnance technician
if (Arrays.stream(generatedBombs).sum() == 0) {
continue;
Expand Down Expand Up @@ -1549,11 +1565,16 @@ private static void loadBombsOntoBombers(List<Entity> bomberList, Map<Integer, i
* enums as the lookup e.g. [BombUnit.HE] will get the number of HE
* bombs.
*/
private static int[] generateExternalOrdnance(int bombUnits,
boolean airOnly,
boolean isPirate,
int quality,
int year) {
public int[] generateExternalOrdnance(
int bombUnits,
boolean airOnly,
boolean isPirate,
int quality,
int year,
String faction,
String techBase,
boolean mixedTech
) {

int[] bombLoad = new int[BombType.B_NUM];

Expand Down Expand Up @@ -1658,6 +1679,18 @@ private static int[] generateExternalOrdnance(int bombUnits,
// rockets or HE
Map<Integer, Integer> workingBombMap = new HashMap<>();
for (int curBombType : bombMap.keySet()) {
// Make sure the bomb type is even legal for the current scenario
if (
!checkLegality(
BombType.createBombByType(curBombType),
faction,
techBase,
mixedTech
)
) {
continue;
}

String typeName = BombType.getBombInternalName(curBombType);
if (curBombType == BombType.B_RL ||
curBombType == BombType.B_HE ||
Expand Down Expand Up @@ -1708,37 +1741,61 @@ private static int[] generateExternalOrdnance(int bombUnits,
completeWeight = ordnanceRandomWeights.stream().mapToInt(curWeight -> Math.max(curWeight, 1)).asDoubleStream()
.sum();

for (int curLoad = 0; curLoad < bombUnits && loopSafety < castPropertyInt("maxBombApplicationLoopCount", 10);) {
if (!ordnanceIDs.isEmpty() && !ordnanceRandomWeights.isEmpty() && completeWeight != 0) {
for (int curLoad = 0; curLoad < bombUnits && loopSafety < castPropertyInt("maxBombApplicationLoopCount", 10); ) {

// Randomly get the ordnance type
randomThreshold = (Compute.randomInt(
// Randomly get the ordnance type
randomThreshold = (Compute.randomInt(
castPropertyInt("maxBombOrdnanceWeightPercentThreshold", 100)) / 100.0) * completeWeight;
countWeight = 0.0;
for (int i = 0; i < ordnanceIDs.size(); i++) {
countWeight += Math.max(ordnanceRandomWeights.get(i), 1.0);
if (countWeight >= randomThreshold) {
selectedBombType = ordnanceIDs.get(i);
break;
countWeight = 0.0;
for (int i = 0; i < ordnanceIDs.size(); i++) {
countWeight += Math.max(ordnanceRandomWeights.get(i), 1.0);
if (countWeight >= randomThreshold) {
selectedBombType = ordnanceIDs.get(i);
break;
}
}
}

// If the selected ordnance doesn't exceed the provided limit increment the
// counter,
// otherwise skip it and keep trying with some safeties to prevent infinite
// loops.
if (selectedBombType >= 0 &&
// If the selected ordnance doesn't exceed the provided limit increment the
// counter,
// otherwise skip it and keep trying with some safeties to prevent infinite
// loops.
if (selectedBombType >= 0 &&
curLoad + BombType.getBombCost(selectedBombType) <= bombUnits) {
bombLoad[selectedBombType]++;
curLoad += BombType.getBombCost(selectedBombType);
} else {
loopSafety++;
bombLoad[selectedBombType]++;
curLoad += BombType.getBombCost(selectedBombType);
} else {
loopSafety++;
}
}
}

// Oops, nothing left - rocket launchers are always popular
if (Arrays.stream(bombLoad).sum() == 0) {
bombLoad[BombType.B_RL] = bombUnits;
return bombLoad;
// Rocket Launchers are a good option after CI era
if (
Copy link
Member

@SJuliez SJuliez Dec 13, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If I may say so, this feels slightly like newline overkill (the whole 7 lines or so)

checkLegality(
BombType.createBombByType(BombType.B_RL),
faction,
techBase,
mixedTech
)
) {
bombLoad[BombType.B_RL] = bombUnits;
return bombLoad;
}
// Otherwise, Prototype Rocket Launchers are almost always in style.
if (
checkLegality(
BombType.createBombByType(BombType.B_RLP),
faction,
techBase,
mixedTech
)
){
bombLoad[BombType.B_RLP] = bombUnits;
return bombLoad;
}
}

// Randomly replace advanced ordnance with rockets or HE, depending on force
Expand Down
47 changes: 42 additions & 5 deletions megamek/src/megamek/common/BombType.java
Original file line number Diff line number Diff line change
Expand Up @@ -41,28 +41,33 @@ public class BombType extends AmmoType {
public static final int B_ALAMO = 14;
public static final int B_FAE_SMALL = 15;
public static final int B_FAE_LARGE = 16;
public static final int B_NUM = 17;
// Rocket Launcher (Prototype) Pod
public static final int B_RLP = 17;
public static final int B_NUM = 18;

public static final String[] bombNames = { "HE Bomb","Cluster Bomb","Laser-guided Bomb",
"Rocket", "TAG", "AAA Missile", "AS Missile",
"ASEW Missile", "Arrow IV Missile",
"Arrow IV Homing Missile", "Inferno Bomb",
"LAA Missile", "Thunder Bomb", "Torpedo Bomb",
"Alamo Missile", "Fuel-Air Bomb (small)", "Fuel-Air Bomb (large)" };
"Alamo Missile", "Fuel-Air Bomb (small)", "Fuel-Air Bomb (large)",
"Prototype Rocket"};

public static final String[] bombInternalNames = { "HEBomb","ClusterBomb","LGBomb",
"RL 10 Ammo (Bomb)", "TAGBomb", "AAAMissile Ammo",
"ASMissile Ammo",
"ASEWMissile Ammo", "ArrowIVMissile Ammo",
"ArrowIVHomingMissile Ammo", "InfernoBomb",
"LAAMissile Ammo", "ThunderBomb", "TorpedoBomb",
"AlamoMissile Ammo", "FABombSmall Ammo", "FABombLarge Ammo" };
"AlamoMissile Ammo", "FABombSmall Ammo", "FABombLarge Ammo",
"RL-P 10 Ammo (Bomb)" };

public static final String[] bombWeaponNames = { null, null, null, "BombRL", "BombTAG", "AAA Missile",
"AS Missile", "ASEWMissile", "BombArrowIV", "BombArrowIV",
null, "LAAMissile", null, null, "AlamoMissile", null, null };
null, "LAAMissile", null, null, "AlamoMissile", null, null,
"BombRLP"};

public static final int[] bombCosts = { 1, 1, 1, 1, 1, 5, 6, 6, 5, 5, 1, 2, 1, 1, 10, 1, 2 };
public static final int[] bombCosts = { 1, 1, 1, 1, 1, 5, 6, 6, 5, 5, 1, 2, 1, 1, 10, 1, 2, 1 };

public static final Map<String, Integer> blastRadius;
private int bombType;
Expand Down Expand Up @@ -173,6 +178,7 @@ public static void initializeTypes() {
EquipmentType.addType(BombType.createLaserGuidedBomb());
// EquipmentType.addType(BombType.createCLLaserGuidedBomb());
EquipmentType.addType(BombType.createRocketBomb());
EquipmentType.addType(BombType.createPrototypeRocketBomb());
EquipmentType.addType(BombType.createTAGBomb());
// EquipmentType.addType(BombType.createCLTAGBomb());
EquipmentType.addType(BombType.createAAAMissileBomb());
Expand Down Expand Up @@ -242,6 +248,8 @@ public static BombType createBombByType(int bType) {
return createSmallFuelAirBomb();
case B_FAE_LARGE:
return createLargeFuelAirBomb();
case B_RLP:
return createPrototypeRocketBomb();
default:
return null;
}
Expand Down Expand Up @@ -631,6 +639,35 @@ private static BombType createRocketBomb() {
return bomb;
}

private static BombType createPrototypeRocketBomb() {
BombType bomb = new BombType();

bomb.name = "Rocket Launcher (Prototype) Pod";
bomb.setInternalName(BombType.getBombInternalName(BombType.B_RLP));
bomb.addLookupName("RL-P 10 (Bomb)");
bomb.damagePerShot = 1;
// This works but is fragile
bomb.flags = bomb.flags.or(AmmoType.F_OTHER_BOMB).or(WeaponType.F_PROTOTYPE);
bomb.rackSize = 10;
bomb.ammoType = AmmoType.T_RL_BOMB;
bomb.bombType = BombType.B_RLP;
bomb.shots = 1;
bomb.bv = 15;
bomb.cost = 15000;
bomb.rulesRefs = "73, 195, 217, IO";
bomb.techAdvancement.setTechBase(TECH_BASE_ALL)
.setIntroLevel(false)
.setUnofficial(false)
.setTechRating(RATING_B)
.setAvailability(RATING_D, RATING_F, RATING_X, RATING_X)
.setISAdvancement(DATE_ES, DATE_NONE, DATE_NONE, DATE_NONE, DATE_NONE)
.setISApproximate(true, false, false, false, false)
.setClanAdvancement(DATE_ES, DATE_NONE, DATE_NONE, 2823, DATE_NONE)
.setClanApproximate(true, false, false, true, false)
.setStaticTechLevel(SimpleTechLevel.EXPERIMENTAL);
return bomb;
}

private static BombType createTAGBomb() {
BombType bomb = new BombType();

Expand Down
1 change: 1 addition & 0 deletions megamek/src/megamek/common/WeaponType.java
Original file line number Diff line number Diff line change
Expand Up @@ -2061,6 +2061,7 @@ public static void initializeTypes() {
EquipmentType.addType(new ISBombTAG());
EquipmentType.addType(new CLBombTAG());
EquipmentType.addType(new BombISRL10());
EquipmentType.addType(new BombISRLP10());
EquipmentType.addType(new AlamoMissileWeapon());
EquipmentType.addType(new SpaceBombAttack());
EquipmentType.addType(new DiveBombAttack());
Expand Down
30 changes: 12 additions & 18 deletions megamek/src/megamek/common/weapons/RLHandler.java
Original file line number Diff line number Diff line change
@@ -1,14 +1,14 @@
/**
* MegaMek - Copyright (C) 2007 Ben Mazur ([email protected])
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the Free
* Software Foundation; either version 2 of the License, or (at your option)
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the Free
* Software Foundation; either version 2 of the License, or (at your option)
* any later version.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* for more details.
*/
package megamek.common.weapons;
Expand All @@ -17,20 +17,14 @@
import java.util.Enumeration;
import java.util.Vector;

import megamek.common.Coords;
import megamek.common.Entity;
import megamek.common.Game;
import megamek.common.Minefield;
import megamek.common.Report;
import megamek.common.Targetable;
import megamek.common.ToHitData;
import megamek.common.*;
import megamek.common.actions.WeaponAttackAction;
import megamek.server.totalwarfare.TWGameManager;

public class RLHandler extends MissileWeaponHandler {

/**
*
*
*/
private static final long serialVersionUID = -3848472655779311898L;

Expand All @@ -46,7 +40,7 @@ public RLHandler(ToHitData t, WeaponAttackAction w, Game g, TWGameManager m) {

/*
* (non-Javadoc)
*
*
* @see
* megamek.common.weapons.WeaponHandler#specialResolution(java.util.Vector,
* megamek.common.Entity, boolean)
Expand Down Expand Up @@ -79,4 +73,4 @@ protected boolean specialResolution(Vector<Report> vPhaseReport,
}
return false;
}
}
}
33 changes: 21 additions & 12 deletions megamek/src/megamek/common/weapons/bombs/BombISRL10.java
Original file line number Diff line number Diff line change
Expand Up @@ -13,10 +13,13 @@
*/
package megamek.common.weapons.bombs;

import megamek.common.AmmoType;
import megamek.common.BombType;
import megamek.common.TechAdvancement;
import megamek.common.*;
import megamek.common.actions.WeaponAttackAction;
import megamek.common.weapons.AttackHandler;
import megamek.common.weapons.PrototypeRLHandler;
import megamek.common.weapons.RLHandler;
import megamek.common.weapons.missiles.MissileWeapon;
import megamek.server.totalwarfare.TWGameManager;

/**
* @author Jay Lawson
Expand Down Expand Up @@ -48,14 +51,20 @@ public BombISRL10() {
this.toHitModifier = 1;
this.ammoType = AmmoType.T_RL_BOMB;
rulesRefs = "229, TM";
new TechAdvancement(TECH_BASE_IS)
.setIntroLevel(false)
.setUnofficial(false)
.setTechRating(RATING_B )
.setAvailability(RATING_X, RATING_X, RATING_B, RATING_B)
.setISAdvancement(3060, 3064, 3067, DATE_NONE, DATE_NONE)
.setISApproximate(true, false, false, false, false)
.setPrototypeFactions(F_MH)
.setProductionFactions(F_MH);
new TechAdvancement(TECH_BASE_IS)
.setIntroLevel(false)
.setUnofficial(false)
.setTechRating(RATING_B)
.setAvailability(RATING_X, RATING_X, RATING_B, RATING_B)
.setISAdvancement(3060, 3064, 3067, DATE_NONE, DATE_NONE)
.setISApproximate(true, false, false, false, false)
.setPrototypeFactions(F_MH)
.setProductionFactions(F_MH);
}

@Override
protected AttackHandler getCorrectHandler(ToHitData toHit,
WeaponAttackAction waa, Game game, TWGameManager manager) {
return new RLHandler(toHit, waa, game, manager);
}
}
Loading
Loading