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

Issue 6303: RFE - Ultra Sublevel #6502

Merged
merged 3 commits into from
Feb 7, 2025
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
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
super * "ultra_sublevel:*;" "" "ultra_sublevel/ultra_sublevel.png"
1 change: 1 addition & 0 deletions megamek/data/images/hexes/atmospheric.tileset
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,7 @@ include "StandardIncludes/StandardThemes.tileinc"

include "StandardIncludes/StandardSpace.tileinc"

include "StandardIncludes/StandardUltraSublevel.tileinc"
include "StandardIncludes/StandardHazardousLiquid.tileinc"

super * "water:0" "" "transparent/blue_water_1.png"
Expand Down
1 change: 1 addition & 0 deletions megamek/data/images/hexes/bw_atmospheric.tileset
Original file line number Diff line number Diff line change
Expand Up @@ -128,6 +128,7 @@ base -6 "" "volcano" "largeTextures/textureVolcano-6.jpg"

include "StandardIncludes/StandardThemes.tileinc"

include "StandardIncludes/StandardUltraSublevel.tileinc"
include "StandardIncludes/StandardHazardousLiquid.tileinc"

super * "water:0" "" "bloodwolf/hq_boring/blue_water_0.png;bloodwolf/hq_boring/blue_water_0.png(0,72-84,-72);bloodwolf/hq_boring/blue_water_0.png(84,0--84,72);bloodwolf/hq_boring/blue_water_0.png(84,72--84,-72)"
Expand Down
1 change: 1 addition & 0 deletions megamek/data/images/hexes/classic.tileset
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ include "StandardIncludes/StandardThemes.tileinc"

include "StandardIncludes/StandardSpace.tileinc"

include "StandardIncludes/StandardUltraSublevel.tileinc"
include "StandardIncludes/StandardHazardousLiquid.tileinc"

super * "water:0" "" "boring/blue_water_1.gif"
Expand Down
1 change: 1 addition & 0 deletions megamek/data/images/hexes/hq_atmospheric.tileset
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,7 @@ include "StandardIncludes/StandardThemes.tileinc"

include "StandardIncludes/StandardSpace.tileinc"

include "StandardIncludes/StandardUltraSublevel.tileinc"
include "StandardIncludes/StandardHazardousLiquid.tileinc"

super * "water:0" "" "transparent/anim_water_1.gif"
Expand Down
1 change: 1 addition & 0 deletions megamek/data/images/hexes/hq_isometric.tileset
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,7 @@ include "StandardIncludes/StandardThemes.tileinc"

include "StandardIncludes/StandardSpace.tileinc"

include "StandardIncludes/StandardUltraSublevel.tileinc"
include "StandardIncludes/StandardHazardousLiquid.tileinc"

super * "water:0" "" "transparent/anim_water_1.gif"
Expand Down
1 change: 1 addition & 0 deletions megamek/data/images/hexes/hq_saxarba.tileset
Original file line number Diff line number Diff line change
Expand Up @@ -87,6 +87,7 @@ super 8 "sand:*" "" "saxarba/base/base_sand_8.png"
super 9 "sand:*" "" "saxarba/base/base_sand_9.png"
super 10 "sand:*" "" "saxarba/base/base_sand_10.png"

include "StandardIncludes/StandardUltraSublevel.tileinc"
include "StandardIncludes/StandardHazardousLiquid.tileinc"

#MARS THEME WATER
Expand Down
1 change: 1 addition & 0 deletions megamek/data/images/hexes/isometric.tileset
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,7 @@ include "StandardIncludes/StandardThemes.tileinc"

include "StandardIncludes/StandardSpace.tileinc"

include "StandardIncludes/StandardUltraSublevel.tileinc"
include "StandardIncludes/StandardHazardousLiquid.tileinc"

super * "water:0" "" "transparent/blue_water_1.png"
Expand Down
1 change: 1 addition & 0 deletions megamek/data/images/hexes/largeTextures.tileset
Original file line number Diff line number Diff line change
Expand Up @@ -171,6 +171,7 @@ base -6 "" "" "Ahne/iLarge_Textures/BigPlains-6.jpg"

base 0 "space:1" "" "largeTextures/BigSpace.jpg"

include "StandardIncludes/StandardUltraSublevel.tileinc"
include "StandardIncludes/StandardHazardousLiquid.tileinc"

#base 1 "water:*" "" "Ahne/iLarge_Textures/BigWater.jpg(0,72-84,-72);Ahne/iLarge_Textures/BigWater.jpg(84,0--84,72);Ahne/iLarge_Textures/BigWater.jpg(84,72--84,-72)"
Expand Down
1 change: 1 addition & 0 deletions megamek/data/images/hexes/saxarba.tileset
Original file line number Diff line number Diff line change
Expand Up @@ -90,6 +90,7 @@ super 8 "sand:*" "" "saxarba/base/base_sand_8.png"
super 9 "sand:*" "" "saxarba/base/base_sand_9.png"
super 10 "sand:*" "" "saxarba/base/base_sand_10.png"

include "StandardIncludes/StandardUltraSublevel.tileinc"
include "StandardIncludes/StandardHazardousLiquid.tileinc"

#MARS THEME WATER
Expand Down
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
1 change: 1 addition & 0 deletions megamek/i18n/megamek/client/messages.properties
Original file line number Diff line number Diff line change
Expand Up @@ -2711,6 +2711,7 @@ MovementDisplay.MagmaCrustMoving=Crossing magma crust will break through on 6+ o
MovementDisplay.MagmaCrustJumpLanding=Jumping onto magma crust will break through on 4+ on 1d6.\n
MovementDisplay.MagmaLiquidMoving=Red hot molten lava melts armour and destroys non-meks!\n
MovementDisplay.HazardousLiquidMoving=Caustic hazardous liquids may damage units!\n
MovementDisplay.UltraSublevel=Ultra sublevels will destroy units!\n
MovementDisplay.ManeuverDialog.title=Choose Maneuver
MovementDisplay.MicroliteMove.message=Microlite VTOL units must enter a new hex each turn to remain in flight.\n
MovementDisplay.MicroliteMove.title=Microlite VTOL movement
Expand Down
3 changes: 3 additions & 0 deletions megamek/i18n/megamek/common/messages.properties
Original file line number Diff line number Diff line change
Expand Up @@ -427,6 +427,7 @@ Terrains.editorName.incline_high_bottom=High Incline Bottom
Terrains.editorName.cliff_bottom=Cliff Bottom
Terrains.editorName.deployment_zone=Deployment Zone
Terrains.editorName.hazardous_liquid=Hazardous Liquid
Terrains.editorName.ultra_sublevel=Ultra Sublevel

Terrains.editorTooltip.woods=Woods
Terrains.editorTooltip.water=Water
Expand Down Expand Up @@ -786,3 +787,5 @@ HazardousLiquidPoolUtil.CLASS_1.text=Class 1: Slightly Hazardous
HazardousLiquidPoolUtil.CLASS_2.text=Class 2: Hazardous
HazardousLiquidPoolUtil.CLASS_3.text=Class 3: Extreme Danger
HazardousLiquidPoolUtil.DEADLY.text=Deadly

TWGameManager.report.ultra_sublevel.text=falling into a deep hole
31 changes: 30 additions & 1 deletion megamek/src/megamek/client/bot/princess/BasicPathRanker.java
Original file line number Diff line number Diff line change
Expand Up @@ -889,6 +889,8 @@ private double checkHexForHazards(Hex hex, Entity movingUnit, boolean endHex, Mo
case Terrains.HAZARDOUS_LIQUID:
hazardValue += calcHazardousLiquidHazard(hex, endHex, movingUnit, step);
break;
case Terrains.ULTRA_SUBLEVEL:
hazardValue += calcUltraSublevelHazard(endHex, movingUnit);
}
}

Expand All @@ -908,7 +910,8 @@ private double checkHexForHazards(Hex hex, Entity movingUnit, boolean endHex, Mo
Terrains.SWAMP,
Terrains.MUD,
Terrains.TUNDRA,
Terrains.HAZARDOUS_LIQUID));
Terrains.HAZARDOUS_LIQUID,
Terrains.ULTRA_SUBLEVEL));
private static final Set<Integer> HAZARDS_WITH_BLACK_ICE = new HashSet<>();
static {
HAZARDS_WITH_BLACK_ICE.addAll(HAZARDS);
Expand Down Expand Up @@ -1352,6 +1355,32 @@ private double calcHazardousLiquidHazard(Hex hex, boolean endHex, Entity movingU
return Math.round(hazardValue);
}

private double calcUltraSublevelHazard(boolean endHex, Entity movingUnit) {
logger.trace("Calculating ultra sublevel hazard.");
int unitDamageLevel = movingUnit.getDamageLevel();
double dmg;

// Hovers/VTOLs are unaffected _unless_ they end on the hex and are in danger of
// losing mobility.
if (EntityMovementMode.HOVER == movingUnit.getMovementMode()
|| EntityMovementMode.WIGE == movingUnit.getMovementMode()) {
if (!endHex) {
logger.trace("Hovering/VTOL while traversing ultra sublevel (0).");
return 0;
} else if (movingUnit.getElevation() > 0) { //elevation of 0 is on the ground (not airborne), which would be destroyed
// Estimate chance of being disabled or immobilized over ultra sublevel; this is
// fatal!
// Calc expected damage as ((current damage level [0 ~ 4]) / 4) *
// UNIT_DESTRUCTION_FACTOR
dmg = (unitDamageLevel / 4.0) * UNIT_DESTRUCTION_FACTOR;
logger.trace("Ending hover/VTOL movement over ultra sublevel ({}).", dmg);
return dmg;
Comment on lines +1373 to +1377
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

if current unit damage level is 0 then the dmg it counts is 0, I suggest juts setting return UNIT_DESTRUCTION_FACTOR

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

if current unit damage level is 0 then the dmg it counts is 0, I suggest juts setting return UNIT_DESTRUCTION_FACTOR

We want unit damage level 0 to indicate that we expect no damage from crossing or stopping on this hex:

0/4 * UNIT_DESTRUCTION_FACTOR = expected hazard damage == 0
1/4 * UNIT_DESTRUCTION_FACTOR = expected hazard damage == UNIT_DESTRUCTION_FACTOR / 4

etc.
The goal is to let Princess drive more aggressively with fresh units, but become more cautious as damage increases.

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

if current unit damage level is 0 then the dmg it counts is 0, I suggest juts setting return UNIT_DESTRUCTION_FACTOR

We want unit damage level 0 to indicate that we expect no damage from crossing or stopping on this hex:

0/4 * UNIT_DESTRUCTION_FACTOR = expected hazard damage == 0
1/4 * UNIT_DESTRUCTION_FACTOR = expected hazard damage == UNIT_DESTRUCTION_FACTOR / 4

etc. The goal is to let Princess drive more aggressively with fresh units, but become more cautious as damage increases.

That's the intent, yeah, this is ripped from the Magma (technically Hazardous Liquid, but that was ripped from Magma) Path Ranker logic. In this specific case it's intended just for VTOLs - a fresh VTOL should feel safe ending its turn over a death hex. But increasingly damaged ones should view it as increasingly dangerous as they get closer to being immobilized and thus risk falling victim to an instant death.

It's why they share the common bug I elude to in a comment in BasicPathRankerTest - VTOLs don't actually consider the ground below them because of some logic at the start of BasicPathRanker::checkPathForHazards - and I'd rather not touch that if I don't have to, that could have other unintended consequences.

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fair, I missed the (EntityMovementMode.HOVER == movingUnit.getMovementMode() || EntityMovementMode.WIGE == movingUnit.getMovementMode()) { at the top

}
}
logger.trace(String.format("Ground unit instant destruction from ultra sublevel (%s).", UNIT_DESTRUCTION_FACTOR));
return UNIT_DESTRUCTION_FACTOR;
}

private double calcBogDownFactor(String name, boolean endHex, boolean jumpLanding, int pilotSkill, int modifier) {
return calcBogDownFactor(name, endHex, jumpLanding, pilotSkill, modifier, true);
}
Expand Down
15 changes: 15 additions & 0 deletions megamek/src/megamek/client/ui/SharedUtility.java
Original file line number Diff line number Diff line change
Expand Up @@ -357,6 +357,16 @@ private static Object doPSRCheck(MovePath md, boolean stringResult) {
.getTextAt("megamek.client.messages", "MovementDisplay.HazardousLiquidMoving"));
}

// Check for Hazardous Liquid
if (curHex.containsTerrain(Terrains.ULTRA_SUBLEVEL) && (step.getElevation() <= 0)
&& (moveType != EntityMovementType.MOVE_JUMP)
&& (entity.getMovementMode() != EntityMovementMode.HOVER)
&& (entity.getMovementMode() != EntityMovementMode.WIGE)
&& !(curPos.equals(lastPos))) {
nagReport.append(Internationalization
.getTextAt("megamek.client.messages", "MovementDisplay.UltraSublevel"));
}

// check for sideslip
if ((entity instanceof VTOL)
|| (entity.getMovementMode() == EntityMovementMode.HOVER)
Expand Down Expand Up @@ -616,6 +626,11 @@ private static Object doPSRCheck(MovePath md, boolean stringResult) {
nagReport.append(Internationalization
.getTextAt("megamek.client.messages", "MovementDisplay.HazardousLiquidMoving"));
}

if ((hex.containsTerrain(Terrains.ULTRA_SUBLEVEL) && lastElevation == 0)) {
nagReport.append(Internationalization
.getTextAt("megamek.client.messages", "MovementDisplay.UltraSublevel"));
}
}

if (entity.isAirborne() && entity.isAero()) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -75,6 +75,12 @@ public Entity getEntity() {
*/
@Override
public void prepare() {
if (entity.getPosition() != null && entity.getGame() != null && entity.getGame().getBoard() != null
&& entity.getGame().getBoard().getHex(entity.getPosition()) != null &&
entity.getGame().getBoard().getHex(entity.getPosition()).containsTerrain(Terrains.ULTRA_SUBLEVEL)) {
return; //Don't show wrecks for "Ultra Sublevels" - The unit fell through the map!
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Glorious!

}

// create image for buffer
image = ImageUtil.createAcceleratedImage(HexTileset.HEX_W, HexTileset.HEX_H);
Graphics2D graph = (Graphics2D) image.getGraphics();
Expand Down
7 changes: 5 additions & 2 deletions megamek/src/megamek/common/Terrains.java
Original file line number Diff line number Diff line change
Expand Up @@ -65,7 +65,6 @@ public class Terrains implements Serializable {
// Bug Storm
// Extreme Depths
// Rail
// Dirt Roads, Gravel Roads
// Water Flow

public static final int FIRE_LVL_NORMAL = 1;
Expand Down Expand Up @@ -155,6 +154,8 @@ public class Terrains implements Serializable {

public static final int HAZARDOUS_LIQUID = 58;

public static final int ULTRA_SUBLEVEL = 59;

/**
* Keeps track of the different type of terrains that can have exits.
*/
Expand All @@ -167,7 +168,7 @@ public class Terrains implements Serializable {
"fuel_tank_magn", "impassable", "elevator", "fortified", "screen", "fluff", "arms", "legs", "metal_deposit",
"bldg_base_collapsed", "bldg_fluff", "road_fluff", "ground_fluff", "water_fluff", "cliff_top", "cliff_bottom",
"incline_top", "incline_bottom", "incline_high_top", "incline_high_bottom", "foliage_elev", "black_ice", "sky",
"deployment_zone", "hazardous_liquid" };
"deployment_zone", "hazardous_liquid", "ultra_sublevel" };

/** Terrains in this set are hidden in the Editor, not saved to board files and handled internally. */
public static final HashSet<Integer> AUTOMATIC = new HashSet<>(Arrays.asList(
Expand Down Expand Up @@ -411,6 +412,8 @@ public static String getDisplayName(int type, int level) {
default:
return "Hazardous Liquid";
}
case ULTRA_SUBLEVEL:
return "Ultra Sublevel";
default:
return null;
}
Expand Down
6 changes: 6 additions & 0 deletions megamek/src/megamek/server/ServerHelper.java
Original file line number Diff line number Diff line change
Expand Up @@ -525,6 +525,12 @@ public static void checkEnteringHazardousLiquid(Hex hex, int elevation, Entity e
}
}

public static void checkEnteringUltraSublevel(Hex hex, int elevation, Entity entity, TWGameManager gameManager) {
if (hex.containsTerrain(Terrains.ULTRA_SUBLEVEL) && (elevation <= 0)) {
gameManager.doUltraSublevelDamage(entity);
}
}

/**
* Check for black ice when moving into pavement hex.
*/
Expand Down
2 changes: 2 additions & 0 deletions megamek/src/megamek/server/totalwarfare/MovePathHandler.java
Original file line number Diff line number Diff line change
Expand Up @@ -768,6 +768,7 @@ && getGame().getOptions().booleanOption(OptionsConstants.ADVAERORULES_FUEL_CONSU
gameManager.getMainPhaseReport(), gameManager);
ServerHelper.checkEnteringMagma(curHex, entity.getElevation(), entity, gameManager);
ServerHelper.checkEnteringHazardousLiquid(curHex, entity.getElevation(), entity, gameManager);
ServerHelper.checkEnteringUltraSublevel(curHex, entity.getElevation(), entity, gameManager);

// jumped into swamp? maybe stuck!
if (curHex.getBogDownModifier(entity.getMovementMode(),
Expand Down Expand Up @@ -2526,6 +2527,7 @@ && getGame().getOptions().booleanOption(OptionsConstants.ADVGRNDMOV_TACOPS_LEAPI
gameManager.getMainPhaseReport(), gameManager);
ServerHelper.checkEnteringMagma(curHex, step.getElevation(), entity, gameManager);
ServerHelper.checkEnteringHazardousLiquid(curHex, step.getElevation(), entity, gameManager);
ServerHelper.checkEnteringUltraSublevel(curHex, entity.getElevation(), entity, gameManager);
}
}

Expand Down
15 changes: 15 additions & 0 deletions megamek/src/megamek/server/totalwarfare/TWGameManager.java
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,7 @@
import megamek.common.equipment.WeaponMounted;
import megamek.common.force.Force;
import megamek.common.force.Forces;
import megamek.common.internationalization.Internationalization;
import megamek.common.net.enums.PacketCommand;
import megamek.common.net.packets.Packet;
import megamek.common.options.GameOptions;
Expand Down Expand Up @@ -4689,6 +4690,7 @@ else if ((target instanceof Infantry) && (bldg != null)) {
ServerHelper.checkAndApplyMagmaCrust(nextHex, nextElevation, entity, curPos, false, mainPhaseReport, this);
ServerHelper.checkEnteringMagma(nextHex, nextElevation, entity, this);
ServerHelper.checkEnteringHazardousLiquid(nextHex, nextElevation, entity, this);
ServerHelper.checkEnteringUltraSublevel(curHex, entity.getElevation(), entity, this);

// is the next hex a swamp?
PilotingRollData rollTarget = entity.checkBogDown(step, moveType, nextHex, curPos, nextPos,
Expand Down Expand Up @@ -8907,6 +8909,7 @@ Vector<Report> doEntityDisplacement(Entity entity, Coords src,
ServerHelper.checkAndApplyMagmaCrust(destHex, entity.getElevation(), entity, dest, false, displacementReport, this);
ServerHelper.checkEnteringMagma(destHex, entity.getElevation(), entity, this);
ServerHelper.checkEnteringHazardousLiquid(destHex, entity.getElevation(), entity, this);
ServerHelper.checkEnteringUltraSublevel(destHex, entity.getElevation(), entity, this);

Entity violation = Compute.stackingViolation(game, entity.getId(), dest, entity.climbMode());
if (violation == null) {
Expand Down Expand Up @@ -24632,6 +24635,7 @@ else if ((null != Compute.stackingViolation(game, other.getId(), curPos, entity.
Hex entityHex = game.getBoard().getHex(curPos);
if (game.getOptions().booleanOption(OptionsConstants.ADVANCED_TACOPS_BATTLE_WRECK)
&& (entityHex != null) && game.getBoard().onGround()
&& !entityHex.containsTerrain(Terrains.ULTRA_SUBLEVEL)
&& !((entity instanceof Infantry) || (entity instanceof ProtoMek))) {
// large support vees will create ultra rough, otherwise rough
if (entity instanceof LargeSupportTank) {
Expand Down Expand Up @@ -31254,6 +31258,17 @@ public void doHazardousLiquidDamage(Entity en, boolean eruption, int depth) {
addNewLines();
}

public void doUltraSublevelDamage(Entity entity) {
if (!isUnitEffectedByHazardousGround(entity, false)) {
return;
}

// {entity} fell into a hole and was never seen again
addReport(destroyEntity(entity, Internationalization.getText("TWGameManager.report.ultra_sublevel.text"), false, false));
addNewLines();
}


/**
* Applies damage to any eligible unit hit by anti-TSM missiles or entering
* a hex with green smoke.
Expand Down
Loading