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

Exclude units by role on random generation, force generator table calculation updates #5572

Merged
merged 11 commits into from
Jun 16, 2024
34 changes: 20 additions & 14 deletions megamek/src/megamek/client/ratgenerator/AbstractUnitRecord.java
Original file line number Diff line number Diff line change
Expand Up @@ -40,26 +40,32 @@ public AbstractUnitRecord(String chassis) {
}

/**
* Adjusts availability rating for the first couple years after introduction.
* Returns availability value modified for rating differential on +/- rating, and adjusted for
* the first few years before introduction (field experiments, etc.) and immediately after
* introduction (low rate initial production).
*
* @param ar The AvailabilityRecord for the chassis or model.
* @param rating The force equipment rating.
* @param ratingLevels The number of equipment rating levels used by the faction.
* @param year The game year
* @return The adjusted availability rating.
* @param initialAv AvailabilityRating for the chassis or model.
* @param formationRating force equipment rating.
* @param ratingLevels number of equipment rating levels used by the faction.
* @param year game year
* @return adjusted availability rating.
*/
public int calcAvailability(AvailabilityRating ar, int rating, int ratingLevels, int year) {
int retVal = ar.adjustForRating(rating, ratingLevels);
public int calcAvailability(AvailabilityRating initialAv, int formationRating, int ratingLevels, int year) {
int avRating = initialAv.adjustForRating(formationRating, ratingLevels);

if (introYear == year) {
retVal -= 2;
if (year < introYear - 2) {
return 0;
} else if (year <= introYear) {
avRating -= 2;
} else if (year <= introYear + 1) {
avRating -= 1;
}
if (introYear == year + 1) {
retVal -= 1;
}
return Math.max(retVal, 0);

return Math.max(avRating, 0);
}



public String getChassis() {
return chassis;
}
Expand Down
19 changes: 16 additions & 3 deletions megamek/src/megamek/client/ratgenerator/AvailabilityRating.java
Original file line number Diff line number Diff line change
Expand Up @@ -107,13 +107,26 @@ public int getAvailability() {
return availability;
}

public int adjustForRating(int rating, int numLevels) {
if (rating < 0 || ratingAdjustment == 0) {
/**
* Return the availability taking into account +/- modifiers and a supplied rating. For example,
* an availability of 5+ will return 5 for an A-rating, 4 for a B rating, and so on; an
* availability of 5- will return 5 for an F-rating, 4 for a D-rating, and so on.
* @param rating numerical equivalent of rating value, from 0 to numLevels - 1
* @param numLevels how many ratings are in this system
* @return availability rating, modified for the provided rating; may return values
* less than zero
*/
public int adjustForRating (int rating, int numLevels) {
if (rating < 0 ||
ratingAdjustment == 0 ||
rating > numLevels - 1) {
return availability;
} else if (ratingAdjustment < 0) {
// '-' modifier provides a 0 modifier at the lowest rating
return availability - rating;
} else {
return availability - (numLevels - rating);
// '+' modifier provides a 0 modifier at the highest rating
return availability - ((numLevels - 1) - rating);
}
}

Expand Down
123 changes: 108 additions & 15 deletions megamek/src/megamek/client/ratgenerator/ChassisRecord.java
Original file line number Diff line number Diff line change
Expand Up @@ -13,46 +13,45 @@
*/
package megamek.client.ratgenerator;

import megamek.common.EntityMovementMode;
import megamek.common.EntityWeightClass;
import org.apache.logging.log4j.LogManager;

import java.util.ArrayList;
import java.util.Comparator;
import java.util.HashSet;
import java.util.List;
import java.util.*;

/**
* The ChassisRecord tracks all available variants and determines how much total weight
* is to be distributed among the various models.
*
*
* @author Neoancient
*/
public class ChassisRecord extends AbstractUnitRecord {

protected HashSet<ModelRecord> models;

public ChassisRecord(String chassis) {
super(chassis);
models = new HashSet<>();
}

public void addModel(ModelRecord model) {
models.add(model);
if (introYear == 0 || model.getIntroYear() < getIntroYear()) {
introYear = model.getIntroYear();
}
}

public HashSet<ModelRecord> getModels() {
return models;
}
public List<ModelRecord> getSortedModels() {

public List<ModelRecord> getSortedModels() {
List<ModelRecord> sortedModels = new ArrayList<>(models);
sortedModels.sort(Comparator.comparing(ModelRecord::getModel));
return sortedModels;

}

public int totalModelWeight(int era, String fKey) {
FactionRecord fRec = RATGenerator.getInstance().getFaction(fKey);
if (fRec == null) {
Expand All @@ -61,19 +60,113 @@ public int totalModelWeight(int era, String fKey) {
}
return totalModelWeight(era, fRec);
}


/**
* Calculate the total 'bucket weight' of all models for this chassis, first converting
* availability numbers to actual weight values (typically 2 ^ (AV / 2.0) ).
* Models which are introduced close to the era year may be included, even when the model's
* introduction date is later.
* @param era Year designator for the era to check e.g. 2765, 3058, 3067
* @param fRec RAT building data for the desired faction
* @return sum of all converted weights
*/

public int totalModelWeight(int era, FactionRecord fRec) {
int retVal = 0;
RATGenerator rg = RATGenerator.getInstance();

for (ModelRecord mr : models) {
AvailabilityRating ar = rg.findModelAvailabilityRecord(era,
mr.getKey(), fRec);
if (ar != null) {
retVal += AvailabilityRating.calcWeight(ar.getAvailability());
}
}

return retVal;
}


/**
* Calculate the total 'bucket weight' of models for this chassis, first converting
* availability numbers to actual weight values (typically 2 ^ (AV / 2.0) ).
* This overload allows a total weight to reflect various filter requirements, with models
* that don't meet filter requirements excluded from the total.
*
* @param era Year designator for the era to check e.g. 2765, 3058, 3067
* @param factionEraData RAT building data for the desired faction
* @param rating Formation rating
* @param year Specific year to check
* @param weightFilter {@link EntityWeightClass} constants with valid weight classes, or
* empty set to accept all
* @param networkFilter Mask for checking various C3 systems
* @param movementFilter Model must use at least one of these movement types
* @param roleStrictness
* @param rolesExcludeFilter Model may not have any of these roles
* @param roles Roles to select for
* @return int with total value of weight of all units which meet the filter
* requirements
*/
public int totalFilteredModelWeight (int era,
FactionRecord factionEraData,
int rating,
int ratingCounts,
int year,
Collection<Integer> weightFilter,
int networkFilter,
Collection<EntityMovementMode> movementFilter,
int roleStrictness,
Collection<MissionRole> roles,
Collection<MissionRole> rolesExcludeFilter) {
double totalWeight = 0;
RATGenerator generator = RATGenerator.getInstance();

for (ModelRecord curModel : models) {

// Models introduced more than 2 years from the current date are ignored. Those within
// two years are considered field testing/prototypes.
if (year < curModel.getIntroYear() - 2) {
continue;
}

// Weight class
if (!weightFilter.isEmpty() && !weightFilter.contains(curModel.getWeightClass())) {
continue;
}

// Movement types
if (!movementFilter.isEmpty() && !movementFilter.contains(curModel.getMovementMode())) {
continue;
}

// Invalid roles
if (!rolesExcludeFilter.isEmpty() && curModel.getRoles().stream().anyMatch(rolesExcludeFilter::contains)) {
continue;
}

// C3 systems
if ((networkFilter & curModel.getNetworkMask()) != networkFilter) {
continue;
}

// If the model is considered available, convert the value to a weight and add it
// to the total
AvailabilityRating modelAvRating = generator.findModelAvailabilityRecord(era,
curModel.getKey(), factionEraData);
if (modelAvRating != null) {

Double adjustedAvRating = (double) curModel.calcAvailability(modelAvRating,
rating, ratingCounts, year);

adjustedAvRating = MissionRole.adjustAvailabilityByRole(adjustedAvRating, roles, curModel, year, roleStrictness);
if (adjustedAvRating != null && adjustedAvRating > 0) {
totalWeight += AvailabilityRating.calcWeight(adjustedAvRating);
}
}

}

return (int) Math.floor(totalWeight);
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -324,7 +324,7 @@ private List<ModelRecord> generateFormation (List<ForceDescriptor> subs, int net
for (ForceDescriptor sub : subs) {
paramCount.merge(new UnitTable.Parameters(sub.getFactionRec(),
sub.getUnitType(), sub.getYear(), sub.ratGeneratorRating(), null, networkMask,
sub.getMovementModes(), sub.getRoles(), 0, sub.getFactionRec()), 1, Integer::sum);
sub.getMovementModes(), sub.getRoles(), new ArrayList<>(), 0, sub.getFactionRec()), 1, Integer::sum);
}

List<UnitTable.Parameters> params = new ArrayList<>();
Expand Down
Loading
Loading