diff --git a/MekHQ/docs/help/en/AutoResolve.html b/MekHQ/docs/help/en/AutoResolve.html new file mode 100644 index 0000000000..6334aecc52 --- /dev/null +++ b/MekHQ/docs/help/en/AutoResolve.html @@ -0,0 +1,54 @@ + + + + + Auto Resolve + + +
+

Auto Resolve Behavior Settings

+

Introduction

+

The Auto Resolve feature is a way to let the PrincessBot control your units so she can quickly play out the battles + for you, its pretty straight forward to setup and use if you want to focus on your company management or just dont + want to play every single lengthy battle.

+

How to Use

+

Auto Resolve is available as a new option in the Scenario panel, the button "Auto Resolve" will setup the game scenario + on MegaMek as normal, and then it adds a Princess bot with the name following the format :AI, it is setup + as the player is setup, same starting position, color, camouflage and team, and then all the players units change owner + to it.

+

To make the game faster, you can change configuration to not show the reports between phases, and select the skip + action if no available unit, with those options selected the game will not request you to press Done between those + phases.

+

Configuring the Auto Resolve Behavior

+

The configuration is accessible in the Manage Campaign menu, in the MekHQ toolbar, there is the entry + Auto Resolve Behavior Settings, it will open the Configure Princess Bot window, where you can define the + behavior for the auto resolve preset.

+

By default, every campaign now have an auto-resolve default preset, that is named :AI, you can change the + configuration as you like and select whatever preset you want.

+

Whenever you hit the "OK" button the current configuration being shown overwrites the auto resolve preset + for your company, so if you want to experiment with different behaviors, I suggest that you create new presets and then + just select the one you want before hitting "OK" to close the configuration.

+

Q&A

+

Q: Can I change the configuration during the game?

+

Sure, its a Princess Bot, so all chat commands to change behavior apply

+

Q: Can I change the configuration for a specific scenario?

+

Also yes, you can create many presets, like for example one for a scape scenario, another for a defend scenario, etc. + Just remember to change the selected preset behavior before entering the game with auto resolve. And remember to change + it back later to your "default" preset.

+

Q: Can I change the configuration for a specific unit?

+

No, you can't, you can emulate that by manually creating many bots with different configurations and then assigning + individual units or lances to them, but that is outside the current scope of the Auto Resolve.

+

Q: I deleted my company preset! Is everything lost?

+

You lost the configuration, sure, but MekHQ won't make any fuss about it, if you delete it by mistake inside MegaMek, + once you open the Auto Resolve Behavior Settings again, the default preset will be recreated for you. And if it is + missing before you enter an auto resolve game, it will use the default behavior for the Princess Bot instead.

+

Q: I want to share my preset with my friends, how can I do that?

+

It's just a preset, so you can use the same way you used to share it with your friends before.

+

Q: The preset is written to the campaign save?

+

No, the preset is saved in the MekHQ configuration folder, so it's available for all your campaigns, not just the one + that created it. So... if you create two different campaigns with the same name they would use the same preset. + Also means that if you change the preset in one save file, the preset is the same in your other campaign. Remember, it + is a preset that you are telling MekHQ to use, not a campaign specific configuration.

+
+ + \ No newline at end of file diff --git a/MekHQ/src/mekhq/AtBGameThread.java b/MekHQ/src/mekhq/AtBGameThread.java index 8ac4d68dec..3f4f3ae32d 100644 --- a/MekHQ/src/mekhq/AtBGameThread.java +++ b/MekHQ/src/mekhq/AtBGameThread.java @@ -28,6 +28,7 @@ import megamek.client.generator.RandomCallsignGenerator; import megamek.client.ui.swing.ClientGUI; import megamek.common.*; +import megamek.common.annotations.Nullable; import megamek.common.planetaryconditions.PlanetaryConditions; import megamek.logging.MMLogger; import mekhq.campaign.force.Force; @@ -56,18 +57,29 @@ public class AtBGameThread extends GameThread { private final AtBScenario scenario; private final BehaviorSettings autoResolveBehaviorSettings; + /** + * Constructor for AtBGameThread + * + *

+ * This constructor creates a new AtBGameThread with the given name, password, client, MekHQ application, list of + * units, scenario, and auto resolve behavior settings. The game thread is started by default. + *

+ * + * @param name The name of the player + * @param password The password for the game + * @param c The client + * @param app The MekHQ application + * @param units The list of units to import into the game + * @param scenario The scenario to use for this game + * @param autoResolveBehaviorSettings The behavior settings for the auto resolve bot + */ public AtBGameThread(String name, String password, Client c, MekHQ app, List units, - AtBScenario scenario) { - this(name, password, c, app, units, scenario, null, true); - } - - public AtBGameThread(String name, String password, Client c, MekHQ app, List units, - AtBScenario scenario, BehaviorSettings autoResolveBehaviorSettings) { + AtBScenario scenario, @Nullable BehaviorSettings autoResolveBehaviorSettings) { this(name, password, c, app, units, scenario, autoResolveBehaviorSettings, true); } public AtBGameThread(String name, String password, Client c, MekHQ app, List units, - AtBScenario scenario, BehaviorSettings autoResolveBehaviorSettings, boolean started) { + AtBScenario scenario, @Nullable BehaviorSettings autoResolveBehaviorSettings, boolean started) { super(name, password, c, app, units, scenario, started); this.scenario = Objects.requireNonNull(scenario); this.autoResolveBehaviorSettings = autoResolveBehaviorSettings; @@ -498,12 +510,11 @@ private void setupPlayerBotForAutoResolve(Player player) throws InterruptedExcep botClient.sendPlayerInfo(); Thread.sleep(MekHQ.getMHQOptions().getStartGameBotClientDelay()); - var ent = client.getEntitiesVector().stream() + var playerEntities = client.getEntitiesVector().stream() .filter(entity -> entity.getOwnerId() == player.getId()) .collect(Collectors.toList()); - botClient.sendChangeOwner(ent, botClient.getLocalPlayer().getId()); + botClient.sendChangeOwner(playerEntities, botClient.getLocalPlayer().getId()); Thread.sleep(MekHQ.getMHQOptions().getStartGameBotClientDelay()); - } private PlanetaryConditions getPlanetaryConditions() { diff --git a/MekHQ/src/mekhq/MekHQ.java b/MekHQ/src/mekhq/MekHQ.java index 1c82c20309..ed49457617 100644 --- a/MekHQ/src/mekhq/MekHQ.java +++ b/MekHQ/src/mekhq/MekHQ.java @@ -35,6 +35,7 @@ import megamek.client.ui.swing.gameConnectionDialogs.ConnectDialog; import megamek.client.ui.swing.gameConnectionDialogs.HostDialog; import megamek.client.ui.swing.util.UIUtil; +import megamek.common.annotations.Nullable; import megamek.common.event.*; import megamek.common.net.marshalling.SanityInputFilter; import megamek.logging.MMLogger; @@ -374,11 +375,28 @@ public void joinGame(Scenario scenario, List meks) { gameThread.start(); } + /** + * Start hosting a game. + * This method is used to start hosting a game. It will create a new server and a client and connect to it. + * + * @param scenario The scenario to host + * @param loadSavegame Whether to load a savegame + * @param meks The units you want to use in the scenario + */ public void startHost(Scenario scenario, boolean loadSavegame, List meks) { startHost(scenario, loadSavegame, meks, null); } - public void startHost(Scenario scenario, boolean loadSavegame, List meks, BehaviorSettings autoResolveBehaviorSettings) + /** + * Start hosting a game. + * This method is used to start hosting a game. It will create a new server and a client and connect to it. + * + * @param scenario The scenario to host + * @param loadSavegame Whether to load a savegame + * @param meks The units you want to use in the scenario + * @param autoResolveBehaviorSettings The auto resolve behavior settings to use if running an AtB scenario and auto resolve is wanted + */ + public void startHost(Scenario scenario, boolean loadSavegame, List meks, @Nullable BehaviorSettings autoResolveBehaviorSettings) { HostDialog hostDialog = new HostDialog(campaignGUI.getFrame(), getCampaign().getName()); hostDialog.setVisible(true); diff --git a/MekHQ/src/mekhq/campaign/io/CampaignXmlParser.java b/MekHQ/src/mekhq/campaign/io/CampaignXmlParser.java index 1291e5d5f7..9d98cf8d81 100644 --- a/MekHQ/src/mekhq/campaign/io/CampaignXmlParser.java +++ b/MekHQ/src/mekhq/campaign/io/CampaignXmlParser.java @@ -78,7 +78,8 @@ import java.util.*; import java.util.Map.Entry; -import static mekhq.utilities.MoreObjects.firstNonNull; +import static org.apache.commons.lang3.ObjectUtils.firstNonNull; + public class CampaignXmlParser { private final InputStream is; diff --git a/MekHQ/src/mekhq/gui/dialog/AutoResolveBehaviorSettingsDialog.java b/MekHQ/src/mekhq/gui/dialog/AutoResolveBehaviorSettingsDialog.java index 724b04b351..38cfee7842 100644 --- a/MekHQ/src/mekhq/gui/dialog/AutoResolveBehaviorSettingsDialog.java +++ b/MekHQ/src/mekhq/gui/dialog/AutoResolveBehaviorSettingsDialog.java @@ -1,560 +1,64 @@ package mekhq.gui.dialog; -import megamek.client.bot.princess.BehaviorSettings; import megamek.client.bot.princess.BehaviorSettingsFactory; -import megamek.client.bot.princess.CardinalEdge; import megamek.client.bot.princess.PrincessException; -import megamek.client.ui.Messages; -import megamek.client.ui.baseComponents.MMComboBox; -import megamek.client.ui.dialogs.helpDialogs.PrincessHelpDialog; -import megamek.client.ui.swing.MMToggleButton; -import megamek.client.ui.swing.util.ScalingPopup; -import megamek.client.ui.swing.util.UIUtil; +import megamek.client.ui.dialogs.BotConfigDialog; import megamek.logging.MMLogger; import mekhq.campaign.Campaign; -import mekhq.gui.baseComponents.AbstractMHQDialog; import javax.swing.*; -import javax.swing.border.EmptyBorder; -import javax.swing.border.TitledBorder; -import javax.swing.event.ChangeEvent; -import javax.swing.event.ChangeListener; -import javax.swing.event.ListSelectionEvent; -import javax.swing.event.ListSelectionListener; -import java.awt.*; -import java.awt.event.*; -import java.util.ArrayList; -import java.util.Arrays; -import java.util.List; public class AutoResolveBehaviorSettingsDialog - extends AbstractMHQDialog - implements ActionListener, ListSelectionListener, ChangeListener + extends BotConfigDialog { private final static MMLogger logger = MMLogger.create(AutoResolveBehaviorSettingsDialog.class); - private static final String OK_ACTION = "Ok_Action"; - - private final transient BehaviorSettingsFactory behaviorSettingsFactory = BehaviorSettingsFactory.getInstance(); - private BehaviorSettings autoResolveBehavior; - - private final JLabel nameLabel = new JLabel(Messages.getString("BotConfigDialog.nameLabel")); - private final UIUtil.TipTextField nameField = new UIUtil.TipTextField("", 16); - - private final MMToggleButton forcedWithdrawalCheck = new UIUtil.TipMMToggleButton( - Messages.getString("BotConfigDialog.forcedWithdrawalCheck")); - private final JLabel withdrawEdgeLabel = new JLabel(Messages.getString("BotConfigDialog.retreatEdgeLabel")); - private final MMComboBox withdrawEdgeCombo = new UIUtil.TipCombo<>("EdgeToWithdraw", CardinalEdge.values()); - private final MMToggleButton autoFleeCheck = new UIUtil.TipMMToggleButton(Messages.getString("BotConfigDialog.autoFleeCheck")); - private final JLabel fleeEdgeLabel = new JLabel(Messages.getString("BotConfigDialog.homeEdgeLabel")); - private final MMComboBox fleeEdgeCombo = new UIUtil.TipCombo<>("EdgeToFlee", CardinalEdge.values()); - - private final UIUtil.TipSlider aggressionSlidebar = new UIUtil.TipSlider(SwingConstants.HORIZONTAL, 0, 10, 5); - private final UIUtil.TipSlider fallShameSlidebar = new UIUtil.TipSlider(SwingConstants.HORIZONTAL, 0, 10, 5); - private final UIUtil.TipSlider herdingSlidebar = new UIUtil.TipSlider(SwingConstants.HORIZONTAL, 0, 10, 5); - private final UIUtil.TipSlider selfPreservationSlidebar = new UIUtil.TipSlider(SwingConstants.HORIZONTAL, 0, 10, 5); - private final UIUtil.TipSlider braverySlidebar = new UIUtil.TipSlider(SwingConstants.HORIZONTAL, 0, 10, 5); -// private final UIUtil.TipButton savePreset = new UIUtil.TipButton(Messages.getString("BotConfigDialog.save")); - private final UIUtil.TipButton saveNewPreset = new UIUtil.TipButton(Messages.getString("BotConfigDialog.saveNew")); - - private final JButton princessHelpButton = new JButton(Messages.getString("BotConfigDialog.help")); - - private JPanel presetsPanel; - private final JLabel chooseLabel = new JLabel(Messages.getString("BotConfigDialog.behaviorNameLabel")); - /** - * A copy of the current presets. Modifications will only be saved when - * accepted. - */ - private List presets; - private final AutoResolveBehaviorSettingsDialog.PresetsModel presetsModel = new AutoResolveBehaviorSettingsDialog.PresetsModel(); - private final JList presetsList = new JList<>(presetsModel); - - private final JButton butOK = new JButton(Messages.getString("Okay")); - private final JButton butCancel = new JButton(Messages.getString("Cancel")); + private Campaign campaign; + private final BehaviorSettingsFactory behaviorSettingsFactory = BehaviorSettingsFactory.getInstance(); /** - * Stores the currently chosen preset. Used to detect if the player has changed - * the sliders. + * Creates a new instance of AutoResolveBehaviorSettingsDialog. + *

+ * This dialog is used to configure the auto resolve behavior settings for a campaign. + * It creates a default preset with a predetermined name and sets the behavior settings + * to the campaign's auto resolve behavior settings. + *

+ * @param frame The parent frame. + * @param campaign The campaign to get the auto resolve behavior settings from. */ - private BehaviorSettings chosenPreset; - private Campaign campaign; - - //region Constructors public AutoResolveBehaviorSettingsDialog(final JFrame frame, final Campaign campaign) { - super(frame, "AutoResolveBehaviorSettingsDialog", "AutoResolveBehaviorSettingsDialog.title"); + super(frame, campaign.getName() + ":AI", campaign.getAutoResolveBehaviorSettings(), null); setAlwaysOnTop(true); setCampaign(campaign); - autoResolveBehavior = ( - campaign.getAutoResolveBehaviorSettings() != null ? - campaign.getAutoResolveBehaviorSettings() : new BehaviorSettings()); - updatePresets(); - initialize(); - updateDialogFields(); - } - - private String getAutoResolveBehaviorSettingName() { - return campaign.getName() + ":AI"; } public void setCampaign(final Campaign campaign) { this.campaign = campaign; } - @Override - protected void initialize() { - // Make Enter confirm and close the dialog - final KeyStroke enter = KeyStroke.getKeyStroke(KeyEvent.VK_ENTER, 0); - getRootPane().getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW).put(enter, OK_ACTION); - getRootPane().getInputMap(JComponent.WHEN_FOCUSED).put(enter, OK_ACTION); - getRootPane().getActionMap().put(OK_ACTION, new AbstractAction() { - @Override - public void actionPerformed(ActionEvent evt) { - okAction(); - } - }); - super.initialize(); - } - - @Override - protected Container createCenterPane() { - JPanel result = new JPanel(); - result.setLayout(new BoxLayout(result, BoxLayout.PAGE_AXIS)); - result.add(nameSection()); - result.add(settingSection()); - return result; - } - - /** - * The setting section contains the presets list on the left side and the - * princess settings on the right. - */ - private JPanel settingSection() { -// var princessScroll = new JScrollPane(princessPanel()); -// princessScroll.getVerticalScrollBar().setUnitIncrement(16); -// princessScroll.setBorder(null); -// presetsPanel = presetsPanel(); - - var result = new JPanel(new BorderLayout(0, 0)); - result.setAlignmentX(LEFT_ALIGNMENT); - result.add(princessPanel(), BorderLayout.CENTER); -// result.add(presetsPanel, BorderLayout.LINE_START); - return result; - } - - /** The princess panel contains the individual princess settings. */ - private JPanel princessPanel() { - JPanel result = new JPanel(); - result.setLayout(new BoxLayout(result, BoxLayout.PAGE_AXIS)); - result.add(behaviorSection()); -// result.add(retreatSection()); - result.add(createButtonPanel()); - return result; - } - - private JPanel nameSection() { - JPanel result = new JPanel(); - result.setLayout(new BoxLayout(result, BoxLayout.PAGE_AXIS)); - result.setBorder(BorderFactory.createEmptyBorder(5, 0, 5, 0)); - UIUtil.Content panContent = new UIUtil.Content(); - panContent.setLayout(new BoxLayout(panContent, BoxLayout.PAGE_AXIS)); - result.add(panContent); - - var namePanel = new JPanel(); - nameField.setToolTipText(Messages.getString("BotConfigDialog.namefield.tooltip")); - // When the dialog configures an existing player, the name must not be changed - nameField.setText(getAutoResolveBehaviorSettingName()); - nameField.setEnabled(false); - nameLabel.setLabelFor(nameField); - nameLabel.setDisplayedMnemonic(KeyEvent.VK_N); - namePanel.add(nameLabel); - namePanel.add(nameField); - - panContent.add(namePanel); - return result; - } - - /** The presets panel has a list of behavior presets for Princess. */ - private JPanel presetsPanel() { - var result = new JPanel(); - result.setLayout(new BoxLayout(result, BoxLayout.PAGE_AXIS)); - result.setBorder(new EmptyBorder(0, 10, 0, 20)); - - chooseLabel.setAlignmentX(CENTER_ALIGNMENT); - chooseLabel.setDisplayedMnemonic(KeyEvent.VK_P); - chooseLabel.setLabelFor(presetsList); - var headerPanel = new UIUtil.FixedYPanel(); - headerPanel.add(chooseLabel); - - presetsList.setSelectionMode(ListSelectionModel.SINGLE_SELECTION); - presetsList.addListSelectionListener(this); - presetsList.setCellRenderer(new PresetsRenderer()); - presetsList.addMouseListener(presetsMouseListener); - - result.add(headerPanel); - result.add(Box.createVerticalStrut(10)); - result.add(presetsList); - - return result; - } - - private JPanel behaviorSection() { - JPanel result = new UIUtil.OptionPanel("BotConfigDialog.behaviorSection"); - UIUtil.Content panContent = new UIUtil.Content(); - panContent.setLayout(new BoxLayout(panContent, BoxLayout.PAGE_AXIS)); - result.add(panContent); - - panContent.add(buildSlider(braverySlidebar, Messages.getString("BotConfigDialog.braverySliderMin"), - Messages.getString("BotConfigDialog.braverySliderMax"), - Messages.getString("BotConfigDialog.braveryTooltip"), - Messages.getString("BotConfigDialog.braverySliderTitle"))); - panContent.add(Box.createVerticalStrut(7)); - - panContent.add( - buildSlider(selfPreservationSlidebar, Messages.getString("BotConfigDialog.selfPreservationSliderMin"), - Messages.getString("BotConfigDialog.selfPreservationSliderMax"), - Messages.getString("BotConfigDialog.selfPreservationTooltip"), - Messages.getString("BotConfigDialog.selfPreservationSliderTitle"))); - panContent.add(Box.createVerticalStrut(7)); - - panContent.add(buildSlider(aggressionSlidebar, Messages.getString("BotConfigDialog.aggressionSliderMin"), - Messages.getString("BotConfigDialog.aggressionSliderMax"), - Messages.getString("BotConfigDialog.aggressionTooltip"), - Messages.getString("BotConfigDialog.aggressionSliderTitle"))); - panContent.add(Box.createVerticalStrut(7)); - - panContent.add(buildSlider(herdingSlidebar, Messages.getString("BotConfigDialog.herdingSliderMin"), - Messages.getString("BotConfigDialog.herdingSliderMax"), - Messages.getString("BotConfigDialog.herdingToolTip"), - Messages.getString("BotConfigDialog.herdingSliderTitle"))); - panContent.add(Box.createVerticalStrut(7)); - - panContent.add(buildSlider(fallShameSlidebar, Messages.getString("BotConfigDialog.fallShameSliderMin"), - Messages.getString("BotConfigDialog.fallShameSliderMax"), - Messages.getString("BotConfigDialog.fallShameToolTip"), - Messages.getString("BotConfigDialog.fallShameSliderTitle"))); - - var buttonPanel = new JPanel(new FlowLayout(FlowLayout.RIGHT, 10, 10)); - buttonPanel.setAlignmentX(SwingConstants.CENTER); - result.add(buttonPanel); - -// savePreset.addActionListener(this); -// savePreset.setMnemonic(KeyEvent.VK_S); -// savePreset.setToolTipText(Messages.getString("BotConfigDialog.saveTip")); -// buttonPanel.add(savePreset); -// saveNewPreset.addActionListener(this); -// saveNewPreset.setMnemonic(KeyEvent.VK_A); -// saveNewPreset.setToolTipText(Messages.getString("BotConfigDialog.saveNewTip")); -// buttonPanel.add(saveNewPreset); - - return result; - } - - - private JPanel retreatSection() { - JPanel result = new UIUtil.OptionPanel("BotConfigDialog.retreatSection"); - UIUtil.Content panContent = new UIUtil.Content(); - panContent.setLayout(new BoxLayout(panContent, BoxLayout.PAGE_AXIS)); - result.add(panContent); - - autoFleeCheck.setToolTipText(Messages.getString("BotConfigDialog.autoFleeTooltip")); - autoFleeCheck.addActionListener(this); - autoFleeCheck.setMnemonic(KeyEvent.VK_F); - - fleeEdgeCombo.removeItem(CardinalEdge.NONE); - fleeEdgeCombo.setToolTipText(Messages.getString("BotConfigDialog.homeEdgeTooltip")); - fleeEdgeCombo.setSelectedIndex(0); - fleeEdgeCombo.addActionListener(this); - - forcedWithdrawalCheck.setToolTipText(Messages.getString("BotConfigDialog.forcedWithdrawalTooltip")); - forcedWithdrawalCheck.addActionListener(this); - forcedWithdrawalCheck.setMnemonic(KeyEvent.VK_W); - - withdrawEdgeCombo.removeItem(CardinalEdge.NONE); - withdrawEdgeCombo.setToolTipText(Messages.getString("BotConfigDialog.retreatEdgeTooltip")); - withdrawEdgeCombo.setSelectedIndex(0); - - var firstLine = new JPanel(new FlowLayout(FlowLayout.LEFT)); - var secondLine = new JPanel(new FlowLayout(FlowLayout.LEFT)); - firstLine.add(forcedWithdrawalCheck); - firstLine.add(Box.createHorizontalStrut(20)); - firstLine.add(withdrawEdgeLabel); - firstLine.add(withdrawEdgeCombo); - secondLine.add(autoFleeCheck); - secondLine.add(Box.createHorizontalStrut(20)); - secondLine.add(fleeEdgeLabel); - secondLine.add(fleeEdgeCombo); - panContent.add(firstLine); - panContent.add(Box.createVerticalStrut(5)); - panContent.add(secondLine); - - return result; - } - - protected void updatePresetFields() { - selfPreservationSlidebar.setValue(autoResolveBehavior.getSelfPreservationIndex()); - aggressionSlidebar.setValue(autoResolveBehavior.getHyperAggressionIndex()); - fallShameSlidebar.setValue(autoResolveBehavior.getFallShameIndex()); - herdingSlidebar.setValue(autoResolveBehavior.getHerdMentalityIndex()); - braverySlidebar.setValue(autoResolveBehavior.getBraveryIndex()); - } - - private void updateDialogFields() { - updatePresetFields(); - - forcedWithdrawalCheck.setSelected(autoResolveBehavior.isForcedWithdrawal()); - withdrawEdgeCombo.setSelectedItem(autoResolveBehavior.getRetreatEdge()); - - autoFleeCheck.setSelected(autoResolveBehavior.shouldAutoFlee()); - fleeEdgeCombo.setSelectedItem(autoResolveBehavior.getDestinationEdge()); - - updateEnabledStates(); - } - - /** Updates all necessary enabled states of buttons/dropdowns. */ - private void updateEnabledStates() { - fleeEdgeLabel.setEnabled(autoFleeCheck.isSelected()); - fleeEdgeCombo.setEnabled(autoFleeCheck.isSelected()); - withdrawEdgeLabel.setEnabled(forcedWithdrawalCheck.isSelected()); - withdrawEdgeCombo.setEnabled(forcedWithdrawalCheck.isSelected()); -// savePreset.setEnabled(isChangedPreset()); - } - - /** - * Returns true if a preset is selected and is different from the current slider - * settings. - */ - private boolean isChangedPreset() { - return (chosenPreset != null) - && (chosenPreset.getSelfPreservationIndex() != selfPreservationSlidebar.getValue() - || chosenPreset.getHyperAggressionIndex() != aggressionSlidebar.getValue() - || chosenPreset.getFallShameIndex() != fallShameSlidebar.getValue() - || chosenPreset.getHerdMentalityIndex() != herdingSlidebar.getValue() - || chosenPreset.getBraveryIndex() != braverySlidebar.getValue()); - } - - private JPanel buildSlider(JSlider thisSlider, String minMsgProperty, - String maxMsgProperty, String toolTip, String title) { - TitledBorder border = BorderFactory.createTitledBorder(title); - border.setTitlePosition(TitledBorder.TOP); - border.setTitleJustification(TitledBorder.CENTER); - var result = new UIUtil.TipPanel(); - result.setBorder(border); - result.setLayout(new BoxLayout(result, BoxLayout.PAGE_AXIS)); - result.setToolTipText(toolTip); - thisSlider.setToolTipText(toolTip); - thisSlider.setPaintLabels(false); - thisSlider.setSnapToTicks(true); - thisSlider.addChangeListener(this); - - var panLabels = new JPanel(); - panLabels.setLayout(new BoxLayout(panLabels, BoxLayout.LINE_AXIS)); - panLabels.add(new JLabel(minMsgProperty, SwingConstants.LEFT)); - panLabels.add(Box.createHorizontalGlue()); - panLabels.add(new JLabel(maxMsgProperty, SwingConstants.RIGHT)); - - result.add(panLabels); - result.add(thisSlider); - result.revalidate(); - return result; - } - - protected JPanel createButtonPanel() { - JPanel result = new JPanel(new FlowLayout(FlowLayout.CENTER, 20, 10)); - - butOK.addActionListener((l) -> { - okAction(); - setVisible(false); - }); - butOK.setMnemonic(KeyEvent.VK_K); - result.add(butOK); - - butCancel.addActionListener(this::cancelActionPerformed); - butCancel.setMnemonic(KeyEvent.VK_C); - result.add(butCancel); - - princessHelpButton.addActionListener(this); - princessHelpButton.setMnemonic(KeyEvent.VK_H); - result.add(princessHelpButton); - - return result; - } - - private void showPrincessHelp() { - new PrincessHelpDialog(getFrame()).setVisible(true); - } - - private void okAction() { + private void updateBehaviorSettings() { + var autoResolveBehaviorSettings = getBehaviorSettings(); try { - savePrincessProperties(); + autoResolveBehaviorSettings.setDescription(campaign.getName() + ":AI"); } catch (PrincessException e) { - logger.error("Error saving AutoResolveBehaviorSettings properties", e); - } - } - - @Override - public void actionPerformed(ActionEvent e) { - if (e.getSource() == princessHelpButton) { - showPrincessHelp(); - } - } - - /** Saves the current Behavior to the currently selected Behavior Preset. */ - private void savePreset() { - writePreset(getAutoResolveBehaviorSettingName()); - } - - /** Removes the given Behavior Preset. */ - private void removePreset(String name) { - behaviorSettingsFactory.removeBehavior(name); - behaviorSettingsFactory.saveBehaviorSettings(false); - updatePresets(); - } - - private void savePrincessProperties() throws PrincessException { - BehaviorSettings tempBehavior = new BehaviorSettings(); - tempBehavior.setFallShameIndex(fallShameSlidebar.getValue()); - tempBehavior.setForcedWithdrawal(forcedWithdrawalCheck.isSelected()); - tempBehavior.setAutoFlee(autoFleeCheck.isSelected()); - tempBehavior.setDestinationEdge(fleeEdgeCombo.getSelectedItem()); - tempBehavior.setRetreatEdge(withdrawEdgeCombo.getSelectedItem()); - tempBehavior.setHyperAggressionIndex(aggressionSlidebar.getValue()); - tempBehavior.setSelfPreservationIndex(selfPreservationSlidebar.getValue()); - tempBehavior.setHerdMentalityIndex(herdingSlidebar.getValue()); - tempBehavior.setBraveryIndex(braverySlidebar.getValue()); - tempBehavior.setDescription(getAutoResolveBehaviorSettingName()); - autoResolveBehavior = tempBehavior; - campaign.setAutoResolveBehaviorSettings(tempBehavior); - savePreset(); - } - - private void writePreset(String name) { - BehaviorSettings newBehavior = new BehaviorSettings(); - try { - newBehavior.setDescription(name); - } catch (PrincessException e1) { - return; - } - newBehavior.setFallShameIndex(fallShameSlidebar.getValue()); - newBehavior.setHyperAggressionIndex(aggressionSlidebar.getValue()); - newBehavior.setSelfPreservationIndex(selfPreservationSlidebar.getValue()); - newBehavior.setHerdMentalityIndex(herdingSlidebar.getValue()); - newBehavior.setBraveryIndex(braverySlidebar.getValue()); - behaviorSettingsFactory.addBehavior(newBehavior); - behaviorSettingsFactory.saveBehaviorSettings(false); - } - - @Override - public void valueChanged(ListSelectionEvent event) { - if (event.getValueIsAdjusting()) { + // This should never happen, but if it does, it is not a critical error. + // We set the auto resolve behavior setting, ignore that its description + // could not be set, log the error and continue. + logger.error("Could not set description for auto resolve behavior settings", e); + campaign.setAutoResolveBehaviorSettings(autoResolveBehaviorSettings); return; } - if (event.getSource() == presetsList) { - presetSelected(); - } - } - - /** Shows a popup menu for a behavior preset, allowing to delete it. */ - private transient MouseListener presetsMouseListener = new MouseAdapter() { - - @Override - public void mouseReleased(MouseEvent e) { - int row = presetsList.locationToIndex(e.getPoint()); - if (e.isPopupTrigger() && (row != -1)) { - ScalingPopup popup = new ScalingPopup(); - String behavior = presetsList.getModel().getElementAt(row); - var deleteItem = new JMenuItem("Delete " + behavior); - deleteItem.addActionListener(event -> removePreset(behavior)); - popup.add(deleteItem); - popup.show(e.getComponent(), e.getX(), e.getY()); - } - } - - @Override - public void mouseClicked(MouseEvent evt) { - if (SwingUtilities.isLeftMouseButton(evt) && evt.getClickCount() == 1) { - presetSelected(); - } - } - }; - - /** - * Called when a Preset is selected. This will often be called twice when - * clicking with the mouse (by the listselectionlistener and the mouselistener). - * In this way the list will react when copying a Preset from another bot and - * then clicking the already selected Preset again. And it will also react to - * keyboard navigation. - */ - private void presetSelected() { - if (presetsList.isSelectionEmpty()) { - chosenPreset = null; - } else { - autoResolveBehavior = behaviorSettingsFactory.getBehavior(presetsList.getSelectedValue()); - chosenPreset = behaviorSettingsFactory.getBehavior(presetsList.getSelectedValue()); + behaviorSettingsFactory.addBehavior(autoResolveBehaviorSettings); + behaviorSettingsFactory.saveBehaviorSettings(false); - if (autoResolveBehavior == null) { - autoResolveBehavior = new BehaviorSettings(); - } - updatePresetFields(); - } - updateEnabledStates(); - } - - /** - * Sets up/Updates the displayed preset list (e.g. after adding or deleting a - * preset) - */ - private void updatePresets() { - presets = new ArrayList<>(Arrays.asList(behaviorSettingsFactory.getBehaviorNames())); - ((AutoResolveBehaviorSettingsDialog.PresetsModel) presetsList.getModel()).fireUpdate(); + campaign.setAutoResolveBehaviorSettings(autoResolveBehaviorSettings); } @Override - public void stateChanged(ChangeEvent e) { - updateEnabledStates(); - } - - private class PresetsModel extends DefaultListModel { - - @Override - public int getSize() { - return presets.size(); - } - - @Override - public String getElementAt(int index) { - return presets.get(index); - } - - /** Call when elements of the list change. */ - private void fireUpdate() { - fireContentsChanged(this, 0, getSize() - 1); - } + protected void okAction() { + super.okAction(); + updateBehaviorSettings(); } - /** - * A renderer for the Behavior Presets list. Adapts the font size to the gui - * scaling and - * colors the special list elements (other bot Configurations and original - * Config). - */ - private class PresetsRenderer extends DefaultListCellRenderer { - - @Override - public Component getListCellRendererComponent(JList list, Object value, int index, boolean isSelected, - boolean cellHasFocus) { - Component comp = super.getListCellRendererComponent(list, value, index, isSelected, cellHasFocus); - comp.setFont(UIUtil.getScaledFont()); - String preset = (String) value; - if (preset.startsWith(UIUtil.BOT_MARKER)) { - comp.setForeground(UIUtil.uiLightBlue()); - } - - if (preset.equals(Messages.getString("BotConfigDialog.previousConfig"))) { - comp.setForeground(UIUtil.uiGreen()); - } - - return comp; - } - } } diff --git a/MekHQ/src/mekhq/utilities/MoreObjects.java b/MekHQ/src/mekhq/utilities/MoreObjects.java deleted file mode 100644 index 088b361cad..0000000000 --- a/MekHQ/src/mekhq/utilities/MoreObjects.java +++ /dev/null @@ -1,12 +0,0 @@ -package mekhq.utilities; - -public class MoreObjects { - - private MoreObjects() { - } - - public static O firstNonNull(O first, O second) { - return first != null ? first : second; - } -} -