Skip to content

Commit

Permalink
Merge pull request #6045 from SJuliez/Scenario-HexArea
Browse files Browse the repository at this point in the history
Hex areas and use for Deployment, Flee Zones and Triggers
  • Loading branch information
HammerGS authored Oct 2, 2024
2 parents 72f857d + db3216f commit 44a0297
Show file tree
Hide file tree
Showing 39 changed files with 1,998 additions and 62 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -33,8 +33,6 @@ map:
modify: rotate

factions:
#- name: Obser


- name: Mek Company, Kell Hounds
camo: Mercs/Kell Hounds.jpg
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,9 @@ factions:
atleast: 4
modify: onlyatend

fleefrom:
border: north

units:
- fullname: Thunderbolt TDR-5S
id: 101
Expand Down Expand Up @@ -250,9 +253,6 @@ messages:
as many Meks as possible.

Be careful! Some of your Meks have already sustained damage.

*Technical note: you can currently retreat off any edge of the battlefield and it will count for victory.
If you do this, Princess will be sad.*
image: loweringboom_map.png
trigger:
type: and
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,9 @@ factions:
camo: Draconis Combine/Dieron Regulars/Dieron Regulars.jpg
deploy: N

fleefrom:
border: south

victory:
- trigger:
type: fledunits
Expand Down Expand Up @@ -164,6 +167,7 @@ factions:
piloting: 4
gunnery: 5

# OPFOR -----------------------

- name: Kell Hounds, Second Battalion
camo: Mercs/Kell Hounds.jpg
Expand Down Expand Up @@ -321,9 +325,6 @@ messages:
Meks off the southern map edge by the end of round 15.

The temperature in this desert area is at 70°C, adding heat to all Meks.

*Technical note: you can currently retreat off any edge of the battlefield and it will count for victory.
If you do this, Princess will be sad.*
image: tosaveaprince_map.png
trigger:
type: and
Expand Down Expand Up @@ -389,6 +390,7 @@ end:
- trigger:
type: killedunits
units: [ 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112 ]
# can't get through with half the force anymore when 7 are killed
atleast: 7

- trigger:
Expand Down
171 changes: 171 additions & 0 deletions megamek/docs/Scenarios/ScenarioV2 HowTo.mms
Original file line number Diff line number Diff line change
Expand Up @@ -188,6 +188,19 @@ factions:
offset: 0
# width is 3 by default
width: 1
# OR
deploy:
# see also area definitions
area:
union:
first:
circle:
center: [ 10, 10 ]
radius: 7
second:
list:
- [2,2]
- [5,5]

minefields: # optional, availability depending on game type
- conventional: 2
Expand Down Expand Up @@ -491,3 +504,161 @@ trigger:
- type: phasestart
phase: movement

trigger:
# The positions condition is met when the given number(s) of units are in the given area
type: positions
area:
border:
edges: north
maxdistance: 3
# Optional: limit the test to the player's units
player: Player A
# Optional: a list of units to limit the check to. This makes sense most of time to avoid counting MekWarriors
# or other spawns; when giving unit IDs, the player limitation is redundant
# It also makes sense to set fixed IDs for all units to make sure this works correctly
units: [ 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112 ]
# At least the given number of units must be in the given area, can be alone or combined with atmost
atleast: 7
# At most the given number of units must be in the given area, can be alone or combined with atleast
atmost: 10
# OR: the exact number of units must be in the given area; this cannot be combined with atmost/atleast
count: 2

trigger:
# This is a simpler way to write a position condition that is met when the unit is in the given area
type: position
area:
border:
edges: north
maxdistance: 3
# The unit ID to be checked
unit: 201

# ###############################################
# Areas
# are used to define places on the map. They are either a single shape or a combination of shapes. They are
# never given as a list, only a single element that is either the shape or the combination type.
# Areas need not be contiguous
area:
# Combinations are union, difference and intersection (as in "Constructive Solid Geometry")
# Each combination requires the "first:" and "second:" area to be given. These are areas in turn, i.e.,
# they are themselves either shapes or combinations. In other words, this can be nested to any depth.
union:
first:
# A hex circle (or more like, hex-shape) is all hexes around the center at a distance of at most the
# given radius (the circle is filled). To get only the hexes at the distance 7, use a difference
# of two circles, the second of radius 6 can be used.
circle:
center: [ 10, 10 ]
radius: 7
# In union and intersection, it does not matter which area is first and second. In a difference, the second
# area is subtracted from the first, so reversing the two changes the result.
second:
# A list is simply a list of hex coordinates
list:
- [2,2]
- [5,5]

area:
difference:
first:
# A rectangle is given by its corners. The order of the values does not matter, i.e. the corners can be
# upper left and lower right or upper right and lower left in any order. The rectangle is filled and includes
# its border
rectangle:
- [ 2, 2 ]
- [ 5, 5 ]
second:
# Subtracting a smaller rectangle leaves the border of the first rectangle
rectangle:
- [ 4, 4 ]
- [ 3, 3 ]

area:
# There are two versions of halfplane
# One is cartesian, i.e. vertical or horizontal, i.e. all hexes above, below, to left or to right of a
# given coordinate value, including the coordinate (line) itself
halfplane:
coordinate: 4
# The direction the halfplane extends to: above, below, left or right. A toleft halfplane includes all
# hexes of x <= coordinate
extends: above

# The other is delimited by a hex row in one of the 3 directions N/S, NE/SW and NW/SE. The plane extends to
# either the right or left of that (there is no above/below, as the hex row cannot be horizontal). The
# directions are, as always N = 0, SE = 2 ...; opposite directions have the same result
halfplane:
point: [4,5]
direction: 2
# The direction the halfplane extends to: above, below, to_left or to_right. A toleft halfplane includes all
# hexes of x <= coordinate
extends: left

area:
intersection:
first:
# A line along one of the hex row directions (N = 0, SE = 2; opposite directions have the same result)
# through one hex; the line is infinite
line:
point: [ 0, 5 ]
direction: 1
second:
union:
first:
# A ray along one of the hex row directions (N = 0, SE = 2) starting at a hex; the ray is similar to the
# line with the same values but it is cut off at the hex (the ray includes the start hex)
ray:
point: [ 0, 5 ]
direction: 1
second:
# This area is the north border of the board (all hexes with y = 0)
border: north

area:
# Two or more borders of the board can be given as a list.
# The absolute hexes that these represent depend on
# the rectangle that the area is applied to (e.g. the board size)
# The east (left) border is all hexes at x = 0; south is all hexes at y = board height; west all hexes at
# x = board width
border: [ south, east, west ]

area:
# for a thicker border or inset border, use the "edges:" node
border:
edges: [ east, north ]
# optional: the minimum distance from the edge; 0 means start at the edge hexes
mindistance: 2
# optional: the maximum distance from the edge
maxdistance: 3

area:
# The empty area has no hexes. Can be used to prevent units from fleeing the board
empty:

area:
# the area can be given as a terrain type
terrain:
# required: the terrain type to include in the area
type: woods
# optional: the terrain level to include; when omitted, any terrain level is included
level: 1
# OR optional: a range of terrain levels to include
minlevel: 1
maxlevel: 2
# optional: the minimum distance from any hex with the terrain; 0 means only the hexes themselves
mindistance: 2
# optional: the maximum distance from any hex with the terrain
# be careful with distances of more than 3 or so on big boards: this leads to exploding calculation times
maxdistance: 3

area:
# the area can be given as hex levels to include
# either a single hex level
hexlevel: 0

area:
# OR a range
hexlevel:
minlevel: 1
# optional: the maximum hex level
maxlevel: 2
2 changes: 2 additions & 0 deletions megamek/i18n/megamek/client/messages.properties
Original file line number Diff line number Diff line change
Expand Up @@ -1111,6 +1111,8 @@ CommonMenuBar.viewToggleFovDarkenTooltip=<html>Darkens hexes with no LOS to the
CommonMenuBar.viewToggleIsometric=Isometric View
CommonMenuBar.viewToggleFieldOfFire=Field of Fire
CommonMenuBar.viewToggleFieldOfFireToolTip=Outline firing arcs for selected weapons
CommonMenuBar.viewToggleFleeZone=Toggle Flee Zone
CommonMenuBar.viewToggleFleeZoneToolTip=Shows or hides the flee zone of the current unit (the hexes from which it can escape the battlefield)
CommonMenuBar.viewToggleSensorRange=Visual & Sensor Ranges
CommonMenuBar.viewToggleSensorRangeToolTip=Outline Visual & Sensor Ranges
CommonMenuBar.viewToggleFiringSolutions=Firing Solutions
Expand Down
42 changes: 32 additions & 10 deletions megamek/src/megamek/client/bot/princess/BotGeometry.java
Original file line number Diff line number Diff line change
Expand Up @@ -108,17 +108,19 @@ public String toString() {
* Coords stores x and y values. Since these are hexes, coordinates with odd x
* values are a half-hex down. Directions work clockwise around the hex,
* starting with zero at the top.
* -y
* 0
* _____
* 5 / \ 1
* -x / \ +x
* \ /
* 4 \_____/ 2
* 3
* +y
* <pre>
* -y
* 0
* _____
* 5 / \ 1
* -x / \ +x
* \ /
* 4 \_____/ 2
* 3
* +y
* </pre>
* ------------------------------
* Direction is stored as above, but the meaning of 'intercept' depends
* <BR>Direction is stored as above, but the meaning of 'intercept' depends
* on the direction. For directions 0, 3, intercept means the y=0 intercept
* for directions 1, 2, 4, 5 intercept is the x=0 intercept
*/
Expand All @@ -144,6 +146,8 @@ public HexLine(Coords c, int dir) {
* returns -1 if the point is to the left of the line
* +1 if the point is to the right of the line
* and 0 if the point is on the line
* Note that this evaluation depends on the "view" direction of this line. The
* result is reversed for HexLines of opposite directions, e.g. directions 0 and 3.
*/
public int judgePoint(Coords c) {
HexLine comparor = new HexLine(c, getDirection());
Expand All @@ -156,6 +160,24 @@ public int judgePoint(Coords c) {
return 0;
}

/**
* @return -1 if the point is to the left of the line,
* +1 if the point is to the right of the line
* and 0 if the point is on the line
* Note that this evaluation is independent of the "view" direction of this line. The
* result is the same for HexLines of opposite directions, e.g. directions 0 and 3.
*/
public int isAbsoluteLeftOrRight(Coords c) {
HexLine comparor = new HexLine(c, getDirection());
if (comparor.getIntercept() == getIntercept()) {
return 0;
} else if (comparor.getIntercept() < getIntercept()) {
return ((getDirection() == 2) || (getDirection() == 5)) ? 1 : -1;
} else {
return ((getDirection() == 2) || (getDirection() == 5)) ? -1 : 1;
}
}

/**
* returns -1 if the area is entirely to the left of the line
* returns +1 if the area is entirely to the right of the line
Expand Down
30 changes: 27 additions & 3 deletions megamek/src/megamek/client/ui/swing/ClientGUI.java
Original file line number Diff line number Diff line change
Expand Up @@ -166,6 +166,7 @@ public class ClientGUI extends AbstractClientGUI implements BoardViewListener,
public static final String VIEW_TOGGLE_HEXCOORDS = "viewToggleHexCoords";
public static final String VIEW_LABELS = "viewLabels";
public static final String VIEW_TOGGLE_FIELD_OF_FIRE = "viewToggleFieldOfFire";
public static final String VIEW_TOGGLE_FLEE_ZONE = "viewToggleFleeZone";
public static final String VIEW_TOGGLE_SENSOR_RANGE = "viewToggleSensorRange";
public static final String VIEW_TOGGLE_FOV_DARKEN = "viewToggleFovDarken";
public static final String VIEW_TOGGLE_FOV_HIGHLIGHT = "viewToggleFovHighlight";
Expand Down Expand Up @@ -244,6 +245,7 @@ public class ClientGUI extends AbstractClientGUI implements BoardViewListener,
private BoardView bv;
private MovementEnvelopeSpriteHandler movementEnvelopeHandler;
private MovementModifierSpriteHandler movementModifierSpriteHandler;
private FleeZoneSpriteHandler fleeZoneSpriteHandler;
private SensorRangeSpriteHandler sensorRangeSpriteHandler;
private CollapseWarningSpriteHandler collapseWarningSpriteHandler;
private GroundObjectSpriteHandler groundObjectSpriteHandler;
Expand Down Expand Up @@ -351,6 +353,8 @@ public class ClientGUI extends AbstractClientGUI implements BoardViewListener,

private Coords currentHex;

private boolean showFleeZone = false;

// endregion Variable Declarations

/**
Expand Down Expand Up @@ -509,10 +513,11 @@ private void initializeSpriteHandlers() {
groundObjectSpriteHandler = new GroundObjectSpriteHandler(bv, client.getGame());
firingSolutionSpriteHandler = new FiringSolutionSpriteHandler(bv, client);
firingArcSpriteHandler = new FiringArcSpriteHandler(bv, this);
fleeZoneSpriteHandler = new FleeZoneSpriteHandler(bv);

spriteHandlers.addAll(List.of(movementEnvelopeHandler, movementModifierSpriteHandler,
sensorRangeSpriteHandler, flareSpritesHandler, collapseWarningSpriteHandler,
groundObjectSpriteHandler, firingSolutionSpriteHandler, firingArcSpriteHandler));
spriteHandlers.addAll(List.of(movementEnvelopeHandler, movementModifierSpriteHandler, sensorRangeSpriteHandler,
flareSpritesHandler, collapseWarningSpriteHandler, groundObjectSpriteHandler, firingSolutionSpriteHandler,
firingArcSpriteHandler, fleeZoneSpriteHandler));
spriteHandlers.forEach(BoardViewSpriteHandler::initialize);
}

Expand Down Expand Up @@ -925,6 +930,9 @@ public void actionPerformed(ActionEvent event) {
GUIP.setShowFieldOfFire(!GUIP.getShowFieldOfFire());
bv.getPanel().repaint();
break;
case VIEW_TOGGLE_FLEE_ZONE:
toggleFleeZone();
break;
case VIEW_TOGGLE_SENSOR_RANGE:
GUIP.setShowSensorRange(!GUIP.getShowSensorRange());
break;
Expand Down Expand Up @@ -2217,6 +2225,7 @@ public void gamePhaseChange(GamePhaseChangeEvent e) {

clientGuiPanel.validate();
cb.moveToEnd();
hideFleeZone();
}

@Override
Expand Down Expand Up @@ -3093,4 +3102,19 @@ public void setCurrentHex(Hex hex) {
public void setCurrentHex(Coords hex) {
currentHex = hex;
}

private void toggleFleeZone() {
showFleeZone = !showFleeZone;
if (showFleeZone && unitDisplay.getCurrentEntity() != null) {
Game game = client.getGame();
fleeZoneSpriteHandler.renewSprites(game.getFleeZone(unitDisplay.getCurrentEntity()).getCoords(game.getBoard()));
} else {
fleeZoneSpriteHandler.clear();
}
}

public void hideFleeZone() {
showFleeZone = false;
fleeZoneSpriteHandler.clear();
}
}
Loading

0 comments on commit 44a0297

Please sign in to comment.