Search in sources :

Example 16 with UnitType

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);
}
Also used : UnitType(games.strategy.engine.data.UnitType) GameParseException(games.strategy.engine.data.GameParseException)

Example 17 with UnitType

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;
}
Also used : UnitType(games.strategy.engine.data.UnitType) ArrayList(java.util.ArrayList)

Example 18 with UnitType

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);
    }
}
Also used : UnitType(games.strategy.engine.data.UnitType) GameParseException(games.strategy.engine.data.GameParseException)

Example 19 with UnitType

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 /> &nbsp;&nbsp;&nbsp;&nbsp; ");
    }
    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 /> &nbsp;&nbsp;&nbsp;&nbsp; ");
    }
    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();
}
Also used : Resource(games.strategy.engine.data.Resource) ArrayList(java.util.ArrayList) UnitType(games.strategy.engine.data.UnitType)

Example 20 with UnitType

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;
}
Also used : Territory(games.strategy.engine.data.Territory) UnitType(games.strategy.engine.data.UnitType) ArrayList(java.util.ArrayList) Collection(java.util.Collection) ResourceCollection(games.strategy.engine.data.ResourceCollection) TripleAUnit(games.strategy.triplea.TripleAUnit) Unit(games.strategy.engine.data.Unit)

Aggregations

UnitType (games.strategy.engine.data.UnitType)211 Test (org.junit.jupiter.api.Test)108 IntegerMap (games.strategy.util.IntegerMap)86 Route (games.strategy.engine.data.Route)76 Unit (games.strategy.engine.data.Unit)76 PlayerID (games.strategy.engine.data.PlayerID)64 Territory (games.strategy.engine.data.Territory)58 TripleAUnit (games.strategy.triplea.TripleAUnit)49 ArrayList (java.util.ArrayList)44 ITestDelegateBridge (games.strategy.engine.data.ITestDelegateBridge)36 GameParseException (games.strategy.engine.data.GameParseException)29 ScriptedRandomSource (games.strategy.engine.random.ScriptedRandomSource)23 UnitAttachment (games.strategy.triplea.attachments.UnitAttachment)21 HashSet (java.util.HashSet)17 GameData (games.strategy.engine.data.GameData)15 Change (games.strategy.engine.data.Change)14 CompositeChange (games.strategy.engine.data.CompositeChange)14 Resource (games.strategy.engine.data.Resource)13 NamedAttachable (games.strategy.engine.data.NamedAttachable)11 ProductionRule (games.strategy.engine.data.ProductionRule)11