use of games.strategy.triplea.attachments.RulesAttachment in project triplea by triplea-game.
the class AbstractPlaceDelegate method getMaxUnitsToBePlacedFrom.
/**
* Returns -1 if can place unlimited units.
*/
protected int getMaxUnitsToBePlacedFrom(final Territory producer, final Collection<Unit> units, final Territory to, final PlayerID player, final boolean countSwitchedProductionToNeighbors, final Collection<Territory> notUsableAsOtherProducers, final Map<Territory, Integer> currentAvailablePlacementForOtherProducers) {
// we may have special units with requiresUnits restrictions
final Collection<Unit> unitsCanBePlacedByThisProducer = (isUnitPlacementRestrictions() ? CollectionUtils.getMatches(units, unitWhichRequiresUnitsHasRequiredUnits(producer, true)) : new ArrayList<>(units));
if (unitsCanBePlacedByThisProducer.size() <= 0) {
return 0;
}
// if its an original factory then unlimited production
// Can be null!
final TerritoryAttachment ta = TerritoryAttachment.get(producer);
final Predicate<Unit> factoryMatch = Matches.unitIsOwnedAndIsFactoryOrCanProduceUnits(player).and(Matches.unitIsBeingTransported().negate()).and(producer.isWater() ? Matches.unitIsLand().negate() : Matches.unitIsSea().negate());
final Collection<Unit> factoryUnits = producer.getUnits().getMatches(factoryMatch);
// boolean placementRestrictedByFactory = isPlacementRestrictedByFactory();
final boolean unitPlacementPerTerritoryRestricted = isUnitPlacementPerTerritoryRestricted();
final boolean originalFactory = (ta != null && ta.getOriginalFactory());
final boolean playerIsOriginalOwner = factoryUnits.size() > 0 && this.player.equals(getOriginalFactoryOwner(producer));
final RulesAttachment ra = (RulesAttachment) player.getAttachment(Constants.RULES_ATTACHMENT_NAME);
final Collection<Unit> alreadProducedUnits = getAlreadyProduced(producer);
final int unitCountAlreadyProduced = alreadProducedUnits.size();
if (originalFactory && playerIsOriginalOwner) {
if (ra != null && ra.getMaxPlacePerTerritory() != -1) {
return Math.max(0, ra.getMaxPlacePerTerritory() - unitCountAlreadyProduced);
}
return -1;
}
// Restricts based on the STARTING number of units in a territory (otherwise it is infinite placement)
if (unitPlacementPerTerritoryRestricted) {
if (ra != null && ra.getPlacementPerTerritory() > 0) {
final int allowedPlacement = ra.getPlacementPerTerritory();
final int ownedUnitsInTerritory = CollectionUtils.countMatches(to.getUnits().getUnits(), Matches.unitIsOwnedBy(player));
if (ownedUnitsInTerritory >= allowedPlacement) {
return 0;
}
if (ra.getMaxPlacePerTerritory() == -1) {
return -1;
}
return Math.max(0, ra.getMaxPlacePerTerritory() - unitCountAlreadyProduced);
}
}
// a factory can produce the same number of units as the number of PUs the territory generates each turn (or not, if
// it has canProduceXUnits)
final int maxConstructions = howManyOfEachConstructionCanPlace(to, producer, unitsCanBePlacedByThisProducer, player).totalValues();
final boolean wasFactoryThereAtStart = wasOwnedUnitThatCanProduceUnitsOrIsFactoryInTerritoryAtStartOfStep(producer, player);
// If there's NO factory, allow placement of the factory
if (!wasFactoryThereAtStart) {
if (ra != null && ra.getMaxPlacePerTerritory() > 0) {
return Math.max(0, Math.min(maxConstructions, ra.getMaxPlacePerTerritory() - unitCountAlreadyProduced));
}
return Math.max(0, maxConstructions);
}
// getHowMuchCanUnitProduce accounts for IncreasedFactoryProduction, but does not account for maxConstructions
int production = TripleAUnit.getProductionPotentialOfTerritory(unitsAtStartOfStepInTerritory(producer), producer, player, getData(), true, true);
// increase the production by the number of constructions allowed
if (maxConstructions > 0) {
production += maxConstructions;
}
// return 0 if less than 0
if (production < 0) {
return 0;
}
production += CollectionUtils.countMatches(alreadProducedUnits, Matches.unitIsConstruction());
// Now we check if units we have already produced here could be produced by a different producer
int unitCountHaveToAndHaveBeenBeProducedHere = unitCountAlreadyProduced;
if (countSwitchedProductionToNeighbors && unitCountAlreadyProduced > 0) {
if (notUsableAsOtherProducers == null) {
throw new IllegalStateException("notUsableAsOtherProducers cannot be null if countSwitchedProductionToNeighbors is true");
}
if (currentAvailablePlacementForOtherProducers == null) {
throw new IllegalStateException("currentAvailablePlacementForOtherProducers cannot be null if countSwitchedProductionToNeighbors is true");
}
int productionCanNotBeMoved = 0;
int productionThatCanBeTakenOver = 0;
// try to find a placement move (to an adjacent sea zone) that can be taken over by some other territory factory
for (final UndoablePlacement placementMove : placements) {
if (placementMove.getProducerTerritory().equals(producer)) {
final Territory placeTerritory = placementMove.getPlaceTerritory();
final Collection<Unit> unitsPlacedByCurrentPlacementMove = placementMove.getUnits();
// for our special 'move shit around' methods.
if (!placeTerritory.isWater() || (isUnitPlacementRestrictions() && unitsPlacedByCurrentPlacementMove.stream().anyMatch(Matches.unitRequiresUnitsOnCreation()))) {
productionCanNotBeMoved += unitsPlacedByCurrentPlacementMove.size();
} else {
final int maxProductionThatCanBeTakenOverFromThisPlacement = unitsPlacedByCurrentPlacementMove.size();
// find other producers for this placement move to the same water territory
final List<Territory> newPotentialOtherProducers = getAllProducers(placeTerritory, player, unitsCanBePlacedByThisProducer);
newPotentialOtherProducers.removeAll(notUsableAsOtherProducers);
newPotentialOtherProducers.sort(getBestProducerComparator(placeTerritory, unitsCanBePlacedByThisProducer, player));
int productionThatCanBeTakenOverFromThisPlacement = 0;
for (final Territory potentialOtherProducer : newPotentialOtherProducers) {
Integer potential = currentAvailablePlacementForOtherProducers.get(potentialOtherProducer);
if (potential == null) {
potential = getMaxUnitsToBePlacedFrom(potentialOtherProducer, unitsPlacedInTerritorySoFar(placeTerritory), placeTerritory, player);
}
if (potential == -1) {
currentAvailablePlacementForOtherProducers.put(potentialOtherProducer, -1);
productionThatCanBeTakenOverFromThisPlacement = maxProductionThatCanBeTakenOverFromThisPlacement;
break;
}
final int needed = maxProductionThatCanBeTakenOverFromThisPlacement - productionThatCanBeTakenOverFromThisPlacement;
final int surplus = potential - needed;
if (surplus > 0) {
currentAvailablePlacementForOtherProducers.put(potentialOtherProducer, surplus);
productionThatCanBeTakenOverFromThisPlacement += needed;
} else {
currentAvailablePlacementForOtherProducers.put(potentialOtherProducer, 0);
productionThatCanBeTakenOverFromThisPlacement += potential;
notUsableAsOtherProducers.add(potentialOtherProducer);
}
if (surplus >= 0) {
break;
}
}
if (productionThatCanBeTakenOverFromThisPlacement > maxProductionThatCanBeTakenOverFromThisPlacement) {
throw new IllegalStateException("productionThatCanBeTakenOverFromThisPlacement should never be larger " + "than maxProductionThatCanBeTakenOverFromThisPlacement");
}
productionThatCanBeTakenOver += productionThatCanBeTakenOverFromThisPlacement;
}
if (productionThatCanBeTakenOver >= unitCountAlreadyProduced - productionCanNotBeMoved) {
break;
}
}
}
unitCountHaveToAndHaveBeenBeProducedHere = Math.max(0, unitCountAlreadyProduced - productionThatCanBeTakenOver);
}
if (ra != null && ra.getMaxPlacePerTerritory() > 0) {
return Math.max(0, Math.min(production - unitCountHaveToAndHaveBeenBeProducedHere, ra.getMaxPlacePerTerritory() - unitCountHaveToAndHaveBeenBeProducedHere));
}
return Math.max(0, production - unitCountHaveToAndHaveBeenBeProducedHere);
}
use of games.strategy.triplea.attachments.RulesAttachment in project triplea by triplea-game.
the class MoveValidator method validateMovementRestrictedByTerritory.
// Added to handle restriction of movement to listed territories
static MoveValidationResult validateMovementRestrictedByTerritory(final GameData data, final Route route, final PlayerID player, final MoveValidationResult result) {
if (getEditMode(data)) {
return result;
}
if (!isMovementByTerritoryRestricted(data)) {
return result;
}
final RulesAttachment ra = (RulesAttachment) player.getAttachment(Constants.RULES_ATTACHMENT_NAME);
if (ra == null || ra.getMovementRestrictionTerritories() == null) {
return result;
}
final String movementRestrictionType = ra.getMovementRestrictionType();
final Collection<Territory> listedTerritories = ra.getListedTerritories(ra.getMovementRestrictionTerritories(), true, true);
if (movementRestrictionType.equals("allowed")) {
for (final Territory current : route.getAllTerritories()) {
if (!listedTerritories.contains(current)) {
return result.setErrorReturnResult("Cannot move outside restricted territories");
}
}
} else if (movementRestrictionType.equals("disallowed")) {
for (final Territory current : route.getAllTerritories()) {
if (listedTerritories.contains(current)) {
return result.setErrorReturnResult("Cannot move to restricted territories");
}
}
}
return result;
}
use of games.strategy.triplea.attachments.RulesAttachment in project triplea by triplea-game.
the class NoPUPurchaseDelegate method getProductionUnits.
private Collection<Unit> getProductionUnits(final Collection<Territory> territories, final PlayerID player) {
final Collection<Unit> productionUnits = new ArrayList<>();
if (!(isProductionPerXTerritoriesRestricted() || isProductionPerValuedTerritoryRestricted())) {
return productionUnits;
}
IntegerMap<UnitType> productionPerXTerritories = new IntegerMap<>();
final RulesAttachment ra = (RulesAttachment) player.getAttachment(Constants.RULES_ATTACHMENT_NAME);
// isProductionPerValuedTerritoryRestricted, then they want 1 infantry for each territory with PU value > 0
if (isProductionPerValuedTerritoryRestricted() && (ra == null || ra.getProductionPerXTerritories() == null || ra.getProductionPerXTerritories().size() == 0)) {
productionPerXTerritories.put(getData().getUnitTypeList().getUnitType(Constants.UNIT_TYPE_INFANTRY), 1);
} else if (isProductionPerXTerritoriesRestricted()) {
productionPerXTerritories = ra.getProductionPerXTerritories();
} else {
return productionUnits;
}
final Collection<UnitType> unitTypes = new ArrayList<>(productionPerXTerritories.keySet());
for (final UnitType ut : unitTypes) {
int unitCount = 0;
final int prodPerXTerrs = productionPerXTerritories.getInt(ut);
if (isPacific) {
unitCount += getBurmaRoad(player);
}
int terrCount = 0;
for (final Territory current : territories) {
if (!isProductionPerValuedTerritoryRestricted()) {
terrCount++;
} else {
if (TerritoryAttachment.getProduction(current) > 0) {
terrCount++;
}
}
}
unitCount += terrCount / prodPerXTerrs;
productionUnits.addAll(getData().getUnitTypeList().getUnitType(ut.getName()).create(unitCount, player));
}
return productionUnits;
}
use of games.strategy.triplea.attachments.RulesAttachment in project triplea by triplea-game.
the class EndTurnDelegate method findNationalObjectiveAndTriggerResources.
/**
* Find the resources generated by national objectives and triggers that are currently met.
*/
public static IntegerMap<Resource> findNationalObjectiveAndTriggerResources(final PlayerID player, final GameData data) {
final IDelegateBridge bridge = new ObjectiveDummyDelegateBridge(data);
// Find and test all the conditions for triggers and national objectives
final Set<TriggerAttachment> triggers = new HashSet<>();
final List<RulesAttachment> objectives = new ArrayList<>();
final HashMap<ICondition, Boolean> testedConditions = testNationalObjectivesAndTriggers(player, data, bridge, triggers, objectives);
// Find triggers value
final IntegerMap<Resource> resources;
final boolean useTriggers = Properties.getTriggers(data);
if (useTriggers && !triggers.isEmpty()) {
final Set<TriggerAttachment> toFireTestedAndSatisfied = new HashSet<>(CollectionUtils.getMatches(triggers, AbstractTriggerAttachment.isSatisfiedMatch(testedConditions)));
resources = TriggerAttachment.findResourceIncome(toFireTestedAndSatisfied, bridge);
} else {
resources = new IntegerMap<>();
}
// Find national objectives value
int pus = 0;
for (final RulesAttachment rule : objectives) {
final int uses = rule.getUses();
if (uses == 0 || !rule.isSatisfied(testedConditions)) {
continue;
}
pus += (rule.getObjectiveValue() * rule.getEachMultiple() * Properties.getPuMultiplier(data));
}
resources.add(data.getResourceList().getResource(Constants.PUS), pus);
return resources;
}
use of games.strategy.triplea.attachments.RulesAttachment in project triplea by triplea-game.
the class EndTurnDelegate method determineNationalObjectives.
/**
* Determine if National Objectives have been met, and then do them.
*/
private String determineNationalObjectives(final IDelegateBridge bridge) {
final GameData data = getData();
final PlayerID player = data.getSequence().getStep().getPlayerId();
// Find and test all the conditions for triggers and national objectives
final Set<TriggerAttachment> triggers = new HashSet<>();
final List<RulesAttachment> objectives = new ArrayList<>();
final HashMap<ICondition, Boolean> testedConditions = testNationalObjectivesAndTriggers(player, data, bridge, triggers, objectives);
// Execute triggers
final StringBuilder endTurnReport = new StringBuilder();
final boolean useTriggers = Properties.getTriggers(data);
if (useTriggers && !triggers.isEmpty()) {
final Set<TriggerAttachment> toFireTestedAndSatisfied = new HashSet<>(CollectionUtils.getMatches(triggers, AbstractTriggerAttachment.isSatisfiedMatch(testedConditions)));
endTurnReport.append(TriggerAttachment.triggerResourceChange(toFireTestedAndSatisfied, bridge, null, null, true, true, true, true)).append("<br />");
}
// Execute national objectives
for (final RulesAttachment rule : objectives) {
int uses = rule.getUses();
if (uses == 0 || !rule.isSatisfied(testedConditions)) {
continue;
}
int toAdd = rule.getObjectiveValue();
toAdd *= Properties.getPuMultiplier(data);
toAdd *= rule.getEachMultiple();
int total = player.getResources().getQuantity(Constants.PUS) + toAdd;
if (total < 0) {
toAdd -= total;
total = 0;
}
final Change change = ChangeFactory.changeResourcesChange(player, data.getResourceList().getResource(Constants.PUS), toAdd);
bridge.addChange(change);
if (uses > 0) {
uses--;
final Change use = ChangeFactory.attachmentPropertyChange(rule, Integer.toString(uses), "uses");
bridge.addChange(use);
}
final String puMessage = MyFormatter.attachmentNameToText(rule.getName()) + ": " + player.getName() + " met a national objective for an additional " + toAdd + MyFormatter.pluralize(" PU", toAdd) + "; end with " + total + MyFormatter.pluralize(" PU", total);
bridge.getHistoryWriter().startEvent(puMessage);
endTurnReport.append(puMessage).append("<br />");
}
return endTurnReport.toString();
}
Aggregations