Search in sources :

Example 46 with Unit

use of games.strategy.engine.data.Unit in project triplea by triplea-game.

the class MoveDelegate method getLargestRepairRateForThisUnit.

/**
 * This has to be the exact same as Matches.UnitCanBeRepairedByFacilitiesInItsTerritory()
 */
private static int getLargestRepairRateForThisUnit(final Unit unitToBeRepaired, final Territory territoryUnitIsIn, final GameData data) {
    if (!Properties.getTwoHitPointUnitsRequireRepairFacilities(data)) {
        return 1;
    }
    final PlayerID owner = unitToBeRepaired.getOwner();
    final Predicate<Unit> repairUnit = Matches.alliedUnit(owner, data).and(Matches.unitCanRepairOthers()).and(Matches.unitCanRepairThisUnit(unitToBeRepaired, territoryUnitIsIn));
    final Set<Unit> repairUnitsForThisUnit = new HashSet<>(territoryUnitIsIn.getUnits().getMatches(repairUnit));
    if (Matches.unitIsSea().test(unitToBeRepaired)) {
        final List<Territory> neighbors = new ArrayList<>(data.getMap().getNeighbors(territoryUnitIsIn, Matches.territoryIsLand()));
        for (final Territory current : neighbors) {
            final Predicate<Unit> repairUnitLand = Matches.alliedUnit(owner, data).and(Matches.unitCanRepairOthers()).and(Matches.unitCanRepairThisUnit(unitToBeRepaired, current)).and(Matches.unitIsLand());
            repairUnitsForThisUnit.addAll(current.getUnits().getMatches(repairUnitLand));
        }
    } else if (Matches.unitIsLand().test(unitToBeRepaired)) {
        final List<Territory> neighbors = new ArrayList<>(data.getMap().getNeighbors(territoryUnitIsIn, Matches.territoryIsWater()));
        for (final Territory current : neighbors) {
            final Predicate<Unit> repairUnitSea = Matches.alliedUnit(owner, data).and(Matches.unitCanRepairOthers()).and(Matches.unitCanRepairThisUnit(unitToBeRepaired, current)).and(Matches.unitIsSea());
            repairUnitsForThisUnit.addAll(current.getUnits().getMatches(repairUnitSea));
        }
    }
    int largest = 0;
    for (final Unit u : repairUnitsForThisUnit) {
        final int repair = UnitAttachment.get(u.getType()).getRepairsUnits().getInt(unitToBeRepaired.getType());
        if (largest < repair) {
            largest = repair;
        }
    }
    return largest;
}
Also used : PlayerID(games.strategy.engine.data.PlayerID) Territory(games.strategy.engine.data.Territory) ArrayList(java.util.ArrayList) ArrayList(java.util.ArrayList) List(java.util.List) TripleAUnit(games.strategy.triplea.TripleAUnit) Unit(games.strategy.engine.data.Unit) HashSet(java.util.HashSet) Predicate(java.util.function.Predicate)

Example 47 with Unit

use of games.strategy.engine.data.Unit in project triplea by triplea-game.

the class MovePerformer method populateStack.

/**
 * We assume that the move is valid.
 */
private void populateStack(final Collection<Unit> units, final Route route, final PlayerID id, final Collection<Unit> transportsToLoad) {
    final IExecutable preAaFire = new IExecutable() {

        private static final long serialVersionUID = -7945930782650355037L;

        @Override
        public void execute(final ExecutionStack stack, final IDelegateBridge bridge) {
            // this can happen for air units moving out of a battle zone
            for (final IBattle battle : getBattleTracker().getPendingBattles(route.getStart(), null)) {
                for (final Unit unit : units) {
                    final Route routeUnitUsedToMove = moveDelegate.getRouteUsedToMoveInto(unit, route.getStart());
                    if (battle != null) {
                        battle.removeAttack(routeUnitUsedToMove, Collections.singleton(unit));
                    }
                }
            }
        }
    };
    // hack to allow the executables to share state
    final IExecutable fireAa = new IExecutable() {

        private static final long serialVersionUID = -3780228078499895244L;

        @Override
        public void execute(final ExecutionStack stack, final IDelegateBridge bridge) {
            final Collection<Unit> aaCasualties = fireAa(route, units);
            final Set<Unit> aaCasualtiesWithDependents = new HashSet<>();
            // need to remove any dependents here
            if (aaCasualties != null) {
                aaCasualtiesWithDependents.addAll(aaCasualties);
                final Map<Unit, Collection<Unit>> dependencies = TransportTracker.transporting(units, units);
                for (final Unit u : aaCasualties) {
                    final Collection<Unit> dependents = dependencies.get(u);
                    if (dependents != null) {
                        aaCasualtiesWithDependents.addAll(dependents);
                    }
                    // we might have new dependents too (ie: paratroopers)
                    final Collection<Unit> newDependents = m_newDependents.get(u);
                    if (newDependents != null) {
                        aaCasualtiesWithDependents.addAll(newDependents);
                    }
                }
            }
            arrivingUnits = CollectionUtils.difference(units, aaCasualtiesWithDependents);
        }
    };
    final IExecutable postAaFire = new IExecutable() {

        private static final long serialVersionUID = 670783657414493643L;

        @Override
        public void execute(final ExecutionStack stack, final IDelegateBridge bridge) {
            // if any non enemy territories on route
            // or if any enemy units on route the
            // battles on (note water could have enemy but its
            // not owned)
            final GameData data = bridge.getData();
            final Predicate<Territory> mustFightThrough = getMustFightThroughMatch(id, data);
            final Collection<Unit> arrived = Collections.unmodifiableList(CollectionUtils.intersection(units, arrivingUnits));
            // Reset Optional
            arrivingUnits = new ArrayList<>();
            final Collection<Unit> arrivedCopyForBattles = new ArrayList<>(arrived);
            final Map<Unit, Unit> transporting = TransportUtils.mapTransports(route, arrived, transportsToLoad);
            // If we have paratrooper land units being carried by air units, they should be dropped off in the last
            // territory. This means they
            // are still dependent during the middle steps of the route.
            final Collection<Unit> dependentOnSomethingTilTheEndOfRoute = new ArrayList<>();
            final Collection<Unit> airTransports = CollectionUtils.getMatches(arrived, Matches.unitIsAirTransport());
            final Collection<Unit> paratroops = CollectionUtils.getMatches(arrived, Matches.unitIsAirTransportable());
            if (!airTransports.isEmpty() && !paratroops.isEmpty()) {
                final Map<Unit, Unit> transportingAir = TransportUtils.mapTransportsToLoad(paratroops, airTransports);
                dependentOnSomethingTilTheEndOfRoute.addAll(transportingAir.keySet());
            }
            final Collection<Unit> presentFromStartTilEnd = new ArrayList<>(arrived);
            presentFromStartTilEnd.removeAll(dependentOnSomethingTilTheEndOfRoute);
            final CompositeChange change = new CompositeChange();
            // markFuelCostResourceChange must be done before we load/unload units
            change.add(Route.getFuelChanges(units, route, id, data));
            markTransportsMovement(arrived, transporting, route);
            if (route.anyMatch(mustFightThrough) && arrived.size() != 0) {
                boolean bombing = false;
                boolean ignoreBattle = false;
                // could it be a bombing raid
                final Collection<Unit> enemyUnits = route.getEnd().getUnits().getMatches(Matches.enemyUnit(id, data));
                final Collection<Unit> enemyTargetsTotal = CollectionUtils.getMatches(enemyUnits, Matches.unitCanBeDamaged().and(Matches.unitIsBeingTransported().negate()));
                final boolean canCreateAirBattle = !enemyTargetsTotal.isEmpty() && Properties.getRaidsMayBePreceededByAirBattles(data) && AirBattle.territoryCouldPossiblyHaveAirBattleDefenders(route.getEnd(), id, data, true);
                final Predicate<Unit> allBombingRaid = PredicateBuilder.of(Matches.unitIsStrategicBomber()).orIf(canCreateAirBattle, Matches.unitCanEscort()).build();
                final boolean allCanBomb = !arrived.isEmpty() && arrived.stream().allMatch(allBombingRaid);
                final Collection<Unit> enemyTargets = CollectionUtils.getMatches(enemyTargetsTotal, Matches.unitIsOfTypes(UnitAttachment.getAllowedBombingTargetsIntersection(CollectionUtils.getMatches(arrived, Matches.unitIsStrategicBomber()), data)));
                final boolean targetsOrEscort = !enemyTargets.isEmpty() || (!enemyTargetsTotal.isEmpty() && canCreateAirBattle && !arrived.isEmpty() && arrived.stream().allMatch(Matches.unitCanEscort()));
                boolean targetedAttack = false;
                // if it's all bombers and there's something to bomb
                if (allCanBomb && targetsOrEscort && GameStepPropertiesHelper.isCombatMove(data)) {
                    bombing = getRemotePlayer().shouldBomberBomb(route.getEnd());
                    // if bombing and there's something to target- ask what to bomb
                    if (bombing) {
                        // CompositeMatchOr<Unit> unitsToBeBombed = new CompositeMatchOr<Unit>(Matches.UnitIsFactory,
                        // Matches.UnitCanBeDamagedButIsNotFactory);
                        // determine which unit to bomb
                        final Unit target;
                        if (enemyTargets.size() > 1 && Properties.getDamageFromBombingDoneToUnitsInsteadOfTerritories(data) && !canCreateAirBattle) {
                            target = getRemotePlayer().whatShouldBomberBomb(route.getEnd(), enemyTargets, arrived);
                        } else if (!enemyTargets.isEmpty()) {
                            target = enemyTargets.iterator().next();
                        } else {
                            // in case we are escorts only
                            target = enemyTargetsTotal.iterator().next();
                        }
                        if (target == null) {
                            bombing = false;
                            targetedAttack = false;
                        } else {
                            targetedAttack = true;
                            final HashMap<Unit, HashSet<Unit>> targets = new HashMap<>();
                            targets.put(target, new HashSet<>(arrived));
                            // createdBattle = true;
                            getBattleTracker().addBattle(route, arrivedCopyForBattles, bombing, id, MovePerformer.this.bridge, m_currentMove, dependentOnSomethingTilTheEndOfRoute, targets, false);
                        }
                    }
                }
                // Ignore Trn on Trn forces.
                if (isIgnoreTransportInMovement(bridge.getData())) {
                    final boolean allOwnedTransports = !arrived.isEmpty() && arrived.stream().allMatch(Matches.unitIsTransportButNotCombatTransport());
                    final boolean allEnemyTransports = !enemyUnits.isEmpty() && enemyUnits.stream().allMatch(Matches.unitIsTransportButNotCombatTransport());
                    // If everybody is a transport, don't create a battle
                    if (allOwnedTransports && allEnemyTransports) {
                        ignoreBattle = true;
                    }
                }
                if (!ignoreBattle && GameStepPropertiesHelper.isCombatMove(data) && !targetedAttack) {
                    // createdBattle = true;
                    if (bombing) {
                        getBattleTracker().addBombingBattle(route, arrivedCopyForBattles, id, MovePerformer.this.bridge, m_currentMove, dependentOnSomethingTilTheEndOfRoute);
                    } else {
                        getBattleTracker().addBattle(route, arrivedCopyForBattles, id, MovePerformer.this.bridge, m_currentMove, dependentOnSomethingTilTheEndOfRoute);
                    }
                }
                if (!ignoreBattle && GameStepPropertiesHelper.isNonCombatMove(data, false) && !targetedAttack) {
                    // difficult if we want these recorded in battle records).
                    for (final Territory t : route.getMatches(Matches.territoryIsOwnedByPlayerWhosRelationshipTypeCanTakeOverOwnedTerritoryAndPassableAndNotWater(id).and(Matches.territoryIsBlitzable(id, data)))) {
                        if (Matches.isTerritoryEnemy(id, data).test(t) || Matches.territoryHasEnemyUnits(id, data).test(t)) {
                            continue;
                        }
                        if ((t.equals(route.getEnd()) && !arrivedCopyForBattles.isEmpty() && arrivedCopyForBattles.stream().allMatch(Matches.unitIsAir())) || (!t.equals(route.getEnd()) && !presentFromStartTilEnd.isEmpty() && presentFromStartTilEnd.stream().allMatch(Matches.unitIsAir()))) {
                            continue;
                        }
                        // createdBattle = true;
                        getBattleTracker().takeOver(t, id, bridge, m_currentMove, arrivedCopyForBattles);
                    }
                }
            }
            // mark movement
            final Change moveChange = markMovementChange(arrived, route, id);
            change.add(moveChange);
            // actually move the units
            if (route.getStart() != null && route.getEnd() != null) {
                // ChangeFactory.addUnits(route.getEnd(), arrived);
                final Change remove = ChangeFactory.removeUnits(route.getStart(), units);
                final Change add = ChangeFactory.addUnits(route.getEnd(), arrived);
                change.add(add, remove);
            }
            MovePerformer.this.bridge.addChange(change);
            m_currentMove.addChange(change);
            m_currentMove.setDescription(MyFormatter.unitsToTextNoOwner(arrived) + " moved from " + route.getStart().getName() + " to " + route.getEnd().getName());
            moveDelegate.updateUndoableMoves(m_currentMove);
        }
    };
    m_executionStack.push(postAaFire);
    m_executionStack.push(fireAa);
    m_executionStack.push(preAaFire);
    m_executionStack.execute(bridge);
}
Also used : Territory(games.strategy.engine.data.Territory) GameData(games.strategy.engine.data.GameData) HashMap(java.util.HashMap) ArrayList(java.util.ArrayList) CompositeChange(games.strategy.engine.data.CompositeChange) Change(games.strategy.engine.data.Change) TripleAUnit(games.strategy.triplea.TripleAUnit) Unit(games.strategy.engine.data.Unit) Collection(java.util.Collection) CompositeChange(games.strategy.engine.data.CompositeChange) Route(games.strategy.engine.data.Route) IDelegateBridge(games.strategy.engine.delegate.IDelegateBridge) HashSet(java.util.HashSet)

Example 48 with Unit

use of games.strategy.engine.data.Unit in project triplea by triplea-game.

the class MoveValidator method addToMapping.

private static void addToMapping(final Map<Unit, Collection<Unit>> mapping, final Map<Unit, Collection<Unit>> newMapping) {
    for (final Unit key : newMapping.keySet()) {
        if (mapping.containsKey(key)) {
            final Collection<Unit> heldUnits = mapping.get(key);
            heldUnits.addAll(newMapping.get(key));
            mapping.put(key, heldUnits);
        } else {
            mapping.put(key, newMapping.get(key));
        }
    }
}
Also used : TripleAUnit(games.strategy.triplea.TripleAUnit) Unit(games.strategy.engine.data.Unit)

Example 49 with Unit

use of games.strategy.engine.data.Unit in project triplea by triplea-game.

the class MoveValidator method validateParatroops.

private static MoveValidationResult validateParatroops(final boolean nonCombat, final GameData data, final Collection<Unit> units, final Route route, final PlayerID player, final MoveValidationResult result) {
    if (!TechAttachment.isAirTransportable(player)) {
        return result;
    }
    if (units.stream().noneMatch(Matches.unitIsAirTransportable()) || units.stream().noneMatch(Matches.unitIsAirTransport())) {
        return result;
    }
    if (nonCombat && !isAirTransportableCanMoveDuringNonCombat(data)) {
        return result.setErrorReturnResult("Paratroops may not move during NonCombat");
    }
    if (!getEditMode(data)) {
        // if we can move without using paratroop tech, do so this allows moving a bomber/infantry from one friendly
        // territory to another
        final List<Unit> paratroopsRequiringTransport = getParatroopsRequiringTransport(units, route);
        if (paratroopsRequiringTransport.isEmpty()) {
            return result;
        }
        final List<Unit> airTransports = CollectionUtils.getMatches(units, Matches.unitIsAirTransport());
        // TODO kev change below to mapAirTransports (or modify mapTransports to handle air cargo)
        // Map<Unit, Unit> airTransportsAndParatroops = MoveDelegate.mapTransports(route, paratroopsRequiringTransport,
        // airTransports);
        final Map<Unit, Unit> airTransportsAndParatroops = TransportUtils.mapTransportsToLoad(paratroopsRequiringTransport, airTransports);
        for (final Unit paratroop : airTransportsAndParatroops.keySet()) {
            if (Matches.unitHasMoved().test(paratroop)) {
                result.addDisallowedUnit("Cannot paratroop units that have already moved", paratroop);
            }
            final Unit transport = airTransportsAndParatroops.get(paratroop);
            if (Matches.unitHasMoved().test(transport)) {
                result.addDisallowedUnit("Cannot move then transport paratroops", transport);
            }
        }
        final Territory routeEnd = route.getEnd();
        for (final Unit paratroop : paratroopsRequiringTransport) {
            if (Matches.unitHasMoved().test(paratroop)) {
                result.addDisallowedUnit("Cannot paratroop units that have already moved", paratroop);
            }
            if (Matches.isTerritoryFriendly(player, data).test(routeEnd) && !isAirTransportableCanMoveDuringNonCombat(data)) {
                result.addDisallowedUnit("Paratroops must advance to battle", paratroop);
            }
            if (!nonCombat && Matches.isTerritoryFriendly(player, data).test(routeEnd) && isAirTransportableCanMoveDuringNonCombat(data)) {
                result.addDisallowedUnit("Paratroops may only airlift during Non-Combat Movement Phase", paratroop);
            }
        }
        if (!Properties.getParatroopersCanAttackDeepIntoEnemyTerritory(data)) {
            for (final Territory current : CollectionUtils.getMatches(route.getMiddleSteps(), Matches.territoryIsLand())) {
                if (Matches.isTerritoryEnemy(player, data).test(current)) {
                    return result.setErrorReturnResult("Must stop paratroops in first enemy territory");
                }
            }
        }
    }
    return result;
}
Also used : Territory(games.strategy.engine.data.Territory) TripleAUnit(games.strategy.triplea.TripleAUnit) Unit(games.strategy.engine.data.Unit)

Example 50 with Unit

use of games.strategy.engine.data.Unit in project triplea by triplea-game.

the class MoveValidator method validateCombat.

private static MoveValidationResult validateCombat(final GameData data, final Collection<Unit> units, final Route route, final PlayerID player, final MoveValidationResult result) {
    if (getEditMode(data)) {
        return result;
    }
    for (final Territory t : route.getSteps()) {
        if (!Matches.territoryOwnerRelationshipTypeCanMoveIntoDuringCombatMove(player).test(t)) {
            return result.setErrorReturnResult("Cannot move into territories owned by " + t.getOwner().getName() + " during Combat Movement Phase");
        }
    }
    // owned territory. do not allow unless each unit can blitz the current territory.
    if (!route.getStart().isWater() && Matches.isAtWar(route.getStart().getOwner(), data).test(player) && (route.anyMatch(Matches.isTerritoryEnemy(player, data)) && !route.allMatchMiddleSteps(Matches.isTerritoryEnemy(player, data).negate(), false))) {
        if (!Matches.territoryIsBlitzable(player, data).test(route.getStart()) && (units.isEmpty() || !units.stream().allMatch(Matches.unitIsAir()))) {
            return result.setErrorReturnResult("Cannot blitz out of a battle further into enemy territory");
        }
        for (final Unit u : CollectionUtils.getMatches(units, Matches.unitCanBlitz().negate().and(Matches.unitIsNotAir()))) {
            result.addDisallowedUnit("Not all units can blitz out of empty enemy territory", u);
        }
    }
    // Do not allow unless the territory is blitzable.
    if (!route.getStart().isWater() && !Matches.isAtWar(route.getStart().getOwner(), data).test(player) && (route.anyMatch(Matches.isTerritoryEnemy(player, data)) && !route.allMatchMiddleSteps(Matches.isTerritoryEnemy(player, data).negate(), false))) {
        if (!Matches.territoryIsBlitzable(player, data).test(route.getStart()) && (units.isEmpty() || !units.stream().allMatch(Matches.unitIsAir()))) {
            return result.setErrorReturnResult("Cannot blitz out of a battle into enemy territory");
        }
    }
    // Don't allow aa guns (and other disallowed units) to move in combat unless they are in a transport
    if (units.stream().anyMatch(Matches.unitCanNotMoveDuringCombatMove()) && (!route.getStart().isWater() || !route.getEnd().isWater())) {
        for (final Unit unit : CollectionUtils.getMatches(units, Matches.unitCanNotMoveDuringCombatMove())) {
            result.addDisallowedUnit("Cannot move AA guns in combat movement phase", unit);
        }
    }
    // 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");
        }
    }
    if (units.stream().anyMatch(Matches.unitIsLand()) && route.hasSteps()) {
        // Check all the territories but the end, if there are enemy territories, make sure they are blitzable
        // if they are not blitzable, or we aren't all blitz units fail
        int enemyCount = 0;
        boolean allEnemyBlitzable = true;
        for (final Territory current : route.getMiddleSteps()) {
            if (current.isWater()) {
                continue;
            }
            if (data.getRelationshipTracker().isAtWar(current.getOwner(), player) || AbstractMoveDelegate.getBattleTracker(data).wasConquered(current)) {
                enemyCount++;
                allEnemyBlitzable &= Matches.territoryIsBlitzable(player, data).test(current);
            }
        }
        if (enemyCount > 0 && !allEnemyBlitzable) {
            if (nonParatroopersPresent(player, units)) {
                return result.setErrorReturnResult("Cannot blitz on that route");
            }
        } else if (allEnemyBlitzable && !(route.getStart().isWater() || route.getEnd().isWater())) {
            final Predicate<Unit> blitzingUnit = Matches.unitCanBlitz().or(Matches.unitIsAir());
            final Predicate<Unit> nonBlitzing = blitzingUnit.negate();
            final Collection<Unit> nonBlitzingUnits = CollectionUtils.getMatches(units, nonBlitzing);
            // remove any units that gain blitz due to certain abilities
            nonBlitzingUnits.removeAll(UnitAttachment.getUnitsWhichReceivesAbilityWhenWith(units, "canBlitz", data));
            final Predicate<Territory> territoryIsNotEnd = Matches.territoryIs(route.getEnd()).negate();
            final Predicate<Territory> nonFriendlyTerritories = Matches.isTerritoryFriendly(player, data).negate();
            final Predicate<Territory> notEndOrFriendlyTerrs = nonFriendlyTerritories.and(territoryIsNotEnd);
            final Predicate<Territory> foughtOver = Matches.territoryWasFoughOver(AbstractMoveDelegate.getBattleTracker(data));
            final Predicate<Territory> notEndWasFought = territoryIsNotEnd.and(foughtOver);
            final boolean wasStartFoughtOver = AbstractMoveDelegate.getBattleTracker(data).wasConquered(route.getStart()) || AbstractMoveDelegate.getBattleTracker(data).wasBlitzed(route.getStart());
            nonBlitzingUnits.addAll(CollectionUtils.getMatches(units, Matches.unitIsOfTypes(TerritoryEffectHelper.getUnitTypesThatLostBlitz((wasStartFoughtOver ? route.getAllTerritories() : route.getSteps())))));
            for (final Unit unit : nonBlitzingUnits) {
                // TODO: Need to actually test if the unit is being air transported or land transported
                if ((Matches.unitIsAirTransportable().test(unit) && units.stream().anyMatch(Matches.unitIsAirTransport())) || (Matches.unitIsLandTransportable().test(unit) && units.stream().anyMatch(Matches.unitIsLandTransport()))) {
                    continue;
                }
                final TripleAUnit taUnit = (TripleAUnit) unit;
                if (wasStartFoughtOver || taUnit.getWasInCombat() || route.anyMatch(notEndOrFriendlyTerrs) || route.anyMatch(notEndWasFought)) {
                    result.addDisallowedUnit(NOT_ALL_UNITS_CAN_BLITZ, unit);
                }
            }
        }
    }
    if (units.stream().anyMatch(Matches.unitIsAir())) {
        // check aircraft
        if (route.hasSteps() && (!Properties.getNeutralFlyoverAllowed(data) || isNeutralsImpassable(data))) {
            if (route.getMiddleSteps().stream().anyMatch(Matches.territoryIsNeutralButNotWater())) {
                return result.setErrorReturnResult("Air units cannot fly over neutral territories");
            }
        }
    }
    // make sure no conquered territories on route
    if (MoveValidator.hasConqueredNonBlitzedNonWaterOnRoute(route, data)) {
        // unless we are all air or we are in non combat OR the route is water (was a bug in convoy zone movement)
        if (units.isEmpty() || !units.stream().allMatch(Matches.unitIsAir())) {
            // what if we are paratroopers?
            return result.setErrorReturnResult("Cannot move through newly captured territories");
        }
    }
    // See if they've already been in combat
    if (units.stream().anyMatch(Matches.unitWasInCombat()) && units.stream().anyMatch(Matches.unitWasUnloadedThisTurn())) {
        final Collection<Territory> end = Collections.singleton(route.getEnd());
        if (!end.isEmpty() && end.stream().allMatch(Matches.isTerritoryEnemyAndNotUnownedWaterOrImpassableOrRestricted(player, data)) && !route.getEnd().getUnits().isEmpty()) {
            return result.setErrorReturnResult("Units cannot participate in multiple battles");
        }
    }
    // See if we are doing invasions in combat phase, with units or transports that can't do invasion.
    if (route.isUnload() && Matches.isTerritoryEnemy(player, data).test(route.getEnd())) {
        for (final Unit unit : CollectionUtils.getMatches(units, Matches.unitCanInvade().negate())) {
            result.addDisallowedUnit(unit.getType().getName() + " can't invade from " + TripleAUnit.get(unit).getTransportedBy().getType().getName(), unit);
        }
    }
    return result;
}
Also used : Territory(games.strategy.engine.data.Territory) Collection(java.util.Collection) ResourceCollection(games.strategy.engine.data.ResourceCollection) TripleAUnit(games.strategy.triplea.TripleAUnit) Unit(games.strategy.engine.data.Unit) TripleAUnit(games.strategy.triplea.TripleAUnit) Predicate(java.util.function.Predicate)

Aggregations

Unit (games.strategy.engine.data.Unit)447 TripleAUnit (games.strategy.triplea.TripleAUnit)301 Territory (games.strategy.engine.data.Territory)255 ArrayList (java.util.ArrayList)204 PlayerID (games.strategy.engine.data.PlayerID)135 GameData (games.strategy.engine.data.GameData)103 HashSet (java.util.HashSet)92 Test (org.junit.jupiter.api.Test)91 Route (games.strategy.engine.data.Route)89 UnitType (games.strategy.engine.data.UnitType)85 CompositeChange (games.strategy.engine.data.CompositeChange)64 HashMap (java.util.HashMap)64 IntegerMap (games.strategy.util.IntegerMap)61 UnitAttachment (games.strategy.triplea.attachments.UnitAttachment)58 Collection (java.util.Collection)58 ITestDelegateBridge (games.strategy.engine.data.ITestDelegateBridge)56 List (java.util.List)48 ScriptedRandomSource (games.strategy.engine.random.ScriptedRandomSource)47 Change (games.strategy.engine.data.Change)44 Set (java.util.Set)43