mirror of
https://github.com/Card-Forge/forge.git
synced 2025-11-20 04:38:00 +00:00
Merge remote-tracking branch 'remotes/core/master' into newBranch
This commit is contained in:
@@ -12,10 +12,12 @@ public class GameEventSpellAbilityCast extends GameEvent {
|
|||||||
public final SpellAbility sa;
|
public final SpellAbility sa;
|
||||||
public final SpellAbilityStackInstance si;
|
public final SpellAbilityStackInstance si;
|
||||||
public final boolean replicate;
|
public final boolean replicate;
|
||||||
|
public final int stackIndex;
|
||||||
|
|
||||||
public GameEventSpellAbilityCast(SpellAbility sp, SpellAbilityStackInstance si, boolean replicate) {
|
public GameEventSpellAbilityCast(SpellAbility sp, SpellAbilityStackInstance si, int stackIndex, boolean replicate) {
|
||||||
sa = sp;
|
sa = sp;
|
||||||
this.si = si;
|
this.si = si;
|
||||||
|
this.stackIndex = stackIndex;
|
||||||
this.replicate = replicate;
|
this.replicate = replicate;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -414,6 +414,7 @@ public class MagicStack /* extends MyObservable */ implements Iterable<SpellAbil
|
|||||||
final SpellAbilityStackInstance si = new SpellAbilityStackInstance(sp);
|
final SpellAbilityStackInstance si = new SpellAbilityStackInstance(sp);
|
||||||
|
|
||||||
stack.addFirst(si);
|
stack.addFirst(si);
|
||||||
|
int stackIndex = stack.size() - 1;
|
||||||
|
|
||||||
// 2012-07-21 the following comparison needs to move below the pushes but somehow screws up priority
|
// 2012-07-21 the following comparison needs to move below the pushes but somehow screws up priority
|
||||||
// When it's down there. That makes absolutely no sense to me, so i'm putting it back for now
|
// When it's down there. That makes absolutely no sense to me, so i'm putting it back for now
|
||||||
@@ -430,7 +431,7 @@ public class MagicStack /* extends MyObservable */ implements Iterable<SpellAbil
|
|||||||
sp.getActivatingPlayer().setActivateLoyaltyAbilityThisTurn(true);
|
sp.getActivatingPlayer().setActivateLoyaltyAbilityThisTurn(true);
|
||||||
}
|
}
|
||||||
game.updateStackForView();
|
game.updateStackForView();
|
||||||
game.fireEvent(new GameEventSpellAbilityCast(sp, si, false));
|
game.fireEvent(new GameEventSpellAbilityCast(sp, si, stackIndex, false));
|
||||||
return si;
|
return si;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -288,16 +288,17 @@ public class GuiChoose {
|
|||||||
public static List<CardView> manipulateCardList(final CMatchUI gui, final String title, final Iterable<CardView> cards, final Iterable<CardView> manipulable,
|
public static List<CardView> manipulateCardList(final CMatchUI gui, final String title, final Iterable<CardView> cards, final Iterable<CardView> manipulable,
|
||||||
final boolean toTop, final boolean toBottom, final boolean toAnywhere) {
|
final boolean toTop, final boolean toBottom, final boolean toAnywhere) {
|
||||||
gui.setSelectables(manipulable);
|
gui.setSelectables(manipulable);
|
||||||
final Callable<List<CardView>> callable = new Callable<List<CardView>>() {
|
@SuppressWarnings("Convert2Lambda") // Avoid lambdas to maintain compatibility with Android 5 API
|
||||||
@Override
|
final Callable<List<CardView>> callable = new Callable<List<CardView>>() {
|
||||||
public List<CardView> call() {
|
@Override
|
||||||
ListCardArea tempArea = ListCardArea.show(gui,title,cards,manipulable,toTop,toBottom,toAnywhere);
|
public List<CardView> call() {
|
||||||
// tempArea.pack();
|
ListCardArea tempArea = ListCardArea.show(gui,title,cards,manipulable,toTop,toBottom,toAnywhere);
|
||||||
tempArea.show();
|
|
||||||
final List<CardView> cardList = tempArea.getCards();
|
// tempArea.pack();
|
||||||
return cardList;
|
tempArea.setVisible(true);
|
||||||
}
|
return tempArea.getCards();
|
||||||
};
|
}
|
||||||
|
};
|
||||||
final FutureTask<List<CardView>> ft = new FutureTask<>(callable);
|
final FutureTask<List<CardView>> ft = new FutureTask<>(callable);
|
||||||
FThreads.invokeInEdtAndWait(ft);
|
FThreads.invokeInEdtAndWait(ft);
|
||||||
gui.clearSelectables();
|
gui.clearSelectables();
|
||||||
|
|||||||
@@ -17,10 +17,9 @@ import forge.screens.home.EMenuGroup;
|
|||||||
import forge.screens.home.IVSubmenu;
|
import forge.screens.home.IVSubmenu;
|
||||||
import forge.screens.home.VHomeUI;
|
import forge.screens.home.VHomeUI;
|
||||||
import forge.toolbox.*;
|
import forge.toolbox.*;
|
||||||
import forge.util.storage.IStorage;
|
|
||||||
import forge.util.Localizer;
|
import forge.util.Localizer;
|
||||||
|
import forge.util.WordUtil;
|
||||||
import net.miginfocom.swing.MigLayout;
|
import net.miginfocom.swing.MigLayout;
|
||||||
import org.apache.commons.lang3.text.WordUtils;
|
|
||||||
|
|
||||||
import javax.swing.*;
|
import javax.swing.*;
|
||||||
import javax.swing.plaf.basic.BasicComboBoxRenderer;
|
import javax.swing.plaf.basic.BasicComboBoxRenderer;
|
||||||
@@ -243,17 +242,15 @@ public enum VSubmenuQuestData implements IVSubmenu<CSubmenuQuestData> {
|
|||||||
cboAllowUnlocks.setSelected(true);
|
cboAllowUnlocks.setSelected(true);
|
||||||
|
|
||||||
final Map<String, String> preconDescriptions = new HashMap<>();
|
final Map<String, String> preconDescriptions = new HashMap<>();
|
||||||
final IStorage<PreconDeck> preconDecks = QuestController.getPrecons();
|
|
||||||
|
|
||||||
for (final PreconDeck preconDeck : preconDecks) {
|
for (final PreconDeck preconDeck : QuestController.getPrecons()) {
|
||||||
if (QuestController.getPreconDeals(preconDeck).getMinWins() > 0) {
|
if (QuestController.getPreconDeals(preconDeck).getMinWins() > 0) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
final String name = preconDeck.getName();
|
final String name = preconDeck.getName();
|
||||||
cbxPreconDeck.addItem(name);
|
cbxPreconDeck.addItem(name);
|
||||||
String description = preconDeck.getDescription();
|
String description = preconDeck.getDescription();
|
||||||
description = "<html>" + WordUtils.wrap(description, 40, "<br>", false) + "</html>";
|
preconDescriptions.put(name, WordUtil.wordWrapAsHTML(description));
|
||||||
preconDescriptions.put(name, description);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// The cbx needs strictly typed renderer
|
// The cbx needs strictly typed renderer
|
||||||
|
|||||||
@@ -227,6 +227,7 @@ public enum CSubmenuPreferences implements ICDoc {
|
|||||||
initializeDefaultFontSizeComboBox();
|
initializeDefaultFontSizeComboBox();
|
||||||
initializeMulliganRuleComboBox();
|
initializeMulliganRuleComboBox();
|
||||||
initializeAiProfilesComboBox();
|
initializeAiProfilesComboBox();
|
||||||
|
initializeStackAdditionsComboBox();
|
||||||
initializeColorIdentityCombobox();
|
initializeColorIdentityCombobox();
|
||||||
initializeAutoYieldModeComboBox();
|
initializeAutoYieldModeComboBox();
|
||||||
initializeCounterDisplayTypeComboBox();
|
initializeCounterDisplayTypeComboBox();
|
||||||
@@ -408,6 +409,16 @@ public enum CSubmenuPreferences implements ICDoc {
|
|||||||
panel.setComboBox(comboBox, selectedItem);
|
panel.setComboBox(comboBox, selectedItem);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void initializeStackAdditionsComboBox() {
|
||||||
|
final String[] elems = {ForgeConstants.STACK_EFFECT_NOTIFICATION_NEVER, ForgeConstants.STACK_EFFECT_NOTIFICATION_ALWAYS,
|
||||||
|
ForgeConstants.STACK_EFFECT_NOTIFICATION_AI_AND_TRIGGERED};
|
||||||
|
final FPref userSetting = FPref.UI_STACK_EFFECT_NOTIFICATION_POLICY;
|
||||||
|
final FComboBoxPanel<String> panel = this.view.getCbpStackAdditionsComboBoxPanel();
|
||||||
|
final FComboBox<String> comboBox = createComboBox(elems, userSetting);
|
||||||
|
final String selectedItem = this.prefs.getPref(userSetting);
|
||||||
|
panel.setComboBox(comboBox, selectedItem);
|
||||||
|
}
|
||||||
|
|
||||||
private void initializeColorIdentityCombobox() {
|
private void initializeColorIdentityCombobox() {
|
||||||
final String[] elems = {ForgeConstants.DISP_CURRENT_COLORS_NEVER, ForgeConstants.DISP_CURRENT_COLORS_CHANGED,
|
final String[] elems = {ForgeConstants.DISP_CURRENT_COLORS_NEVER, ForgeConstants.DISP_CURRENT_COLORS_CHANGED,
|
||||||
ForgeConstants.DISP_CURRENT_COLORS_MULTICOLOR, ForgeConstants.DISP_CURRENT_COLORS_MULTI_OR_CHANGED,
|
ForgeConstants.DISP_CURRENT_COLORS_MULTICOLOR, ForgeConstants.DISP_CURRENT_COLORS_MULTI_OR_CHANGED,
|
||||||
|
|||||||
@@ -116,6 +116,7 @@ public enum VSubmenuPreferences implements IVSubmenu<CSubmenuPreferences> {
|
|||||||
private final FComboBoxPanel<String> cbpDefaultFontSize = new FComboBoxPanel<>(localizer.getMessage("cbpDefaultFontSize")+":");
|
private final FComboBoxPanel<String> cbpDefaultFontSize = new FComboBoxPanel<>(localizer.getMessage("cbpDefaultFontSize")+":");
|
||||||
private final FComboBoxPanel<String> cbpMulliganRule = new FComboBoxPanel<>(localizer.getMessage("cbpMulliganRule")+":");
|
private final FComboBoxPanel<String> cbpMulliganRule = new FComboBoxPanel<>(localizer.getMessage("cbpMulliganRule")+":");
|
||||||
private final FComboBoxPanel<String> cbpAiProfiles = new FComboBoxPanel<>(localizer.getMessage("cbpAiProfiles")+":");
|
private final FComboBoxPanel<String> cbpAiProfiles = new FComboBoxPanel<>(localizer.getMessage("cbpAiProfiles")+":");
|
||||||
|
private final FComboBoxPanel<String> cbpStackAdditions = new FComboBoxPanel<>(localizer.getMessage("cbpStackAdditions")+":");
|
||||||
private final FComboBoxPanel<String> cbpDisplayCurrentCardColors = new FComboBoxPanel<>(localizer.getMessage("cbpDisplayCurrentCardColors")+":");
|
private final FComboBoxPanel<String> cbpDisplayCurrentCardColors = new FComboBoxPanel<>(localizer.getMessage("cbpDisplayCurrentCardColors")+":");
|
||||||
private final FComboBoxPanel<String> cbpAutoYieldMode = new FComboBoxPanel<>(localizer.getMessage("cbpAutoYieldMode")+":");
|
private final FComboBoxPanel<String> cbpAutoYieldMode = new FComboBoxPanel<>(localizer.getMessage("cbpAutoYieldMode")+":");
|
||||||
private final FComboBoxPanel<String> cbpCounterDisplayType = new FComboBoxPanel<>(localizer.getMessage("cbpCounterDisplayType")+":");
|
private final FComboBoxPanel<String> cbpCounterDisplayType = new FComboBoxPanel<>(localizer.getMessage("cbpCounterDisplayType")+":");
|
||||||
@@ -194,6 +195,9 @@ public enum VSubmenuPreferences implements IVSubmenu<CSubmenuPreferences> {
|
|||||||
pnlPrefs.add(cbManaLostPrompt, titleConstraints);
|
pnlPrefs.add(cbManaLostPrompt, titleConstraints);
|
||||||
pnlPrefs.add(new NoteLabel(localizer.getMessage("nlManaLostPrompt")), descriptionConstraints);
|
pnlPrefs.add(new NoteLabel(localizer.getMessage("nlManaLostPrompt")), descriptionConstraints);
|
||||||
|
|
||||||
|
pnlPrefs.add(cbpStackAdditions, comboBoxConstraints);
|
||||||
|
pnlPrefs.add(new NoteLabel(localizer.getMessage("nlpStackAdditions")), descriptionConstraints);
|
||||||
|
|
||||||
pnlPrefs.add(cbEnforceDeckLegality, titleConstraints);
|
pnlPrefs.add(cbEnforceDeckLegality, titleConstraints);
|
||||||
pnlPrefs.add(new NoteLabel(localizer.getMessage("nlEnforceDeckLegality")), descriptionConstraints);
|
pnlPrefs.add(new NoteLabel(localizer.getMessage("nlEnforceDeckLegality")), descriptionConstraints);
|
||||||
|
|
||||||
@@ -649,6 +653,10 @@ public enum VSubmenuPreferences implements IVSubmenu<CSubmenuPreferences> {
|
|||||||
return cbpAiProfiles;
|
return cbpAiProfiles;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public FComboBoxPanel<String> getCbpStackAdditionsComboBoxPanel() {
|
||||||
|
return cbpStackAdditions;
|
||||||
|
}
|
||||||
|
|
||||||
public FComboBoxPanel<GameLogEntryType> getGameLogVerbosityComboBoxPanel() {
|
public FComboBoxPanel<GameLogEntryType> getGameLogVerbosityComboBoxPanel() {
|
||||||
return cbpGameLogEntryType;
|
return cbpGameLogEntryType;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -18,7 +18,9 @@
|
|||||||
package forge.screens.match;
|
package forge.screens.match;
|
||||||
|
|
||||||
import java.awt.Component;
|
import java.awt.Component;
|
||||||
|
import java.awt.Dimension;
|
||||||
import java.awt.event.KeyEvent;
|
import java.awt.event.KeyEvent;
|
||||||
|
import java.awt.image.BufferedImage;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.Collection;
|
import java.util.Collection;
|
||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
@@ -30,6 +32,8 @@ import java.util.Map.Entry;
|
|||||||
import java.util.concurrent.atomic.AtomicReference;
|
import java.util.concurrent.atomic.AtomicReference;
|
||||||
|
|
||||||
import javax.swing.JMenu;
|
import javax.swing.JMenu;
|
||||||
|
import javax.swing.JOptionPane;
|
||||||
|
import javax.swing.JPanel;
|
||||||
import javax.swing.JPopupMenu;
|
import javax.swing.JPopupMenu;
|
||||||
import javax.swing.KeyStroke;
|
import javax.swing.KeyStroke;
|
||||||
import javax.swing.SwingUtilities;
|
import javax.swing.SwingUtilities;
|
||||||
@@ -41,25 +45,43 @@ import com.google.common.collect.ImmutableList;
|
|||||||
import com.google.common.collect.ImmutableMap;
|
import com.google.common.collect.ImmutableMap;
|
||||||
|
|
||||||
import forge.FThreads;
|
import forge.FThreads;
|
||||||
|
import forge.GuiBase;
|
||||||
import forge.ImageCache;
|
import forge.ImageCache;
|
||||||
import forge.LobbyPlayer;
|
import forge.LobbyPlayer;
|
||||||
import forge.Singletons;
|
import forge.Singletons;
|
||||||
|
import forge.StaticData;
|
||||||
import forge.assets.FSkinProp;
|
import forge.assets.FSkinProp;
|
||||||
|
import forge.card.CardStateName;
|
||||||
import forge.control.KeyboardShortcuts;
|
import forge.control.KeyboardShortcuts;
|
||||||
import forge.deck.CardPool;
|
import forge.deck.CardPool;
|
||||||
import forge.deck.Deck;
|
import forge.deck.Deck;
|
||||||
import forge.deckchooser.FDeckViewer;
|
import forge.deckchooser.FDeckViewer;
|
||||||
|
import forge.game.GameEntity;
|
||||||
import forge.game.GameEntityView;
|
import forge.game.GameEntityView;
|
||||||
import forge.game.GameView;
|
import forge.game.GameView;
|
||||||
|
import forge.game.ability.AbilityKey;
|
||||||
|
import forge.game.card.Card;
|
||||||
import forge.game.card.CardView;
|
import forge.game.card.CardView;
|
||||||
|
import forge.game.card.CardView.CardStateView;
|
||||||
import forge.game.combat.CombatView;
|
import forge.game.combat.CombatView;
|
||||||
|
import forge.game.event.GameEventSpellAbilityCast;
|
||||||
|
import forge.game.event.GameEventSpellRemovedFromStack;
|
||||||
|
import forge.game.keyword.Keyword;
|
||||||
import forge.game.phase.PhaseType;
|
import forge.game.phase.PhaseType;
|
||||||
import forge.game.player.DelayedReveal;
|
import forge.game.player.DelayedReveal;
|
||||||
import forge.game.player.IHasIcon;
|
import forge.game.player.IHasIcon;
|
||||||
import forge.game.player.PlayerView;
|
import forge.game.player.PlayerView;
|
||||||
|
import forge.game.spellability.SpellAbility;
|
||||||
|
import forge.game.spellability.SpellAbilityStackInstance;
|
||||||
import forge.game.spellability.SpellAbilityView;
|
import forge.game.spellability.SpellAbilityView;
|
||||||
|
import forge.game.spellability.StackItemView;
|
||||||
|
import forge.game.spellability.TargetChoices;
|
||||||
import forge.game.zone.ZoneType;
|
import forge.game.zone.ZoneType;
|
||||||
import forge.gui.*;
|
import forge.gui.FNetOverlay;
|
||||||
|
import forge.gui.GuiChoose;
|
||||||
|
import forge.gui.GuiDialog;
|
||||||
|
import forge.gui.GuiUtils;
|
||||||
|
import forge.gui.SOverlayUtils;
|
||||||
import forge.gui.framework.DragCell;
|
import forge.gui.framework.DragCell;
|
||||||
import forge.gui.framework.EDocID;
|
import forge.gui.framework.EDocID;
|
||||||
import forge.gui.framework.FScreen;
|
import forge.gui.framework.FScreen;
|
||||||
@@ -74,6 +96,7 @@ import forge.match.AbstractGuiGame;
|
|||||||
import forge.menus.IMenuProvider;
|
import forge.menus.IMenuProvider;
|
||||||
import forge.model.FModel;
|
import forge.model.FModel;
|
||||||
import forge.player.PlayerZoneUpdate;
|
import forge.player.PlayerZoneUpdate;
|
||||||
|
import forge.properties.ForgeConstants;
|
||||||
import forge.properties.ForgePreferences;
|
import forge.properties.ForgePreferences;
|
||||||
import forge.properties.ForgePreferences.FPref;
|
import forge.properties.ForgePreferences.FPref;
|
||||||
import forge.screens.match.controllers.CAntes;
|
import forge.screens.match.controllers.CAntes;
|
||||||
@@ -88,19 +111,25 @@ import forge.screens.match.menus.CMatchUIMenus;
|
|||||||
import forge.screens.match.views.VField;
|
import forge.screens.match.views.VField;
|
||||||
import forge.screens.match.views.VHand;
|
import forge.screens.match.views.VHand;
|
||||||
import forge.toolbox.FButton;
|
import forge.toolbox.FButton;
|
||||||
|
import forge.toolbox.FLabel;
|
||||||
import forge.toolbox.FOptionPane;
|
import forge.toolbox.FOptionPane;
|
||||||
import forge.toolbox.FSkin;
|
import forge.toolbox.FSkin;
|
||||||
import forge.toolbox.FSkin.SkinImage;
|
import forge.toolbox.FSkin.SkinImage;
|
||||||
|
import forge.toolbox.FTextArea;
|
||||||
|
import forge.toolbox.imaging.FImagePanel;
|
||||||
|
import forge.toolbox.imaging.FImagePanel.AutoSizeImageMode;
|
||||||
|
import forge.toolbox.imaging.FImageUtil;
|
||||||
import forge.toolbox.special.PhaseIndicator;
|
import forge.toolbox.special.PhaseIndicator;
|
||||||
import forge.toolbox.special.PhaseLabel;
|
import forge.toolbox.special.PhaseLabel;
|
||||||
import forge.trackable.TrackableCollection;
|
import forge.trackable.TrackableCollection;
|
||||||
|
import forge.util.ITriggerEvent;
|
||||||
import forge.util.collect.FCollection;
|
import forge.util.collect.FCollection;
|
||||||
import forge.util.collect.FCollectionView;
|
import forge.util.collect.FCollectionView;
|
||||||
import forge.util.ITriggerEvent;
|
|
||||||
import forge.util.gui.SOptionPane;
|
import forge.util.gui.SOptionPane;
|
||||||
import forge.view.FView;
|
import forge.view.FView;
|
||||||
import forge.view.arcane.CardPanel;
|
import forge.view.arcane.CardPanel;
|
||||||
import forge.view.arcane.FloatingZone;
|
import forge.view.arcane.FloatingZone;
|
||||||
|
import net.miginfocom.swing.MigLayout;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Constructs instance of match UI controller, used as a single point of
|
* Constructs instance of match UI controller, used as a single point of
|
||||||
@@ -136,6 +165,7 @@ public final class CMatchUI
|
|||||||
private final CLog cLog = new CLog(this);
|
private final CLog cLog = new CLog(this);
|
||||||
private final CPrompt cPrompt = new CPrompt(this);
|
private final CPrompt cPrompt = new CPrompt(this);
|
||||||
private final CStack cStack = new CStack(this);
|
private final CStack cStack = new CStack(this);
|
||||||
|
private int nextNotifiableStackIndex = 0;
|
||||||
|
|
||||||
public CMatchUI() {
|
public CMatchUI() {
|
||||||
this.view = new VMatchUI(this);
|
this.view = new VMatchUI(this);
|
||||||
@@ -1180,4 +1210,204 @@ public final class CMatchUI
|
|||||||
return reply == 0;
|
return reply == 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void notifyStackAddition(GameEventSpellAbilityCast event) {
|
||||||
|
SpellAbility sa = event.sa;
|
||||||
|
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) {
|
||||||
|
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);
|
||||||
|
|
||||||
|
// 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();
|
||||||
|
if(hostCard.isEnchantment()) {
|
||||||
|
GameEntity enchantedEntity = hostCard.getEntityAttachedTo();
|
||||||
|
if(enchantedEntity != null) {
|
||||||
|
enchantedEntityView = enchantedEntity.getView();
|
||||||
|
numSmallImages++;
|
||||||
|
} else if ((sa.getRootAbility() != null)
|
||||||
|
&& (sa.getRootAbility().getPaidList("Sacrificed") != null)
|
||||||
|
&& !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();
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
if(sourceCardView != null) {
|
||||||
|
addSmallImageToStackModalPanel(sourceCardView,mainPanel,numSmallImages);
|
||||||
|
}
|
||||||
|
for(GameEntityView gev : targets) {
|
||||||
|
addSmallImageToStackModalPanel(gev, mainPanel, numSmallImages);
|
||||||
|
}
|
||||||
|
|
||||||
|
FOptionPane.showOptionDialog(null, "Forge", null, mainPanel, ImmutableList.of("OK"));
|
||||||
|
// 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
|
||||||
|
public void run() {
|
||||||
|
notifyStackAddition(event);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
GuiBase.getInterface().invokeInEdtLater(tryAgainThread);
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private List<GameEntityView> getTargets(SpellAbilityStackInstance si, List<GameEntityView> result){
|
||||||
|
if(si == null) {
|
||||||
|
return result;
|
||||||
|
} else {
|
||||||
|
FCollectionView<CardView> targetCards = CardView.getCollection(si.getTargetChoices().getTargetCards());
|
||||||
|
for(CardView currCardView: targetCards) {
|
||||||
|
result.add(currCardView);
|
||||||
|
}
|
||||||
|
|
||||||
|
for(SpellAbility currSA : si.getTargetChoices().getTargetSpells()) {
|
||||||
|
CardView currCardView = currSA.getCardView();
|
||||||
|
result.add(currCardView);
|
||||||
|
}
|
||||||
|
|
||||||
|
FCollectionView<PlayerView> targetPlayers = PlayerView.getCollection(si.getTargetChoices().getTargetPlayers());
|
||||||
|
for(PlayerView currPlayerView : targetPlayers) {
|
||||||
|
result.add(currPlayerView);
|
||||||
|
}
|
||||||
|
|
||||||
|
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());
|
||||||
|
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");
|
||||||
|
}
|
||||||
|
|
||||||
|
private void addTextToStackModalPanel(JPanel mainPanel, SpellAbility sa, SpellAbilityStackInstance si) {
|
||||||
|
String who = sa.getActivatingPlayer().getName();
|
||||||
|
String action = sa.isSpell() ? " cast " : sa.isTrigger() ? " triggered " : " activated ";
|
||||||
|
String what = sa.getStackDescription().startsWith("Morph ") ? "Morph" : sa.getHostCard().toString();
|
||||||
|
|
||||||
|
StringBuilder sb = new StringBuilder();
|
||||||
|
sb.append(who).append(action).append(what);
|
||||||
|
|
||||||
|
if (sa.getTargetRestrictions() != null) {
|
||||||
|
sb.append(" targeting ");
|
||||||
|
TargetChoices targets = si.getTargetChoices();
|
||||||
|
sb.append(targets.getTargetedString());
|
||||||
|
}
|
||||||
|
sb.append(".");
|
||||||
|
String message1 = sb.toString();
|
||||||
|
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");
|
||||||
|
}
|
||||||
|
|
||||||
|
private void addSmallImageToStackModalPanel(GameEntityView gameEntityView, JPanel mainPanel, int numTarget) {
|
||||||
|
if(gameEntityView instanceof CardView) {
|
||||||
|
CardView cardView = (CardView) gameEntityView;
|
||||||
|
int currRotation = getRotation(cardView);
|
||||||
|
FImagePanel targetPanel = new FImagePanel();
|
||||||
|
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");
|
||||||
|
} 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");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
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);
|
||||||
|
|
||||||
|
rotation = cardView.isFaceDown() ? 0 : hasKeywordAftermath ? (CardStateName.LeftSplit.equals(cardView.getState(false).getState()) ? 0 : 270) : 90; // rotate Aftermath splits the other way to correctly show the right split (graveyard) half
|
||||||
|
} else {
|
||||||
|
CardStateView cardStateView = cardView.getState(false);
|
||||||
|
rotation = cardStateView.isPlane() || cardStateView.isPhenomenon() ? 90 : 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
return rotation;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void notifyStackRemoval(GameEventSpellRemovedFromStack event) {
|
||||||
|
// I always decrease the counter
|
||||||
|
nextNotifiableStackIndex--;
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -78,6 +78,10 @@ public class FOptionPane extends FDialog {
|
|||||||
return showOptionDialog(message, title, icon, options, 0);
|
return showOptionDialog(message, title, icon, options, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static int showOptionDialog(final String message, final String title, final SkinImage icon, Component comp, final List<String> options) {
|
||||||
|
return showOptionDialog(message, title, icon, comp, options, 0);
|
||||||
|
}
|
||||||
|
|
||||||
public static int showOptionDialog(final String message, final String title, final SkinImage icon, final List<String> options, final int defaultOption) {
|
public static int showOptionDialog(final String message, final String title, final SkinImage icon, final List<String> options, final int defaultOption) {
|
||||||
final FOptionPane optionPane = new FOptionPane(message, title, icon, null, options, defaultOption);
|
final FOptionPane optionPane = new FOptionPane(message, title, icon, null, options, defaultOption);
|
||||||
optionPane.setVisible(true);
|
optionPane.setVisible(true);
|
||||||
@@ -86,6 +90,14 @@ public class FOptionPane extends FDialog {
|
|||||||
return dialogResult;
|
return dialogResult;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static int showOptionDialog(final String message, final String title, final SkinImage icon, final Component comp, final List<String> options, final int defaultOption) {
|
||||||
|
final FOptionPane optionPane = new FOptionPane(message, title, icon, comp, options, defaultOption);
|
||||||
|
optionPane.setVisible(true);
|
||||||
|
final int dialogResult = optionPane.result;
|
||||||
|
optionPane.dispose();
|
||||||
|
return dialogResult;
|
||||||
|
}
|
||||||
|
|
||||||
public static String showInputDialog(final String message, final String title) {
|
public static String showInputDialog(final String message, final String title) {
|
||||||
return showInputDialog(message, title, null, "", null);
|
return showInputDialog(message, title, null, "", null);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -28,8 +28,8 @@ import forge.properties.ForgeConstants;
|
|||||||
import forge.properties.ForgePreferences;
|
import forge.properties.ForgePreferences;
|
||||||
import forge.properties.ForgePreferences.FPref;
|
import forge.properties.ForgePreferences.FPref;
|
||||||
import forge.util.OperatingSystem;
|
import forge.util.OperatingSystem;
|
||||||
|
import forge.util.WordUtil;
|
||||||
import forge.view.FView;
|
import forge.view.FView;
|
||||||
import org.apache.commons.lang3.text.WordUtils;
|
|
||||||
|
|
||||||
import javax.imageio.ImageIO;
|
import javax.imageio.ImageIO;
|
||||||
import javax.swing.*;
|
import javax.swing.*;
|
||||||
@@ -1085,7 +1085,7 @@ public class FSkin {
|
|||||||
allSkins = new ArrayList<>();
|
allSkins = new ArrayList<>();
|
||||||
final List<String> skinDirectoryNames = getSkinDirectoryNames();
|
final List<String> skinDirectoryNames = getSkinDirectoryNames();
|
||||||
for (String skinDirectoryName : skinDirectoryNames) {
|
for (String skinDirectoryName : skinDirectoryNames) {
|
||||||
allSkins.add(WordUtils.capitalize(skinDirectoryName.replace('_', ' ')));
|
allSkins.add(WordUtil.capitalize(skinDirectoryName.replace('_', ' ')));
|
||||||
}
|
}
|
||||||
Collections.sort(allSkins);
|
Collections.sort(allSkins);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,31 +1,24 @@
|
|||||||
package forge.toolbox.special;
|
package forge.toolbox.special;
|
||||||
|
|
||||||
import java.awt.Component;
|
|
||||||
import java.awt.Font;
|
|
||||||
import java.awt.Graphics;
|
|
||||||
import java.awt.event.MouseEvent;
|
|
||||||
import java.util.ArrayList;
|
|
||||||
import java.util.List;
|
|
||||||
|
|
||||||
import javax.swing.JPanel;
|
|
||||||
import javax.swing.SwingConstants;
|
|
||||||
|
|
||||||
import forge.card.mana.ManaAtom;
|
|
||||||
import forge.trackable.TrackableProperty;
|
|
||||||
import net.miginfocom.swing.MigLayout;
|
|
||||||
|
|
||||||
import org.apache.commons.lang3.StringUtils;
|
|
||||||
import org.apache.commons.lang3.tuple.Pair;
|
|
||||||
|
|
||||||
import com.google.common.base.Function;
|
import com.google.common.base.Function;
|
||||||
|
|
||||||
import forge.assets.FSkinProp;
|
import forge.assets.FSkinProp;
|
||||||
|
import forge.card.mana.ManaAtom;
|
||||||
import forge.game.player.PlayerView;
|
import forge.game.player.PlayerView;
|
||||||
import forge.toolbox.FLabel;
|
import forge.toolbox.FLabel;
|
||||||
import forge.toolbox.FMouseAdapter;
|
import forge.toolbox.FMouseAdapter;
|
||||||
import forge.toolbox.FSkin;
|
import forge.toolbox.FSkin;
|
||||||
import forge.toolbox.FSkin.SkinFont;
|
import forge.toolbox.FSkin.SkinFont;
|
||||||
import forge.toolbox.FSkin.SkinnedPanel;
|
import forge.toolbox.FSkin.SkinnedPanel;
|
||||||
|
import forge.trackable.TrackableProperty;
|
||||||
|
import net.miginfocom.swing.MigLayout;
|
||||||
|
import org.apache.commons.lang3.StringUtils;
|
||||||
|
import org.apache.commons.lang3.tuple.Pair;
|
||||||
|
|
||||||
|
import javax.swing.*;
|
||||||
|
import java.awt.*;
|
||||||
|
import java.awt.event.MouseEvent;
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
public class PlayerDetailsPanel extends JPanel {
|
public class PlayerDetailsPanel extends JPanel {
|
||||||
private static final long serialVersionUID = -6531759554646891983L;
|
private static final long serialVersionUID = -6531759554646891983L;
|
||||||
|
|||||||
@@ -12,8 +12,8 @@ import forge.game.*;
|
|||||||
import forge.properties.ForgeConstants;
|
import forge.properties.ForgeConstants;
|
||||||
import forge.tournament.system.*;
|
import forge.tournament.system.*;
|
||||||
import forge.util.TextUtil;
|
import forge.util.TextUtil;
|
||||||
|
import forge.util.WordUtil;
|
||||||
import forge.util.storage.IStorage;
|
import forge.util.storage.IStorage;
|
||||||
import org.apache.commons.lang3.text.WordUtils;
|
|
||||||
import org.apache.commons.lang3.time.StopWatch;
|
import org.apache.commons.lang3.time.StopWatch;
|
||||||
|
|
||||||
import forge.deck.Deck;
|
import forge.deck.Deck;
|
||||||
@@ -75,7 +75,7 @@ public class SimulateMatch {
|
|||||||
|
|
||||||
GameType type = GameType.Constructed;
|
GameType type = GameType.Constructed;
|
||||||
if (params.containsKey("f")) {
|
if (params.containsKey("f")) {
|
||||||
type = GameType.valueOf(WordUtils.capitalize(params.get("f").get(0)));
|
type = GameType.valueOf(WordUtil.capitalize(params.get("f").get(0)));
|
||||||
}
|
}
|
||||||
|
|
||||||
GameRules rules = new GameRules(type);
|
GameRules rules = new GameRules(type);
|
||||||
|
|||||||
@@ -687,7 +687,7 @@ public class GifDecoder {
|
|||||||
} while ((blockSize > 0) && !err());
|
} while ((blockSize > 0) && !err());
|
||||||
}
|
}
|
||||||
|
|
||||||
public Animation getAnimation(PlayMode playType) {
|
private Animation<TextureRegion> getAnimation(PlayMode playType) {
|
||||||
int nrFrames = getFrameCount();
|
int nrFrames = getFrameCount();
|
||||||
Pixmap frame = getFrame(0);
|
Pixmap frame = getFrame(0);
|
||||||
int width = frame.getWidth();
|
int width = frame.getWidth();
|
||||||
@@ -725,12 +725,11 @@ public class GifDecoder {
|
|||||||
}
|
}
|
||||||
float frameDuration = (float)getDelay(0);
|
float frameDuration = (float)getDelay(0);
|
||||||
frameDuration /= 1000; // convert milliseconds into seconds
|
frameDuration /= 1000; // convert milliseconds into seconds
|
||||||
Animation result = new Animation(frameDuration, texReg, playType);
|
|
||||||
|
|
||||||
return result;
|
return new Animation<>(frameDuration, texReg, playType);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static Animation loadGIFAnimation(PlayMode playType, InputStream is) {
|
public static Animation<TextureRegion> loadGIFAnimation(PlayMode playType, InputStream is) {
|
||||||
GifDecoder gdec = new GifDecoder();
|
GifDecoder gdec = new GifDecoder();
|
||||||
gdec.read(is);
|
gdec.read(is);
|
||||||
return gdec.getAnimation(playType);
|
return gdec.getAnimation(playType);
|
||||||
|
|||||||
@@ -3,9 +3,9 @@ package forge.assets;
|
|||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
|
||||||
|
import forge.util.WordUtil;
|
||||||
import com.badlogic.gdx.utils.Array;
|
import com.badlogic.gdx.utils.Array;
|
||||||
import forge.Forge;
|
import forge.Forge;
|
||||||
import org.apache.commons.lang3.text.WordUtils;
|
|
||||||
|
|
||||||
import com.badlogic.gdx.Gdx;
|
import com.badlogic.gdx.Gdx;
|
||||||
import com.badlogic.gdx.files.FileHandle;
|
import com.badlogic.gdx.files.FileHandle;
|
||||||
@@ -102,7 +102,7 @@ public class FSkin {
|
|||||||
allSkins = new Array<>();
|
allSkins = new Array<>();
|
||||||
final Array<String> skinDirectoryNames = getSkinDirectoryNames();
|
final Array<String> skinDirectoryNames = getSkinDirectoryNames();
|
||||||
for (final String skinDirectoryName : skinDirectoryNames) {
|
for (final String skinDirectoryName : skinDirectoryNames) {
|
||||||
allSkins.add(WordUtils.capitalize(skinDirectoryName.replace('_', ' ')));
|
allSkins.add(WordUtil.capitalize(skinDirectoryName.replace('_', ' ')));
|
||||||
}
|
}
|
||||||
allSkins.sort();
|
allSkins.sort();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -47,15 +47,10 @@ import forge.util.FileUtil;
|
|||||||
import forge.util.ThreadUtil;
|
import forge.util.ThreadUtil;
|
||||||
import forge.util.Utils;
|
import forge.util.Utils;
|
||||||
import forge.util.gui.SOptionPane;
|
import forge.util.gui.SOptionPane;
|
||||||
import forge.util.storage.IStorage;
|
|
||||||
|
|
||||||
import org.apache.commons.lang3.text.WordUtils;
|
|
||||||
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.HashMap;
|
|
||||||
import java.util.HashSet;
|
import java.util.HashSet;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
|
||||||
import java.util.Map.Entry;
|
import java.util.Map.Entry;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
|
|
||||||
@@ -282,18 +277,12 @@ public class NewQuestScreen extends FScreen {
|
|||||||
|
|
||||||
cbAllowUnlocks.setSelected(true);
|
cbAllowUnlocks.setSelected(true);
|
||||||
|
|
||||||
final Map<String, String> preconDescriptions = new HashMap<>();
|
for (PreconDeck preconDeck : QuestController.getPrecons()) {
|
||||||
IStorage<PreconDeck> preconDecks = QuestController.getPrecons();
|
|
||||||
|
|
||||||
for (PreconDeck preconDeck : preconDecks) {
|
|
||||||
if (QuestController.getPreconDeals(preconDeck).getMinWins() > 0) {
|
if (QuestController.getPreconDeals(preconDeck).getMinWins() > 0) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
String name = preconDeck.getName();
|
String name = preconDeck.getName();
|
||||||
cbxPreconDeck.addItem(name);
|
cbxPreconDeck.addItem(name);
|
||||||
String description = preconDeck.getDescription();
|
|
||||||
description = "<html>" + WordUtils.wrap(description, 40, "<br>", false) + "</html>";
|
|
||||||
preconDescriptions.put(name, description);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// disable the very powerful sets -- they can be unlocked later for a high price
|
// disable the very powerful sets -- they can be unlocked later for a high price
|
||||||
|
|||||||
@@ -3,7 +3,7 @@ ManaCost:3 B B
|
|||||||
Types:Legendary Creature Human Knight
|
Types:Legendary Creature Human Knight
|
||||||
PT:5/4
|
PT:5/4
|
||||||
T:Mode$ ChangesZone | Origin$ Any | Destination$ Graveyard | ValidCard$ Creature.Other | TriggerZones$ Battlefield | Execute$ TrigDmg | TriggerDescription$ Whenever another creature dies, or a creature card is put into a graveyard from anywhere than the battlefield, or a creature card leaves your graveyard, CARDNAME deals 1 damage to each opponent.
|
T:Mode$ ChangesZone | Origin$ Any | Destination$ Graveyard | ValidCard$ Creature.Other | TriggerZones$ Battlefield | Execute$ TrigDmg | TriggerDescription$ Whenever another creature dies, or a creature card is put into a graveyard from anywhere than the battlefield, or a creature card leaves your graveyard, CARDNAME deals 1 damage to each opponent.
|
||||||
T:Mode$ ChangesZone | Origin$ Graveyard | Destination$ Any | ValidCard$ Card.Creature+Other | TriggerZones$ Battlefield | Execute$ TrigDmg | Secondary$ True | TriggerDescription$ Whenever another creature dies, or a creature card is put into a graveyard from anywhere than the battlefield, or a creature card leaves your graveyard, CARDNAME deals 1 damage to each opponent.
|
T:Mode$ ChangesZone | Origin$ Graveyard | Destination$ Any | ValidCard$ Card.Creature+Other+YouOwn | TriggerZones$ Battlefield | Execute$ TrigDmg | Secondary$ True | TriggerDescription$ Whenever another creature dies, or a creature card is put into a graveyard from anywhere than the battlefield, or a creature card leaves your graveyard, CARDNAME deals 1 damage to each opponent.
|
||||||
SVar:TrigDmg:DB$ DealDamage | Defined$ Player.Opponent | NumDmg$ 1
|
SVar:TrigDmg:DB$ DealDamage | Defined$ Player.Opponent | NumDmg$ 1
|
||||||
A:AB$ Mill | Cost$ 1 B | NumCards$ 1 | Defined$ Player | SpellDescription$ Each player puts the top card of their library into their graveyard.
|
A:AB$ Mill | Cost$ 1 B | NumCards$ 1 | Defined$ Player | SpellDescription$ Each player puts the top card of their library into their graveyard.
|
||||||
AI:RemoveDeck:All
|
AI:RemoveDeck:All
|
||||||
|
|||||||
@@ -102,6 +102,7 @@ cbpGameLogEntryType=Game Log Verbosity
|
|||||||
cbpCloseAction=Close Action
|
cbpCloseAction=Close Action
|
||||||
cbpDefaultFontSize=Default Font Size
|
cbpDefaultFontSize=Default Font Size
|
||||||
cbpAiProfiles=AI Personality
|
cbpAiProfiles=AI Personality
|
||||||
|
cbpStackAdditions=Stack effect notifications
|
||||||
cbpDisplayCurrentCardColors=Show Detailed Card Color
|
cbpDisplayCurrentCardColors=Show Detailed Card Color
|
||||||
cbpAutoYieldMode=Auto-Yield
|
cbpAutoYieldMode=Auto-Yield
|
||||||
cbpCounterDisplayType=Counter Display Type
|
cbpCounterDisplayType=Counter Display Type
|
||||||
@@ -116,6 +117,7 @@ nlUseSentry=When enabled, automatically submits bug reports to developers.
|
|||||||
GamePlay=Gameplay
|
GamePlay=Gameplay
|
||||||
nlpMulliganRule=Choose the version of the Mulligan rule
|
nlpMulliganRule=Choose the version of the Mulligan rule
|
||||||
nlpAiProfiles=Choose your AI opponent
|
nlpAiProfiles=Choose your AI opponent
|
||||||
|
nlpStackAdditions=Choose when you want to get visual notifications for an effect added to the stack: Never, always, or only for the effects cast/activated by a AI player or triggered by any player
|
||||||
nlAnte=Determines whether or not the game is played for ante.
|
nlAnte=Determines whether or not the game is played for ante.
|
||||||
nlAnteMatchRarity=Attempts to make antes the same rarity for all players.
|
nlAnteMatchRarity=Attempts to make antes the same rarity for all players.
|
||||||
nlEnableAICheats=Allow the AI to cheat to gain advantage (for personalities that have cheat shuffling options set).
|
nlEnableAICheats=Allow the AI to cheat to gain advantage (for personalities that have cheat shuffling options set).
|
||||||
|
|||||||
@@ -240,7 +240,17 @@ public class FControlGameEventHandler extends IGameEventVisitor.Base<Void> {
|
|||||||
@Override
|
@Override
|
||||||
public Void visit(final GameEventSpellAbilityCast event) {
|
public Void visit(final GameEventSpellAbilityCast event) {
|
||||||
needStackUpdate = true;
|
needStackUpdate = true;
|
||||||
return processEvent();
|
processEvent();
|
||||||
|
|
||||||
|
final Runnable notifyStackAddition = new Runnable() {
|
||||||
|
@Override
|
||||||
|
public void run() {
|
||||||
|
matchController.notifyStackAddition(event);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
GuiBase.getInterface().invokeInEdtLater(notifyStackAddition);
|
||||||
|
|
||||||
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -252,7 +262,17 @@ public class FControlGameEventHandler extends IGameEventVisitor.Base<Void> {
|
|||||||
@Override
|
@Override
|
||||||
public Void visit(final GameEventSpellRemovedFromStack event) {
|
public Void visit(final GameEventSpellRemovedFromStack event) {
|
||||||
needStackUpdate = true;
|
needStackUpdate = true;
|
||||||
return processEvent();
|
processEvent();
|
||||||
|
|
||||||
|
final Runnable notifyStackAddition = new Runnable() {
|
||||||
|
@Override
|
||||||
|
public void run() {
|
||||||
|
matchController.notifyStackRemoval(event);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
GuiBase.getInterface().invokeInEdtLater(notifyStackAddition);
|
||||||
|
|
||||||
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -340,10 +360,10 @@ public class FControlGameEventHandler extends IGameEventVisitor.Base<Void> {
|
|||||||
if(event.to.getZoneType() == ZoneType.Battlefield)
|
if(event.to.getZoneType() == ZoneType.Battlefield)
|
||||||
refreshFieldUpdate = true;
|
refreshFieldUpdate = true;
|
||||||
//pfps the change to the zones have already been performed with add and remove calls
|
//pfps the change to the zones have already been performed with add and remove calls
|
||||||
// this is only for playing a sound
|
// this is only for playing a sound
|
||||||
// updateZone(event.from);
|
// updateZone(event.from);
|
||||||
//return updateZone(event.to);
|
//return updateZone(event.to);
|
||||||
return processEvent();
|
return processEvent();
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -373,9 +393,9 @@ public class FControlGameEventHandler extends IGameEventVisitor.Base<Void> {
|
|||||||
@Override
|
@Override
|
||||||
public Void visit(final GameEventShuffle event) {
|
public Void visit(final GameEventShuffle event) {
|
||||||
//pfps the change to the library has already been performed by a setCards call
|
//pfps the change to the library has already been performed by a setCards call
|
||||||
// this is only for playing a sound
|
// this is only for playing a sound
|
||||||
// return updateZone(event.player.getZone(ZoneType.Library));
|
// return updateZone(event.player.getZone(ZoneType.Library));
|
||||||
return processEvent();
|
return processEvent();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|||||||
@@ -264,12 +264,8 @@ public abstract class GuiDownloadService implements Runnable {
|
|||||||
count++;
|
count++;
|
||||||
cardSkipped = true; //assume skipped unless saved successfully
|
cardSkipped = true; //assume skipped unless saved successfully
|
||||||
String url = kv.getValue();
|
String url = kv.getValue();
|
||||||
/*
|
|
||||||
* decode URL Key, Reverted to old version,
|
String decodedKey = decodeURL(kv.getKey());
|
||||||
* on Android 6.0 it throws an error
|
|
||||||
* when you download the card price
|
|
||||||
*/
|
|
||||||
String decodedKey = URLDecoder.decode(kv.getKey());
|
|
||||||
final File fileDest = new File(decodedKey);
|
final File fileDest = new File(decodedKey);
|
||||||
final String filePath = fileDest.getPath();
|
final String filePath = fileDest.getPath();
|
||||||
final String subLastIndex = filePath.contains("pics") ? "\\pics\\" : "\\db\\";
|
final String subLastIndex = filePath.contains("pics") ? "\\pics\\" : "\\db\\";
|
||||||
@@ -365,6 +361,16 @@ public abstract class GuiDownloadService implements Runnable {
|
|||||||
GuiBase.getInterface().preventSystemSleep(false);
|
GuiBase.getInterface().preventSystemSleep(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@SuppressWarnings("deprecation")
|
||||||
|
private static String decodeURL(String key) {
|
||||||
|
/*
|
||||||
|
* decode URL Key, Reverted to old version,
|
||||||
|
* on Android 6.0 it throws an error
|
||||||
|
* when you download the card price
|
||||||
|
*/
|
||||||
|
return URLDecoder.decode(key);
|
||||||
|
}
|
||||||
|
|
||||||
protected Proxy getProxy() {
|
protected Proxy getProxy() {
|
||||||
if (type == 0) {
|
if (type == 0) {
|
||||||
return Proxy.NO_PROXY;
|
return Proxy.NO_PROXY;
|
||||||
@@ -385,7 +391,7 @@ public abstract class GuiDownloadService implements Runnable {
|
|||||||
|
|
||||||
protected static void addMissingItems(Map<String, String> list, String nameUrlFile, String dir) {
|
protected static void addMissingItems(Map<String, String> list, String nameUrlFile, String dir) {
|
||||||
for (Pair<String, String> nameUrlPair : FileUtil.readNameUrlFile(nameUrlFile)) {
|
for (Pair<String, String> nameUrlPair : FileUtil.readNameUrlFile(nameUrlFile)) {
|
||||||
File f = new File(dir, URLDecoder.decode(nameUrlPair.getLeft()));
|
File f = new File(dir, decodeURL(nameUrlPair.getLeft()));
|
||||||
//System.out.println(f.getAbsolutePath());
|
//System.out.println(f.getAbsolutePath());
|
||||||
if (!f.exists()) {
|
if (!f.exists()) {
|
||||||
list.put(f.getAbsolutePath(), nameUrlPair.getRight());
|
list.put(f.getAbsolutePath(), nameUrlPair.getRight());
|
||||||
|
|||||||
@@ -12,6 +12,8 @@ import forge.deck.CardPool;
|
|||||||
import forge.game.GameEntityView;
|
import forge.game.GameEntityView;
|
||||||
import forge.game.GameView;
|
import forge.game.GameView;
|
||||||
import forge.game.card.CardView;
|
import forge.game.card.CardView;
|
||||||
|
import forge.game.event.GameEventSpellAbilityCast;
|
||||||
|
import forge.game.event.GameEventSpellRemovedFromStack;
|
||||||
import forge.game.phase.PhaseType;
|
import forge.game.phase.PhaseType;
|
||||||
import forge.game.player.DelayedReveal;
|
import forge.game.player.DelayedReveal;
|
||||||
import forge.game.player.IHasIcon;
|
import forge.game.player.IHasIcon;
|
||||||
@@ -47,6 +49,8 @@ public interface IGuiGame {
|
|||||||
void showManaPool(PlayerView player);
|
void showManaPool(PlayerView player);
|
||||||
void hideManaPool(PlayerView player);
|
void hideManaPool(PlayerView player);
|
||||||
void updateStack();
|
void updateStack();
|
||||||
|
void notifyStackAddition(final GameEventSpellAbilityCast event);
|
||||||
|
void notifyStackRemoval(final GameEventSpellRemovedFromStack event);
|
||||||
Iterable<PlayerZoneUpdate> tempShowZones(PlayerView controller, Iterable<PlayerZoneUpdate> zonesToUpdate);
|
Iterable<PlayerZoneUpdate> tempShowZones(PlayerView controller, Iterable<PlayerZoneUpdate> zonesToUpdate);
|
||||||
void hideZones(PlayerView controller, Iterable<PlayerZoneUpdate> zonesToUpdate);
|
void hideZones(PlayerView controller, Iterable<PlayerZoneUpdate> zonesToUpdate);
|
||||||
void updateZones(Iterable<PlayerZoneUpdate> zonesToUpdate);
|
void updateZones(Iterable<PlayerZoneUpdate> zonesToUpdate);
|
||||||
|
|||||||
@@ -24,6 +24,8 @@ import forge.assets.FSkinProp;
|
|||||||
import forge.game.GameView;
|
import forge.game.GameView;
|
||||||
import forge.game.card.CardView;
|
import forge.game.card.CardView;
|
||||||
import forge.game.card.CardView.CardStateView;
|
import forge.game.card.CardView.CardStateView;
|
||||||
|
import forge.game.event.GameEventSpellAbilityCast;
|
||||||
|
import forge.game.event.GameEventSpellRemovedFromStack;
|
||||||
import forge.game.player.PlayerView;
|
import forge.game.player.PlayerView;
|
||||||
import forge.interfaces.IGameController;
|
import forge.interfaces.IGameController;
|
||||||
import forge.interfaces.IGuiGame;
|
import forge.interfaces.IGuiGame;
|
||||||
@@ -251,16 +253,16 @@ public abstract class AbstractGuiGame implements IGuiGame, IMayViewCards {
|
|||||||
|
|
||||||
private final Set<CardView> selectableCards = Sets.newHashSet();
|
private final Set<CardView> selectableCards = Sets.newHashSet();
|
||||||
public void setSelectables(final Iterable<CardView> cards) {
|
public void setSelectables(final Iterable<CardView> cards) {
|
||||||
for ( CardView cv : cards ) { selectableCards.add(cv); }
|
for ( CardView cv : cards ) { selectableCards.add(cv); }
|
||||||
}
|
}
|
||||||
public void clearSelectables() {
|
public void clearSelectables() {
|
||||||
selectableCards.clear();
|
selectableCards.clear();
|
||||||
}
|
}
|
||||||
public boolean isSelectable(final CardView card) {
|
public boolean isSelectable(final CardView card) {
|
||||||
return selectableCards.contains(card);
|
return selectableCards.contains(card);
|
||||||
}
|
}
|
||||||
public boolean isSelecting() {
|
public boolean isSelecting() {
|
||||||
return !selectableCards.isEmpty();
|
return !selectableCards.isEmpty();
|
||||||
}
|
}
|
||||||
public boolean isGamePaused() { return gamePause; }
|
public boolean isGamePaused() { return gamePause; }
|
||||||
public void setgamePause(boolean pause) { gamePause = pause; }
|
public void setgamePause(boolean pause) { gamePause = pause; }
|
||||||
@@ -695,5 +697,13 @@ public abstract class AbstractGuiGame implements IGuiGame, IMayViewCards {
|
|||||||
return showConfirmDialog(message, title, yesButtonText, noButtonText, true);
|
return showConfirmDialog(message, title, yesButtonText, noButtonText, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void notifyStackAddition(GameEventSpellAbilityCast event) {
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void notifyStackRemoval(GameEventSpellRemovedFromStack event) {
|
||||||
|
}
|
||||||
|
|
||||||
// End of Choice code
|
// End of Choice code
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -310,6 +310,11 @@ public final class ForgeConstants {
|
|||||||
public static final String GRAVEYARD_ORDERING_OWN_CARDS = "With Relevant Cards";
|
public static final String GRAVEYARD_ORDERING_OWN_CARDS = "With Relevant Cards";
|
||||||
public static final String GRAVEYARD_ORDERING_ALWAYS = "Always";
|
public static final String GRAVEYARD_ORDERING_ALWAYS = "Always";
|
||||||
|
|
||||||
|
// Constants for Stack effect addition notification policy
|
||||||
|
public static final String STACK_EFFECT_NOTIFICATION_NEVER = "Never";
|
||||||
|
public static final String STACK_EFFECT_NOTIFICATION_ALWAYS = "Always";
|
||||||
|
public static final String STACK_EFFECT_NOTIFICATION_AI_AND_TRIGGERED = "AI cast/activated, or triggered by any player";
|
||||||
|
|
||||||
// Set boolean constant for landscape mode for gdx port
|
// Set boolean constant for landscape mode for gdx port
|
||||||
public static final boolean isGdxPortLandscape = FileUtil.doesFileExist(ASSETS_DIR + "switch_orientation.ini");
|
public static final boolean isGdxPortLandscape = FileUtil.doesFileExist(ASSETS_DIR + "switch_orientation.ini");
|
||||||
|
|
||||||
|
|||||||
@@ -119,6 +119,7 @@ public class ForgePreferences extends PreferencesStore<ForgePreferences.FPref> {
|
|||||||
UI_HIDE_GAME_TABS ("false"), // Visibility of tabs in match screen.
|
UI_HIDE_GAME_TABS ("false"), // Visibility of tabs in match screen.
|
||||||
UI_CLOSE_ACTION ("NONE"),
|
UI_CLOSE_ACTION ("NONE"),
|
||||||
UI_MANA_LOST_PROMPT ("false"), // Prompt on losing mana when passing priority
|
UI_MANA_LOST_PROMPT ("false"), // Prompt on losing mana when passing priority
|
||||||
|
UI_STACK_EFFECT_NOTIFICATION_POLICY ("Never"),
|
||||||
UI_PAUSE_WHILE_MINIMIZED("false"),
|
UI_PAUSE_WHILE_MINIMIZED("false"),
|
||||||
UI_TOKENS_IN_SEPARATE_ROW("false"), // Display tokens in their own battlefield row.
|
UI_TOKENS_IN_SEPARATE_ROW("false"), // Display tokens in their own battlefield row.
|
||||||
UI_DISPLAY_CURRENT_COLORS(ForgeConstants.DISP_CURRENT_COLORS_NEVER),
|
UI_DISPLAY_CURRENT_COLORS(ForgeConstants.DISP_CURRENT_COLORS_NEVER),
|
||||||
|
|||||||
87
forge-gui/src/main/java/forge/util/WordUtil.java
Normal file
87
forge-gui/src/main/java/forge/util/WordUtil.java
Normal file
@@ -0,0 +1,87 @@
|
|||||||
|
package forge.util;
|
||||||
|
|
||||||
|
import org.apache.commons.lang3.StringUtils;
|
||||||
|
|
||||||
|
import java.util.regex.Matcher;
|
||||||
|
import java.util.regex.Pattern;
|
||||||
|
|
||||||
|
public class WordUtil {
|
||||||
|
public static String capitalize(String str) {
|
||||||
|
if (StringUtils.isEmpty(str)) {
|
||||||
|
return str;
|
||||||
|
}
|
||||||
|
final char[] buffer = str.toCharArray();
|
||||||
|
boolean capitalizeNext = true;
|
||||||
|
for (int i = 0; i < buffer.length; i++) {
|
||||||
|
final char ch = buffer[i];
|
||||||
|
if (Character.isWhitespace(ch)) {
|
||||||
|
capitalizeNext = true;
|
||||||
|
} else if (capitalizeNext) {
|
||||||
|
buffer[i] = Character.toTitleCase(ch);
|
||||||
|
capitalizeNext = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return new String(buffer);
|
||||||
|
}
|
||||||
|
|
||||||
|
private final static Pattern patternToWrapOn = Pattern.compile(" ");
|
||||||
|
public static String wordWrapAsHTML(String str) {
|
||||||
|
String result = null;
|
||||||
|
int wrapLength = 40;
|
||||||
|
String newLineStr = "<br>";
|
||||||
|
if (str != null) {
|
||||||
|
final int inputLineLength = str.length();
|
||||||
|
int offset = 0;
|
||||||
|
final StringBuilder wrappedLine = new StringBuilder(inputLineLength + 32);
|
||||||
|
while (offset < inputLineLength) {
|
||||||
|
int spaceToWrapAt = -1;
|
||||||
|
Matcher matcher = patternToWrapOn.matcher(str.substring(offset, Math.min(offset + wrapLength + 1, inputLineLength)));
|
||||||
|
if (matcher.find()) {
|
||||||
|
if (matcher.start() == 0) {
|
||||||
|
offset += matcher.end();
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
spaceToWrapAt = matcher.start() + offset;
|
||||||
|
}
|
||||||
|
|
||||||
|
// only last line without leading spaces is left
|
||||||
|
if (inputLineLength - offset <= wrapLength) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
while (matcher.find()) {
|
||||||
|
spaceToWrapAt = matcher.start() + offset;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (spaceToWrapAt >= offset) {
|
||||||
|
// normal case
|
||||||
|
wrappedLine.append(str, offset, spaceToWrapAt);
|
||||||
|
wrappedLine.append(newLineStr);
|
||||||
|
offset = spaceToWrapAt + 1;
|
||||||
|
|
||||||
|
} else {
|
||||||
|
// do not wrap really long word, just extend beyond limit
|
||||||
|
matcher = patternToWrapOn.matcher(str.substring(offset + wrapLength));
|
||||||
|
if (matcher.find()) {
|
||||||
|
spaceToWrapAt = matcher.start() + offset + wrapLength;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (spaceToWrapAt >= 0) {
|
||||||
|
wrappedLine.append(str, offset, spaceToWrapAt);
|
||||||
|
wrappedLine.append(newLineStr);
|
||||||
|
offset = spaceToWrapAt + 1;
|
||||||
|
} else {
|
||||||
|
wrappedLine.append(str, offset, str.length());
|
||||||
|
offset = inputLineLength;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}// Whatever is left in line is short enough to just pass through
|
||||||
|
wrappedLine.append(str, offset, str.length());
|
||||||
|
result = wrappedLine.toString();
|
||||||
|
}
|
||||||
|
|
||||||
|
return "<html>" + result + "</html>";
|
||||||
|
}
|
||||||
|
|
||||||
|
private WordUtil() {}
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user