mirror of
https://github.com/Card-Forge/forge.git
synced 2025-11-17 19:28:01 +00:00
Implement missing cards with dividable shields for damage replacement effects
This commit is contained in:
@@ -760,7 +760,7 @@ public final class CMatchUI
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
if (FThreads.isGuiThread()) { // run this now whether in EDT or not so that it doesn't clobber later stuff
|
||||
FThreads.invokeInEdtNowOrLater(focusRoutine);
|
||||
} else {
|
||||
@@ -1028,6 +1028,24 @@ public final class CMatchUI
|
||||
return result.get();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Map<GameEntityView, Integer> assignGenericAmount(final CardView effectSource, final Map<GameEntityView, Integer> target,
|
||||
final int amount, final boolean atLeastOne, final String amountLabel) {
|
||||
if (amount <= 0) {
|
||||
return Collections.emptyMap();
|
||||
}
|
||||
|
||||
final AtomicReference<Map<GameEntityView, Integer>> result = new AtomicReference<>();
|
||||
FThreads.invokeInEdtAndWait(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
final VAssignGenericAmount v = new VAssignGenericAmount(CMatchUI.this, effectSource, target, amount, atLeastOne, amountLabel);
|
||||
result.set(v.getAssignedMap());
|
||||
}});
|
||||
return result.get();
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public void openView(final TrackableCollection<PlayerView> myPlayers) {
|
||||
final GameView gameView = getGameView();
|
||||
@@ -1273,28 +1291,28 @@ public final class CMatchUI
|
||||
String stackNotificationPolicy = FModel.getPreferences().getPref(FPref.UI_STACK_EFFECT_NOTIFICATION_POLICY);
|
||||
boolean isAi = sa.getActivatingPlayer().isAI();
|
||||
boolean isTrigger = sa.isTrigger();
|
||||
int stackIndex = event.stackIndex;
|
||||
if(stackIndex == nextNotifiableStackIndex) {
|
||||
int stackIndex = event.stackIndex;
|
||||
if(stackIndex == nextNotifiableStackIndex) {
|
||||
if(ForgeConstants.STACK_EFFECT_NOTIFICATION_ALWAYS.equals(stackNotificationPolicy) || (ForgeConstants.STACK_EFFECT_NOTIFICATION_AI_AND_TRIGGERED.equals(stackNotificationPolicy) && (isAi || isTrigger))) {
|
||||
// We can go and show the modal
|
||||
SpellAbilityStackInstance si = event.si;
|
||||
|
||||
|
||||
MigLayout migLayout = new MigLayout("insets 15, left, gap 30, fill");
|
||||
JPanel mainPanel = new JPanel(migLayout);
|
||||
final Dimension parentSize = JOptionPane.getRootFrame().getSize();
|
||||
Dimension maxSize = new Dimension(1400, parentSize.height - 100);
|
||||
mainPanel.setMaximumSize(maxSize);
|
||||
mainPanel.setOpaque(false);
|
||||
mainPanel.setOpaque(false);
|
||||
|
||||
// Big Image
|
||||
addBigImageToStackModalPanel(mainPanel, si);
|
||||
|
||||
|
||||
// Text
|
||||
addTextToStackModalPanel(mainPanel,sa,si);
|
||||
|
||||
|
||||
// Small images
|
||||
int numSmallImages = 0;
|
||||
|
||||
|
||||
// If current effect is a triggered/activated ability of an enchantment card, I want to show the enchanted card
|
||||
GameEntityView enchantedEntityView = null;
|
||||
Card hostCard = sa.getHostCard();
|
||||
@@ -1308,45 +1326,45 @@ public final class CMatchUI
|
||||
&& !sa.getRootAbility().getPaidList("Sacrificed").isEmpty()) {
|
||||
// If the player activated its ability by sacrificing the enchantment, the enchantment has not anything attached anymore and the ex-enchanted card has to be searched in other ways.. for example, the green enchantment "Carapace"
|
||||
enchantedEntity = sa.getRootAbility().getPaidList("Sacrificed").get(0).getEnchantingCard();
|
||||
if(enchantedEntity != null) {
|
||||
enchantedEntityView = enchantedEntity.getView();
|
||||
if(enchantedEntity != null) {
|
||||
enchantedEntityView = enchantedEntity.getView();
|
||||
numSmallImages++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// If current effect is a triggered ability, I want to show the triggering card if present
|
||||
SpellAbility sourceSA = (SpellAbility) si.getTriggeringObject(AbilityKey.SourceSA);
|
||||
CardView sourceCardView = null;
|
||||
if(sourceSA != null) {
|
||||
sourceCardView = sourceSA.getHostCard().getView();
|
||||
numSmallImages++;
|
||||
}
|
||||
}
|
||||
|
||||
// I also want to show each type of targets (both cards and players)
|
||||
List<GameEntityView> targets = getTargets(si,new ArrayList<GameEntityView>());
|
||||
numSmallImages = numSmallImages + targets.size();
|
||||
|
||||
|
||||
// Now I know how many small images - on to render them
|
||||
if(enchantedEntityView != null) {
|
||||
addSmallImageToStackModalPanel(enchantedEntityView,mainPanel,numSmallImages);
|
||||
addSmallImageToStackModalPanel(enchantedEntityView,mainPanel,numSmallImages);
|
||||
}
|
||||
if(sourceCardView != null) {
|
||||
addSmallImageToStackModalPanel(sourceCardView,mainPanel,numSmallImages);
|
||||
addSmallImageToStackModalPanel(sourceCardView,mainPanel,numSmallImages);
|
||||
}
|
||||
for(GameEntityView gev : targets) {
|
||||
addSmallImageToStackModalPanel(gev, mainPanel, numSmallImages);
|
||||
}
|
||||
|
||||
FOptionPane.showOptionDialog(null, "Forge", null, mainPanel, ImmutableList.of(Localizer.getInstance().getMessage("lblOK")));
|
||||
}
|
||||
|
||||
FOptionPane.showOptionDialog(null, "Forge", null, mainPanel, ImmutableList.of(Localizer.getInstance().getMessage("lblOK")));
|
||||
// here the user closed the modal - time to update the next notifiable stack index
|
||||
|
||||
|
||||
}
|
||||
// In any case, I have to increase the counter
|
||||
nextNotifiableStackIndex++;
|
||||
|
||||
|
||||
} else {
|
||||
|
||||
|
||||
// Not yet time to show the modal - schedule the method again, and try again later
|
||||
Runnable tryAgainThread = new Runnable() {
|
||||
@Override
|
||||
@@ -1355,8 +1373,8 @@ public final class CMatchUI
|
||||
}
|
||||
};
|
||||
GuiBase.getInterface().invokeInEdtLater(tryAgainThread);
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
private List<GameEntityView> getTargets(SpellAbilityStackInstance si, List<GameEntityView> result){
|
||||
@@ -1380,22 +1398,22 @@ public final class CMatchUI
|
||||
|
||||
return getTargets(si.getSubInstance(),result);
|
||||
}
|
||||
|
||||
|
||||
private void addBigImageToStackModalPanel(JPanel mainPanel, SpellAbilityStackInstance si) {
|
||||
StackItemView siv = si.getView();
|
||||
int rotation = getRotation(si.getCardView());
|
||||
|
||||
FImagePanel imagePanel = new FImagePanel();
|
||||
BufferedImage bufferedImage = FImageUtil.getImage(siv.getSourceCard().getCurrentState());
|
||||
FImagePanel imagePanel = new FImagePanel();
|
||||
BufferedImage bufferedImage = FImageUtil.getImage(siv.getSourceCard().getCurrentState());
|
||||
imagePanel.setImage(bufferedImage, rotation, AutoSizeImageMode.SOURCE);
|
||||
int imageWidth = 433;
|
||||
int imageHeight = 600;
|
||||
Dimension imagePanelDimension = new Dimension(imageWidth,imageHeight);
|
||||
imagePanel.setMinimumSize(imagePanelDimension);
|
||||
|
||||
mainPanel.add(imagePanel, "cell 0 0, spany 3");
|
||||
|
||||
mainPanel.add(imagePanel, "cell 0 0, spany 3");
|
||||
}
|
||||
|
||||
|
||||
private void addTextToStackModalPanel(JPanel mainPanel, SpellAbility sa, SpellAbilityStackInstance si) {
|
||||
String who = sa.getActivatingPlayer().getName();
|
||||
String action = sa.isSpell() ? " cast " : sa.isTrigger() ? " triggered " : " activated ";
|
||||
@@ -1409,45 +1427,45 @@ public final class CMatchUI
|
||||
TargetChoices targets = si.getTargetChoices();
|
||||
sb.append(targets);
|
||||
}
|
||||
sb.append(".");
|
||||
sb.append(".");
|
||||
String message1 = sb.toString();
|
||||
String message2 = si.getStackDescription();
|
||||
String message2 = si.getStackDescription();
|
||||
String messageTotal = message1 + "\n\n" + message2;
|
||||
|
||||
|
||||
final FTextArea prompt1 = new FTextArea(messageTotal);
|
||||
prompt1.setFont(FSkin.getFont(21));
|
||||
prompt1.setAutoSize(true);
|
||||
prompt1.setMinimumSize(new Dimension(475,200));
|
||||
mainPanel.add(prompt1, "cell 1 0, aligny top");
|
||||
mainPanel.add(prompt1, "cell 1 0, aligny top");
|
||||
}
|
||||
|
||||
|
||||
private void addSmallImageToStackModalPanel(GameEntityView gameEntityView, JPanel mainPanel, int numTarget) {
|
||||
if(gameEntityView instanceof CardView) {
|
||||
CardView cardView = (CardView) gameEntityView;
|
||||
int currRotation = getRotation(cardView);
|
||||
int currRotation = getRotation(cardView);
|
||||
FImagePanel targetPanel = new FImagePanel();
|
||||
BufferedImage bufferedImage = FImageUtil.getImage(cardView.getCurrentState());
|
||||
BufferedImage bufferedImage = FImageUtil.getImage(cardView.getCurrentState());
|
||||
targetPanel.setImage(bufferedImage, currRotation, AutoSizeImageMode.SOURCE);
|
||||
int imageWidth = 217;
|
||||
int imageHeight = 300;
|
||||
Dimension targetPanelDimension = new Dimension(imageWidth,imageHeight);
|
||||
targetPanel.setMinimumSize(targetPanelDimension);
|
||||
mainPanel.add(targetPanel, "cell 1 1, split " + numTarget+ ", aligny bottom");
|
||||
mainPanel.add(targetPanel, "cell 1 1, split " + numTarget+ ", aligny bottom");
|
||||
} else if(gameEntityView instanceof PlayerView) {
|
||||
PlayerView playerView = (PlayerView) gameEntityView;
|
||||
SkinImage playerAvatar = getPlayerAvatar(playerView, 0);
|
||||
final FLabel lblIcon = new FLabel.Builder().icon(playerAvatar).build();
|
||||
Dimension dimension = playerAvatar.getSizeForPaint(JOptionPane.getRootFrame().getGraphics());
|
||||
mainPanel.add(lblIcon, "cell 1 1, split " + numTarget+ ", w " + dimension.getWidth() + ", h " + dimension.getHeight() + ", aligny bottom");
|
||||
mainPanel.add(lblIcon, "cell 1 1, split " + numTarget+ ", w " + dimension.getWidth() + ", h " + dimension.getHeight() + ", aligny bottom");
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private int getRotation(CardView cardView) {
|
||||
final int rotation;
|
||||
if (cardView.isSplitCard()) {
|
||||
String cardName = cardView.getName();
|
||||
if (cardName.isEmpty()) { cardName = cardView.getAlternateState().getName(); }
|
||||
|
||||
|
||||
PaperCard pc = StaticData.instance().getCommonCards().getCard(cardName);
|
||||
boolean hasKeywordAftermath = pc != null && Card.getCardForUi(pc).hasKeyword(Keyword.AFTERMATH);
|
||||
|
||||
@@ -1459,7 +1477,7 @@ public final class CMatchUI
|
||||
|
||||
return rotation;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public void notifyStackRemoval(GameEventSpellRemovedFromStack event) {
|
||||
// I always decrease the counter
|
||||
@@ -1474,49 +1492,49 @@ public final class CMatchUI
|
||||
createLandPopupPanel(land);
|
||||
}
|
||||
};
|
||||
GuiBase.getInterface().invokeInEdtAndWait(createPopupThread);
|
||||
GuiBase.getInterface().invokeInEdtAndWait(createPopupThread);
|
||||
}
|
||||
|
||||
private void createLandPopupPanel(Card land) {
|
||||
|
||||
|
||||
String landPlayedNotificationPolicy = FModel.getPreferences().getPref(FPref.UI_LAND_PLAYED_NOTIFICATION_POLICY);
|
||||
Player cardController = land.getController();
|
||||
boolean isAi = cardController.isAI();
|
||||
if(ForgeConstants.LAND_PLAYED_NOTIFICATION_ALWAYS.equals(landPlayedNotificationPolicy)
|
||||
Player cardController = land.getController();
|
||||
boolean isAi = cardController.isAI();
|
||||
if(ForgeConstants.LAND_PLAYED_NOTIFICATION_ALWAYS.equals(landPlayedNotificationPolicy)
|
||||
|| (ForgeConstants.LAND_PLAYED_NOTIFICATION_AI.equals(landPlayedNotificationPolicy) && (isAi))
|
||||
|| (ForgeConstants.LAND_PLAYED_NOTIFICATION_ALWAYS_FOR_NONBASIC_LANDS.equals(landPlayedNotificationPolicy) && !land.isBasicLand())
|
||||
|| (ForgeConstants.LAND_PLAYED_NOTIFICATION_AI_FOR_NONBASIC_LANDS.equals(landPlayedNotificationPolicy) && !land.isBasicLand()) && (isAi)) {
|
||||
String title = "Forge";
|
||||
String title = "Forge";
|
||||
List<String> options = ImmutableList.of(Localizer.getInstance().getMessage("lblOK"));
|
||||
|
||||
|
||||
MigLayout migLayout = new MigLayout("insets 15, left, gap 30, fill");
|
||||
JPanel mainPanel = new JPanel(migLayout);
|
||||
final Dimension parentSize = JOptionPane.getRootFrame().getSize();
|
||||
Dimension maxSize = new Dimension(1400, parentSize.height - 100);
|
||||
mainPanel.setMaximumSize(maxSize);
|
||||
mainPanel.setOpaque(false);
|
||||
|
||||
mainPanel.setOpaque(false);
|
||||
|
||||
int rotation = getRotation(land.getView());
|
||||
|
||||
FImagePanel imagePanel = new FImagePanel();
|
||||
BufferedImage bufferedImage = FImageUtil.getImage(land.getCurrentState().getView());
|
||||
FImagePanel imagePanel = new FImagePanel();
|
||||
BufferedImage bufferedImage = FImageUtil.getImage(land.getCurrentState().getView());
|
||||
imagePanel.setImage(bufferedImage, rotation, AutoSizeImageMode.SOURCE);
|
||||
int imageWidth = 433;
|
||||
int imageHeight = 600;
|
||||
Dimension imagePanelDimension = new Dimension(imageWidth,imageHeight);
|
||||
imagePanel.setMinimumSize(imagePanelDimension);
|
||||
|
||||
|
||||
mainPanel.add(imagePanel, "cell 0 0, spany 3");
|
||||
|
||||
String msg = cardController.toString() + " puts " + land.toString() + " into play into " + ZoneType.Battlefield.toString() + ".";
|
||||
|
||||
|
||||
String msg = cardController.toString() + " puts " + land.toString() + " into play into " + ZoneType.Battlefield.toString() + ".";
|
||||
|
||||
final FTextArea prompt1 = new FTextArea(msg);
|
||||
prompt1.setFont(FSkin.getFont(21));
|
||||
prompt1.setAutoSize(true);
|
||||
prompt1.setMinimumSize(new Dimension(475,200));
|
||||
mainPanel.add(prompt1, "cell 1 0, aligny top");
|
||||
|
||||
FOptionPane.showOptionDialog(null, title, null, mainPanel, options);
|
||||
}
|
||||
mainPanel.add(prompt1, "cell 1 0, aligny top");
|
||||
|
||||
FOptionPane.showOptionDialog(null, title, null, mainPanel, options);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,314 @@
|
||||
/*
|
||||
* Forge: Play Magic: the Gathering.
|
||||
* Copyright (C) 2021 Forge 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 3 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.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package forge.screens.match;
|
||||
|
||||
import java.awt.Dialog.ModalityType;
|
||||
import java.awt.Dimension;
|
||||
import java.awt.event.ActionEvent;
|
||||
import java.awt.event.ActionListener;
|
||||
import java.awt.event.MouseAdapter;
|
||||
import java.awt.event.MouseEvent;
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import javax.swing.JLabel;
|
||||
import javax.swing.JPanel;
|
||||
import javax.swing.SwingConstants;
|
||||
import javax.swing.SwingUtilities;
|
||||
import javax.swing.border.Border;
|
||||
|
||||
import forge.game.GameEntityView;
|
||||
import forge.game.card.CardView;
|
||||
import forge.game.player.PlayerView;
|
||||
import forge.gui.SOverlayUtils;
|
||||
import forge.toolbox.FButton;
|
||||
import forge.toolbox.FLabel;
|
||||
import forge.toolbox.FScrollPane;
|
||||
import forge.toolbox.FSkin;
|
||||
import forge.toolbox.FSkin.SkinnedPanel;
|
||||
import forge.util.Localizer;
|
||||
import forge.util.TextUtil;
|
||||
import forge.view.FDialog;
|
||||
import forge.view.arcane.CardPanel;
|
||||
import net.miginfocom.swing.MigLayout;
|
||||
|
||||
/**
|
||||
* Assembles Swing components of assign damage dialog.
|
||||
*
|
||||
* This needs a JDialog to maintain a modal state.
|
||||
* Without the modal state, the PhaseHandler automatically
|
||||
* moves forward to phase Main2 without assigning damage.
|
||||
*
|
||||
* <br><br><i>(V at beginning of class name denotes a view class.)</i>
|
||||
*/
|
||||
public class VAssignGenericAmount {
|
||||
final Localizer localizer = Localizer.getInstance();
|
||||
private final CMatchUI matchUI;
|
||||
|
||||
// Width and height of assign dialog
|
||||
private final int wDlg = 700;
|
||||
private final int hDlg = 500;
|
||||
private final FDialog dlg = new FDialog();
|
||||
|
||||
// Amount storage
|
||||
private final int totalAmountToAssign;
|
||||
|
||||
private final String lblAmount;
|
||||
private final JLabel lblTotalAmount;
|
||||
// Label Buttons
|
||||
private final FButton btnOK = new FButton(localizer.getMessage("lblOk"));
|
||||
private final FButton btnReset = new FButton(localizer.getMessage("lblReset"));
|
||||
|
||||
private static class AssignTarget {
|
||||
public final GameEntityView entity;
|
||||
public final JLabel label;
|
||||
public final int max;
|
||||
public int amount;
|
||||
|
||||
public AssignTarget(final GameEntityView e, final JLabel lbl, int max0) {
|
||||
entity = e;
|
||||
label = lbl;
|
||||
max = max0;
|
||||
amount = 0;
|
||||
}
|
||||
}
|
||||
|
||||
private final List<AssignTarget> targetsList = new ArrayList<>();
|
||||
private final Map<GameEntityView, AssignTarget> targetsMap = new HashMap<>();
|
||||
|
||||
// Mouse actions
|
||||
private final MouseAdapter mad = new MouseAdapter() {
|
||||
@Override
|
||||
public void mouseEntered(final MouseEvent evt) {
|
||||
((CardPanel) evt.getSource()).setBorder(new FSkin.LineSkinBorder(FSkin.getColor(FSkin.Colors.CLR_ACTIVE), 2));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void mouseExited(final MouseEvent evt) {
|
||||
((CardPanel) evt.getSource()).setBorder((Border)null);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void mousePressed(final MouseEvent evt) {
|
||||
CardView source = ((CardPanel) evt.getSource()).getCard(); // will be NULL for player
|
||||
|
||||
boolean meta = evt.isControlDown();
|
||||
boolean isLMB = SwingUtilities.isLeftMouseButton(evt);
|
||||
boolean isRMB = SwingUtilities.isRightMouseButton(evt);
|
||||
|
||||
if ( isLMB || isRMB)
|
||||
assignAmountTo(source, meta, isLMB);
|
||||
}
|
||||
};
|
||||
|
||||
public VAssignGenericAmount(final CMatchUI matchUI, final CardView effectSource, final Map<GameEntityView, Integer> targets, final int amount, final boolean atLeastOne, final String amountLabel) {
|
||||
this.matchUI = matchUI;
|
||||
dlg.setTitle(localizer.getMessage("lbLAssignAmountForEffect", amountLabel, effectSource.toString()));
|
||||
|
||||
totalAmountToAssign = amount;
|
||||
|
||||
lblAmount = amountLabel;
|
||||
lblTotalAmount = new FLabel.Builder().text(localizer.getMessage("lblTotalAmountText", lblAmount)).build();
|
||||
|
||||
// Top-level UI stuff
|
||||
final JPanel overlay = SOverlayUtils.genericOverlay();
|
||||
final SkinnedPanel pnlMain = new SkinnedPanel();
|
||||
pnlMain.setBackground(FSkin.getColor(FSkin.Colors.CLR_THEME2));
|
||||
|
||||
// Effect Source area
|
||||
final CardPanel pnlSource = new CardPanel(matchUI, effectSource);
|
||||
pnlSource.setOpaque(false);
|
||||
pnlSource.setCardBounds(0, 0, 105, 150);
|
||||
|
||||
final JPanel pnlInfo = new JPanel(new MigLayout("insets 0, gap 0, wrap"));
|
||||
pnlInfo.setOpaque(false);
|
||||
pnlInfo.add(lblTotalAmount, "gap 0 0 20px 5px");
|
||||
pnlInfo.add(new FLabel.Builder().text(localizer.getMessage("lblLClickAmountMessage", lblAmount)).build(), "gap 0 0 0 5px");
|
||||
pnlInfo.add(new FLabel.Builder().text(localizer.getMessage("lblRClickAmountMessage", lblAmount)).build(), "gap 0 0 0 5px");
|
||||
|
||||
// Targets area
|
||||
final JPanel pnlTargets = new JPanel();
|
||||
pnlTargets.setOpaque(false);
|
||||
int cols = targets.size();
|
||||
final String wrap = "wrap " + cols;
|
||||
pnlTargets.setLayout(new MigLayout("insets 0, gap 0, ax center, " + wrap));
|
||||
|
||||
final FScrollPane scrTargets = new FScrollPane(pnlTargets, false);
|
||||
|
||||
// Top row of cards...
|
||||
for (final Map.Entry<GameEntityView, Integer> e : targets.entrySet()) {
|
||||
int maxAmount = e.getValue() != null ? e.getValue() : amount;
|
||||
final AssignTarget at = new AssignTarget(e.getKey(), new FLabel.Builder().text("0").fontSize(18).fontAlign(SwingConstants.CENTER).build(), maxAmount);
|
||||
addPanelForTarget(pnlTargets, at);
|
||||
}
|
||||
|
||||
// ... bottom row of labels.
|
||||
for (final AssignTarget l : targetsList) {
|
||||
pnlTargets.add(l.label, "w 145px!, h 30px!, gap 5px 5px 0 5px");
|
||||
}
|
||||
|
||||
btnOK.addActionListener(new ActionListener() {
|
||||
@Override public void actionPerformed(ActionEvent arg0) { finish(); } });
|
||||
btnReset.addActionListener(new ActionListener() {
|
||||
@Override public void actionPerformed(ActionEvent arg0) { resetAssignedAmount(); initialAssignAmount(atLeastOne); } });
|
||||
|
||||
// Final UI layout
|
||||
pnlMain.setLayout(new MigLayout("insets 0, gap 0, wrap 2, ax center"));
|
||||
pnlMain.add(pnlSource, "w 125px!, h 160px!, gap 50px 0 0 15px");
|
||||
pnlMain.add(pnlInfo, "gap 20px 0 0 15px");
|
||||
pnlMain.add(scrTargets, "w 96%!, gap 2% 0 0 0, pushy, growy, ax center, span 2");
|
||||
|
||||
final JPanel pnlButtons = new JPanel(new MigLayout("insets 0, gap 0, ax center"));
|
||||
pnlButtons.setOpaque(false);
|
||||
pnlButtons.add(btnOK, "w 110px!, h 30px!, gap 0 10px 0 0");
|
||||
pnlButtons.add(btnReset, "w 110px!, h 30px!");
|
||||
|
||||
pnlMain.add(pnlButtons, "ax center, w 350px!, gap 10px 10px 10px 10px, span 2");
|
||||
overlay.add(pnlMain);
|
||||
|
||||
pnlMain.getRootPane().setDefaultButton(btnOK);
|
||||
|
||||
initialAssignAmount(atLeastOne);
|
||||
SOverlayUtils.showOverlay();
|
||||
|
||||
dlg.setUndecorated(true);
|
||||
dlg.setContentPane(pnlMain);
|
||||
dlg.setSize(new Dimension(wDlg, hDlg));
|
||||
dlg.setLocation((overlay.getWidth() - wDlg) / 2, (overlay.getHeight() - hDlg) / 2);
|
||||
dlg.setModalityType(ModalityType.APPLICATION_MODAL);
|
||||
dlg.setVisible(true);
|
||||
}
|
||||
|
||||
private void addPanelForTarget(final JPanel pnlTargets, final AssignTarget at) {
|
||||
CardView cv = null;
|
||||
if (at.entity instanceof CardView) {
|
||||
cv = (CardView)at.entity;
|
||||
} else if (at.entity instanceof PlayerView) {
|
||||
final PlayerView p = (PlayerView)at.entity;
|
||||
cv = new CardView(-1, null, at.entity.toString(), p, matchUI.getAvatarImage(p.getLobbyPlayerName()));
|
||||
} else {
|
||||
return;
|
||||
}
|
||||
final CardPanel cp = new CardPanel(matchUI, cv);
|
||||
cp.setCardBounds(0, 0, 105, 150);
|
||||
cp.setOpaque(true);
|
||||
pnlTargets.add(cp, "w 145px!, h 170px!, gap 5px 5px 3px 3px, ax center");
|
||||
cp.addMouseListener(mad);
|
||||
targetsMap.put(cv, at);
|
||||
targetsList.add(at);
|
||||
}
|
||||
|
||||
private void assignAmountTo(CardView source, final boolean meta, final boolean isAdding) {
|
||||
AssignTarget at = targetsMap.get(source);
|
||||
int assigned = at.amount;
|
||||
int leftToAssign = Math.max(0, at.max - assigned);
|
||||
int amountToAdd = isAdding ? 1 : -1;
|
||||
int remainingAmount = Math.min(getRemainingAmount(), leftToAssign);
|
||||
// Left click adds, right click substracts.
|
||||
// Hold Ctrl to assign to maximum amount
|
||||
if (meta) {
|
||||
if (isAdding) {
|
||||
amountToAdd = leftToAssign > 0 ? leftToAssign : 0;
|
||||
} else {
|
||||
amountToAdd = -assigned;
|
||||
}
|
||||
}
|
||||
|
||||
if (amountToAdd > remainingAmount) {
|
||||
amountToAdd = remainingAmount;
|
||||
}
|
||||
|
||||
if (0 == amountToAdd || amountToAdd + assigned < 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
addAssignedAmount(at, amountToAdd);
|
||||
updateLabels();
|
||||
}
|
||||
|
||||
private void initialAssignAmount(boolean atLeastOne) {
|
||||
if (!atLeastOne) {
|
||||
updateLabels();
|
||||
return;
|
||||
}
|
||||
|
||||
for(AssignTarget at : targetsList) {
|
||||
addAssignedAmount(at, 1);
|
||||
}
|
||||
updateLabels();
|
||||
}
|
||||
|
||||
private void resetAssignedAmount() {
|
||||
for(AssignTarget at : targetsList)
|
||||
at.amount = 0;
|
||||
}
|
||||
|
||||
private void addAssignedAmount(final AssignTarget at, int addedAmount) {
|
||||
// If we don't have enough left or we're trying to unassign too much return
|
||||
final int canAssign = getRemainingAmount();
|
||||
if (canAssign < addedAmount) {
|
||||
addedAmount = canAssign;
|
||||
}
|
||||
|
||||
at.amount = Math.max(0, addedAmount + at.amount);
|
||||
}
|
||||
|
||||
private int getRemainingAmount() {
|
||||
int spent = 0;
|
||||
for(AssignTarget at : targetsList) {
|
||||
spent += at.amount;
|
||||
}
|
||||
return totalAmountToAssign - spent;
|
||||
}
|
||||
|
||||
/** Updates labels and other UI elements.*/
|
||||
private void updateLabels() {
|
||||
int amountLeft = totalAmountToAssign;
|
||||
|
||||
for ( AssignTarget at : targetsList )
|
||||
{
|
||||
amountLeft -= at.amount;
|
||||
StringBuilder sb = new StringBuilder();
|
||||
sb.append(at.amount);
|
||||
if (at.max - at.amount == 0) {
|
||||
sb.append(" (").append(localizer.getMessage("lblMax")).append(")");
|
||||
}
|
||||
at.label.setText(sb.toString());
|
||||
}
|
||||
|
||||
lblTotalAmount.setText(TextUtil.concatNoSpace(localizer.getMessage("lblAvailableAmount", lblAmount), ": " , String.valueOf(amountLeft), " (of ", String.valueOf(totalAmountToAssign), ")"));
|
||||
btnOK.setEnabled(amountLeft == 0);
|
||||
}
|
||||
|
||||
private void finish() {
|
||||
if ( getRemainingAmount() > 0 )
|
||||
return;
|
||||
|
||||
dlg.dispose();
|
||||
SOverlayUtils.hideOverlay();
|
||||
}
|
||||
|
||||
public Map<GameEntityView, Integer> getAssignedMap() {
|
||||
Map<GameEntityView, Integer> result = new HashMap<>(targetsList.size());
|
||||
for (AssignTarget at : targetsList)
|
||||
result.put(at.entity, at.amount);
|
||||
return result;
|
||||
}
|
||||
}
|
||||
@@ -146,6 +146,12 @@ public class PlayerControllerForTests extends PlayerController {
|
||||
throw new IllegalStateException("Erring on the side of caution here...");
|
||||
}
|
||||
|
||||
@Override
|
||||
public Map<GameEntity, Integer> divideShield(Card effectSource, Map<GameEntity, Integer> affected, int shieldAmount) {
|
||||
throw new IllegalStateException("Erring on the side of caution here...");
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public Integer announceRequirements(SpellAbility ability, String announce) {
|
||||
throw new IllegalStateException("Erring on the side of caution here...");
|
||||
|
||||
Reference in New Issue
Block a user