Skip to content

Commit

Permalink
Merge pull request #6230 from kuronekochomusuke/fleeAtEndOfMovement
Browse files Browse the repository at this point in the history
allow fleeing at end of movement
  • Loading branch information
HammerGS authored Nov 29, 2024
2 parents 2fc1f33 + 84ffea3 commit e371f22
Show file tree
Hide file tree
Showing 10 changed files with 132 additions and 52 deletions.
6 changes: 4 additions & 2 deletions megamek/i18n/megamek/common/report-messages.properties
Original file line number Diff line number Diff line change
Expand Up @@ -76,10 +76,11 @@
1511= to maximise range.

2000=<newline><B>Movement Phase</B><newline>-------------------
2005=<newline><data> (<data>) flees the battlefield.
2005=<newline><data> (<data>) flees the battlefield to the <data>.
2010=It carries <data> (<data>) with it.
2015=It takes <data> (<data>) with it.
2016=It carries <data> with it.
2017=<newline> flee failed.
2020=<newline><data> ejects from a <data> (<data>).
2025=<newline><data> (<data>) is abandoned by its crew.
2026=<newline><data> (<data>) is given the order to abandon ship.
Expand Down Expand Up @@ -159,7 +160,7 @@
2216=collides!
2217=<<span class='miss'><B>misses</B></span>.
2220=<data> (<data>) takes <data> damage from the collision.
2230=<newline><span class='info'>*** <data> (<data>) has been forced from the field. ***</span>
2230=<newline><span class='info'>*** <data> (<data>) has been forced from the field to the <data>. ***</span>
2235=<data> (<data>) is displaced into hex <data>.
2240=<data> (<data>) is displaced into hex <data>, violating stacking with <data> (<data>).
2245=<data> attempts to clear a(n) <data> mine in hex <data>:
Expand Down Expand Up @@ -1037,6 +1038,7 @@
7075=The following units never entered the field of battle:
7076=All fighters in squadron destroyed
7080=<newline>The following units are in retreat:
7081=fled to the <data>.
7085=<newline>Graveyard contains:
7090=<newline>The following utterly destroyed units are not available for salvage:
7095=<newline>Detailed unit status saved to entitystatus.txt
Expand Down
4 changes: 2 additions & 2 deletions megamek/src/megamek/client/bot/princess/Princess.java
Original file line number Diff line number Diff line change
Expand Up @@ -1047,7 +1047,7 @@ protected void calculateTargetingOffBoardTurn() {
Entity entityToFire = getGame().getFirstEntity(getMyTurn());

// if we're crippled, off-board and can do so, disengage
if (entityToFire.isOffBoard() && entityToFire.canFlee() && entityToFire.isCrippled(true)) {
if (entityToFire.isOffBoard() && entityToFire.canFlee(entityToFire.getPosition()) && entityToFire.isCrippled(true)) {
Vector<EntityAction> disengageVector = new Vector<>();
disengageVector.add(new DisengageAction(entityToFire.getId()));
sendAttackData(entityToFire.getId(), disengageVector);
Expand Down Expand Up @@ -2138,7 +2138,7 @@ boolean canShootWhileFallingBack(Entity entity) {
boolean mustFleeBoard(final Entity entity) {
if (!isFallingBack(entity)) {
return false;
} else if (!entity.canFlee()) {
} else if (!entity.canFlee(entity.getPosition())) {
return false;
} else if (0 < getPathRanker(entity).distanceToHomeEdge(entity.getPosition(),
getHomeEdge(entity), getGame())) {
Expand Down
26 changes: 23 additions & 3 deletions megamek/src/megamek/client/ui/swing/MovementDisplay.java
Original file line number Diff line number Diff line change
Expand Up @@ -853,7 +853,8 @@ private void updateButtons() {
(ce instanceof Tank)
&& (ce.getSwarmAttackerId() != Entity.NONE));

setFleeEnabled(ce.canFlee());
updateFleeButton();

if (gOpts.booleanOption(OptionsConstants.ADVGRNDMOV_VEHICLES_CAN_EJECT) && (ce instanceof Tank)) {
// Vehicle don't have ejection systems so crews abandon, and must enter a valid
// hex.
Expand Down Expand Up @@ -968,9 +969,28 @@ private void updateMove(boolean redrawMovement) {
if (redrawMovement) {
clientgui.getBoardView().drawMovementData(ce(), cmd);
}

updateFleeButton();
updateDonePanel();
}

private void updateFleeButton() {
boolean fleeStart = (cmd.getLastStep() == null)
&& ce().canFlee(ce().getPosition());
boolean jumpMoveRemaining = (cmd.getLastStep() != null)
&& cmd.getLastStep().isJumping()
&& (cmd.getMpUsed() < ce().getJumpMP());
boolean runMoveRemaining = (cmd.getLastStep() != null)
&& !cmd.getLastStep().isJumping()
&& (cmd.getMpUsed() < ce().getRunMP());
boolean moveRemaining = jumpMoveRemaining || runMoveRemaining;
boolean fleeEnd = (cmd.getLastStep() != null)
&& (cmd.getLastStepMovementType() != EntityMovementType.MOVE_ILLEGAL)
&& moveRemaining
&& clientgui.getClient().getGame().canFleeFrom(ce(), cmd.getLastStep().getPosition());
setFleeEnabled(fleeStart || fleeEnd);
}

private void updateAeroButtons() {
if (ce() != null && ce().isAero()) {
getBtn(MoveCommand.MOVE_THRUST).setEnabled(true);
Expand Down Expand Up @@ -1966,6 +1986,7 @@ public synchronized void hexMoused(BoardViewEvent b) {
// else clear movement
clear();
}

return;
}
// if not valid, tell why
Expand Down Expand Up @@ -4893,10 +4914,9 @@ public synchronized void actionPerformed(ActionEvent ev) {
&& clientgui.doYesNoDialog(
Messages.getString("MovementDisplay.EscapeDialog.title"),
Messages.getString("MovementDisplay.EscapeDialog.message"))) {

clear();
addStepToMovePath(MoveStepType.FLEE);
ready();
clear();
} else if (actionCmd.equals(MoveCommand.MOVE_FLY_OFF.getCmd())
&& clientgui.doYesNoDialog(
Messages.getString("MovementDisplay.FlyOffDialog.title"),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -404,7 +404,7 @@ private void beginMyTurn() {
if (GUIP.getAutoSelectNextUnit()) {
selectEntity(clientgui.getClient().getFirstEntityNum());
}
setDisengageEnabled((ce() != null) && attacks.isEmpty() && ce().canFlee());
setDisengageEnabled((ce() != null) && attacks.isEmpty() && ce().canFlee(ce().getPosition()));

GameTurn turn = clientgui.getClient().getMyTurn();
// There's special processing for triggering AP Pods.
Expand Down Expand Up @@ -754,7 +754,7 @@ private void clearAttacks() {
// restore any other movement to default
ce().setSecondaryFacing(ce().getFacing());
ce().setArmsFlipped(false);
setDisengageEnabled(ce().isOffBoard() && ce().canFlee());
setDisengageEnabled(ce().isOffBoard() && ce().canFlee(ce().getPosition()));
}

/**
Expand All @@ -776,7 +776,7 @@ private void removeLastFiring() {
WeaponAttackAction waa = (WeaponAttackAction) o;
ce().getEquipment(waa.getWeaponId()).setUsedThisRound(false);
removeAttack(o);
setDisengageEnabled(attacks.isEmpty() && ce().isOffBoard() && ce().canFlee());
setDisengageEnabled(attacks.isEmpty() && ce().isOffBoard() && ce().canFlee(ce().getPosition()));
clientgui.getUnitDisplay().wPan.displayMek(ce());
clientgui.getClient().getGame().removeAction(o);
clientgui.getBoardView().refreshAttacks();
Expand Down
3 changes: 1 addition & 2 deletions megamek/src/megamek/common/Entity.java
Original file line number Diff line number Diff line change
Expand Up @@ -9546,8 +9546,7 @@ public short getUnitNumber() {
* Returns whether an entity can flee from its current position. Currently
* returns true if the entity is on the edge of the board.
*/
public boolean canFlee() {
Coords pos = getPosition();
public boolean canFlee(Coords pos) {
return ((getWalkMP() > 0) || (this instanceof Infantry))
&& !isProne()
&& !isStuck()
Expand Down
2 changes: 1 addition & 1 deletion megamek/src/megamek/common/GunEmplacement.java
Original file line number Diff line number Diff line change
Expand Up @@ -229,7 +229,7 @@ public boolean canCharge() {
}

@Override
public boolean canFlee() {
public boolean canFlee(Coords pos) {
return false;
}

Expand Down
4 changes: 2 additions & 2 deletions megamek/src/megamek/common/MoveStep.java
Original file line number Diff line number Diff line change
Expand Up @@ -2214,7 +2214,7 @@ && getClearance() < prev.getClearance()) { // landing
}

// check to see if it's trying to flee and can legally do so.
if ((type == MoveStepType.FLEE) && entity.canFlee()) {
if ((type == MoveStepType.FLEE) && entity.canFlee(curPos)) {
movementType = EntityMovementType.MOVE_LEGAL;
}

Expand Down Expand Up @@ -3365,7 +3365,7 @@ public boolean isMovementPossible(Game game, Coords src, int srcEl, CachedEntity
}

// If you want to flee, and you can flee, flee.
if ((type == MoveStepType.FLEE) && entity.canFlee()) {
if ((type == MoveStepType.FLEE) && entity.canFlee(dest)) {
return true;
}

Expand Down
17 changes: 11 additions & 6 deletions megamek/src/megamek/server/totalwarfare/MovePathHandler.java
Original file line number Diff line number Diff line change
Expand Up @@ -123,12 +123,6 @@ class MovePathHandler extends AbstractTWRuleHandler {
}

void processMovement() {
// check for fleeing
if (md.contains(MovePath.MoveStepType.FLEE)) {
addReport(gameManager.processLeaveMap(md, false, -1));
return;
}

if (md.contains(MovePath.MoveStepType.EJECT)) {
if (entity.isLargeCraft() && !entity.isCarcass()) {
r = new Report(2026);
Expand Down Expand Up @@ -1200,6 +1194,17 @@ && getGame().getOptions().booleanOption(OptionsConstants.ADVAERORULES_FUEL_CONSU
((Mek) entity).setShouldDieAtEndOfTurnBecauseOfWater(false);
}
}

// check for fleeing
if (md.contains(MovePath.MoveStepType.FLEE)) {
if (entity.canFlee(entity.getPosition())) {
addReport(gameManager.processLeaveMap(md, false, -1));
} else {
r = new Report(2017, Report.PUBLIC);
r.indent();
addReport(r);
}
}
}

/**
Expand Down
110 changes: 82 additions & 28 deletions megamek/src/megamek/server/totalwarfare/TWGameManager.java
Original file line number Diff line number Diff line change
Expand Up @@ -1171,6 +1171,29 @@ void prepareVictoryReport() {
while (retreat.hasMoreElements()) {
Entity entity = retreat.nextElement();
addReport(entity.victoryReport());

String fleeDirection;
switch (entity.getStartingPos(false)) {
case Board.START_N:
fleeDirection = "North";
break;
case Board.START_E:
fleeDirection = "Ease";
break;
case Board.START_S:
fleeDirection = "South";
break;
case Board.START_W:
fleeDirection = "West";
break;
default:
fleeDirection = "Edge";
}

r = new Report(7081, Report.PUBLIC);
r.indent();
r.add(fleeDirection);
addReport(r);
}
}
// List destroyed units
Expand Down Expand Up @@ -5283,6 +5306,50 @@ Vector<Report> processCrash(Entity entity, int vel, Coords c) {
return vReport;
}

private OffBoardDirection calculateEdge(Coords coords) {
OffBoardDirection fleeDirection;

if (coords.getY() <= 0) {
fleeDirection = OffBoardDirection.NORTH;
} else if (coords.getY() >= (getGame().getBoard().getHeight() - 1)) {
fleeDirection = OffBoardDirection.SOUTH;
} else if (coords.getX() <= 0) {
fleeDirection = OffBoardDirection.WEST;
} else {
fleeDirection = OffBoardDirection.EAST;
}

return fleeDirection;
}

private String setRetreatEdge(Entity entity, OffBoardDirection fleeDirection) {
String result;

switch (fleeDirection) {
case NORTH:
entity.setStartingPos(Board.START_N);
result = "North";
break;
case EAST:
entity.setStartingPos(Board.START_E);
result = "East";
break;
case SOUTH:
entity.setStartingPos(Board.START_S);
result = "South";
break;
case WEST:
entity.setStartingPos(Board.START_W);
result = "West";
break;
default:
entity.setStartingPos(Board.START_EDGE);
result = "Edge";
}

return result;
}

/**
* Process any flee movement actions, including flying off the map
*
Expand All @@ -5305,20 +5372,15 @@ public Vector<Report> processLeaveMap(MovePath movePath, boolean flewOff, int re
r = new Report(9370, Report.PUBLIC);
}
r.addDesc(entity);

OffBoardDirection fleeDirection = calculateEdge(movePath.getFinalCoords());
String retreatEdge = setRetreatEdge(entity, fleeDirection);
r.add(retreatEdge);
addReport(r);
OffBoardDirection fleeDirection;
if (movePath.getFinalCoords().getY() <= 0) {
fleeDirection = OffBoardDirection.NORTH;
} else if (movePath.getFinalCoords().getY() >= (getGame().getBoard().getHeight() - 1)) {
fleeDirection = OffBoardDirection.SOUTH;
} else if (movePath.getFinalCoords().getX() <= 0) {
fleeDirection = OffBoardDirection.WEST;
} else {
fleeDirection = OffBoardDirection.EAST;
}

if (returnable > -1) {
entityUpdate(entity.getId());

if (returnable > -1) {
entity.setDeployed(false);
entity.setDeployRound(1 + game.getRoundCount() + returnable);
entity.setPosition(null);
Expand All @@ -5331,23 +5393,7 @@ public Vector<Report> processLeaveMap(MovePath movePath, boolean flewOff, int re
// fly off again instantly.
((IAero) entity).setOutControl(false);
}
switch (fleeDirection) {
case WEST:
entity.setStartingPos(Board.START_W);
break;
case NORTH:
entity.setStartingPos(Board.START_N);
break;
case EAST:
entity.setStartingPos(Board.START_E);
break;
case SOUTH:
entity.setStartingPos(Board.START_S);
break;
default:
entity.setStartingPos(Board.START_EDGE);
}
entityUpdate(entity.getId());

return vReport;
} else {
ServerHelper.clearBloodStalkers(game, entity.getId(), this);
Expand Down Expand Up @@ -8620,6 +8666,7 @@ Vector<Report> doEntityDisplacement(Entity entity, Coords src,
Coords dest, PilotingRollData roll) {
Vector<Report> vPhaseReport = new Vector<>();
Report r;

if (!game.getBoard().contains(dest)) {
// set position anyway, for pushes moving through, stuff like that
entity.setPosition(dest);
Expand All @@ -8633,12 +8680,17 @@ Vector<Report> doEntityDisplacement(Entity entity, Coords src,
} else if (turnsRemoved > 0) {
send(packetHelper.createTurnListPacket());
}

OffBoardDirection fleeDirection = calculateEdge(src);
String retreatEdge = setRetreatEdge(entity, fleeDirection);

game.removeEntity(entity.getId(), IEntityRemovalConditions.REMOVE_PUSHED);
send(createRemoveEntityPacket(entity.getId(), IEntityRemovalConditions.REMOVE_PUSHED));
// entity forced from the field
r = new Report(2230);
r.subject = entity.getId();
r.addDesc(entity);
r.add(retreatEdge);
vPhaseReport.add(r);
// TODO : remove passengers and swarmers.
}
Expand Down Expand Up @@ -8777,6 +8829,7 @@ else if ((waterDepth > 0)
doSkillCheckInPlace(entity, waterRoll);
}
}

// Update the entity's position on the client.
entityUpdate(entity.getId());

Expand Down Expand Up @@ -8888,6 +8941,7 @@ else if ((waterDepth > 0)
entityUpdate(violation.getId());
}
}

return vPhaseReport;
}

Expand Down
Loading

0 comments on commit e371f22

Please sign in to comment.