Skip to content

Commit

Permalink
Merge pull request #4940 from Sleet01/fix_3917_jump_vehicles_with_mot…
Browse files Browse the repository at this point in the history
…ive_damage

Fix #3917 jump vehicles with motive damage
  • Loading branch information
NickAragua authored Dec 5, 2023
2 parents b7747cd + 188ed8b commit bcb248d
Show file tree
Hide file tree
Showing 7 changed files with 102 additions and 10 deletions.
4 changes: 2 additions & 2 deletions megamek/src/megamek/client/ui/swing/MovementDisplay.java
Original file line number Diff line number Diff line change
Expand Up @@ -570,7 +570,7 @@ public void performAction() {
final Entity ce = ce();
boolean isAero = ce.isAero();
// first check if jumping is available at all
if (!isAero && !ce.isImmobile() && (ce.getJumpMP() > 0)
if (!isAero && !ce.isImmobileForJump() && (ce.getJumpMP() > 0)
&& !(ce.isStuck() && !ce.canUnstickByJumping())) {
if (gear != MovementDisplay.GEAR_JUMP) {
if (!((cmd.getLastStep() != null)
Expand Down Expand Up @@ -843,7 +843,7 @@ private void updateButtons() {

setWalkEnabled(!ce.isImmobile() && ((ce.getWalkMP() > 0) || (ce.getRunMP() > 0))
&& !ce.isStuck());
setJumpEnabled(!isAero && !ce.isImmobile() && !ce.isProne()
setJumpEnabled(!isAero && !ce.isImmobileForJump() && !ce.isProne()
// Conventional infantry also uses jump MP for VTOL and UMU MP
&& ((ce.getJumpMP() > 0) && (!ce.isConventionalInfantry() || ce.getMovementMode().isJumpInfantry()))
&& !(ce.isStuck() && !ce.canUnstickByJumping()));
Expand Down
8 changes: 7 additions & 1 deletion megamek/src/megamek/common/Compute.java
Original file line number Diff line number Diff line change
Expand Up @@ -1072,7 +1072,13 @@ public static ToHitData getImmobileMod(Targetable target, int aimingAt, AimingMo
if ((target instanceof Mech) && (aimingAt == Mech.LOC_HEAD) && aimingMode.isImmobile()) {
return new ToHitData(3, "aiming at head");
}
return new ToHitData(-4, "target immobile");
ToHitData immobileTHD = new ToHitData(-4, "target immobile");
if(target instanceof Tank) {
// An "immobilized" but jumping CV is not actually immobile for targeting purposes
// (See issue #3917)
return ((Tank)target).moved == EntityMovementType.MOVE_JUMP ? null : immobileTHD;
}
return immobileTHD;
}
return null;
}
Expand Down
4 changes: 4 additions & 0 deletions megamek/src/megamek/common/Entity.java
Original file line number Diff line number Diff line change
Expand Up @@ -1751,6 +1751,10 @@ public boolean isImmobile() {
return isImmobile(true);
}

public boolean isImmobileForJump() {
return isImmobile();
}

/**
* Is this entity shut down, or if applicable is the crew unconscious?
* @param checkCrew If true, consider the fitness of the crew when determining
Expand Down
5 changes: 5 additions & 0 deletions megamek/src/megamek/common/MoveStep.java
Original file line number Diff line number Diff line change
Expand Up @@ -3250,6 +3250,11 @@ public boolean isMovementPossible(Game game, Coords src, int srcEl, CachedEntity
return true;
}

// Motive hit has immobilized CV, but it still wants to (and can) jump: okay!
if (movementType == EntityMovementType.MOVE_JUMP && (entity instanceof Tank) && !entity.isImmobileForJump()) {
return true;
}

// super-easy, but not any more
if (entity.isImmobile() && !entity.isBracing()) {
return false;
Expand Down
17 changes: 17 additions & 0 deletions megamek/src/megamek/common/Tank.java
Original file line number Diff line number Diff line change
Expand Up @@ -567,6 +567,23 @@ public boolean isPermanentlyImmobilized(boolean checkCrew) {
return super.isPermanentlyImmobilized(checkCrew) || isMovementHit();
}

/**
* Per https://bg.battletech.com/forums/index.php/topic,78336.msg1869386.html#msg1869386
* CVs with working engines and Jump Jets should still have the option to jump during the movement
* phase, even if reduced to 0 MP by motive hits, or rolling 12 on the Motive System Damage table.
*/
@Override
public boolean isImmobileForJump() {
// *Can* jump unless 0 Jump MP, or 1+ Jump MP but engine is critted, or crew unconscious/dead.
boolean jumpImmobile = (
super.isImmobile(true) ||
super.isPermanentlyImmobilized(true) ||
(getJumpMP() == 0) ||
(isEngineHit())
);
return jumpImmobile;
}

@Override
public boolean hasCommandConsoleBonus() {
if (!hasWorkingMisc(MiscType.F_COMMAND_CONSOLE) || isCommanderHit() || isUsingConsoleCommander()) {
Expand Down
4 changes: 2 additions & 2 deletions megamek/src/megamek/server/GameManager.java
Original file line number Diff line number Diff line change
Expand Up @@ -33664,7 +33664,7 @@ private Vector<Report> vehicleMotiveDamage(Tank te, int modifier, boolean noRoll
default:
break;
}
// Apply vehicle effectiveness...except for jumps.
// Apply vehicle effectiveness...except for hits from jumps.
if (game.getOptions().booleanOption(OptionsConstants.ADVCOMBAT_TACOPS_VEHICLE_EFFECTIVE)
&& !jumpDamage) {
modifier = Math.max(modifier - 1, 0);
Expand Down Expand Up @@ -33729,7 +33729,7 @@ private Vector<Report> vehicleMotiveDamage(Tank te, int modifier, boolean noRoll
// unsure how to *report* any outcomes from there. Note that these treat
// being reduced to 0 MP and being actually immobilized as the same thing,
// which for these particular purposes may or may not be the intent of
// the rules in all cases.
// the rules in all cases (for instance, motive-immobilized CVs can still jump).
// Immobile hovercraft on water sink...
if (!te.isOffBoard() && (te.getMovementMode() == EntityMovementMode.HOVER
&& (te.isMovementHitPending() || (te.getWalkMP() <= 0))
Expand Down
70 changes: 65 additions & 5 deletions megamek/unittests/megamek/common/EntityTest.java
Original file line number Diff line number Diff line change
Expand Up @@ -26,8 +26,7 @@
import java.io.File;
import java.util.ArrayList;

import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.fail;
import static org.junit.jupiter.api.Assertions.*;
import static org.mockito.ArgumentMatchers.*;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.when;
Expand Down Expand Up @@ -73,14 +72,14 @@ public void testCalculateBattleValue() {
actual = testEntity.calculateBattleValue(true, true);
assertEquals(expected, actual);
}

@Test
public void testCalculateWeight() {
File f;
File f;
MechFileParser mfp;
Entity e;
int expectedWeight, computedWeight;

// Test 1/1
try {
f = new File("data/mechfiles/mechs/3050U/Exterminator EXT-4A.mtf");
Expand All @@ -93,4 +92,65 @@ public void testCalculateWeight() {
fail(ex.getMessage());
}
}

/**
* Verify new Tank method .isImmobilizedForJump() returns correct values in
* various states. Note: vehicles cannot lose individual Jump Jets via crits,
* so this is not tested.
*/
@Test
public void testIsImmobilizedForJump() {
File f;
MechFileParser mfp;
Entity e;

// Test 1/1
try {
f = new File("data/mechfiles/vehicles/3050U/Kanga Medium Hovertank.blk");
mfp = new MechFileParser(f);
e = mfp.getEntity();
Tank t = (Tank) e;
Crew c = t.getCrew();

// 1 Crew condition
// 1.a Killed crew should prevent jumping; live crew should allow jumping
c.setDead(true);
assertTrue(t.isImmobileForJump());
c.resetGameState();
assertFalse(t.isImmobileForJump());

// 1.b Unconscious crew should prevent jumping; conscious crew should allow jumping
c.setUnconscious(true);
assertTrue(t.isImmobileForJump());
c.resetGameState();
assertFalse(t.isImmobileForJump());

// 1.c Stunned crew should _not_ prevent jumping
t.setStunnedTurns(1);
assertFalse(t.isImmobileForJump());
t.setStunnedTurns(0);

// 2. Engine condition
// 2.a Engine hit should prevent jumping; fixing engine should enable jumping
t.engineHit();
assertTrue(t.isImmobileForJump());
t.engineFix();
assertFalse(t.isImmobileForJump());

// 2.b Shutdown should prevent jumping; restarting should enable jumping
t.setShutDown(true);
assertTrue(t.isImmobileForJump());
t.setShutDown(false);
assertFalse(t.isImmobileForJump());

// 3. Immobilization due to massive damage motive hit / reducing MP to 0 should
// _not_ prevent jumping
t.setMotiveDamage(t.getOriginalWalkMP());
assertFalse(t.isImmobileForJump());
t.setMotiveDamage(0);

} catch (Exception ex) {
fail(ex.getMessage());
}
}
}

0 comments on commit bcb248d

Please sign in to comment.