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; + } }