Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Prevent units from unloading over bay door limits #5808

Merged
merged 2 commits into from
Jul 28, 2024
Merged
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
32 changes: 12 additions & 20 deletions megamek/src/megamek/client/ui/swing/MovementDisplay.java
Original file line number Diff line number Diff line change
Expand Up @@ -318,10 +318,7 @@ public static MoveCommand[] values(int f, GameOptions opts, boolean forwardIni)
// is the shift key held?
private boolean shiftheld;

/**
* A local copy of the current entity's loaded units.
*/
private List<Entity> loadedUnits = null;
private List<Entity> unloadableUnits = null;

/**
* A local copy of the current entity's towed trailers.
Expand Down Expand Up @@ -1255,12 +1252,7 @@ public void clear() {
updateAeroButtons();
updateLayMineButton();

loadedUnits = ce.getLoadedUnits();
for (Entity e : ce.getUnitsUnloadableFromBays()) {
if (!loadedUnits.contains(e)) {
loadedUnits.add(e);
}
}
unloadableUnits = ce.getUnloadableUnits();
towedUnits = ce.getLoadedTrailers();

updateLoadButtons();
Expand Down Expand Up @@ -2825,7 +2817,7 @@ private void updateUnloadButton() {
}

if ((ce instanceof SmallCraft) || ce.isSupportVehicle()) {
setUnloadEnabled(!loadedUnits.isEmpty() && !ce.isAirborne());
setUnloadEnabled(!unloadableUnits.isEmpty() && !ce.isAirborne());
return;
}

Expand All @@ -2836,13 +2828,13 @@ private void updateUnloadButton() {

// A unit that has somehow exited the map is assumed to be unable to unload
if (isFinalPositionOnBoard()) {
canUnloadHere = loadedUnits.stream().anyMatch(en -> en.isElevationValid(unloadEl, hex) || (en.getJumpMP() > 0));
canUnloadHere = unloadableUnits.stream().anyMatch(en -> en.isElevationValid(unloadEl, hex) || (en.getJumpMP() > 0));
// Zip lines, TO pg 219
if (game().getOptions().booleanOption(ADVGRNDMOV_TACOPS_ZIPLINES) && (ce instanceof VTOL)) {
canUnloadHere |= loadedUnits.stream().filter(Entity::isInfantry).anyMatch(en -> !((Infantry) en).isMechanized());
canUnloadHere |= unloadableUnits.stream().filter(Entity::isInfantry).anyMatch(en -> !((Infantry) en).isMechanized());
}
}
setUnloadEnabled(legalGear && canUnloadHere && !loadedUnits.isEmpty());
setUnloadEnabled(legalGear && canUnloadHere && !unloadableUnits.isEmpty());
}

/** Updates the status of the Mount button. */
Expand Down Expand Up @@ -3282,21 +3274,21 @@ private Entity getUnloadedUnit() {
Entity ce = ce();
Entity choice = null;
// Handle error condition.
if (loadedUnits.isEmpty()) {
if (unloadableUnits.isEmpty()) {
LogManager.getLogger().error("MovementDisplay#getUnloadedUnit() called without loaded units.");
} else if (loadedUnits.size() > 1) {
} else if (unloadableUnits.size() > 1) {
// If we have multiple choices, display a selection dialog.
String input = (String) JOptionPane.showInputDialog(
clientgui.getFrame(),
Messages.getString("MovementDisplay.UnloadUnitDialog.message", ce.getShortName(), ce.getUnusedString()),
Messages.getString("MovementDisplay.UnloadUnitDialog.title"),
JOptionPane.QUESTION_MESSAGE, null,
SharedUtility.getDisplayArray(loadedUnits), null);
choice = (Entity) SharedUtility.getTargetPicked(loadedUnits, input);
SharedUtility.getDisplayArray(unloadableUnits), null);
choice = (Entity) SharedUtility.getTargetPicked(unloadableUnits, input);
} else {
// Only one choice.
choice = loadedUnits.get(0);
loadedUnits.remove(0);
choice = unloadableUnits.get(0);
unloadableUnits.remove(0);
}

// Return the chosen unit.
Expand Down
9 changes: 4 additions & 5 deletions megamek/src/megamek/common/Bay.java
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@ public class Bay implements Transporter, ITechnology {
int doors = 1;
int doorsNext = 1;
int currentdoors = doors;
protected int unloadedThisTurn = 0;
private int unloadedThisTurn = 0;
protected int loadedThisTurn = 0;
List<Integer> recoverySlots = new ArrayList<>();
int bayNumber = 0;
Expand Down Expand Up @@ -182,10 +182,8 @@ public boolean canLoad(Entity unit) {
}

/**
* To unload units, a bay must have more doors available than units unloaded
* this turn. Can't load, launch or recover into a damaged bay, but you can unload it
*
* @return True when further doors are available to unload units this turn
* @return True when further doors are available to unload units this turn. This method checks only
* the state of bay doors, not if it has units left to unload or the status of those.
*/
public boolean canUnloadUnits() {
return currentdoors > unloadedThisTurn;
Expand Down Expand Up @@ -235,6 +233,7 @@ public List<Entity> getDroppableUnits() {
/** @return A (possibly empty) list of units from this bay that can be unloaded on the ground. */
public List<Entity> getUnloadableUnits() {
// TODO: we need to handle aeros and VTOLs differently
// TODO: shouldn't this check the entity state like wasLoadedThisTurn()? It is equal to getLoadedUnits()
return troops.stream().map(game::getEntity).filter(Objects::nonNull).collect(toList());
}

Expand Down
79 changes: 42 additions & 37 deletions megamek/src/megamek/common/Entity.java
Original file line number Diff line number Diff line change
Expand Up @@ -8614,6 +8614,7 @@ public Bay getBayById(int bayNumber) {
* @return the DockingCollar with the given ID or null
*/
@Nullable
@SuppressWarnings("unused") // Used in MHQ
public DockingCollar getCollarById(int collarNumber) {
return getDockingCollars().stream()
.filter(dc -> dc.getCollarNumber() == collarNumber)
Expand Down Expand Up @@ -8690,47 +8691,50 @@ public Vector<Entity> getDroppableUnits() {
}

/**
* @return only entities in that can be unloaded on ground
* @return All Entities that can at this point be unloaded from any of the bays of this Entity. This
* does not include any units that were loaded this turn or any bays where the door capacity has
* been exceeded this turn.
* Note that the returned list may be unmodifiable.
*
* @see #wasLoadedThisTurn()
* @see Bay#canUnloadUnits()
*/
public Vector<Entity> getUnitsUnloadableFromBays() {
Vector<Entity> result = new Vector<>();

// Walk through this entity's transport components;
// add all of their lists to ours.

// I should only add entities in bays that are functional
for (Transporter next : transports) {
if ((next instanceof Bay) && (((Bay) next).canUnloadUnits())) {
Bay nextbay = (Bay) next;
for (Entity e : nextbay.getUnloadableUnits()) {
if (!e.wasLoadedThisTurn()) {
result.addElement(e);
}
}
}
}

// Return the list.
return result;
public List<Entity> getUnitsUnloadableFromBays() {
return transports.stream()
.filter(t -> t instanceof Bay).map(t -> (Bay) t)
.filter(Bay::canUnloadUnits)
.flatMap(b -> b.getUnloadableUnits().stream())
.filter(e -> !e.wasLoadedThisTurn())
.toList();
}

public Bay getLoadedBay(int bayID) {

Vector<Bay> bays = getFighterBays();
for (int nbay = 0; nbay < bays.size(); nbay++) {
Bay currentBay = bays.elementAt(nbay);
Vector<Entity> currentFighters = currentBay.getLoadedUnits();
for (int nfighter = 0; nfighter < currentFighters.size(); nfighter++) {
Entity fighter = currentFighters.elementAt(nfighter);
if (fighter.getId() == bayID) {
// then we are in the right bay
return currentBay;
}
}
}

return null;
/**
* @return All Entities that can at this point be unloaded from any transports of this Entity which are
* no Bays. This does not include any units that were loaded this turn.
* Note that the returned list may be unmodifiable.
*
* @see #wasLoadedThisTurn()
*/
public List<Entity> getUnitsUnloadableFromNonBays() {
return transports.stream()
.filter(t -> !(t instanceof Bay))
.flatMap(b -> b.getLoadedUnits().stream())
.filter(e -> !e.wasLoadedThisTurn())
.toList();
}

/**
* @return All Entities that can at this point be unloaded from any transports of this Entity. This does
* not include any units that were loaded this turn nor units from bays where the door capacity has been
* exceeded this turn.
*
* @see #wasLoadedThisTurn()
* @see Bay#canUnloadUnits()
*/
public List<Entity> getUnloadableUnits() {
List<Entity> loadedUnits = new ArrayList<>(getUnitsUnloadableFromNonBays());
loadedUnits.addAll(getUnitsUnloadableFromBays());
return loadedUnits;
}

/**
Expand Down Expand Up @@ -8919,6 +8923,7 @@ public boolean unload(Entity unit) {
}

@Override
@SuppressWarnings("unused") // Used in MHQ
public void resetTransporter() {
transports.forEach(Transporter::resetTransporter);
}
Expand Down