Search in sources :

Example 11 with Change

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

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

the class MustFightBattle method markNoMovementLeft.

private void markNoMovementLeft(final IDelegateBridge bridge) {
    if (m_headless) {
        return;
    }
    final Collection<Unit> attackingNonAir = CollectionUtils.getMatches(m_attackingUnits, Matches.unitIsAir().negate());
    final Change noMovementChange = ChangeFactory.markNoMovementChange(attackingNonAir);
    if (!noMovementChange.isEmpty()) {
        bridge.addChange(noMovementChange);
    }
}
Also used : CompositeChange(games.strategy.engine.data.CompositeChange) Change(games.strategy.engine.data.Change) TripleAUnit(games.strategy.triplea.TripleAUnit) Unit(games.strategy.engine.data.Unit)

Example 13 with Change

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

the class MustFightBattle method reLoadTransports.

void reLoadTransports(final Collection<Unit> units, final CompositeChange change) {
    final Collection<Unit> transports = CollectionUtils.getMatches(units, Matches.unitCanTransport());
    // Put units back on their transports
    for (final Unit transport : transports) {
        final Collection<Unit> unloaded = TransportTracker.unloaded(transport);
        for (final Unit load : unloaded) {
            final Change loadChange = TransportTracker.loadTransportChange((TripleAUnit) transport, load);
            change.add(loadChange);
        }
    }
}
Also used : CompositeChange(games.strategy.engine.data.CompositeChange) Change(games.strategy.engine.data.Change) TripleAUnit(games.strategy.triplea.TripleAUnit) Unit(games.strategy.engine.data.Unit)

Example 14 with Change

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

the class MustFightBattle method fireNavalBombardment.

private void fireNavalBombardment(final IDelegateBridge bridge) {
    // TODO - check within the method for the bombarding limitations
    final Collection<Unit> bombard = getBombardingUnits();
    final Collection<Unit> attacked = CollectionUtils.getMatches(m_defendingUnits, Matches.unitIsNotInfrastructureAndNotCapturedOnEntering(m_attacker, m_battleSite, m_data));
    // bombarding units can't move after bombarding
    if (!m_headless) {
        final Change change = ChangeFactory.markNoMovementChange(bombard);
        bridge.addChange(change);
    }
    /*
     * TODO This code is actually a bug- the property is intended to tell if the return fire is
     * RESTRICTED- but it's used as if it's ALLOWED. The reason is the default values on the
     * property definition. However, fixing this will entail a fix to the XML to reverse
     * all values. We'll leave it as is for now and try to figure out a patch strategy later.
     */
    final boolean canReturnFire = isNavalBombardCasualtiesReturnFire();
    if (bombard.size() > 0 && attacked.size() > 0) {
        if (!m_headless) {
            bridge.getSoundChannelBroadcaster().playSoundForAll(SoundPath.CLIP_BATTLE_BOMBARD, m_attacker);
        }
        final List<Unit> allEnemyUnitsAliveOrWaitingToDie = new ArrayList<>();
        allEnemyUnitsAliveOrWaitingToDie.addAll(m_defendingUnits);
        allEnemyUnitsAliveOrWaitingToDie.addAll(m_defendingWaitingToDie);
        fire(SELECT_NAVAL_BOMBARDMENT_CASUALTIES, bombard, attacked, allEnemyUnitsAliveOrWaitingToDie, false, canReturnFire ? ReturnFire.ALL : ReturnFire.NONE, "Bombard");
    }
}
Also used : 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)

Example 15 with Change

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

the class NonFightingBattle method unitsLostInPrecedingBattle.

@Override
public void unitsLostInPrecedingBattle(final IBattle battle, final Collection<Unit> units, final IDelegateBridge bridge, final boolean withdrawn) {
    if (withdrawn) {
        return;
    }
    Collection<Unit> lost = getDependentUnits(units);
    lost.addAll(CollectionUtils.intersection(units, m_attackingUnits));
    lost = CollectionUtils.getMatches(lost, Matches.unitIsInTerritory(m_battleSite));
    if (lost.size() != 0) {
        final String transcriptText = MyFormatter.unitsToText(lost) + " lost in " + m_battleSite.getName();
        bridge.getHistoryWriter().addChildToEvent(transcriptText, lost);
        final Change change = ChangeFactory.removeUnits(m_battleSite, lost);
        bridge.addChange(change);
    }
}
Also used : Change(games.strategy.engine.data.Change) Unit(games.strategy.engine.data.Unit)

Aggregations

Change (games.strategy.engine.data.Change)70 CompositeChange (games.strategy.engine.data.CompositeChange)44 Unit (games.strategy.engine.data.Unit)40 TripleAUnit (games.strategy.triplea.TripleAUnit)29 PlayerID (games.strategy.engine.data.PlayerID)25 Territory (games.strategy.engine.data.Territory)23 ArrayList (java.util.ArrayList)20 GameData (games.strategy.engine.data.GameData)19 UnitType (games.strategy.engine.data.UnitType)16 Resource (games.strategy.engine.data.Resource)12 Test (org.junit.jupiter.api.Test)11 ITestDelegateBridge (games.strategy.engine.data.ITestDelegateBridge)9 Route (games.strategy.engine.data.Route)9 HashSet (java.util.HashSet)8 UnitAttachment (games.strategy.triplea.attachments.UnitAttachment)6 Collection (java.util.Collection)6 IntegerMap (games.strategy.util.IntegerMap)5 Tuple (games.strategy.util.Tuple)4 ProductionFrontier (games.strategy.engine.data.ProductionFrontier)3 ITripleAPlayer (games.strategy.triplea.player.ITripleAPlayer)3