Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@
import lombok.extern.slf4j.Slf4j;
import org.triplea.java.Interruptibles;
import org.triplea.java.ThreadRunner;
import org.triplea.swing.SwingComponents;

/** Implementation of {@link ILauncher} for a headed local or network client game. */
@Slf4j
Expand Down Expand Up @@ -80,6 +81,18 @@ private Optional<ServerGame> loadGame() {
} catch (final MapNotFoundException e) {
// The throwing method of MapNotFoundException notifies and prompts user to download the map.
return Optional.empty();
} catch (final MapMissingResourceException e) {
log.warn("Map cannot be loaded: {}", e.getMessage(), e);
SwingComponents.showError(
parent,
"Cannot load map",
"The map cannot be loaded because it is missing the required file '"
+ e.getResourceName()
+ "'.\n\n"
+ "The map may be corrupted, incomplete, or still in development.\n"
+ "Try re-downloading the map, or contact the map's author if you are testing"
+ " an unfinished map.");
return Optional.empty();
} catch (final Exception ex) {
log.error("Failed to start game", ex);
return Optional.empty();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -1100,10 +1100,10 @@ public static Predicate<Unit> unitHasEnoughMovementForRoute(final Route route) {
// Apply "AAP" (Pacific) Naval base bonus. Note: In "AAG40" (1940) naval bases are implemented
// differently: via a naval base _unit_ that boosts movement rather than territory attachment.
if (ua.isSea() && unit.getData().getSequence().getStep().isNonCombat()) {
// If a zone adjacent to the starting and ending sea zones are allied naval bases, increase
// the range.
// TODO Still need to be able to handle stops on the way
if (hasNeighboringAlliedNavalBase(route.getStart(), unit.getOwner())
// The bonus applies if the unit's overall journey this phase started adjacent to a friendly
// naval base and ends adjacent to one — even if the journey was made in multiple legs.
final Territory journeyStart = findPhaseStartTerritory(unit, route.getStart());
if (hasNeighboringAlliedNavalBase(journeyStart, unit.getOwner())
&& hasNeighboringAlliedNavalBase(route.getEnd(), unit.getOwner())) {
left = left.add(BigDecimal.ONE);
}
Expand All @@ -1129,6 +1129,19 @@ private static boolean hasAlliedNavalBase(Territory t, GamePlayer player) {
return TerritoryAttachment.hasNavalBase(t) && t.getOwner().isAllied(player);
}

/**
* Returns the territory the unit started this move phase from. If the unit has already moved this
* phase, walks back through the move history; otherwise returns {@code currentLocation}.
*/
private static Territory findPhaseStartTerritory(Unit unit, Territory currentLocation) {
for (final UndoableMove move : unit.getData().getMoveDelegate().getMovesMade()) {
if (move.getUnits().contains(unit)) {
return move.getRoute().getStart();
}
}
return currentLocation;
}

public static Predicate<Unit> unitHasMovementLeft() {
return Unit::hasMovementLeft;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -356,6 +356,37 @@ void testCanMoveFurtherBetweenNavalBases() throws MutableProperty.InvalidValueEx
assertMoveError(GameDataTestUtil.getUnits(map, toSz30.getStart()), toSz30);
}

@Test
void testCanMoveBetweenNavalBasesInMultipleSteps() {
// Remove Japanese units from sz20 so that we can move ships there non-combat.
removeFrom(sz20, sz20.getUnits());
addTo(sz5, destroyer.create(2, americans));
addTo(sz5, carrier.create(1, americans));
final IntegerMap<UnitType> oneDestroyer = new IntegerMap<>();
oneDestroyer.put(destroyer, 1);

advanceToStep(bridge, "americanNonCombatMove");

// First leg: sz5 -> sz7 (1 space). Destroyer has movement 2, no bonus needed here.
final Route leg1 = new Route(sz5, sz7);
move(GameDataTestUtil.getUnits(oneDestroyer, leg1.getStart()), leg1);

// Second leg: sz7 -> sz8 -> sz20 (2 spaces). The unit's overall journey
// is from sz5 (naval-base-adjacent) to sz20 (naval-base-adjacent), so the +1 bonus
// should still apply, allowing it to traverse the remaining 2 spaces with 1 movement left.
final Route leg2FromSz7 = new Route(sz7, sz8, sz20);
move(GameDataTestUtil.getUnits(oneDestroyer, leg2FromSz7.getStart()), leg2FromSz7);

// Now verify the +1 cap is still respected across multiple legs: starting fresh, a 4-space
// journey should fail even when split (sz5 -> sz4, then sz4 -> sz10 -> sz14 -> sz30).
final IntegerMap<UnitType> oneCarrier = new IntegerMap<>();
oneCarrier.put(carrier, 1);
final Route firstLeg = new Route(sz5, sz4);
move(GameDataTestUtil.getUnits(oneCarrier, firstLeg.getStart()), firstLeg);
final Route secondLegOver = new Route(sz4, sz10, sz14, sz30);
assertMoveError(GameDataTestUtil.getUnits(oneCarrier, secondLegOver.getStart()), secondLegOver);
}

@Test
void testJapaneseDestroyerTransport() {
bridge = newDelegateBridge(japanese);
Expand Down
Loading