use of games.strategy.engine.data.UnitType in project triplea by triplea-game.
the class UnitAttachment method setCreatesUnitsList.
private void setCreatesUnitsList(final String value) throws GameParseException {
final String[] s = value.split(":");
if (s.length <= 0 || s.length > 2) {
throw new GameParseException("createsUnitsList cannot be empty or have more than two fields" + thisErrorMsg());
}
final String unitTypeToProduce = s[1];
// validate that this unit exists in the xml
final UnitType ut = getData().getUnitTypeList().getUnitType(unitTypeToProduce);
if (ut == null) {
throw new GameParseException("createsUnitsList: No unit called:" + unitTypeToProduce + thisErrorMsg());
}
final int n = getInt(s[0]);
if (n < 1) {
throw new GameParseException("createsUnitsList must have positive values" + thisErrorMsg());
}
m_createsUnitsList.put(ut, n);
}
use of games.strategy.engine.data.UnitType in project triplea by triplea-game.
the class UnitAttachment method getListedUnits.
public Collection<UnitType> getListedUnits(final String[] list) {
final List<UnitType> unitTypes = new ArrayList<>();
for (final String name : list) {
// Validate all units exist
final UnitType ut = getData().getUnitTypeList().getUnitType(name);
if (ut == null) {
throw new IllegalStateException("No unit called: " + name + thisErrorMsg());
}
unitTypes.add(ut);
}
return unitTypes;
}
use of games.strategy.engine.data.UnitType in project triplea by triplea-game.
the class UnitAttachment method setTargetsAa.
private void setTargetsAa(final String value) throws GameParseException {
if (value == null) {
m_targetsAA = null;
return;
}
if (m_targetsAA == null) {
m_targetsAA = new HashSet<>();
}
final String[] s = value.split(":");
for (final String u : s) {
final UnitType ut = getData().getUnitTypeList().getUnitType(u);
if (ut == null) {
throw new GameParseException("AAtargets: no such unit type: " + u + thisErrorMsg());
}
m_targetsAA.add(ut);
}
}
use of games.strategy.engine.data.UnitType in project triplea by triplea-game.
the class UnitAttachment method toStringShortAndOnlyImportantDifferences.
/**
* Displays all unit options in a short description form that's user friendly rather than as XML.
* Shows all except for: m_constructionType, m_constructionsPerTerrPerTypePerTurn, m_maxConstructionsPerTypePerTerr,
* m_canBeGivenByTerritoryTo, m_destroyedWhenCapturedBy, m_canBeCapturedOnEnteringBy.
*/
public String toStringShortAndOnlyImportantDifferences(final PlayerID player, final boolean useHtml, final boolean includeAttachedToName) {
final StringBuilder stats = new StringBuilder();
final UnitType unitType = (UnitType) this.getAttachedTo();
if (includeAttachedToName && unitType != null) {
stats.append(unitType.getName()).append(": ");
}
if (getIsAir()) {
stats.append("Air unit, ");
} else if (getIsSea()) {
stats.append("Sea unit, ");
} else {
stats.append("Land unit, ");
}
final int attackRolls = getAttackRolls(player);
final int defenseRolls = getDefenseRolls(player);
if (getAttack(player) > 0) {
stats.append(attackRolls > 1 ? (attackRolls + "x ") : "").append(getAttack(player)).append(" Attack, ");
}
if (getDefense(player) > 0) {
stats.append(defenseRolls > 1 ? (defenseRolls + "x ") : "").append(getDefense(player)).append(" Defense, ");
}
if (getMovement(player) > 0) {
stats.append(getMovement(player)).append(" Movement, ");
}
if (getHitPoints() > 1) {
stats.append(getHitPoints()).append(" Hitpoints, ");
}
if (getCanProduceUnits() && getCanProduceXUnits() < 0) {
stats.append("can Produce Units Up To Territory Value, ");
} else if (getCanProduceUnits() && getCanProduceXUnits() > 0) {
stats.append("can Produce ").append(getCanProduceXUnits()).append(" Units, ");
}
if (getCreatesUnitsList() != null && getCreatesUnitsList().size() > 0) {
if (getCreatesUnitsList().size() > 4) {
stats.append("Produces ").append(getCreatesUnitsList().totalValues()).append(" Units Each Turn, ");
} else {
stats.append("Produces ");
for (final Entry<UnitType, Integer> entry : getCreatesUnitsList().entrySet()) {
stats.append(entry.getValue()).append("x").append(entry.getKey().getName()).append(" ");
}
stats.append("Each Turn, ");
}
}
if (getCreatesResourcesList() != null && getCreatesResourcesList().size() > 0) {
if (getCreatesResourcesList().size() > 4) {
stats.append("Produces ").append(getCreatesResourcesList().totalValues()).append(" Resources Each Turn, ");
} else {
stats.append("Produces ");
for (final Entry<Resource, Integer> entry : getCreatesResourcesList().entrySet()) {
stats.append(entry.getValue()).append("x").append(entry.getKey().getName()).append(" ");
}
stats.append("Each Turn, ");
}
}
if (getFuelCost() != null && getFuelCost().size() > 0) {
if (getFuelCost().size() > 4) {
stats.append("Uses ").append(m_fuelCost.totalValues()).append(" Resources Each movement point, ");
} else {
stats.append("Uses ");
for (final Entry<Resource, Integer> entry : getFuelCost().entrySet()) {
stats.append(entry.getValue()).append("x").append(entry.getKey().getName()).append(" ");
}
stats.append("Each movement point, ");
}
}
if (getFuelFlatCost() != null && getFuelFlatCost().size() > 0) {
if (getFuelFlatCost().size() > 4) {
stats.append("Uses ").append(m_fuelFlatCost.totalValues()).append(" Resources Each turn if moved, ");
} else {
stats.append("Uses ");
for (final Entry<Resource, Integer> entry : getFuelFlatCost().entrySet()) {
stats.append(entry.getValue()).append("x").append(entry.getKey().getName()).append(" ");
}
stats.append("Each turn if moved, ");
}
}
if ((getIsAaForCombatOnly() || getIsAaForBombingThisUnitOnly() || getIsAaForFlyOverOnly()) && (getAttackAa(player) > 0 || getOffensiveAttackAa(player) > 0)) {
if (getOffensiveAttackAa(player) > 0) {
stats.append(getOffensiveAttackAa(player)).append("/").append(getOffensiveAttackAaMaxDieSides() != -1 ? getOffensiveAttackAaMaxDieSides() : getData().getDiceSides()).append(" att ");
}
if (getAttackAa(player) > 0) {
stats.append(getAttackAa(player)).append("/").append(getAttackAaMaxDieSides() != -1 ? getAttackAaMaxDieSides() : getData().getDiceSides()).append(" def ");
}
if (getIsAaForCombatOnly() && getIsAaForBombingThisUnitOnly() && getIsAaForFlyOverOnly()) {
stats.append(getTypeAa()).append(", ");
} else if (getIsAaForCombatOnly() && getIsAaForFlyOverOnly() && !Properties.getAaTerritoryRestricted(getData())) {
stats.append(getTypeAa()).append(" for Combat & Move Through, ");
} else if (getIsAaForBombingThisUnitOnly() && getIsAaForFlyOverOnly() && !Properties.getAaTerritoryRestricted(getData())) {
stats.append(getTypeAa()).append(" for Raids & Move Through, ");
} else if (getIsAaForCombatOnly()) {
stats.append(getTypeAa()).append(" for Combat, ");
} else if (getIsAaForBombingThisUnitOnly()) {
stats.append(getTypeAa()).append(" for Raids, ");
} else if (getIsAaForFlyOverOnly()) {
stats.append(getTypeAa()).append(" for Move Through, ");
}
if (getMaxAaAttacks() > -1) {
stats.append(getMaxAaAttacks()).append(" ").append(getTypeAa()).append(" Attacks, ");
}
}
if (getIsRocket() && playerHasRockets(player)) {
stats.append("can Rocket Attack, ");
final int bombingBonus = getBombingBonus();
if ((getBombingMaxDieSides() != -1 || bombingBonus != 0) && Properties.getUseBombingMaxDiceSidesAndBonus(getData())) {
stats.append(bombingBonus != 0 ? bombingBonus + 1 : 1).append("-").append(getBombingMaxDieSides() != -1 ? getBombingMaxDieSides() + bombingBonus : getData().getDiceSides() + bombingBonus).append(" Rocket Damage, ");
} else {
stats.append("1-").append(getData().getDiceSides()).append(" Rocket Damage, ");
}
}
// line break
if (useHtml) {
stats.append("<br /> ");
}
if (getIsInfrastructure()) {
stats.append("can be Captured, ");
}
if (getIsConstruction()) {
stats.append("can be Placed Without Factory, ");
}
if ((getCanBeDamaged()) && Properties.getDamageFromBombingDoneToUnitsInsteadOfTerritories(getData())) {
stats.append("can be Damaged By Raids, ");
if (getMaxOperationalDamage() > -1) {
stats.append(getMaxOperationalDamage()).append(" Max Operational Damage, ");
}
if ((getCanProduceUnits()) && getCanProduceXUnits() < 0) {
stats.append("Total Damage up to ").append(getMaxDamage() > -1 ? getMaxDamage() : 2).append("x Territory Value, ");
} else if (getMaxDamage() > -1) {
stats.append(getMaxDamage()).append(" Max Total Damage, ");
}
if (getCanDieFromReachingMaxDamage()) {
stats.append("will Die If Max Damage Reached, ");
}
} else if (getCanBeDamaged()) {
stats.append("can be Attacked By Raids, ");
}
if (getIsAirBase() && Properties.getScrambleRulesInEffect(getData())) {
stats.append("can Allow Scrambling, ");
}
if (getCanScramble() && Properties.getScrambleRulesInEffect(getData())) {
stats.append("can Scramble ").append(getMaxScrambleDistance() > 0 ? getMaxScrambleDistance() : 1).append(" Distance, ");
}
if (getArtillery()) {
stats.append("can Give Attack Bonus To Other Units, ");
} else {
final List<UnitSupportAttachment> supports = CollectionUtils.getMatches(UnitSupportAttachment.get(unitType), Matches.unitSupportAttachmentCanBeUsedByPlayer(player));
if (supports.size() > 0) {
if (supports.size() > 2) {
stats.append("can Modify Power Of Other Units, ");
} else {
for (final UnitSupportAttachment support : supports) {
if (support.getUnitType() == null || support.getUnitType().isEmpty()) {
continue;
}
stats.append("gives ").append(support.getBonus()).append(support.getStrength() && support.getRoll() ? " Power&Rolls" : (support.getStrength() ? " Power" : " Rolls")).append(" to ").append(support.getNumber()).append(support.getAllied() && support.getEnemy() ? " Allied&Enemy " : (support.getAllied() ? " Allied " : " Enemy ")).append(support.getUnitType().size() > 4 ? "Units" : MyFormatter.defaultNamedToTextList(support.getUnitType(), "/", false)).append(" when ").append(support.getOffence() && support.getDefence() ? "Att/Def" : (support.getOffence() ? "Attacking" : "Defending")).append(", ");
}
}
}
}
if (getArtillerySupportable()) {
stats.append("can Receive Attack Bonus From Other Units, ");
}
if (getIsMarine() != 0) {
stats.append(getIsMarine()).append(" Amphibious Attack Modifier, ");
}
if (getCanBlitz(player)) {
stats.append("can Blitz, ");
}
if (!getReceivesAbilityWhenWith().isEmpty()) {
if (getReceivesAbilityWhenWith().size() <= 2) {
for (final String ability : getReceivesAbilityWhenWith()) {
stats.append("receives ").append(ability.split(":")[0]).append(" when paired with ").append(ability.split(":")[1]).append(", ");
}
} else {
stats.append("receives Abilities When Paired with Other Units, ");
}
}
if (getIsStrategicBomber()) {
stats.append("can Perform Raids, ");
final int bombingBonus = getBombingBonus();
if ((getBombingMaxDieSides() != -1 || bombingBonus != 0) && Properties.getUseBombingMaxDiceSidesAndBonus(getData())) {
stats.append(bombingBonus != 0 ? bombingBonus + 1 : 1).append("-").append(getBombingMaxDieSides() != -1 ? getBombingMaxDieSides() + bombingBonus : getData().getDiceSides() + bombingBonus).append(" Raid Damage, ");
} else {
stats.append("1-").append(getData().getDiceSides()).append(" Raid Damage, ");
}
}
final int airAttack = getAirAttack(player);
final int airDefense = getAirDefense(player);
if (airAttack > 0 && (getIsStrategicBomber() || getCanEscort() || getCanAirBattle())) {
stats.append(attackRolls > 1 ? (attackRolls + "x ") : "").append(airAttack).append(" Air Attack, ");
}
if (airDefense > 0 && (getCanIntercept() || getCanAirBattle())) {
stats.append(defenseRolls > 1 ? (defenseRolls + "x ") : "").append(airAttack).append(" Air Defense, ");
}
if (getIsSub()) {
stats.append("is Stealth, ");
}
if (getIsDestroyer()) {
stats.append("is Anti-Stealth, ");
}
if (getCanBombard(player) && getBombard() > 0) {
stats.append(getBombard()).append(" Bombard, ");
}
if (getBlockade() > 0) {
stats.append(getBlockade()).append(" Blockade Loss, ");
}
if (getIsSuicide()) {
stats.append("Suicide/Munition Unit, ");
}
if (getIsSuicideOnHit()) {
stats.append("SuicideOnHit Unit, ");
}
if (getIsAir() && (getIsKamikaze() || Properties.getKamikazeAirplanes(getData()))) {
stats.append("can use All Movement To Attack Target, ");
}
if ((getIsInfantry() || getIsLandTransportable()) && playerHasMechInf(player)) {
stats.append("can be Transported By Land, ");
}
if (getIsLandTransport() && playerHasMechInf(player)) {
stats.append("is a Land Transport, ");
}
if (getIsAirTransportable() && playerHasParatroopers(player)) {
stats.append("can be Transported By Air, ");
}
if (getIsAirTransport() && playerHasParatroopers(player)) {
stats.append("is an Air Transport, ");
}
if (getIsCombatTransport() && getTransportCapacity() > 0) {
stats.append("is a Combat Transport, ");
} else if (getTransportCapacity() > 0 && getIsSea()) {
stats.append("is a Sea Transport, ");
}
if (getTransportCost() > -1) {
stats.append(getTransportCost()).append(" Transporting Cost, ");
}
if (getTransportCapacity() > 0 && getIsSea()) {
stats.append(getTransportCapacity()).append(" Transporting Capacity, ");
} else if (getTransportCapacity() > 0 && getIsAir() && playerHasParatroopers(player)) {
stats.append(getTransportCapacity()).append(" Transporting Capacity, ");
} else if (getTransportCapacity() > 0 && playerHasMechInf(player) && !getIsSea() && !getIsAir()) {
stats.append(getTransportCapacity()).append(" Transporting Capacity, ");
}
if (getCarrierCost() > -1) {
stats.append(getCarrierCost()).append(" Carrier Cost, ");
}
if (getCarrierCapacity() > 0) {
stats.append(getCarrierCapacity()).append(" Carrier Capacity, ");
}
if (!getWhenCombatDamaged().isEmpty()) {
stats.append("when hit this unit loses certain abilities, ");
}
// line break
if (useHtml) {
stats.append("<br /> ");
}
if (getMaxBuiltPerPlayer() > -1) {
stats.append(getMaxBuiltPerPlayer()).append(" Max Built Allowed, ");
}
if (getRepairsUnits() != null && !getRepairsUnits().isEmpty() && Properties.getTwoHitPointUnitsRequireRepairFacilities(getData()) && (Properties.getBattleshipsRepairAtBeginningOfRound(getData()) || Properties.getBattleshipsRepairAtEndOfRound(getData()))) {
if (getRepairsUnits().size() <= 4) {
stats.append("can Repair: ").append(MyFormatter.integerDefaultNamedMapToString(getRepairsUnits(), " ", "=", false)).append(", ");
} else {
stats.append("can Repair Some Units, ");
}
}
if (getGivesMovement() != null && getGivesMovement().totalValues() > 0 && Properties.getUnitsMayGiveBonusMovement(getData())) {
if (getGivesMovement().size() <= 4) {
stats.append("can Modify Unit Movement: ").append(MyFormatter.integerDefaultNamedMapToString(getGivesMovement(), " ", "=", false)).append(", ");
} else {
stats.append("can Modify Unit Movement, ");
}
}
if (getConsumesUnits() != null && getConsumesUnits().totalValues() == 1) {
stats.append("unit is an Upgrade Of ").append(getConsumesUnits().keySet().iterator().next().getName()).append(", ");
} else if (getConsumesUnits() != null && getConsumesUnits().totalValues() > 0) {
if (getConsumesUnits().size() <= 4) {
stats.append("unit Consumes On Placement: ").append(MyFormatter.integerDefaultNamedMapToString(getConsumesUnits(), " ", "x", true)).append(", ");
} else {
stats.append("unit Consumes Other Units On Placement, ");
}
}
if (getRequiresUnits() != null && getRequiresUnits().size() > 0 && Properties.getUnitPlacementRestrictions(getData())) {
final List<String> totalUnitsListed = new ArrayList<>();
for (final String[] list : getRequiresUnits()) {
totalUnitsListed.addAll(Arrays.asList(list));
}
if (totalUnitsListed.size() > 4) {
stats.append("unit Requires Other Units Present To Be Placed, ");
} else {
stats.append("unit can only be Placed Where There Is: ");
stats.append(joinRequiredUnits(getRequiresUnits()));
stats.append(", ");
}
}
if (getRequiresUnitsToMove() != null && !getRequiresUnitsToMove().isEmpty()) {
final List<String> totalUnitsListed = new ArrayList<>();
for (final String[] list : getRequiresUnitsToMove()) {
totalUnitsListed.addAll(Arrays.asList(list));
}
if (totalUnitsListed.size() > 4) {
stats.append("unit Requires Other Units Present To Be Moved, ");
} else {
stats.append("unit can only be Moved Where There Is: ");
stats.append(joinRequiredUnits(getRequiresUnitsToMove()));
stats.append(", ");
}
}
if (getUnitPlacementRestrictions() != null && Properties.getUnitPlacementRestrictions(getData())) {
stats.append("has Placement Restrictions, ");
}
if (getCanOnlyBePlacedInTerritoryValuedAtX() > 0 && Properties.getUnitPlacementRestrictions(getData())) {
stats.append("must be Placed In Territory Valued >=").append(getCanOnlyBePlacedInTerritoryValuedAtX()).append(", ");
}
if (getCanNotMoveDuringCombatMove()) {
stats.append("cannot Combat Move, ");
}
if (getMovementLimit() != null) {
if (getMovementLimit().getFirst() == Integer.MAX_VALUE && (getIsAaForBombingThisUnitOnly() || getIsAaForCombatOnly()) && !(Properties.getWW2V2(getData()) || Properties.getWW2V3(getData()) || Properties.getMultipleAaPerTerritory(getData()))) {
stats.append("max of 1 ").append(getMovementLimit().getSecond()).append(" moving per territory, ");
} else if (getMovementLimit().getFirst() < 10000) {
stats.append("max of ").append(getMovementLimit().getFirst()).append(" ").append(getMovementLimit().getSecond()).append(" moving per territory, ");
}
}
if (getAttackingLimit() != null) {
if (getAttackingLimit().getFirst() == Integer.MAX_VALUE && (getIsAaForBombingThisUnitOnly() || getIsAaForCombatOnly()) && !(Properties.getWW2V2(getData()) || Properties.getWW2V3(getData()) || Properties.getMultipleAaPerTerritory(getData()))) {
stats.append("max of 1 ").append(getAttackingLimit().getSecond()).append(" attacking per territory, ");
} else if (getAttackingLimit().getFirst() < 10000) {
stats.append("max of ").append(getAttackingLimit().getFirst()).append(" ").append(getAttackingLimit().getSecond()).append(" attacking per territory, ");
}
}
if (getPlacementLimit() != null) {
if (getPlacementLimit().getFirst() == Integer.MAX_VALUE && (getIsAaForBombingThisUnitOnly() || getIsAaForCombatOnly()) && !(Properties.getWW2V2(getData()) || Properties.getWW2V3(getData()) || Properties.getMultipleAaPerTerritory(getData()))) {
stats.append("max of 1 ").append(getPlacementLimit().getSecond()).append(" placed per territory, ");
} else if (getPlacementLimit().getFirst() < 10000) {
stats.append("max of ").append(getPlacementLimit().getFirst()).append(" ").append(getPlacementLimit().getSecond()).append(" placed per territory, ");
}
}
if (stats.indexOf(", ") > -1) {
stats.delete(stats.lastIndexOf(", "), stats.length() - 1);
}
return stats.toString();
}
use of games.strategy.engine.data.UnitType in project triplea by triplea-game.
the class MoveValidator method validateBasic.
private static MoveValidationResult validateBasic(final GameData data, final Collection<Unit> units, final Route route, final PlayerID player, final Collection<Unit> transportsToLoad, final Map<Unit, Collection<Unit>> newDependents, final MoveValidationResult result) {
final boolean isEditMode = getEditMode(data);
// make sure transports in the destination
if (route.getEnd() != null && !route.getEnd().getUnits().containsAll(transportsToLoad) && !units.containsAll(transportsToLoad)) {
return result.setErrorReturnResult("Transports not found in route end");
}
if (!isEditMode) {
// Make sure all units are at least friendly
for (final Unit unit : CollectionUtils.getMatches(units, Matches.enemyUnit(player, data))) {
result.addDisallowedUnit("Can only move friendly units", unit);
}
// Ensure all air transports are included
for (final Unit airTransport : newDependents.keySet()) {
if (!units.contains(airTransport)) {
for (final Unit unit : newDependents.get(airTransport)) {
if (units.contains(unit)) {
result.addDisallowedUnit("Not all units have enough movement", unit);
}
}
}
}
// Ignore transported units
Collection<Unit> moveTest = new ArrayList<>(units);
if (route.getStart().isWater()) {
moveTest = MoveValidator.getNonLand(units);
}
final Map<Unit, Collection<Unit>> dependentsMap = getDependents(CollectionUtils.getMatches(units, Matches.unitCanTransport()));
final Set<Unit> dependents = dependentsMap.values().stream().flatMap(Collection::stream).collect(Collectors.toSet());
dependents.addAll(newDependents.values().stream().flatMap(Collection::stream).collect(Collectors.toSet()));
moveTest.removeAll(dependents);
// Can only move owned units except transported units or allied air on carriers
for (final Unit unit : CollectionUtils.getMatches(moveTest, Matches.unitIsOwnedBy(player).negate())) {
if (!(UnitAttachment.get(unit.getType()).getCarrierCost() > 0 && data.getRelationshipTracker().isAllied(player, unit.getOwner()))) {
result.addDisallowedUnit("Can only move own troops", unit);
}
}
// Check if units have enough movement accounting for land transports
// Land transports can either:
// 1. Transport units on a 1-to-1 basis (have no capacity set)
// 2. Transport like sea transports using capacity and cost
data.acquireReadLock();
try {
int numLandTransportsWithoutCapacity = getNumLandTransportsWithoutCapacity(units, player);
final IntegerMap<Unit> landTransportsWithCapacity = getLandTransportsWithCapacity(units, player);
moveTest = TransportUtils.sortByTransportCostDescending(moveTest);
for (final Unit unit : moveTest) {
if (!Matches.unitHasEnoughMovementForRoute(route).test(unit)) {
boolean unitOk = false;
if (Matches.unitIsOwnedBy(player).negate().test(unit) && Matches.alliedUnit(player, data).test(unit) && Matches.unitTypeCanLandOnCarrier().test(unit.getType()) && moveTest.stream().anyMatch(Matches.unitIsAlliedCarrier(unit.getOwner(), data))) {
// this is so that if the unit is owned by any ally and it is cargo, then it will not count.
// (shouldn't it be a dependent in this case??)
unitOk = true;
} else if (Matches.unitHasNotMoved().test(unit) && Matches.unitIsLandTransportable().test(unit)) {
if (numLandTransportsWithoutCapacity > 0) {
numLandTransportsWithoutCapacity--;
unitOk = true;
} else {
for (final Unit transport : landTransportsWithCapacity.keySet()) {
final int cost = UnitAttachment.get((unit).getType()).getTransportCost();
if (cost <= landTransportsWithCapacity.getInt(transport)) {
landTransportsWithCapacity.add(transport, -cost);
unitOk = true;
break;
}
}
}
}
if (!unitOk) {
result.addDisallowedUnit("Not all units have enough movement", unit);
}
}
}
} finally {
data.releaseReadLock();
}
// if there is a neutral in the middle must stop unless all are air or getNeutralsBlitzable
if (route.hasNeutralBeforeEnd()) {
if ((units.isEmpty() || !units.stream().allMatch(Matches.unitIsAir())) && !isNeutralsBlitzable(data)) {
return result.setErrorReturnResult("Must stop land units when passing through neutral territories");
}
}
// a territory effect can disallow unit types in
if (units.stream().anyMatch(Matches.unitIsOfTypes(TerritoryEffectHelper.getUnitTypesForUnitsNotAllowedIntoTerritory(route.getSteps())))) {
return result.setErrorReturnResult("Territory Effects disallow some units into " + (route.numberOfSteps() > 1 ? "these territories" : "this territory"));
}
// Check requiresUnitsToMove conditions
Collection<Unit> requiresUnitsToMoveList = moveTest;
if (route.isUnload()) {
requiresUnitsToMoveList = units;
}
for (final Territory t : route.getAllTerritories()) {
if (!requiresUnitsToMoveList.stream().allMatch(Matches.unitHasRequiredUnitsToMove(t, data))) {
return result.setErrorReturnResult(t.getName() + " doesn't have the required units to allow moving the selected units into it");
}
}
}
// make sure that no non sea non transportable no carriable units end at sea
if (route.getEnd() != null && route.getEnd().isWater()) {
for (final Unit unit : MoveValidator.getUnitsThatCantGoOnWater(units)) {
result.addDisallowedUnit("Not all units can end at water", unit);
}
}
// if we are water make sure no land
if (units.stream().anyMatch(Matches.unitIsSea())) {
if (route.hasLand()) {
for (final Unit unit : CollectionUtils.getMatches(units, Matches.unitIsSea())) {
result.addDisallowedUnit("Sea units cannot go on land", unit);
}
}
}
// test for stack limits per unit
if (route.getEnd() != null) {
final Collection<Unit> unitsWithStackingLimits = CollectionUtils.getMatches(units, Matches.unitHasMovementLimit().or(Matches.unitHasAttackingLimit()));
for (final Territory t : route.getSteps()) {
final Collection<Unit> unitsAllowedSoFar = new ArrayList<>();
if (Matches.isTerritoryEnemyAndNotUnownedWater(player, data).test(t) || t.getUnits().anyMatch(Matches.unitIsEnemyOf(data, player))) {
for (final Unit unit : unitsWithStackingLimits) {
final UnitType ut = unit.getType();
int maxAllowed = UnitAttachment.getMaximumNumberOfThisUnitTypeToReachStackingLimit("attackingLimit", ut, t, player, data);
maxAllowed -= CollectionUtils.countMatches(unitsAllowedSoFar, Matches.unitIsOfType(ut));
if (maxAllowed > 0) {
unitsAllowedSoFar.add(unit);
} else {
result.addDisallowedUnit("UnitType " + ut.getName() + " has reached stacking limit", unit);
}
}
if (!PlayerAttachment.getCanTheseUnitsMoveWithoutViolatingStackingLimit("attackingLimit", units, t, player, data)) {
return result.setErrorReturnResult("Units Cannot Go Over Stacking Limit");
}
} else {
for (final Unit unit : unitsWithStackingLimits) {
final UnitType ut = unit.getType();
int maxAllowed = UnitAttachment.getMaximumNumberOfThisUnitTypeToReachStackingLimit("movementLimit", ut, t, player, data);
maxAllowed -= CollectionUtils.countMatches(unitsAllowedSoFar, Matches.unitIsOfType(ut));
if (maxAllowed > 0) {
unitsAllowedSoFar.add(unit);
} else {
result.addDisallowedUnit("UnitType " + ut.getName() + " has reached stacking limit", unit);
}
}
if (!PlayerAttachment.getCanTheseUnitsMoveWithoutViolatingStackingLimit("movementLimit", units, t, player, data)) {
return result.setErrorReturnResult("Units Cannot Go Over Stacking Limit");
}
}
}
}
// Don't allow move through impassable territories
if (!isEditMode && route.anyMatch(Matches.territoryIsImpassable())) {
return result.setErrorReturnResult(CANT_MOVE_THROUGH_IMPASSABLE);
}
if (canCrossNeutralTerritory(data, route, player, result).getError() != null) {
return result;
}
if (isNeutralsImpassable(data) && !isNeutralsBlitzable(data) && !route.getMatches(Matches.territoryIsNeutralButNotWater()).isEmpty()) {
return result.setErrorReturnResult(CANNOT_VIOLATE_NEUTRALITY);
}
return result;
}
Aggregations