Search in sources :

Example 1 with Route

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

the class BattleDelegate method scramblingCleanup.

private void scramblingCleanup() {
    // return scrambled units to their original territories, or let them move 1 or x to a new territory.
    final GameData data = getData();
    if (!Properties.getScrambleRulesInEffect(data)) {
        return;
    }
    final boolean mustReturnToBase = Properties.getScrambledUnitsReturnToBase(data);
    for (final Territory t : data.getMap().getTerritories()) {
        int carrierCostOfCurrentTerr = 0;
        final Collection<Unit> wasScrambled = t.getUnits().getMatches(Matches.unitWasScrambled());
        for (final Unit u : wasScrambled) {
            final CompositeChange change = new CompositeChange();
            final Territory originatedFrom = TripleAUnit.get(u).getOriginatedFrom();
            Territory landingTerr = null;
            final String historyText;
            if (!mustReturnToBase || !Matches.isTerritoryAllied(u.getOwner(), data).test(originatedFrom)) {
                final Collection<Territory> possible = whereCanAirLand(Collections.singletonList(u), t, u.getOwner(), data, battleTracker, carrierCostOfCurrentTerr, 1, !mustReturnToBase);
                if (possible.size() > 1) {
                    landingTerr = getRemotePlayer(u.getOwner()).selectTerritoryForAirToLand(possible, t, "Select territory for air units to land. (Current territory is " + t.getName() + "): " + MyFormatter.unitsToText(Collections.singletonList(u)));
                } else if (possible.size() == 1) {
                    landingTerr = possible.iterator().next();
                }
                if (landingTerr == null || landingTerr.equals(t)) {
                    carrierCostOfCurrentTerr += AirMovementValidator.carrierCost(Collections.singletonList(u));
                    historyText = "Scrambled unit stays in territory " + t.getName();
                } else {
                    historyText = "Moving scrambled unit from " + t.getName() + " to " + landingTerr.getName();
                }
            } else {
                landingTerr = originatedFrom;
                historyText = "Moving scrambled unit from " + t.getName() + " back to originating territory: " + landingTerr.getName();
            }
            // if null, we leave it to die
            if (landingTerr != null) {
                change.add(ChangeFactory.moveUnits(t, landingTerr, Collections.singletonList(u)));
                change.add(Route.getFuelChanges(Collections.singleton(u), new Route(t, landingTerr), u.getOwner(), data));
            }
            change.add(ChangeFactory.unitPropertyChange(u, null, TripleAUnit.ORIGINATED_FROM));
            change.add(ChangeFactory.unitPropertyChange(u, false, TripleAUnit.WAS_SCRAMBLED));
            if (!change.isEmpty()) {
                bridge.getHistoryWriter().startEvent(historyText, u);
                bridge.addChange(change);
            }
        }
    }
}
Also used : Territory(games.strategy.engine.data.Territory) GameData(games.strategy.engine.data.GameData) TripleAUnit(games.strategy.triplea.TripleAUnit) Unit(games.strategy.engine.data.Unit) CompositeChange(games.strategy.engine.data.CompositeChange) Route(games.strategy.engine.data.Route)

Example 2 with Route

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

the class BattleDelegate method whereCanAirLand.

private static Collection<Territory> whereCanAirLand(final Collection<Unit> strandedAir, final Territory currentTerr, final PlayerID alliedPlayer, final GameData data, final BattleTracker battleTracker, final int carrierCostForCurrentTerr, final int allowedMovement, final boolean useMaxScrambleDistance) {
    int maxDistance = allowedMovement;
    if ((maxDistance > 1) || useMaxScrambleDistance) {
        UnitType ut = null;
        for (final Unit u : strandedAir) {
            if (ut == null) {
                ut = u.getType();
            } else if (!ut.equals(u.getType())) {
                throw new IllegalStateException("whereCanAirLand can only accept 1 UnitType if byMovementCost or scrambled is true");
            }
        }
        if (useMaxScrambleDistance) {
            maxDistance = UnitAttachment.get(ut).getMaxScrambleDistance();
        }
    }
    if (maxDistance < 1 || strandedAir == null || strandedAir.isEmpty()) {
        return Collections.singletonList(currentTerr);
    }
    final boolean areNeutralsPassableByAir = (Properties.getNeutralFlyoverAllowed(data) && !Properties.getNeutralsImpassable(data));
    final HashSet<Territory> canNotLand = new HashSet<>();
    canNotLand.addAll(battleTracker.getPendingBattleSites(false));
    canNotLand.addAll(CollectionUtils.getMatches(data.getMap().getTerritories(), Matches.territoryHasEnemyUnits(alliedPlayer, data)));
    final Collection<Territory> possibleTerrs = new ArrayList<>(data.getMap().getNeighbors(currentTerr, maxDistance));
    if (maxDistance > 1) {
        final Iterator<Territory> possibleIter = possibleTerrs.iterator();
        while (possibleIter.hasNext()) {
            final Route route = data.getMap().getRoute(currentTerr, possibleIter.next(), Matches.airCanFlyOver(alliedPlayer, data, areNeutralsPassableByAir));
            if (route == null || route.getMovementCost(strandedAir.iterator().next()) > maxDistance) {
                possibleIter.remove();
            }
        }
    }
    possibleTerrs.add(currentTerr);
    final HashSet<Territory> availableLand = new HashSet<>(CollectionUtils.getMatches(possibleTerrs, Matches.isTerritoryAllied(alliedPlayer, data).and(Matches.territoryIsLand())));
    availableLand.removeAll(canNotLand);
    final HashSet<Territory> whereCanLand = new HashSet<>(availableLand);
    // now for carrier-air-landing validation
    if (!strandedAir.isEmpty() && strandedAir.stream().allMatch(Matches.unitCanLandOnCarrier())) {
        final HashSet<Territory> availableWater = new HashSet<>(CollectionUtils.getMatches(possibleTerrs, Matches.territoryHasUnitsThatMatch(Matches.unitIsAlliedCarrier(alliedPlayer, data)).and(Matches.territoryIsWater())));
        availableWater.removeAll(battleTracker.getPendingBattleSites(false));
        // a rather simple calculation, either we can take all the air, or we can't, nothing in the middle
        final int carrierCost = AirMovementValidator.carrierCost(strandedAir);
        final Iterator<Territory> waterIter = availableWater.iterator();
        while (waterIter.hasNext()) {
            final Territory t = waterIter.next();
            int carrierCapacity = AirMovementValidator.carrierCapacity(t.getUnits().getMatches(Matches.unitIsAlliedCarrier(alliedPlayer, data)), t);
            if (!t.equals(currentTerr)) {
                carrierCapacity -= AirMovementValidator.carrierCost(t.getUnits().getMatches(Matches.unitCanLandOnCarrier().and(Matches.alliedUnit(alliedPlayer, data))));
            } else {
                carrierCapacity -= carrierCostForCurrentTerr;
            }
            if (carrierCapacity < carrierCost) {
                waterIter.remove();
            }
        }
        whereCanLand.addAll(availableWater);
    }
    return whereCanLand;
}
Also used : Territory(games.strategy.engine.data.Territory) UnitType(games.strategy.engine.data.UnitType) ArrayList(java.util.ArrayList) TripleAUnit(games.strategy.triplea.TripleAUnit) Unit(games.strategy.engine.data.Unit) Route(games.strategy.engine.data.Route) HashSet(java.util.HashSet)

Example 3 with Route

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

the class AirMovementValidator method validateAirCaughtByMovingCarriersAndOwnedAndAlliedAir.

private static void validateAirCaughtByMovingCarriersAndOwnedAndAlliedAir(final MoveValidationResult result, final List<Territory> landingSpots, final Collection<Territory> potentialCarrierOrigins, final Map<Unit, Collection<Unit>> movedCarriersAndTheirFighters, final Collection<Unit> airThatMustLandOnCarriers, final Collection<Unit> airNotToConsider, final PlayerID player, final Route route, final GameData data) {
    final Predicate<Unit> ownedCarrierMatch = Matches.unitIsOwnedBy(player).and(Matches.unitIsCarrier());
    final Predicate<Unit> ownedAirMatch = Matches.unitIsOwnedBy(player).and(Matches.unitIsAir()).and(Matches.unitCanLandOnCarrier());
    final Predicate<Unit> alliedNotOwnedAirMatch = Matches.unitIsOwnedBy(player).negate().and(Matches.isUnitAllied(player, data)).and(Matches.unitIsAir()).and(Matches.unitCanLandOnCarrier());
    final Predicate<Unit> alliedNotOwnedCarrierMatch = Matches.unitIsOwnedBy(player).negate().and(Matches.isUnitAllied(player, data)).and(Matches.unitIsCarrier());
    final Territory routeEnd = route.getEnd();
    final boolean areNeutralsPassableByAir = areNeutralsPassableByAir(data);
    final IntegerMap<Territory> landingSpotsWithCarrierCapacity = // fill our landing spot capacity with capacity from allied carriers and potential building of new carriers
    populateStaticAlliedAndBuildingCarrierCapacity(landingSpots, movedCarriersAndTheirFighters, player, data);
    final LinkedHashMap<Unit, Integer> movementLeftForAirToValidate = // calculate movement left only once
    getMovementLeftForValidatingAir(airThatMustLandOnCarriers, player, route);
    for (final Territory landingSpot : landingSpots) {
        // since we are here, no point looking at this place twice
        potentialCarrierOrigins.remove(landingSpot);
        final List<Unit> airCanReach = new ArrayList<>();
        for (final Unit air : airThatMustLandOnCarriers) {
            if (canAirReachThisSpot(data, player, air, routeEnd, movementLeftForAirToValidate.get(air), landingSpot, areNeutralsPassableByAir)) {
                // get all air that can reach this spot
                airCanReach.add(air);
            }
        }
        if (airCanReach.isEmpty()) {
            continue;
        }
        final Collection<Unit> unitsInLandingSpot = landingSpot.getUnits().getUnits();
        unitsInLandingSpot.removeAll(movedCarriersAndTheirFighters.keySet());
        // make sure to remove any units we have already moved, or units that are excluded
        unitsInLandingSpot.removeAll(airNotToConsider);
        // because they are in our mouse selection
        for (final Collection<Unit> ftrs : movedCarriersAndTheirFighters.values()) {
            // also remove any fighters that are being moved with carriers that we have already moved
            unitsInLandingSpot.removeAll(ftrs);
        }
        final Collection<Unit> ownedCarriersInLandingSpot = CollectionUtils.getMatches(unitsInLandingSpot, ownedCarrierMatch);
        // get air we own here, but exclude any air that can fly to allied land
        final Collection<Unit> airInLandingSpot = CollectionUtils.getMatches(CollectionUtils.getMatches(unitsInLandingSpot, ownedAirMatch), unitCanFindLand(data, landingSpot).negate());
        // add allied air (it can't fly away)
        airInLandingSpot.addAll(CollectionUtils.getMatches(unitsInLandingSpot, alliedNotOwnedAirMatch));
        // make sure we don't count this again
        // airNotToConsider.addAll(airInLandingSpot);
        // get the current capacity
        int landingSpotCapacity = landingSpotsWithCarrierCapacity.getInt(landingSpot);
        // add capacity of owned carriers
        landingSpotCapacity += carrierCapacity(ownedCarriersInLandingSpot, landingSpot);
        // minus capacity of air in the territory
        landingSpotCapacity -= carrierCost(airInLandingSpot);
        if (!airCanReach.isEmpty()) {
            final Iterator<Unit> airIter = airCanReach.iterator();
            while (airIter.hasNext()) {
                final Unit air = airIter.next();
                final int carrierCost = carrierCost(air);
                if (landingSpotCapacity >= carrierCost) {
                    landingSpotCapacity -= carrierCost;
                    // we can land this one here, yay
                    airThatMustLandOnCarriers.remove(air);
                    airIter.remove();
                }
            }
        }
        if (airThatMustLandOnCarriers.isEmpty()) {
            // all can land here, so return
            return;
        }
        // final int lowestCarrierCost = getLowestCarrierCost(airCanReach);
        // now bring carriers here...
        final Iterator<Territory> iter = potentialCarrierOrigins.iterator();
        while (iter.hasNext()) {
            final Territory carrierSpot = iter.next();
            final Collection<Unit> unitsInCarrierSpot = carrierSpot.getUnits().getUnits();
            // remove carriers we have already moved
            unitsInCarrierSpot.removeAll(movedCarriersAndTheirFighters.keySet());
            // remove units we do not want to consider because they are in our mouse selection
            unitsInCarrierSpot.removeAll(airNotToConsider);
            for (final Collection<Unit> ftrs : movedCarriersAndTheirFighters.values()) {
                // remove the fighters that are moving with the carriers we have already moved
                unitsInCarrierSpot.removeAll(ftrs);
            }
            final Collection<Unit> ownedCarriersInCarrierSpot = CollectionUtils.getMatches(unitsInCarrierSpot, ownedCarrierMatch);
            if (ownedCarriersInCarrierSpot.isEmpty()) {
                iter.remove();
                continue;
            }
            final Collection<Unit> ownedAirInCarrierSpot = CollectionUtils.getMatches(// exclude any owned air that can fly to land
            CollectionUtils.getMatches(unitsInCarrierSpot, ownedAirMatch), unitCanFindLand(data, carrierSpot).negate());
            final Collection<Unit> alliedNotOwnedAirInCarrierSpot = CollectionUtils.getMatches(unitsInCarrierSpot, alliedNotOwnedAirMatch);
            final Map<Unit, Collection<Unit>> mustMoveWithMap = // this only returns the allied cargo
            MoveValidator.carrierMustMoveWith(ownedCarriersInCarrierSpot, carrierSpot, data, player);
            // planes that MUST travel with the carrier
            // get the current capacity for the carrier spot
            int carrierSpotCapacity = landingSpotsWithCarrierCapacity.getInt(carrierSpot);
            // we don't have it because this spot is not in the landing zone area.
            if (!landingSpotsWithCarrierCapacity.containsKey(carrierSpot)) {
                // we still have a capacity for allied carriers, but only to carry other allied or local owned units, not to
                // carry our selected
                // units.
                carrierSpotCapacity = carrierCapacity(carrierSpot.getUnits().getMatches(alliedNotOwnedCarrierMatch), carrierSpot);
                landingSpotsWithCarrierCapacity.put(carrierSpot, carrierSpotCapacity);
            }
            // we have allied air here, so we need to account for them before moving any carriers
            if (!alliedNotOwnedAirInCarrierSpot.isEmpty() || !mustMoveWithMap.isEmpty()) {
                // them
                if (mustMoveWithMap.isEmpty()) {
                    // allied carriers can carry enough
                    carrierSpotCapacity -= carrierCost(alliedNotOwnedAirInCarrierSpot);
                    // we do not want to consider these units again
                    airNotToConsider.addAll(alliedNotOwnedAirInCarrierSpot);
                    if (carrierSpotCapacity > 0) {
                        // we can hold some of the owned air here too
                        final Iterator<Unit> ownedIter = ownedAirInCarrierSpot.iterator();
                        while (ownedIter.hasNext()) {
                            final Unit air = ownedIter.next();
                            final int carrierCost = carrierCost(air);
                            if (carrierSpotCapacity >= carrierCost) {
                                carrierSpotCapacity -= carrierCost;
                                // we do not want to consider this one again
                                airNotToConsider.add(air);
                                ownedIter.remove();
                            }
                        }
                    }
                    // put correct value for future reference now that we
                    // have considered the allied air
                    landingSpotsWithCarrierCapacity.put(carrierSpot, carrierSpotCapacity);
                } else {
                    // carrierMustMoveWith does not account for any allied cargo already moved out.
                    for (final Collection<Unit> airMovingWith : mustMoveWithMap.values()) {
                        for (final Collection<Unit> ftrs : movedCarriersAndTheirFighters.values()) {
                            // remove the fighters that are moving with the carriers we have already moved
                            airMovingWith.removeAll(ftrs);
                        }
                    }
                    for (final Collection<Unit> airMovingWith : mustMoveWithMap.values()) {
                        // we will consider these as part of their moving carrier
                        alliedNotOwnedAirInCarrierSpot.removeAll(airMovingWith);
                    }
                    carrierSpotCapacity -= carrierCost(alliedNotOwnedAirInCarrierSpot);
                    // we do not want to consider these units again
                    airNotToConsider.addAll(alliedNotOwnedAirInCarrierSpot);
                    // put correct value for future reference now that we
                    // have considered the allied air
                    landingSpotsWithCarrierCapacity.put(carrierSpot, carrierSpotCapacity);
                }
            }
            final Route toLandingSpot = data.getMap().getRoute(carrierSpot, landingSpot, Matches.seaCanMoveOver(player, data));
            if (toLandingSpot == null) {
                continue;
            }
            final List<Unit> carrierCanReach = CollectionUtils.getMatches(ownedCarriersInCarrierSpot, Matches.unitHasEnoughMovementForRoute(toLandingSpot));
            if (carrierCanReach.isEmpty()) {
                // none can reach
                continue;
            }
            final List<Unit> carrierNotReach = new ArrayList<>(ownedCarriersInCarrierSpot);
            // we want to see if the air units can be put on the carriers that cannot make it
            // first, before taking up room on the carriers that can make it
            carrierNotReach.removeAll(carrierCanReach);
            final List<Unit> allCarriers = new ArrayList<>(carrierNotReach);
            // so we remove them from the list then re-add them so that they will be at the end of the list
            allCarriers.addAll(carrierCanReach);
            // now we want to make a map of the carriers to the units they must carry with them (both allied and owned)
            final Map<Unit, Collection<Unit>> carriersToMove = new HashMap<>();
            final List<Unit> carrierFull = new ArrayList<>();
            for (final Unit carrier : allCarriers) {
                final Collection<Unit> airMovingWith = new ArrayList<>();
                // first add allied cargo
                final Collection<Unit> alliedMovingWith = mustMoveWithMap.get(carrier);
                if (alliedMovingWith != null) {
                    airMovingWith.addAll(alliedMovingWith);
                }
                // now test if our carrier has any room for owned fighters
                int carrierCapacity = carrierCapacity(carrier, carrierSpot);
                carrierCapacity -= carrierCost(airMovingWith);
                final Iterator<Unit> ownedIter = ownedAirInCarrierSpot.iterator();
                while (ownedIter.hasNext()) {
                    final Unit air = ownedIter.next();
                    final int carrierCost = carrierCost(air);
                    if (carrierCapacity >= carrierCost) {
                        carrierCapacity -= carrierCost;
                        airMovingWith.add(air);
                        ownedIter.remove();
                    }
                }
                carriersToMove.put(carrier, airMovingWith);
                if (carrierCapacity <= 0) {
                    carrierFull.add(carrier);
                }
            }
            // if all carriers full, remove this carrier spot from consideration
            if (carrierFull.containsAll(allCarriers)) {
                iter.remove();
                continue;
            }
            if (carrierFull.containsAll(carrierNotReach)) {
                iter.remove();
            }
            // ok, now lets move them.
            for (final Unit carrier : carrierCanReach) {
                movedCarriersAndTheirFighters.put(carrier, carriersToMove.get(carrier));
                landingSpotCapacity += carrierCapacity(carrier, carrierSpot);
                landingSpotCapacity -= carrierCost(carriersToMove.get(carrier));
            }
            // optional for debugging
            final Iterator<Unit> reachIter = airCanReach.iterator();
            while (reachIter.hasNext()) {
                final Unit air = reachIter.next();
                final int carrierCost = carrierCost(air);
                if (landingSpotCapacity >= carrierCost) {
                    landingSpotCapacity -= carrierCost;
                    // we can land this one here, yay
                    airThatMustLandOnCarriers.remove(air);
                    reachIter.remove();
                }
            }
            if (airThatMustLandOnCarriers.isEmpty()) {
                // all can land here, so return
                return;
            }
        }
    }
    // anyone left over cannot land
    for (final Unit air : airThatMustLandOnCarriers) {
        result.addDisallowedUnit(NOT_ALL_AIR_UNITS_CAN_LAND, air);
    }
}
Also used : Territory(games.strategy.engine.data.Territory) HashMap(java.util.HashMap) LinkedHashMap(java.util.LinkedHashMap) ArrayList(java.util.ArrayList) TripleAUnit(games.strategy.triplea.TripleAUnit) Unit(games.strategy.engine.data.Unit) Collection(java.util.Collection) Route(games.strategy.engine.data.Route)

Example 4 with Route

use of games.strategy.engine.data.Route 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 5 with Route

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

the class MustFightBattle method retreatFromDependents.

private Change retreatFromDependents(final Collection<Unit> units, final Territory retreatTo, final Collection<IBattle> dependentBattles) {
    final CompositeChange change = new CompositeChange();
    for (final IBattle dependent : dependentBattles) {
        final Route route = new Route();
        route.setStart(m_battleSite);
        route.add(dependent.getTerritory());
        final Collection<Unit> retreatedUnits = dependent.getDependentUnits(units);
        dependent.removeAttack(route, retreatedUnits);
        reLoadTransports(units, change);
        change.add(ChangeFactory.moveUnits(dependent.getTerritory(), retreatTo, retreatedUnits));
    }
    return change;
}
Also used : CompositeChange(games.strategy.engine.data.CompositeChange) TripleAUnit(games.strategy.triplea.TripleAUnit) Unit(games.strategy.engine.data.Unit) Route(games.strategy.engine.data.Route)

Aggregations

Route (games.strategy.engine.data.Route)200 Test (org.junit.jupiter.api.Test)148 Territory (games.strategy.engine.data.Territory)132 Unit (games.strategy.engine.data.Unit)84 UnitType (games.strategy.engine.data.UnitType)83 ITestDelegateBridge (games.strategy.engine.data.ITestDelegateBridge)77 TripleAUnit (games.strategy.triplea.TripleAUnit)70 IntegerMap (games.strategy.util.IntegerMap)69 PlayerID (games.strategy.engine.data.PlayerID)64 ArrayList (java.util.ArrayList)44 GameData (games.strategy.engine.data.GameData)29 ScriptedRandomSource (games.strategy.engine.random.ScriptedRandomSource)26 HashSet (java.util.HashSet)21 HashMap (java.util.HashMap)20 Collection (java.util.Collection)15 List (java.util.List)12 Set (java.util.Set)12 UnitAttachment (games.strategy.triplea.attachments.UnitAttachment)11 Change (games.strategy.engine.data.Change)10 MoveValidationResult (games.strategy.triplea.delegate.dataObjects.MoveValidationResult)10