diff --git a/megamek/data/images/hexes/obinc.gif b/megamek/data/images/hexes/obinc.gif new file mode 100644 index 00000000000..c5f4c4b6b2d Binary files /dev/null and b/megamek/data/images/hexes/obinc.gif differ diff --git a/megamek/i18n/megamek/client/messages.properties b/megamek/i18n/megamek/client/messages.properties index 9cc5a513173..7c316346a05 100644 --- a/megamek/i18n/megamek/client/messages.properties +++ b/megamek/i18n/megamek/client/messages.properties @@ -4625,16 +4625,96 @@ CMVPanel.copyText=Copy as Text CMVPanel.MUL=Open MUL CMVPanel.font=Font: +# Scenario Chooser +ScenarioChooser.title=Choose Scenario + +# SBF Target Dialog +SBFTargetDialog.title=Targeting + + #Gamemaster Menu Text Gamemaster.Gamemaster=Gamemaster Gamemaster.EditDamage=Edit Damage Gamemaster.Configure=Configure Gamemaster.Traitor=Traitor Unit -Gamemaster.SpecialCommands=Special Commands Gamemaster.KillUnit=Kill Unit +Gamemaster.SpecialCommands=Special Commands -# Scenario Chooser -ScenarioChooser.title=Choose Scenario - -# SBF Target Dialog -SBFTargetDialog.title=Targeting +#Gamemaster Chat Commands +Gamemaster.cmd.missingUnit=Specified unit is not on the board. +Gamemaster.cmd.error.integerparse=must be between the min and max values: +Gamemaster.cmd.help=Usage: +Gamemaster.cmd.params.required=Required. +Gamemaster.cmd.params.optional=Optional. +Gamemaster.cmd.x=The x coordinate of the hex. +Gamemaster.cmd.y=The y coordinate of the hex. +# Remove Smoke cmd +Gamemaster.cmd.removesmoke.help=Removes all smoke cloud hexes. +Gamemaster.cmd.removesmoke.success=The air is cleaner and the smoke is gone. +# Kill Unit cmd +Gamemaster.cmd.kill.unitID=ID of the unit to kill. +Gamemaster.cmd.kill.help=Kills a single unit. +Gamemaster.cmd.kill.success=Is going to be destroyed at the end of this phase. +Gamemaster.cmd.kill.reason=Killed by GM. +# Change ownership cmd +Gamemaster.cmd.changeownership.help=Changes the ownership of a unit from one player to another. +Gamemaster.cmd.changeownership.unitID=ID of the unit to change ownership. +Gamemaster.cmd.changeownership.playerID=ID of the player to receive the unit. +Gamemaster.cmd.changeownership.unitNotFound=No such entity. +Gamemaster.cmd.changeownership.playerNotFound=No such player. +Gamemaster.cmd.changeownership.playerUnassigned=Player must be assigned a team. +Gamemaster.cmd.changeownership.success=Ownership of unit {0} will be transferred to player {1} at the end of this round. +# Change weather cmd +Gamemaster.cmd.changeweather.help=Change any of the planetary conditions. Effects change at the next round. +Gamemaster.cmd.changeweather.fog=Fog: 0=none, 1=light, 2=heavy +Gamemaster.cmd.changeweather.light=Light: 0=daylight, 1=dusk, 2=full moon, 3=glare, 4=moonless night, 5=solar flare, 6=pitch black +Gamemaster.cmd.changeweather.wind=Wind: 0=calm, 1=light gale, 2=moderate gale, 3=strong gale, 4=storm, 5=tornado F1-F3, 6=tornado F4 +Gamemaster.cmd.changeweather.winddir=Wind direction: 0=south, 1=southwest, 2=northwest, 3=north, 4=northeast, 5=southeast, 6=random +Gamemaster.cmd.changeweather.atmo=Atmosphere: 0=vacuum, 1=trace, 2=thin, 3=standard, 4=high, 5=very high +Gamemaster.cmd.changeweather.blowsand=Blowing Sand: 0=no, 1=yes +Gamemaster.cmd.changeweather.emi=EMI: 0=no, 1=yes +Gamemaster.cmd.changeweather.weather=Weather: 0=clear, 1=light rain, 2=moderate rain, 3=heavy rain, 4=gusting rain, 5=downpour, 6=light snow, 7=moderate snow, 8=snow flurries, 9=heavy snow, 10=sleet, 11=ice storm, 12=light hail, 13=heavy hail, 14=lightning storm +# Disaster cmd +Gamemaster.cmd.disaster.help=Causes a disaster on the board. +Gamemaster.cmd.disaster.type=Type of disaster. Beware, some disasters are very destructive! +Gamemaster.cmd.changeweather.fog.success=The fog has changed. +Gamemaster.cmd.changeweather.fog.error=Invalid fog value. Must be between 0 and {0} + +Gamemaster.cmd.changeweather.wind.success=The wind strength has changed. +Gamemaster.cmd.changeweather.wind.error=Invalid wind value. Must be between 0 and {0} + +Gamemaster.cmd.changeweather.winddir.success=The wind direction has changed. +Gamemaster.cmd.changeweather.winddir.error=Invalid wind direction value. Must be between 0 and {0} + +Gamemaster.cmd.changeweather.light.success=The light has changed. +Gamemaster.cmd.changeweather.light.error=Invalid light value. Must be between 0 and {0} + +Gamemaster.cmd.changeweather.atmo.success0=The air has vanished, put your vac suits! +Gamemaster.cmd.changeweather.atmo.success=The air is changing. +Gamemaster.cmd.changeweather.atmo.error=Invalid atmosphere value. Must be between 0 and {0} + +Gamemaster.cmd.changeweather.blowsand.success1=Sand started blowing. +Gamemaster.cmd.changeweather.blowsand.success=The sand has settled. +Gamemaster.cmd.changeweather.blowsand.error=Invalid blowsand value. Must be between 0 and {0} + +Gamemaster.cmd.changeweather.weather.success=The weather has changed. +Gamemaster.cmd.changeweather.weather.error=Invalid weather value. Must be between 0 and {0} + +Gamemaster.cmd.changeweather.emi.success1=EMI is active. +Gamemaster.cmd.changeweather.emi.success=EMI is inactive. +Gamemaster.cmd.changeweather.emi.error=Invalid EMI value. Must be between 0 and {0} +# Firestarter cmd +Gamemaster.cmd.fire.type=Type of fire. They are 1=Normal, 2=Inferno, 3=Inferno Bomb or 4=Inferno IV. +Gamemaster.cmd.fire.help=Starts a fire on the board. + +# Firestorm cmd +Gamemaster.cmd.firestorm.help=Starts fire in the entire board. +Gamemaster.cmd.fire.failed=Failed to ignite fire. +Gamemaster.cmd.fire.percent=Percentage of the board hexes to ignite. + +# Orbital bombardment cmd +Gamemaster.cmd.orbitalbombardment.help=Calls an orbital bombardment on the board. It hits after the firing phase. +Gamemaster.cmd.orbitalbombardment.dmg=Damage of the bombardment at target hex. +Gamemaster.cmd.orbitalbombardment.radius=Radius of the bombardment. +Gamemaster.cmd.orbitalbombardment.error.outofbounds=Specified hex is not on the board. +Gamemaster.cmd.orbitalbombardment.success=Orbital bombardment incoming! \ No newline at end of file diff --git a/megamek/i18n/megamek/common/report-messages.properties b/megamek/i18n/megamek/common/report-messages.properties index 5bb6ad59327..b82e7e2a3aa 100755 --- a/megamek/i18n/megamek/common/report-messages.properties +++ b/megamek/i18n/megamek/common/report-messages.properties @@ -59,6 +59,7 @@ 1300=Orbital bombardment hit hex !!! 1301=End of orbital bombardment resolution 1302= has commenced an orbital bombardment, it will land at the end of the next weapons phase at hex . +1303=Start of orbital bombardment resolution # 1500s - ammo handling related 1500= () selected diff --git a/megamek/src/megamek/client/ui/swing/MapMenu.java b/megamek/src/megamek/client/ui/swing/MapMenu.java index 743528ea0d2..505e6fee4f9 100644 --- a/megamek/src/megamek/client/ui/swing/MapMenu.java +++ b/megamek/src/megamek/client/ui/swing/MapMenu.java @@ -441,22 +441,14 @@ private record Tuple(String name, GamemasterServerCommand command) {} private JMenu createGMSpecialCommandsMenu() { JMenu menu = new JMenu(Messages.getString("Gamemaster.SpecialCommands")); - var commands = List.of( - new Tuple("Kill Unit", new KillCommand(null, null)), - new Tuple("Change Ownership", new ChangeOwnershipCommand(null, null)), - new Tuple("Change Weather", new ChangeWeatherCommand(null, null)), - new Tuple("Disasters", new DisasterCommand(null, null)), - new Tuple("Orbital Bombardment", new OrbitalBombardmentCommand(null, null)), - new Tuple("Remove Smoke", new RemoveSmokeCommand(null, null)), - new Tuple("Firestarter", new FirestarterCommand(null, null)), - new Tuple("Firestorm", new FirestormCommand(null, null)) - ); - - for (var cmd : commands) { - JMenuItem item = new JMenuItem(cmd.name()); - item.addActionListener(evt -> new GamemasterCommandPanel(gui.getFrame(), gui, cmd.command()).setVisible(true)); - menu.add(item); - } + Server.getServerInstance().getAllCommands().stream() + .filter(cmd -> cmd instanceof GamemasterServerCommand) + .map(cmd -> (GamemasterServerCommand) cmd) + .forEach(cmd -> { + JMenuItem item = new JMenuItem(cmd.getName()); + item.addActionListener(evt -> new GamemasterCommandPanel(gui.getFrame(), gui, cmd).setVisible(true)); + menu.add(item); + }); return menu; } diff --git a/megamek/src/megamek/client/ui/swing/gmCommands/GamemasterCommandPanel.java b/megamek/src/megamek/client/ui/swing/gmCommands/GamemasterCommandPanel.java index f85f1b7b55d..bd47005e518 100644 --- a/megamek/src/megamek/client/ui/swing/gmCommands/GamemasterCommandPanel.java +++ b/megamek/src/megamek/client/ui/swing/gmCommands/GamemasterCommandPanel.java @@ -1,6 +1,5 @@ package megamek.client.ui.swing.gmCommands; -import megamek.client.IClient; import megamek.client.ui.swing.ClientGUI; import megamek.server.commands.GamemasterServerCommand; import megamek.server.commands.arguments.Argument; @@ -8,6 +7,7 @@ import megamek.server.commands.arguments.IntegerArgument; import javax.swing.*; +import java.awt.*; import java.util.HashMap; import java.util.List; import java.util.Map; @@ -24,25 +24,30 @@ public GamemasterCommandPanel(JFrame parent, ClientGUI client, GamemasterServerC this.client = client; setLayout(new BoxLayout(getContentPane(), BoxLayout.Y_AXIS)); - JLabel helpLabel = new JLabel(command.getHelp()); + JLabel helpLabel = new JLabel(command.getHelpHtml()); add(helpLabel); List> arguments = command.defineArguments(); Map argumentComponents = new HashMap<>(); for (Argument argument : arguments) { + JPanel argumentPanel = new JPanel(); + argumentPanel.setLayout(new FlowLayout(FlowLayout.LEFT)); + JLabel label = new JLabel(argument.getName() + ":"); - add(label); + argumentPanel.add(label); - if (argument instanceof IntegerArgument intArg) { + if (argument instanceof IntegerArgument) { + IntegerArgument intArg = (IntegerArgument) argument; JSpinner spinner = new JSpinner(new SpinnerNumberModel( intArg.hasDefaultValue() ? intArg.getValue() : 0, intArg.getMinValue(), intArg.getMaxValue(), 1)); - add(spinner); + argumentPanel.add(spinner); argumentComponents.put(argument.getName(), spinner); - } else if (argument instanceof EnumArgument enumArg) { + } else if (argument instanceof EnumArgument) { + EnumArgument enumArg = (EnumArgument) argument; JComboBox comboBox = new JComboBox<>(); for (Enum constant : enumArg.getEnumType().getEnumConstants()) { comboBox.addItem(constant.name()); @@ -50,9 +55,11 @@ public GamemasterCommandPanel(JFrame parent, ClientGUI client, GamemasterServerC if (enumArg.getValue() != null) { comboBox.setSelectedItem(enumArg.getValue().name()); } - add(comboBox); + argumentPanel.add(comboBox); argumentComponents.put(argument.getName(), comboBox); } + + add(argumentPanel); } JButton executeButton = new JButton("Execute Command"); @@ -63,6 +70,18 @@ public GamemasterCommandPanel(JFrame parent, ClientGUI client, GamemasterServerC setLocationRelativeTo(parent); } + private String wrapText(String text, int lineLength) { + StringBuilder wrappedText = new StringBuilder(""); + int currentIndex = 0; + while (currentIndex < text.length()) { + int endIndex = Math.min(currentIndex + lineLength, text.length()); + wrappedText.append(text, currentIndex, endIndex).append("
"); + currentIndex = endIndex; + } + wrappedText.append(""); + return wrappedText.toString(); + } + private void executeCommand(Map argumentComponents) { List> arguments = command.defineArguments(); String[] args = new String[arguments.size()]; diff --git a/megamek/src/megamek/client/ui/swing/tileset/TilesetManager.java b/megamek/src/megamek/client/ui/swing/tileset/TilesetManager.java index 1a3ec4ff91e..bd4a3b6feef 100644 --- a/megamek/src/megamek/client/ui/swing/tileset/TilesetManager.java +++ b/megamek/src/megamek/client/ui/swing/tileset/TilesetManager.java @@ -77,7 +77,7 @@ public class TilesetManager implements IPreferenceChangeListener { private static final String FILENAME_ARTILLERY_ADJUSTED_IMAGE = "artyadj.gif"; private static final String FILENAME_ARTILLERY_INCOMING_IMAGE = "artyinc.gif"; - private static final String FILENAME_ORBITAL_BOMBARDMENT_INCOMING_IMAGE = "obinc.gif"; + public static final String FILENAME_ORBITAL_BOMBARDMENT_INCOMING_IMAGE = "obinc.gif"; public static final int ARTILLERY_AUTOHIT = 0; public static final int ARTILLERY_ADJUSTED = 1; diff --git a/megamek/src/megamek/common/SpecialHexDisplay.java b/megamek/src/megamek/common/SpecialHexDisplay.java index 2fb11e1cac3..64875395302 100644 --- a/megamek/src/megamek/common/SpecialHexDisplay.java +++ b/megamek/src/megamek/common/SpecialHexDisplay.java @@ -23,6 +23,8 @@ import megamek.common.util.ImageUtil; import megamek.common.util.fileUtils.MegaMekFile; +import static megamek.client.ui.swing.tileset.TilesetManager.FILENAME_ORBITAL_BOMBARDMENT_INCOMING_IMAGE; + /** * @author dirk */ @@ -101,7 +103,7 @@ public boolean drawAfter() { return true; } }, - ORBITAL_BOMBARDMENT(new MegaMekFile(Configuration.hexesDir(), "obinc.gif").toString()); + ORBITAL_BOMBARDMENT(new MegaMekFile(Configuration.hexesDir(), FILENAME_ORBITAL_BOMBARDMENT_INCOMING_IMAGE).toString()); private transient Image defaultImage; private final String defaultImagePath; diff --git a/megamek/src/megamek/server/Server.java b/megamek/src/megamek/server/Server.java index d62d8555e92..ee832da035b 100644 --- a/megamek/src/megamek/server/Server.java +++ b/megamek/src/megamek/server/Server.java @@ -538,6 +538,13 @@ public Collection getAllCommandNames() { return commandsHash.keySet(); } + /** + * Returns the list of all server commands + */ + public List getAllCommands() { + return new ArrayList<>(commandsHash.values()); + } + /** * Sent when a client attempts to connect. */ diff --git a/megamek/src/megamek/server/commands/ChangeOwnershipCommand.java b/megamek/src/megamek/server/commands/ChangeOwnershipCommand.java index d9ca02e4e9f..d2860a04112 100644 --- a/megamek/src/megamek/server/commands/ChangeOwnershipCommand.java +++ b/megamek/src/megamek/server/commands/ChangeOwnershipCommand.java @@ -1,23 +1,19 @@ /* - * Copyright (c) 2024 - The MegaMek Team. All Rights Reserved. + * MegaMek - Copyright (c) 2024 - The MegaMek Team. All Rights Reserved. * - * This file is part of MegaMek. + * This program 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 2 of the License, or (at your option) + * any later version. * - * 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 . + * This program 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. */ package megamek.server.commands; +import megamek.client.ui.Messages; import megamek.common.Entity; import megamek.common.Player; import megamek.server.Server; @@ -25,49 +21,48 @@ import megamek.server.commands.arguments.IntegerArgument; import megamek.server.totalwarfare.TWGameManager; -import java.util.ArrayList; import java.util.List; import java.util.Map; /** * The Server Command "/changeOwner" that will switch an entity's owner to another player. * - * @author Luana Scoppio + * @author Luana Coppio */ public class ChangeOwnershipCommand extends GamemasterServerCommand { + public static final String UNIT_ID = "unitID"; + public static final String PLAYER_ID = "playerID"; + public ChangeOwnershipCommand(Server server, TWGameManager gameManager) { super(server, gameManager, "changeOwner", - "Switches ownership of a player's entity to another player during the end phase. " - + "Usage: /changeOwner " - + "The following is an example of changing unit ID 7 to player ID 2: /changeOwner 7 2 "); + Messages.getString("Gamemaster.cmd.changeownership.help")); } @Override public List> defineArguments() { - List> arguments = new ArrayList<>(); - arguments.add(new IntegerArgument("unitID", 0, Integer.MAX_VALUE)); - arguments.add(new IntegerArgument("playerID", 0, Integer.MAX_VALUE)); - return arguments; + return List.of( + new IntegerArgument(UNIT_ID, Messages.getString("Gamemaster.cmd.changeownership.unitID")), + new IntegerArgument(PLAYER_ID, Messages.getString("Gamemaster.cmd.changeownership.playerID"))); } @Override protected void runAsGM(int connId, Map> args) { - IntegerArgument unitID = (IntegerArgument) args.get("unitID"); - IntegerArgument playerID = (IntegerArgument) args.get("playerID"); + IntegerArgument unitID = (IntegerArgument) args.get(UNIT_ID); + IntegerArgument playerID = (IntegerArgument) args.get(PLAYER_ID); Entity ent = gameManager.getGame().getEntity(unitID.getValue()); Player player = server.getGame().getPlayer(playerID.getValue()); if (null == ent) { - server.sendServerChat(connId, "No such entity."); + server.sendServerChat(connId, Messages.getString("Gamemaster.cmd.changeownership.unitNotFound")); } else if (null == player) { - server.sendServerChat(connId, "No such player."); + server.sendServerChat(connId, Messages.getString("Gamemaster.cmd.changeownership.playerNotFound")); } else if (player.getTeam() == Player.TEAM_UNASSIGNED) { - server.sendServerChat(connId, "Player must be assigned a team."); + server.sendServerChat(connId, Messages.getString("Gamemaster.cmd.changeownership.playerUnassigned")); } else { - server.sendServerChat(connId, ent.getDisplayName() + " will switch to " + player.getName() + "'s side at the end of this turn."); + server.sendServerChat(connId, Messages.getString("Gamemaster.cmd.changeownership.success", ent.getDisplayName(), player.getName())); ent.setTraitorId(player.getId()); } } diff --git a/megamek/src/megamek/server/commands/ChangeWeatherCommand.java b/megamek/src/megamek/server/commands/ChangeWeatherCommand.java index 3ff818d1c1d..b28f24962ed 100644 --- a/megamek/src/megamek/server/commands/ChangeWeatherCommand.java +++ b/megamek/src/megamek/server/commands/ChangeWeatherCommand.java @@ -1,71 +1,59 @@ /* - * Copyright (c) 2024 - The MegaMek Team. All Rights Reserved. + * MegaMek - Copyright (c) 2024 - The MegaMek Team. All Rights Reserved. * - * This file is part of MegaMek. + * This program 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 2 of the License, or (at your option) + * any later version. * - * 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 . + * This program 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. */ package megamek.server.commands; +import megamek.client.ui.Messages; import megamek.common.planetaryconditions.*; import megamek.server.Server; import megamek.server.commands.arguments.Argument; -import megamek.server.commands.arguments.IntegerArgument; +import megamek.server.commands.arguments.OptionalIntegerArgument; import megamek.server.totalwarfare.TWGameManager; - -import java.util.ArrayList; import java.util.List; import java.util.Map; import java.util.function.Consumer; import java.util.function.Function; -import java.util.stream.Stream; /** - * @author Luana Scoppio + * @author Luana Coppio */ public class ChangeWeatherCommand extends GamemasterServerCommand { - private static final String HELP_TEXT = "GM changes (weather) planetary conditions. The parameters are optional and unordered " + - "and the effects are applied at the beginning of the next turn. The square brackets means that argument is optional. " + - "Usage format: /weather [fog=0-2] [wind=0-6] [winddir=0-6] [light=0-6] [atmo=0-5] [blowsand=0-1] [weather=0-14] " + - "light= 0: daylight, 1: dusk, 2: full moon, 3: glare, 4: moonless night, 5: solar flare, 6: pitch black " + - "fog= 0: none, 1: light, 2: heavy " + - "wind= 0: calm, 1: light gale, 2: moderate gale, 3: strong gale, 4: storm, 5: tornado F1-F3, 6: tornado F4 " + - "winddir= 0: south, 1: southwest, 2: northwest, 3: north, 4: northeast, 5: southeast, 6: random " + - "atmo= 0: vacuum, 1: trace, 2: thin, 3: standard, 4: high, 5: very high " + - "blowsand= 0: no, 1: yes " + - "emi= 0: no, 1: yes " + - "weather= 0: clear, 1: light rain, 2: moderate rain, 3: heavy rain, 4: gusting rain, 5: downpour, 6: light snow " + - "7: moderate snow, 8: snow flurries, 9: heavy snow, 10: sleet, 11: ice storm, 12: light hail, 13: heavy hail " + - "14: lightning storm"; + private static final String FOG = "fog"; + private static final String LIGHT = "light"; + private static final String WIND = "wind"; + private static final String WIND_DIR = "winddir"; + private static final String ATMO = "atmo"; + private static final String BLOWSAND = "blowsand"; + private static final String EMIS = "emi"; + private static final String WEATHER = "weather"; /** Creates new ChangeWeatherCommand */ public ChangeWeatherCommand(Server server, TWGameManager gameManager) { - super(server, gameManager, "weather", HELP_TEXT); + super(server, gameManager, WEATHER, Messages.getString("Gamemaster.cmd.changeweather.help")); } + @Override public List> defineArguments() { - List> arguments = new ArrayList<>(); - arguments.add(new IntegerArgument("fog", 0, 2)); - arguments.add(new IntegerArgument("light", 0, 6)); - arguments.add(new IntegerArgument("wind", 0, 6)); - arguments.add(new IntegerArgument("atmo", 0, 5)); - arguments.add(new IntegerArgument("blowsand", 0, 1)); - arguments.add(new IntegerArgument("emi", 0, 1)); - arguments.add(new IntegerArgument("weather", 0, 14)); - return arguments; + return List.of(new OptionalIntegerArgument(FOG, Messages.getString("Gamemaster.cmd.changeweather.fog"), 0, 2), + new OptionalIntegerArgument(LIGHT, Messages.getString("Gamemaster.cmd.changeweather.light"), 0, 6), + new OptionalIntegerArgument(WIND, Messages.getString("Gamemaster.cmd.changeweather.wind"), 0, 6), + new OptionalIntegerArgument(WIND_DIR, Messages.getString("Gamemaster.cmd.changeweather.winddir"), 0, 6), + new OptionalIntegerArgument(ATMO, Messages.getString("Gamemaster.cmd.changeweather.atmo"), 0, 5), + new OptionalIntegerArgument(BLOWSAND, Messages.getString("Gamemaster.cmd.changeweather.blowsand"), 0, 1), + new OptionalIntegerArgument(EMIS, Messages.getString("Gamemaster.cmd.changeweather.emi"), 0, 1), + new OptionalIntegerArgument(WEATHER, Messages.getString("Gamemaster.cmd.changeweather.weather"), 0, 14)); } private void updatePlanetaryCondition(int value, int connId, int maxLength, Consumer setter, @@ -78,7 +66,6 @@ private void updatePlanetaryCondition(int value, int connId, int maxLength, Cons } } - private record Condition(int maxLength, Consumer setter, Function successMessage, Function errorMessage) {} /** @@ -89,27 +76,36 @@ public void runAsGM(int connId, Map> args) { var planetaryConditions = getGameManager().getGame().getPlanetaryConditions(); Map conditions = Map.of( - "fog", new Condition(Fog.values().length, value -> planetaryConditions.setFog(Fog.values()[value]), - value -> "The fog has changed.", maxLength -> "Invalid fog value. Must be between 0 and " + (maxLength - 1)), - "wind", new Condition(Wind.values().length, value -> planetaryConditions.setWind(Wind.values()[value]), - value -> "The wind strength has changed.", maxLength -> "Invalid wind value. Must be between 0 and " + (maxLength - 1)), - "winddir", new Condition(WindDirection.values().length, value -> planetaryConditions.setWindDirection(WindDirection.values()[value]), - value -> "The wind direction has changed.", maxLength -> "Invalid wind direction value. Must be between 0 and " + (maxLength - 1)), - "light", new Condition(Light.values().length, value -> planetaryConditions.setLight(Light.values()[value]), - value -> "The light has changed.", maxLength -> "Invalid light value. Must be between 0 and " + (maxLength - 1)), - "atmo", new Condition(Atmosphere.values().length, value -> planetaryConditions.setAtmosphere(Atmosphere.values()[value]), - value -> value == 0 ? "The air has vanished, put your vac suits!" : "The air is changing.", maxLength -> "Invalid atmosphere value. Must be between 0 and " + (maxLength - 1)), - "blowsand", new Condition(BlowingSand.values().length, value -> planetaryConditions.setBlowingSand(BlowingSand.values()[value]), - value -> value == 1 ? "Sand started blowing." : "The sand has settled.", maxLength -> "Invalid blowsand value. Must be between 0 and " + (maxLength - 1)), - "weather", new Condition(Weather.values().length, value -> planetaryConditions.setWeather(Weather.values()[value]), - value -> "The weather has changed.", maxLength -> "Invalid weather value. Must be between 0 and " + (maxLength - 1)), - "emi", new Condition(EMI.values().length, value -> planetaryConditions.setEMI(EMI.values()[value]), - value -> value == 1 ? "EMI is active." : "EMI is inactive.", maxLength -> "Invalid EMI value. Must be between 0 and " + (maxLength - 1)) + FOG, new Condition(Fog.values().length, value -> planetaryConditions.setFog(Fog.values()[value]), + value -> Messages.getString("Gamemaster.cmd.changeweather.fog.success"), + maxLength -> Messages.getString("Gamemaster.cmd.changeweather.fog.error", (maxLength - 1))), + WIND, new Condition(Wind.values().length, value -> planetaryConditions.setWind(Wind.values()[value]), + value -> Messages.getString("Gamemaster.cmd.changeweather.wind.success"), + maxLength -> Messages.getString("Gamemaster.cmd.changeweather.wind.error", (maxLength - 1))), + WIND_DIR, new Condition(WindDirection.values().length, value -> planetaryConditions.setWindDirection(WindDirection.values()[value]), + value -> Messages.getString("Gamemaster.cmd.changeweather.winddir.success"), + maxLength -> Messages.getString("Gamemaster.cmd.changeweather.winddir.error", (maxLength - 1))), + LIGHT, new Condition(Light.values().length, value -> planetaryConditions.setLight(Light.values()[value]), + value -> Messages.getString("Gamemaster.cmd.changeweather.light.success"), + maxLength -> Messages.getString("Gamemaster.cmd.changeweather.light.error", (maxLength - 1))), + ATMO, new Condition(Atmosphere.values().length, value -> planetaryConditions.setAtmosphere(Atmosphere.values()[value]), + value -> value == 0 ? Messages.getString("Gamemaster.cmd.changeweather.atmo.success0") : Messages.getString("Gamemaster.cmd.changeweather.atmo.success"), + maxLength -> Messages.getString("Gamemaster.cmd.changeweather.atmo.error", (maxLength - 1))), + BLOWSAND, new Condition(BlowingSand.values().length, value -> planetaryConditions.setBlowingSand(BlowingSand.values()[value]), + value -> value == 1 ? Messages.getString("Gamemaster.cmd.changeweather.blowsand.success1") : Messages.getString("Gamemaster.cmd.changeweather.blowsand.success"), + maxLength -> Messages.getString("Gamemaster.cmd.changeweather.blowsand.error", (maxLength - 1))), + WEATHER, new Condition(Weather.values().length, value -> planetaryConditions.setWeather(Weather.values()[value]), + value -> Messages.getString("Gamemaster.cmd.changeweather.weather.success"), + maxLength -> Messages.getString("Gamemaster.cmd.changeweather.weather.error", (maxLength - 1))), + EMIS, new Condition(EMI.values().length, value -> planetaryConditions.setEMI(EMI.values()[value]), + value -> value == 1 ? Messages.getString("Gamemaster.cmd.changeweather.emi.success1") : Messages.getString("Gamemaster.cmd.changeweather.emi.success"), + maxLength -> Messages.getString("Gamemaster.cmd.changeweather.emi.error", (maxLength - 1))) ); + conditions.forEach((prefix, condition) -> { - if (args.containsKey(prefix)) { + if (args.containsKey(prefix) && ((OptionalIntegerArgument) args.get(prefix)).getValue().isPresent()) { updatePlanetaryCondition( - (int) args.get(prefix).getValue(), + ((OptionalIntegerArgument) args.get(prefix)).getValue().get(), connId, condition.maxLength, condition.setter, @@ -120,5 +116,4 @@ public void runAsGM(int connId, Map> args) { getGameManager().getGame().setPlanetaryConditions(planetaryConditions); } - } diff --git a/megamek/src/megamek/server/commands/DisasterCommand.java b/megamek/src/megamek/server/commands/DisasterCommand.java index f3fc13e354d..0c7d3dc4b2f 100644 --- a/megamek/src/megamek/server/commands/DisasterCommand.java +++ b/megamek/src/megamek/server/commands/DisasterCommand.java @@ -1,25 +1,20 @@ /* - * Copyright (c) 2024 - The MegaMek Team. All Rights Reserved. + * MegaMek - Copyright (c) 2024 - The MegaMek Team. All Rights Reserved. * - * This file is part of MegaMek. + * This program 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 2 of the License, or (at your option) + * any later version. * - * 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 . + * This program 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. */ package megamek.server.commands; +import megamek.client.ui.Messages; import megamek.common.Coords; -import megamek.logging.MMLogger; import megamek.server.Server; import megamek.server.commands.arguments.Argument; import megamek.server.commands.arguments.EnumArgument; @@ -27,13 +22,14 @@ import java.util.List; import java.util.Map; -import java.util.Objects; /** - * @author Luana Scoppio + * @author Luana Coppio */ public class DisasterCommand extends GamemasterServerCommand { + public static final String TYPE = "type"; + enum Disaster { RANDOM, HURRICANE, @@ -56,18 +52,12 @@ public static Disaster getRandomDisaster() { } public DisasterCommand(Server server, TWGameManager gameManager) { - super(server, gameManager, "gomorrah", "GM calls a disaster, arguments in square brackets are optional. " + - "Usage: /gomorrah [type] " + - "if not type is passed, one is chosen at random. " + - "Type can be one of the following: hurricane, lightning, ob, ob2, ob3, sandstorm, hailstorm, eclipse, solarflare, " + - "supernova, smog, firestorm, traitor. " + - "The type ob, ob2 and ob3 are orbital bombardment with one, two or three random hit locations, at default values " + - "for damage (100) and radius (4)."); + super(server, gameManager, "disaster", Messages.getString("Gamemaster.cmd.disaster.help")); } @Override public List> defineArguments() { - return List.of(new EnumArgument<>("type", Disaster.class, Disaster.RANDOM)); + return List.of(new EnumArgument<>(TYPE, Messages.getString("Gamemaster.cmd.disaster.type"), Disaster.class, Disaster.RANDOM)); } private void runDisasterCommand(int connId, Disaster disaster) { @@ -157,10 +147,10 @@ private void orbitalBombardment(int connId) { */ @Override protected void runAsGM(int connId, Map> args) { - if (args.get("type").getValue().equals(Disaster.RANDOM)) { + if (args.get(TYPE).getValue().equals(Disaster.RANDOM)) { runDisasterCommand(connId, Disaster.getRandomDisaster()); } else { - runDisasterCommand(connId, (Disaster) args.get("type").getValue()); + runDisasterCommand(connId, (Disaster) args.get(TYPE).getValue()); } } } diff --git a/megamek/src/megamek/server/commands/FirestarterCommand.java b/megamek/src/megamek/server/commands/FirestarterCommand.java index 8e4fece3254..2af7f0d4913 100644 --- a/megamek/src/megamek/server/commands/FirestarterCommand.java +++ b/megamek/src/megamek/server/commands/FirestarterCommand.java @@ -1,23 +1,19 @@ /* - * Copyright (c) 2024 - The MegaMek Team. All Rights Reserved. + * MegaMek - Copyright (c) 2024 - The MegaMek Team. All Rights Reserved. * - * This file is part of MegaMek. + * This program 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 2 of the License, or (at your option) + * any later version. * - * 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 . + * This program 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. */ package megamek.server.commands; +import megamek.client.ui.Messages; import megamek.common.Coords; import megamek.common.Hex; import megamek.server.Server; @@ -32,26 +28,28 @@ /** * The Server Command "/firestarter" that will put one hex on fire. * - * @author Luana Scoppio + * @author Luana Coppio */ public class FirestarterCommand extends GamemasterServerCommand { + private static final String FIRESTARTER = "firestarter"; + private static final String X = "x"; + private static final String Y = "y"; + private static final String TYPE = "type"; + public FirestarterCommand(Server server, TWGameManager gameManager) { super(server, gameManager, - "firestarter", - "Starts fire in one specific hex at a specific intensity. " - + "Usage: /firestarter [] " - + "The intensity can be 1=Norma, 2=Inferno, 3=Inferno Bomb or 4=Inferno IV, default is 1."); + FIRESTARTER, + Messages.getString("Gamemaster.cmd.fire.help")); } - @Override public List> defineArguments() { return List.of( - new IntegerArgument("x"), - new IntegerArgument("y"), - new IntegerArgument("intensity", 1, 4, 1)); + new IntegerArgument(X, Messages.getString("Gamemaster.cmd.x")), + new IntegerArgument(Y, Messages.getString("Gamemaster.cmd.y")), + new IntegerArgument(TYPE, Messages.getString("Gamemaster.cmd.fire.type"), 1, 4, 1)); } /** @@ -61,10 +59,9 @@ public List> defineArguments() { */ @Override protected void runAsGM(int connId, Map> args) { - int xArg = (int) args.get("x").getValue() - 1; - int yArg = (int) args.get("y").getValue() -1; - int fireType = (int) args.get("intensity").getValue(); - + int xArg = (int) args.get(X).getValue() - 1; + int yArg = (int) args.get(Y).getValue() - 1; + int fireType = (int) args.get(TYPE).getValue(); igniteHex(new Coords(xArg, yArg), fireType); } @@ -77,5 +74,4 @@ private void igniteHex(Coords coords, int fireType) { throw new IllegalArgumentException("Failed to ignite hex: " + e.getMessage()); } } - } diff --git a/megamek/src/megamek/server/commands/FirestormCommand.java b/megamek/src/megamek/server/commands/FirestormCommand.java index 03d2e03d961..e349392718c 100644 --- a/megamek/src/megamek/server/commands/FirestormCommand.java +++ b/megamek/src/megamek/server/commands/FirestormCommand.java @@ -1,23 +1,19 @@ /* - * Copyright (c) 2024 - The MegaMek Team. All Rights Reserved. + * MegaMek - Copyright (c) 2024 - The MegaMek Team. All Rights Reserved. * - * This file is part of MegaMek. + * This program 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 2 of the License, or (at your option) + * any later version. * - * 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 . + * This program 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. */ package megamek.server.commands; +import megamek.client.ui.Messages; import megamek.common.Coords; import megamek.common.Hex; import megamek.server.Server; @@ -25,7 +21,6 @@ import megamek.server.commands.arguments.IntegerArgument; import megamek.server.totalwarfare.TWGameManager; -import java.util.ArrayList; import java.util.HashSet; import java.util.List; import java.util.Map; @@ -33,24 +28,27 @@ /** * The Server Command "/firestorm" that starts a blazing inferno on the board. * - * @author Luana Scoppio + * @author Luana Coppio */ public class FirestormCommand extends GamemasterServerCommand { + private static final String FIRESTORM = "firestorm"; + private static final String TYPE = "type"; + private static final String PERCENT = "percent"; + public FirestormCommand(Server server, TWGameManager gameManager) { super(server, gameManager, - "firestorm", - "Starts fire in the entire board. " - + "Usage: /firestorm [] []" - + "The intensity can be 1=Normal, 2=Inferno, 3=Inferno Bomb or 4=Inferno IV, default is 1. " - + "The size can be a percent of the board, from 1 to 100, default is 25."); + FIRESTORM, + Messages.getString("Gamemaster.cmd.firestorm.help")); } @Override public List> defineArguments() { - return List.of(new IntegerArgument("intensity", 1, 4, 1), - new IntegerArgument("percent", 1, 100, 25)); + return List.of( + new IntegerArgument(TYPE, Messages.getString("Gamemaster.cmd.fire.type"), 1, 4, 1), + new IntegerArgument(PERCENT, Messages.getString("Gamemaster.cmd.fire.percent"), 1, 100, 25) + ); } /** @@ -61,13 +59,13 @@ public List> defineArguments() { @Override protected void runAsGM(int connId, Map> args) { try { - var fireType = (int) args.get("intensity").getValue(); - var percent = (int) args.get("percent").getValue(); + var fireType = (int) args.get(TYPE).getValue(); + var percent = (int) args.get(PERCENT).getValue(); var coords = getRandomCoords(numberOfCoordsFromPercent(percent)); coords.forEach(c -> igniteHex(c, fireType)); } catch (Exception e) { - logger.error("Failed to ignite fire.", e); - server.sendServerChat(connId, "Failed to ignite fire."); + logger.error(Messages.getString("Gamemaster.cmd.fire.failed"), e); + server.sendServerChat(connId, Messages.getString("Gamemaster.cmd.fire.failed")); } } @@ -95,7 +93,8 @@ private HashSet getRandomCoords(int size) { private void igniteHex(Coords coords, int fireType) { Hex hex = gameManager.getGame().getBoard().getHex(coords); if (null == hex) { - // Just ignore null hexes... they should not happen, but I don't want to crash the command + // Just ignore null hexes... + // they should not happen, but I don't want to crash the command return; } gameManager.ignite(coords, fireType, gameManager.getvPhaseReport()); diff --git a/megamek/src/megamek/server/commands/GamemasterServerCommand.java b/megamek/src/megamek/server/commands/GamemasterServerCommand.java index 2c56403cc29..cd3674e09bf 100644 --- a/megamek/src/megamek/server/commands/GamemasterServerCommand.java +++ b/megamek/src/megamek/server/commands/GamemasterServerCommand.java @@ -1,23 +1,19 @@ /* - * Copyright (c) 2024 - The MegaMek Team. All Rights Reserved. + * MegaMek - Copyright (c) 2024 - The MegaMek Team. All Rights Reserved. * - * This file is part of MegaMek. + * This program 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 2 of the License, or (at your option) + * any later version. * - * 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 . + * This program 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. */ package megamek.server.commands; +import megamek.client.ui.Messages; import megamek.logging.MMLogger; import megamek.server.Server; import megamek.server.commands.arguments.Argument; @@ -31,7 +27,9 @@ * @author Luana Coppio */ public abstract class GamemasterServerCommand extends ServerCommand { - + private static final String NEWLINE = "\n"; + private static final String WHITESPACE = " "; + private static final String LONG_WHITESPACE = " "; private static final String EMPTY_ARGUMENT = null; protected final TWGameManager gameManager; protected final static MMLogger logger = MMLogger.create(GamemasterServerCommand.class); @@ -82,6 +80,7 @@ public void run(int connId, String[] args) { // Parses the arguments using the definition private Map> parseArguments(String[] args) { + List> argumentDefinitions = defineArguments(); Map> parsedArguments = new HashMap<>(); List positionalArguments = new ArrayList<>(); @@ -94,7 +93,8 @@ private Map> parseArguments(String[] args) { // Separate positional arguments and named arguments boolean namedArgumentStarted = false; - for (String arg : List.of(args)) { + for (int i = 1; i < args.length; i++) { + String arg = args[i]; String[] keyValue = arg.split("="); if (keyValue.length == 2) { @@ -140,6 +140,43 @@ private Map> parseArguments(String[] args) { return parsedArguments; } + public String getHelpHtml() { + return "" + + this.getHelp() + .replaceAll("<", "<") + .replaceAll(">", ">") + .replaceAll(" ", " ") + .replaceAll(NEWLINE, "
")+ + ""; + } + + @Override + public String getHelp() { + StringBuilder help = new StringBuilder(); + help.append(super.getHelp()) + .append(NEWLINE) + .append(Messages.getString("Gamemaster.cmd.help")) + .append(NEWLINE) + .append("/") + .append(getName()); + + for (Argument arg : defineArguments()) { + help.append(WHITESPACE) + .append(arg.getRepr()); + } + + help.append(NEWLINE); + for (var arg : defineArguments()) { + help.append(LONG_WHITESPACE) + .append(arg.getName()) + .append(":") + .append(WHITESPACE) + .append(arg.getHelp()) + .append(NEWLINE); + } + return help.toString(); + } + // The new method for game master commands that uses parsed arguments protected abstract void runAsGM(int connId, Map> args); } diff --git a/megamek/src/megamek/server/commands/HelpCommand.java b/megamek/src/megamek/server/commands/HelpCommand.java index 8c68edde3d3..ceaeb93c94c 100644 --- a/megamek/src/megamek/server/commands/HelpCommand.java +++ b/megamek/src/megamek/server/commands/HelpCommand.java @@ -22,7 +22,7 @@ * The help command lists the other commands when run without arguments. When * run with another command name as an argument, it queries that command for its * help string and send that to the client. - * + * * @author Ben * @since March 30, 2002, 7:03 PM */ @@ -51,8 +51,10 @@ public void run(int connId, String[] args) { + "\" not recognized. Commands available: " + commandList()); } else { - server.sendServerChat(connId, "/" + command.getName() + " : " - + command.getHelp()); + var help = command.getHelp(); + for (String line : help.split("\n")) { + server.sendServerChat(connId, line); + } } } } @@ -64,7 +66,7 @@ private String commandList() { Collections.sort(cmdNames); for (String cmdName : cmdNames) { - if (commandList.length() > 0) { + if (!commandList.isEmpty()) { commandList.append(", "); } commandList.append(cmdName); diff --git a/megamek/src/megamek/server/commands/KillCommand.java b/megamek/src/megamek/server/commands/KillCommand.java index 3001ae0fe5a..d0d19a94970 100644 --- a/megamek/src/megamek/server/commands/KillCommand.java +++ b/megamek/src/megamek/server/commands/KillCommand.java @@ -1,24 +1,19 @@ /* - * Copyright (c) 2024 - The MegaMek Team. All Rights Reserved. + * MegaMek - Copyright (c) 2024 - The MegaMek Team. All Rights Reserved. * - * This file is part of MegaMek. + * This program 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 2 of the License, or (at your option) + * any later version. * - * 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 . + * This program 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. */ package megamek.server.commands; -import megamek.common.options.OptionsConstants; +import megamek.client.ui.Messages; import megamek.server.Server; import megamek.server.commands.arguments.Argument; import megamek.server.commands.arguments.IntegerArgument; @@ -28,24 +23,20 @@ import java.util.Map; /** - * @author Luana Scoppio + * @author Luana Coppio */ public class KillCommand extends GamemasterServerCommand{ - private final TWGameManager gameManager; + public static final String UNIT_ID = "unitID"; /** Creates new KillCommand */ public KillCommand(Server server, TWGameManager gameManager) { - super(server, gameManager, "kill", "Allows a GM to destroy a single unit instantly" + - "Usage: "+ - "/kill " + - "where id is the units ID. The units ID can be found by hovering over the unit."); - this.gameManager = gameManager; + super(server, gameManager, "kill", Messages.getString("Gamemaster.cmd.kill.help")); } @Override public List> defineArguments() { - return List.of(new IntegerArgument("unitID", 0, Integer.MAX_VALUE)); + return List.of(new IntegerArgument(UNIT_ID, Messages.getString("Gamemaster.cmd.kill.unitID"))); } /** @@ -53,14 +44,14 @@ public List> defineArguments() { */ @Override protected void runAsGM(int connId, Map> args) { - int unitId = (int) args.get("unitID").getValue(); + int unitId = (int) args.get(UNIT_ID).getValue(); // is the unit on the board? var unit = gameManager.getGame().getEntity(unitId); if (unit == null) { - server.sendServerChat(connId, "Specified unit is not on the board."); + server.sendServerChat(connId, Messages.getString("Gamemaster.cmd.missingUnit")); return; } - gameManager.destroyEntity(unit, "Act of God", false, false); - server.sendServerChat(unit.getDisplayName() + " has been devastated."); + gameManager.destroyEntity(unit, Messages.getString("Gamemaster.cmd.kill.reason"), false, false); + server.sendServerChat(unit.getDisplayName() + Messages.getString("Gamemaster.cmd.kill.success")); } } diff --git a/megamek/src/megamek/server/commands/OrbitalBombardmentCommand.java b/megamek/src/megamek/server/commands/OrbitalBombardmentCommand.java index 9a970eb2d1f..7d9a08b65db 100644 --- a/megamek/src/megamek/server/commands/OrbitalBombardmentCommand.java +++ b/megamek/src/megamek/server/commands/OrbitalBombardmentCommand.java @@ -1,62 +1,49 @@ /* - * Copyright (c) 2024 - The MegaMek Team. All Rights Reserved. + * MegaMek - Copyright (c) 2024 - The MegaMek Team. All Rights Reserved. * - * This file is part of MegaMek. + * This program 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 2 of the License, or (at your option) + * any later version. * - * 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 . + * This program 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. */ package megamek.server.commands; -import megamek.common.options.OptionsConstants; +import megamek.client.ui.Messages; import megamek.server.Server; import megamek.server.commands.arguments.Argument; import megamek.server.commands.arguments.IntegerArgument; import megamek.server.props.OrbitalBombardment; import megamek.server.totalwarfare.TWGameManager; -import java.util.ArrayList; import java.util.List; import java.util.Map; /** - * @author Luana Scoppio + * @author Luana Coppio */ public class OrbitalBombardmentCommand extends GamemasterServerCommand { + public static final String X = "x"; + public static final String Y = "y"; + public static final String DMG = "dmg"; + public static final String RADIUS = "radius"; + public OrbitalBombardmentCommand(Server server, TWGameManager gameManager) { - super(server, gameManager, "ob", "GM orders an unknown warship to strike the board doing of 100 damage with a 4 hex radius, to be exploded at" - + "the end of the next weapons attack phase." - + "Allowed formats: " - + "/ob and" - + "/ob [dmg=#] [r=#] and" - + "/ob and " - + "/ob " - + "X and Y are the hex position where is x=column number and y=row number (hex 0923 would be x=9 and y=23), " - + "dmg is the amount of damage at impact point, default is 100, the damage drops off linearly according to the radius. " - + "r is radius, defaults to 4. " - + " Example: /ob 10 10 dmg=120 r=4 and /ob 10 10 120 4 are equivalent. " - + " Parameters in square brackets may be omitted, and using named variables permits to write them out of order. " - + " Example: /ob 10 10 r=12 dmg=300"); + super(server, gameManager, "ob", Messages.getString("Gamemaster.cmd.orbitalbombardment.help")); } @Override public List> defineArguments() { return List.of( - new IntegerArgument("x"), - new IntegerArgument("y"), - new IntegerArgument("dmg", 10, Integer.MAX_VALUE, 100), - new IntegerArgument("r", 1, 10, 4)); + new IntegerArgument(X, Messages.getString("Gamemaster.cmd.x")), + new IntegerArgument(Y, Messages.getString("Gamemaster.cmd.y")), + new IntegerArgument(DMG, Messages.getString("Gamemaster.cmd.orbitalbombardment.dmg"), 10, Integer.MAX_VALUE, 100), + new IntegerArgument(RADIUS, Messages.getString("Gamemaster.cmd.orbitalbombardment.radius"), 1, 10, 4)); } /** @@ -67,19 +54,20 @@ protected void runAsGM(int connId, Map> args) { var orbitalBombardmentBuilder = new OrbitalBombardment.Builder(); - orbitalBombardmentBuilder.x((int) args.get("x").getValue() - 1).y((int) args.get("y").getValue() - 1); - orbitalBombardmentBuilder.radius((int) args.get("r").getValue()); - orbitalBombardmentBuilder.damageFactor((int) args.get("dmg").getValue()); + orbitalBombardmentBuilder.x((int) args.get(X).getValue() - 1) + .y((int) args.get(Y).getValue() - 1) + .radius((int) args.get(RADIUS).getValue()) + .damage((int) args.get(DMG).getValue()); var orbitalBombardment = orbitalBombardmentBuilder.build(); // is the hex on the board? if (!gameManager.getGame().getBoard().contains(orbitalBombardment.getX(), orbitalBombardment.getY())) { - server.sendServerChat(connId, "Specified hex is not on the board."); + server.sendServerChat(connId, Messages.getString("Gamemaster.cmd.orbitalbombardment.error.outofbounds")); return; } gameManager.addScheduledOrbitalBombardment(orbitalBombardment); - server.sendServerChat("Orbital bombardment incoming!"); + server.sendServerChat(Messages.getString("Gamemaster.cmd.orbitalbombardment.success")); } } diff --git a/megamek/src/megamek/server/commands/RemoveSmokeCommand.java b/megamek/src/megamek/server/commands/RemoveSmokeCommand.java index 75373384714..7286cc99955 100644 --- a/megamek/src/megamek/server/commands/RemoveSmokeCommand.java +++ b/megamek/src/megamek/server/commands/RemoveSmokeCommand.java @@ -1,26 +1,19 @@ /* - * Copyright (C) 2024 Luana Scoppio (luana.coppio@gmail.com) - * Copyright (c) 2024 - The MegaMek Team. All Rights Reserved. + * MegaMek - Copyright (c) 2024 - The MegaMek Team. All Rights Reserved. * - * This file is part of MegaMek. + * This program 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 2 of the License, or (at your option) + * any later version. * - * 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 . + * This program 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. */ package megamek.server.commands; -import megamek.common.planetaryconditions.Fog; -import megamek.common.planetaryconditions.Wind; +import megamek.client.ui.Messages; import megamek.server.Server; import megamek.server.commands.arguments.Argument; import megamek.server.totalwarfare.TWGameManager; @@ -29,13 +22,13 @@ import java.util.Map; /** - * @author Luana Scoppio + * @author Luana Coppio */ public class RemoveSmokeCommand extends GamemasterServerCommand { /** Creates new KillCommand */ public RemoveSmokeCommand(Server server, TWGameManager gameManager) { - super(server, gameManager, "nosmoke", "GM removes all smoke cloud hexes. Usage: /nosmoke"); + super(server, gameManager, "nosmoke", Messages.getString("Gamemaster.cmd.removesmoke.help")); } @Override @@ -46,6 +39,6 @@ public List> defineArguments() { @Override protected void runAsGM(int connId, Map> args) { gameManager.getSmokeCloudList().forEach(gameManager::removeSmokeTerrain); - server.sendServerChat(connId, "GM cleared the smoke clouds."); + server.sendServerChat(connId, Messages.getString("Gamemaster.cmd.removesmoke.success")); } } diff --git a/megamek/src/megamek/server/commands/TraitorCommand.java b/megamek/src/megamek/server/commands/TraitorCommand.java index 6b19396f8bb..a03e977511d 100644 --- a/megamek/src/megamek/server/commands/TraitorCommand.java +++ b/megamek/src/megamek/server/commands/TraitorCommand.java @@ -1,20 +1,15 @@ /* - * Copyright (c) 2021 - The MegaMek Team. All Rights Reserved. + * MegaMek - Copyright (c) 2024 - The MegaMek Team. All Rights Reserved. * - * This file is part of MegaMek. + * This program 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 2 of the License, or (at your option) + * any later version. * - * 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 . + * This program 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. */ package megamek.server.commands; @@ -25,7 +20,7 @@ /** * The Server Command "/traitor" that will switch an entity's owner to another player. - * + * * @author Jay Lawson (Taharqa) */ public class TraitorCommand extends ServerCommand { @@ -43,7 +38,7 @@ public TraitorCommand(Server server, TWGameManager gameManager) { /** * Run this command with the arguments supplied - * + * * @see megamek.server.commands.ServerCommand#run(int, java.lang.String[]) */ @Override diff --git a/megamek/src/megamek/server/commands/arguments/Argument.java b/megamek/src/megamek/server/commands/arguments/Argument.java index 39d4aa056c3..e04da44df35 100644 --- a/megamek/src/megamek/server/commands/arguments/Argument.java +++ b/megamek/src/megamek/server/commands/arguments/Argument.java @@ -3,11 +3,12 @@ // A generic Argument class that can be extended for different argument types public abstract class Argument { protected T value; - private final String name; + private final String description; - public Argument(String name) { + public Argument(String name, String description) { this.name = name; + this.description = description; } public T getValue() { @@ -18,5 +19,15 @@ public String getName() { return name; } + public String getDescription() { + return description; + } + + public String getRepr() { + return "<" + getName() + ">"; + } + + public abstract String getHelp(); + public abstract void parse(String input) throws IllegalArgumentException; } diff --git a/megamek/src/megamek/server/commands/arguments/EnumArgument.java b/megamek/src/megamek/server/commands/arguments/EnumArgument.java index 5c51072579b..f317027432f 100644 --- a/megamek/src/megamek/server/commands/arguments/EnumArgument.java +++ b/megamek/src/megamek/server/commands/arguments/EnumArgument.java @@ -1,13 +1,15 @@ package megamek.server.commands.arguments; +import megamek.client.ui.Messages; + import java.util.Arrays; public class EnumArgument> extends Argument { private final Class enumType; private final E defaultValue; - public EnumArgument(String name, Class enumType, E defaultValue) { - super(name); + public EnumArgument(String name, String description, Class enumType, E defaultValue) { + super(name, description); this.enumType = enumType; this.defaultValue = defaultValue; } @@ -41,4 +43,14 @@ public E getValue() { } return value; } + + @Override + public String getHelp() { + return getDescription() + + " (" + String.join(", ", Arrays.toString(enumType.getEnumConstants())) + ")" + + (defaultValue != null ? + " [default: " + defaultValue + "]. " + Messages.getString("Gamemaster.cmd.params.optional") : + " " + Messages.getString("Gamemaster.cmd.params.required")); + } + } diff --git a/megamek/src/megamek/server/commands/arguments/IntegerArgument.java b/megamek/src/megamek/server/commands/arguments/IntegerArgument.java index 26340b84879..e3d7b27d962 100644 --- a/megamek/src/megamek/server/commands/arguments/IntegerArgument.java +++ b/megamek/src/megamek/server/commands/arguments/IntegerArgument.java @@ -1,20 +1,24 @@ package megamek.server.commands.arguments; +import megamek.client.ui.Messages; + +import java.util.Arrays; + public class IntegerArgument extends Argument { private final int minValue; private final int maxValue; private final Integer defaultValue; - public IntegerArgument(String name) { - this(name, Integer.MIN_VALUE, Integer.MAX_VALUE, null); + public IntegerArgument(String name, String description) { + this(name, description, Integer.MIN_VALUE, Integer.MAX_VALUE, null); } - public IntegerArgument(String name, int minValue, int maxValue) { - this(name, minValue, maxValue, null); + public IntegerArgument(String name, String description, int minValue, int maxValue) { + this(name, description, minValue, maxValue, null); } - public IntegerArgument(String name, int minValue, int maxValue, Integer defaultValue) { - super(name); + public IntegerArgument(String name, String description, int minValue, int maxValue, Integer defaultValue) { + super(name, description); this.minValue = minValue; this.maxValue = maxValue; this.defaultValue = defaultValue; @@ -60,4 +64,13 @@ public int getMinValue() { public int getMaxValue() { return maxValue; } + + @Override + public String getHelp() { + return getDescription() + (minValue == Integer.MIN_VALUE ? "": " Min: " + minValue) + + (defaultValue != null ? + " [default: " + defaultValue + "]. " + Messages.getString("Gamemaster.cmd.params.optional") : + " " + Messages.getString("Gamemaster.cmd.params.required")); + } + } diff --git a/megamek/src/megamek/server/commands/arguments/OptionalIntegerArgument.java b/megamek/src/megamek/server/commands/arguments/OptionalIntegerArgument.java new file mode 100644 index 00000000000..fc857b1148e --- /dev/null +++ b/megamek/src/megamek/server/commands/arguments/OptionalIntegerArgument.java @@ -0,0 +1,77 @@ +/* + * MegaMek - Copyright (c) 2024 - The MegaMek Team. All Rights Reserved. + * + * This program 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 2 of the License, or (at your option) + * any later version. + * + * This program 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. + */ +package megamek.server.commands.arguments; + +import megamek.client.ui.Messages; + +import java.util.Optional; + +/** + * @author Luana Coppio + */ +public class OptionalIntegerArgument extends Argument> { + private final int minValue; + private final int maxValue; + + public OptionalIntegerArgument(String name, String description) { + this(name, description, Integer.MIN_VALUE, Integer.MAX_VALUE); + } + + public OptionalIntegerArgument(String name, String description, int minValue, int maxValue) { + super(name, description); + this.minValue = minValue; + this.maxValue = maxValue; + } + + @Override + public Optional getValue() { + return value; + } + + @Override + public void parse(String input) throws IllegalArgumentException { + if (input == null) { + value = Optional.empty(); + return; + } + try { + int parsedValue = Integer.parseInt(input); + if (parsedValue < getMinValue() || parsedValue > getMaxValue()) { + throw new IllegalArgumentException(getName() + Messages.getString("Gamemaster.cmd.error.integerparse") + getMinValue() + " and " + getMaxValue()); + } + value = Optional.of(parsedValue); + } catch (NumberFormatException e) { + throw new IllegalArgumentException(getName() + " must be an integer."); + } + } + + public int getMinValue() { + return minValue; + } + + public int getMaxValue() { + return maxValue; + } + + @Override + public String getRepr() { + return "[" + getName() + "]"; + } + + @Override + public String getHelp() { + return getDescription() + (minValue == Integer.MIN_VALUE ? "": " Min: " + minValue) + + (maxValue == Integer.MAX_VALUE ? "": " Max: " + maxValue) + ". " + Messages.getString("Gamemaster.cmd.params.optional"); + } +} diff --git a/megamek/src/megamek/server/props/OrbitalBombardment.java b/megamek/src/megamek/server/props/OrbitalBombardment.java index 0bfa383c45f..972011043ac 100644 --- a/megamek/src/megamek/server/props/OrbitalBombardment.java +++ b/megamek/src/megamek/server/props/OrbitalBombardment.java @@ -1,20 +1,15 @@ /* - * Copyright (c) 2024 - The MegaMek Team. All Rights Reserved. + * MegaMek - Copyright (c) 2024 - The MegaMek Team. All Rights Reserved. * - * This file is part of MegaMek. + * This program 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 2 of the License, or (at your option) + * any later version. * - * 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 . + * This program 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. */ package megamek.server.props; @@ -25,13 +20,13 @@ * x and y are board positions, damageFactor is the damage at impact point times 10, and radius is the blast radius of the explosion with * regular/linear damage droppoff. * - * @author Luana Scoppio + * @author Luana Coppio */ public class OrbitalBombardment { private final int x; private final int y; - private final int damageFactor; + private final int damage; private final int radius; private final Coords coords; /** @@ -43,7 +38,7 @@ public class OrbitalBombardment { private OrbitalBombardment(Builder builder) { this.x = builder.x; this.y = builder.y; - this.damageFactor = builder.damageFactor; + this.damage = builder.damage; this.radius = builder.radius; this.coords = new Coords(x, y); } @@ -60,8 +55,8 @@ public int getY() { return y; } - public int getDamageFactor() { - return damageFactor; + public int getDamage() { + return damage; } public int getRadius() { @@ -77,7 +72,7 @@ public int getRadius() { public static class Builder { private int x; private int y; - private int damageFactor = 10; + private int damage = 10; private int radius = 4; public Builder x(int x) { @@ -90,8 +85,8 @@ public Builder y(int y) { return this; } - public Builder damageFactor(int damageFactor) { - this.damageFactor = damageFactor; + public Builder damage(int damage) { + this.damage = damage; return this; } diff --git a/megamek/src/megamek/server/totalwarfare/TWGameManager.java b/megamek/src/megamek/server/totalwarfare/TWGameManager.java index 57c86de9f08..2ac90e804de 100644 --- a/megamek/src/megamek/server/totalwarfare/TWGameManager.java +++ b/megamek/src/megamek/server/totalwarfare/TWGameManager.java @@ -20306,17 +20306,16 @@ private void explosionDamage(Coords position, Vector vDesc, Entity e, in } private void orbitalBombardmentDamage(Coords position, Vector vDesc, Entity e, int damage) { + var distanceFromGroundZero = e.getPosition().distance(position); while (damage > 0) { int cluster = Math.min(5, damage); int table = ToHitData.HIT_NORMAL; int hitSide = ToHitData.SIDE_RANDOM; + if (e instanceof ProtoMek) { table = ToHitData.HIT_SPECIAL_PROTO; - } else if (e instanceof Mek) { - table = ToHitData.HIT_ABOVE; - hitSide = e.sideTable(position); - } else if (e instanceof Tank) { - if (e.isAirborneVTOLorWIGE()) { + } else if ((e instanceof Mek) || (e instanceof Tank)) { + if (distanceFromGroundZero == 0) { table = ToHitData.HIT_ABOVE; } hitSide = e.sideTable(position); @@ -20408,15 +20407,18 @@ public void addScheduledOrbitalBombardment(OrbitalBombardment orbitalBombardment getGame().setOrbitalBombardmentVector(new Vector<>(scheduledOrbitalBombardment)); } + /** + * Draws one "orbital bombardment target" on each hex where it is going to hit. + * @param orbitalBombardment + */ private void drawOrbitalBombardmentOnBoard(OrbitalBombardment orbitalBombardment) { - for (var coord : orbitalBombardment.getCoords().allAtDistanceOrLess(orbitalBombardment.getRadius())) { getGame().getBoard().addSpecialHexDisplay( coord, new SpecialHexDisplay( SpecialHexDisplay.Type.ORBITAL_BOMBARDMENT, getGame().getRoundCount(), - getGame().getPlayersList().get(0), // It doesnt matter which is the player, but I dont want to cause a nullpointer. + getGame().getPlayersList().get(0), // It doesnt the player, I just dont want to cause a nullpointer. "Orbital bombardment incoming, landing on round " + getGame().getRoundCount() + ", fired by an unknown warship in orbit", @@ -20447,13 +20449,21 @@ void resolveScheduledNukes() { * explode any scheduled orbital bombardments */ void resolveScheduledOrbitalBombardments() { + if (scheduledOrbitalBombardment.isEmpty()) { + return; + } + + var r = new Report(1303, Report.PUBLIC); + r.indent(); + r.newlines = 2; + getvPhaseReport().add(r); + scheduledOrbitalBombardment - .forEach(ob -> doOrbitalBombardment(new Coords(ob.getX(), ob.getY()), ob.getDamageFactor(), ob.getRadius())); + .forEach(ob -> doOrbitalBombardment(new Coords(ob.getX(), ob.getY()), ob.getDamage(), ob.getRadius())); scheduledOrbitalBombardment.clear(); getGame().resetOrbitalBombardmentAttacks(); - // All right. We're done. - var r = new Report(1301, Report.PUBLIC); + r = new Report(1301, Report.PUBLIC); r.indent(); r.newlines = 2; getvPhaseReport().add(r); @@ -20480,10 +20490,10 @@ public void doNuclearExplosion(Coords position, int nukeType, Vector vDe /** * do an orbital bombardment * @param position the position that will be hit by the orbital bombardment - * @param damageFactor the factor by which the base damage will be multiplied + * @param damage the damage of the bombardment at target hex * @param radius the radius which the damage will hit */ - public void doOrbitalBombardment(Coords position, int damageFactor, int radius) { + public void doOrbitalBombardment(Coords position, int damage, int radius) { Report r = new Report(1300, Report.PUBLIC); r.indent(); r.add(position.getBoardNum(), true); @@ -20494,9 +20504,8 @@ public void doOrbitalBombardment(Coords position, int damageFactor, int radius) Vector tmpV = new Vector<>(); Vector blastedUnitsVec = new Vector<>(); int range = radius + 1; - int baseDamage = damageFactor * 10; - var degradation = baseDamage / range; - doExplosion(baseDamage, degradation , false, position, true, tmpV, + var degradation = damage / range; + doExplosion(damage, degradation , false, position, true, tmpV, blastedUnitsVec, -1, true); Report.indentAll(tmpV, 2); getvPhaseReport().addAll(tmpV);