diff --git a/src/megameklab/com/ui/Aero/tabs/StructureTab.java b/src/megameklab/com/ui/Aero/tabs/StructureTab.java index e47c01d15..75dc95931 100644 --- a/src/megameklab/com/ui/Aero/tabs/StructureTab.java +++ b/src/megameklab/com/ui/Aero/tabs/StructureTab.java @@ -30,34 +30,33 @@ import javax.swing.JPanel; import javax.swing.SwingConstants; +import megamek.common.Aero; import megamek.common.CriticalSlot; import megamek.common.Engine; import megamek.common.Entity; import megamek.common.EquipmentType; import megamek.common.ITechManager; +import megamek.common.LocationFullException; +import megamek.common.Mounted; import megamek.common.SimpleTechLevel; import megamek.common.verifier.TestAero; import megamek.common.verifier.TestEntity; import megameklab.com.ui.EntitySource; -import megameklab.com.ui.Aero.views.ArmorView; import megameklab.com.ui.Aero.views.SummaryView; import megameklab.com.ui.view.AeroFuelView; +import megameklab.com.ui.view.ArmorAllocationView; import megameklab.com.ui.view.BasicInfoView; import megameklab.com.ui.view.FighterChassisView; import megameklab.com.ui.view.HeatSinkView; import megameklab.com.ui.view.MVFArmorView; import megameklab.com.ui.view.MovementView; +import megameklab.com.ui.view.PatchworkArmorView; +import megameklab.com.ui.view.listeners.AeroBuildListener; import megameklab.com.util.ITab; import megameklab.com.util.RefreshListener; import megameklab.com.util.UnitUtil; -public class StructureTab extends ITab implements - BasicInfoView.BasicInfoListener, - FighterChassisView.ChassisListener, - HeatSinkView.HeatSinkListener, - AeroFuelView.FuelListener, - MovementView.MovementListener, - MVFArmorView.ArmorListener { +public class StructureTab extends ITab implements AeroBuildListener { /** * @@ -72,13 +71,13 @@ public class StructureTab extends ITab implements private AeroFuelView panFuel; private HeatSinkView panHeat; private SummaryView panSummary; - private ArmorView armorView; + private ArmorAllocationView panArmorAllocation; + private PatchworkArmorView panPatchwork; RefreshListener refresh = null; public StructureTab(EntitySource eSource) { super(eSource); - armorView = new ArmorView(eSource); setLayout(new BorderLayout()); setUpPanels(); this.add(masterPanel, BorderLayout.CENTER); @@ -93,7 +92,14 @@ private void setUpPanels() { panMovement = new MovementView(panInfo); panFuel = new AeroFuelView(); panHeat = new HeatSinkView(panInfo); + panArmorAllocation = new ArmorAllocationView(panInfo, Entity.ETYPE_AERO); + panPatchwork = new PatchworkArmorView(panInfo); panSummary = new SummaryView(eSource); + if (getAero().hasPatchworkArmor()) { + panArmorAllocation.showPatchwork(true); + } else { + panPatchwork.setVisible(false); + } GridBagConstraints gbc = new GridBagConstraints(); @@ -117,7 +123,8 @@ private void setUpPanels() { midPanel.add(Box.createHorizontalStrut(300)); rightPanel.add(panArmor); - rightPanel.add(armorView); + rightPanel.add(panArmorAllocation); + rightPanel.add(panPatchwork); gbc = new GridBagConstraints(); gbc.gridx = 0; @@ -139,7 +146,8 @@ private void setUpPanels() { panHeat.setBorder(BorderFactory.createTitledBorder("Heat Sinks")); panArmor.setBorder(BorderFactory.createTitledBorder("Armor")); panSummary.setBorder(BorderFactory.createTitledBorder("Summary")); - armorView.setBorder(BorderFactory.createTitledBorder("Armor Allocation")); + panArmorAllocation.setBorder(BorderFactory.createTitledBorder("Armor Allocation")); + panPatchwork.setBorder(BorderFactory.createTitledBorder("Patchwork Armor")); } public ITechManager getTechManager() { @@ -162,12 +170,13 @@ public void refresh() { panFuel.setFromEntity(getAero()); panMovement.setFromEntity(getAero()); panArmor.setFromEntity(getAero()); + panArmorAllocation.setFromEntity(getAero()); + panPatchwork.setFromEntity(getAero()); panHeat.setVisible(!getAero().hasETypeFlag(Entity.ETYPE_CONV_FIGHTER)); setAeroStructuralIntegrity(); - armorView.refresh(); panSummary.refresh(); addAllListeners(); @@ -232,6 +241,8 @@ public void removeAllListeners() { panFuel.removeListener(this); panMovement.removeListener(this); panArmor.removeListener(this); + panArmorAllocation.removeListener(this); + panPatchwork.removeListener(this); } public void addAllListeners() { @@ -241,52 +252,12 @@ public void addAllListeners() { panFuel.addListener(this); panMovement.addListener(this); panArmor.addListener(this); + panArmorAllocation.addListener(this); + panPatchwork.addListener(this); } public void addRefreshedListener(RefreshListener l) { refresh = l; - armorView.addRefreshedListener(l); - } - - private void createArmorMountsAndSetArmorType(int at, int aTechLevel) { - /* TODO: Patchwork armor needs support from ArmorView - if (EquipmentType.T_ARMOR_PATCHWORK == at) { - boolean isMixed = panInfo.isMixedTech(); - List armors = panArmor.getAllArmors(); - List> combos = new ArrayList<>(); - JPanel panel = new JPanel(new GridBagLayout()); - // Start with 1 to skip body - for (int loc = 0; loc < Aero.LOC_WINGS; loc++) { - TechComboBox cbLoc = new TechComboBox<>(eq -> eq.getName()); - cbLoc.showTechBase(isMixed); - armors.forEach(a -> cbLoc.addItem(a)); - EquipmentType locArmor = EquipmentType.get(EquipmentType - .getArmorTypeName(getAero().getArmorType(loc), - TechConstants.isClan(getAero().getArmorTechLevel(loc)))); - cbLoc.setSelectedItem(locArmor); - combos.add(cbLoc); - JLabel label = new JLabel(getAero().getLocationName(loc)); - panel.add(label, GBC.std()); - panel.add(cbLoc, GBC.eol()); - } - JOptionPane.showMessageDialog(this, panel, - "Please choose the armor types", - JOptionPane.QUESTION_MESSAGE); - UnitUtil.removeISorArmorMounts(getAero(), false); - for (int loc = 0; loc < Aero.LOC_WINGS; loc++) { - EquipmentType armor = (EquipmentType)combos.get(loc).getSelectedItem(); - getAero().setArmorTechLevel(armor.getTechLevel(panInfo.getTechYear()), loc); - getAero().setArmorType(EquipmentType.getArmorType(armor), loc); - } - panArmor.removeListener(this); - panArmor.setFromEntity(getAero()); - panArmor.addListener(this); - } else { - * - */ - getAero().setArmorTechLevel(aTechLevel); - getAero().setArmorType(at); - //} } public void setAsCustomization() { @@ -355,7 +326,6 @@ public void updateTechLevel() { if (!getAero().hasPatchworkArmor()) { UnitUtil.removeISorArmorMounts(getAero(), false); } - createArmorMountsAndSetArmorType(getAero().getArmorType(0), getAero().getArmorTechLevel(0)); // If we have a large engine, a drop in tech level may make it unavailable and we will need // to reduce speed to a legal value. if (getAero().getEngine().hasFlag(Engine.LARGE_ENGINE) @@ -385,7 +355,8 @@ public void updateTechLevel() { panHeat.refresh(); panArmor.refresh(); panMovement.refresh(); - armorView.resetArmorPoints(); + panArmorAllocation.setFromEntity(getAero()); + panPatchwork.setFromEntity(getAero()); addAllListeners(); } @@ -405,11 +376,6 @@ public void heatSinksChanged(int index, int count) { refresh.refreshPreview(); } - @Override - public void heatSinksChanged(EquipmentType hsType, int count) { - // Not used by aerospace units - } - @Override public void heatSinkBaseCountChanged(int count) { getAero().getEngine().setBaseChassisHeatSinks(Math.max(0, count)); @@ -418,15 +384,18 @@ public void heatSinkBaseCountChanged(int count) { @Override public void armorTypeChanged(int at, int aTechLevel) { - if (!getAero().hasPatchworkArmor()) { - UnitUtil.removeISorArmorMounts(getAero(), false); - } - createArmorMountsAndSetArmorType(at, aTechLevel); - if (!getAero().hasPatchworkArmor()) { - armorView.resetArmorPoints(); + UnitUtil.removeISorArmorMounts(getAero(), false); + if (at != EquipmentType.T_ARMOR_PATCHWORK) { + getAero().setArmorTechLevel(aTechLevel); + getAero().setArmorType(at); + panArmorAllocation.showPatchwork(false); + panPatchwork.setVisible(false); + } else { + panPatchwork.setFromEntity(getAero()); + panArmorAllocation.showPatchwork(true); + panPatchwork.setVisible(true); } - - armorView.refresh(); + panArmorAllocation.setFromEntity(getAero()); panSummary.refresh(); refresh.refreshStatus(); refresh.refreshBuild(); @@ -436,9 +405,7 @@ public void armorTypeChanged(int at, int aTechLevel) { @Override public void armorTonnageChanged(double tonnage) { getAero().setArmorTonnage(Math.round(tonnage * 2) / 2.0); - armorView.resetArmorPoints(); - - armorView.refresh(); + panArmorAllocation.setFromEntity(getAero()); panSummary.refresh(); refresh.refreshStatus(); refresh.refreshPreview(); @@ -448,12 +415,11 @@ public void armorTonnageChanged(double tonnage) { public void maximizeArmor() { double maxArmor = UnitUtil.getMaximumArmorTonnage(getAero()); getAero().setArmorTonnage(maxArmor); - armorView.resetArmorPoints(); panArmor.removeListener(this); panArmor.setFromEntity(getAero()); panArmor.addListener(this); - armorView.refresh(); + panArmorAllocation.setFromEntity(getAero()); panSummary.refresh(); refresh.refreshStatus(); refresh.refreshPreview(); @@ -471,12 +437,11 @@ public void useRemainingTonnageArmor() { double maxArmor = Math.min(getAero().getArmorWeight() + remainingTonnage, UnitUtil.getMaximumArmorTonnage(getAero())); getAero().setArmorTonnage(maxArmor); - armorView.resetArmorPoints(); panArmor.removeListener(this); panArmor.setFromEntity(getAero()); panArmor.addListener(this); - armorView.refresh(); + panArmorAllocation.setFromEntity(getAero()); panSummary.refresh(); refresh.refreshStatus(); refresh.refreshPreview(); @@ -590,4 +555,100 @@ public void fuelTonnageChanged(double tonnage) { refresh.refreshPreview(); } + @Override + public void armorPointsChanged(int location, int front, int rear) { + getAero().initializeArmor(front, location); + if (panArmor.getArmorType() == EquipmentType.T_ARMOR_PATCHWORK) { + getAero().setArmorTonnage(panArmorAllocation.getTotalArmorWeight(getAero())); + } + panArmorAllocation.setFromEntity(getAero()); + refresh.refreshPreview(); + refresh.refreshSummary(); + refresh.refreshStatus(); + } + + @Override + public void autoAllocateArmor() { + for (int loc = 0; loc < getAero().locations(); loc++) { + getAero().initializeArmor(0, loc); + } + + // divide armor among positions, with more toward the front + int points = UnitUtil.getArmorPoints(getAero(), getAero().getLabArmorTonnage()); + int nose = (int)Math.floor(points * 0.3); + int wing = (int)Math.floor(points * 0.25); + int aft = (int)Math.floor(points * 0.2); + int remainder = points - nose - wing - wing - aft; + + // spread remainder among nose and wings + switch(remainder % 4) { + case 1: + nose++; + break; + case 3: + nose++; + wing++; + break; + case 2: + wing++; + break; + } + getAero().initializeArmor(nose, Aero.LOC_NOSE); + getAero().initializeArmor(wing, Aero.LOC_LWING); + getAero().initializeArmor(wing, Aero.LOC_RWING); + getAero().initializeArmor(aft, Aero.LOC_AFT); + + panArmorAllocation.setFromEntity(getAero()); + refresh.refreshPreview(); + refresh.refreshSummary(); + refresh.refreshStatus(); + + } + + @Override + public void patchworkChanged(int location, EquipmentType armor) { + UnitUtil.resetArmor(getAero(), location); + + //TODO: move this construction data out of the ui + int crits = 0; + switch (EquipmentType.getArmorType(armor)) { + case EquipmentType.T_ARMOR_STEALTH_VEHICLE: + case EquipmentType.T_ARMOR_LIGHT_ALUM: + case EquipmentType.T_ARMOR_ALUM: + case EquipmentType.T_ARMOR_FERRO_ALUM_PROTO: + case EquipmentType.T_ARMOR_FERRO_LAMELLOR: + case EquipmentType.T_ARMOR_REFLECTIVE: + case EquipmentType.T_ARMOR_REACTIVE: + crits = 1; + break; + case EquipmentType.T_ARMOR_HEAVY_ALUM: + crits = 2; + break; + } + if (getAero().getEmptyCriticals(location) < crits) { + JOptionPane .showMessageDialog( + null, armor.getName() + + " does not fit in location " + + getAero().getLocationName(location) + + ". Resetting to Standard Armor in this location.", + "Error", + JOptionPane.INFORMATION_MESSAGE); + } else { + getAero().setArmorType(EquipmentType.getArmorType(armor), location); + getAero().setArmorTechLevel(armor.getTechLevel(getTechManager().getGameYear(), armor.isClan())); + for (; crits > 0; crits--) { + try { + getAero().addEquipment( new Mounted(getAero(), armor), location, false); + } catch (LocationFullException ex) { + } + } + } + panArmor.refresh(); + panArmorAllocation.setFromEntity(getAero()); + refresh.refreshBuild(); + refresh.refreshPreview(); + refresh.refreshSummary(); + refresh.refreshStatus(); + } + } diff --git a/src/megameklab/com/ui/Aero/views/ArmorView.java b/src/megameklab/com/ui/Aero/views/ArmorView.java deleted file mode 100644 index bc27caa41..000000000 --- a/src/megameklab/com/ui/Aero/views/ArmorView.java +++ /dev/null @@ -1,474 +0,0 @@ -/* - * MegaMekLab - Copyright (C) 2008 - * - * Original author - jtighe (torren@users.sourceforge.net) - * - * 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 megameklab.com.ui.Aero.views; - -import java.awt.Color; -import java.awt.Dimension; -import java.awt.GridBagConstraints; -import java.awt.GridBagLayout; -import java.awt.GridLayout; -import java.awt.Insets; -import java.awt.event.ActionEvent; -import java.awt.event.ActionListener; -import java.util.ArrayList; -import java.util.List; -import java.util.Vector; - -import javax.swing.BorderFactory; -import javax.swing.Box; -import javax.swing.BoxLayout; -import javax.swing.JButton; -import javax.swing.JLabel; -import javax.swing.JPanel; -import javax.swing.JSpinner; -import javax.swing.JTextField; -import javax.swing.SpinnerNumberModel; -import javax.swing.SwingConstants; -import javax.swing.border.TitledBorder; -import javax.swing.event.ChangeEvent; -import javax.swing.event.ChangeListener; - -import megamek.common.Aero; -import megamek.common.EquipmentType; -import megamek.common.verifier.TestAero; -import megameklab.com.ui.EntitySource; -import megameklab.com.util.IView; -import megameklab.com.util.RefreshListener; - -public class ArmorView extends IView implements ChangeListener, ActionListener { - - /** - * - */ - private static final long serialVersionUID = 799195356642563937L; - - private JPanel mainPanel = new JPanel(); - - private JPanel nosePanel = new JPanel(); - private JPanel lWingPanel = new JPanel(); - private JPanel rWingPanel = new JPanel(); - private JPanel aftPanel = new JPanel(); - - - public SpinnerNumberModel noseArmorModel = new SpinnerNumberModel(); - public SpinnerNumberModel lwArmorModel = new SpinnerNumberModel(); - public SpinnerNumberModel rwArmorModel = new SpinnerNumberModel(); - public SpinnerNumberModel aftArmorModel = new SpinnerNumberModel(); - - private JSpinner noseArmorField = new JSpinner(noseArmorModel); - private JSpinner lwArmorField = new JSpinner(lwArmorModel); - private JSpinner rwArmorField = new JSpinner(rwArmorModel); - private JSpinner aftArmorField = new JSpinner(aftArmorModel); - - private List armorFieldList = new ArrayList(); - - private JLabel noseArmorMaxLabel = new JLabel("", SwingConstants.CENTER); - private JLabel lwArmorMaxLabel = new JLabel("", SwingConstants.CENTER); - private JLabel rwArmorMaxLabel = new JLabel("", SwingConstants.CENTER); - private JLabel aftArmorMaxLabel = new JLabel("", SwingConstants.CENTER); - - private List armorMaxLabelList = new ArrayList(); - - private JLabel lblAllocatedArmor = new JLabel("Allocated Armor Points:"); - private JTextField valueAllocatedArmor = new JTextField(); - private JLabel lblUnallocatedArmor = new JLabel("Unallocated Armor Points:"); - private JTextField valueUnallocatedArmor = new JTextField(); - private JLabel lblCurrentArmor = new JLabel("Total Armor Points:"); - private JTextField valueCurrentArmor = new JTextField(); - private JLabel lblMaxArmor = new JLabel("Maximum Possible Armor Points:"); - private JTextField valueMaxArmor = new JTextField(); - private JLabel lblWastedArmor = new JLabel("Wasted Armor Points:"); - private JTextField valueWastedArmor = new JTextField(); - - private int armorPoints; - private int wastedArmorPoints; - - private JButton allocateArmorButton = new JButton("Auto-Allocate Armor"); - - private RefreshListener refresh; - - public ArmorView(EntitySource eSource) { - super(eSource); - - setLayout(new GridLayout(1, 1)); - - mainPanel.setLayout(new GridBagLayout()); - GridBagConstraints gbc; - - nosePanel.setLayout(new BoxLayout(nosePanel, BoxLayout.Y_AXIS)); - rWingPanel.setLayout(new BoxLayout(rWingPanel, BoxLayout.Y_AXIS)); - lWingPanel.setLayout(new BoxLayout(lWingPanel, BoxLayout.Y_AXIS)); - aftPanel.setLayout(new BoxLayout(aftPanel, BoxLayout.Y_AXIS)); - - gbc = new GridBagConstraints(); - gbc.gridx = 1; - gbc.gridy = 0; - mainPanel.add(nosePanel, gbc); - gbc.gridx = 0; - gbc.gridy = 1; - gbc.gridheight = 2; - mainPanel.add(lWingPanel, gbc); - gbc.gridx = 1; - mainPanel.add(Box.createHorizontalStrut(nosePanel.getWidth()), gbc); - gbc.gridx = 2; - mainPanel.add(rWingPanel, gbc); - gbc.gridx = 1; - gbc.gridy = 3; - gbc.gridheight = 1; - mainPanel.add(aftPanel, gbc); - - noseArmorField.setName(Integer.toString(Aero.LOC_NOSE)); - rwArmorField.setName(Integer.toString(Aero.LOC_RWING)); - lwArmorField.setName(Integer.toString(Aero.LOC_LWING)); - aftArmorField.setName(Integer.toString(Aero.LOC_AFT)); - - armorFieldList.add(noseArmorField); - armorFieldList.add(rwArmorField); - armorFieldList.add(lwArmorField); - armorFieldList.add(aftArmorField); - - - Dimension size = new Dimension(40, 25); - for (JSpinner spinner : armorFieldList) { - spinner.setToolTipText("Armor"); - // you don't set the size of the jspinner, but rather its internal - // textfield - ((JSpinner.DefaultEditor) spinner.getEditor()).setSize(size); - ((JSpinner.DefaultEditor) spinner.getEditor()).setMaximumSize(size); - ((JSpinner.DefaultEditor) spinner.getEditor()) - .setPreferredSize(size); - ((JSpinner.DefaultEditor) spinner.getEditor()).setMinimumSize(size); - } - - armorMaxLabelList.add(noseArmorMaxLabel); - armorMaxLabelList.add(lwArmorMaxLabel); - armorMaxLabelList.add(rwArmorMaxLabel); - armorMaxLabelList.add(aftArmorMaxLabel); - - Dimension labelSize = new Dimension(80, 20); - for (JLabel label : armorMaxLabelList) { - label.setSize(labelSize); - label.setMaximumSize(labelSize); - label.setPreferredSize(labelSize); - label.setMinimumSize(labelSize); - } - - addAllListeners(); - - JPanel topPanel; - - synchronized (getAero()) { - for (int location = 0; location < getAero().locations(); location++) { - - switch (location) { - case Aero.LOC_NOSE: - topPanel = new JPanel(new GridLayout(2, 0)); - topPanel.add(noseArmorField); - topPanel.add(noseArmorMaxLabel); - nosePanel.add(topPanel); - nosePanel.setBorder(BorderFactory.createTitledBorder( - null, getAero().getLocationAbbr(location), - TitledBorder.TOP, - TitledBorder.DEFAULT_POSITION)); - break; - case Aero.LOC_LWING: - topPanel = new JPanel(new GridLayout(2, 0)); - topPanel.add(lwArmorField); - topPanel.add(lwArmorMaxLabel); - lWingPanel.add(topPanel); - lWingPanel.setBorder(BorderFactory.createTitledBorder( - null, getAero().getLocationAbbr(location), - TitledBorder.TOP, - TitledBorder.DEFAULT_POSITION)); - break; - case Aero.LOC_RWING: - topPanel = new JPanel(new GridLayout(2, 0)); - topPanel.add(rwArmorField); - topPanel.add(rwArmorMaxLabel); - rWingPanel.add(topPanel); - rWingPanel.setBorder(BorderFactory.createTitledBorder( - null, getAero().getLocationAbbr(location), - TitledBorder.TOP, - TitledBorder.DEFAULT_POSITION)); - break; - case Aero.LOC_AFT: - topPanel = new JPanel(new GridLayout(2, 0)); - topPanel.add(aftArmorField); - topPanel.add(aftArmorMaxLabel); - aftPanel.add(topPanel); - aftPanel.setBorder(BorderFactory.createTitledBorder( - null, getAero().getLocationAbbr(location), - TitledBorder.TOP, - TitledBorder.DEFAULT_POSITION)); - break; - } - } - } - - JPanel totalArmorPanel = new JPanel(); - - Vector valueFields = new Vector(); - valueFields.add(valueUnallocatedArmor); - valueFields.add(valueAllocatedArmor); - valueFields.add(valueCurrentArmor); - valueFields.add(valueMaxArmor); - valueFields.add(valueWastedArmor); - - Dimension valueSize = new Dimension(45, 20); - for (JTextField field : valueFields) { - field.setEditable(false); - field.setSize(valueSize); - field.setPreferredSize(valueSize); - field.setMinimumSize(valueSize); - field.setMaximumSize(valueSize); - field.setHorizontalAlignment(SwingConstants.RIGHT); - } - - totalArmorPanel.setLayout(new GridBagLayout()); - gbc = new GridBagConstraints(); - gbc.gridx = 0; - gbc.gridy = 0; - gbc.insets = new Insets(2, 2, 2, 2); - gbc.anchor = GridBagConstraints.WEST; - totalArmorPanel.add(lblUnallocatedArmor, gbc); - gbc.gridx = 1; - totalArmorPanel.add(valueUnallocatedArmor, gbc); - gbc.gridx = 0; - gbc.gridy = 1; - totalArmorPanel.add(lblAllocatedArmor, gbc); - gbc.gridx = 1; - totalArmorPanel.add(valueAllocatedArmor, gbc); - gbc.gridx = 0; - gbc.gridy = 2; - totalArmorPanel.add(lblCurrentArmor, gbc); - gbc.gridx = 1; - totalArmorPanel.add(valueCurrentArmor, gbc); - gbc.gridx = 0; - gbc.gridy = 3; - totalArmorPanel.add(lblMaxArmor, gbc); - gbc.gridx = 1; - totalArmorPanel.add(valueMaxArmor, gbc); - gbc.gridx = 0; - gbc.gridy = 4; - totalArmorPanel.add(lblWastedArmor, gbc); - gbc.gridx = 1; - totalArmorPanel.add(valueWastedArmor, gbc); - gbc.gridx = 0; - gbc.gridy = 5; - gbc.gridwidth = 2; - gbc.anchor = GridBagConstraints.CENTER; - totalArmorPanel.add(allocateArmorButton, gbc); - - gbc = new GridBagConstraints(); - gbc.gridx = 0; - gbc.gridy = 4; - gbc.gridwidth = 5; - gbc.fill = GridBagConstraints.NONE; - gbc.anchor = GridBagConstraints.CENTER; - mainPanel.add(totalArmorPanel, gbc); - this.add(mainPanel); - - resetArmorPoints(); - } - - private void addAllListeners() { - allocateArmorButton.addActionListener(this); - for (JSpinner spinner : armorFieldList) { - spinner.addChangeListener(this); - } - } - - private void removeAllListeners() { - allocateArmorButton.removeActionListener(this); - for (JSpinner spinner : armorFieldList) { - spinner.removeChangeListener(this); - } - } - - public void refresh() { - removeAllListeners(); - for (int location = 0; location < getAero().locations(); location++) { - - int maxArmor = TestAero.maxArmorPoints(getAero(), getAero().getWeight()); - switch (location) { - case Aero.LOC_NOSE: - noseArmorModel.setValue( - Math.min(maxArmor, getAero().getArmor(location))); - if (isFullyAllocated()) { - noseArmorModel.setMaximum( - (Integer) noseArmorModel.getValue()); - } else { - noseArmorModel.setMaximum(maxArmor); - } - noseArmorModel.setStepSize(1); - noseArmorModel.setMinimum(0); - noseArmorMaxLabel.setText("max: " + maxArmor); - break; - case Aero.LOC_LWING: - lwArmorModel.setValue( - Math.min(maxArmor, getAero().getArmor(location))); - if (isFullyAllocated()) { - lwArmorModel.setMaximum( - (Integer) lwArmorModel.getValue()); - } else { - lwArmorModel.setMaximum(maxArmor); - } - lwArmorModel.setStepSize(1); - lwArmorModel.setMinimum(0); - lwArmorMaxLabel.setText("max: " + maxArmor); - break; - case Aero.LOC_RWING: - rwArmorModel.setValue( - Math.min(maxArmor, getAero().getArmor(location))); - if (isFullyAllocated()) { - rwArmorModel.setMaximum( - (Integer) rwArmorModel.getValue()); - } else { - rwArmorModel.setMaximum(maxArmor); - } - rwArmorModel.setStepSize(1); - rwArmorModel.setMinimum(0); - rwArmorMaxLabel.setText("max: " + maxArmor); - break; - case Aero.LOC_AFT: - aftArmorModel.setValue( - Math.min(maxArmor, getAero().getArmor(location))); - if (isFullyAllocated()) { - aftArmorModel.setMaximum( - (Integer) aftArmorModel.getValue()); - } else { - aftArmorModel.setMaximum(maxArmor); - } - aftArmorModel.setStepSize(1); - aftArmorModel.setMinimum(0); - aftArmorMaxLabel.setText("max: " + maxArmor); - break; - } - } - - - valueAllocatedArmor.setText(Integer.toString(getAero().getTotalOArmor())); - valueUnallocatedArmor.setText(Integer.toString(armorPoints - - getAero().getTotalOArmor())); - if (armorPoints != getAero().getTotalOArmor()) { - valueUnallocatedArmor.setForeground(Color.RED); - lblUnallocatedArmor.setForeground(Color.RED); - } else { - valueUnallocatedArmor.setForeground(Color.BLACK); - lblUnallocatedArmor.setForeground(Color.BLACK); - } - valueCurrentArmor.setText(Integer.toString(armorPoints)); - valueMaxArmor.setText("" + TestAero.maxArmorPoints( - getAero(), getAero().getWeight())); - valueWastedArmor.setText(Integer.toString(wastedArmorPoints)); - - addAllListeners(); - } - - public void addRefreshedListener(RefreshListener l) { - refresh = l; - } - - public void allocateArmor() { - double pointsToAllocate = armorPoints; - double totalArmor = TestAero.maxArmorPoints( - getAero(), getAero().getWeight()); - if (pointsToAllocate > totalArmor) { - pointsToAllocate = totalArmor; - } - double percent = pointsToAllocate / totalArmor; - // put 5 times the percentage of total possible armor into the head - for (int location = 0; location < getAero().locations(); location++) { - double IS = (getAero().getInternal(location) * 2); - double allocate = Math.min(IS * percent, pointsToAllocate); - getAero().initializeArmor((int) allocate, location); - pointsToAllocate -= (int) allocate; - } - allocateLeftoverPoints(pointsToAllocate); - - if (refresh != null) { - refresh.refreshStatus(); - } - } - - /** - * allocate any leftover points one-by-one - * - * @param points - * the amount of points left over - */ - private void allocateLeftoverPoints(double points) { - int [] locs = - {Aero.LOC_NOSE, Aero.LOC_AFT, Aero.LOC_LWING, Aero.LOC_RWING}; - - int locIdx = 0; - while (points > 0){ - int armor = getAero().getArmor(locs[locIdx]) + 1; - getAero().initializeArmor(armor, locs[locIdx]); - points--; - locIdx = (locIdx + 1) % locs.length; - } - } - - public void stateChanged(ChangeEvent e) { - removeAllListeners(); - JSpinner field = (JSpinner) e.getSource(); - int location = Integer.parseInt(field.getName()); - int value = (Integer) field.getModel().getValue(); - getAero().initializeArmor(value, location); - if (getAero().hasPatchworkArmor()) { - setArmorPoints(getMech().getTotalArmor()); - } - if (refresh != null) { - addAllListeners(); - refresh.refreshStructure(); - removeAllListeners(); - refresh.refreshStatus(); - } - addAllListeners(); - } - - public void setArmorPoints(int points) { - int maxArmor = TestAero.maxArmorPoints(getAero(), getAero().getWeight()); - wastedArmorPoints = Math.max(points - maxArmor, 0); - armorPoints = Math.min(maxArmor, points); - } - - private boolean isFullyAllocated() { - if (!getAero().hasPatchworkArmor()) { - return armorPoints == getAero().getTotalOArmor(); - } - return false; - } - - @Override - public void actionPerformed(ActionEvent e) { - removeAllListeners(); - if (e.getSource().equals(allocateArmorButton)) { - allocateArmor(); - } - addAllListeners(); - refresh.refreshAll(); - } - - public void resetArmorPoints() { - double armorPerTon = 16.0 * EquipmentType.getArmorPointMultiplier( - getAero().getArmorType(0), getAero().getArmorTechLevel(0)); - setArmorPoints((int) Math - .floor(getAero().getLabArmorTonnage() * armorPerTon)); - } -} \ No newline at end of file diff --git a/src/megameklab/com/ui/BattleArmor/tabs/StructureTab.java b/src/megameklab/com/ui/BattleArmor/tabs/StructureTab.java index 1fd6e6954..46e11165c 100644 --- a/src/megameklab/com/ui/BattleArmor/tabs/StructureTab.java +++ b/src/megameklab/com/ui/BattleArmor/tabs/StructureTab.java @@ -53,16 +53,12 @@ import megameklab.com.ui.view.BAProtoArmorView; import megameklab.com.ui.view.BasicInfoView; import megameklab.com.ui.view.MovementView; +import megameklab.com.ui.view.listeners.BABuildListener; import megameklab.com.util.ITab; import megameklab.com.util.RefreshListener; import megameklab.com.util.UnitUtil; -public class StructureTab extends ITab implements ActionListener, - BasicInfoView.BasicInfoListener, - BAChassisView.ChassisListener, - MovementView.MovementListener, - BAProtoArmorView.ArmorListener, - BAEnhancementView.EnhancementListener { +public class StructureTab extends ITab implements ActionListener, BABuildListener { /** * diff --git a/src/megameklab/com/ui/Infantry/tabs/StructureTab.java b/src/megameklab/com/ui/Infantry/tabs/StructureTab.java index 7a6c027cb..9e2b4065a 100644 --- a/src/megameklab/com/ui/Infantry/tabs/StructureTab.java +++ b/src/megameklab/com/ui/Infantry/tabs/StructureTab.java @@ -54,15 +54,12 @@ import megameklab.com.ui.view.BasicInfoView; import megameklab.com.ui.view.InfantryWeaponView; import megameklab.com.ui.view.PlatoonTypeView; +import megameklab.com.ui.view.listeners.InfantryBuildListener; import megameklab.com.util.ITab; import megameklab.com.util.RefreshListener; import megameklab.com.util.UnitUtil; -public class StructureTab extends ITab implements - BasicInfoView.BasicInfoListener, - PlatoonTypeView.PlatoonListener, - InfantryWeaponView.WeaponListener, - SpecializationView.SpecializationListener { +public class StructureTab extends ITab implements InfantryBuildListener { /** * @@ -462,4 +459,20 @@ public void antiMekChanged(final boolean antiMek) { getInfantry().setAntiMekSkill(antiMek); refresh.refreshStatus(); } + + @Override + public void walkChanged(int walkMP) { + // not used by conventional infantry + } + + @Override + public void jumpChanged(int jumpMP, EquipmentType jumpJet) { + // not used by conventional infantry + } + + @Override + public void jumpTypeChanged(EquipmentType jumpJet) { + // not used by conventional infantry + } + } \ No newline at end of file diff --git a/src/megameklab/com/ui/Infantry/views/SpecializationView.java b/src/megameklab/com/ui/Infantry/views/SpecializationView.java index 4992663d7..c9bd84576 100644 --- a/src/megameklab/com/ui/Infantry/views/SpecializationView.java +++ b/src/megameklab/com/ui/Infantry/views/SpecializationView.java @@ -37,6 +37,7 @@ import megamek.common.TechAdvancement; import megamek.common.verifier.TestInfantry; import megameklab.com.ui.EntitySource; +import megameklab.com.ui.view.listeners.InfantryBuildListener; import megameklab.com.util.IView; import megameklab.com.util.RefreshListener; import megameklab.com.util.UnitUtil; @@ -52,14 +53,11 @@ public class SpecializationView extends IView implements TableModelListener { private static final long serialVersionUID = -5851020780074510576L; - public interface SpecializationListener { - void specializationsChanged(); - } - private List listeners = new CopyOnWriteArrayList<>(); - public void addListener(SpecializationListener l) { + private List listeners = new CopyOnWriteArrayList<>(); + public void addListener(InfantryBuildListener l) { listeners.add(l); } - public void removeListener(SpecializationListener l) { + public void removeListener(InfantryBuildListener l) { listeners.remove(l); } @@ -124,7 +122,7 @@ public boolean include(Entry e @Override public void tableChanged(TableModelEvent e) { - listeners.forEach(SpecializationListener::specializationsChanged); + listeners.forEach(InfantryBuildListener::specializationsChanged); } private class SpecializationModel extends AbstractTableModel { diff --git a/src/megameklab/com/ui/Mek/tabs/StructureTab.java b/src/megameklab/com/ui/Mek/tabs/StructureTab.java index 6889461cf..30b78c4c6 100644 --- a/src/megameklab/com/ui/Mek/tabs/StructureTab.java +++ b/src/megameklab/com/ui/Mek/tabs/StructureTab.java @@ -20,7 +20,6 @@ import java.awt.Dimension; import java.awt.GridBagConstraints; import java.awt.GridBagLayout; -import java.util.ArrayList; import java.util.List; import java.util.Optional; import java.util.stream.Collectors; @@ -34,7 +33,6 @@ import javax.swing.JPanel; import javax.swing.SwingConstants; -import megamek.client.ui.GBC; import megamek.common.CriticalSlot; import megamek.common.Engine; import megamek.common.Entity; @@ -52,41 +50,39 @@ import megamek.common.loaders.EntityLoadingException; import megamek.common.verifier.TestEntity; import megameklab.com.ui.EntitySource; -import megameklab.com.ui.Mek.views.ArmorView; import megameklab.com.ui.Mek.views.SummaryView; -import megameklab.com.ui.util.TechComboBox; +import megameklab.com.ui.view.ArmorAllocationView; import megameklab.com.ui.view.BasicInfoView; import megameklab.com.ui.view.HeatSinkView; import megameklab.com.ui.view.MVFArmorView; import megameklab.com.ui.view.MekChassisView; import megameklab.com.ui.view.MovementView; +import megameklab.com.ui.view.PatchworkArmorView; +import megameklab.com.ui.view.listeners.MekBuildListener; import megameklab.com.util.ITab; import megameklab.com.util.RefreshListener; import megameklab.com.util.UnitUtil; -public class StructureTab extends ITab implements BasicInfoView.BasicInfoListener, - MekChassisView.MekChassisListener, HeatSinkView.HeatSinkListener, MVFArmorView.ArmorListener, - MovementView.MovementListener { +public class StructureTab extends ITab implements MekBuildListener { /** * */ private static final long serialVersionUID = -6756011847500605874L; - BasicInfoView panBasicInfo; - MekChassisView panChassis; - MVFArmorView panArmor; - MovementView panMovement; - HeatSinkView panHeat; - SummaryView panSummary; - - private ArmorView armor; + private BasicInfoView panBasicInfo; + private MekChassisView panChassis; + private MVFArmorView panArmor; + private MovementView panMovement; + private HeatSinkView panHeat; + private SummaryView panSummary; + private ArmorAllocationView panArmorAllocation; + private PatchworkArmorView panPatchwork; RefreshListener refresh = null; JPanel masterPanel; public StructureTab(EntitySource eSource) { super(eSource); - armor = new ArmorView(eSource); setLayout(new BorderLayout()); setUpPanels(); this.add(masterPanel, BorderLayout.CENTER); @@ -100,7 +96,14 @@ private void setUpPanels() { panArmor = new MVFArmorView(panBasicInfo); panMovement = new MovementView(panBasicInfo); panHeat = new HeatSinkView(panBasicInfo); + panArmorAllocation = new ArmorAllocationView(panBasicInfo, Entity.ETYPE_MECH); + panPatchwork = new PatchworkArmorView(panBasicInfo); panSummary = new SummaryView(eSource); + if (getMech().hasPatchworkArmor()) { + panArmorAllocation.showPatchwork(true); + } else { + panPatchwork.setVisible(false); + } GridBagConstraints gbc; @@ -109,10 +112,14 @@ private void setUpPanels() { panArmor.setFromEntity(getMech()); panMovement.setFromEntity(getMech()); panHeat.setFromMech(getMech()); + panArmorAllocation.setFromEntity(getMech()); + panPatchwork.setFromEntity(getMech()); JPanel leftPanel = new JPanel(); + JPanel centerPanel = new JPanel(); JPanel rightPanel = new JPanel(); leftPanel.setLayout(new BoxLayout(leftPanel, BoxLayout.Y_AXIS)); + centerPanel.setLayout(new BoxLayout(centerPanel, BoxLayout.Y_AXIS)); rightPanel.setLayout(new BoxLayout(rightPanel, BoxLayout.Y_AXIS)); leftPanel.add(panBasicInfo); @@ -121,11 +128,15 @@ private void setUpPanels() { leftPanel.add(Box.createVerticalStrut(11)); leftPanel.add(panHeat); leftPanel.add(Box.createGlue()); - - rightPanel.add(panArmor); - rightPanel.add(panMovement); - rightPanel.add(panSummary); - leftPanel.add(Box.createVerticalGlue()); + + centerPanel.add(panArmor); + centerPanel.add(panMovement); + centerPanel.add(panSummary); + centerPanel.add(Box.createVerticalGlue()); + + rightPanel.add(panArmorAllocation); + rightPanel.add(panPatchwork); + rightPanel.add(Box.createVerticalGlue()); gbc = new GridBagConstraints(); gbc.gridx = 0; @@ -136,9 +147,9 @@ private void setUpPanels() { gbc.anchor = GridBagConstraints.NORTHWEST; masterPanel.add(leftPanel, gbc); gbc.gridx = 1; - masterPanel.add(rightPanel, gbc); + masterPanel.add(centerPanel, gbc); gbc.gridx = 2; - masterPanel.add(armor, gbc); + masterPanel.add(rightPanel, gbc); panBasicInfo.setBorder(BorderFactory.createTitledBorder("Basic Information")); panChassis.setBorder(BorderFactory.createTitledBorder("Chassis")); @@ -146,7 +157,8 @@ private void setUpPanels() { panHeat.setBorder(BorderFactory.createTitledBorder("Heat Sinks")); panArmor.setBorder(BorderFactory.createTitledBorder("Armor")); panSummary.setBorder(BorderFactory.createTitledBorder("Summary")); - armor.setBorder(BorderFactory.createTitledBorder("Armor Allocation")); + panArmorAllocation.setBorder(BorderFactory.createTitledBorder("Armor Allocation")); + panPatchwork.setBorder(BorderFactory.createTitledBorder("Patchwork Armor")); } @@ -157,13 +169,14 @@ public void refresh() { panArmor.setFromEntity(getMech()); panHeat.setFromMech(getMech()); panMovement.setFromEntity(getMech()); + panArmorAllocation.setFromEntity(getMech()); + panPatchwork.setFromEntity(getMech()); - armor.refresh(); panSummary.refresh(); addAllListeners(); } - + public JLabel createLabel(String text, Dimension maxSize) { JLabel label = new JLabel(text, SwingConstants.RIGHT); @@ -177,7 +190,7 @@ public void setFieldSize(JComponent box, Dimension maxSize) { box.setMaximumSize(maxSize); box.setMinimumSize(maxSize); } - + public ITechManager getTechManager() { return panBasicInfo; } @@ -193,7 +206,7 @@ private void resetSystemCrits() { getMech().clearCockpitCrits(); getMech().clearGyroCrits(); getMech().clearEngineCrits(); - + int[] ctEngine = getMech().getEngine().getCenterTorsoCriticalSlots(getMech().getGyroType()); int lastEngine = ctEngine[ctEngine.length - 1]; for (int slot = 0; slot <= lastEngine; slot++) { @@ -205,22 +218,22 @@ private void resetSystemCrits() { } getMech().addEngineCrits(); switch (getMech().getGyroType()) { - case Mech.GYRO_COMPACT: - getMech().addCompactGyro(); - break; - case Mech.GYRO_HEAVY_DUTY: - getMech().addHeavyDutyGyro(); - break; - case Mech.GYRO_XL: - getMech().addXLGyro(); - break; - case Mech.GYRO_NONE: - UnitUtil.compactCriticals(getMech(), Mech.LOC_CT); - break; - default: - getMech().addGyro(); + case Mech.GYRO_COMPACT: + getMech().addCompactGyro(); + break; + case Mech.GYRO_HEAVY_DUTY: + getMech().addHeavyDutyGyro(); + break; + case Mech.GYRO_XL: + getMech().addXLGyro(); + break; + case Mech.GYRO_NONE: + UnitUtil.compactCriticals(getMech(), Mech.LOC_CT); + break; + default: + getMech().addGyro(); } - + switch (getMech().getCockpitType()) { case Mech.COCKPIT_COMMAND_CONSOLE: clearCritsForCockpit(false, true); @@ -289,7 +302,7 @@ && getMech().getCritical(Mech.LOC_RT, i).getType() == CriticalSlot.TYPE_EQUIPMEN } refresh.refreshBuild(); } - + /** * Removes equipment placed in head locations that are needed for a cockpit. For most cockpit * types, this is all but the fourth slot. @@ -365,6 +378,8 @@ public void removeAllListeners() { panHeat.removeListener(this); panArmor.removeListener(this); panMovement.removeListener(this); + panArmorAllocation.removeListener(this); + panPatchwork.removeListener(this); } public void addAllListeners() { @@ -373,11 +388,12 @@ public void addAllListeners() { panHeat.addListener(this); panArmor.addListener(this); panMovement.addListener(this); + panArmorAllocation.addListener(this); + panPatchwork.addListener(this); } public void addRefreshedListener(RefreshListener l) { refresh = l; - armor.addRefreshedListener(l); } public boolean isQuad() { @@ -402,7 +418,7 @@ private void createISMounts(EquipmentType structure) { int isCount = 0; getMech().setStructureType(EquipmentType.getStructureType(structure)); getMech().setStructureTechLevel(structure.getStaticTechLevel().getCompoundTechLevel(structure.isClan())); - + isCount = structure.getCriticals(getMech()); if (isCount < 1) { return; @@ -417,7 +433,7 @@ private void createISMounts(EquipmentType structure) { } } } - + /** * Calculates required engine rating for speed and tonnage and updates engine if possible. * @return true if the new engine is legal for rating, space, and tech level @@ -453,7 +469,7 @@ private boolean recalculateEngineRating(int walkMP, double tonnage) { } return true; } - + private boolean hasCTSpace(Engine engine, int gyroType, int cockpitType) { if (getMech().isSuperHeavy()) { return true; @@ -475,106 +491,38 @@ private boolean hasCTSpace(Engine engine, int gyroType, int cockpitType) { } return crits <= 12; } - + private void createArmorMountsAndSetArmorType(int at, int aTechLevel) { + getMech().setArmorTechLevel(aTechLevel); + getMech().setArmorType(at); + final EquipmentType armor = EquipmentType.get(EquipmentType.getArmorTypeName(at, + TechConstants.isClan(aTechLevel))); + int armorCount = armor.getCriticals(getMech()); - if (at == EquipmentType.T_ARMOR_PATCHWORK) { - boolean isMixed = panBasicInfo.useMixedTech(); - List armors = panArmor.getAllArmors(); - List> combos = new ArrayList<>(); - JPanel panel = new JPanel(new GridBagLayout()); - for (int loc = 0; loc < getMech().locations(); loc++) { - TechComboBox cbLoc = new TechComboBox<>(eq -> eq.getName()); - cbLoc.showTechBase(isMixed); - armors.forEach(a -> cbLoc.addItem(a)); - EquipmentType locArmor = EquipmentType.get(EquipmentType - .getArmorTypeName(getMech().getArmorType(loc), - TechConstants.isClan(getMech().getArmorTechLevel(loc)))); - cbLoc.setSelectedItem(locArmor); - combos.add(cbLoc); - JLabel label = new JLabel(getMech().getLocationName(loc)); - panel.add(label, GBC.std()); - panel.add(cbLoc, GBC.eol()); - } - JOptionPane.showMessageDialog(this, panel, - "Please choose the armor types", - JOptionPane.QUESTION_MESSAGE); - UnitUtil.removeISorArmorMounts(getMech(), false); - for (int loc = 0; loc < getMech().locations(); loc++) { - EquipmentType armor = (EquipmentType)combos.get(loc).getSelectedItem(); - getMech().setArmorTechLevel(armor.getTechLevel(panBasicInfo.getGameYear()), loc); - getMech().setArmorType(EquipmentType.getArmorType(armor), loc); - int crits = 0; - switch (EquipmentType.getArmorType(armor)) { - case EquipmentType.T_ARMOR_STEALTH: - case EquipmentType.T_ARMOR_FERRO_LAMELLOR: - crits = 2; - break; - case EquipmentType.T_ARMOR_HEAVY_FERRO: - crits = 3; - break; - case EquipmentType.T_ARMOR_FERRO_FIBROUS: - case EquipmentType.T_ARMOR_REFLECTIVE: - case EquipmentType.T_ARMOR_REACTIVE: - if (armor.isClan()) { - crits = 1; - } else { - crits = 2; - } - break; - } - if (getMech().getEmptyCriticals(loc) < crits) { - JOptionPane .showMessageDialog( - null, armor.getName() - + " does not fit in location " - + getMech().getLocationName(loc) - + ". Resetting to Standard Armor in this location.", - "Error", - JOptionPane.INFORMATION_MESSAGE); - getMech().setArmorTechLevel(TechConstants.T_INTRO_BOXSET, loc); - getMech().setArmorType(EquipmentType.T_ARMOR_STANDARD, loc); - } else { - for (; crits > 0; crits--) { - try { - getMech().addEquipment( new Mounted(getMech(), armor), loc, false); - } catch (LocationFullException ex) { - } - } - } + if (armorCount < 1) { + return; + } + // auto-place stealth crits + if (getMech().getArmorType(0) == EquipmentType.T_ARMOR_STEALTH) { + Mounted mount = UnitUtil.createSpreadMounts( + getMech(), + EquipmentType.get(EquipmentType.getArmorTypeName( + getMech().getArmorType(0), false))); + if (mount == null) { + JOptionPane.showMessageDialog(null, + "Stealth Armor does not fit in location.", + "Resetting to Standard Armor", + JOptionPane.INFORMATION_MESSAGE); + getMech().setArmorType(EquipmentType.T_ARMOR_STANDARD); + getMech().setArmorTechLevel(TechConstants.T_INTRO_BOXSET); + panArmor.setFromEntity(getMech()); } - panArmor.setFromEntity(getMech()); } else { - getMech().setArmorTechLevel(aTechLevel); - getMech().setArmorType(at); - final EquipmentType armor = EquipmentType.get(EquipmentType.getArmorTypeName(at, - TechConstants.isClan(aTechLevel))); - int armorCount = armor.getCriticals(getMech()); - - if (armorCount < 1) { - return; - } - // auto-place stealth crits - if (getMech().getArmorType(0) == EquipmentType.T_ARMOR_STEALTH) { - Mounted mount = UnitUtil.createSpreadMounts( - getMech(), - EquipmentType.get(EquipmentType.getArmorTypeName( - getMech().getArmorType(0), false))); - if (mount == null) { - JOptionPane.showMessageDialog(null, - "Stealth Armor does not fit in location.", - "Resetting to Standard Armor", - JOptionPane.INFORMATION_MESSAGE); - getMech().setArmorType(EquipmentType.T_ARMOR_STANDARD); - getMech().setArmorTechLevel(TechConstants.T_INTRO_BOXSET); - panArmor.setFromEntity(getMech()); - } - } else { - for (; armorCount > 0; armorCount--) { - try { - getMech().addEquipment(new Mounted(getMech(), - armor), Entity.LOC_NONE, false); - } catch (Exception ex) { - } + for (; armorCount > 0; armorCount--) { + try { + getMech().addEquipment(new Mounted(getMech(), + armor), Entity.LOC_NONE, false); + } catch (Exception ex) { } } } @@ -589,7 +537,7 @@ public void setAsCustomization() { public void refreshSummary() { panSummary.refresh(); } - + @Override public void chassisChanged(String chassis) { getMech().setChassis(chassis); @@ -627,7 +575,7 @@ public void techBaseChanged(boolean clan, boolean mixed) { public void techLevelChanged(SimpleTechLevel techLevel) { updateTechLevel(); } - + @Override public void updateTechLevel() { removeAllListeners(); @@ -635,7 +583,6 @@ public void updateTechLevel() { if (!getMech().hasPatchworkArmor()) { UnitUtil.removeISorArmorMounts(getMech(), false); } - createArmorMountsAndSetArmorType(getMech().getArmorType(0), getMech().getArmorTechLevel(0)); // If we have a large engine, a drop in tech level may make it unavailable and we will need // to reduce speed to a legal value. if (getMech().getEngine().hasFlag(Engine.LARGE_ENGINE) @@ -662,7 +609,8 @@ public void updateTechLevel() { panHeat.refresh(); panArmor.refresh(); panMovement.refresh(); - armor.resetArmorPoints(); + panArmorAllocation.setFromEntity(getMech()); + panPatchwork.setFromEntity(getMech()); addAllListeners(); } @@ -678,7 +626,7 @@ public void tonnageChanged(double tonnage) { return; } boolean changedSuperHeavyStatus = getMech().isSuperHeavy() != tonnage > 100; - + if (changedSuperHeavyStatus) { // if we switch from being superheavy to not being superheavy, // remove crits @@ -757,7 +705,7 @@ public void typeChanged(int baseType, int motiveType, long etype) { if (mount.isPresent()) { UnitUtil.removeMounted(getMech(), mount.get()); } - + if (motiveType == QuadVee.MOTIVE_WHEEL) { ((QuadVee)getMech()).setMotiveType(QuadVee.MOTIVE_WHEEL); UnitUtil.createSpreadMounts(getMech(), EquipmentType.get("Wheels")); @@ -777,7 +725,6 @@ public void typeChanged(int baseType, int motiveType, long etype) { } refresh(); - armor.refresh(); refresh.refreshBuild(); refresh.refreshPreview(); refresh.refreshStatus(); @@ -920,30 +867,30 @@ public void heatSinkBaseCountChanged(int count) { refresh.refreshStatus(); refresh.refreshPreview(); } - + @Override public void armorTypeChanged(int at, int aTechLevel) { - if (!getMech().hasPatchworkArmor()) { - UnitUtil.removeISorArmorMounts(getMech(), false); - } - createArmorMountsAndSetArmorType(at, aTechLevel); - if (!getMech().hasPatchworkArmor()) { - armor.resetArmorPoints(); + UnitUtil.removeISorArmorMounts(getMech(), false); + if (at != EquipmentType.T_ARMOR_PATCHWORK) { + createArmorMountsAndSetArmorType(at, aTechLevel); + panArmorAllocation.showPatchwork(false); + panPatchwork.setVisible(false); + } else { + panPatchwork.setFromEntity(getMech()); + panArmorAllocation.showPatchwork(true); + panPatchwork.setVisible(true); } - - armor.refresh(); + panArmorAllocation.setFromEntity(getMech()); panSummary.refresh(); refresh.refreshStatus(); refresh.refreshBuild(); refresh.refreshPreview(); } - + @Override public void armorTonnageChanged(double tonnage) { getMech().setArmorTonnage(Math.round(tonnage * 2) / 2.0); - armor.resetArmorPoints(); - - armor.refresh(); + panArmorAllocation.setFromEntity(getMech()); panSummary.refresh(); refresh.refreshStatus(); refresh.refreshPreview(); @@ -953,17 +900,16 @@ public void armorTonnageChanged(double tonnage) { public void maximizeArmor() { double maxArmor = UnitUtil.getMaximumArmorTonnage(getMech()); getMech().setArmorTonnage(maxArmor); - armor.resetArmorPoints(); panArmor.removeListener(this); panArmor.setFromEntity(getMech()); panArmor.addListener(this); - - armor.refresh(); + + panArmorAllocation.setFromEntity(getMech()); panSummary.refresh(); refresh.refreshStatus(); refresh.refreshPreview(); } - + @Override public void useRemainingTonnageArmor() { double currentTonnage = UnitUtil.getEntityVerifier(getMech()) @@ -972,16 +918,15 @@ public void useRemainingTonnageArmor() { double totalTonnage = getMech().getWeight(); double remainingTonnage = TestEntity.floor( totalTonnage - currentTonnage, TestEntity.Ceil.HALFTON); - + double maxArmor = Math.min(getMech().getArmorWeight() + remainingTonnage, UnitUtil.getMaximumArmorTonnage(getMech())); getMech().setArmorTonnage(maxArmor); - armor.resetArmorPoints(); panArmor.removeListener(this); panArmor.setFromEntity(getMech()); panArmor.addListener(this); - - armor.refresh(); + + panArmorAllocation.setFromEntity(getMech()); panSummary.refresh(); refresh.refreshStatus(); refresh.refreshPreview(); @@ -1052,4 +997,257 @@ public void jumpTypeChanged(final EquipmentType jumpJet) { jjs.forEach(jj -> UnitUtil.removeMounted(getMech(), jj)); jumpChanged(panMovement.getJump(), jumpJet); } + + @Override + public void armorPointsChanged(int location, int front, int rear) { + getMech().initializeArmor(front, location); + if (getMech().hasRearArmor(location)) { + getMech().initializeRearArmor(rear, location); + } + if (panArmor.getArmorType() == EquipmentType.T_ARMOR_PATCHWORK) { + getMech().setArmorTonnage(panArmorAllocation.getTotalArmorWeight(getMech())); + } + panArmorAllocation.setFromEntity(getMech()); + refresh.refreshPreview(); + refresh.refreshSummary(); + refresh.refreshStatus(); + } + + @Override + public void autoAllocateArmor() { + double pointsToAllocate = UnitUtil.getArmorPoints(getMech(), getMech().getLabArmorTonnage()); + double maxArmor = UnitUtil.getMaximumArmorPoints(getMech()); + if (pointsToAllocate > maxArmor) { + pointsToAllocate = maxArmor; + } + double percent = pointsToAllocate / maxArmor; + int headMaxArmor = 9; + if (getMech().isSuperHeavy()) { + headMaxArmor = 12; + } + // put 5 times the percentage of total possible armor into the head + int headArmor = (int) Math.min(Math.floor(percent * headMaxArmor * 5), headMaxArmor); + getMech().initializeArmor(headArmor, Mech.LOC_HEAD); + pointsToAllocate -= headArmor; + maxArmor -= headMaxArmor; + // recalculate percentage for remainder + percent = pointsToAllocate / maxArmor; + for (int location = 0; location < getMech().locations(); location++) { + double IS = (getMech().getInternal(location) * 2); + double allocate = Math.min(IS * percent, pointsToAllocate); + switch (location) { + case Mech.LOC_HEAD: + break; + case Mech.LOC_CT: + case Mech.LOC_LT: + case Mech.LOC_RT: + double rear = Math.floor(allocate * .25); + double front = Math.ceil(allocate * .75); + pointsToAllocate -= (int) rear; + pointsToAllocate -= (int) front; + getMech().initializeArmor((int) front, location); + getMech().initializeRearArmor((int) rear, location); + break; + default: + getMech().initializeArmor((int) allocate, location); + pointsToAllocate -= (int) allocate; + break; + } + } + allocateLeftoverPoints(pointsToAllocate); + + panArmorAllocation.setFromEntity(getMech()); + refresh.refreshPreview(); + refresh.refreshSummary(); + refresh.refreshStatus(); + } + + /** + * allocate any leftover points one-by-one + * + * @param points + * the amount of points left over + */ + private void allocateLeftoverPoints(double points) { + int headMaxArmor = 9; + if (getMech().isSuperHeavy()) { + headMaxArmor = 12; + } + while (points >= 1) { + // if two or more are left, add armor to symmetrical locations, + // to torso, legs, arms, in that order + if (points >= 2) { + if (((getMech().getOArmor(Mech.LOC_LT) + getMech().getOArmor(Mech.LOC_LT, + true)) < (getMech().getOInternal(Mech.LOC_LT) * 2)) + && ((getMech().getOArmor(Mech.LOC_RT) + getMech().getOArmor( + Mech.LOC_RT, true)) < (getMech() + .getOInternal(Mech.LOC_RT) * 2))) { + getMech().initializeArmor(getMech().getOArmor(Mech.LOC_LT) + 1, + Mech.LOC_LT); + getMech().initializeArmor(getMech().getOArmor(Mech.LOC_RT) + 1, + Mech.LOC_RT); + points -= 2; + } else if ((getMech().getOArmor(Mech.LOC_LLEG) < (getMech() + .getOInternal(Mech.LOC_LLEG) * 2)) + && (getMech().getOArmor(Mech.LOC_RLEG) < (getMech() + .getOInternal(Mech.LOC_RLEG) * 2))) { + getMech().initializeArmor(getMech().getOArmor(Mech.LOC_LLEG) + 1, + Mech.LOC_LLEG); + getMech().initializeArmor(getMech().getOArmor(Mech.LOC_RLEG) + 1, + Mech.LOC_RLEG); + points -= 2; + } else if ((getMech().getOArmor(Mech.LOC_LARM) < (getMech() + .getOInternal(Mech.LOC_LARM) * 2)) + && (getMech().getOArmor(Mech.LOC_RARM) < (getMech() + .getOInternal(Mech.LOC_RARM) * 2))) { + getMech().initializeArmor(getMech().getOArmor(Mech.LOC_LARM) + 1, + Mech.LOC_LARM); + getMech().initializeArmor(getMech().getOArmor(Mech.LOC_RARM) + 1, + Mech.LOC_RARM); + points -= 2; + } + // otherwise, first add to the head, and then even out uneven + // allocation + } else if (getMech().getOArmor(Mech.LOC_HEAD) < headMaxArmor) { + getMech().initializeArmor(getMech().getOArmor(Mech.LOC_HEAD) + 1, + Mech.LOC_HEAD); + points--; + } else if (getMech().getOArmor(Mech.LOC_LT) < getMech() + .getOArmor(Mech.LOC_RT)) { + getMech().initializeArmor(getMech().getOArmor(Mech.LOC_LT) + 1, + Mech.LOC_LT); + points--; + } else if (getMech().getOArmor(Mech.LOC_RT) < getMech() + .getOArmor(Mech.LOC_LT)) { + getMech().initializeArmor(getMech().getOArmor(Mech.LOC_RT) + 1, + Mech.LOC_RT); + points--; + } else if (getMech().getOArmor(Mech.LOC_RARM) < getMech() + .getOArmor(Mech.LOC_LARM)) { + getMech().initializeArmor(getMech().getOArmor(Mech.LOC_RARM) + 1, + Mech.LOC_RARM); + points--; + } else if (getMech().getOArmor(Mech.LOC_LARM) < getMech() + .getOArmor(Mech.LOC_RARM)) { + getMech().initializeArmor(getMech().getOArmor(Mech.LOC_LARM) + 1, + Mech.LOC_LARM); + points--; + } else if (getMech().getOArmor(Mech.LOC_RLEG) < getMech() + .getArmor(Mech.LOC_LLEG)) { + getMech().initializeArmor(getMech().getOArmor(Mech.LOC_RLEG) + 1, + Mech.LOC_RLEG); + points--; + } else if (getMech().getOArmor(Mech.LOC_LLEG) < getMech() + .getOArmor(Mech.LOC_RLEG)) { + getMech().initializeArmor(getMech().getOArmor(Mech.LOC_LLEG) + 1, + Mech.LOC_LLEG); + points--; + // if nothing is uneven, add to the CT + } else if (((getMech().getOArmor(Mech.LOC_CT) + getMech().getOArmor( + Mech.LOC_CT, true)) < (getMech().getOInternal(Mech.LOC_CT) * 2))) { + getMech().initializeArmor(getMech().getOArmor(Mech.LOC_CT) + 1, + Mech.LOC_CT); + points--; + } + // if only one is left, and head and CT have max, remove one from CT + // so symmetric locations can get extra, unless they are already at + // max + if (points == 1) { + if ((getMech().getOArmor(Mech.LOC_HEAD) == headMaxArmor) + && ((getMech().getOArmor(Mech.LOC_CT) + getMech().getOArmor( + Mech.LOC_CT, true)) == (getMech() + .getOInternal(Mech.LOC_CT) * 2))) { + getMech().initializeArmor(getMech().getOArmor(Mech.LOC_CT) - 1, + Mech.LOC_CT); + points++; + } + } + // if all locations have max, return + boolean toReturn = true; + for (int location = 0; location < getMech().locations(); location++) { + double is = (getMech().getInternal(location) * 2); + switch (location) { + case Mech.LOC_HEAD: + int headPoints = 3; + if (getMech().isSuperHeavy()) { + headPoints = 4; + } + if ((is + headPoints) > getMech().getOArmor(location)) { + toReturn = false; + } + break; + case Mech.LOC_CT: + case Mech.LOC_LT: + case Mech.LOC_RT: + if (is > (getMech().getOArmor(location) + getMech().getOArmor( + location, true))) { + toReturn = false; + } + break; + default: + if (is > getMech().getOArmor(location)) { + toReturn = false; + } + break; + } + } + if (toReturn) { + return; + } + } + } + + @Override + public void patchworkChanged(int location, EquipmentType armor) { + UnitUtil.resetArmor(getMech(), location); + + //TODO: move this construction data out of the ui + int crits = 0; + switch (EquipmentType.getArmorType(armor)) { + case EquipmentType.T_ARMOR_STEALTH: + case EquipmentType.T_ARMOR_FERRO_LAMELLOR: + crits = 2; + break; + case EquipmentType.T_ARMOR_HEAVY_FERRO: + crits = 3; + break; + case EquipmentType.T_ARMOR_LIGHT_FERRO: + crits = 1; + break; + case EquipmentType.T_ARMOR_FERRO_FIBROUS: + case EquipmentType.T_ARMOR_REFLECTIVE: + case EquipmentType.T_ARMOR_REACTIVE: + if (armor.isClan()) { + crits = 1; + } else { + crits = 2; + } + break; + } + if (getMech().getEmptyCriticals(location) < crits) { + JOptionPane .showMessageDialog( + null, armor.getName() + + " does not fit in location " + + getMech().getLocationName(location) + + ". Resetting to Standard Armor in this location.", + "Error", + JOptionPane.INFORMATION_MESSAGE); + } else { + getMech().setArmorType(EquipmentType.getArmorType(armor), location); + getMech().setArmorTechLevel(armor.getTechLevel(getTechManager().getGameYear(), armor.isClan())); + for (; crits > 0; crits--) { + try { + getMech().addEquipment( new Mounted(getMech(), armor), location, false); + } catch (LocationFullException ex) { + } + } + } + panArmor.refresh(); + panArmorAllocation.setFromEntity(getMech()); + refresh.refreshBuild(); + refresh.refreshPreview(); + refresh.refreshSummary(); + refresh.refreshStatus(); + } + } \ No newline at end of file diff --git a/src/megameklab/com/ui/Mek/views/ArmorView.java b/src/megameklab/com/ui/Mek/views/ArmorView.java deleted file mode 100644 index ffae1d41b..000000000 --- a/src/megameklab/com/ui/Mek/views/ArmorView.java +++ /dev/null @@ -1,1104 +0,0 @@ -/* - * MegaMekLab - Copyright (C) 2008 - * - * Original author - jtighe (torren@users.sourceforge.net) - * - * 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 megameklab.com.ui.Mek.views; - -import java.awt.Color; -import java.awt.Dimension; -import java.awt.GridBagConstraints; -import java.awt.GridBagLayout; -import java.awt.GridLayout; -import java.awt.Insets; -import java.awt.event.ActionEvent; -import java.awt.event.ActionListener; -import java.util.ArrayList; -import java.util.List; -import java.util.Vector; - -import javax.swing.BorderFactory; -import javax.swing.Box; -import javax.swing.BoxLayout; -import javax.swing.JButton; -import javax.swing.JLabel; -import javax.swing.JPanel; -import javax.swing.JSpinner; -import javax.swing.JTextField; -import javax.swing.SpinnerNumberModel; -import javax.swing.SwingConstants; -import javax.swing.border.TitledBorder; -import javax.swing.event.ChangeEvent; -import javax.swing.event.ChangeListener; - -import megamek.common.EquipmentType; -import megamek.common.Mech; -import megamek.common.TripodMech; -import megameklab.com.ui.EntitySource; -import megameklab.com.util.IView; -import megameklab.com.util.RefreshListener; -import megameklab.com.util.UnitUtil; - -public class ArmorView extends IView implements ChangeListener, ActionListener { - - /** - * - */ - private static final long serialVersionUID = 799195356642563937L; - - private JPanel mainPanel = new JPanel(); - - private JPanel headPanel = new JPanel(); - private JPanel laPanel = new JPanel(); - private JPanel raPanel = new JPanel(); - private JPanel llPanel = new JPanel(); - private JPanel rlPanel = new JPanel(); - private JPanel ltPanel = new JPanel(); - private JPanel rtPanel = new JPanel(); - private JPanel ctPanel = new JPanel(); - private JPanel clPanel = new JPanel(); - - public SpinnerNumberModel laArmorModel = new SpinnerNumberModel(); - public SpinnerNumberModel raArmorModel = new SpinnerNumberModel(); - public SpinnerNumberModel llArmorModel = new SpinnerNumberModel(); - public SpinnerNumberModel rlArmorModel = new SpinnerNumberModel(); - public SpinnerNumberModel ltArmorModel = new SpinnerNumberModel(); - public SpinnerNumberModel rtArmorModel = new SpinnerNumberModel(); - public SpinnerNumberModel ctArmorModel = new SpinnerNumberModel(); - public SpinnerNumberModel hdArmorModel = new SpinnerNumberModel(); - public SpinnerNumberModel clArmorModel = new SpinnerNumberModel(); - - private SpinnerNumberModel rtrArmorModel = new SpinnerNumberModel(); - private SpinnerNumberModel ltrArmorModel = new SpinnerNumberModel(); - private SpinnerNumberModel ctrArmorModel = new SpinnerNumberModel(); - - private JSpinner laArmorField = new JSpinner(laArmorModel); - private JSpinner raArmorField = new JSpinner(raArmorModel); - private JSpinner llArmorField = new JSpinner(llArmorModel); - private JSpinner rlArmorField = new JSpinner(rlArmorModel); - private JSpinner ltArmorField = new JSpinner(ltArmorModel); - private JSpinner rtArmorField = new JSpinner(rtArmorModel); - private JSpinner ctArmorField = new JSpinner(ctArmorModel); - private JSpinner hdArmorField = new JSpinner(hdArmorModel); - private JSpinner clArmorField = new JSpinner(clArmorModel); - - private JSpinner rtrArmorField = new JSpinner(rtrArmorModel); - private JSpinner ltrArmorField = new JSpinner(ltrArmorModel); - private JSpinner ctrArmorField = new JSpinner(ctrArmorModel); - private List armorFieldList = new ArrayList(); - - private JLabel hdArmorMaxLabel = new JLabel("", SwingConstants.CENTER); - private JLabel laArmorMaxLabel = new JLabel("", SwingConstants.CENTER); - private JLabel raArmorMaxLabel = new JLabel("", SwingConstants.CENTER); - private JLabel llArmorMaxLabel = new JLabel("", SwingConstants.CENTER); - private JLabel rlArmorMaxLabel = new JLabel("", SwingConstants.CENTER); - private JLabel ltArmorMaxLabel = new JLabel("", SwingConstants.CENTER); - private JLabel rtArmorMaxLabel = new JLabel("", SwingConstants.CENTER); - private JLabel ctArmorMaxLabel = new JLabel("", SwingConstants.CENTER); - private JLabel clArmorMaxLabel = new JLabel("", SwingConstants.CENTER); - private List armorMaxLabelList = new ArrayList(); - - private JLabel lblAllocatedArmor = new JLabel("Allocated Armor Points:"); - private JTextField valueAllocatedArmor = new JTextField(); - private JLabel lblUnallocatedArmor = new JLabel("Unallocated Armor Points:"); - private JTextField valueUnallocatedArmor = new JTextField(); - private JLabel lblCurrentArmor = new JLabel("Total Armor Points:"); - private JTextField valueCurrentArmor = new JTextField(); - private JLabel lblMaxArmor = new JLabel("Maximum Possible Armor Points:"); - private JTextField valueMaxArmor = new JTextField(); - private JLabel lblWastedArmor = new JLabel("Wasted Armor Points:"); - private JTextField valueWastedArmor = new JTextField(); - - private JLabel unallocatedPointsLabelPatchworkHead = new JLabel( - "Unalloc.:", SwingConstants.TRAILING); - private JLabel unallocatedPointsLabelPatchworkLa = new JLabel( - "Unalloc.:", SwingConstants.TRAILING); - private JLabel unallocatedPointsLabelPatchworkLt = new JLabel( - "Unalloc.:", SwingConstants.TRAILING); - private JLabel unallocatedPointsLabelPatchworkCt = new JLabel( - "Unalloc.:", SwingConstants.TRAILING); - private JLabel unallocatedPointsLabelPatchworkRt = new JLabel( - "Unalloc.:", SwingConstants.TRAILING); - private JLabel unallocatedPointsLabelPatchworkRa = new JLabel( - "Unalloc.:", SwingConstants.TRAILING); - private JLabel unallocatedPointsLabelPatchworkLl = new JLabel( - "Unalloc.:", SwingConstants.TRAILING); - private JLabel unallocatedPointsLabelPatchworkRl = new JLabel( - "Unalloc.:", SwingConstants.TRAILING); - private JLabel unallocatedPointsLabelPatchworkCl = new JLabel( - "Unalloc.:", SwingConstants.TRAILING); - private JLabel unallocatedPointsFieldHead = new JLabel(); - private JLabel unallocatedPointsFieldLa = new JLabel(); - private JLabel unallocatedPointsFieldLt = new JLabel(); - private JLabel unallocatedPointsFieldCt = new JLabel(); - private JLabel unallocatedPointsFieldRt = new JLabel(); - private JLabel unallocatedPointsFieldRa = new JLabel(); - private JLabel unallocatedPointsFieldLl = new JLabel(); - private JLabel unallocatedPointsFieldRl = new JLabel(); - private JLabel unallocatedPointsFieldCl = new JLabel(); - - private int armorPoints; - private int wastedArmorPoints; - - private JButton allocateArmorButton = new JButton("Auto-Allocate Armor"); - - private RefreshListener refresh; - - public ArmorView(EntitySource eSource) { - super(eSource); - - setLayout(new GridLayout(1, 1)); - - mainPanel.setLayout(new GridBagLayout()); - GridBagConstraints gbc; - - headPanel.setLayout(new BoxLayout(headPanel, BoxLayout.Y_AXIS)); - laPanel.setLayout(new BoxLayout(laPanel, BoxLayout.Y_AXIS)); - raPanel.setLayout(new BoxLayout(raPanel, BoxLayout.Y_AXIS)); - ltPanel.setLayout(new BoxLayout(ltPanel, BoxLayout.Y_AXIS)); - ctPanel.setLayout(new BoxLayout(ctPanel, BoxLayout.Y_AXIS)); - rtPanel.setLayout(new BoxLayout(rtPanel, BoxLayout.Y_AXIS)); - llPanel.setLayout(new BoxLayout(llPanel, BoxLayout.Y_AXIS)); - rlPanel.setLayout(new BoxLayout(rlPanel, BoxLayout.Y_AXIS)); - clPanel.setLayout(new BoxLayout(clPanel, BoxLayout.Y_AXIS)); - - int mainPanelGridY; - gbc = new GridBagConstraints(); - gbc.gridx = 2; - gbc.gridy = 0; - mainPanel.add(Box.createVerticalStrut(13), gbc); - gbc.gridy++; - mainPanel.add(headPanel, gbc); - gbc.gridx = 0; - gbc.gridy++; - mainPanel.add(laPanel, gbc); - gbc.gridx = 1; - mainPanel.add(ltPanel, gbc); - gbc.gridx = 2; - mainPanel.add(ctPanel, gbc); - gbc.gridx = 3; - mainPanel.add(rtPanel, gbc); - gbc.gridx = 4; - mainPanel.add(raPanel, gbc); - gbc.gridx = 1; - gbc.gridy++; - mainPanel.add(llPanel, gbc); - gbc.gridx = 2; - mainPanel.add(clPanel, gbc); - gbc.gridx = 3; - mainPanel.add(rlPanel, gbc); - mainPanelGridY = gbc.gridy + 1; - - laArmorField.setName(Integer.toString(Mech.LOC_LARM)); - raArmorField.setName(Integer.toString(Mech.LOC_RARM)); - llArmorField.setName(Integer.toString(Mech.LOC_LLEG)); - rlArmorField.setName(Integer.toString(Mech.LOC_RLEG)); - clArmorField.setName(Integer.toString(Mech.LOC_CLEG)); - ltArmorField.setName(Integer.toString(Mech.LOC_LT)); - rtArmorField.setName(Integer.toString(Mech.LOC_RT)); - ctArmorField.setName(Integer.toString(Mech.LOC_CT)); - hdArmorField.setName(Integer.toString(Mech.LOC_HEAD)); - rtrArmorField.setName(Integer.toString(Mech.LOC_RT)); - ltrArmorField.setName(Integer.toString(Mech.LOC_LT)); - ctrArmorField.setName(Integer.toString(Mech.LOC_CT)); - - armorFieldList.add(laArmorField); - armorFieldList.add(raArmorField); - armorFieldList.add(llArmorField); - armorFieldList.add(rlArmorField); - armorFieldList.add(clArmorField); - armorFieldList.add(ltArmorField); - armorFieldList.add(rtArmorField); - armorFieldList.add(ctArmorField); - armorFieldList.add(hdArmorField); - armorFieldList.add(ltrArmorField); - armorFieldList.add(ctrArmorField); - armorFieldList.add(rtrArmorField); - - Dimension size = new Dimension(40, 25); - for (JSpinner spinner : armorFieldList) { - spinner.setToolTipText("Front Armor"); - // you don't set the size of the jspinner, but rather its internal - // textfield - ((JSpinner.DefaultEditor) spinner.getEditor()).setSize(size); - ((JSpinner.DefaultEditor) spinner.getEditor()).setMaximumSize(size); - ((JSpinner.DefaultEditor) spinner.getEditor()) - .setPreferredSize(size); - ((JSpinner.DefaultEditor) spinner.getEditor()).setMinimumSize(size); - } - rtrArmorField.setToolTipText("Rear Armor"); - ltrArmorField.setToolTipText("Rear Armor"); - ctrArmorField.setToolTipText("Rear Armor"); - - armorMaxLabelList.add(hdArmorMaxLabel); - armorMaxLabelList.add(laArmorMaxLabel); - armorMaxLabelList.add(raArmorMaxLabel); - armorMaxLabelList.add(llArmorMaxLabel); - armorMaxLabelList.add(rlArmorMaxLabel); - armorMaxLabelList.add(clArmorMaxLabel); - armorMaxLabelList.add(ltArmorMaxLabel); - armorMaxLabelList.add(rtArmorMaxLabel); - armorMaxLabelList.add(ctArmorMaxLabel); - - Dimension labelSize = new Dimension(40, 20); - for (JLabel label : armorMaxLabelList) { - label.setSize(labelSize); - label.setMaximumSize(labelSize); - label.setPreferredSize(labelSize); - label.setMinimumSize(labelSize); - } - - JPanel topPanel; - JPanel bottomPanel; - - synchronized (getMech()) { - for (int location = 0; location < getMech().locations(); location++) { - - switch (location) { - case Mech.LOC_HEAD: - topPanel = new JPanel(new GridLayout(2, 0)); - topPanel.add(hdArmorField); - topPanel.add(hdArmorMaxLabel); - headPanel.add(topPanel); - - bottomPanel = new JPanel(); - bottomPanel.add(unallocatedPointsLabelPatchworkHead); - bottomPanel.add(unallocatedPointsFieldHead); - - headPanel.add(bottomPanel); - - headPanel - .setBorder(BorderFactory.createTitledBorder( - null, getMech().getLocationAbbr(location), - TitledBorder.TOP, - TitledBorder.DEFAULT_POSITION)); - - hdArmorModel.setStepSize(1); - hdArmorModel.setMinimum(0); - break; - case Mech.LOC_LARM: - topPanel = new JPanel(new GridLayout(2, 0)); - topPanel.add(laArmorField); - topPanel.add(laArmorMaxLabel); - laPanel.add(topPanel); - - bottomPanel = new JPanel(); - bottomPanel.add(unallocatedPointsLabelPatchworkLa); - bottomPanel.add(unallocatedPointsFieldLa); - laPanel.add(bottomPanel); - - laPanel.setBorder(BorderFactory.createTitledBorder( - null, getMech().getLocationAbbr(location), - TitledBorder.TOP, TitledBorder.DEFAULT_POSITION)); - - laArmorModel.setStepSize(1); - laArmorModel.setMinimum(0); - break; - case Mech.LOC_RARM: - topPanel = new JPanel(new GridLayout(2, 0)); - topPanel.add(raArmorField); - topPanel.add(raArmorMaxLabel); - raPanel.add(topPanel); - - bottomPanel = new JPanel(); - bottomPanel.add(unallocatedPointsLabelPatchworkRa); - bottomPanel.add(unallocatedPointsFieldRa); - raPanel.add(bottomPanel); - - raPanel.setBorder(BorderFactory.createTitledBorder( - null, getMech().getLocationAbbr(location), - TitledBorder.TOP, TitledBorder.DEFAULT_POSITION)); - - raArmorModel.setStepSize(1); - raArmorModel.setMinimum(0); - break; - case Mech.LOC_CT: - topPanel = new JPanel(new GridLayout(4, 0)); - topPanel.add(ctArmorField); - topPanel.add(new JLabel("Rear", SwingConstants.CENTER)); - topPanel.add(ctrArmorField); - topPanel.add(ctArmorMaxLabel); - ctPanel.setBorder(BorderFactory.createTitledBorder( - null, getMech().getLocationAbbr(location), - TitledBorder.TOP, TitledBorder.DEFAULT_POSITION)); - ctPanel.add(topPanel); - - bottomPanel = new JPanel(); - bottomPanel.add(unallocatedPointsLabelPatchworkCt); - bottomPanel.add(unallocatedPointsFieldCt); - ctPanel.add(bottomPanel); - - ctArmorModel.setStepSize(1); - ctArmorModel.setMinimum(0); - ctrArmorModel.setStepSize(1); - ctrArmorModel.setMinimum(0); - break; - case Mech.LOC_LT: - topPanel = new JPanel(new GridLayout(4, 0)); - topPanel.add(ltArmorField); - topPanel.add(new JLabel("Rear", SwingConstants.CENTER)); - topPanel.add(ltrArmorField); - topPanel.add(ltArmorMaxLabel); - ltPanel.setBorder(BorderFactory.createTitledBorder( - null, getMech().getLocationAbbr(location), - TitledBorder.TOP, TitledBorder.DEFAULT_POSITION)); - ltPanel.add(topPanel); - - bottomPanel = new JPanel(); - bottomPanel.add(unallocatedPointsLabelPatchworkLt); - bottomPanel.add(unallocatedPointsFieldLt); - ltPanel.add(bottomPanel); - - ltArmorModel.setStepSize(1); - ltArmorModel.setMinimum(0); - ltrArmorModel.setStepSize(1); - ltrArmorModel.setMinimum(0); - break; - case Mech.LOC_RT: - topPanel = new JPanel(new GridLayout(4, 0)); - topPanel.add(rtArmorField); - topPanel.add(new JLabel("Rear", SwingConstants.CENTER)); - topPanel.add(rtrArmorField); - topPanel.add(rtArmorMaxLabel); - rtPanel.setBorder(BorderFactory.createTitledBorder( - null, getMech().getLocationAbbr(location), - TitledBorder.TOP, TitledBorder.DEFAULT_POSITION)); - rtPanel.add(topPanel); - - bottomPanel = new JPanel(); - bottomPanel.add(unallocatedPointsLabelPatchworkRt); - bottomPanel.add(unallocatedPointsFieldRt); - rtPanel.add(bottomPanel); - - rtArmorModel.setStepSize(1); - rtArmorModel.setMinimum(0); - rtrArmorModel.setStepSize(1); - rtrArmorModel.setMinimum(0); - break; - case Mech.LOC_LLEG: - topPanel = new JPanel(new GridLayout(2, 0)); - topPanel.add(llArmorField); - topPanel.add(llArmorMaxLabel); - llPanel.add(topPanel); - - bottomPanel = new JPanel(); - bottomPanel.add(unallocatedPointsLabelPatchworkLl); - bottomPanel.add(unallocatedPointsFieldLl); - llPanel.add(bottomPanel); - - llPanel.setBorder(BorderFactory.createTitledBorder( - null, getMech().getLocationAbbr(location), - TitledBorder.TOP, TitledBorder.DEFAULT_POSITION)); - - llArmorModel.setStepSize(1); - llArmorModel.setMinimum(0); - break; - case Mech.LOC_RLEG: - topPanel = new JPanel(new GridLayout(2, 0)); - topPanel.add(rlArmorField); - topPanel.add(rlArmorMaxLabel); - rlPanel.add(topPanel); - - bottomPanel = new JPanel(); - bottomPanel.add(unallocatedPointsLabelPatchworkRl); - bottomPanel.add(unallocatedPointsFieldRl); - rlPanel.add(bottomPanel); - - rlPanel.setBorder(BorderFactory.createTitledBorder( - null, getMech().getLocationAbbr(location), - TitledBorder.TOP, TitledBorder.DEFAULT_POSITION)); - - rlArmorModel.setStepSize(1); - rlArmorModel.setMinimum(0); - break; - case Mech.LOC_CLEG: - topPanel = new JPanel(new GridLayout(2, 0)); - topPanel.add(clArmorField); - topPanel.add(clArmorMaxLabel); - clPanel.add(topPanel); - - bottomPanel = new JPanel(); - bottomPanel.add(unallocatedPointsLabelPatchworkCl); - bottomPanel.add(unallocatedPointsFieldCl); - clPanel.add(bottomPanel); - - clPanel.setBorder(BorderFactory.createTitledBorder( - null, getMech().getLocationAbbr(location), - TitledBorder.TOP, TitledBorder.DEFAULT_POSITION)); - - clArmorModel.setStepSize(1); - clArmorModel.setMinimum(0); - break; - } - } - } - - JPanel totalArmorPanel = new JPanel(); - - Vector valueFields = new Vector(); - valueFields.add(valueUnallocatedArmor); - valueFields.add(valueAllocatedArmor); - valueFields.add(valueCurrentArmor); - valueFields.add(valueMaxArmor); - valueFields.add(valueWastedArmor); - - Dimension valueSize = new Dimension(45, 20); - for (JTextField field : valueFields) { - field.setEditable(false); - field.setSize(valueSize); - field.setPreferredSize(valueSize); - field.setMinimumSize(valueSize); - field.setMaximumSize(valueSize); - field.setHorizontalAlignment(SwingConstants.RIGHT); - } - - totalArmorPanel.setLayout(new GridBagLayout()); - gbc = new GridBagConstraints(); - gbc.gridx = 0; - gbc.gridy = 0; - gbc.insets = new Insets(2, 2, 2, 2); - gbc.anchor = GridBagConstraints.WEST; - totalArmorPanel.add(Box.createVerticalStrut(18), gbc); - gbc.gridy++; - totalArmorPanel.add(lblUnallocatedArmor, gbc); - gbc.gridx = 1; - totalArmorPanel.add(valueUnallocatedArmor, gbc); - gbc.gridx = 0; - gbc.gridy++; - totalArmorPanel.add(lblAllocatedArmor, gbc); - gbc.gridx = 1; - totalArmorPanel.add(valueAllocatedArmor, gbc); - gbc.gridx = 0; - gbc.gridy++; - totalArmorPanel.add(lblCurrentArmor, gbc); - gbc.gridx = 1; - totalArmorPanel.add(valueCurrentArmor, gbc); - gbc.gridx = 0; - gbc.gridy++; - totalArmorPanel.add(lblMaxArmor, gbc); - gbc.gridx = 1; - totalArmorPanel.add(valueMaxArmor, gbc); - gbc.gridx = 0; - gbc.gridy++; - totalArmorPanel.add(lblWastedArmor, gbc); - gbc.gridx = 1; - totalArmorPanel.add(valueWastedArmor, gbc); - gbc.gridx = 0; - gbc.gridy++; - gbc.gridwidth = 2; - gbc.anchor = GridBagConstraints.CENTER; - totalArmorPanel.add(Box.createVerticalStrut(18), gbc); - gbc.gridy++; - totalArmorPanel.add(allocateArmorButton, gbc); - - gbc = new GridBagConstraints(); - gbc.gridx = 0; - gbc.gridy = mainPanelGridY; - gbc.gridwidth = 5; - gbc.fill = GridBagConstraints.NONE; - gbc.anchor = GridBagConstraints.CENTER; - mainPanel.add(totalArmorPanel, gbc); - this.add(mainPanel); - - resetArmorPoints(); - - addAllListeners(); - } - - private void addAllListeners() { - allocateArmorButton.addActionListener(this); - for (JSpinner spinner : armorFieldList) { - spinner.addChangeListener(this); - } - } - - private void removeAllListeners() { - allocateArmorButton.removeActionListener(this); - for (JSpinner spinner : armorFieldList) { - spinner.removeChangeListener(this); - } - } - - public void refresh() { - removeAllListeners(); - clPanel.setVisible(getMech() instanceof TripodMech); - for (int location = 0; location < getMech().locations(); location++) { - int maxArmor = getMech().getOInternal(location) * 2; - int headMaxArmor = 9; - if (getMech().isSuperHeavy()) { - headMaxArmor = 12; - } - int rearArmor; - switch (location) { - case Mech.LOC_HEAD: - hdArmorModel.setValue(Math.min(headMaxArmor, getMech().getArmor(location))); - hdArmorModel.setMaximum(headMaxArmor); - hdArmorMaxLabel.setText("max: "+headMaxArmor); - break; - case Mech.LOC_LARM: - laArmorModel.setValue(Math.min(maxArmor, - getMech().getArmor(location))); - laArmorModel.setMaximum(maxArmor); - laArmorMaxLabel.setText("max: " - + Integer.toString(maxArmor)); - break; - case Mech.LOC_RARM: - raArmorModel.setValue(Math.min(maxArmor, - getMech().getArmor(location))); - raArmorModel.setMaximum(maxArmor); - raArmorMaxLabel.setText("max: " - + Integer.toString(maxArmor)); - break; - case Mech.LOC_CT: - ctArmorModel.setValue(Math.min(maxArmor, - getMech().getArmor(location))); - ctArmorModel.setMaximum(maxArmor); - ctrArmorModel.setMaximum(maxArmor); - rearArmor = Math.min(getMech().getArmor(location, true), - maxArmor - getMech().getArmor(location)); - ctrArmorModel.setValue(rearArmor); - getMech().initializeRearArmor(rearArmor, location); - - ctArmorMaxLabel.setText("max: " - + Integer.toString(maxArmor)); - break; - case Mech.LOC_LT: - ltArmorModel.setValue(Math.min(maxArmor, - getMech().getArmor(location))); - - ltArmorModel.setMaximum(maxArmor); - ltrArmorModel.setMaximum(maxArmor); - rearArmor = Math.min(getMech().getArmor(location, true), - maxArmor - getMech().getArmor(location)); - ltrArmorModel.setValue(rearArmor); - getMech().initializeRearArmor(rearArmor, location); - - ltArmorMaxLabel.setText("max: " - + Integer.toString(maxArmor)); - break; - case Mech.LOC_RT: - rtArmorModel.setValue(Math.min(maxArmor, - getMech().getArmor(location))); - - rtArmorModel.setMaximum(maxArmor); - rtrArmorModel.setMaximum(maxArmor); - rearArmor = Math.min(getMech().getArmor(location, true), - maxArmor - getMech().getArmor(location)); - rtrArmorModel.setValue(rearArmor); - getMech().initializeRearArmor(rearArmor, location); - - rtArmorMaxLabel.setText("max: " - + Integer.toString(maxArmor)); - break; - case Mech.LOC_LLEG: - llArmorModel.setValue(Math.min(maxArmor, - getMech().getArmor(location))); - llArmorModel.setMaximum(maxArmor); - llArmorMaxLabel.setText("max: " - + Integer.toString(maxArmor)); - break; - case Mech.LOC_RLEG: - rlArmorModel.setValue(Math.min(maxArmor, - getMech().getArmor(location))); - rlArmorModel.setMaximum(maxArmor); - rlArmorMaxLabel.setText("max: " - + Integer.toString(maxArmor)); - break; - case Mech.LOC_CLEG: - clArmorModel.setValue(Math.min(maxArmor, - getMech().getArmor(location))); - clArmorModel.setMaximum(maxArmor); - clArmorMaxLabel.setText("max: " - + Integer.toString(maxArmor)); - break; - } - } - - // unallocated armorpoints - if (getMech().hasPatchworkArmor()) { - valueUnallocatedArmor.setVisible(false); - lblUnallocatedArmor.setVisible(false); - valueAllocatedArmor.setVisible(false); - lblAllocatedArmor.setVisible(false); - valueWastedArmor.setVisible(false); - lblWastedArmor.setVisible(false); - allocateArmorButton.setVisible(false); - unallocatedPointsLabelPatchworkHead.setVisible(true); - unallocatedPointsLabelPatchworkLa.setVisible(true); - unallocatedPointsLabelPatchworkLt.setVisible(true); - unallocatedPointsLabelPatchworkCt.setVisible(true); - unallocatedPointsLabelPatchworkRt.setVisible(true); - unallocatedPointsLabelPatchworkRa.setVisible(true); - unallocatedPointsLabelPatchworkLl.setVisible(true); - unallocatedPointsLabelPatchworkRl.setVisible(true); - unallocatedPointsFieldHead.setVisible(true); - unallocatedPointsFieldLa.setVisible(true); - unallocatedPointsFieldLt.setVisible(true); - unallocatedPointsFieldCt.setVisible(true); - unallocatedPointsFieldRt.setVisible(true); - unallocatedPointsFieldRa.setVisible(true); - unallocatedPointsFieldLl.setVisible(true); - unallocatedPointsFieldRl.setVisible(true); - unallocatedPointsFieldHead.setText(Integer.toString(UnitUtil - .getArmorPoints(getMech(), Mech.LOC_HEAD, - getMech().getArmorWeight(Mech.LOC_HEAD)) - - getMech().getOArmor(Mech.LOC_HEAD))); - unallocatedPointsFieldLa.setText(Integer.toString(UnitUtil - .getArmorPoints(getMech(), Mech.LOC_LARM, - getMech().getArmorWeight(Mech.LOC_LARM)) - - getMech().getOArmor(Mech.LOC_LARM))); - unallocatedPointsFieldLt.setText(Integer.toString(UnitUtil - .getArmorPoints(getMech(), Mech.LOC_LT, - getMech().getArmorWeight(Mech.LOC_LT)) - - getMech().getOArmor(Mech.LOC_LT) - getMech().getOArmor(Mech.LOC_LT, true))); - unallocatedPointsFieldCt.setText(Integer.toString(UnitUtil - .getArmorPoints(getMech(), Mech.LOC_CT, - getMech().getArmorWeight(Mech.LOC_CT)) - - getMech().getOArmor(Mech.LOC_CT) - getMech().getOArmor(Mech.LOC_CT, true))); - unallocatedPointsFieldRt.setText(Integer.toString(UnitUtil - .getArmorPoints(getMech(), Mech.LOC_RT, - getMech().getArmorWeight(Mech.LOC_RT)) - - getMech().getOArmor(Mech.LOC_RT) - getMech().getOArmor(Mech.LOC_RT, true))); - unallocatedPointsFieldRa.setText(Integer.toString(UnitUtil - .getArmorPoints(getMech(), Mech.LOC_RARM, - getMech().getArmorWeight(Mech.LOC_RARM)) - - getMech().getOArmor(Mech.LOC_RARM))); - unallocatedPointsFieldLl.setText(Integer.toString(UnitUtil - .getArmorPoints(getMech(), Mech.LOC_LLEG, - getMech().getArmorWeight(Mech.LOC_LLEG)) - - getMech().getOArmor(Mech.LOC_LLEG))); - unallocatedPointsFieldRl.setText(Integer.toString(UnitUtil - .getArmorPoints(getMech(), Mech.LOC_RLEG, - getMech().getArmorWeight(Mech.LOC_RLEG)) - - getMech().getOArmor(Mech.LOC_RLEG))); - if (getMech() instanceof TripodMech) { - unallocatedPointsFieldCl.setVisible(true); - unallocatedPointsFieldCl.setText(Integer.toString(UnitUtil - .getArmorPoints(getMech(), Mech.LOC_CLEG, - getMech().getArmorWeight(Mech.LOC_CLEG)) - - getMech().getOArmor(Mech.LOC_CLEG))); - } - } else { - valueUnallocatedArmor.setVisible(true); - lblUnallocatedArmor.setVisible(true); - valueAllocatedArmor.setVisible(true); - lblAllocatedArmor.setVisible(true); - allocateArmorButton.setVisible(true); - valueWastedArmor.setVisible(true); - lblWastedArmor.setVisible(true); - unallocatedPointsLabelPatchworkHead.setVisible(false); - unallocatedPointsLabelPatchworkLa.setVisible(false); - unallocatedPointsLabelPatchworkLt.setVisible(false); - unallocatedPointsLabelPatchworkCt.setVisible(false); - unallocatedPointsLabelPatchworkRt.setVisible(false); - unallocatedPointsLabelPatchworkRa.setVisible(false); - unallocatedPointsLabelPatchworkLl.setVisible(false); - unallocatedPointsLabelPatchworkRl.setVisible(false); - unallocatedPointsFieldHead.setVisible(false); - unallocatedPointsFieldLa.setVisible(false); - unallocatedPointsFieldLt.setVisible(false); - unallocatedPointsFieldCt.setVisible(false); - unallocatedPointsFieldRt.setVisible(false); - unallocatedPointsFieldRa.setVisible(false); - unallocatedPointsFieldLl.setVisible(false); - unallocatedPointsFieldRl.setVisible(false); - if (getMech() instanceof TripodMech) { - unallocatedPointsLabelPatchworkCl.setVisible(false); - unallocatedPointsFieldCl.setVisible(false); - } - } - valueAllocatedArmor.setText(Integer.toString(getMech().getTotalOArmor())); - valueUnallocatedArmor.setText(Integer.toString(armorPoints - - getMech().getTotalOArmor())); - if (armorPoints != getMech().getTotalOArmor()) { - valueUnallocatedArmor.setForeground(Color.RED); - lblUnallocatedArmor.setForeground(Color.RED); - } else { - valueUnallocatedArmor.setForeground(Color.BLACK); - lblUnallocatedArmor.setForeground(Color.BLACK); - } - valueCurrentArmor.setText(Integer.toString(armorPoints)); - // Total Possible armor is Internal*2 +3 for the extra 3 armor the head - // can support. - int headArmor = 3; - if (getMech().isSuperHeavy()) { - headArmor = 4; - } - valueMaxArmor.setText(Integer.toString((getMech().getTotalOInternal() * 2) - + headArmor)); - valueWastedArmor.setText(Integer.toString(wastedArmorPoints)); - - addAllListeners(); - } - - public void addRefreshedListener(RefreshListener l) { - refresh = l; - } - - public void allocateArmor() { - double pointsToAllocate = armorPoints; - int headPoints = 3; - if (getMech().isSuperHeavy()) { - headPoints = 4; - } - double totalArmor = (getMech().getTotalOInternal() * 2) + headPoints; - if (pointsToAllocate > totalArmor) { - pointsToAllocate = totalArmor; - } - double percent = pointsToAllocate / totalArmor; - int headMaxArmor = 9; - if (getMech().isSuperHeavy()) { - headMaxArmor = 12; - } - // put 5 times the percentage of total possible armor into the head - int headArmor = (int) Math.min(Math.floor(percent * headMaxArmor * 5), headMaxArmor); - getMech().initializeArmor(headArmor, Mech.LOC_HEAD); - pointsToAllocate -= headArmor; - for (int location = 0; location < getMech().locations(); location++) { - double IS = (getMech().getInternal(location) * 2); - double allocate = Math.min(IS * percent, pointsToAllocate); - switch (location) { - case Mech.LOC_HEAD: - break; - case Mech.LOC_CT: - case Mech.LOC_LT: - case Mech.LOC_RT: - double rear = Math.floor(allocate * .25); - double front = Math.ceil(allocate * .75); - pointsToAllocate -= (int) rear; - pointsToAllocate -= (int) front; - getMech().initializeArmor((int) front, location); - getMech().initializeRearArmor((int) rear, location); - break; - default: - getMech().initializeArmor((int) allocate, location); - pointsToAllocate -= (int) allocate; - break; - } - } - allocateLeftoverPoints(pointsToAllocate); - - if (refresh != null) { - refresh.refreshStatus(); - } - } - - /** - * allocate any leftover points one-by-one - * - * @param points - * the amount of points left over - */ - private void allocateLeftoverPoints(double points) { - int headMaxArmor = 9; - if (getMech().isSuperHeavy()) { - headMaxArmor = 12; - } - while (points >= 1) { - // if two or more are left, add armor to symmetrical locations, - // to torso, legs, arms, in that order - if (points >= 2) { - if (((getMech().getOArmor(Mech.LOC_LT) + getMech().getOArmor(Mech.LOC_LT, - true)) < (getMech().getOInternal(Mech.LOC_LT) * 2)) - && ((getMech().getOArmor(Mech.LOC_RT) + getMech().getOArmor( - Mech.LOC_RT, true)) < (getMech() - .getOInternal(Mech.LOC_RT) * 2))) { - getMech().initializeArmor(getMech().getOArmor(Mech.LOC_LT) + 1, - Mech.LOC_LT); - getMech().initializeArmor(getMech().getOArmor(Mech.LOC_RT) + 1, - Mech.LOC_RT); - points -= 2; - } else if ((getMech().getOArmor(Mech.LOC_LLEG) < (getMech() - .getOInternal(Mech.LOC_LLEG) * 2)) - && (getMech().getOArmor(Mech.LOC_RLEG) < (getMech() - .getOInternal(Mech.LOC_RLEG) * 2))) { - getMech().initializeArmor(getMech().getOArmor(Mech.LOC_LLEG) + 1, - Mech.LOC_LLEG); - getMech().initializeArmor(getMech().getOArmor(Mech.LOC_RLEG) + 1, - Mech.LOC_RLEG); - points -= 2; - } else if ((getMech().getOArmor(Mech.LOC_LARM) < (getMech() - .getOInternal(Mech.LOC_LARM) * 2)) - && (getMech().getOArmor(Mech.LOC_RARM) < (getMech() - .getOInternal(Mech.LOC_RARM) * 2))) { - getMech().initializeArmor(getMech().getOArmor(Mech.LOC_LARM) + 1, - Mech.LOC_LARM); - getMech().initializeArmor(getMech().getOArmor(Mech.LOC_RARM) + 1, - Mech.LOC_RARM); - points -= 2; - } - // otherwise, first add to the head, and then even out uneven - // allocation - } else if (getMech().getOArmor(Mech.LOC_HEAD) < headMaxArmor) { - getMech().initializeArmor(getMech().getOArmor(Mech.LOC_HEAD) + 1, - Mech.LOC_HEAD); - points--; - } else if (getMech().getOArmor(Mech.LOC_LT) < getMech() - .getOArmor(Mech.LOC_RT)) { - getMech().initializeArmor(getMech().getOArmor(Mech.LOC_LT) + 1, - Mech.LOC_LT); - points--; - } else if (getMech().getOArmor(Mech.LOC_RT) < getMech() - .getOArmor(Mech.LOC_LT)) { - getMech().initializeArmor(getMech().getOArmor(Mech.LOC_RT) + 1, - Mech.LOC_RT); - points--; - } else if (getMech().getOArmor(Mech.LOC_RARM) < getMech() - .getOArmor(Mech.LOC_LARM)) { - getMech().initializeArmor(getMech().getOArmor(Mech.LOC_RARM) + 1, - Mech.LOC_RARM); - points--; - } else if (getMech().getOArmor(Mech.LOC_LARM) < getMech() - .getOArmor(Mech.LOC_RARM)) { - getMech().initializeArmor(getMech().getOArmor(Mech.LOC_LARM) + 1, - Mech.LOC_LARM); - points--; - } else if (getMech().getOArmor(Mech.LOC_RLEG) < getMech() - .getArmor(Mech.LOC_LLEG)) { - getMech().initializeArmor(getMech().getOArmor(Mech.LOC_RLEG) + 1, - Mech.LOC_RLEG); - points--; - } else if (getMech().getOArmor(Mech.LOC_LLEG) < getMech() - .getOArmor(Mech.LOC_RLEG)) { - getMech().initializeArmor(getMech().getOArmor(Mech.LOC_LLEG) + 1, - Mech.LOC_LLEG); - points--; - // if nothing is uneven, add to the CT - } else if (((getMech().getOArmor(Mech.LOC_CT) + getMech().getOArmor( - Mech.LOC_CT, true)) < (getMech().getOInternal(Mech.LOC_CT) * 2))) { - getMech().initializeArmor(getMech().getOArmor(Mech.LOC_CT) + 1, - Mech.LOC_CT); - points--; - } - // if only one is left, and head and CT have max, remove one from CT - // so symmetric locations can get extra, unless they are already at - // max - if (points == 1) { - if ((getMech().getOArmor(Mech.LOC_HEAD) == headMaxArmor) - && ((getMech().getOArmor(Mech.LOC_CT) + getMech().getOArmor( - Mech.LOC_CT, true)) == (getMech() - .getOInternal(Mech.LOC_CT) * 2))) { - getMech().initializeArmor(getMech().getOArmor(Mech.LOC_CT) - 1, - Mech.LOC_CT); - points++; - } - } - // if all locations have max, return - boolean toReturn = true; - for (int location = 0; location < getMech().locations(); location++) { - double is = (getMech().getInternal(location) * 2); - switch (location) { - case Mech.LOC_HEAD: - int headPoints = 3; - if (getMech().isSuperHeavy()) { - headPoints = 4; - } - if ((is + headPoints) > getMech().getOArmor(location)) { - toReturn = false; - } - break; - case Mech.LOC_CT: - case Mech.LOC_LT: - case Mech.LOC_RT: - if (is > (getMech().getOArmor(location) + getMech().getOArmor( - location, true))) { - toReturn = false; - } - break; - default: - if (is > getMech().getOArmor(location)) { - toReturn = false; - } - break; - } - } - if (toReturn) { - return; - } - } - } - - public void stateChanged(ChangeEvent e) { - removeAllListeners(); - int allowedArmorPoints = armorPoints; - if (getMech().hasPatchworkArmor()) { - allowedArmorPoints = UnitUtil.getMaximumArmorPoints(getMech()); - } - JSpinner field = (JSpinner) e.getSource(); - boolean isRear = field.equals(ctrArmorField) - || field.equals(ltrArmorField) || field.equals(rtrArmorField); - int location = Integer.parseInt(field.getName()); - int maxArmor = getMech().getOInternal(location) * 2; - int value = (Integer) field.getModel().getValue(); - - // How much armor do we have without the value that was just changed - int totalArmor = 0; - for (int loc = 0; loc < getMech().locations(); loc++) { - if (loc != location) { - totalArmor += getMech().getOArmor(loc); - if (getMech().hasRearArmor(loc)) { - totalArmor += getMech().getOArmor(loc, true); - } - } else if ((loc == location) && getMech().hasRearArmor(loc)) { - totalArmor += getMech().getOArmor(loc, !isRear); - } - } - - // Do we have enough armor points to make this change? - if ((allowedArmorPoints - (totalArmor + value)) < 0) { - // See if we can pull armor from the opposite location - if (getMech().hasRearArmor(location) - && getMech().getOArmor(location,!isRear) > 0) { - stealArmorFromOppositeSide(location, isRear); - } else { // If we can't pull armor, just revert the change and end - field.setValue(value - 1); - addAllListeners(); - return; - } - } - - // If this change would put us over the per-location total, may have to - // steal a point from the other side - if (getMech().hasRearArmor(location) - && ((value + getMech().getOArmor(location, !isRear)) > maxArmor)) { - stealArmorFromOppositeSide(location, isRear); - } - - // Update armor in the changed location - switch (location) { - case Mech.LOC_CT: - if (isRear) { - getMech().initializeRearArmor(value, location); - } else { - getMech().initializeArmor(value, location); - } - break; - case Mech.LOC_RT: - if (isRear) { - getMech().initializeRearArmor(value, location); - } else { - getMech().initializeArmor(value, location); - } - break; - case Mech.LOC_LT: - if (isRear) { - getMech().initializeRearArmor(value, location); - } else { - getMech().initializeArmor(value, location); - } - break; - default: - getMech().initializeArmor(value, location); - break; - } - if (getMech().hasPatchworkArmor()) { - setArmorPoints(getMech().getTotalArmor()); - } - if (refresh != null) { - addAllListeners(); - refresh.refreshStructure(); - removeAllListeners(); - refresh.refreshStatus(); - } - addAllListeners(); - } - - /** - * Given a location and whether it's rear or not, take a point of armor from - * the opposite side. That is, given a rear CT location, reduce the front - * CT by 1 point of armor. - * - * @param location - * @param isRear - */ - private void stealArmorFromOppositeSide(int location, boolean isRear) { - JSpinner opposite = getOppositeSpinner(location, isRear); - int oppositeValue = (Integer)opposite.getValue(); - // "Steal" armor from the opposite side - oppositeValue--; - opposite.setValue(oppositeValue); - // Make sure the Unit reflects the armor update - if (!isRear) { - getMech().initializeRearArmor(oppositeValue, location); - } else { - getMech().initializeArmor(oppositeValue, location); - } - } - - /** - * For swapping armor between front and rear locations, we need to get the - * JSpinner that correspondes to the opposite side of a location. Ie, if - * we are given the front CT, return the rear CT JSpinner. - * - * @param location - * @param isRear - * @return - */ - private JSpinner getOppositeSpinner(int location, boolean isRear) { - JSpinner opposite; - switch (location) { - case Mech.LOC_CT: - if (isRear) { - opposite = ctArmorField; - } else { - opposite = ctrArmorField; - } - break; - case Mech.LOC_LT: - if (isRear) { - opposite = ltArmorField; - } else { - opposite = ltrArmorField; - } - break; - case Mech.LOC_RT: - if (isRear) { - opposite = rtArmorField; - } else { - opposite = rtrArmorField; - } - break; - default : - opposite = null; - } - return opposite; - } - - public void setArmorPoints(int points) { - int headPoints = 3; - if (getMech().isSuperHeavy()) { - headPoints = 4; - } - int maxArmor = (getMech().getTotalOInternal() * 2) + headPoints; - wastedArmorPoints = Math.max(points - maxArmor, 0); - armorPoints = Math.min(maxArmor, points); - } - - @Override - public void actionPerformed(ActionEvent e) { - removeAllListeners(); - if (e.getSource().equals(allocateArmorButton)) { - allocateArmor(); - } - addAllListeners(); - refresh.refreshAll(); - } - - public void resetArmorPoints() { - double armorPerTon = 16.0 * EquipmentType.getArmorPointMultiplier( - getMech().getArmorType(0), getMech().getArmorTechLevel(0)); - setArmorPoints((int) Math - .floor(getMech().getLabArmorTonnage() * armorPerTon)); - } -} \ No newline at end of file diff --git a/src/megameklab/com/ui/Mek/views/SummaryView.java b/src/megameklab/com/ui/Mek/views/SummaryView.java index 52098a2e9..4a7470591 100644 --- a/src/megameklab/com/ui/Mek/views/SummaryView.java +++ b/src/megameklab/com/ui/Mek/views/SummaryView.java @@ -275,7 +275,11 @@ public void refresh() { txtCockpitTon.setText(Double.toString(testMech.getWeightCockpit())); txtHeatTon.setText(Double.toString(testMech.getWeightHeatSinks())); txtStructTon.setText(Double.toString(testMech.getWeightStructure())); - txtArmorTon.setText(Double.toString(testMech.getWeightArmor())); + if (getMech().hasPatchworkArmor()) { + txtArmorTon.setText(Double.toString(testMech.getWeightAllocatedArmor())); + } else { + txtArmorTon.setText(Double.toString(testMech.getWeightArmor())); + } txtOtherTon.setText(Double.toString(testMech.getWeightPowerAmp() + testMech.getWeightCarryingSpace() + testMech.getWeightMisc())); diff --git a/src/megameklab/com/ui/Vehicle/tabs/StructureTab.java b/src/megameklab/com/ui/Vehicle/tabs/StructureTab.java index d53c60b3c..dcce200d7 100644 --- a/src/megameklab/com/ui/Vehicle/tabs/StructureTab.java +++ b/src/megameklab/com/ui/Vehicle/tabs/StructureTab.java @@ -17,20 +17,15 @@ package megameklab.com.ui.Vehicle.tabs; import java.awt.BorderLayout; -import java.awt.Dimension; import java.awt.GridBagConstraints; import java.awt.GridBagLayout; -import java.util.ArrayList; -import java.util.List; import javax.swing.BorderFactory; import javax.swing.Box; import javax.swing.BoxLayout; -import javax.swing.JLabel; import javax.swing.JOptionPane; import javax.swing.JPanel; -import megamek.client.ui.GBC; import megamek.common.Engine; import megamek.common.Entity; import megamek.common.EntityMovementMode; @@ -40,47 +35,43 @@ import megamek.common.MiscType; import megamek.common.Mounted; import megamek.common.SimpleTechLevel; +import megamek.common.SuperHeavyTank; import megamek.common.Tank; -import megamek.common.TechConstants; import megamek.common.TroopSpace; +import megamek.common.VTOL; import megamek.common.verifier.TestEntity; import megameklab.com.ui.EntitySource; -import megameklab.com.ui.Vehicle.views.ArmorView; import megameklab.com.ui.Vehicle.views.SummaryView; -import megameklab.com.ui.util.TechComboBox; +import megameklab.com.ui.view.ArmorAllocationView; import megameklab.com.ui.view.BasicInfoView; import megameklab.com.ui.view.CVChassisView; import megameklab.com.ui.view.MVFArmorView; import megameklab.com.ui.view.MovementView; +import megameklab.com.ui.view.PatchworkArmorView; +import megameklab.com.ui.view.listeners.CVBuildListener; import megameklab.com.util.ITab; import megameklab.com.util.RefreshListener; import megameklab.com.util.UnitUtil; -public class StructureTab extends ITab implements - BasicInfoView.BasicInfoListener, - CVChassisView.ChassisListener, - MovementView.MovementListener, - MVFArmorView.ArmorListener { +public class StructureTab extends ITab implements CVBuildListener { /** * */ private static final long serialVersionUID = -6756011847500605874L; - RefreshListener refresh = null; - Dimension maxSize = new Dimension(); - JPanel masterPanel; - BasicInfoView panBasicInfo; - CVChassisView panChassis; - MVFArmorView panArmor; - MovementView panMovement; - SummaryView panSummary; + private RefreshListener refresh = null; + private JPanel masterPanel; + private BasicInfoView panBasicInfo; + private CVChassisView panChassis; + private MVFArmorView panArmor; + private MovementView panMovement; + private SummaryView panSummary; + private ArmorAllocationView panArmorAllocation; + private PatchworkArmorView panPatchwork; - private ArmorView armor; - public StructureTab(EntitySource eSource) { super(eSource); - armor = new ArmorView(eSource); setLayout(new BorderLayout()); setUpPanels(); this.add(masterPanel, BorderLayout.CENTER); @@ -93,7 +84,14 @@ private void setUpPanels() { panChassis = new CVChassisView(panBasicInfo); panArmor = new MVFArmorView(panBasicInfo); panMovement = new MovementView(panBasicInfo); + panArmorAllocation = new ArmorAllocationView(panBasicInfo, Entity.ETYPE_TANK); + panPatchwork = new PatchworkArmorView(panBasicInfo); panSummary = new SummaryView(eSource); + if (getTank().hasPatchworkArmor()) { + panArmorAllocation.showPatchwork(true); + } else { + panPatchwork.setVisible(false); + } GridBagConstraints gbc; @@ -101,12 +99,16 @@ private void setUpPanels() { panChassis.setFromEntity(getTank()); panMovement.setFromEntity(getTank()); panArmor.setFromEntity(getTank()); + panArmorAllocation.setFromEntity(getTank()); + panPatchwork.setFromEntity(getTank()); gbc = new GridBagConstraints(); JPanel leftPanel = new JPanel(); + JPanel midPanel = new JPanel(); JPanel rightPanel = new JPanel(); leftPanel.setLayout(new BoxLayout(leftPanel, BoxLayout.Y_AXIS)); + midPanel.setLayout(new BoxLayout(midPanel, BoxLayout.Y_AXIS)); rightPanel.setLayout(new BoxLayout(rightPanel, BoxLayout.Y_AXIS)); leftPanel.add(panBasicInfo); @@ -116,9 +118,12 @@ private void setUpPanels() { leftPanel.add(panMovement); leftPanel.add(Box.createGlue()); - rightPanel.add(panArmor); - rightPanel.add(panSummary); - rightPanel.add(Box.createVerticalGlue()); + midPanel.add(panArmor); + midPanel.add(panSummary); + midPanel.add(Box.createVerticalGlue()); + + rightPanel.add(panArmorAllocation); + rightPanel.add(panPatchwork); gbc = new GridBagConstraints(); gbc.gridx = 0; @@ -129,16 +134,17 @@ private void setUpPanels() { gbc.anchor = GridBagConstraints.NORTHWEST; masterPanel.add(leftPanel, gbc); gbc.gridx = 1; - masterPanel.add(rightPanel, gbc); + masterPanel.add(midPanel, gbc); gbc.gridx = 2; - masterPanel.add(armor, gbc); + masterPanel.add(rightPanel, gbc); panBasicInfo.setBorder(BorderFactory.createTitledBorder("Basic Information")); panChassis.setBorder(BorderFactory.createTitledBorder("Chassis")); panMovement.setBorder(BorderFactory.createTitledBorder("Movement")); panArmor.setBorder(BorderFactory.createTitledBorder("Armor")); panSummary.setBorder(BorderFactory.createTitledBorder("Summary")); - armor.setBorder(BorderFactory.createTitledBorder("Armor Allocation")); + panArmorAllocation.setBorder(BorderFactory.createTitledBorder("Armor Allocation")); + panPatchwork.setBorder(BorderFactory.createTitledBorder("Patchwork Armor")); } public void refresh() { @@ -148,8 +154,9 @@ public void refresh() { panChassis.setFromEntity(getTank()); panMovement.setFromEntity(getTank()); panArmor.setFromEntity(getTank()); + panArmorAllocation.setFromEntity(getTank()); + panPatchwork.setFromEntity(getTank()); - armor.refresh(); panSummary.refresh(); addAllListeners(); @@ -171,6 +178,8 @@ public void removeAllListeners() { panChassis.removeListener(this); panMovement.removeListener(this); panArmor.removeListener(this); + panArmorAllocation.removeListener(this); + panPatchwork.removeListener(this); } public void addAllListeners() { @@ -178,11 +187,12 @@ public void addAllListeners() { panChassis.addListener(this); panMovement.addListener(this); panArmor.addListener(this); + panArmorAllocation.addListener(this); + panPatchwork.addListener(this); } public void addRefreshedListener(RefreshListener l) { refresh = l; - armor.addRefreshedListener(l); } private void removeTurret(int loc) { @@ -233,44 +243,6 @@ private boolean recalculateEngineRating(int walkMP, double tonnage) { return true; } - private void createArmorMountsAndSetArmorType(int at, int aTechLevel) { - if (EquipmentType.T_ARMOR_PATCHWORK == at) { - boolean isMixed = panBasicInfo.useMixedTech(); - List armors = panArmor.getAllArmors(); - List> combos = new ArrayList<>(); - JPanel panel = new JPanel(new GridBagLayout()); - // Start with 1 to skip body - for (int loc = 1; loc < getTank().locations(); loc++) { - TechComboBox cbLoc = new TechComboBox<>(eq -> eq.getName()); - cbLoc.showTechBase(isMixed); - armors.forEach(a -> cbLoc.addItem(a)); - EquipmentType locArmor = EquipmentType.get(EquipmentType - .getArmorTypeName(getTank().getArmorType(loc), - TechConstants.isClan(getTank().getArmorTechLevel(loc)))); - cbLoc.setSelectedItem(locArmor); - combos.add(cbLoc); - JLabel label = new JLabel(getTank().getLocationName(loc)); - panel.add(label, GBC.std()); - panel.add(cbLoc, GBC.eol()); - } - JOptionPane.showMessageDialog(this, panel, - "Please choose the armor types", - JOptionPane.QUESTION_MESSAGE); - UnitUtil.removeISorArmorMounts(getTank(), false); - for (int loc = 0; loc < getTank().locations(); loc++) { - EquipmentType armor = (EquipmentType)combos.get(loc).getSelectedItem(); - getTank().setArmorTechLevel(armor.getTechLevel(panBasicInfo.getGameYear()), loc); - getTank().setArmorType(EquipmentType.getArmorType(armor), loc); - } - panArmor.removeListener(this); - panArmor.setFromEntity(getTank()); - panArmor.addListener(this); - } else { - getTank().setArmorTechLevel(aTechLevel); - getTank().setArmorType(at); - } - } - public void refreshSummary() { panSummary.refresh(); } @@ -320,7 +292,6 @@ public void updateTechLevel() { if (!getTank().hasPatchworkArmor()) { UnitUtil.removeISorArmorMounts(getTank(), false); } - createArmorMountsAndSetArmorType(getTank().getArmorType(0), getTank().getArmorTechLevel(0)); // If we have a large engine, a drop in tech level may make it unavailable and we will need // to reduce speed to a legal value. if (getTank().getEngine().hasFlag(Engine.LARGE_ENGINE) @@ -343,7 +314,8 @@ public void updateTechLevel() { panChassis.refresh(); panArmor.refresh(); panMovement.refresh(); - armor.resetArmorPoints(); + panArmorAllocation.setFromEntity(getTank()); + panPatchwork.setFromEntity(getTank()); addAllListeners(); } @@ -400,15 +372,18 @@ public void jumpTypeChanged(final EquipmentType jumpJet) { @Override public void armorTypeChanged(int at, int aTechLevel) { - if (!getTank().hasPatchworkArmor()) { - UnitUtil.removeISorArmorMounts(getTank(), false); - } - createArmorMountsAndSetArmorType(at, aTechLevel); - if (!getTank().hasPatchworkArmor()) { - armor.resetArmorPoints(); + UnitUtil.removeISorArmorMounts(getTank(), false); + if (at != EquipmentType.T_ARMOR_PATCHWORK) { + getTank().setArmorTechLevel(aTechLevel); + getTank().setArmorType(at); + panArmorAllocation.showPatchwork(false); + panPatchwork.setVisible(false); + } else { + panPatchwork.setFromEntity(getTank()); + panArmorAllocation.showPatchwork(true); + panPatchwork.setVisible(true); } - - armor.refresh(); + panArmorAllocation.setFromEntity(getTank()); panSummary.refresh(); refresh.refreshStatus(); refresh.refreshBuild(); @@ -418,9 +393,7 @@ public void armorTypeChanged(int at, int aTechLevel) { @Override public void armorTonnageChanged(double tonnage) { getTank().setArmorTonnage(Math.round(tonnage * 2) / 2.0); - armor.resetArmorPoints(); - - armor.refresh(); + panArmorAllocation.setFromEntity(getTank()); panSummary.refresh(); refresh.refreshStatus(); refresh.refreshPreview(); @@ -430,12 +403,11 @@ public void armorTonnageChanged(double tonnage) { public void maximizeArmor() { double maxArmor = UnitUtil.getMaximumArmorTonnage(getTank()); getTank().setArmorTonnage(maxArmor); - armor.resetArmorPoints(); panArmor.removeListener(this); panArmor.setFromEntity(getTank()); panArmor.addListener(this); - armor.refresh(); + panArmorAllocation.setFromEntity(getTank()); panSummary.refresh(); refresh.refreshStatus(); refresh.refreshPreview(); @@ -453,12 +425,11 @@ public void useRemainingTonnageArmor() { double maxArmor = Math.min(getTank().getArmorWeight() + remainingTonnage, UnitUtil.getMaximumArmorTonnage(getTank())); getTank().setArmorTonnage(maxArmor); - armor.resetArmorPoints(); panArmor.removeListener(this); panArmor.setFromEntity(getTank()); panArmor.addListener(this); - armor.refresh(); + panArmorAllocation.setFromEntity(getTank()); panSummary.refresh(); refresh.refreshStatus(); refresh.refreshPreview(); @@ -508,6 +479,7 @@ public void superheavyChanged(boolean superheavy) { } panChassis.refresh(); panSummary.refresh(); + panArmorAllocation.setFromEntity(getTank()); refresh.refreshPreview(); refresh.refreshBuild(); refresh.refreshStatus(); @@ -540,7 +512,9 @@ public void motiveChanged(EntityMovementMode motive) { panMovement.removeListener(this); panMovement.setFromEntity(getTank()); panMovement.addListener(this); - armor.refresh(); + panArmor.setFromEntity(getTank()); + panArmorAllocation.setFromEntity(getTank()); + panPatchwork.setFromEntity(getTank()); panSummary.refresh(); refresh.refreshBuild(); refresh.refreshStatus(); @@ -584,7 +558,7 @@ public void turretChanged(int turretConfig) { initTurretArmor(getTank().getLocTurret2()); } panChassis.setFromEntity(getTank()); - armor.refresh(); + panArmorAllocation.setFromEntity(getTank()); refresh.refreshBuild(); refresh.refreshPreview(); refresh.refreshStatus(); @@ -626,4 +600,121 @@ public void resetChassis() { refresh.refreshPreview(); refresh.refreshStatus(); } + + @Override + public void armorPointsChanged(int location, int front, int rear) { + getTank().initializeArmor(front, location); + if (panArmor.getArmorType() == EquipmentType.T_ARMOR_PATCHWORK) { + getTank().setArmorTonnage(panArmorAllocation.getTotalArmorWeight(getTank())); + } + panArmorAllocation.setFromEntity(getTank()); + refresh.refreshPreview(); + refresh.refreshSummary(); + refresh.refreshStatus(); + } + + @Override + public void autoAllocateArmor() { + int pointsToAllocate = UnitUtil.getArmorPoints(getTank(), getTank().getLabArmorTonnage()); + + for (int location = 0; location < getTank().locations(); location++) { + getTank().initializeArmor(0, location); + } + + // Discount body, as it's not armored + int numLocations = getTank().locations() - 1; + + // Make sure that the VTOL rotor has the 2 armor it should have + if (getTank().hasETypeFlag(Entity.ETYPE_VTOL)) { + getTank().initializeArmor(Math.min(pointsToAllocate, 2), VTOL.LOC_ROTOR); + pointsToAllocate -= 2; + numLocations--; + } + + // Determine the percentage of total armor each location should get + double otherPercent = 1.0 / numLocations; + double remainingPercent = 1.0 - (otherPercent * (numLocations - 2)); + // Front should be slightly more armored and rear slightly less + double frontPercent = remainingPercent * 0.6; + double rearPercent = remainingPercent * 0.4; + + // With the percentage of total for each location, assign armor + int allocatedPoints = 0; + int rear = Tank.LOC_REAR; + if (getTank().hasETypeFlag(Entity.ETYPE_SUPER_HEAVY_TANK)) { + rear = SuperHeavyTank.LOC_REAR; + } + for (int location = 1; location < getTank().locations(); location++) { + if ((getTank().hasETypeFlag(Entity.ETYPE_VTOL)) && (location == VTOL.LOC_ROTOR)) { + continue; + } + int armorToAllocate = 0; + if (location == Tank.LOC_FRONT) { + armorToAllocate = (int)(pointsToAllocate * frontPercent); + } else if (location == rear) { + armorToAllocate = (int)(pointsToAllocate * rearPercent); + } else { + armorToAllocate = (int)(pointsToAllocate * otherPercent); + } + getTank().initializeArmor(armorToAllocate, location); + allocatedPoints += armorToAllocate; + } + + // Because of rounding, may have leftover armor: allocate it to front + int unallocated = pointsToAllocate - allocatedPoints; + int currentFrontArmor = getTank().getOArmor(Tank.LOC_FRONT); + getTank().initializeArmor(currentFrontArmor + unallocated, Tank.LOC_FRONT); + + + panArmorAllocation.setFromEntity(getTank()); + refresh.refreshPreview(); + refresh.refreshSummary(); + refresh.refreshStatus(); + } + + @Override + public void patchworkChanged(int location, EquipmentType armor) { + UnitUtil.resetArmor(getAero(), location); + + //TODO: move this construction data out of the ui + int crits = 0; + switch (EquipmentType.getArmorType(armor)) { + case EquipmentType.T_ARMOR_STEALTH_VEHICLE: + case EquipmentType.T_ARMOR_LIGHT_FERRO: + case EquipmentType.T_ARMOR_FERRO_FIBROUS: + case EquipmentType.T_ARMOR_FERRO_FIBROUS_PROTO: + case EquipmentType.T_ARMOR_FERRO_LAMELLOR: + case EquipmentType.T_ARMOR_REFLECTIVE: + case EquipmentType.T_ARMOR_REACTIVE: + crits = 1; + break; + case EquipmentType.T_ARMOR_HEAVY_FERRO: + crits = 2; + break; + } + if (getAero().getEmptyCriticals(location) < crits) { + JOptionPane .showMessageDialog( + null, armor.getName() + + " does not fit in location " + + getAero().getLocationName(location) + + ". Resetting to Standard Armor in this location.", + "Error", + JOptionPane.INFORMATION_MESSAGE); + } else { + getAero().setArmorType(EquipmentType.getArmorType(armor), location); + getAero().setArmorTechLevel(armor.getTechLevel(getTechManager().getGameYear(), armor.isClan())); + for (; crits > 0; crits--) { + try { + getAero().addEquipment( new Mounted(getAero(), armor), location, false); + } catch (LocationFullException ex) { + } + } + } + panArmor.refresh(); + panArmorAllocation.setFromEntity(getAero()); + refresh.refreshBuild(); + refresh.refreshPreview(); + refresh.refreshSummary(); + refresh.refreshStatus(); + } } diff --git a/src/megameklab/com/ui/Vehicle/views/ArmorView.java b/src/megameklab/com/ui/Vehicle/views/ArmorView.java deleted file mode 100644 index c321ca457..000000000 --- a/src/megameklab/com/ui/Vehicle/views/ArmorView.java +++ /dev/null @@ -1,931 +0,0 @@ -/* - * MegaMekLab - Copyright (C) 2008 - * - * Original author - jtighe (torren@users.sourceforge.net) - * - * 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 megameklab.com.ui.Vehicle.views; - -import java.awt.Color; -import java.awt.Dimension; -import java.awt.GridBagConstraints; -import java.awt.GridBagLayout; -import java.awt.GridLayout; -import java.awt.Insets; -import java.awt.event.ActionEvent; -import java.awt.event.ActionListener; -import java.util.ArrayList; -import java.util.List; -import java.util.Vector; - -import javax.swing.BorderFactory; -import javax.swing.Box; -import javax.swing.BoxLayout; -import javax.swing.JButton; -import javax.swing.JLabel; -import javax.swing.JPanel; -import javax.swing.JSpinner; -import javax.swing.JTextField; -import javax.swing.SpinnerNumberModel; -import javax.swing.SwingConstants; -import javax.swing.border.TitledBorder; -import javax.swing.event.ChangeEvent; -import javax.swing.event.ChangeListener; - -import megamek.common.EquipmentType; -import megamek.common.Mech; -import megamek.common.SuperHeavyTank; -import megamek.common.Tank; -import megamek.common.VTOL; -import megamek.common.verifier.TestTank; -import megameklab.com.ui.EntitySource; -import megameklab.com.util.IView; -import megameklab.com.util.RefreshListener; -import megameklab.com.util.UnitUtil; - -public class ArmorView extends IView implements ChangeListener, ActionListener { - - /** - * - */ - private static final long serialVersionUID = 799195356642563937L; - - private JPanel mainPanel = new JPanel(); - - private JPanel frontPanel = new JPanel(); - private JPanel leftPanel = new JPanel(); - private JPanel rightPanel = new JPanel(); - private JPanel rearPanel = new JPanel(); - private JPanel turretPanel = new JPanel(); - private JPanel turret2Panel = new JPanel(); - private JPanel rearLeftPanel = new JPanel(); - private JPanel rearRightPanel = new JPanel(); - - public SpinnerNumberModel leftArmorModel = new SpinnerNumberModel(); - public SpinnerNumberModel rightArmorModel = new SpinnerNumberModel(); - public SpinnerNumberModel rearArmorModel = new SpinnerNumberModel(); - public SpinnerNumberModel turretArmorModel = new SpinnerNumberModel(); - public SpinnerNumberModel turret2ArmorModel = new SpinnerNumberModel(); - public SpinnerNumberModel rearLeftArmorModel = new SpinnerNumberModel(); - public SpinnerNumberModel rearRightArmorModel = new SpinnerNumberModel(); - public SpinnerNumberModel frontArmorModel = new SpinnerNumberModel(); - - private JSpinner leftArmorField = new JSpinner(leftArmorModel); - private JSpinner rightArmorField = new JSpinner(rightArmorModel); - private JSpinner rearArmorField = new JSpinner(rearArmorModel); - private JSpinner turretArmorField = new JSpinner(turretArmorModel); - private JSpinner turret2ArmorField = new JSpinner(turret2ArmorModel); - private JSpinner rearLeftArmorField = new JSpinner(rearLeftArmorModel); - private JSpinner rearRightArmorField = new JSpinner(rearRightArmorModel); - private JSpinner frontArmorField = new JSpinner(frontArmorModel); - - private List armorFieldList = new ArrayList(); - - private JLabel frontArmorMaxLabel = new JLabel("", SwingConstants.CENTER); - private JLabel leftArmorMaxLabel = new JLabel("", SwingConstants.CENTER); - private JLabel rightArmorMaxLabel = new JLabel("", SwingConstants.CENTER); - private JLabel rearArmorMaxLabel = new JLabel("", SwingConstants.CENTER); - private JLabel turretArmorMaxLabel = new JLabel("", SwingConstants.CENTER); - private JLabel turret2ArmorMaxLabel = new JLabel("", SwingConstants.CENTER); - private JLabel rearLeftArmorMaxLabel = new JLabel("", SwingConstants.CENTER); - private JLabel rearRightArmorMaxLabel = new JLabel("", SwingConstants.CENTER); - - private List armorMaxLabelList = new ArrayList(); - - private JLabel lblAllocatedArmor = new JLabel("Allocated Armor Points:"); - private JTextField valueAllocatedArmor = new JTextField(); - private JLabel lblUnallocatedArmor = new JLabel("Unallocated Armor Points:"); - private JTextField valueUnallocatedArmor = new JTextField(); - private JLabel lblCurrentArmor = new JLabel("Total Armor Points:"); - private JTextField valueCurrentArmor = new JTextField(); - private JLabel lblMaxArmor = new JLabel("Maximum Possible Armor Points:"); - private JTextField valueMaxArmor = new JTextField(); - private JLabel lblWastedArmor = new JLabel("Wasted Armor Points:"); - private JTextField valueWastedArmor = new JTextField(); - - private JLabel unallocatedPointsLabelPatchworkFront = new JLabel( - "Unalloc.:", SwingConstants.TRAILING); - private JLabel unallocatedPointsLabelPatchworkLeft = new JLabel( - "Unalloc.:", SwingConstants.TRAILING); - private JLabel unallocatedPointsLabelPatchworkTurret2 = new JLabel( - "Unalloc.:", SwingConstants.TRAILING); - private JLabel unallocatedPointsLabelPatchworkRearRight = new JLabel( - "Unalloc.:", SwingConstants.TRAILING); - private JLabel unallocatedPointsLabelPatchworkRearLeft = new JLabel( - "Unalloc.:", SwingConstants.TRAILING); - private JLabel unallocatedPointsLabelPatchworkRight = new JLabel( - "Unalloc.:", SwingConstants.TRAILING); - private JLabel unallocatedPointsLabelPatchworkRear = new JLabel( - "Unalloc.:", SwingConstants.TRAILING); - private JLabel unallocatedPointsLabelPatchworkTurret = new JLabel( - "Unalloc.:", SwingConstants.TRAILING); - private JLabel unallocatedPointsFieldFront = new JLabel(); - private JLabel unallocatedPointsFieldLeft = new JLabel(); - private JLabel unallocatedPointsFieldTurret2 = new JLabel(); - private JLabel unallocatedPointsFieldRearRight = new JLabel(); - private JLabel unallocatedPointsFieldRearLeft = new JLabel(); - private JLabel unallocatedPointsFieldRight = new JLabel(); - private JLabel unallocatedPointsFieldRear = new JLabel(); - private JLabel unallocatedPointsFieldTurret = new JLabel(); - - private int armorPoints; - private int wastedArmorPoints; - - private JButton allocateArmorButton = new JButton("Auto-Allocate Armor"); - - private RefreshListener refresh; - - public ArmorView(EntitySource eSource) { - super(eSource); - - setLayout(new GridLayout(1, 1)); - - mainPanel.setLayout(new GridBagLayout()); - GridBagConstraints gbc; - - frontPanel.setLayout(new BoxLayout(frontPanel, BoxLayout.Y_AXIS)); - leftPanel.setLayout(new BoxLayout(leftPanel, BoxLayout.Y_AXIS)); - rightPanel.setLayout(new BoxLayout(rightPanel, BoxLayout.Y_AXIS)); - turret2Panel.setLayout(new BoxLayout(turret2Panel, BoxLayout.Y_AXIS)); - rearRightPanel.setLayout(new BoxLayout(rearRightPanel, BoxLayout.Y_AXIS)); - rearLeftPanel.setLayout(new BoxLayout(rearLeftPanel, BoxLayout.Y_AXIS)); - rearPanel.setLayout(new BoxLayout(rearPanel, BoxLayout.Y_AXIS)); - turretPanel.setLayout(new BoxLayout(turretPanel, BoxLayout.Y_AXIS)); - - - if (getTank() instanceof SuperHeavyTank) { - gbc = new GridBagConstraints(); - gbc.gridx = 1; - gbc.gridy = 0; - mainPanel.add(frontPanel, gbc); - gbc.gridx = 0; - gbc.gridy = 1; - mainPanel.add(leftPanel, gbc); - gbc.gridx = 1; - mainPanel.add(turret2Panel, gbc); - gbc.gridx = 2; - mainPanel.add(rightPanel, gbc); - gbc.gridx = 0; - gbc.gridy = 2; - mainPanel.add(rearLeftPanel, gbc); - gbc.gridx = 1; - mainPanel.add(turretPanel, gbc); - gbc.gridx = 2; - mainPanel.add(rearRightPanel, gbc); - gbc.gridy = 3; - gbc.gridx = 1; - mainPanel.add(rearPanel, gbc); - - leftArmorField.setName(Integer.toString(SuperHeavyTank.LOC_FRONTLEFT)); - rightArmorField.setName(Integer.toString(SuperHeavyTank.LOC_FRONTRIGHT)); - rearArmorField.setName(Integer.toString(SuperHeavyTank.LOC_REAR)); - turretArmorField.setName(Integer.toString(SuperHeavyTank.LOC_TURRET)); - turret2ArmorField.setName(Integer.toString(SuperHeavyTank.LOC_TURRET_2)); - rearLeftArmorField.setName(Integer.toString(SuperHeavyTank.LOC_REARLEFT)); - rearRightArmorField.setName(Integer.toString(SuperHeavyTank.LOC_REARRIGHT)); - frontArmorField.setName(Integer.toString(Tank.LOC_FRONT)); - armorFieldList.add(leftArmorField); - armorFieldList.add(rightArmorField); - armorFieldList.add(rearArmorField); - armorFieldList.add(turretArmorField); - armorFieldList.add(turret2ArmorField); - armorFieldList.add(rearLeftArmorField); - armorFieldList.add(rearRightArmorField); - armorFieldList.add(frontArmorField); - } else { - gbc = new GridBagConstraints(); - gbc.gridx = 1; - gbc.gridy = 0; - mainPanel.add(frontPanel, gbc); - gbc.gridx = 0; - gbc.gridy = 1; - gbc.gridheight = 2; - mainPanel.add(leftPanel, gbc); - gbc.gridx = 1; - gbc.gridheight = 1; - mainPanel.add(turret2Panel, gbc); - gbc.gridx = 2; - gbc.gridheight = 2; - mainPanel.add(rightPanel, gbc); - gbc.gridx = 1; - gbc.gridy = 2; - gbc.gridheight = 1; - mainPanel.add(turretPanel, gbc); - gbc.gridy = 3; - gbc.gridx = 1; - mainPanel.add(rearPanel, gbc); - leftArmorField.setName(Integer.toString(Tank.LOC_LEFT)); - rightArmorField.setName(Integer.toString(Tank.LOC_RIGHT)); - rearArmorField.setName(Integer.toString(Tank.LOC_REAR)); - turretArmorField.setName(Integer.toString(Tank.LOC_TURRET)); - turret2ArmorField.setName(Integer.toString(Tank.LOC_TURRET_2)); - frontArmorField.setName(Integer.toString(Tank.LOC_FRONT)); - armorFieldList.add(leftArmorField); - armorFieldList.add(rightArmorField); - armorFieldList.add(rearArmorField); - armorFieldList.add(turretArmorField); - armorFieldList.add(turret2ArmorField); - armorFieldList.add(frontArmorField); - } - Dimension size = new Dimension(40, 25); - for (JSpinner spinner : armorFieldList) { - // you don't set the size of the jspinner, but rather its internal - // textfield - ((JSpinner.DefaultEditor) spinner.getEditor()).setSize(size); - ((JSpinner.DefaultEditor) spinner.getEditor()).setMaximumSize(size); - ((JSpinner.DefaultEditor) spinner.getEditor()) - .setPreferredSize(size); - ((JSpinner.DefaultEditor) spinner.getEditor()).setMinimumSize(size); - } - armorMaxLabelList.add(frontArmorMaxLabel); - armorMaxLabelList.add(leftArmorMaxLabel); - armorMaxLabelList.add(rightArmorMaxLabel); - armorMaxLabelList.add(rearArmorMaxLabel); - armorMaxLabelList.add(turretArmorMaxLabel); - armorMaxLabelList.add(turret2ArmorMaxLabel); - armorMaxLabelList.add(rearLeftArmorMaxLabel); - armorMaxLabelList.add(rearRightArmorMaxLabel); - - Dimension labelSize = new Dimension(40, 20); - for (JLabel label : armorMaxLabelList) { - label.setSize(labelSize); - label.setMaximumSize(labelSize); - label.setPreferredSize(labelSize); - label.setMinimumSize(labelSize); - } - - addAllListeners(); - - JPanel topPanel; - JPanel bottomPanel; - - synchronized (getTank()) { - for (int location = 1; location <= getTank().locations(); location++) { - - if (getTank() instanceof SuperHeavyTank) { - switch (location) { - case Tank.LOC_FRONT: - topPanel = new JPanel(new GridLayout(2, 0)); - topPanel.add(frontArmorField); - topPanel.add(frontArmorMaxLabel); - frontPanel.add(topPanel); - - bottomPanel = new JPanel(); - bottomPanel.add(unallocatedPointsLabelPatchworkFront); - bottomPanel.add(unallocatedPointsFieldFront); - - frontPanel.add(bottomPanel); - - frontPanel - .setBorder(BorderFactory.createTitledBorder( - null, getTank().getLocationAbbr(location), - TitledBorder.TOP, - TitledBorder.DEFAULT_POSITION)); - break; - case SuperHeavyTank.LOC_FRONTLEFT: - topPanel = new JPanel(new GridLayout(2, 0)); - topPanel.add(leftArmorField); - topPanel.add(leftArmorMaxLabel); - leftPanel.add(topPanel); - - bottomPanel = new JPanel(); - bottomPanel.add(unallocatedPointsLabelPatchworkLeft); - bottomPanel.add(unallocatedPointsFieldLeft); - leftPanel.add(bottomPanel); - - leftPanel.setBorder(BorderFactory.createTitledBorder( - null, getTank().getLocationAbbr(location), - TitledBorder.TOP, TitledBorder.DEFAULT_POSITION)); - break; - case SuperHeavyTank.LOC_FRONTRIGHT: - topPanel = new JPanel(new GridLayout(2, 0)); - topPanel.add(rightArmorField); - topPanel.add(rightArmorMaxLabel); - rightPanel.add(topPanel); - - bottomPanel = new JPanel(); - bottomPanel.add(unallocatedPointsLabelPatchworkRight); - bottomPanel.add(unallocatedPointsFieldRight); - rightPanel.add(bottomPanel); - - rightPanel.setBorder(BorderFactory.createTitledBorder( - null, getTank().getLocationAbbr(location), - TitledBorder.TOP, TitledBorder.DEFAULT_POSITION)); - break; - case SuperHeavyTank.LOC_REARRIGHT: - topPanel = new JPanel(new GridLayout(2, 0)); - topPanel.add(rearRightArmorField); - topPanel.add(rearRightArmorMaxLabel); - rearRightPanel.setBorder(BorderFactory.createTitledBorder( - null, getTank().getLocationAbbr(location), - TitledBorder.TOP, TitledBorder.DEFAULT_POSITION)); - rearRightPanel.add(topPanel); - - bottomPanel = new JPanel(); - bottomPanel.add(unallocatedPointsLabelPatchworkRearRight); - bottomPanel.add(unallocatedPointsFieldRearRight); - rearRightPanel.add(bottomPanel); - - break; - case SuperHeavyTank.LOC_TURRET_2: - topPanel = new JPanel(new GridLayout(2, 0)); - topPanel.add(turret2ArmorField); - topPanel.add(turret2ArmorMaxLabel); - turret2Panel.setBorder(BorderFactory.createTitledBorder( - null, getTank().getLocationAbbr(location), - TitledBorder.TOP, TitledBorder.DEFAULT_POSITION)); - turret2Panel.add(topPanel); - - bottomPanel = new JPanel(); - bottomPanel.add(unallocatedPointsLabelPatchworkTurret2); - bottomPanel.add(unallocatedPointsFieldTurret2); - turret2Panel.add(bottomPanel); - - break; - case SuperHeavyTank.LOC_REARLEFT: - topPanel = new JPanel(new GridLayout(2, 0)); - topPanel.add(rearLeftArmorField); - topPanel.add(rearLeftArmorMaxLabel); - rearLeftPanel.setBorder(BorderFactory.createTitledBorder( - null, getTank().getLocationAbbr(location), - TitledBorder.TOP, TitledBorder.DEFAULT_POSITION)); - rearLeftPanel.add(topPanel); - - bottomPanel = new JPanel(); - bottomPanel.add(unallocatedPointsLabelPatchworkRearLeft); - bottomPanel.add(unallocatedPointsFieldRearLeft); - rearLeftPanel.add(bottomPanel); - - break; - case SuperHeavyTank.LOC_REAR: - topPanel = new JPanel(new GridLayout(2, 0)); - topPanel.add(rearArmorField); - topPanel.add(rearArmorMaxLabel); - rearPanel.add(topPanel); - - bottomPanel = new JPanel(); - bottomPanel.add(unallocatedPointsLabelPatchworkRear); - bottomPanel.add(unallocatedPointsFieldRear); - rearPanel.add(bottomPanel); - - rearPanel.setBorder(BorderFactory.createTitledBorder( - null, getTank().getLocationAbbr(location), - TitledBorder.TOP, TitledBorder.DEFAULT_POSITION)); - break; - case SuperHeavyTank.LOC_TURRET: - topPanel = new JPanel(new GridLayout(2, 0)); - topPanel.add(turretArmorField); - topPanel.add(turretArmorMaxLabel); - turretPanel.add(topPanel); - - bottomPanel = new JPanel(); - bottomPanel.add(unallocatedPointsLabelPatchworkTurret); - bottomPanel.add(unallocatedPointsFieldTurret); - turretPanel.add(bottomPanel); - - turretPanel.setBorder(BorderFactory.createTitledBorder( - null, getTank().getLocationAbbr(location), - TitledBorder.TOP, TitledBorder.DEFAULT_POSITION)); - break; - } - } else { - switch (location) { - case Tank.LOC_FRONT: - topPanel = new JPanel(new GridLayout(2, 0)); - topPanel.add(frontArmorField); - topPanel.add(frontArmorMaxLabel); - frontPanel.add(topPanel); - - bottomPanel = new JPanel(); - bottomPanel.add(unallocatedPointsLabelPatchworkFront); - bottomPanel.add(unallocatedPointsFieldFront); - - frontPanel.add(bottomPanel); - - frontPanel - .setBorder(BorderFactory.createTitledBorder( - null, getTank().getLocationAbbr(location), - TitledBorder.TOP, - TitledBorder.DEFAULT_POSITION)); - break; - case Tank.LOC_LEFT: - topPanel = new JPanel(new GridLayout(2, 0)); - topPanel.add(leftArmorField); - topPanel.add(leftArmorMaxLabel); - leftPanel.add(topPanel); - - bottomPanel = new JPanel(); - bottomPanel.add(unallocatedPointsLabelPatchworkLeft); - bottomPanel.add(unallocatedPointsFieldLeft); - leftPanel.add(bottomPanel); - - leftPanel.setBorder(BorderFactory.createTitledBorder( - null, getTank().getLocationAbbr(location), - TitledBorder.TOP, TitledBorder.DEFAULT_POSITION)); - break; - case Tank.LOC_RIGHT: - topPanel = new JPanel(new GridLayout(2, 0)); - topPanel.add(rightArmorField); - topPanel.add(rightArmorMaxLabel); - rightPanel.add(topPanel); - - bottomPanel = new JPanel(); - bottomPanel.add(unallocatedPointsLabelPatchworkRight); - bottomPanel.add(unallocatedPointsFieldRight); - rightPanel.add(bottomPanel); - - rightPanel.setBorder(BorderFactory.createTitledBorder( - null, getTank().getLocationAbbr(location), - TitledBorder.TOP, TitledBorder.DEFAULT_POSITION)); - break; - case Tank.LOC_TURRET_2: - topPanel = new JPanel(new GridLayout(2, 0)); - topPanel.add(turret2ArmorField); - topPanel.add(turret2ArmorMaxLabel); - turret2Panel.setBorder(BorderFactory.createTitledBorder( - null, getTank().getLocationAbbr(location), - TitledBorder.TOP, TitledBorder.DEFAULT_POSITION)); - turret2Panel.add(topPanel); - - bottomPanel = new JPanel(); - bottomPanel.add(unallocatedPointsLabelPatchworkTurret2); - bottomPanel.add(unallocatedPointsFieldTurret2); - turret2Panel.add(bottomPanel); - - break; - case Tank.LOC_REAR: - topPanel = new JPanel(new GridLayout(2, 0)); - topPanel.add(rearArmorField); - topPanel.add(rearArmorMaxLabel); - rearPanel.add(topPanel); - - bottomPanel = new JPanel(); - bottomPanel.add(unallocatedPointsLabelPatchworkRear); - bottomPanel.add(unallocatedPointsFieldRear); - rearPanel.add(bottomPanel); - - rearPanel.setBorder(BorderFactory.createTitledBorder( - null, getTank().getLocationAbbr(location), - TitledBorder.TOP, TitledBorder.DEFAULT_POSITION)); - break; - case Tank.LOC_TURRET: - topPanel = new JPanel(new GridLayout(2, 0)); - topPanel.add(turretArmorField); - topPanel.add(turretArmorMaxLabel); - turretPanel.add(topPanel); - - bottomPanel = new JPanel(); - bottomPanel.add(unallocatedPointsLabelPatchworkTurret); - bottomPanel.add(unallocatedPointsFieldTurret); - turretPanel.add(bottomPanel); - - turretPanel.setBorder(BorderFactory.createTitledBorder( - null, getTank().getLocationAbbr(location), - TitledBorder.TOP, TitledBorder.DEFAULT_POSITION)); - break; - } - } - - } - } - - JPanel totalArmorPanel = new JPanel(); - - Vector valueFields = new Vector(); - valueFields.add(valueUnallocatedArmor); - valueFields.add(valueAllocatedArmor); - valueFields.add(valueCurrentArmor); - valueFields.add(valueMaxArmor); - valueFields.add(valueWastedArmor); - - Dimension valueSize = new Dimension(45, 20); - for (JTextField field : valueFields) { - field.setEditable(false); - field.setSize(valueSize); - field.setPreferredSize(valueSize); - field.setMinimumSize(valueSize); - field.setMaximumSize(valueSize); - field.setHorizontalAlignment(SwingConstants.RIGHT); - } - - totalArmorPanel.setLayout(new GridBagLayout()); - gbc = new GridBagConstraints(); - gbc.gridx = 0; - gbc.gridy = 0; - gbc.insets = new Insets(2, 2, 2, 2); - gbc.anchor = GridBagConstraints.WEST; - totalArmorPanel.add(Box.createVerticalStrut(11), gbc); - gbc.gridy++; - totalArmorPanel.add(lblUnallocatedArmor, gbc); - gbc.gridx = 1; - totalArmorPanel.add(valueUnallocatedArmor, gbc); - gbc.gridx = 0; - gbc.gridy++; - totalArmorPanel.add(lblAllocatedArmor, gbc); - gbc.gridx = 1; - totalArmorPanel.add(valueAllocatedArmor, gbc); - gbc.gridx = 0; - gbc.gridy++; - totalArmorPanel.add(lblCurrentArmor, gbc); - gbc.gridx = 1; - totalArmorPanel.add(valueCurrentArmor, gbc); - gbc.gridx = 0; - gbc.gridy++; - totalArmorPanel.add(lblMaxArmor, gbc); - gbc.gridx = 1; - totalArmorPanel.add(valueMaxArmor, gbc); - gbc.gridx = 0; - gbc.gridy++; - totalArmorPanel.add(lblWastedArmor, gbc); - gbc.gridx = 1; - totalArmorPanel.add(valueWastedArmor, gbc); - gbc.gridx = 0; - gbc.gridy++; - gbc.gridwidth = 2; - totalArmorPanel.add(Box.createVerticalStrut(12), gbc); - gbc.gridy++; - gbc.anchor = GridBagConstraints.CENTER; - totalArmorPanel.add(allocateArmorButton, gbc); - - gbc = new GridBagConstraints(); - gbc.gridx = 0; - gbc.gridy = 4; - gbc.gridwidth = 5; - gbc.fill = GridBagConstraints.NONE; - gbc.anchor = GridBagConstraints.CENTER; - mainPanel.add(totalArmorPanel, gbc); - this.add(mainPanel); - - resetArmorPoints(); - } - - private void addAllListeners() { - allocateArmorButton.addActionListener(this); - for (JSpinner spinner : armorFieldList) { - spinner.addChangeListener(this); - } - } - - private void removeAllListeners() { - allocateArmorButton.removeActionListener(this); - for (JSpinner spinner : armorFieldList) { - spinner.removeChangeListener(this); - } - } - - public void refresh() { - turretPanel.setVisible(!getTank().hasNoTurret()||(getTank() instanceof VTOL)); - turret2Panel.setVisible(!getTank().hasNoDualTurret()|| ((getTank() instanceof VTOL) && !getTank().hasNoTurret())); - removeAllListeners(); - int maxArmor = armorPoints; - if (getTank().hasPatchworkArmor()) { - maxArmor = (int)Math.floor((getTank().getWeight() * 3.5) + 40); - } - for (int location = 0; location < getTank().locations(); location++) { - - if (getTank() instanceof SuperHeavyTank) { - switch (location) { - case Tank.LOC_FRONT: - frontArmorModel.setValue(Math.min(maxArmor, getTank().getArmor(location))); - frontArmorModel.setMaximum(maxArmor); - frontArmorModel.setStepSize(1); - frontArmorModel.setMinimum(0); - frontArmorMaxLabel.setText("max: " - + Integer.toString(maxArmor)); - break; - case SuperHeavyTank.LOC_FRONTLEFT: - leftArmorModel.setValue(Math.min(maxArmor, - getTank().getArmor(location))); - leftArmorModel.setMaximum(maxArmor); - leftArmorModel.setStepSize(1); - leftArmorModel.setMinimum(0); - leftArmorMaxLabel.setText("max: " - + Integer.toString(maxArmor)); - break; - case SuperHeavyTank.LOC_FRONTRIGHT: - rightArmorModel.setValue(Math.min(maxArmor, - getTank().getArmor(location))); - rightArmorModel.setMaximum(maxArmor); - rightArmorModel.setStepSize(1); - rightArmorModel.setMinimum(0); - rightArmorMaxLabel.setText("max: " - + Integer.toString(maxArmor)); - break; - case SuperHeavyTank.LOC_REARRIGHT: - rearRightArmorModel.setValue(Math.min(maxArmor, - getTank().getArmor(location))); - rearRightArmorModel.setMaximum(maxArmor); - rearRightArmorModel.setStepSize(1); - rearRightArmorModel.setMinimum(0); - rearRightArmorMaxLabel.setText("max: " - + Integer.toString(maxArmor)); - break; - case SuperHeavyTank.LOC_TURRET_2: - turret2ArmorModel.setValue(Math.min(maxArmor, - getTank().getArmor(location))); - turret2ArmorModel.setMaximum(maxArmor); - turret2ArmorModel.setStepSize(1); - turret2ArmorModel.setMinimum(0); - turret2ArmorMaxLabel.setText("max: " - + Integer.toString(maxArmor)); - break; - case SuperHeavyTank.LOC_REARLEFT: - rearLeftArmorModel.setValue(Math.min(maxArmor, - getTank().getArmor(location))); - rearLeftArmorModel.setMaximum(maxArmor); - rearLeftArmorModel.setStepSize(1); - rearLeftArmorModel.setMinimum(0); - - rearLeftArmorMaxLabel.setText("max: " - + Integer.toString(maxArmor)); - break; - case SuperHeavyTank.LOC_REAR: - rearArmorModel.setValue(Math.min(maxArmor, - getTank().getArmor(location))); - rearArmorModel.setMaximum(maxArmor); - rearArmorModel.setStepSize(1); - rearArmorModel.setMinimum(0); - rearArmorMaxLabel.setText("max: " - + Integer.toString(maxArmor)); - break; - case SuperHeavyTank.LOC_TURRET: - turretArmorModel.setValue(Math.min(maxArmor, - getTank().getArmor(location))); - turretArmorModel.setMaximum(maxArmor); - turretArmorModel.setStepSize(1); - turretArmorModel.setMinimum(0); - turretArmorMaxLabel.setText("max: " - + Integer.toString(maxArmor)); - break; - } - } else { - switch (location) { - case Tank.LOC_FRONT: - frontArmorModel.setValue(Math.min(maxArmor, getTank().getArmor(location))); - frontArmorModel.setMaximum(maxArmor); - frontArmorModel.setStepSize(1); - frontArmorModel.setMinimum(0); - frontArmorMaxLabel.setText("max: " - + Integer.toString(maxArmor)); - break; - case Tank.LOC_LEFT: - leftArmorModel.setValue(Math.min(maxArmor, - getTank().getArmor(location))); - leftArmorModel.setMaximum(maxArmor); - leftArmorModel.setStepSize(1); - leftArmorModel.setMinimum(0); - leftArmorMaxLabel.setText("max: " - + Integer.toString(maxArmor)); - break; - case Tank.LOC_RIGHT: - rightArmorModel.setValue(Math.min(maxArmor, - getTank().getArmor(location))); - rightArmorModel.setMaximum(maxArmor); - rightArmorModel.setStepSize(1); - rightArmorModel.setMinimum(0); - rightArmorMaxLabel.setText("max: " - + Integer.toString(maxArmor)); - break; - case Tank.LOC_TURRET_2: - turret2ArmorModel.setValue(Math.min(maxArmor, - getTank().getArmor(location))); - turret2ArmorModel.setMaximum(maxArmor); - turret2ArmorModel.setStepSize(1); - turret2ArmorModel.setMinimum(0); - turret2ArmorMaxLabel.setText("max: " - + Integer.toString(maxArmor)); - break; - case Tank.LOC_REAR: - rearArmorModel.setValue(Math.min(maxArmor, - getTank().getArmor(location))); - rearArmorModel.setMaximum(maxArmor); - rearArmorModel.setStepSize(1); - rearArmorModel.setMinimum(0); - rearArmorMaxLabel.setText("max: " - + Integer.toString(maxArmor)); - break; - case Tank.LOC_TURRET: - turretArmorModel.setValue(Math.min(maxArmor, - getTank().getArmor(location))); - if (getTank() instanceof VTOL){ - turretArmorModel - .setMaximum(TestTank.VTOL_MAX_ROTOR_ARMOR); - } else { - turretArmorModel.setMaximum(maxArmor); - } - turretArmorModel.setStepSize(1); - turretArmorModel.setMinimum(0); - turretArmorMaxLabel.setText("max: " - + Integer.toString(maxArmor)); - break; - } - } - } - - // unallocated armorpoints - if (getTank().hasPatchworkArmor()) { - valueUnallocatedArmor.setVisible(false); - lblUnallocatedArmor.setVisible(false); - valueAllocatedArmor.setVisible(false); - lblAllocatedArmor.setVisible(false); - valueWastedArmor.setVisible(false); - lblWastedArmor.setVisible(false); - allocateArmorButton.setVisible(false); - unallocatedPointsLabelPatchworkFront.setVisible(true); - unallocatedPointsLabelPatchworkLeft.setVisible(true); - unallocatedPointsLabelPatchworkTurret2.setVisible(true); - unallocatedPointsLabelPatchworkRearRight.setVisible(true); - unallocatedPointsLabelPatchworkRearLeft.setVisible(true); - unallocatedPointsLabelPatchworkRight.setVisible(true); - unallocatedPointsLabelPatchworkRear.setVisible(true); - unallocatedPointsLabelPatchworkTurret.setVisible(true); - unallocatedPointsFieldFront.setVisible(true); - unallocatedPointsFieldLeft.setVisible(true); - unallocatedPointsFieldTurret2.setVisible(true); - unallocatedPointsFieldRearRight.setVisible(true); - unallocatedPointsFieldRearLeft.setVisible(true); - unallocatedPointsFieldRight.setVisible(true); - unallocatedPointsFieldRear.setVisible(true); - unallocatedPointsFieldTurret.setVisible(true); - unallocatedPointsFieldFront.setText(Integer.toString(UnitUtil - .getArmorPoints(getTank(), Tank.LOC_FRONT, - getTank().getArmorWeight(Tank.LOC_FRONT)) - - getTank().getOArmor(Mech.LOC_HEAD))); - unallocatedPointsFieldLeft.setText(Integer.toString(UnitUtil - .getArmorPoints(getTank(), getTank() instanceof SuperHeavyTank?SuperHeavyTank.LOC_FRONTLEFT:Tank.LOC_LEFT, - getTank().getArmorWeight(getTank() instanceof SuperHeavyTank?SuperHeavyTank.LOC_FRONTLEFT:Tank.LOC_LEFT)) - - getTank().getOArmor(getTank() instanceof SuperHeavyTank?SuperHeavyTank.LOC_FRONTLEFT:Tank.LOC_LEFT))); - unallocatedPointsFieldTurret2.setText(Integer.toString(UnitUtil - .getArmorPoints(getTank(), getTank() instanceof SuperHeavyTank?SuperHeavyTank.LOC_TURRET_2:Tank.LOC_TURRET_2, - getTank().getArmorWeight(getTank() instanceof SuperHeavyTank?SuperHeavyTank.LOC_TURRET_2:Tank.LOC_TURRET_2)) - - getTank().getOArmor(getTank() instanceof SuperHeavyTank?SuperHeavyTank.LOC_TURRET_2:Tank.LOC_TURRET_2))); - unallocatedPointsFieldRearRight.setText(Integer.toString(UnitUtil - .getArmorPoints(getTank(), SuperHeavyTank.LOC_REARRIGHT, - getTank().getArmorWeight(SuperHeavyTank.LOC_REARRIGHT)) - - getTank().getOArmor(SuperHeavyTank.LOC_REARRIGHT))); - unallocatedPointsFieldRearLeft.setText(Integer.toString(UnitUtil - .getArmorPoints(getTank(), SuperHeavyTank.LOC_REARLEFT, - getTank().getArmorWeight(SuperHeavyTank.LOC_REARLEFT)) - - getTank().getOArmor(SuperHeavyTank.LOC_REARLEFT))); - unallocatedPointsFieldRight.setText(Integer.toString(UnitUtil - .getArmorPoints(getTank(), getTank() instanceof SuperHeavyTank?SuperHeavyTank.LOC_FRONTRIGHT:Tank.LOC_RIGHT, - getTank().getArmorWeight(getTank() instanceof SuperHeavyTank?SuperHeavyTank.LOC_FRONTRIGHT:Tank.LOC_RIGHT)) - - getTank().getOArmor(getTank() instanceof SuperHeavyTank?SuperHeavyTank.LOC_FRONTRIGHT:Tank.LOC_RIGHT))); - unallocatedPointsFieldRear.setText(Integer.toString(UnitUtil - .getArmorPoints(getTank(), getTank() instanceof SuperHeavyTank?SuperHeavyTank.LOC_REAR:Tank.LOC_REAR, - getTank().getArmorWeight(getTank() instanceof SuperHeavyTank?SuperHeavyTank.LOC_REAR:Tank.LOC_REAR)) - - getTank().getOArmor(getTank() instanceof SuperHeavyTank?SuperHeavyTank.LOC_REAR:Tank.LOC_REAR))); - unallocatedPointsFieldTurret.setText(Integer.toString(UnitUtil - .getArmorPoints(getTank(), getTank() instanceof SuperHeavyTank?SuperHeavyTank.LOC_TURRET:Tank.LOC_TURRET, - getTank().getArmorWeight(getTank() instanceof SuperHeavyTank?SuperHeavyTank.LOC_TURRET:Tank.LOC_TURRET)) - - getTank().getOArmor(getTank() instanceof SuperHeavyTank?SuperHeavyTank.LOC_TURRET:Tank.LOC_TURRET))); - } else { - valueUnallocatedArmor.setVisible(true); - lblUnallocatedArmor.setVisible(true); - valueAllocatedArmor.setVisible(true); - lblAllocatedArmor.setVisible(true); - allocateArmorButton.setVisible(true); - valueWastedArmor.setVisible(true); - lblWastedArmor.setVisible(true); - unallocatedPointsLabelPatchworkFront.setVisible(false); - unallocatedPointsLabelPatchworkLeft.setVisible(false); - unallocatedPointsLabelPatchworkTurret2.setVisible(false); - unallocatedPointsLabelPatchworkRearRight.setVisible(false); - unallocatedPointsLabelPatchworkRearLeft.setVisible(false); - unallocatedPointsLabelPatchworkRight.setVisible(false); - unallocatedPointsLabelPatchworkRear.setVisible(false); - unallocatedPointsLabelPatchworkTurret.setVisible(false); - unallocatedPointsFieldFront.setVisible(false); - unallocatedPointsFieldLeft.setVisible(false); - unallocatedPointsFieldTurret2.setVisible(false); - unallocatedPointsFieldRearRight.setVisible(false); - unallocatedPointsFieldRearLeft.setVisible(false); - unallocatedPointsFieldRight.setVisible(false); - unallocatedPointsFieldRear.setVisible(false); - unallocatedPointsFieldTurret.setVisible(false); - } - valueAllocatedArmor.setText(Integer.toString(getTank().getTotalOArmor())); - valueUnallocatedArmor.setText(Integer.toString(armorPoints - - getTank().getTotalOArmor())); - if (armorPoints != getTank().getTotalOArmor()) { - valueUnallocatedArmor.setForeground(Color.RED); - lblUnallocatedArmor.setForeground(Color.RED); - } else { - valueUnallocatedArmor.setForeground(Color.BLACK); - lblUnallocatedArmor.setForeground(Color.BLACK); - } - valueCurrentArmor.setText(Integer.toString(armorPoints)); - valueMaxArmor - .setText(Integer.toString(maxArmor)); - valueWastedArmor.setText(Integer.toString(wastedArmorPoints)); - - addAllListeners(); - } - - public void addRefreshedListener(RefreshListener l) { - refresh = l; - } - - public void allocateArmor() { - int pointsToAllocate = armorPoints; - - for (int location = 0; location < getTank().locations(); location++) { - getTank().initializeArmor(0, location); - } - - // Make sure that the VTOL rotor has the 2 armor it should have - if (getTank() instanceof VTOL) { - getTank().initializeArmor(Math.min(pointsToAllocate, 2), VTOL.LOC_ROTOR); - pointsToAllocate -= 2; - } - - int numLocations = getTank().locations(); - // Discount rotor for VTOLs - if (getTank() instanceof VTOL) { - numLocations--; - } - // Discount body, as it's not armored - numLocations--; - - // Determine the percentage of total armor each location should get - double otherPercent = 1.0 / numLocations; - double remainingPercent = 1.0 - (otherPercent * (numLocations - 2)); - // Front should be slightly more armored and rear slightly less - double frontPercent = remainingPercent * 0.6; - double rearPercent = remainingPercent * 0.4; - - // With the percentage of total for each location, assign armor - int allocatedPoints = 0; - for (int location = 1; location < getTank().locations(); location++) { - if ((getTank() instanceof VTOL) && (location == VTOL.LOC_ROTOR)) { - continue; - } - int armorToAllocate = 0; - if (location == Tank.LOC_FRONT) { - armorToAllocate = (int)(pointsToAllocate * frontPercent); - } else if (location == Tank.LOC_REAR) { - armorToAllocate = (int)(pointsToAllocate * rearPercent); - } else { - armorToAllocate = (int)(pointsToAllocate * otherPercent); - } - getTank().initializeArmor(armorToAllocate, location); - allocatedPoints += armorToAllocate; - } - - // Because of rounding, may have leftover armor: allocate it to front - int unallocated = pointsToAllocate - allocatedPoints; - int currentFrontArmor = getTank().getOArmor(Tank.LOC_FRONT); - getTank().initializeArmor(currentFrontArmor + unallocated, Tank.LOC_FRONT); - } - - public void stateChanged(ChangeEvent e) { - removeAllListeners(); - JSpinner field = (JSpinner) e.getSource(); - int location = Integer.parseInt(field.getName()); - int value = (Integer) field.getModel().getValue(); - getTank().initializeArmor(value, location); - if (getTank().hasPatchworkArmor()) { - setArmorPoints(getTank().getTotalArmor()); - } - if (refresh != null) { - addAllListeners(); - refresh.refreshStructure(); - removeAllListeners(); - refresh.refreshStatus(); - } - addAllListeners(); - } - - public void setArmorPoints(int points) { - int maxArmor = (int) Math.floor((getTank().getWeight() * 3.5) +40); - wastedArmorPoints = Math.max(points - maxArmor, 0); - armorPoints = Math.min(maxArmor, points); - } - - @Override - public void actionPerformed(ActionEvent e) { - removeAllListeners(); - if (e.getSource().equals(allocateArmorButton)) { - allocateArmor(); - } - addAllListeners(); - refresh.refreshAll(); - } - - public void resetArmorPoints() { - double armorPerTon = 16.0 * EquipmentType.getArmorPointMultiplier( - getTank().getArmorType(0), getTank().getArmorTechLevel(0)); - setArmorPoints((int) Math - .floor(getTank().getLabArmorTonnage() * armorPerTon)); - } -} \ No newline at end of file diff --git a/src/megameklab/com/ui/view/AeroFuelView.java b/src/megameklab/com/ui/view/AeroFuelView.java index 3c28f5615..778421ce5 100644 --- a/src/megameklab/com/ui/view/AeroFuelView.java +++ b/src/megameklab/com/ui/view/AeroFuelView.java @@ -32,6 +32,7 @@ import megamek.common.Entity; import megamek.common.util.EncodeControl; import megamek.common.verifier.TestAero; +import megameklab.com.ui.view.listeners.AeroBuildListener; /** * Structure tab panel for aero unit fuel @@ -39,21 +40,18 @@ * @author Neoancient * */ -public class AeroFuelView extends MainUIView implements ChangeListener { +public class AeroFuelView extends BuildView implements ChangeListener { /** * */ private static final long serialVersionUID = -3321986392656071192L; - public interface FuelListener { - void fuelTonnageChanged(double tonnage); - } - List listeners = new CopyOnWriteArrayList<>(); - public void addListener(FuelListener l) { + List listeners = new CopyOnWriteArrayList<>(); + public void addListener(AeroBuildListener l) { listeners.add(l); } - public void removeListener(FuelListener l) { + public void removeListener(AeroBuildListener l) { listeners.remove(l); } diff --git a/src/megameklab/com/ui/view/ArmorAllocationView.java b/src/megameklab/com/ui/view/ArmorAllocationView.java new file mode 100644 index 000000000..ed1f48b6a --- /dev/null +++ b/src/megameklab/com/ui/view/ArmorAllocationView.java @@ -0,0 +1,316 @@ +/* + * MegaMekLab - Copyright (C) 2017 - The MegaMek Team + * + * 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 megameklab.com.ui.view; + +import java.awt.Color; +import java.awt.GridBagConstraints; +import java.awt.GridBagLayout; +import java.util.ArrayList; +import java.util.List; +import java.util.ResourceBundle; +import java.util.concurrent.CopyOnWriteArrayList; + +import javax.swing.Box; +import javax.swing.BoxLayout; +import javax.swing.JButton; +import javax.swing.JLabel; +import javax.swing.JPanel; +import javax.swing.JTextField; +import javax.swing.SwingConstants; + +import megamek.common.Aero; +import megamek.common.Entity; +import megamek.common.ITechManager; +import megamek.common.Mech; +import megamek.common.SuperHeavyTank; +import megamek.common.Tank; +import megamek.common.VTOL; +import megamek.common.util.EncodeControl; +import megameklab.com.ui.view.listeners.BuildListener; +import megameklab.com.util.UnitUtil; + +/** + * Panel for allocating armor to various locations on an Entity. The assignment of armor values for specific + * locations is delegated to ArmorLocationView. This class handles positioning of the subviews to approximate + * the position on the unit and tracking the total amount of armor allocated. + * + * @author Neoancient + * + */ +public class ArmorAllocationView extends BuildView implements + ArmorLocationView.ArmorLocationListener { + + /** + * + */ + private static final long serialVersionUID = 1707528067499186372L; + + private final List listeners = new CopyOnWriteArrayList<>(); + public void addListener(BuildListener l) { + listeners.add(l); + } + public void removeListener(BuildListener l) { + listeners.remove(l); + } + + private static final int[][] MEK_LAYOUT = { + {-1, -1, Mech.LOC_HEAD, -1, -1}, + {Mech.LOC_LARM, Mech.LOC_LT, Mech.LOC_CT, Mech.LOC_RT, Mech.LOC_RARM}, + {-1, Mech.LOC_LLEG, Mech.LOC_CLEG, Mech.LOC_RLEG, -1} + }; + + private static final int[][] TANK_LAYOUT = { + {-1, Tank.LOC_FRONT, -1}, + {Tank.LOC_LEFT, Tank.LOC_TURRET, Tank.LOC_RIGHT}, + {-1, Tank.LOC_TURRET_2, -1}, + {-1, Tank.LOC_REAR, -1} + }; + + private static final int[][] SH_TANK_LAYOUT = { + {-1, SuperHeavyTank.LOC_FRONT, -1}, + {SuperHeavyTank.LOC_FRONTLEFT, SuperHeavyTank.LOC_TURRET, SuperHeavyTank.LOC_FRONTRIGHT}, + {SuperHeavyTank.LOC_REARLEFT, SuperHeavyTank.LOC_TURRET_2, SuperHeavyTank.LOC_REARRIGHT}, + {-1, SuperHeavyTank.LOC_REAR, -1} + }; + + private static final int[][] VTOL_LAYOUT = { + {-1, VTOL.LOC_FRONT, -1}, + {VTOL.LOC_LEFT, VTOL.LOC_ROTOR, VTOL.LOC_RIGHT}, + {-1, VTOL.LOC_TURRET, -1}, + {-1, VTOL.LOC_REAR, -1} + }; + + private static final int[][] AERODYNE_LAYOUT = { + {-1, Aero.LOC_NOSE, -1}, + {Aero.LOC_LWING, -1, Aero.LOC_RWING}, + {-1, Aero.LOC_AFT, -1} + }; + + private final List locationViews = new ArrayList<>(); + private final JPanel panLocations = new JPanel(); + private final JTextField txtUnallocated = new JTextField(); + private final JTextField txtAllocated = new JTextField(); + private final JTextField txtTotal = new JTextField(); + private final JTextField txtMaxPossible = new JTextField(); + private final JTextField txtWasted = new JTextField(); + private final JButton btnAutoAllocate = new JButton(); + + private long entitytype; + private int armorPoints = 0; + private int maxArmorPoints = 0; + private int wastedPoints = 0; + private boolean showPatchwork = false; + private String tooltipFormat; + + public ArmorAllocationView(ITechManager techManager, long entitytype) { + this.entitytype = entitytype; + initUI(); + } + + private void initUI() { + ResourceBundle resourceMap = ResourceBundle.getBundle("megameklab.resources.Views", new EncodeControl()); //$NON-NLS-1$ + tooltipFormat = resourceMap.getString("ArmorAllocationView.locationTooltip.format"); + setLayout(new GridBagLayout()); + GridBagConstraints gbc = new GridBagConstraints(); + + panLocations.setLayout(new GridBagLayout()); + gbc.gridx = 0; + gbc.gridy = 0; + gbc.gridwidth = GridBagConstraints.REMAINDER; + add(panLocations, gbc); + + updateLayout(); + gbc.gridy++; + + gbc.gridwidth = 1; + add(new JLabel(resourceMap.getString("ArmorAllocationView.txtUnallocated.text"), SwingConstants.RIGHT), gbc); //$NON-NLS-1$ + gbc.gridx = 1; + txtUnallocated.setEditable(false); + setFieldSize(txtUnallocated, editorSize); + add(txtUnallocated, gbc); + + gbc.gridx = 0; + gbc.gridy++; + add(new JLabel(resourceMap.getString("ArmorAllocationView.txtAllocated.text"), SwingConstants.RIGHT), gbc); //$NON-NLS-1$ + gbc.gridx = 1; + txtAllocated.setEditable(false); + setFieldSize(txtAllocated, editorSize); + add(txtAllocated, gbc); + + gbc.gridx = 0; + gbc.gridy++; + add(new JLabel(resourceMap.getString("ArmorAllocationView.txtTotal.text"), SwingConstants.RIGHT), gbc); //$NON-NLS-1$ + gbc.gridx = 1; + txtTotal.setEditable(false); + setFieldSize(txtTotal, editorSize); + add(txtTotal, gbc); + + gbc.gridx = 0; + gbc.gridy++; + add(new JLabel(resourceMap.getString("ArmorAllocationView.txtMaxPossible.text"), SwingConstants.RIGHT), gbc); //$NON-NLS-1$ + gbc.gridx = 1; + txtMaxPossible.setEditable(false); + setFieldSize(txtMaxPossible, editorSize); + add(txtMaxPossible, gbc); + + gbc.gridx = 0; + gbc.gridy++; + add(new JLabel(resourceMap.getString("ArmorAllocationView.txtWasted.text"), SwingConstants.RIGHT), gbc); //$NON-NLS-1$ + gbc.gridx = 1; + txtWasted.setEditable(false); + setFieldSize(txtWasted, editorSize); + add(txtWasted, gbc); + + btnAutoAllocate.setText(resourceMap.getString("ArmorAllocationView.btnAutoAllocate.text")); //$NON-NLS-1$ + gbc.gridx = 0; + gbc.gridy++; + gbc.gridwidth = 2; + gbc.anchor = GridBagConstraints.CENTER; + add(Box.createVerticalStrut(18), gbc); + gbc.gridy++; + add(btnAutoAllocate, gbc); + btnAutoAllocate.addActionListener(e -> listeners.forEach(BuildListener::autoAllocateArmor)); + } + + public void setFromEntity(Entity en) { + setEntityType(en.getEntityType()); + maxArmorPoints = UnitUtil.getMaximumArmorPoints(en); + int raw = UnitUtil.getRawArmorPoints(en, en.getLabArmorTonnage()); + int currentPoints = en.getTotalOArmor(); + if (showPatchwork) { + armorPoints = currentPoints; + raw = currentPoints; + btnAutoAllocate.setEnabled(false); + } else { + armorPoints = Math.min(raw, maxArmorPoints); + btnAutoAllocate.setEnabled(true); + } + wastedPoints = Math.max(0, raw - armorPoints); + for (ArmorLocationView locView : locationViews) { + final int location = locView.getLocationIndex(); + if (location < en.locations()) { + locView.setVisible(true); + locView.updateLocation(en.getLocationAbbr(location), + en.hasRearArmor(location)); + locView.setMaxPoints(UnitUtil.getMaxArmor(en, location)); + locView.setPoints(en.getArmor(location)); + if (en.hasRearArmor(location)) { + locView.setPointsRear(en.getArmor(location, true)); + } else { + locView.setPointsRear(0); + } + if (showPatchwork) { + double pointsPerTon = UnitUtil.getArmorPointsPerTon(en, en.getArmorType(location), en.getArmorTechLevel(location)); + double points = en.getArmor(location, false); + if (en.hasRearArmor(location)) { + points += en.getArmor(location, true); + } + locView.setToolTipText(String.format(tooltipFormat, pointsPerTon, + points / pointsPerTon)); + } + } else { + locView.setVisible(false); + locView.setPoints(0); + locView.setPointsRear(0); + } + } + txtUnallocated.setText(Integer.toString(armorPoints - currentPoints)); + txtAllocated.setText(String.valueOf(currentPoints)); + if (armorPoints != currentPoints) { + txtUnallocated.setForeground(Color.RED); + } else { + txtUnallocated.setForeground(Color.BLACK); + } + txtTotal.setText(String.valueOf(armorPoints)); + txtMaxPossible.setText(String.valueOf(maxArmorPoints)); + txtWasted.setText(String.valueOf(wastedPoints)); + } + + private void updateLayout() { + int[][] layout; + if ((entitytype & Entity.ETYPE_MECH) != 0) { + layout = MEK_LAYOUT; + } else if ((entitytype & Entity.ETYPE_AERO) != 0) { + // Spheroids use lwing/rwing rear for l/r aft positions + layout = AERODYNE_LAYOUT; + } else if ((entitytype & Entity.ETYPE_VTOL) != 0) { + layout = VTOL_LAYOUT; + } else if ((entitytype & Entity.ETYPE_SUPER_HEAVY_TANK) != 0) { + layout = SH_TANK_LAYOUT; + } else { + layout = TANK_LAYOUT; + } + GridBagConstraints gbc = new GridBagConstraints(); + gbc.gridx = 0; + gbc.gridy = 0; + gbc.anchor = GridBagConstraints.CENTER; + gbc.fill = GridBagConstraints.NONE; + gbc.gridwidth = GridBagConstraints.REMAINDER; + locationViews.clear(); + for (int row = 0; row < layout.length; row++) { + JPanel panRow = new JPanel(); + panRow.setLayout(new BoxLayout(panRow, BoxLayout.X_AXIS)); + for (int col = 0; col < layout[row].length; col++) { + final int loc = layout[row][col]; + if (loc >= 0) { + ArmorLocationView locView = new ArmorLocationView(loc); + locationViews.add(locView); + panRow.add(locView); + locView.addListener(this); + } else { + panRow.add(Box.createHorizontalGlue()); + } + } + panLocations.add(panRow, gbc); + gbc.gridy++; + } + } + + public void setEntityType(long etype) { + if (etype != entitytype) { + entitytype = etype; + panLocations.removeAll(); + updateLayout(); + panLocations.repaint(); + } + } + + /** + * Helper function for patchwork. If used for non-patchwork, it will likely give incorrect values + * due to rounding up by location. + * + * @param en + * @return The total weight of all allocated armor. + */ + public double getTotalArmorWeight(Entity en) { + double weight = 0.0; + for (ArmorLocationView locView : locationViews) { + final int loc = locView.getLocationIndex(); + if (loc < en.locations()) { + double pointsPerTon = UnitUtil.getArmorPointsPerTon(en, en.getArmorType(loc), en.getArmorTechLevel(loc)); + weight += (locView.getPoints() + locView.getPointsRear()) / pointsPerTon; + } + } + return Math.ceil(weight * 2.0) * 0.5; + } + + public void showPatchwork(boolean show) { + showPatchwork = show; + } + + @Override + public void armorPointsChanged(int location, int front, int rear) { + listeners.forEach(l -> l.armorPointsChanged(location, front, rear)); + } +} diff --git a/src/megameklab/com/ui/view/ArmorLocationView.java b/src/megameklab/com/ui/view/ArmorLocationView.java new file mode 100644 index 000000000..b5c182add --- /dev/null +++ b/src/megameklab/com/ui/view/ArmorLocationView.java @@ -0,0 +1,192 @@ +/* + * MegaMekLab - Copyright (C) 2017 - The MegaMek Team + * + * 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 megameklab.com.ui.view; + +import java.awt.GridBagConstraints; +import java.awt.GridBagLayout; +import java.util.List; +import java.util.ResourceBundle; +import java.util.concurrent.CopyOnWriteArrayList; + +import javax.swing.BorderFactory; +import javax.swing.JLabel; +import javax.swing.JSpinner; +import javax.swing.SpinnerNumberModel; +import javax.swing.border.TitledBorder; +import javax.swing.event.ChangeEvent; +import javax.swing.event.ChangeListener; + +import megamek.common.annotations.Nullable; +import megamek.common.util.EncodeControl; + +/** + * Panel used to set armor value for a single location. Optionally used for rear location as well, + * and can be used to set the armor type for units with patchwork armor. + * + * @author Neoancient + * + */ +public class ArmorLocationView extends BuildView implements ChangeListener { + + /** + * + */ + private static final long serialVersionUID = 6663440021651827007L; + + public interface ArmorLocationListener { + void armorPointsChanged(int location, int front, int rear); + } + private final List listeners = new CopyOnWriteArrayList<>(); + public void addListener(ArmorLocationListener l) { + listeners.add(l); + } + public void removeListener(ArmorLocationListener l) { + listeners.remove(l); + } + + private final SpinnerNumberModel spnPointsModel = new SpinnerNumberModel(0, 0, null, 1); + private final SpinnerNumberModel spnPointsRearModel = new SpinnerNumberModel(0, 0, null, 1); + private final JSpinner spnPoints = new JSpinner(spnPointsModel); + private final JSpinner spnPointsRear = new JSpinner(spnPointsRearModel); + private final JLabel lblRear = new JLabel(); + private final JLabel lblMaxPoints = new JLabel(); + + private final int location; + private final String maxFormat; + private Integer maxPoints; + private boolean hasRear = false; + + ArmorLocationView(int location) { + this.location = location; + + ResourceBundle resourceMap = ResourceBundle.getBundle("megameklab.resources.Views", new EncodeControl()); //$NON-NLS-1$ + lblRear.setText(resourceMap.getString("ArmorLocationView.lblRear.text")); //$NON-NLS-1$ + maxFormat = resourceMap.getString("ArmorLocationView.lblMax.format"); //$NON-NLS-1$ + setBorder(BorderFactory.createTitledBorder( + null, "", + TitledBorder.TOP, + TitledBorder.DEFAULT_POSITION)); + setLayout(new GridBagLayout()); + GridBagConstraints gbc = new GridBagConstraints(); + gbc.gridx = 0; + gbc.gridy = 0; + setFieldSize(spnPoints, spinnerSize); + add(spnPoints, gbc); + gbc.gridy++; + add(lblRear, gbc); + gbc.gridy++; + setFieldSize(spnPointsRear, spinnerSize); + add(spnPointsRear, gbc); + gbc.gridy++; + gbc.weighty = 1.0; + add(lblMaxPoints, gbc); + } + + /** + * Changes the location name in the title and whether it has a rear armor location. + * + * @param locName + * @param rear + */ + public void updateLocation(String locName, boolean rear) { + ((TitledBorder)getBorder()).setTitle(locName); + hasRear = rear; + lblRear.setVisible(rear); + spnPointsRear.setVisible(rear); + if (!rear) { + spnPointsRear.setValue(0); + } + } + + /** + * @return The index (LOC_* constant) of the location managed by this view. + */ + public int getLocationIndex() { + return location; + } + + /** + * Sets the maximum number of armor points that can be assigned to this location. + * A value of null indicates that there is no maximum. + * + * @param max + */ + public void setMaxPoints(@Nullable Integer max) { + maxPoints = max; + spnPointsModel.setMaximum(max); + spnPointsRearModel.setMaximum(max); + if (null == max) { + lblMaxPoints.setVisible(false); + } else { + lblMaxPoints.setVisible(true); + lblMaxPoints.setText(String.format(maxFormat, max)); + } + } + + /** + * Sets the number of points for this location. If the location has rear armor, this sets only the front. + * + * @param points + */ + public void setPoints(int points) { + spnPoints.removeChangeListener(this); + if (null == maxPoints) { + spnPoints.setValue(points); + } else { + spnPoints.setValue(Math.min(points, maxPoints)); + if (hasRear && (getPoints() + getPointsRear() > maxPoints)) { + spnPointsRearModel.setValue(maxPoints - getPoints()); + } + } + spnPoints.addChangeListener(this); + } + + /** + * @return The number of points of armor for this location (front). + */ + public int getPoints() { + return spnPointsModel.getNumber().intValue(); + } + + /** + * Sets the number of points of armor for this location in the rear. + * + * @param points + */ + public void setPointsRear(int points) { + spnPointsRear.removeChangeListener(this); + if (null == maxPoints) { + spnPointsRear.setValue(points); + } else { + spnPointsRear.setValue(Math.min(points, maxPoints)); + if (getPoints() + getPointsRear() > maxPoints) { + spnPointsModel.setValue(maxPoints - getPointsRear()); + } + } + spnPointsRear.addChangeListener(this); + } + + /** + * @return The number of points of rear armor in this location. + */ + public int getPointsRear() { + return spnPointsRearModel.getNumber().intValue(); + } + + @Override + public void stateChanged(ChangeEvent e) { + listeners.forEach(l -> l.armorPointsChanged(location, getPoints(), getPointsRear())); + } + +} diff --git a/src/megameklab/com/ui/view/BAChassisView.java b/src/megameklab/com/ui/view/BAChassisView.java index f17eee2c2..3f0f11463 100644 --- a/src/megameklab/com/ui/view/BAChassisView.java +++ b/src/megameklab/com/ui/view/BAChassisView.java @@ -35,6 +35,7 @@ import megamek.common.ITechManager; import megamek.common.util.EncodeControl; import megameklab.com.ui.util.CustomComboBox; +import megameklab.com.ui.view.listeners.BABuildListener; /** * Structure tab chassis view for BattleArmor @@ -42,26 +43,18 @@ * @author Neoancient * */ -public class BAChassisView extends MainUIView implements ActionListener, ChangeListener { +public class BAChassisView extends BuildView implements ActionListener, ChangeListener { /** * */ private static final long serialVersionUID = 2230418263440532689L; - public interface ChassisListener { - void chassisTypeChanged(int bodyType); - void weightClassChanged(int weightClass); - void turretChanged(int type, int size); - void exoskeletonChanged(boolean exoskeleton); - void harjelChanged(boolean harjel); - void squadSizeChanged(int squadSize); - } - private final List listeners = new CopyOnWriteArrayList<>(); - public void addListener(ChassisListener l) { + private final List listeners = new CopyOnWriteArrayList<>(); + public void addListener(BABuildListener l) { listeners.add(l); } - public void removeListener(ChassisListener l) { + public void removeListener(BABuildListener l) { listeners.remove(l); } diff --git a/src/megameklab/com/ui/view/BAEnhancementView.java b/src/megameklab/com/ui/view/BAEnhancementView.java index 84fc8388b..76a45ee36 100644 --- a/src/megameklab/com/ui/view/BAEnhancementView.java +++ b/src/megameklab/com/ui/view/BAEnhancementView.java @@ -29,6 +29,7 @@ import megamek.common.ITechManager; import megamek.common.MiscType; import megamek.common.util.EncodeControl; +import megameklab.com.ui.view.listeners.BABuildListener; /** * Structure tab panel for BA movement enhancements @@ -36,21 +37,18 @@ * @author Neoancient * */ -public class BAEnhancementView extends MainUIView implements ActionListener { +public class BAEnhancementView extends BuildView implements ActionListener { /** * */ private static final long serialVersionUID = 6181555446271444880L; - public interface EnhancementListener { - void enhancementChanged(EquipmentType eq, boolean selected); - } - private List listeners = new CopyOnWriteArrayList<>(); - public void addListener(EnhancementListener l) { + private List listeners = new CopyOnWriteArrayList<>(); + public void addListener(BABuildListener l) { listeners.add(l); } - public void removeListener(EnhancementListener l) { + public void removeListener(BABuildListener l) { listeners.remove(l); } diff --git a/src/megameklab/com/ui/view/BAProtoArmorView.java b/src/megameklab/com/ui/view/BAProtoArmorView.java index 44ed30640..2c2bdfebd 100644 --- a/src/megameklab/com/ui/view/BAProtoArmorView.java +++ b/src/megameklab/com/ui/view/BAProtoArmorView.java @@ -35,6 +35,7 @@ import megamek.common.TechConstants; import megamek.common.util.EncodeControl; import megameklab.com.ui.util.TechComboBox; +import megameklab.com.ui.view.listeners.BuildListener; /** * Structure table armor panel for units that allocate armor by point instead of ton. @@ -42,22 +43,18 @@ * @author Neoancient * */ -public class BAProtoArmorView extends MainUIView implements ActionListener, ChangeListener { +public class BAProtoArmorView extends BuildView implements ActionListener, ChangeListener { /** * */ private static final long serialVersionUID = 14527455823813010L; - public interface ArmorListener { - void armorValueChanged(int points); - void armorTypeChanged(EquipmentType armor); - } - private final List listeners = new CopyOnWriteArrayList<>(); - public void addListener(ArmorListener l) { + private final List listeners = new CopyOnWriteArrayList<>(); + public void addListener(BuildListener l) { listeners.add(l); } - public void removeListener(ArmorListener l) { + public void removeListener(BuildListener l) { listeners.remove(l); } @@ -96,7 +93,7 @@ private void initUI() { add(createLabel(resourceMap.getString("ArmorView.spnArmorPoints.text"), labelSize), gbc); //$NON-NLS-1$ gbc.gridx = 1; gbc.gridy = 1; - setFieldSize(spnArmorPoints.getEditor(), spinnerEditorSize); + setFieldSize(spnArmorPoints.getEditor(), editorSize); spnArmorPoints.setToolTipText(resourceMap.getString("ArmorView.spnArmorPoints.tooltip")); //$NON-NLS-1$ add(spnArmorPoints, gbc); spnArmorPoints.addChangeListener(this); diff --git a/src/megameklab/com/ui/view/BasicInfoView.java b/src/megameklab/com/ui/view/BasicInfoView.java index 1c7f3aeef..7c114ecb3 100644 --- a/src/megameklab/com/ui/view/BasicInfoView.java +++ b/src/megameklab/com/ui/view/BasicInfoView.java @@ -37,6 +37,7 @@ import megameklab.com.ui.util.CustomComboBox; import megameklab.com.ui.util.FactionComboBox; import megameklab.com.ui.util.IntRangeTextField; +import megameklab.com.ui.view.listeners.BuildListener; import megameklab.com.util.CConfig; /** @@ -45,32 +46,20 @@ * @author Neoancient * */ -public class BasicInfoView extends MainUIView implements ITechManager, ActionListener, FocusListener { +public class BasicInfoView extends BuildView implements ITechManager, ActionListener, FocusListener { /** * */ private static final long serialVersionUID = -6831478201489228066L; - public interface BasicInfoListener { - void refreshSummary(); - void chassisChanged(String chassis); - void modelChanged(String model); - void yearChanged(int year); - void updateTechLevel(); - void sourceChanged(String source); - void techBaseChanged(boolean clan, boolean mixed); - void techLevelChanged(SimpleTechLevel techLevel); - void manualBVChanged(int manualBV); - } - - private List listeners = new CopyOnWriteArrayList<>(); - public void addListener(BasicInfoListener l) { + private List listeners = new CopyOnWriteArrayList<>(); + public void addListener(BuildListener l) { if (null != l) { listeners.add(l); } } - public void removeListener(BasicInfoListener l) { + public void removeListener(BuildListener l) { listeners.remove(l); } diff --git a/src/megameklab/com/ui/view/MainUIView.java b/src/megameklab/com/ui/view/BuildView.java similarity index 92% rename from src/megameklab/com/ui/view/MainUIView.java rename to src/megameklab/com/ui/view/BuildView.java index 7cf40d8f7..16c560aeb 100644 --- a/src/megameklab/com/ui/view/MainUIView.java +++ b/src/megameklab/com/ui/view/BuildView.java @@ -27,7 +27,7 @@ * @author Neoancient * */ -public abstract class MainUIView extends JPanel { +public abstract class BuildView extends JPanel { /** * @@ -37,7 +37,7 @@ public abstract class MainUIView extends JPanel { final protected Dimension labelSize = new Dimension(110, 25); final protected Dimension controlSize = new Dimension(180, 25); final protected Dimension spinnerSize = new Dimension(55, 25); - final protected Dimension spinnerEditorSize = new Dimension(40, 25); + final protected Dimension editorSize = new Dimension(40, 25); public JLabel createLabel(String text, Dimension maxSize) { JLabel label = new JLabel(text, SwingConstants.RIGHT); diff --git a/src/megameklab/com/ui/view/CVChassisView.java b/src/megameklab/com/ui/view/CVChassisView.java index 12aa109c7..1e714ef50 100644 --- a/src/megameklab/com/ui/view/CVChassisView.java +++ b/src/megameklab/com/ui/view/CVChassisView.java @@ -44,6 +44,7 @@ import megamek.common.util.EncodeControl; import megameklab.com.ui.util.CustomComboBox; import megameklab.com.ui.util.TechComboBox; +import megameklab.com.ui.view.listeners.CVBuildListener; /** * Chassis panel for combat vehicles @@ -51,29 +52,18 @@ * @author Neoancient * */ -public class CVChassisView extends MainUIView implements ActionListener, ChangeListener { +public class CVChassisView extends BuildView implements ActionListener, ChangeListener { /** * */ private static final long serialVersionUID = -5860627963911641227L; - public interface ChassisListener { - void tonnageChanged(double tonnage); - void omniChanged(boolean omni); - void superheavyChanged(boolean superheavy); - void motiveChanged(EntityMovementMode motive); - void engineChanged(Engine engine); - void turretChanged(int turretConfig); - void turretBaseWtChanged(double turret1, double turret2); - void troopSpaceChanged(double fixed, double pod); - void resetChassis(); - } - List listeners = new CopyOnWriteArrayList<>(); - public void addListener(ChassisListener l) { + List listeners = new CopyOnWriteArrayList<>(); + public void addListener(CVBuildListener l) { listeners.add(l); } - public void removeListener(ChassisListener l) { + public void removeListener(CVBuildListener l) { listeners.remove(l); } diff --git a/src/megameklab/com/ui/view/FighterChassisView.java b/src/megameklab/com/ui/view/FighterChassisView.java index 8d04df1be..3bc62661f 100644 --- a/src/megameklab/com/ui/view/FighterChassisView.java +++ b/src/megameklab/com/ui/view/FighterChassisView.java @@ -38,6 +38,7 @@ import megamek.common.util.EncodeControl; import megameklab.com.ui.util.CustomComboBox; import megameklab.com.ui.util.TechComboBox; +import megameklab.com.ui.view.listeners.AeroBuildListener; /** * Structure tab chassis panel for aerospace and conventional fighters. @@ -45,27 +46,18 @@ * @author Neoancient * */ -public class FighterChassisView extends MainUIView implements ActionListener, ChangeListener { +public class FighterChassisView extends BuildView implements ActionListener, ChangeListener { /** * */ private static final long serialVersionUID = -1129246135285707937L; - public interface ChassisListener { - void tonnageChanged(double tonnage); - void omniChanged(boolean omni); - void vstolChanged(boolean vstol); - void fighterTypeChanged(int type); - void engineChanged(Engine engine); - void cockpitChanged(int cockpitType); - void resetChassis(); - } - private final List listeners = new CopyOnWriteArrayList<>(); - public void addListener(ChassisListener l) { + private final List listeners = new CopyOnWriteArrayList<>(); + public void addListener(AeroBuildListener l) { listeners.add(l); } - public void removeListener(ChassisListener l) { + public void removeListener(AeroBuildListener l) { listeners.remove(l); } @@ -128,7 +120,7 @@ public void initUI() { gbc.gridwidth = 1; gbc.anchor = GridBagConstraints.WEST; add(createLabel(resourceMap.getString("FighterChassisView.txtSI.text"), labelSize),gbc); //$NON-NLS-1$ - setFieldSize(txtSI, spinnerEditorSize); + setFieldSize(txtSI, editorSize); txtSI.setToolTipText(resourceMap.getString("FighterChassisView.txtSI.tooltip")); //$NON-NLS-1$ txtSI.setEditable(false); diff --git a/src/megameklab/com/ui/view/HeatSinkView.java b/src/megameklab/com/ui/view/HeatSinkView.java index a618e3b66..986be82a1 100644 --- a/src/megameklab/com/ui/view/HeatSinkView.java +++ b/src/megameklab/com/ui/view/HeatSinkView.java @@ -36,6 +36,7 @@ import megamek.common.Mounted; import megamek.common.util.EncodeControl; import megameklab.com.ui.util.CustomComboBox; +import megameklab.com.ui.view.listeners.BuildListener; import megameklab.com.util.UnitUtil; /** @@ -44,23 +45,18 @@ * @author Neoancient * */ -public class HeatSinkView extends MainUIView implements ActionListener, ChangeListener { +public class HeatSinkView extends BuildView implements ActionListener, ChangeListener { /** * */ private static final long serialVersionUID = -3310994380270514088L; - public interface HeatSinkListener { - void heatSinksChanged(int index, int count); - void heatSinksChanged(EquipmentType hsType, int count); - void heatSinkBaseCountChanged(int count); - } - private final List listeners = new CopyOnWriteArrayList<>(); - public void addListener(HeatSinkListener l) { + private final List listeners = new CopyOnWriteArrayList<>(); + public void addListener(BuildListener l) { listeners.add(l); } - public void removeListener(HeatSinkListener l) { + public void removeListener(BuildListener l) { listeners.remove(l); } @@ -129,7 +125,7 @@ private void initUI() { add(createLabel(resourceMap.getString("HeatSinkView.spnCount.text"), labelSize), gbc); //$NON-NLS-1$ gbc.gridx = 1; gbc.gridy = 1; - setFieldSize(spnCount.getEditor(), spinnerEditorSize); + setFieldSize(spnCount.getEditor(), editorSize); spnCount.setToolTipText(resourceMap.getString("HeatSinkView.spnCount.tooltip")); //$NON-NLS-1$ add(spnCount, gbc); spnCount.addChangeListener(this); @@ -149,7 +145,7 @@ private void initUI() { add(createLabel(resourceMap.getString("HeatSinkView.spnBaseCount.text"), labelSize), gbc); //$NON-NLS-1$ gbc.gridx = 1; gbc.gridy = 2; - setFieldSize(spnBaseCount.getEditor(), spinnerEditorSize); + setFieldSize(spnBaseCount.getEditor(), editorSize); spnBaseCount.setToolTipText(resourceMap.getString("HeatSinkView.spnBaseCount.tooltip")); //$NON-NLS-1$ add(spnBaseCount, gbc); spnBaseCount.addChangeListener(this); diff --git a/src/megameklab/com/ui/view/InfantryWeaponView.java b/src/megameklab/com/ui/view/InfantryWeaponView.java index 9a18334cb..5b29eb006 100644 --- a/src/megameklab/com/ui/view/InfantryWeaponView.java +++ b/src/megameklab/com/ui/view/InfantryWeaponView.java @@ -40,6 +40,7 @@ import megamek.common.verifier.TestInfantry; import megamek.common.weapons.artillery.ArtilleryCannonWeapon; import megamek.common.weapons.artillery.ArtilleryWeapon; +import megameklab.com.ui.view.listeners.InfantryBuildListener; import megameklab.com.util.UnitUtil; /** @@ -49,23 +50,18 @@ * @author Neoancient * */ -public class InfantryWeaponView extends MainUIView implements ActionListener { +public class InfantryWeaponView extends BuildView implements ActionListener { /** * */ private static final long serialVersionUID = 6150492212690074504L; - public interface WeaponListener { - void numSecondaryChanged(int count); - void numFieldGunsChanged(int count); - void antiMekChanged(boolean antiMek); - } - private List listeners = new CopyOnWriteArrayList<>(); - public void addListener(WeaponListener l) { + private List listeners = new CopyOnWriteArrayList<>(); + public void addListener(InfantryBuildListener l) { listeners.add(l); } - public void removeListener(WeaponListener l) { + public void removeListener(InfantryBuildListener l) { listeners.remove(l); } diff --git a/src/megameklab/com/ui/view/MVFArmorView.java b/src/megameklab/com/ui/view/MVFArmorView.java index 40da8da71..9f68ea13f 100644 --- a/src/megameklab/com/ui/view/MVFArmorView.java +++ b/src/megameklab/com/ui/view/MVFArmorView.java @@ -39,6 +39,7 @@ import megamek.common.TechConstants; import megamek.common.util.EncodeControl; import megameklab.com.ui.util.TechComboBox; +import megameklab.com.ui.view.listeners.BuildListener; import megameklab.com.util.UnitUtil; /** @@ -47,24 +48,18 @@ * @author Neoancient * */ -public class MVFArmorView extends MainUIView implements ActionListener, ChangeListener { +public class MVFArmorView extends BuildView implements ActionListener, ChangeListener { /** * */ private static final long serialVersionUID = 1246552271894765543L; - public interface ArmorListener { - void armorTypeChanged(int at, int armorTechLevel); - void armorTonnageChanged(double tonnage); - void maximizeArmor(); - void useRemainingTonnageArmor(); - } - private final List listeners = new CopyOnWriteArrayList<>(); - public void addListener(ArmorListener l) { + private final List listeners = new CopyOnWriteArrayList<>(); + public void addListener(BuildListener l) { listeners.add(l); } - public void removeListener(ArmorListener l) { + public void removeListener(BuildListener l) { listeners.remove(l); } @@ -118,7 +113,7 @@ private void initUI() { add(createLabel(resourceMap.getString("ArmorView.spnTonnage.text"), labelSize), gbc); //$NON-NLS-1$ gbc.gridx = 1; gbc.gridy = 1; - setFieldSize(spnTonnage.getEditor(), spinnerEditorSize); + setFieldSize(spnTonnage.getEditor(), editorSize); spnTonnage.setToolTipText(resourceMap.getString("ArmorView.spnTonnage.tooltip")); //$NON-NLS-1$ add(spnTonnage, gbc); spnTonnage.addChangeListener(this); @@ -230,17 +225,19 @@ public void refresh() { } } } - cbArmorType.setSelectedItem(prev); - cbArmorType.addActionListener(this); - if (cbArmorType.getSelectedIndex() < 0) { - cbArmorType.setSelectedIndex(0); - } } - //TODO: patchwork armor for fighters needs work on the armor allocation view - if (((etype & Entity.ETYPE_AERO) == 0) - && techManager.isLegal(Entity.getPatchworkArmorAdvancement())) { + if (techManager.isLegal(Entity.getPatchworkArmorAdvancement())) { cbArmorType.addItem(null); } + if (null == prev) { + cbArmorType.setSelectedIndex(cbArmorType.getModel().getSize() - 1); + } else { + cbArmorType.setSelectedItem(prev); + } + cbArmorType.addActionListener(this); + if ((null != prev) && (cbArmorType.getSelectedIndex() < 0)) { + cbArmorType.setSelectedIndex(0); + } cbArmorType.showTechBase(techManager.useMixedTech()); } diff --git a/src/megameklab/com/ui/view/MekChassisView.java b/src/megameklab/com/ui/view/MekChassisView.java index f8d880d44..cd6a62709 100644 --- a/src/megameklab/com/ui/view/MekChassisView.java +++ b/src/megameklab/com/ui/view/MekChassisView.java @@ -48,6 +48,7 @@ import megamek.common.util.EncodeControl; import megameklab.com.ui.util.CustomComboBox; import megameklab.com.ui.util.TechComboBox; +import megameklab.com.ui.view.listeners.MekBuildListener; /** * Construction options and systems for Meks. @@ -55,31 +56,18 @@ * @author Neoancient * */ -public class MekChassisView extends MainUIView implements ActionListener, ChangeListener { +public class MekChassisView extends BuildView implements ActionListener, ChangeListener { /** * */ private static final long serialVersionUID = -2620071922845931509L; - public interface MekChassisListener { - void refreshSummary(); - void tonnageChanged(double tonnage); - void omniChanged(boolean omni); - void typeChanged(int baseType, int motiveType, long etype); - void structureChanged(EquipmentType structure); - void engineChanged(Engine engine); - void gyroChanged(int gyroType); - void cockpitChanged(int cockpitType); - void enhancementChanged(EquipmentType enhancement); - void fullHeadEjectChanged(boolean eject); - void resetChassis(); - } - List listeners = new CopyOnWriteArrayList<>(); - public void addListener(MekChassisListener l) { + List listeners = new CopyOnWriteArrayList<>(); + public void addListener(MekBuildListener l) { listeners.add(l); } - public void removeListener(MekChassisListener l) { + public void removeListener(MekBuildListener l) { listeners.remove(l); } @@ -764,7 +752,7 @@ public void actionPerformed(ActionEvent e) { } else if (e.getSource() == chkFullHeadEject) { listeners.forEach(l -> l.fullHeadEjectChanged(chkFullHeadEject.isSelected())); } else if (e.getSource() == btnResetChassis) { - listeners.forEach(MekChassisListener::resetChassis); + listeners.forEach(MekBuildListener::resetChassis); } refresh(); } diff --git a/src/megameklab/com/ui/view/MovementView.java b/src/megameklab/com/ui/view/MovementView.java index 110444662..486f7d848 100644 --- a/src/megameklab/com/ui/view/MovementView.java +++ b/src/megameklab/com/ui/view/MovementView.java @@ -45,6 +45,7 @@ import megamek.common.verifier.TestEntity; import megamek.common.verifier.TestMech; import megameklab.com.ui.util.TechComboBox; +import megameklab.com.ui.view.listeners.BuildListener; /** * Controls for setting a unit's speed @@ -52,23 +53,18 @@ * @author Neoancient * */ -public class MovementView extends MainUIView implements ActionListener, ChangeListener { +public class MovementView extends BuildView implements ActionListener, ChangeListener { /** * */ private static final long serialVersionUID = 9047797409742756926L; - public interface MovementListener { - void walkChanged(int walkMP); - void jumpChanged(int jumpMP, EquipmentType jumpJet); - void jumpTypeChanged(EquipmentType jumpJet); - } - private final List listeners = new CopyOnWriteArrayList<>(); - public void addListener(MovementListener l) { + private final List listeners = new CopyOnWriteArrayList<>(); + public void addListener(BuildListener l) { listeners.add(l); } - public void removeListener(MovementListener l) { + public void removeListener(BuildListener l) { listeners.remove(l); } @@ -181,17 +177,17 @@ private void initUI() { add(cbJumpType, gbc); cbJumpType.addActionListener(this); - setFieldSize(spnWalk.getEditor(), spinnerEditorSize); - setFieldSize(txtWalkFinal, spinnerEditorSize); + setFieldSize(spnWalk.getEditor(), editorSize); + setFieldSize(txtWalkFinal, editorSize); txtWalkFinal.setEditable(false); txtWalkFinal.setHorizontalAlignment(SwingConstants.RIGHT); - setFieldSize(txtRunBase, spinnerEditorSize); - setFieldSize(txtRunFinal, spinnerEditorSize); + setFieldSize(txtRunBase, editorSize); + setFieldSize(txtRunFinal, editorSize); txtRunBase.setEditable(false); txtRunFinal.setEditable(false); txtRunFinal.setHorizontalAlignment(SwingConstants.RIGHT); - setFieldSize(spnJump.getEditor(), spinnerEditorSize); - setFieldSize(txtJumpFinal, spinnerEditorSize); + setFieldSize(spnJump.getEditor(), editorSize); + setFieldSize(txtJumpFinal, editorSize); txtJumpFinal.setEditable(false); txtJumpFinal.setHorizontalAlignment(SwingConstants.RIGHT); } diff --git a/src/megameklab/com/ui/view/PatchworkArmorView.java b/src/megameklab/com/ui/view/PatchworkArmorView.java new file mode 100644 index 000000000..cb2413816 --- /dev/null +++ b/src/megameklab/com/ui/view/PatchworkArmorView.java @@ -0,0 +1,148 @@ +/* + * MegaMekLab - Copyright (C) 2017 - The MegaMek Team + * + * 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 megameklab.com.ui.view; + +import java.awt.GridBagConstraints; +import java.awt.GridBagLayout; +import java.awt.Insets; +import java.awt.event.ActionEvent; +import java.awt.event.ActionListener; +import java.util.ArrayList; +import java.util.List; +import java.util.ResourceBundle; +import java.util.concurrent.CopyOnWriteArrayList; + +import javax.swing.BorderFactory; +import javax.swing.JLabel; +import javax.swing.border.TitledBorder; + +import megamek.common.Aero; +import megamek.common.Entity; +import megamek.common.EquipmentType; +import megamek.common.ITechManager; +import megamek.common.Tank; +import megamek.common.TechConstants; +import megamek.common.util.EncodeControl; +import megameklab.com.ui.util.TechComboBox; +import megameklab.com.ui.view.listeners.BuildListener; +import megameklab.com.util.UnitUtil; + +/** + * Displays a list of comboboxes with labels that displays the current armor type per location for + * patchwork armor and allows it to be changed. + * + * @author Neoancient + * + */ +public class PatchworkArmorView extends BuildView implements ActionListener { + + /** + * + */ + private static final long serialVersionUID = -16930846399307224L; + + private final List listeners = new CopyOnWriteArrayList<>(); + public void addListener(BuildListener l) { + listeners.add(l); + } + public void removeListener(BuildListener l) { + listeners.remove(l); + } + + private final static int MAX_LOC = 10; + + private final List labels = new ArrayList<>(); + private final List> combos = new ArrayList<>(); + + private final ITechManager techManager; + private boolean ignoreEvents = false; + + public PatchworkArmorView(ITechManager techManager) { + this.techManager = techManager; + initUI(); + } + + private void initUI() { + ResourceBundle resourceMap = ResourceBundle.getBundle("megameklab.resources.Views", new EncodeControl()); //$NON-NLS-1$ + setLayout(new GridBagLayout()); + + setBorder(BorderFactory.createTitledBorder( + null, resourceMap.getString("ArmorAllocationView.panPatwork.title"), //$NON-NLS-1$ + TitledBorder.TOP, + TitledBorder.DEFAULT_POSITION)); + + setLayout(new GridBagLayout()); + GridBagConstraints gbc = new GridBagConstraints(); + gbc.gridx = 0; + gbc.gridy = 0; + gbc.insets = new Insets(0, 5, 0, 5); + for (int loc = 0; loc < MAX_LOC; loc++) { + JLabel label = new JLabel(); + TechComboBox combo = new TechComboBox<>(eq -> eq.getName()); + combo.setActionCommand(Integer.toString(loc)); + combo.addActionListener(this); + labels.add(label); + combos.add(combo); + gbc.gridx = 0; + gbc.anchor = GridBagConstraints.EAST; + add(label, gbc); + gbc.gridx = 1; + gbc.anchor = GridBagConstraints.WEST; + add(combo, gbc); + gbc.gridy++; + } + } + + public void setFromEntity(Entity en) { + List armors = UnitUtil.legalArmorsFor(en, techManager); + ignoreEvents = true; + for (int loc = 0; loc < combos.size(); loc++) { + if ((loc < en.locations()) + && !((en.hasETypeFlag(Entity.ETYPE_TANK) && (loc == Tank.LOC_BODY))) + && !((en.hasETypeFlag(Entity.ETYPE_AERO) && (loc == Aero.LOC_WINGS)))) { + labels.get(loc).setText(en.getLocationName(loc)); + combos.get(loc).removeAllItems(); + for (EquipmentType eq : armors) { + combos.get(loc).addItem(eq); + } + String name = EquipmentType.getArmorTypeName(en.getArmorType(loc), + TechConstants.isClan(en.getArmorTechLevel(loc))); + combos.get(loc).setSelectedItem(EquipmentType.get(name)); + labels.get(loc).setVisible(true); + combos.get(loc).setVisible(true); + } else { + labels.get(loc).setVisible(false); + combos.get(loc).setVisible(false); + } + } + ignoreEvents = false; + } + + public EquipmentType getArmor(int location) { + return (EquipmentType)combos.get(location).getSelectedItem(); + } + + public void setArmorType(EquipmentType armor, int location) { + combos.get(location).setSelectedItem(armor); + } + + @Override + public void actionPerformed(ActionEvent e) { + if (!ignoreEvents) { + final int location = Integer.parseInt(e.getActionCommand()); + listeners.forEach(l -> l.patchworkChanged(location, getArmor(location))); + } + } + +} diff --git a/src/megameklab/com/ui/view/PlatoonTypeView.java b/src/megameklab/com/ui/view/PlatoonTypeView.java index a46ab71d9..5fae4fc0f 100644 --- a/src/megameklab/com/ui/view/PlatoonTypeView.java +++ b/src/megameklab/com/ui/view/PlatoonTypeView.java @@ -34,6 +34,7 @@ import megamek.common.util.EncodeControl; import megamek.common.verifier.TestInfantry; import megameklab.com.ui.util.CustomComboBox; +import megameklab.com.ui.view.listeners.InfantryBuildListener; /** * Infantry structure tab panel for selecting platoon movement type and number/size of squads. @@ -41,28 +42,18 @@ * @author Neoancient * */ -public class PlatoonTypeView extends MainUIView implements ActionListener, ChangeListener { +public class PlatoonTypeView extends BuildView implements ActionListener, ChangeListener { /** * */ private static final long serialVersionUID = -7227731728613831387L; - public interface PlatoonListener { - /** - * @param motiveType The selected motive type - * @param alt If motiveType is VTOL or INF_UMU, alt is true for microlite and motorized scuba - * respectively, false for microcopter and foot scuba. It has no meaning for other - * motive types. - */ - void motiveTypeChanged(EntityMovementMode motiveType, boolean alt); - void platoonSizeChanged(int numSquads, int squadSize); - } - List listeners = new CopyOnWriteArrayList<>(); - public void addListener(PlatoonListener l) { + List listeners = new CopyOnWriteArrayList<>(); + public void addListener(InfantryBuildListener l) { listeners.add(l); } - public void removeListener(PlatoonListener l) { + public void removeListener(InfantryBuildListener l) { listeners.remove(l); } diff --git a/src/megameklab/com/ui/view/listeners/AeroBuildListener.java b/src/megameklab/com/ui/view/listeners/AeroBuildListener.java new file mode 100644 index 000000000..7945d8ee1 --- /dev/null +++ b/src/megameklab/com/ui/view/listeners/AeroBuildListener.java @@ -0,0 +1,36 @@ +/* + * MegaMekLab - Copyright (C) 2017 - The MegaMek Team + * + * 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 megameklab.com.ui.view.listeners; + +import megamek.common.Engine; + +/** + * Listener for views used by aerospace units. + * + * @author Neoancient + * + */ +public interface AeroBuildListener extends BuildListener { + + void tonnageChanged(double tonnage); + void omniChanged(boolean omni); + void vstolChanged(boolean vstol); + void fighterTypeChanged(int type); + void engineChanged(Engine engine); + void cockpitChanged(int cockpitType); + void resetChassis(); + + void fuelTonnageChanged(double tonnage); + +} diff --git a/src/megameklab/com/ui/view/listeners/BABuildListener.java b/src/megameklab/com/ui/view/listeners/BABuildListener.java new file mode 100644 index 000000000..e675d9a46 --- /dev/null +++ b/src/megameklab/com/ui/view/listeners/BABuildListener.java @@ -0,0 +1,36 @@ +/* + * MegaMekLab - Copyright (C) 2017 - The MegaMek Team + * + * 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 megameklab.com.ui.view.listeners; + +import megamek.common.EquipmentType; + +/** + * Listener for views used by BattleArmor. + * + * @author Neoancient + * + */ +public interface BABuildListener extends BuildListener { + void chassisTypeChanged(int bodyType); + void weightClassChanged(int weightClass); + void turretChanged(int type, int size); + void exoskeletonChanged(boolean exoskeleton); + void harjelChanged(boolean harjel); + void squadSizeChanged(int squadSize); + void enhancementChanged(EquipmentType eq, boolean selected); + + void armorValueChanged(int points); + void armorTypeChanged(EquipmentType armor); +} diff --git a/src/megameklab/com/ui/view/listeners/BuildListener.java b/src/megameklab/com/ui/view/listeners/BuildListener.java new file mode 100644 index 000000000..0500137f4 --- /dev/null +++ b/src/megameklab/com/ui/view/listeners/BuildListener.java @@ -0,0 +1,66 @@ +/* + * MegaMekLab - Copyright (C) 2017 - The MegaMek Team + * + * 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 megameklab.com.ui.view.listeners; + +import megamek.common.EquipmentType; +import megamek.common.SimpleTechLevel; + +/** + * Combined listener interface for the various subviews of the structure tab. Includes callbacks + * used by multiple unit types. Listeners for specific unit types extend this one. + * + * @author Neoancient + * + */ +public interface BuildListener { + + void refreshSummary(); + void chassisChanged(String chassis); + void modelChanged(String model); + void yearChanged(int year); + void updateTechLevel(); + void sourceChanged(String source); + void techBaseChanged(boolean clan, boolean mixed); + void techLevelChanged(SimpleTechLevel techLevel); + void manualBVChanged(int manualBV); + + void walkChanged(int walkMP); + void jumpChanged(int jumpMP, EquipmentType jumpJet); + void jumpTypeChanged(EquipmentType jumpJet); + + /* + * Methods used by multiple unit types but not all are given default implementations that + * ignore them. + */ + + default void heatSinksChanged(int index, int count) {}; + default void heatSinksChanged(EquipmentType hsType, int count) {}; + default void heatSinkBaseCountChanged(int count) {}; + + // For units that allocate armor by tonnage + default void armorTypeChanged(int at, int armorTechLevel) {}; + default void armorTonnageChanged(double tonnage) {}; + default void maximizeArmor() {}; + default void useRemainingTonnageArmor() {}; + + // For units that allocate armor by point + default void armorValueChanged(int points) {}; + default void armorTypeChanged(EquipmentType armor) {}; + + // For units that allocate armor to location + default void armorPointsChanged(int location, int front, int rear) {}; + default void patchworkChanged(int location, EquipmentType armor) {}; + default void autoAllocateArmor() {}; + +} diff --git a/src/megameklab/com/ui/view/listeners/CVBuildListener.java b/src/megameklab/com/ui/view/listeners/CVBuildListener.java new file mode 100644 index 000000000..589f25ebb --- /dev/null +++ b/src/megameklab/com/ui/view/listeners/CVBuildListener.java @@ -0,0 +1,37 @@ +/* + * MegaMekLab - Copyright (C) 2017 - The MegaMek Team + * + * 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 megameklab.com.ui.view.listeners; + +import megamek.common.Engine; +import megamek.common.EntityMovementMode; + +/** + * Listener for views used by combat vehicles. + * + * @author Neoancient + * + */ +public interface CVBuildListener extends BuildListener { + + void tonnageChanged(double tonnage); + void omniChanged(boolean omni); + void superheavyChanged(boolean superheavy); + void motiveChanged(EntityMovementMode motive); + void engineChanged(Engine engine); + void turretChanged(int turretConfig); + void turretBaseWtChanged(double turret1, double turret2); + void troopSpaceChanged(double fixed, double pod); + void resetChassis(); + +} diff --git a/src/megameklab/com/ui/view/listeners/InfantryBuildListener.java b/src/megameklab/com/ui/view/listeners/InfantryBuildListener.java new file mode 100644 index 000000000..915ba9196 --- /dev/null +++ b/src/megameklab/com/ui/view/listeners/InfantryBuildListener.java @@ -0,0 +1,39 @@ +/* + * MegaMekLab - Copyright (C) 2017 - The MegaMek Team + * + * 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 megameklab.com.ui.view.listeners; + +import megamek.common.EntityMovementMode; + +/** + * Listener for views used by conventional infantry. + * + * @author Neoancient + * + */ +public interface InfantryBuildListener extends BuildListener { + void numSecondaryChanged(int count); + void numFieldGunsChanged(int count); + void antiMekChanged(boolean antiMek); + + /** + * @param motiveType The selected motive type + * @param alt If motiveType is VTOL or INF_UMU, alt is true for microlite and motorized scuba + * respectively, false for microcopter and foot scuba. It has no meaning for other + * motive types. + */ + void motiveTypeChanged(EntityMovementMode motiveType, boolean alt); + void platoonSizeChanged(int numSquads, int squadSize); + + void specializationsChanged(); +} diff --git a/src/megameklab/com/ui/view/listeners/MekBuildListener.java b/src/megameklab/com/ui/view/listeners/MekBuildListener.java new file mode 100644 index 000000000..5733edec9 --- /dev/null +++ b/src/megameklab/com/ui/view/listeners/MekBuildListener.java @@ -0,0 +1,37 @@ +/* + * MegaMekLab - Copyright (C) 2017 - The MegaMek Team + * + * 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 megameklab.com.ui.view.listeners; + +import megamek.common.Engine; +import megamek.common.EquipmentType; + +/** + * Listener for views used by Meks. + * + * @author Neoancient + * + */ +public interface MekBuildListener extends BuildListener { + void tonnageChanged(double tonnage); + void omniChanged(boolean omni); + void typeChanged(int baseType, int motiveType, long etype); + void structureChanged(EquipmentType structure); + void engineChanged(Engine engine); + void gyroChanged(int gyroType); + void cockpitChanged(int cockpitType); + void enhancementChanged(EquipmentType enhancement); + void fullHeadEjectChanged(boolean eject); + void resetChassis(); + +} diff --git a/src/megameklab/com/util/UnitUtil.java b/src/megameklab/com/util/UnitUtil.java index c56ecda6c..05683149e 100644 --- a/src/megameklab/com/util/UnitUtil.java +++ b/src/megameklab/com/util/UnitUtil.java @@ -48,6 +48,8 @@ import megamek.common.BipedMech; import megamek.common.CriticalSlot; import megamek.common.Entity; +import megamek.common.EntityMovementMode; +import megamek.common.EntityWeightClass; import megamek.common.EquipmentType; import megamek.common.ITechManager; import megamek.common.ITechnology; @@ -58,12 +60,15 @@ import megamek.common.MechView; import megamek.common.MiscType; import megamek.common.Mounted; +import megamek.common.Protomech; import megamek.common.QuadMech; +import megamek.common.SimpleTechLevel; import megamek.common.Tank; import megamek.common.TechConstants; import megamek.common.TripodMech; import megamek.common.VTOL; import megamek.common.WeaponType; +import megamek.common.annotations.Nullable; import megamek.common.logging.LogLevel; import megamek.common.logging.MMLogger; import megamek.common.verifier.EntityVerifier; @@ -1271,16 +1276,20 @@ public static double getUnallocatedAmmoTonnage(Entity unit) { public static int getMaximumArmorPoints(Entity unit) { int points = 0; - if (unit instanceof Mech) { + if (unit.hasETypeFlag(Entity.ETYPE_MECH)) { int headPoints = 3; - if (((Mech)unit).isSuperHeavy()) { + if (unit.getWeightClass() == EntityWeightClass.WEIGHT_SUPER_HEAVY) { headPoints = 4; } points = (unit.getTotalInternal() * 2) + headPoints; - } else if (unit instanceof Tank) { + } else if (unit.hasETypeFlag(Entity.ETYPE_TANK)) { points = (int) Math.floor((unit.getWeight() * 3.5) + 40); - } else if (unit instanceof BattleArmor) { + } else if (unit.hasETypeFlag(Entity.ETYPE_BATTLEARMOR)) { points = (unit.getWeightClass() * 4) + 2; + } else if (unit.hasETypeFlag(Entity.ETYPE_CONV_FIGHTER)) { + points = (int) Math.floor(unit.getWeight()); + } else if (unit.hasETypeFlag(Entity.ETYPE_AERO)) { + points = (int) Math.floor(unit.getWeight() * 8); } return points; } @@ -1343,13 +1352,24 @@ public static double getMaximumArmorTonnage(Entity unit) { * @param armorTons * @return */ - public static int getArmorPoints(Entity unit, double armorTons) { + public static int getRawArmorPoints(Entity unit, double armorTons) { double armorPerTon = 16.0 * EquipmentType.getArmorPointMultiplier( unit.getArmorType(1), unit.getArmorTechLevel(1)); if (unit.getArmorType(1) == EquipmentType.T_ARMOR_HARDENED) { armorPerTon = 8.0; } - return Math.min((int) Math.floor(armorPerTon * armorTons), + return (int)Math.floor(armorPerTon * armorTons); + } + + /** + * NOTE: only use for non-patchwork armor + * + * @param unit + * @param armorTons + * @return + */ + public static int getArmorPoints(Entity unit, double armorTons) { + return Math.min(UnitUtil.getRawArmorPoints(unit, armorTons), UnitUtil.getMaximumArmorPoints(unit)); } @@ -1369,6 +1389,35 @@ public static int getArmorPoints(Entity unit, int loc, double armorTons) { return Math.min((int) Math.floor(armorPerTon * armorTons), UnitUtil.getMaximumArmorPoints(unit, loc)); } + + /** + * Calculate the number of armor points per ton of armor for the given unit. + * + * @param en + * @param at + * @param clanArmor + * @return + */ + // TODO: aerospace and support vehicle armor + public static double getArmorPointsPerTon(Entity en, int at, boolean clanArmor) { + if (at == EquipmentType.T_ARMOR_HARDENED) { + return 8.0; + } else { + return 16.0 * EquipmentType.getArmorPointMultiplier(at, clanArmor); + } + } + + /** + * Calculate the number of armor points per ton of armor for the given unit. + * + * @param en + * @param at + * @param atTechLevel + * @return + */ + public static double getArmorPointsPerTon(Entity en, int at, int techLevel) { + return getArmorPointsPerTon(en, at, TechConstants.isClan(techLevel)); + } public static void compactCriticals(Entity unit) { for (int loc = 0; loc < unit.locations(); loc++) { @@ -1380,6 +1429,105 @@ public static void compactCriticals(Entity unit) { } } + /** + * Determine the maximum number of armor points that can be mounted in a location. + * + * @param entity + * @param location + * @return The maximum number of armor points for the location, or null if there is no maximum. + */ + public static @Nullable Integer getMaxArmor(Entity entity, int location) { + if ((location < 0) || (location >= entity.locations())) { + return 0; + } + if (entity.hasETypeFlag(Entity.ETYPE_MECH)) { + if (location == Mech.LOC_HEAD) { + return (entity.getWeightClass() == EntityWeightClass.WEIGHT_SUPER_HEAVY)? 12 : 9; + } else { + return entity.getOInternal(location) * 2; + } + } else if (entity.hasETypeFlag(Entity.ETYPE_PROTOMECH)) { + if (location == Protomech.LOC_HEAD) { + return 2 + (int)entity.getWeight() / 2; + } else if (location == Protomech.LOC_MAINGUN) { + return entity.getOInternal(location) * 3; + } else if ((location == Protomech.LOC_LARM) + || (location == Protomech.LOC_RARM)) { + return Math.min(entity.getOInternal(location) * 2, 6); + } else { + return entity.getOInternal(location) * 2; + } + } + return null; + } + + //Types available for industrial mechs, used by legalArmorsFor + private final static int[] INDUSTRIAL_TYPES = { + EquipmentType.T_ARMOR_INDUSTRIAL, EquipmentType.T_ARMOR_HEAVY_INDUSTRIAL, + EquipmentType.T_ARMOR_COMMERCIAL + }; + + /** + * Compiles a list of all armor types legal for the unit under given tech limits + * + * @param en The unit for which to compile the list + * @param techManager Provides era and tech constraints to determine whether the armor is legal + * @return A list of armors legal for the unit type under the tech constaints + */ + public static List legalArmorsFor(Entity en, ITechManager techManager) { + List retVal = new ArrayList<>(); + // IndustrialMechs can only use industrial armor below experimental rules level + if ((en instanceof Mech) && ((Mech)en).isIndustrial() + && (techManager.getTechLevel().ordinal() < SimpleTechLevel.EXPERIMENTAL.ordinal())) { + + for (int at : INDUSTRIAL_TYPES) { + String name = EquipmentType.getArmorTypeName(at, false); + EquipmentType eq = EquipmentType.get(name); + if ((null != eq) && techManager.isLegal(eq)) { + retVal.add(eq); + } + } + } else { + BigInteger flag = MiscType.F_MECH_EQUIPMENT; + if (en.hasETypeFlag(Entity.ETYPE_AERO)) { + flag = MiscType.F_AERO_EQUIPMENT; + } else if (en.hasETypeFlag(Entity.ETYPE_TANK)) { + flag = MiscType.F_TANK_EQUIPMENT; + } + boolean isLAM = en.hasETypeFlag(Entity.ETYPE_LAND_AIR_MECH); + boolean hardenedIllegal = isLAM + || (en.getMovementMode() == EntityMovementMode.VTOL) + || (en.getMovementMode() == EntityMovementMode.WIGE) + || (en.getMovementMode() == EntityMovementMode.HOVER); + + for (int at = 0; at < EquipmentType.armorNames.length; at++) { + if (at == EquipmentType.T_ARMOR_PATCHWORK) { + continue; + } + if ((at == EquipmentType.T_ARMOR_HARDENED) && hardenedIllegal) { + continue; + } + String name = EquipmentType.getArmorTypeName(at, techManager.useClanTechBase()); + EquipmentType eq = EquipmentType.get(name); + if ((null == eq) || (isLAM && ((eq.getCriticals(null) > 0)))) { + continue; + } + if ((null != eq) && eq.hasFlag(flag) && techManager.isLegal(eq)) { + retVal.add(eq); + } + if (techManager.useMixedTech()) { + name = EquipmentType.getArmorTypeName(at, !techManager.useClanTechBase()); + EquipmentType eq2 = EquipmentType.get(name); + if ((null != eq2) && (eq != eq2) && eq2.hasFlag(flag) + && techManager.isLegal(eq2)) { + retVal.add(eq2); + } + } + } + } + return retVal; + } + public static void compactCriticals(Entity unit, int loc) { int firstEmpty = -1; for (int slot = 0; slot < unit.getNumberOfCriticals(loc); slot++) { @@ -2869,6 +3017,31 @@ public static void removeISorArmorMounts(Entity unit, } } + /** + * Remove all mounts for the current armor type from a single location on the passed unit + * and sets the armor type in that location to standard. + * + * @param unit The Entity + * @param loc The location from which to remove the armor mounts. + */ + public static void resetArmor(Entity unit, int loc) { + String name = EquipmentType.getArmorTypeName(unit.getArmorType(loc), + TechConstants.isClan(unit.getArmorTechLevel(loc))); + EquipmentType eq = EquipmentType.get(name); + if (null != eq) { + for (int slot = 0; slot < unit.getNumberOfCriticals(loc); slot++) { + final CriticalSlot crit = unit.getCritical(loc, slot); + if ((null != crit) && (crit.getType() == CriticalSlot.TYPE_EQUIPMENT) + && (null != crit.getMount()) && crit.getMount().getType().equals(eq)) { + unit.getMisc().remove(crit.getMount()); + unit.setCritical(loc, slot, null); + } + } + } + unit.setArmorType(EquipmentType.T_ARMOR_STANDARD, loc); + unit.setArmorTechLevel(TechConstants.T_INTRO_BOXSET, loc); + } + public static void checkArmor(Entity unit) { if (!(unit instanceof Mech)) { diff --git a/src/megameklab/resources/Views.properties b/src/megameklab/resources/Views.properties index 9d5d435a3..ab196482d 100644 --- a/src/megameklab/resources/Views.properties +++ b/src/megameklab/resources/Views.properties @@ -153,6 +153,18 @@ ArmorView.btnRemaining.tooltip=Use all remaining unallocated tonnage for armor, ArmorView.spnArmorPoints.text=Points: ArmorView.spnArmorPoints.tooltip=The number of points of armor for the unit. +ArmorLocationView.lblRear.text=Rear +ArmorLocationView.lblMax.format=Max: %d + +ArmorAllocationView.txtUnallocated.text=Unallocated Armor Points: +ArmorAllocationView.txtAllocated.text=Allocated Armor Points: +ArmorAllocationView.txtTotal.text=Total Armor Points: +ArmorAllocationView.txtMaxPossible.text=Maximum Possible Armor Points: +ArmorAllocationView.txtWasted.text=Wasted Armor Points: +ArmorAllocationView.panPatwork.title=Patchwork +ArmorAllocationView.locationTooltip.format=Points per ton: %.2f
Current tonnage: %.3f +ArmorAllocationView.btnAutoAllocate.text=Auto-Allocate Armor + MovementView.lblBase.text=Base MovementView.lblFinal.text=Final MovementView.lblWalk.values=Walk MP:,Cruise MP:,Safe Thrust:,Walk MP: