use of games.strategy.triplea.attachments.UnitAttachment in project triplea by triplea-game.
the class BattleDelegate method resetMaxScrambleCount.
private static void resetMaxScrambleCount(final IDelegateBridge bridge) {
// reset the tripleaUnit property for all airbases that were used
final GameData data = bridge.getData();
if (!Properties.getScrambleRulesInEffect(data)) {
return;
}
final CompositeChange change = new CompositeChange();
for (final Territory t : data.getMap().getTerritories()) {
final Collection<Unit> airbases = t.getUnits().getMatches(Matches.unitIsAirBase());
for (final Unit u : airbases) {
final UnitAttachment ua = UnitAttachment.get(u.getType());
final int currentMax = ((TripleAUnit) u).getMaxScrambleCount();
final int allowedMax = ua.getMaxScrambleCount();
if (currentMax != allowedMax) {
change.add(ChangeFactory.unitPropertyChange(u, allowedMax, TripleAUnit.MAX_SCRAMBLE_COUNT));
}
}
}
if (!change.isEmpty()) {
bridge.getHistoryWriter().startEvent("Preparing Airbases for Possible Scrambling");
bridge.addChange(change);
}
}
use of games.strategy.triplea.attachments.UnitAttachment in project triplea by triplea-game.
the class AbstractPlaceDelegate method getUnitsToBePlacedAllDefault.
protected Collection<Unit> getUnitsToBePlacedAllDefault(final Territory to, final Collection<Unit> allUnits, final PlayerID player) {
final boolean water = to.isWater();
if (water && (!isWW2V2() && !isUnitPlacementInEnemySeas()) && to.getUnits().anyMatch(Matches.enemyUnit(player, getData()))) {
return null;
}
final Collection<Unit> units = new ArrayList<>(allUnits);
// if water, remove land. if land, remove water.
units.removeAll(CollectionUtils.getMatches(units, water ? Matches.unitIsLand() : Matches.unitIsSea()));
final Collection<Unit> placeableUnits = new ArrayList<>();
final Collection<Unit> unitsAtStartOfTurnInTo = unitsAtStartOfStepInTerritory(to);
final Collection<Unit> allProducedUnits = unitsPlacedInTerritorySoFar(to);
final boolean isBid = GameStepPropertiesHelper.isBid(getData());
final boolean wasFactoryThereAtStart = wasOwnedUnitThatCanProduceUnitsOrIsFactoryInTerritoryAtStartOfStep(to, player);
// we add factories and constructions later
if (water || wasFactoryThereAtStart || (!water && isPlayerAllowedToPlacementAnyTerritoryOwnedLand(player))) {
final Predicate<Unit> seaOrLandMatch = water ? Matches.unitIsSea() : Matches.unitIsLand();
placeableUnits.addAll(CollectionUtils.getMatches(units, seaOrLandMatch.and(Matches.unitIsNotConstruction())));
if (!water) {
placeableUnits.addAll(CollectionUtils.getMatches(units, Matches.unitIsAir().and(Matches.unitIsNotConstruction())));
} else if (((isBid || canProduceFightersOnCarriers() || AirThatCantLandUtil.isLhtrCarrierProduction(getData())) && allProducedUnits.stream().anyMatch(Matches.unitIsCarrier())) || ((isBid || canProduceNewFightersOnOldCarriers() || AirThatCantLandUtil.isLhtrCarrierProduction(getData())) && to.getUnits().anyMatch(Matches.unitIsCarrier()))) {
placeableUnits.addAll(CollectionUtils.getMatches(units, Matches.unitIsAir().and(Matches.unitCanLandOnCarrier())));
}
}
if (units.stream().anyMatch(Matches.unitIsConstruction())) {
final IntegerMap<String> constructionsMap = howManyOfEachConstructionCanPlace(to, to, units, player);
final Collection<Unit> skipUnits = new ArrayList<>();
for (final Unit currentUnit : CollectionUtils.getMatches(units, Matches.unitIsConstruction())) {
final int maxUnits = howManyOfConstructionUnit(currentUnit, constructionsMap);
if (maxUnits > 0) {
// max placement by constructionType of each unitType
if (skipUnits.contains(currentUnit)) {
continue;
}
placeableUnits.addAll(CollectionUtils.getNMatches(units, maxUnits, Matches.unitIsOfType(currentUnit.getType())));
skipUnits.addAll(CollectionUtils.getMatches(units, Matches.unitIsOfType(currentUnit.getType())));
}
}
}
// remove any units that require other units to be consumed on creation, if we don't have enough to consume (veqryn)
if (placeableUnits.stream().anyMatch(Matches.unitConsumesUnitsOnCreation())) {
final Collection<Unit> unitsWhichConsume = CollectionUtils.getMatches(placeableUnits, Matches.unitConsumesUnitsOnCreation());
for (final Unit unit : unitsWhichConsume) {
if (Matches.unitWhichConsumesUnitsHasRequiredUnits(unitsAtStartOfTurnInTo).negate().test(unit)) {
placeableUnits.remove(unit);
}
}
}
// now check stacking limits
final Collection<Unit> placeableUnits2 = new ArrayList<>();
final Collection<UnitType> typesAlreadyChecked = new ArrayList<>();
for (final Unit currentUnit : placeableUnits) {
final UnitType ut = currentUnit.getType();
if (typesAlreadyChecked.contains(ut)) {
continue;
}
typesAlreadyChecked.add(ut);
placeableUnits2.addAll(CollectionUtils.getNMatches(placeableUnits, UnitAttachment.getMaximumNumberOfThisUnitTypeToReachStackingLimit("placementLimit", ut, to, player, getData()), Matches.unitIsOfType(ut)));
}
if (!isUnitPlacementRestrictions()) {
return placeableUnits2;
}
final Collection<Unit> placeableUnits3 = new ArrayList<>();
for (final Unit currentUnit : placeableUnits2) {
final UnitAttachment ua = UnitAttachment.get(currentUnit.getType());
// Can be null!
final TerritoryAttachment ta = TerritoryAttachment.get(to);
if (ua.getCanOnlyBePlacedInTerritoryValuedAtX() != -1 && ua.getCanOnlyBePlacedInTerritoryValuedAtX() > (ta == null ? 0 : ta.getProduction())) {
continue;
}
if (unitWhichRequiresUnitsHasRequiredUnits(to, false).negate().test(currentUnit)) {
continue;
}
if (Matches.unitCanOnlyPlaceInOriginalTerritories().test(currentUnit) && !Matches.territoryIsOriginallyOwnedBy(player).test(to)) {
continue;
}
// account for any unit placement restrictions by territory
final String[] terrs = ua.getUnitPlacementRestrictions();
final Collection<Territory> listedTerrs = getListedTerritories(terrs);
if (!listedTerrs.contains(to)) {
placeableUnits3.add(currentUnit);
}
}
return placeableUnits3;
}
use of games.strategy.triplea.attachments.UnitAttachment in project triplea by triplea-game.
the class AbstractPlaceDelegate method canUnitsBePlaced.
public String canUnitsBePlaced(final Territory to, final Collection<Unit> units, final PlayerID player) {
final Collection<Unit> allowedUnits = getUnitsToBePlaced(to, units, player);
if (allowedUnits == null || !allowedUnits.containsAll(units)) {
return "Cannot place these units in " + to.getName();
}
final IntegerMap<String> constructionMap = howManyOfEachConstructionCanPlace(to, to, units, player);
for (final Unit currentUnit : CollectionUtils.getMatches(units, Matches.unitIsConstruction())) {
final UnitAttachment ua = UnitAttachment.get(currentUnit.getType());
/*
* if (ua.getIsFactory() && !ua.getIsConstruction())
* constructionMap.add("factory", -1);
* else
*/
constructionMap.add(ua.getConstructionType(), -1);
}
if (!constructionMap.isPositive()) {
return "Too many constructions in " + to.getName();
}
final List<Territory> capitalsListOwned = new ArrayList<>(TerritoryAttachment.getAllCurrentlyOwnedCapitals(player, getData()));
if (!capitalsListOwned.contains(to) && isPlacementInCapitalRestricted(player)) {
return "Cannot place these units outside of the capital";
}
if (to.isWater()) {
final String canLand = validateNewAirCanLandOnCarriers(to, units);
if (canLand != null) {
return canLand;
}
} else {
// make sure we own the territory
if (!to.getOwner().equals(player)) {
if (GameStepPropertiesHelper.isBid(getData())) {
final PlayerAttachment pa = PlayerAttachment.get(to.getOwner());
if ((pa == null || pa.getGiveUnitControl() == null || !pa.getGiveUnitControl().contains(player)) && !to.getUnits().anyMatch(Matches.unitIsOwnedBy(player))) {
return "You don't own " + to.getName();
}
} else {
return "You don't own " + to.getName();
}
}
// make sure all units are land
if (units.isEmpty() || !units.stream().allMatch(Matches.unitIsNotSea())) {
return "Cant place sea units on land";
}
}
// make sure we can place consuming units
if (!canWeConsumeUnits(units, to, false, null)) {
return "Not Enough Units To Upgrade or Be Consumed";
}
// now check for stacking limits
final Collection<UnitType> typesAlreadyChecked = new ArrayList<>();
for (final Unit currentUnit : units) {
final UnitType ut = currentUnit.getType();
if (typesAlreadyChecked.contains(ut)) {
continue;
}
typesAlreadyChecked.add(ut);
final int maxForThisType = UnitAttachment.getMaximumNumberOfThisUnitTypeToReachStackingLimit("placementLimit", ut, to, player, getData());
if (CollectionUtils.countMatches(units, Matches.unitIsOfType(ut)) > maxForThisType) {
return "UnitType " + ut.getName() + " is over stacking limit of " + maxForThisType;
}
}
if (!PlayerAttachment.getCanTheseUnitsMoveWithoutViolatingStackingLimit("placementLimit", units, to, player, getData())) {
return "Units Cannot Go Over Stacking Limit";
}
// now return null (valid placement) if we have placement restrictions disabled in game options
if (!isUnitPlacementRestrictions()) {
return null;
}
// account for any unit placement restrictions by territory
for (final Unit currentUnit : units) {
final UnitAttachment ua = UnitAttachment.get(currentUnit.getType());
// Can be null!
final TerritoryAttachment ta = TerritoryAttachment.get(to);
if (ua.getCanOnlyBePlacedInTerritoryValuedAtX() != -1 && ua.getCanOnlyBePlacedInTerritoryValuedAtX() > (ta == null ? 0 : ta.getProduction())) {
return "Cannot place these units in " + to.getName() + " due to Unit Placement Restrictions on Territory Value";
}
final String[] terrs = ua.getUnitPlacementRestrictions();
final Collection<Territory> listedTerrs = getListedTerritories(terrs);
if (listedTerrs.contains(to)) {
return "Cannot place these units in " + to.getName() + " due to Unit Placement Restrictions";
}
if (Matches.unitCanOnlyPlaceInOriginalTerritories().test(currentUnit) && !Matches.territoryIsOriginallyOwnedBy(player).test(to)) {
return "Cannot place these units in " + to.getName() + " as territory is not originally owned";
}
}
return null;
}
use of games.strategy.triplea.attachments.UnitAttachment in project triplea by triplea-game.
the class AbstractPlaceDelegate method howManyOfEachConstructionCanPlace.
/**
* @param to
* referring territory.
* @param units
* units to place
* @param player
* PlayerID
* @return an empty IntegerMap if you can't produce any constructions (will never return null)
*/
public IntegerMap<String> howManyOfEachConstructionCanPlace(final Territory to, final Territory producer, final Collection<Unit> units, final PlayerID player) {
// constructions can ONLY be produced BY the same territory that they are going into!
if (!to.equals(producer) || units == null || units.isEmpty() || units.stream().noneMatch(Matches.unitIsConstruction())) {
return new IntegerMap<>();
}
final Collection<Unit> unitsAtStartOfTurnInTo = unitsAtStartOfStepInTerritory(to);
final Collection<Unit> unitsInTo = to.getUnits().getUnits();
final Collection<Unit> unitsPlacedAlready = getAlreadyProduced(to);
// build an integer map of each unit we have in our list of held units, as well as integer maps for maximum units
// and units per turn
final IntegerMap<String> unitMapHeld = new IntegerMap<>();
final IntegerMap<String> unitMapMaxType = new IntegerMap<>();
final IntegerMap<String> unitMapTypePerTurn = new IntegerMap<>();
final int maxFactory = Properties.getFactoriesPerCountry(getData());
// Can be null!
final TerritoryAttachment terrAttachment = TerritoryAttachment.get(to);
int toProduction = 0;
if (terrAttachment != null) {
toProduction = terrAttachment.getProduction();
}
for (final Unit currentUnit : CollectionUtils.getMatches(units, Matches.unitIsConstruction())) {
final UnitAttachment ua = UnitAttachment.get(currentUnit.getType());
// account for any unit placement restrictions by territory
if (isUnitPlacementRestrictions()) {
final String[] terrs = ua.getUnitPlacementRestrictions();
final Collection<Territory> listedTerrs = getListedTerritories(terrs);
if (listedTerrs.contains(to)) {
continue;
}
if (ua.getCanOnlyBePlacedInTerritoryValuedAtX() != -1 && ua.getCanOnlyBePlacedInTerritoryValuedAtX() > toProduction) {
continue;
}
if (unitWhichRequiresUnitsHasRequiredUnits(to, false).negate().test(currentUnit)) {
continue;
}
}
// remove any units that require other units to be consumed on creation (veqryn)
if (Matches.unitConsumesUnitsOnCreation().test(currentUnit) && Matches.unitWhichConsumesUnitsHasRequiredUnits(unitsAtStartOfTurnInTo).negate().test(currentUnit)) {
continue;
}
unitMapHeld.add(ua.getConstructionType(), 1);
unitMapTypePerTurn.put(ua.getConstructionType(), ua.getConstructionsPerTerrPerTypePerTurn());
if (ua.getConstructionType().equals(Constants.CONSTRUCTION_TYPE_FACTORY)) {
unitMapMaxType.put(ua.getConstructionType(), maxFactory);
} else {
unitMapMaxType.put(ua.getConstructionType(), ua.getMaxConstructionsPerTypePerTerr());
}
}
final boolean moreWithoutFactory = Properties.getMoreConstructionsWithoutFactory(getData());
final boolean moreWithFactory = Properties.getMoreConstructionsWithFactory(getData());
final boolean unlimitedConstructions = Properties.getUnlimitedConstructions(getData());
final boolean wasFactoryThereAtStart = wasOwnedUnitThatCanProduceUnitsOrIsFactoryInTerritoryAtStartOfStep(to, player);
// build an integer map of each construction unit in the territory
final IntegerMap<String> unitMapTo = new IntegerMap<>();
if (unitsInTo.stream().anyMatch(Matches.unitIsConstruction())) {
for (final Unit currentUnit : CollectionUtils.getMatches(unitsInTo, Matches.unitIsConstruction())) {
final UnitAttachment ua = UnitAttachment.get(currentUnit.getType());
/*
* if (Matches.UnitIsFactory.test(currentUnit) && !ua.getIsConstruction())
* unitMapTO.add("factory", 1);
* else
*/
unitMapTo.add(ua.getConstructionType(), 1);
}
// account for units already in the territory, based on max
for (final String constructionType : unitMapHeld.keySet()) {
int unitMax = unitMapMaxType.getInt(constructionType);
if (wasFactoryThereAtStart && !constructionType.equals(Constants.CONSTRUCTION_TYPE_FACTORY) && !constructionType.endsWith("structure")) {
unitMax = Math.max(Math.max(unitMax, (moreWithFactory ? toProduction : 0)), (unlimitedConstructions ? 10000 : 0));
}
if (!wasFactoryThereAtStart && !constructionType.equals(Constants.CONSTRUCTION_TYPE_FACTORY) && !constructionType.endsWith("structure")) {
unitMax = Math.max(Math.max(unitMax, (moreWithoutFactory ? toProduction : 0)), (unlimitedConstructions ? 10000 : 0));
}
unitMapHeld.put(constructionType, Math.max(0, Math.min(unitMax - unitMapTo.getInt(constructionType), unitMapHeld.getInt(constructionType))));
}
}
// deal with already placed units
for (final Unit currentUnit : CollectionUtils.getMatches(unitsPlacedAlready, Matches.unitIsConstruction())) {
final UnitAttachment ua = UnitAttachment.get(currentUnit.getType());
unitMapTypePerTurn.add(ua.getConstructionType(), -1);
}
// modify this list based on how many we can place per turn
final IntegerMap<String> unitsAllowed = new IntegerMap<>();
for (final String constructionType : unitMapHeld.keySet()) {
final int unitAllowed = Math.max(0, Math.min(unitMapTypePerTurn.getInt(constructionType), unitMapHeld.getInt(constructionType)));
if (unitAllowed > 0) {
unitsAllowed.put(constructionType, unitAllowed);
}
}
// return our integer map
return unitsAllowed;
}
use of games.strategy.triplea.attachments.UnitAttachment in project triplea by triplea-game.
the class AirThatCantLandUtil method removeAirThatCantLand.
private void removeAirThatCantLand(final PlayerID player, final Territory territory, final Collection<Unit> airUnits) {
final Collection<Unit> toRemove = new ArrayList<>(airUnits.size());
// if we cant land on land then none can
if (!territory.isWater()) {
toRemove.addAll(airUnits);
} else {
// on water we may just no have enough carriers
// find the carrier capacity
final Collection<Unit> carriers = territory.getUnits().getMatches(Matches.alliedUnit(player, bridge.getData()));
int capacity = AirMovementValidator.carrierCapacity(carriers, territory);
for (final Unit unit : airUnits) {
final UnitAttachment ua = UnitAttachment.get(unit.getType());
final int cost = ua.getCarrierCost();
if (cost == -1 || cost > capacity) {
toRemove.add(unit);
} else {
capacity -= cost;
}
}
}
final Change remove = ChangeFactory.removeUnits(territory, toRemove);
final String transcriptText = MyFormatter.unitsToTextNoOwner(toRemove) + " could not land in " + territory.getName() + " and " + (toRemove.size() > 1 ? "were" : "was") + " removed";
bridge.getHistoryWriter().startEvent(transcriptText);
bridge.addChange(remove);
}
Aggregations