use of games.strategy.triplea.TripleAUnit 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;
}
use of games.strategy.triplea.TripleAUnit in project triplea by triplea-game.
the class MoveValidator method getCanCarry.
private static Collection<Unit> getCanCarry(final Unit carrier, final Collection<Unit> selectFrom, final PlayerID playerWhoIsDoingTheMovement, final GameData data) {
final UnitAttachment ua = UnitAttachment.get(carrier.getType());
final Collection<Unit> canCarry = new ArrayList<>();
int available = ua.getCarrierCapacity();
final TripleAUnit taCarrier = (TripleAUnit) carrier;
for (final Unit plane : selectFrom) {
final TripleAUnit taPlane = (TripleAUnit) plane;
final UnitAttachment planeAttachment = UnitAttachment.get(plane.getType());
final int cost = planeAttachment.getCarrierCost();
if (available >= cost) {
// this is to test if they started in the same sea zone or not, and its not a very good way of testing it.
if ((taCarrier.getAlreadyMoved() == taPlane.getAlreadyMoved()) || (Matches.unitHasNotMoved().test(plane) && Matches.unitHasNotMoved().test(carrier)) || (Matches.unitIsOwnedBy(playerWhoIsDoingTheMovement).negate().test(plane) && Matches.alliedUnit(playerWhoIsDoingTheMovement, data).test(plane))) {
available -= cost;
canCarry.add(plane);
}
}
if (available == 0) {
break;
}
}
return canCarry;
}
use of games.strategy.triplea.TripleAUnit in project triplea by triplea-game.
the class MoveValidator method validateTransport.
private static MoveValidationResult validateTransport(final boolean isNonCombat, final GameData data, final List<UndoableMove> undoableMoves, final Collection<Unit> units, final Route route, final PlayerID player, final Collection<Unit> transportsToLoad, final MoveValidationResult result) {
final boolean isEditMode = getEditMode(data);
if (!units.isEmpty() && units.stream().allMatch(Matches.unitIsAir())) {
return result;
}
if (!route.hasWater()) {
return result;
}
// If there are non-sea transports return
final boolean seaOrNoTransportsPresent = transportsToLoad.isEmpty() || transportsToLoad.stream().anyMatch(Matches.unitIsSea().and(Matches.unitCanTransport()));
if (!seaOrNoTransportsPresent) {
return result;
}
final Territory routeEnd = route.getEnd();
final Territory routeStart = route.getStart();
// if unloading make sure length of route is only 1
if (!isEditMode && route.isUnload()) {
if (route.hasMoreThenOneStep()) {
return result.setErrorReturnResult("Unloading units must stop where they are unloaded");
}
for (final Unit unit : TransportTracker.getUnitsLoadedOnAlliedTransportsThisTurn(units)) {
result.addDisallowedUnit(CANNOT_LOAD_AND_UNLOAD_AN_ALLIED_TRANSPORT_IN_THE_SAME_ROUND, unit);
}
final Collection<Unit> transports = TransportUtils.mapTransports(route, units, null).values();
final boolean isScramblingOrKamikazeAttacksEnabled = Properties.getScrambleRulesInEffect(data) || Properties.getUseKamikazeSuicideAttacks(data);
final boolean submarinesPreventUnescortedAmphibAssaults = Properties.getSubmarinesPreventUnescortedAmphibiousAssaults(data);
final Predicate<Unit> enemySubmarineMatch = Matches.unitIsEnemyOf(data, player).and(Matches.unitIsSub());
final Predicate<Unit> ownedSeaNonTransportMatch = Matches.unitIsOwnedBy(player).and(Matches.unitIsSea()).and(Matches.unitIsNotTransportButCouldBeCombatTransport());
for (final Unit transport : transports) {
if (!isNonCombat && route.numberOfStepsIncludingStart() == 2) {
if (Matches.territoryHasEnemyUnits(player, data).test(routeEnd) || Matches.isTerritoryEnemyAndNotUnownedWater(player, data).test(routeEnd)) {
// this is an amphibious assault
if (submarinesPreventUnescortedAmphibAssaults && !Matches.territoryHasUnitsThatMatch(ownedSeaNonTransportMatch).test(routeStart) && Matches.territoryHasUnitsThatMatch(enemySubmarineMatch).test(routeStart)) {
// stops our unloading for amphibious assault
for (final Unit unit : TransportTracker.transporting(transport)) {
result.addDisallowedUnit(ENEMY_SUBMARINE_PREVENTING_UNESCORTED_AMPHIBIOUS_ASSAULT_LANDING, unit);
}
}
} else if (!AbstractMoveDelegate.getBattleTracker(data).wasConquered(routeEnd)) {
// this is an unload to a friendly territory
if (isScramblingOrKamikazeAttacksEnabled || !Matches.territoryIsEmptyOfCombatUnits(data, player).test(routeStart)) {
// TODO: should we use the battle tracker for this instead?
for (final Unit unit : TransportTracker.transporting(transport)) {
result.addDisallowedUnit(TRANSPORT_MAY_NOT_UNLOAD_TO_FRIENDLY_TERRITORIES_UNTIL_AFTER_COMBAT_IS_RESOLVED, unit);
}
}
}
}
// in which they perform their actions. check whether transport has already unloaded
if (TransportTracker.hasTransportUnloadedInPreviousPhase(transport)) {
for (final Unit unit : TransportTracker.transporting(transport)) {
result.addDisallowedUnit(TRANSPORT_HAS_ALREADY_UNLOADED_UNITS_IN_A_PREVIOUS_PHASE, unit);
}
// check whether transport is restricted to another territory
} else if (TransportTracker.isTransportUnloadRestrictedToAnotherTerritory(transport, route.getEnd())) {
final Territory alreadyUnloadedTo = getTerritoryTransportHasUnloadedTo(undoableMoves, transport);
for (final Unit unit : TransportTracker.transporting(transport)) {
result.addDisallowedUnit(TRANSPORT_HAS_ALREADY_UNLOADED_UNITS_TO + alreadyUnloadedTo.getName(), unit);
}
// Check if the transport has already loaded after being in combat
} else if (TransportTracker.isTransportUnloadRestrictedInNonCombat(transport)) {
for (final Unit unit : TransportTracker.transporting(transport)) {
result.addDisallowedUnit(TRANSPORT_CANNOT_LOAD_AND_UNLOAD_AFTER_COMBAT, unit);
}
}
}
}
// if we are land make sure no water in route except for transport situations
final Collection<Unit> land = CollectionUtils.getMatches(units, Matches.unitIsLand());
final Collection<Unit> landAndAir = CollectionUtils.getMatches(units, Matches.unitIsLand().or(Matches.unitIsAir()));
// make sure we can be transported
final Predicate<Unit> cantBeTransported = Matches.unitCanBeTransported().negate();
for (final Unit unit : CollectionUtils.getMatches(land, cantBeTransported)) {
result.addDisallowedUnit("Not all units can be transported", unit);
}
// make sure that the only the first or last territory is land don't want situation where they go sea land sea
if (!isEditMode && route.hasLand() && !(route.getStart().isWater() || route.getEnd().isWater())) {
// carried by the air and that the air has enough capacity
if (nonParatroopersPresent(player, landAndAir)) {
return result.setErrorReturnResult("Invalid move, only start or end can be land when route has water.");
}
}
// TODO handle this
if (!isEditMode && !route.getEnd().isWater() && !route.getStart().isWater() && nonParatroopersPresent(player, landAndAir)) {
return result.setErrorReturnResult("Must stop units at a transport on route");
}
if (route.getEnd().isWater() && route.getStart().isWater()) {
// make sure units and transports stick together
for (final Unit unit : units) {
final UnitAttachment ua = UnitAttachment.get(unit.getType());
// make sure transports dont leave their units behind
if (ua.getTransportCapacity() != -1) {
final Collection<Unit> holding = TransportTracker.transporting(unit);
if (!units.containsAll(holding)) {
result.addDisallowedUnit("Transports cannot leave their units", unit);
}
}
// make sure units dont leave their transports behind
if (ua.getTransportCost() != -1) {
final Unit transport = TransportTracker.transportedBy(unit);
if (transport != null && !units.contains(transport)) {
result.addDisallowedUnit("Unit must stay with its transport while moving", unit);
}
}
}
}
if (route.isLoad()) {
if (!isEditMode && !route.hasExactlyOneStep() && nonParatroopersPresent(player, landAndAir)) {
return result.setErrorReturnResult("Units cannot move before loading onto transports");
}
final Predicate<Unit> enemyNonSubmerged = Matches.enemyUnit(player, data).and(Matches.unitIsSubmerged().negate());
if (!Properties.getUnitsCanLoadInHostileSeaZones(data) && route.getEnd().getUnits().anyMatch(enemyNonSubmerged) && nonParatroopersPresent(player, landAndAir) && !onlyIgnoredUnitsOnPath(route, player, data, false) && !AbstractMoveDelegate.getBattleTracker(data).didAllThesePlayersJustGoToWarThisTurn(player, route.getEnd().getUnits().getUnits(), data)) {
return result.setErrorReturnResult("Cannot load when enemy sea units are present");
}
final Map<Unit, Unit> unitsToTransports = TransportUtils.mapTransports(route, land, transportsToLoad);
if (!isEditMode) {
for (final Unit baseUnit : land) {
final TripleAUnit unit = (TripleAUnit) baseUnit;
if (Matches.unitHasMoved().test(unit)) {
result.addDisallowedUnit("Units cannot move before loading onto transports", unit);
}
final Unit transport = unitsToTransports.get(unit);
if (transport == null) {
continue;
}
if (TransportTracker.hasTransportUnloadedInPreviousPhase(transport)) {
result.addDisallowedUnit(TRANSPORT_HAS_ALREADY_UNLOADED_UNITS_IN_A_PREVIOUS_PHASE, unit);
} else if (TransportTracker.isTransportUnloadRestrictedToAnotherTerritory(transport, route.getEnd())) {
Territory alreadyUnloadedTo = getTerritoryTransportHasUnloadedTo(undoableMoves, transport);
for (final Unit transportToLoad : transportsToLoad) {
final TripleAUnit trn = (TripleAUnit) transportToLoad;
if (!TransportTracker.isTransportUnloadRestrictedToAnotherTerritory(trn, route.getEnd())) {
final UnitAttachment ua = UnitAttachment.get(unit.getType());
if (TransportTracker.getAvailableCapacity(trn) >= ua.getTransportCost()) {
alreadyUnloadedTo = null;
break;
}
}
}
if (alreadyUnloadedTo != null) {
result.addDisallowedUnit(TRANSPORT_HAS_ALREADY_UNLOADED_UNITS_TO + alreadyUnloadedTo.getName(), unit);
}
}
}
}
if (!unitsToTransports.keySet().containsAll(land)) {
// some units didn't get mapped to a transport
final Collection<UnitCategory> unitsToLoadCategories = UnitSeperator.categorize(land);
if (unitsToTransports.size() == 0 || unitsToLoadCategories.size() == 1) {
// set all unmapped units as disallowed if there are no transports or only one unit category
for (final Unit unit : land) {
if (unitsToTransports.containsKey(unit)) {
continue;
}
final UnitAttachment ua = UnitAttachment.get(unit.getType());
if (ua.getTransportCost() != -1) {
result.addDisallowedUnit("Not enough transports", unit);
}
}
} else {
// set all units as unresolved if there is at least one transport and mixed unit categories
for (final Unit unit : land) {
final UnitAttachment ua = UnitAttachment.get(unit.getType());
if (ua.getTransportCost() != -1) {
result.addUnresolvedUnit("Not enough transports", unit);
}
}
}
}
}
return result;
}
use of games.strategy.triplea.TripleAUnit 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);
}
}
}
use of games.strategy.triplea.TripleAUnit in project triplea by triplea-game.
the class MustFightBattle method landParatroops.
private void landParatroops(final IDelegateBridge bridge) {
if (TechAttachment.isAirTransportable(m_attacker)) {
final Collection<Unit> airTransports = CollectionUtils.getMatches(m_battleSite.getUnits().getUnits(), Matches.unitIsAirTransport());
if (!airTransports.isEmpty()) {
final Collection<Unit> dependents = getDependentUnits(airTransports);
if (!dependents.isEmpty()) {
final CompositeChange change = new CompositeChange();
// remove dependency from paratroopers by unloading the air transports
for (final Unit unit : dependents) {
change.add(TransportTracker.unloadAirTransportChange((TripleAUnit) unit, m_battleSite, false));
}
bridge.addChange(change);
// remove bombers from m_dependentUnits
for (final Unit unit : airTransports) {
m_dependentUnits.remove(unit);
}
}
}
}
}
Aggregations