From 24ebd714853b1956a5236be96e69200ee1cad3bb Mon Sep 17 00:00:00 2001 From: psikomonkie <189469115+psikomonkie@users.noreply.github.com> Date: Sat, 1 Feb 2025 16:02:35 -0500 Subject: [PATCH] Issue 6303: RFE - Hazardous Liquid Pools - Changes requested by @rjhancock --- .../client/bot/princess/BasicPathRanker.java | 2 +- megamek/src/megamek/common/Terrains.java | 17 +- .../common/enums/HazardousLiquidPoolType.java | 49 ++ .../bot/princess/BasicPathRankerTest.java | 440 ++++++++++++------ 4 files changed, 347 insertions(+), 161 deletions(-) create mode 100644 megamek/src/megamek/common/enums/HazardousLiquidPoolType.java diff --git a/megamek/src/megamek/client/bot/princess/BasicPathRanker.java b/megamek/src/megamek/client/bot/princess/BasicPathRanker.java index 55c2424cf4d..09a4ec66c56 100644 --- a/megamek/src/megamek/client/bot/princess/BasicPathRanker.java +++ b/megamek/src/megamek/client/bot/princess/BasicPathRanker.java @@ -1337,7 +1337,7 @@ private double calcHazardousLiquidHazard(Hex hex, boolean endHex, Entity movingU // After all that math let's make sure we do at least 1 damage // (.6 repeating when normalized for the HLP doing no damage 1/3 of the time) - dmg = Math.max(dmg, 0.666); + dmg = Math.max(dmg, 2.0/3.0); if (step.isProne() || (hex.containsTerrain(Terrains.WATER) && hex.terrainLevel(Terrains.WATER) > 1)) { exposedArmor = movingUnit.getTotalArmor(); diff --git a/megamek/src/megamek/common/Terrains.java b/megamek/src/megamek/common/Terrains.java index 1d5c443e704..35933463f7d 100644 --- a/megamek/src/megamek/common/Terrains.java +++ b/megamek/src/megamek/common/Terrains.java @@ -18,6 +18,7 @@ import java.util.HashSet; import java.util.Hashtable; +import megamek.common.enums.HazardousLiquidPoolType; import megamek.server.SmokeCloud; public class Terrains implements Serializable { @@ -153,13 +154,6 @@ public class Terrains implements Serializable { public static final int DEPLOYMENT_ZONE = 57; public static final int HAZARDOUS_LIQUID = 58; - // Wind blown hazardous is for MapPack Alien Worlds' Wind Blown Hazardous Liquid rules - // Wind blown (MP: Alien Rules) isn't implemented - // Water flow (TO:AR 47 for Hazardous Pools rules) isn't implemented - public static final int HAZARDOUS_LIQUID_LVL_NORMAL = 0; - public static final int HAZARDOUS_LIQUID_LVL_WIND_BLOWN = 1; - public static final int HAZARDOUS_LIQUID_LVL_FLOWS = 2; - public static final int HAZARDOUS_LIQUID_LVL_FLOWS_AND_WIND_BLOWN = 3; /** * Keeps track of the different type of terrains that can have exits. @@ -406,12 +400,13 @@ public static String getDisplayName(int type, int level) { case DEPLOYMENT_ZONE: return "Deployment Zone"; case HAZARDOUS_LIQUID: - switch (level) { - case HAZARDOUS_LIQUID_LVL_WIND_BLOWN: + HazardousLiquidPoolType hazardousLiquidPoolType = HazardousLiquidPoolType.getType(level); + switch (hazardousLiquidPoolType) { + case WIND_BLOWN: return "Hazardous Liquid (Wind Blown)"; - case HAZARDOUS_LIQUID_LVL_FLOWS: + case FLOWS: return "Hazardous Liquid (Flows)"; - case HAZARDOUS_LIQUID_LVL_FLOWS_AND_WIND_BLOWN: + case FLOWS_AND_WIND_BLOWN: return "Hazardous Liquid (Flows and Wind Blown)"; default: return "Hazardous Liquid"; diff --git a/megamek/src/megamek/common/enums/HazardousLiquidPoolType.java b/megamek/src/megamek/common/enums/HazardousLiquidPoolType.java new file mode 100644 index 00000000000..bf2992ee8d3 --- /dev/null +++ b/megamek/src/megamek/common/enums/HazardousLiquidPoolType.java @@ -0,0 +1,49 @@ +/* + * Copyright (c) 2025 - The MegaMek Team. All Rights Reserved. + * + * This file is part of MegaMek. + * + * MegaMek is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * MegaMek is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with MegaMek. If not, see . + */ + +package megamek.common.enums; + +import java.util.Arrays; + +/** + * A hazardous liquid pool can be wind-blown, pushed by water flow, both, or neither. + */ +public enum HazardousLiquidPoolType { + // Wind blown hazardous is for MapPack Alien Worlds' Wind Blown Hazardous Liquid rules + // Wind blown (MP: Alien Rules) isn't implemented + // Water flow (TO:AR 47 for Hazardous Pools rules) isn't implemented + NORMAL(0), + WIND_BLOWN(1), + FLOWS(2), + FLOWS_AND_WIND_BLOWN(3); + + private final Integer terrainLevel; + + HazardousLiquidPoolType(final Integer terrainLevel) { + this.terrainLevel = terrainLevel; + } + + public int getTerrainLevel() { + return this.terrainLevel; + } + + public static HazardousLiquidPoolType getType(final int ordinal) { + return Arrays.stream(HazardousLiquidPoolType.values()).filter(type -> type.ordinal() == ordinal).findFirst().orElse(NORMAL); + } +} diff --git a/megamek/unittests/megamek/client/bot/princess/BasicPathRankerTest.java b/megamek/unittests/megamek/client/bot/princess/BasicPathRankerTest.java index da17f6f7185..f77e2b96be1 100644 --- a/megamek/unittests/megamek/client/bot/princess/BasicPathRankerTest.java +++ b/megamek/unittests/megamek/client/bot/princess/BasicPathRankerTest.java @@ -39,6 +39,7 @@ import java.util.*; import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Nested; import org.junit.jupiter.api.Test; import megamek.client.bot.princess.BotGeometry.HexLine; @@ -1439,78 +1440,6 @@ void testCheckPathForHazards() { when(mockFinalHex.getTerrainTypesSet()).thenReturn(new HashSet<>(Set.of(0))); when(mockFinalHex.terrainLevel(Terrains.MAGMA)).thenReturn(0); - // Test walking through 3 hexes of shallow hazardous liquid. - when(mockPath.isJumping()).thenReturn(false); - when(mockHexTwo.getTerrainTypesSet()).thenReturn(new HashSet<>(Set.of(Terrains.HAZARDOUS_LIQUID, Terrains.WATER))); - when(mockHexThree.getTerrainTypesSet()).thenReturn(new HashSet<>(Set.of(Terrains.HAZARDOUS_LIQUID, Terrains.WATER))); - when(mockFinalHex.getTerrainTypesSet()).thenReturn(new HashSet<>(Set.of(Terrains.HAZARDOUS_LIQUID, Terrains.WATER))); - when(mockHexTwo.terrainLevel(Terrains.HAZARDOUS_LIQUID)).thenReturn(1); - when(mockHexThree.terrainLevel(Terrains.HAZARDOUS_LIQUID)).thenReturn(1); - when(mockFinalHex.terrainLevel(Terrains.HAZARDOUS_LIQUID)).thenReturn(1); - when(mockHexTwo.terrainLevel(Terrains.WATER)).thenReturn(1); - when(mockHexThree.terrainLevel(Terrains.WATER)).thenReturn(1); - when(mockFinalHex.terrainLevel(Terrains.WATER)).thenReturn(1); - when(mockHexTwo.containsTerrain(Terrains.WATER)).thenReturn(true); - when(mockHexThree.containsTerrain(Terrains.WATER)).thenReturn(true); - when(mockFinalHex.containsTerrain(Terrains.WATER)).thenReturn(true); - assertEquals(450.0, testRanker.checkPathForHazards(mockPath, mockUnit, mockGame), TOLERANCE); - when(mockHexTwo.getTerrainTypesSet()).thenReturn(new HashSet<>(Set.of(0))); - when(mockHexThree.getTerrainTypesSet()).thenReturn(new HashSet<>(Set.of(0))); - when(mockFinalHex.getTerrainTypesSet()).thenReturn(new HashSet<>(Set.of(0))); - when(mockHexTwo.terrainLevel(Terrains.HAZARDOUS_LIQUID)).thenReturn(0); - when(mockHexThree.terrainLevel(Terrains.HAZARDOUS_LIQUID)).thenReturn(0); - when(mockFinalHex.terrainLevel(Terrains.HAZARDOUS_LIQUID)).thenReturn(0); - when(mockHexTwo.terrainLevel(Terrains.WATER)).thenReturn(0); - when(mockHexThree.terrainLevel(Terrains.WATER)).thenReturn(0); - when(mockFinalHex.terrainLevel(Terrains.WATER)).thenReturn(0); - when(mockHexTwo.containsTerrain(Terrains.WATER)).thenReturn(false); - when(mockHexThree.containsTerrain(Terrains.WATER)).thenReturn(false); - when(mockFinalHex.containsTerrain(Terrains.WATER)).thenReturn(false); - - // Test walking through 3 hexes of deep hazardous liquid - this should be extremely dangerous for our test unit!. - when(mockPath.isJumping()).thenReturn(false); - when(mockHexTwo.getTerrainTypesSet()).thenReturn(new HashSet<>(Set.of(Terrains.HAZARDOUS_LIQUID, Terrains.WATER))); - when(mockHexThree.getTerrainTypesSet()).thenReturn(new HashSet<>(Set.of(Terrains.HAZARDOUS_LIQUID, Terrains.WATER))); - when(mockFinalHex.getTerrainTypesSet()).thenReturn(new HashSet<>(Set.of(Terrains.HAZARDOUS_LIQUID, Terrains.WATER))); - when(mockHexTwo.terrainLevel(Terrains.HAZARDOUS_LIQUID)).thenReturn(1); - when(mockHexThree.terrainLevel(Terrains.HAZARDOUS_LIQUID)).thenReturn(1); - when(mockFinalHex.terrainLevel(Terrains.HAZARDOUS_LIQUID)).thenReturn(1); - when(mockHexTwo.terrainLevel(Terrains.WATER)).thenReturn(2); - when(mockHexThree.terrainLevel(Terrains.WATER)).thenReturn(2); - when(mockFinalHex.terrainLevel(Terrains.WATER)).thenReturn(2); - when(mockHexTwo.containsTerrain(Terrains.WATER)).thenReturn(true); - when(mockHexThree.containsTerrain(Terrains.WATER)).thenReturn(true); - when(mockFinalHex.containsTerrain(Terrains.WATER)).thenReturn(true); - assertEquals(9000.0, testRanker.checkPathForHazards(mockPath, mockUnit, mockGame), TOLERANCE); - when(mockHexTwo.getTerrainTypesSet()).thenReturn(new HashSet<>(Set.of(0))); - when(mockHexThree.getTerrainTypesSet()).thenReturn(new HashSet<>(Set.of(0))); - when(mockFinalHex.getTerrainTypesSet()).thenReturn(new HashSet<>(Set.of(0))); - when(mockHexTwo.terrainLevel(Terrains.HAZARDOUS_LIQUID)).thenReturn(0); - when(mockHexThree.terrainLevel(Terrains.HAZARDOUS_LIQUID)).thenReturn(0); - when(mockFinalHex.terrainLevel(Terrains.HAZARDOUS_LIQUID)).thenReturn(0); - when(mockHexTwo.terrainLevel(Terrains.WATER)).thenReturn(0); - when(mockHexThree.terrainLevel(Terrains.WATER)).thenReturn(0); - when(mockFinalHex.terrainLevel(Terrains.WATER)).thenReturn(0); - when(mockHexTwo.containsTerrain(Terrains.WATER)).thenReturn(false); - when(mockHexThree.containsTerrain(Terrains.WATER)).thenReturn(false); - when(mockFinalHex.containsTerrain(Terrains.WATER)).thenReturn(false); - - // Test the stupidity of going prone in shallow hazardous liquid. - // Now that hazard is inversely related to remaining armor, this is a _BIG_ - // number - when(mockPath.isJumping()).thenReturn(false); - when(mockFinalStep.isProne()).thenReturn(true); - when(mockFinalHex.getTerrainTypesSet()).thenReturn(new HashSet<>(Set.of(Terrains.HAZARDOUS_LIQUID, Terrains.WATER))); - when(mockFinalHex.terrainLevel(Terrains.HAZARDOUS_LIQUID)).thenReturn(1);; - when(mockFinalHex.terrainLevel(Terrains.WATER)).thenReturn(1); - when(mockFinalHex.containsTerrain(Terrains.WATER)).thenReturn(true); - assertEquals(3000.0, testRanker.checkPathForHazards(mockPath, mockUnit, mockGame), TOLERANCE); - when(mockFinalStep.isProne()).thenReturn(false); - when(mockFinalHex.getTerrainTypesSet()).thenReturn(new HashSet<>(Set.of(0))); - when(mockFinalHex.terrainLevel(Terrains.HAZARDOUS_LIQUID)).thenReturn(0);; - when(mockFinalHex.terrainLevel(Terrains.WATER)).thenReturn(0); - when(mockFinalHex.containsTerrain(Terrains.WATER)).thenReturn(false); - // Test walking through 2 hexes of fire. when(mockPath.isJumping()).thenReturn(false); when(mockHexTwo.getTerrainTypesSet()).thenReturn(new HashSet<>(Set.of(Terrains.WOODS, Terrains.FIRE))); @@ -1671,105 +1600,318 @@ void testMagmaHazard() { assertEquals(83.0, testRanker.checkPathForHazards(mockPath, mockTank, mockGame), TOLERANCE); } - @Test - void testHazardousLiquidHazard() { - final BasicPathRanker testRanker = spy(new BasicPathRanker(mockPrincess)); - final List testCoords = setupCoords("10,7", "10,8", "10,9", "10,10"); - final Coords testCoordsThree = testCoords.get(2); + @Nested + /** + * The tests from most the hazard-testing-related-tests could + * probably be broken down into individual tests - and put here. + */ + class hazardTests { + BasicPathRanker testRanker; + List testCoords; + Coords testCoordsThree; + List testHexes; + Hex mockFinalHex; + Vector stepVector; + MovePath mockPath; - final List testHexes = setupHexes(testCoords); - final Hex mockFinalHex = testHexes.get(3); + Game mockGame; - final Vector stepVector = setupMoveStepVector(testCoords); + Entity mockUnit; + Crew mockCrew; - final MovePath mockPath = setupPath(stepVector); + Building mockBuilding; - final Entity mockUnit = mock(BipedMek.class); - when(mockUnit.locations()).thenReturn(8); - when(mockUnit.getArmor(anyInt())).thenReturn(10); + @BeforeEach + void init() { + testRanker = spy(new BasicPathRanker(mockPrincess)); - final Game mockGame = setupGame(testCoords, testHexes); + testCoords = setupCoords("10,7", "10,8", "10,9", "10,10"); + testCoordsThree = testCoords.get(2); - final Crew mockCrew = mock(Crew.class); - when(mockUnit.getCrew()).thenReturn(mockCrew); - when(mockCrew.getPiloting()).thenReturn(5); + testHexes = setupHexes(testCoords); + mockFinalHex = testHexes.get(3); - final Building mockBuilding = mock(Building.class); - when(mockGame.getBoard().getBuildingAt(eq(testCoordsThree))).thenReturn(mockBuilding); - when(mockBuilding.getCurrentCF(eq(testCoordsThree))).thenReturn(77); + stepVector = setupMoveStepVector(testCoords); - // Test jumping onto Magma Crust. - when(mockPath.isJumping()).thenReturn(true); - when(mockUnit.getArmor(eq(Mek.LOC_LLEG))).thenReturn(24); - when(mockUnit.getArmor(eq(Mek.LOC_RLEG))).thenReturn(24); - when(mockFinalHex.depth()).thenReturn(1); - when(mockFinalHex.getTerrainTypesSet()).thenReturn(new HashSet<>(Set.of(Terrains.HAZARDOUS_LIQUID, Terrains.WATER))); - when(mockFinalHex.terrainLevel(Terrains.WATER)).thenReturn(1); - when(mockFinalHex.containsTerrain(Terrains.WATER)).thenReturn(true); - when(mockFinalHex.terrainLevel(Terrains.HAZARDOUS_LIQUID)).thenReturn(1); - assertEquals(63.0, testRanker.checkPathForHazards(mockPath, mockUnit, mockGame), TOLERANCE); + mockPath = setupPath(stepVector); + mockGame = setupGame(testCoords, testHexes); + mockUnit = mock(BipedMek.class); - // Test damaged 'mek walking hazard (more dangerous in deeper liquid) - when(mockCrew.getPiloting()).thenReturn(5); - when(mockPath.isJumping()).thenReturn(false); - when(mockUnit.getArmor(eq(Mek.LOC_LLEG))).thenReturn(2); - when(mockUnit.getArmor(eq(Mek.LOC_RLEG))).thenReturn(2); - when(mockFinalHex.depth()).thenReturn(1); - // Moderate damage means moderate hazard - when(mockUnit.getDamageLevel()).thenReturn(Entity.DMG_MODERATE); - assertEquals(750.0, testRanker.checkPathForHazards(mockPath, mockUnit, mockGame), TOLERANCE); + mockCrew = mock(Crew.class); + when(mockUnit.getCrew()).thenReturn(mockCrew); + when(mockCrew.getPiloting()).thenReturn(5); - when(mockFinalHex.terrainLevel(Terrains.WATER)).thenReturn(2); - when(mockFinalHex.depth()).thenReturn(2); + mockBuilding = mock(Building.class); - assertEquals(3000.0, testRanker.checkPathForHazards(mockPath, mockUnit, mockGame), TOLERANCE); - // Crippled should be very high hazard + when(mockGame.getBoard().getBuildingAt(eq(testCoordsThree))).thenReturn(mockBuilding); + when(mockBuilding.getCurrentCF(eq(testCoordsThree))).thenReturn(77); + } - when(mockFinalHex.terrainLevel(Terrains.WATER)).thenReturn(1); - when(mockFinalHex.depth()).thenReturn(1); + @Test + void testThreeHexShallowHazardousLiquid() { + when(mockUnit.locations()).thenReturn(8); + when(mockUnit.getArmor(anyInt())).thenReturn(10); + + final Hex mockHexTwo = testHexes.get(1); + final Hex mockHexThree = testHexes.get(2); + final Hex mockFinalHex = testHexes.get(3); + + // Test walking through 3 hexes of shallow hazardous liquid. + when(mockHexTwo.depth()).thenReturn(1); + when(mockHexThree.depth()).thenReturn(1); + when(mockFinalHex.depth()).thenReturn(1); + when(mockPath.isJumping()).thenReturn(false); + when(mockHexTwo.getTerrainTypesSet()).thenReturn(new HashSet<>(Set.of(Terrains.HAZARDOUS_LIQUID, Terrains.WATER))); + when(mockHexThree.getTerrainTypesSet()).thenReturn(new HashSet<>(Set.of(Terrains.HAZARDOUS_LIQUID, Terrains.WATER))); + when(mockFinalHex.getTerrainTypesSet()).thenReturn(new HashSet<>(Set.of(Terrains.HAZARDOUS_LIQUID, Terrains.WATER))); + when(mockHexTwo.terrainLevel(Terrains.HAZARDOUS_LIQUID)).thenReturn(1); + when(mockHexThree.terrainLevel(Terrains.HAZARDOUS_LIQUID)).thenReturn(1); + when(mockFinalHex.terrainLevel(Terrains.HAZARDOUS_LIQUID)).thenReturn(1); + when(mockHexTwo.terrainLevel(Terrains.WATER)).thenReturn(1); + when(mockHexThree.terrainLevel(Terrains.WATER)).thenReturn(1); + when(mockFinalHex.terrainLevel(Terrains.WATER)).thenReturn(1); + when(mockHexTwo.containsTerrain(Terrains.WATER)).thenReturn(true); + when(mockHexThree.containsTerrain(Terrains.WATER)).thenReturn(true); + when(mockFinalHex.containsTerrain(Terrains.WATER)).thenReturn(true); + assertEquals(450.0, testRanker.checkPathForHazards(mockPath, mockUnit, mockGame), TOLERANCE); + } + @Test + void testThreeHexDeepHazardousLiquid() { + when(mockUnit.locations()).thenReturn(8); + when(mockUnit.getArmor(anyInt())).thenReturn(10); + + final Hex mockHexTwo = testHexes.get(1); + final Hex mockHexThree = testHexes.get(2); + final Hex mockFinalHex = testHexes.get(3); + + // Test walking through 3 hexes of deep hazardous liquid - this should be extremely dangerous for our test unit!. + when(mockPath.isJumping()).thenReturn(false); + when(mockHexTwo.getTerrainTypesSet()).thenReturn(new HashSet<>(Set.of(Terrains.HAZARDOUS_LIQUID, Terrains.WATER))); + when(mockHexThree.getTerrainTypesSet()).thenReturn(new HashSet<>(Set.of(Terrains.HAZARDOUS_LIQUID, Terrains.WATER))); + when(mockFinalHex.getTerrainTypesSet()).thenReturn(new HashSet<>(Set.of(Terrains.HAZARDOUS_LIQUID, Terrains.WATER))); + when(mockHexTwo.terrainLevel(Terrains.HAZARDOUS_LIQUID)).thenReturn(1); + when(mockHexThree.terrainLevel(Terrains.HAZARDOUS_LIQUID)).thenReturn(1); + when(mockFinalHex.terrainLevel(Terrains.HAZARDOUS_LIQUID)).thenReturn(1); + when(mockHexTwo.terrainLevel(Terrains.WATER)).thenReturn(2); + when(mockHexThree.terrainLevel(Terrains.WATER)).thenReturn(2); + when(mockFinalHex.terrainLevel(Terrains.WATER)).thenReturn(2); + when(mockHexTwo.containsTerrain(Terrains.WATER)).thenReturn(true); + when(mockHexThree.containsTerrain(Terrains.WATER)).thenReturn(true); + when(mockFinalHex.containsTerrain(Terrains.WATER)).thenReturn(true); + assertEquals(9000.0, testRanker.checkPathForHazards(mockPath, mockUnit, mockGame), TOLERANCE); + } - when(mockUnit.getDamageLevel()).thenReturn(Entity.DMG_CRIPPLED); - assertEquals(750.0, testRanker.checkPathForHazards(mockPath, mockUnit, mockGame), TOLERANCE); + @Test + void testProneHazardousLiquid() { + when(mockUnit.locations()).thenReturn(8); + when(mockUnit.getArmor(anyInt())).thenReturn(10); + + final Hex mockFinalHex = testHexes.get(3); + + final MoveStep mockFinalStep = stepVector.lastElement(); + + // Test the stupidity of going prone in shallow hazardous liquid. + // Now that hazard is inversely related to remaining armor, this is a _BIG_ + // number + when(mockPath.isJumping()).thenReturn(false); + when(mockFinalHex.depth()).thenReturn(1); + when(mockFinalStep.isProne()).thenReturn(true); + when(mockFinalHex.getTerrainTypesSet()).thenReturn(new HashSet<>(Set.of(Terrains.HAZARDOUS_LIQUID, Terrains.WATER))); + when(mockFinalHex.terrainLevel(Terrains.HAZARDOUS_LIQUID)).thenReturn(1);; + when(mockFinalHex.terrainLevel(Terrains.WATER)).thenReturn(1); + when(mockFinalHex.containsTerrain(Terrains.WATER)).thenReturn(true); + assertEquals(3000.0, testRanker.checkPathForHazards(mockPath, mockUnit, mockGame), TOLERANCE); + } - when(mockFinalHex.terrainLevel(Terrains.WATER)).thenReturn(2); - when(mockFinalHex.depth()).thenReturn(2); + @Test + void testHazardousLiquidHazard() { + when(mockUnit.locations()).thenReturn(8); + when(mockUnit.getArmor(anyInt())).thenReturn(10); + + // Test jumping into Hazardous Liquid. + when(mockPath.isJumping()).thenReturn(true); + when(mockUnit.getArmor(eq(Mek.LOC_LLEG))).thenReturn(24); + when(mockUnit.getArmor(eq(Mek.LOC_RLEG))).thenReturn(24); + when(mockFinalHex.depth()).thenReturn(1); + when(mockFinalHex.getTerrainTypesSet()).thenReturn(new HashSet<>(Set.of(Terrains.HAZARDOUS_LIQUID, Terrains.WATER))); + when(mockFinalHex.terrainLevel(Terrains.WATER)).thenReturn(1); + when(mockFinalHex.containsTerrain(Terrains.WATER)).thenReturn(true); + when(mockFinalHex.terrainLevel(Terrains.HAZARDOUS_LIQUID)).thenReturn(1); + assertEquals(63.0, testRanker.checkPathForHazards(mockPath, mockUnit, mockGame), TOLERANCE); + } + @Test + void testHazardousLiquidWalkingHazard() { + // Test damaged 'mek walking hazard (more dangerous in deeper liquid) + when(mockUnit.locations()).thenReturn(8); + when(mockUnit.getArmor(anyInt())).thenReturn(10); + + when(mockFinalHex.getTerrainTypesSet()).thenReturn(new HashSet<>(Set.of(Terrains.HAZARDOUS_LIQUID, Terrains.WATER))); + when(mockFinalHex.terrainLevel(Terrains.WATER)).thenReturn(1); + when(mockFinalHex.containsTerrain(Terrains.WATER)).thenReturn(true); + when(mockFinalHex.terrainLevel(Terrains.HAZARDOUS_LIQUID)).thenReturn(1); + when(mockCrew.getPiloting()).thenReturn(5); + when(mockPath.isJumping()).thenReturn(false); + when(mockFinalHex.depth()).thenReturn(1); + + assertEquals(150.0, testRanker.checkPathForHazards(mockPath, mockUnit, mockGame), TOLERANCE); + } - assertEquals(3000.0, testRanker.checkPathForHazards(mockPath, mockUnit, mockGame), TOLERANCE); + @Test + void testDeepHazardousLiquidWalkingHazard() { + when(mockUnit.locations()).thenReturn(8); + when(mockUnit.getArmor(anyInt())).thenReturn(10); - when(mockFinalHex.terrainLevel(Terrains.WATER)).thenReturn(1); - when(mockFinalHex.depth()).thenReturn(1); + when(mockFinalHex.getTerrainTypesSet()).thenReturn(new HashSet<>(Set.of(Terrains.HAZARDOUS_LIQUID, Terrains.WATER))); + when(mockFinalHex.containsTerrain(Terrains.WATER)).thenReturn(true); + when(mockFinalHex.terrainLevel(Terrains.HAZARDOUS_LIQUID)).thenReturn(1); + when(mockFinalHex.terrainLevel(Terrains.WATER)).thenReturn(2); + when(mockFinalHex.depth()).thenReturn(2); - // If this is an industrial Mek this is twice as dangerous! - when(mockUnit.isIndustrialMek()).thenReturn(true); - when(mockUnit.hasEnvironmentalSealing()).thenReturn(false); - assertEquals(1500, testRanker.checkPathForHazards(mockPath, mockUnit, mockGame), TOLERANCE); - //If it has environmental sealing though it should be normal - when(mockUnit.hasEnvironmentalSealing()).thenReturn(true); - assertEquals(750.0, testRanker.checkPathForHazards(mockPath, mockUnit, mockGame), TOLERANCE); - when(mockUnit.isIndustrialMek()).thenReturn(false); - when(mockUnit.hasEnvironmentalSealing()).thenReturn(false); - - // Check damaged Hover ending on Hazardous Liquid - // Ramps up quickly with damage state! - final Entity mockTank = mock(Tank.class); - when(mockTank.locations()).thenReturn(5); - when(mockTank.getArmor(anyInt())).thenReturn(10); - when(mockTank.getCrew()).thenReturn(mockCrew); - when(mockCrew.getPiloting()).thenReturn(5); - when(mockPath.isJumping()).thenReturn(false); - when(mockTank.getMovementMode()).thenReturn(EntityMovementMode.HOVER); - when(mockTank.getHeatCapacity()).thenReturn(Entity.DOES_NOT_TRACK_HEAT); + assertEquals(3000., testRanker.checkPathForHazards(mockPath, mockUnit, mockGame), TOLERANCE); + } - when(mockTank.getDamageLevel()).thenReturn(0); - assertEquals(0.0, testRanker.checkPathForHazards(mockPath, mockTank, mockGame), TOLERANCE); + @Test + void testCrippledHazardousLiquidWalkingHazard() { + when(mockUnit.locations()).thenReturn(8); + when(mockUnit.getArmor(anyInt())).thenReturn(10); + when(mockUnit.getArmor(eq(Mek.LOC_LLEG))).thenReturn(2); + when(mockUnit.getArmor(eq(Mek.LOC_RLEG))).thenReturn(2); + + when(mockFinalHex.getTerrainTypesSet()).thenReturn(new HashSet<>(Set.of(Terrains.HAZARDOUS_LIQUID, Terrains.WATER))); + when(mockFinalHex.containsTerrain(Terrains.WATER)).thenReturn(true); + when(mockFinalHex.terrainLevel(Terrains.HAZARDOUS_LIQUID)).thenReturn(1); + when(mockFinalHex.terrainLevel(Terrains.WATER)).thenReturn(1); + when(mockFinalHex.depth()).thenReturn(1); + + when(mockUnit.getDamageLevel()).thenReturn(Entity.DMG_CRIPPLED); + assertEquals(750.0, testRanker.checkPathForHazards(mockPath, mockUnit, mockGame), TOLERANCE); + } - when(mockTank.getDamageLevel()).thenReturn(1); - assertEquals(250.0, testRanker.checkPathForHazards(mockPath, mockTank, mockGame), TOLERANCE); + @Test + void testCrippledDeepHazardousLiquidWalkingHazard() { + when(mockUnit.locations()).thenReturn(8); + when(mockUnit.getArmor(anyInt())).thenReturn(2); - when(mockTank.getDamageLevel()).thenReturn(2); - assertEquals(500.0, testRanker.checkPathForHazards(mockPath, mockTank, mockGame), TOLERANCE); + when(mockFinalHex.getTerrainTypesSet()).thenReturn(new HashSet<>(Set.of(Terrains.HAZARDOUS_LIQUID, Terrains.WATER))); + when(mockFinalHex.containsTerrain(Terrains.WATER)).thenReturn(true); + when(mockFinalHex.terrainLevel(Terrains.HAZARDOUS_LIQUID)).thenReturn(1); + when(mockFinalHex.terrainLevel(Terrains.WATER)).thenReturn(2); + when(mockFinalHex.depth()).thenReturn(2); + + assertEquals(3000.0, testRanker.checkPathForHazards(mockPath, mockUnit, mockGame), TOLERANCE); + } + + + @Test + void testHazardousLiquidUnsealedIndustrialMek() { + // If this is an industrial Mek this is twice as dangerous! + when(mockUnit.locations()).thenReturn(8); + when(mockUnit.getArmor(anyInt())).thenReturn(10); + when(mockFinalHex.depth()).thenReturn(1); + when(mockFinalHex.getTerrainTypesSet()).thenReturn(new HashSet<>(Set.of(Terrains.HAZARDOUS_LIQUID, Terrains.WATER))); + when(mockFinalHex.terrainLevel(Terrains.WATER)).thenReturn(1); + when(mockFinalHex.containsTerrain(Terrains.WATER)).thenReturn(true); + when(mockFinalHex.terrainLevel(Terrains.HAZARDOUS_LIQUID)).thenReturn(1); + + when(mockUnit.isIndustrialMek()).thenReturn(true); + when(mockUnit.hasEnvironmentalSealing()).thenReturn(false); + assertEquals(300.0, testRanker.checkPathForHazards(mockPath, mockUnit, mockGame), TOLERANCE); + } + + + @Test + void testHazardousLiquidSealedIndustrialMek() { + //If it has environmental sealing though it should be normal + when(mockUnit.locations()).thenReturn(8); + when(mockUnit.getArmor(anyInt())).thenReturn(10); + when(mockFinalHex.depth()).thenReturn(1); + when(mockFinalHex.getTerrainTypesSet()).thenReturn(new HashSet<>(Set.of(Terrains.HAZARDOUS_LIQUID, Terrains.WATER))); + when(mockFinalHex.terrainLevel(Terrains.WATER)).thenReturn(1); + when(mockFinalHex.containsTerrain(Terrains.WATER)).thenReturn(true); + when(mockFinalHex.terrainLevel(Terrains.HAZARDOUS_LIQUID)).thenReturn(1); + + + when(mockUnit.hasEnvironmentalSealing()).thenReturn(true); + assertEquals(150.0, testRanker.checkPathForHazards(mockPath, mockUnit, mockGame), TOLERANCE); + when(mockUnit.isIndustrialMek()).thenReturn(false); + when(mockUnit.hasEnvironmentalSealing()).thenReturn(false); + } + + + @Test + void testHoverCraft() { + when(mockFinalHex.depth()).thenReturn(1); + when(mockFinalHex.getTerrainTypesSet()).thenReturn(new HashSet<>(Set.of(Terrains.HAZARDOUS_LIQUID, Terrains.WATER))); + when(mockFinalHex.terrainLevel(Terrains.WATER)).thenReturn(1); + when(mockFinalHex.containsTerrain(Terrains.WATER)).thenReturn(true); + when(mockFinalHex.terrainLevel(Terrains.HAZARDOUS_LIQUID)).thenReturn(1); + + // Check damaged Hover ending on Hazardous Liquid + // Ramps up quickly with damage state! + final Entity mockTank = mock(Tank.class); + when(mockTank.locations()).thenReturn(5); + when(mockTank.getArmor(anyInt())).thenReturn(10); + when(mockTank.getCrew()).thenReturn(mockCrew); + when(mockCrew.getPiloting()).thenReturn(5); + when(mockPath.isJumping()).thenReturn(false); + when(mockTank.getMovementMode()).thenReturn(EntityMovementMode.HOVER); + when(mockTank.getHeatCapacity()).thenReturn(Entity.DOES_NOT_TRACK_HEAT); + + when(mockTank.getDamageLevel()).thenReturn(Entity.DMG_NONE); + assertEquals(0.0, testRanker.checkPathForHazards(mockPath, mockTank, mockGame), TOLERANCE); + + } + + + @Test + void testLightDamageHoverCraft() { + when(mockFinalHex.depth()).thenReturn(1); + when(mockFinalHex.getTerrainTypesSet()).thenReturn(new HashSet<>(Set.of(Terrains.HAZARDOUS_LIQUID, Terrains.WATER))); + when(mockFinalHex.terrainLevel(Terrains.WATER)).thenReturn(1); + when(mockFinalHex.containsTerrain(Terrains.WATER)).thenReturn(true); + when(mockFinalHex.terrainLevel(Terrains.HAZARDOUS_LIQUID)).thenReturn(1); + + // Check damaged Hover ending on Hazardous Liquid + // Ramps up quickly with damage state! + final Entity mockTank = mock(Tank.class); + when(mockTank.locations()).thenReturn(5); + when(mockTank.getArmor(anyInt())).thenReturn(10); + when(mockTank.getCrew()).thenReturn(mockCrew); + when(mockCrew.getPiloting()).thenReturn(5); + when(mockPath.isJumping()).thenReturn(false); + when(mockTank.getMovementMode()).thenReturn(EntityMovementMode.HOVER); + when(mockTank.getHeatCapacity()).thenReturn(Entity.DOES_NOT_TRACK_HEAT); + + when(mockTank.getDamageLevel()).thenReturn(Entity.DMG_LIGHT); + assertEquals(250.0, testRanker.checkPathForHazards(mockPath, mockTank, mockGame), TOLERANCE); + + } + + + @Test + void testHeavyDamageHoverCraft() { + when(mockFinalHex.depth()).thenReturn(1); + when(mockFinalHex.getTerrainTypesSet()).thenReturn(new HashSet<>(Set.of(Terrains.HAZARDOUS_LIQUID, Terrains.WATER))); + when(mockFinalHex.terrainLevel(Terrains.WATER)).thenReturn(1); + when(mockFinalHex.containsTerrain(Terrains.WATER)).thenReturn(true); + when(mockFinalHex.terrainLevel(Terrains.HAZARDOUS_LIQUID)).thenReturn(1); + + // Check damaged Hover ending on Hazardous Liquid + // Ramps up quickly with damage state! + final Entity mockTank = mock(Tank.class); + when(mockTank.locations()).thenReturn(5); + when(mockTank.getArmor(anyInt())).thenReturn(10); + when(mockTank.getCrew()).thenReturn(mockCrew); + when(mockCrew.getPiloting()).thenReturn(5); + when(mockPath.isJumping()).thenReturn(false); + when(mockTank.getMovementMode()).thenReturn(EntityMovementMode.HOVER); + when(mockTank.getHeatCapacity()).thenReturn(Entity.DOES_NOT_TRACK_HEAT); + + when(mockTank.getDamageLevel()).thenReturn(Entity.DMG_MODERATE); + assertEquals(500.0, testRanker.checkPathForHazards(mockPath, mockTank, mockGame), TOLERANCE); + } } @Test