diff --git a/megamek/data/scenarios/Kell Hounds/DeathOfTheLegion/DeathOfTheLegion.mms b/megamek/data/scenarios/Kell Hounds/DeathOfTheLegion/DeathOfTheLegion.mms
new file mode 100644
index 0000000000..810a9602d1
--- /dev/null
+++ b/megamek/data/scenarios/Kell Hounds/DeathOfTheLegion/DeathOfTheLegion.mms
@@ -0,0 +1,487 @@
+#
+# Copyright (c) 2024 - 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 .
+#
+# Based on Death of the Legion, FASA's 01652 "Kell Hounds" sourcebook
+MMSVersion: 2
+name: Death of the Legion
+planet: Mankova
+description: >
+ During a raid on Mankova by Gorman Toth and his pirate unit known as the Legion of Honor, Toth learned that
+ a Star League depot had been found during strip mining. Thinking he had tricked the Kell Hounds into
+ taking action elsewhere he went straight for it.
+
+map:
+ cols: 2
+ boards:
+ - file: Map Set 2/16x17 River Valley.board
+ - file: Map Set 2/16x17 BattleTech.board
+ modify: rotate
+
+factions:
+#- name: Obser
+
+
+- name: Mek Company, Kell Hounds
+ camo: Mercs/Kell Hounds.jpg
+ deploy: W
+
+ units:
+ - fullname: Thunderbolt TDR-5S
+ id: 101
+ force: Command Lance|1
+ crew:
+ name: Lt. Col. Patrick M. Kell
+ portrait: Male/MekWarrior/MW_M_27.png
+ gunnery: 2
+ piloting: 3
+
+ - fullname: Orion ON1-K
+ id: 102
+ force: Command Lance|1
+ crew:
+ name: Lt. Anne Finn
+ portrait: Female/MekWarrior/MW_F_41.png
+ gunnery: 3
+ piloting: 4
+
+ - fullname: Marauder MAD-3R
+ id: 103
+ force: Command Lance|1
+ crew:
+ name: Sgt. Clarence Wilson
+ portrait: Male/MekWarrior/MW_M_103.png
+ callsign: Cat
+ gunnery: 2
+ piloting: 3
+
+ - fullname: Crusader CRD-3R
+ id: 104
+ force: Command Lance|1
+ crew:
+ name: Bethany Connor
+ portrait: Female/MekWarrior/MW_F_48.png
+ gunnery: 4
+ piloting: 5
+
+ - fullname: Wolverine WVR-6R
+ id: 105
+ force: Assault Lance|2
+ crew:
+ name: Maj. Salome Ward
+ portrait: Female/MekWarrior/MW_F_46.png
+ gunnery: 2
+ piloting: 3
+
+ - fullname: Catapult CPLT-C1
+ id: 106
+ force: Assault Lance|2
+ crew:
+ name: Lt. Mike Fitzhugh
+ portrait: Male/MekWarrior/MW_M_88.png
+ gunnery: 3
+ piloting: 4
+
+ - fullname: Trebuchet TBT-5N
+ id: 107
+ force: Assault Lance|2
+ crew:
+ name: Sgt. Diane McWilliams
+ portrait: Female/MekWarrior/MW_F_85.png
+ gunnery: 3
+ piloting: 4
+
+ - fullname: Rifleman RFL-3N
+ id: 108
+ force: Assault Lance|2
+ crew:
+ name: Mary Lasker
+ portrait: Female/MekWarrior/MW_F_5.png
+ gunnery: 4
+ piloting: 5
+
+ - fullname: Valkyrie VLK-QA
+ id: 109
+ force: Scout Lance|3
+ crew:
+ name: Cpt. Daniel W. Allard
+ portrait: Male/MekWarrior/MW_M_37.png
+ gunnery: 3
+ piloting: 4
+
+ - fullname: Commando COM-2D
+ id: 110
+ force: Scout Lance|3
+ crew:
+ name: Lt. Austin Brand
+ portrait: Male/MekWarrior/MW_M_5.png
+ gunnery: 3
+ piloting: 4
+
+ - fullname: Wasp WSP-1A
+ id: 111
+ force: Scout Lance|3
+ crew:
+ name: Sgt. Margaret Lang
+ callsign: Meg
+ portrait: Female/MekWarrior/MW_F_1.png
+ gunnery: 4
+ piloting: 5
+
+ - fullname: Jenner JR7-D
+ id: 112
+ force: Scout Lance|3
+ crew:
+ name: Eddie Baker
+ portrait: Male/MekWarrior/MW_M_65.png
+ gunnery: 4
+ piloting: 5
+
+# OpFor
+- name: Legion of Honor
+ camo: Pirates/Tortuga Fusiliers.jpg
+ deploy: S
+
+ units:
+ - fullname: Marauder MAD-3R
+ id: 201
+ force: Leader Lance|11
+ at: [ 27, 13 ]
+ facing: 5
+ remaining:
+ armor:
+ LA: 15
+ crits:
+ LA: 4
+ crew:
+ name: Gorman Toth
+ gunnery: 4
+ piloting: 3
+
+ - fullname: JagerMech JM6-S
+ id: 202
+ at: [ 28, 12 ]
+ facing: 4
+ force: Leader Lance|11
+ remaining:
+ armor:
+ HD: 5
+ crew:
+ name: Maj. Adolf Rillan
+ gunnery: 4
+ piloting: 4
+
+ - fullname: Centurion CN9-A
+ id: 203
+ at: [ 25, 12 ]
+ facing: 5
+ force: Leader Lance|11
+ crew:
+ name: Joe Toomb
+ callsign: Blackjack
+ gunnery: 4
+ piloting: 5
+
+ - fullname: Assassin ASN-21
+ id: 204
+ facing: 5
+ at: [ 24, 11 ]
+ force: Leader Lance|11
+ crew:
+ name: Peter Manheim
+ callsign: Slippery Pete
+ gunnery: 4
+ piloting: 4
+
+ - fullname: Orion ON1-K
+ id: 205
+ facing: 4
+ at: [ 29, 12 ]
+ force: Attack Lance|12
+ crew:
+ name: Dan Glory
+ gunnery: 4
+ piloting: 4
+
+ - fullname: Rifleman RFL-3N
+ id: 206
+ at: [ 30, 11 ]
+ facing: 4
+ force: Attack Lance|12
+ remaining:
+ armor:
+ CT: 12
+ crits:
+ RA: 3
+ crew:
+ name: Sandra Fitzsimmons
+ gunnery: 5
+ piloting: 4
+
+ - fullname: Scorpion SCP-1N
+ id: 207
+ at: [ 31, 12 ]
+ facing: 5
+ force: Attack Lance|12
+ crew:
+ name: Marcus Worrus
+ gunnery: 4
+ piloting: 4
+
+ - fullname: Firestarter FS9-H
+ id: 208
+ at: [ 32, 12 ]
+ facing: 5
+ force: Attack Lance|12
+ crew:
+ name: Zeke Smuthers
+ callsign: Zippo
+ gunnery: 3
+ piloting: 5
+
+ - fullname: Valkyrie VLK-QA
+ id: 209
+ at: [ 23, 11 ]
+ facing: 5
+ force: Probe Lance|13
+ crew:
+ name: Roxanne Devers
+ piloting: 4
+ gunnery: 4
+
+ - fullname: Spider SDR-5V
+ id: 210
+ at: [ 21, 10 ]
+ facing: 5
+ force: Probe Lance|13
+ crew:
+ name: Lancelot Smith
+ gunnery: 5
+ piloting: 4
+
+ - fullname: Stinger STG-3R
+ id: 211
+ at: [ 20, 9 ]
+ facing: 4
+ force: Probe Lance|13
+ crits:
+ LA: 5
+ RA: 6
+ crew:
+ name: Dorothy Gail
+ gunnery: 5
+ piloting: 5
+
+ - fullname: Locust LCT-1V
+ id: 212
+ at: [ 19, 10 ]
+ facing: 4
+ force: Probe Lance|13
+ crew:
+ name: Sam Norgales
+ gunnery: 4
+ piloting: 4
+
+
+messages:
+ - header: Situation
+ text: |
+ # Situation
+ ## Mankova, Foredam District
+ ## Free Worlds League
+ ## November 3017
+
+ During a raid on Mankova led by Gorman Toth and his pirate band, the Legion of Honor, Toth discovered
+ that a Star League depot had been unearthed during strip-mining operations in the Foredam District.
+ Toth had been plundering the planet for nearly a week, having deceived the Kell Hounds into chasing
+ another pirate, Hassin Hys. Believing he had successfully evaded the Hounds, Toth made his way to the
+ remote mining district to seize the depot and its contents. Unbeknownst to him, he had walked right
+ into a carefully orchestrated trap laid by Lieutenant Colonel Patrick Kell, who had fabricated the story
+ about the Star League depot.
+
+ As Toth's Legion of Honor advanced toward Foredam, Colonel Kell detached his AeroSpace company and
+ Jump Infantry Company to cut off all potential escape routes. When Major Salome Ward and her Relentless
+ Wolves engaged Toth's Legion, they had no options but to confront the Kell Hounds in direct battle.
+
+ *This scenario is based on "Death of the Legion", published in the "Kell Hounds" sourcebook, FASA 01652.*
+ image: deathlegion_splash.png
+ trigger:
+ type: gamestart
+
+ - header: Attacker's Task
+ text: |
+ ## Attacker's Task
+
+ In this scenario, it is your task to deal with the pirate rabble of the so-called Legion of Honor. Destroy,
+ cripple or chase off the enemy.
+ trigger:
+ type: and
+ triggers:
+ - type: phasestart
+ phase: deployment
+ - type: round
+ round: 0
+
+ - header: Defeat
+ text: |
+ ## Defeat
+
+ The pirates sadly proved to be hardier than Patrick Martin Kell had thought. It will take the Kell Hounds
+ quite some time to recover from today's losses.
+
+ It's a good thing the pirates won't be able to resupply at a Star League depot on this planet.
+ image: deathlegion_splash.png
+ trigger:
+ type: activeunits
+ modify: [ atend, once ]
+ units: [ 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112 ]
+ count: 0
+
+ - header: Victory
+ text: |
+ ## Victory!
+
+ Congratulations! With your leadership, the Kell Hounds wiped the pirates from the face of the
+ planet at almost no losses to themselves.
+
+ Let the opponents tremble when the Kell Hounds arrive.
+ image: deathlegion_splash.png
+ trigger:
+ type: and
+ modify: [ atend, once ]
+ triggers:
+ - type: activeunits
+ units: [ 201, 202, 203, 204, 205, 206, 207, 208, 209, 210, 211, 212 ]
+ count: 0
+ - type: killedunits
+ units: [ 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112 ]
+ atmost: 1
+
+ - header: Victory
+ text: |
+ ## Victory!
+
+ Congratulations! The Kell Hounds have secured the battlefield. While every lost MekWarrior hurts and every lost
+ Mek is expensive to replace, this victory came at not too great a cost.
+
+ The pirates, as far as they survived will think of this day for a long time. Time to
+ collect the salvage.
+ image: deathlegion_splash.png
+ trigger:
+ type: and
+ modify: [ atend, once ]
+ triggers:
+ - type: activeunits
+ units: [ 201, 202, 203, 204, 205, 206, 207, 208, 209, 210, 211, 212 ]
+ count: 0
+ - type: killedunits
+ units: [ 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112 ]
+ atleast: 2
+ atmost: 4
+
+ - header: Victory
+ text: |
+ ## Victory!
+
+ The Legion of Honor is no more. But the Kell Hounds are limping off the battlefield. Let's hope that
+ some of the wreckage can be salvaged.
+ image: deathlegion_splash.png
+ trigger:
+ type: and
+ modify: [ atend, once ]
+ triggers:
+ - type: activeunits
+ units: [ 201, 202, 203, 204, 205, 206, 207, 208, 209, 210, 211, 212 ]
+ count: 0
+ - type: killedunits
+ units: [ 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112 ]
+ atleast: 5
+ atmost: 8
+
+ - header: Victory
+ text: |
+ ## Victory!
+
+ The pirates exacted a heavy toll on the Kell Hounds today. It can only be hoped that the battlefield
+ salvage and the contract payment can make up for the sustained damage.
+ image: deathlegion_splash.png
+ trigger:
+ type: and
+ modify: [ atend, once ]
+ triggers:
+ - type: activeunits
+ units: [ 201, 202, 203, 204, 205, 206, 207, 208, 209, 210, 211, 212 ]
+ count: 0
+ - type: killedunits
+ units: [ 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112 ]
+ atleast: 9
+
+ - header: Pilot Message
+ text: |
+ *Sgt. Clarence Wilson:* Sir, reporting the pirate's leader lance is gone. This will surely demoralize them.
+ image: portraits/Male/MekWarrior/MW_M_103.png
+ trigger:
+ type: and
+ triggers:
+ - type: activeunits
+ units: [ 103 ]
+ - type: battlefieldcontrol
+ modify: not
+ - type: activeunits
+ modify: once
+ units: [ 201, 202, 203, 204 ]
+ count: 0
+
+ - header: Pilot Message
+ text: |
+ *Sgt. Clarence Wilson:* Sir, Jump Infantry is reporting several of the pirates who've fled have been caught and captured
+ or destroyed.
+ image: portraits/Male/MekWarrior/MW_M_103.png
+ trigger:
+ type: and
+ triggers:
+ - type: activeunits
+ units: [ 103 ]
+ - type: battlefieldcontrol
+ modify: not
+ - type: fledunits
+ modify: once
+ units: [ 201, 202, 203, 204, 205, 206, 207, 208, 209, 210, 211, 212 ]
+ atleast: 3
+
+ - header: Pilot Message
+ text: |
+ *Lt. Mike Fitzhugh:* One pirate down.
+ image: portraits/Male/MekWarrior/MW_M_88.png
+ trigger:
+ type: and
+ triggers:
+ - type: activeunits
+ units: [ 106 ]
+ - type: battlefieldcontrol
+ modify: not
+ - type: activeunits
+ modify: once
+ units: [ 201, 202, 203, 204, 205, 206, 207, 208, 209, 210, 211, 212 ]
+ count: 11
+
+end:
+ - trigger:
+ type: battlefieldcontrol
+
+
+
diff --git a/megamek/data/scenarios/Kell Hounds/DeathOfTheLegion/deathlegion_splash.png b/megamek/data/scenarios/Kell Hounds/DeathOfTheLegion/deathlegion_splash.png
new file mode 100644
index 0000000000..fbc59b1514
Binary files /dev/null and b/megamek/data/scenarios/Kell Hounds/DeathOfTheLegion/deathlegion_splash.png differ
diff --git a/megamek/data/scenarios/Kell Hounds/LoweringTheBoom/LoweringTheBoom.mms b/megamek/data/scenarios/Kell Hounds/LoweringTheBoom/LoweringTheBoom.mms
index 84e7e55974..521949d1b0 100644
--- a/megamek/data/scenarios/Kell Hounds/LoweringTheBoom/LoweringTheBoom.mms
+++ b/megamek/data/scenarios/Kell Hounds/LoweringTheBoom/LoweringTheBoom.mms
@@ -59,6 +59,12 @@ factions:
armor:
LT: 2
CT: 15
+ ammo:
+ CT:
+ - slot: 11
+ shots: 5
+ - slot: 12
+ shots: 5
crew:
name: Col. Oliver Nage
portrait: Male/MekWarrior/MW_M_15.png
@@ -74,6 +80,8 @@ factions:
CT: 15
internal:
LT: 10
+ crits:
+ RT: 3
crew:
name: Maj. Abraham Morrison
portrait: Male/MekWarrior/MW_M_13.png
@@ -87,6 +95,12 @@ factions:
armor:
HD: 5
RL: 10
+ ammo:
+ LT:
+ - slot: 1
+ shots: 3
+ - slot: 2
+ shots: 3
crew:
name: Lt. Alicia Devon
piloting: 4
@@ -98,6 +112,12 @@ factions:
remaining:
armor:
CT: 12
+ ammo:
+ LT:
+ - slot: 4
+ shots: 4
+ - slot: 5
+ shots: 4
crew:
name: Sgt. Jonathan Taylor
piloting: 4
@@ -151,6 +171,13 @@ factions:
- fullname: Dervish DV-6M
id: 203
deploymentround: 2
+ ammo:
+ LT:
+ - slot: 3
+ shots: 4
+ RT:
+ - slot: 3
+ shots: 4
crew:
name: Brian Martell
piloting: 4
diff --git a/megamek/data/scenarios/Kell Hounds/ToSaveAPrince/ToSaveAPrince.mms b/megamek/data/scenarios/Kell Hounds/ToSaveAPrince/ToSaveAPrince.mms
index be23cf2aca..c101fd9826 100644
--- a/megamek/data/scenarios/Kell Hounds/ToSaveAPrince/ToSaveAPrince.mms
+++ b/megamek/data/scenarios/Kell Hounds/ToSaveAPrince/ToSaveAPrince.mms
@@ -95,7 +95,10 @@ factions:
id: 106
force: 2nd Sword of Light|21||Zakahashi's Zombies|22||Support Lance|24
remaining:
- RTR: 0
+ armor:
+ RTR: 0
+ crits:
+ LA: 5
crew:
name: Cletus Palmer
piloting: 4
@@ -105,7 +108,12 @@ factions:
id: 107
force: 2nd Sword of Light|21||Zakahashi's Zombies|22||Support Lance|24
remaining:
- CT: 10
+ armor:
+ CT: 10
+ crits:
+ CT: 11
+ LL: [ 5, 6 ]
+ RL: [ 5, 6 ]
crew:
name: Tom Meyer
callsign: Hands
diff --git a/megamek/docs/Scenarios/ScenarioV2 HowTo.mms b/megamek/docs/Scenarios/ScenarioV2 HowTo.mms
index bea1975294..62eeb3c0a7 100644
--- a/megamek/docs/Scenarios/ScenarioV2 HowTo.mms
+++ b/megamek/docs/Scenarios/ScenarioV2 HowTo.mms
@@ -28,8 +28,9 @@ singleplayer: yes # default: yes; the first player is
# Game Map -------------------------------------------------------------------------------------------
map:
- boardcolumns: 2 # a 2x1 map, default: 1
-# boardrows: 1 # default: 1
+ # Optional: the columns to arrange boards in. Default: 1
+ # The number of rows follows from the number of boards given and the columns
+ cols: 2 # a 2x1 map, default: 1
boards:
- board1.board # all files are first searched relative to the scenario file, and
- board2.board # if not found there, then relative to the appropriate data/... directory
@@ -171,6 +172,12 @@ planetaryconditions: # default: standard conditions
# Forces -------------------------------------------------------------------------------------------
factions:
+ # The first player is assumed to be the human player, while the rest get bots assigned by default.
+ # To have the bots play all factions, insert a player without any units as the first player
+ # Only this line is required:
+ # - name: Human Observer
+
+
- name: Player A
team: 1 # default: each player goes into their own team
deploy: N # default: same as the home edge
@@ -188,11 +195,15 @@ factions:
- vibra: 2
camo: clans/wolf/Alpha Galaxy.jpg # image file, relative to the scenario file, or in data/camos otherwise
# use slashes
+
+ # Units are always an array (use dashes)
units:
# - include: Annihilator ANH-13.mmu
- fullname: Atlas AS7-D
- # type: TW_UNIT # default: TW_UNIT other: ASElement
# pre-deployed:
+ offboard: N # default: not offboard; values: N, E, S, W (TODO)
+ # Optional: when pre-deployed, set the facing. 5 = NW
+ facing: 5
at: [7, 4] # position 0704 (pre-deployed)
# x: 7 # alternative way to give position
# y: 4 # must have both x and y or neither
@@ -208,11 +219,52 @@ factions:
# the force ids are used to distinguish different forces with the same name (e.g. multiple "Assault Lance")
force: 2nd Sword of Light|21||Zakahashi's Zombies|22||Assault Lance|23
- offboard: N # default: not offboard; values: N, E, S, W
- crew: # default: unnamed 4/5 pilot
+ # pre-applied damage may assign remaining armor and internal structure values. Values
+ # higher than the undamaged values of the unit are ignored. Negative values set to 0 (TODO)
+ remaining:
+ armor:
+ # remaining armor values, use the usual location names
+ LT: 2
+ CTR: 0
+ internal:
+ # remaining internal structure is independent of armor and does not create any crits
+ # TODO: have 0 internal destroy the location
+ LA: 2
+
+ # location crits
+ # this usually requires looking up the unit file
+ crits:
+ # the usual location names. Give the slots as an array ([ 4, 8 ] or using dashes on separate lines)
+ # slots are 1-based, i.e. CT has slots 1 to 12 (not 0)
+ # location crits will mark the equipment as damaged, but never have any secondary effects
+ # like explosions or pilot hits. Crits that destroy a unit are invalid (e.g. 3 engine hits)
+ LA: 4
+ RT: [ 1, 3 ]
+ CT: 1
+ # non-location crits (TODO)
+ # motive: 1
+ # firecontrol: 1
+
+ # ammo types and reduced amount
+ # this usually requires looking up the unit file and possibly AmmoType.java for the type designations
+ ammo:
+ LA:
+ slot: 5
+ shots: 2
+ # type: xyz (TODO)
+
+ # Optional: give details of the crew/pilot - currently only for single pilots (TODO)
+ # by default, the pilot is an unnamed 4/5 pilot
+ # all fields in crew are optional
+ crew:
name: Cpt. Frederic Nguyen
+ callsign: MAGIC
piloting: 4
gunnery: 3
+ # Optional: pilot hits, 0 to 6
+ hits: 3
+ # Optional: a portrait, relative to data/images/portraits
+ portrait: Male/MechWarrior/MW_M_13.png
# Carryable objects. These currently have no real owner, but if they are not pre-deployed, the present
# player will deploy them. When pre-deployed (at: [ x, y ]), the owner is currently irrelevant.
@@ -438,3 +490,4 @@ trigger:
units: 201
- type: phasestart
phase: movement
+
diff --git a/megamek/src/megamek/client/ui/dialogs/MMStoryDialog.java b/megamek/src/megamek/client/ui/dialogs/MMStoryDialog.java
index 46e7131951..dc6fb64f0b 100644
--- a/megamek/src/megamek/client/ui/dialogs/MMStoryDialog.java
+++ b/megamek/src/megamek/client/ui/dialogs/MMStoryDialog.java
@@ -60,7 +60,6 @@ public void actionPerformed(ActionEvent evt) {
}
protected void initialize() {
- setAlwaysOnTop(true);
setLayout(new BorderLayout());
add(getMainPanel(), BorderLayout.CENTER);
add(getButtonPanel(), BorderLayout.SOUTH);
diff --git a/megamek/src/megamek/common/AbstractGame.java b/megamek/src/megamek/common/AbstractGame.java
index cb67922894..56b38c72ce 100644
--- a/megamek/src/megamek/common/AbstractGame.java
+++ b/megamek/src/megamek/common/AbstractGame.java
@@ -104,7 +104,7 @@ public abstract class AbstractGame implements IGame {
* should only ever be present on the server. Only the results of events should
* be sent to clients.
*/
- protected final List scriptedEvents = new ArrayList<>();
+ protected final List scriptedEvents = new CopyOnWriteArrayList<>();
/**
* Piles of carry-able objects, sorted by coordinates
diff --git a/megamek/src/megamek/common/jacksonadapters/EntityDeserializer.java b/megamek/src/megamek/common/jacksonadapters/EntityDeserializer.java
index 94e85569c6..8d6810c015 100644
--- a/megamek/src/megamek/common/jacksonadapters/EntityDeserializer.java
+++ b/megamek/src/megamek/common/jacksonadapters/EntityDeserializer.java
@@ -31,10 +31,7 @@
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.deser.std.StdDeserializer;
-import megamek.common.Coords;
-import megamek.common.Entity;
-import megamek.common.IAero;
-import megamek.common.MekSummary;
+import megamek.common.*;
import megamek.common.icons.Camouflage;
import megamek.common.scenario.Scenario;
@@ -58,6 +55,10 @@ public class EntityDeserializer extends StdDeserializer {
private static final String ARMOR = "armor";
private static final String INTERNAL = "internal";
private static final String FORCE = "force";
+ private static final String CRITS = "crits";
+ private static final String AMMO = "ammo";
+ private static final String SLOT = "slot";
+ private static final String SHOTS = "shots";
public EntityDeserializer() {
this(null);
@@ -86,6 +87,8 @@ public Entity deserialize(JsonParser jp, DeserializationContext ctxt) throws IOE
assignForce(entity, node);
CrewDeserializer.parseCrew(node, entity);
assignRemaining(entity, node);
+ assignCrits(entity, node);
+ assignAmmos(entity, node);
return entity;
}
@@ -165,7 +168,17 @@ private void assignRemaining(Entity entity, JsonNode node) {
for (int location = 0; location < entity.locations(); location++) {
String locationAbbr = entity.getLocationAbbr(location);
if (armorNode.has(locationAbbr)) {
- entity.setArmor(armorNode.get(locationAbbr).intValue(), location);
+ // don't allow more than the maximum armor
+ int newArmor = Math.min(armorNode.get(locationAbbr).intValue(), entity.getArmor(location));
+ entity.setArmor(newArmor, location);
+ }
+ if (entity.hasRearArmor(location)) {
+ String rearLocationAbbr = entity.getLocationAbbr(location) + "R";
+ if (armorNode.has(rearLocationAbbr)) {
+ int newArmor = Math.min(armorNode.get(rearLocationAbbr).intValue(),
+ entity.getArmor(location, true));
+ entity.setArmor(newArmor, location, true);
+ }
}
}
}
@@ -174,7 +187,9 @@ private void assignRemaining(Entity entity, JsonNode node) {
for (int location = 0; location < entity.locations(); location++) {
String locationAbbr = entity.getLocationAbbr(location);
if (internalNode.has(locationAbbr)) {
- entity.setInternal(internalNode.get(locationAbbr).intValue(), location);
+ int newIS = Math.min(internalNode.get(locationAbbr).intValue(),
+ entity.getInternal(location));
+ entity.setInternal(newIS, location);
}
}
}
@@ -248,4 +263,79 @@ private void assignVelocity(Entity entity, JsonNode node) {
((IAero) entity).setNextVelocity(velocity);
}
}
+
+ private void assignCrits(Entity entity, JsonNode node) {
+ if (!(entity instanceof Mek) || !node.has(CRITS)) {
+ // Implementation very different for different entities; for now: Meks
+ return;
+ }
+ JsonNode critsNode = node.get(CRITS);
+ for (int location = 0; location < entity.locations(); location++) {
+ String locationAbbr = entity.getLocationAbbr(location);
+ if (critsNode.has(locationAbbr)) {
+ for (int slot : parseArrayOrSingleNode(critsNode.get(locationAbbr))) {
+ int zeroBasedSlot = slot - 1;
+ CriticalSlot cs = entity.getCritical(location, zeroBasedSlot);
+ if ((cs == null) || !cs.isHittable()) {
+ throw new IllegalArgumentException("Invalid slot " + location + ":" + slot + " on " + entity);
+ } else {
+ cs.setHit(true);
+ if ((cs.getType() == CriticalSlot.TYPE_SYSTEM) && (cs.getIndex() == Mek.SYSTEM_ENGINE)) {
+ entity.engineHitsThisPhase++;
+ } else {
+ Mounted> mounted = cs.getMount();
+ mounted.setDestroyed(true);
+ }
+ }
+ }
+ }
+ }
+ }
+
+ private void assignAmmos(Entity entity, JsonNode node) {
+ if (node.has(AMMO)) {
+ JsonNode critsNode = node.get(AMMO);
+ for (int location = 0; location < entity.locations(); location++) {
+ String locationAbbr = entity.getLocationAbbr(location);
+ final int finalLoc = location;
+ if (critsNode.has(locationAbbr)) {
+ critsNode.get(locationAbbr).iterator().forEachRemaining(n -> assignAmmo(entity, n, finalLoc));
+ }
+ }
+ }
+ }
+
+ private void assignAmmo(Entity entity, JsonNode node, int location) {
+ int slot = node.get(SLOT).asInt() - 1;
+ int shots = node.get(SHOTS).asInt();
+ CriticalSlot cs = entity.getCritical(location, slot);
+ if (cs != null) {
+ Mounted> ammo = cs.getMount();
+ if (ammo.getType() instanceof AmmoType) {
+ // Also make sure we dont exceed the max allowed
+ ammo.setShotsLeft(Math.min(shots, ammo.getBaseShotsLeft()));
+ } else {
+ throw new IllegalArgumentException("Invalid ammo slot " + location + ":" + (slot + 1) + " on " + entity);
+ }
+ }
+ }
+
+ /**
+ * Returns all Integers of a node as a List. The node may be either of the form "node: singleNumber", in
+ * which case the List will only contain singleNumber, or it may be an array node of the form
+ * "node: [ firstNumber, secondNumber ]" (or the multi-line form using dashes) in which case the list
+ * contains all the given numbers.
+ *
+ * @param node The node to parse
+ * @return A list of the given numbers of the node
+ */
+ public static List parseArrayOrSingleNode(JsonNode node) {
+ List result = new ArrayList<>();
+ if (node.isArray()) {
+ node.iterator().forEachRemaining(n -> result.add(n.asInt()));
+ } else {
+ result.add(node.asInt());
+ }
+ return result;
+ }
}