diff --git a/.gitlab/issue_templates/Bug.md b/.gitlab/issue_templates/Bug.md new file mode 100644 index 00000000000..c2804f08ab3 --- /dev/null +++ b/.gitlab/issue_templates/Bug.md @@ -0,0 +1,33 @@ +Summary + +(Summarize the bug encountered concisely) + + +Steps to reproduce + +(How one can reproduce the issue - this is very important. Specific cards and specific actions especially) + + +Which version of Forge are you on (Release, Snapshot? Desktop, Android?) + + +What is the current bug behavior? + +(What actually happens) + + +What is the expected correct behavior? + +(What you should see instead) + + +Relevant logs and/or screenshots + +(Paste/Attach your game.log from the crash - please use code blocks (```)) Also, provide screenshots of the current state. + + +Possible fixes + +(If you can, link to the line of code that might be responsible for the problem) + +/label ~needs-investigation \ No newline at end of file diff --git a/.gitlab/issue_templates/Feature.md b/.gitlab/issue_templates/Feature.md new file mode 100644 index 00000000000..712f6a75065 --- /dev/null +++ b/.gitlab/issue_templates/Feature.md @@ -0,0 +1,15 @@ +Summary + +(Summarize the feature you wish concisely) + + +Example screenshots + +(If this is a UI change, please provide an example screenshot of how this feature might work) + + +Feature type + +(Where in Forge does this belong? e.g. Quest Mode, Deck Editor, Limited, Constructed, etc.) + +/label ~feature request \ No newline at end of file diff --git a/forge-ai/src/main/java/forge/ai/GameState.java b/forge-ai/src/main/java/forge/ai/GameState.java index db79263a93e..bd4c26c19b0 100644 --- a/forge-ai/src/main/java/forge/ai/GameState.java +++ b/forge-ai/src/main/java/forge/ai/GameState.java @@ -74,6 +74,7 @@ public abstract class GameState { private final Map cardToEnchantPlayerId = new HashMap<>(); private final Map markedDamage = new HashMap<>(); private final Map> cardToChosenClrs = new HashMap<>(); + private final Map cardToChosenCards = new HashMap<>(); private final Map cardToChosenType = new HashMap<>(); private final Map> cardToRememberedId = new HashMap<>(); private final Map> cardToImprintedId = new HashMap<>(); @@ -211,6 +212,10 @@ public abstract class GameState { // Remember the IDs of imprinted cards cardsReferencedByID.add(i); } + for (Card i : card.getChosenCards()) { + // Remember the IDs of chosen cards + cardsReferencedByID.add(i); + } if (game.getCombat() != null && game.getCombat().isAttacking(card)) { // Remember the IDs of attacked planeswalkers GameEntity def = game.getCombat().getDefenderByAttacker(card); @@ -312,6 +317,17 @@ public abstract class GameState { newText.append("|NamedCard:").append(c.getNamedCard()); } + List chosenCardIds = Lists.newArrayList(); + for (Object obj : c.getChosenCards()) { + if (obj instanceof Card) { + int id = ((Card)obj).getId(); + chosenCardIds.add(String.valueOf(id)); + } + } + if (!chosenCardIds.isEmpty()) { + newText.append("|ChosenCards:").append(TextUtil.join(chosenCardIds, ",")); + } + List rememberedCardIds = Lists.newArrayList(); for (Object obj : c.getRemembered()) { if (obj instanceof Card) { @@ -552,6 +568,7 @@ public abstract class GameState { cardToExiledWithId.clear(); markedDamage.clear(); cardToChosenClrs.clear(); + cardToChosenCards.clear(); cardToChosenType.clear(); cardToScript.clear(); cardAttackMap.clear(); @@ -947,6 +964,12 @@ public abstract class GameState { Card c = entry.getKey(); c.setNamedCard(entry.getValue()); } + + // Chosen cards + for (Entry entry : cardToChosenCards.entrySet()) { + Card c = entry.getKey(); + c.setChosenCards(entry.getValue()); + } } private void handleCardAttachments() { @@ -1143,6 +1166,13 @@ public abstract class GameState { cardToChosenClrs.put(c, Arrays.asList(info.substring(info.indexOf(':') + 1).split(","))); } else if (info.startsWith("ChosenType:")) { cardToChosenType.put(c, info.substring(info.indexOf(':') + 1)); + } else if (info.startsWith("ChosenCards:")) { + CardCollection chosen = new CardCollection(); + String[] idlist = info.substring(info.indexOf(':') + 1).split(","); + for (String id : idlist) { + chosen.add(idToCard.get(Integer.parseInt(id))); + } + cardToChosenCards.put(c, chosen); } else if (info.startsWith("NamedCard:")) { cardToNamedCard.put(c, info.substring(info.indexOf(':') + 1)); } else if (info.startsWith("ExecuteScript:")) { diff --git a/forge-game/src/main/java/forge/game/ability/effects/TokenEffect.java b/forge-game/src/main/java/forge/game/ability/effects/TokenEffect.java index 1636c8f6cc7..b1a59467e76 100644 --- a/forge-game/src/main/java/forge/game/ability/effects/TokenEffect.java +++ b/forge-game/src/main/java/forge/game/ability/effects/TokenEffect.java @@ -499,7 +499,7 @@ public class TokenEffect extends SpellAbilityEffect { // TODO update when doing Attach Update boolean canAttach = lki.isAttachment(); - if (canAttach && ge.canBeAttached(lki)) { + if (canAttach && !ge.canBeAttached(lki)) { canAttach = false; } @@ -507,7 +507,7 @@ public class TokenEffect extends SpellAbilityEffect { game.getAction().checkStaticAbilities(false); if (!canAttach) { - // Token can't attach it + // Token can't attach to it return false; } diff --git a/forge-gui-android/pom.xml b/forge-gui-android/pom.xml index 41868952585..bb9023e6c52 100644 --- a/forge-gui-android/pom.xml +++ b/forge-gui-android/pom.xml @@ -6,7 +6,7 @@ jar -Xms1024m -Xmx1536m - 1.6.21.001 + 1.6.21.003 keystore alias storepass diff --git a/forge-gui-desktop/src/main/java/forge/control/KeyboardShortcuts.java b/forge-gui-desktop/src/main/java/forge/control/KeyboardShortcuts.java index 15a18e1a94d..72ecf54fb83 100644 --- a/forge-gui-desktop/src/main/java/forge/control/KeyboardShortcuts.java +++ b/forge-gui-desktop/src/main/java/forge/control/KeyboardShortcuts.java @@ -26,6 +26,7 @@ import forge.properties.ForgePreferences; import forge.properties.ForgePreferences.FPref; import forge.screens.home.settings.VSubmenuPreferences.KeyboardShortcutField; import forge.screens.match.CMatchUI; +import forge.util.Localizer; /** * Consolidates keyboard shortcut assembly into one location @@ -35,7 +36,6 @@ import forge.screens.match.CMatchUI; * and you're done. */ public class KeyboardShortcuts { - public static List getKeyboardShortcuts() { return attachKeyboardShortcuts(null); } @@ -200,20 +200,21 @@ public class KeyboardShortcuts { } }; + final Localizer localizer = Localizer.getInstance(); //========== Instantiate shortcut objects and add to list. - list.add(new Shortcut(FPref.SHORTCUT_SHOWSTACK, "Match: show stack panel", actShowStack, am, im)); - list.add(new Shortcut(FPref.SHORTCUT_SHOWCOMBAT, "Match: show combat panel", actShowCombat, am, im)); - list.add(new Shortcut(FPref.SHORTCUT_SHOWCONSOLE, "Match: show console panel", actShowConsole, am, im)); - list.add(new Shortcut(FPref.SHORTCUT_SHOWDEV, "Match: show dev panel", actShowDev, am, im)); - list.add(new Shortcut(FPref.SHORTCUT_CONCEDE, "Match: concede game", actConcede, am, im)); - list.add(new Shortcut(FPref.SHORTCUT_ENDTURN, "Match: pass priority until EOT or next stack event", actEndTurn, am, im)); - list.add(new Shortcut(FPref.SHORTCUT_ALPHASTRIKE, "Match: Alpha Strike (attack with all available)", actAllAttack, am, im)); - list.add(new Shortcut(FPref.SHORTCUT_SHOWTARGETING, "Match: toggle targeting visual overlay", actTgtOverlay, am, im)); - list.add(new Shortcut(FPref.SHORTCUT_AUTOYIELD_ALWAYS_YES, "Match: auto-yield ability on stack (Always Yes)", actAutoYieldAndYes, am, im)); - list.add(new Shortcut(FPref.SHORTCUT_AUTOYIELD_ALWAYS_NO, "Match: auto-yield ability on stack (Always No)", actAutoYieldAndNo, am, im)); - list.add(new Shortcut(FPref.SHORTCUT_MACRO_RECORD, "Match: record a macro sequence of actions", actMacroRecord, am, im)); - list.add(new Shortcut(FPref.SHORTCUT_MACRO_NEXT_ACTION, "Match: execute next action in a recorded macro", actMacroNextAction, am, im)); - list.add(new Shortcut(FPref.SHORTCUT_CARD_ZOOM, "Match: zoom the currently selected card", actZoomCard, am, im)); + list.add(new Shortcut(FPref.SHORTCUT_SHOWSTACK, localizer.getMessage("lblSHORTCUT_SHOWSTACK"), actShowStack, am, im)); + list.add(new Shortcut(FPref.SHORTCUT_SHOWCOMBAT, localizer.getMessage("lblSHORTCUT_SHOWCOMBAT"), actShowCombat, am, im)); + list.add(new Shortcut(FPref.SHORTCUT_SHOWCONSOLE, localizer.getMessage("lblSHORTCUT_SHOWCONSOLE"), actShowConsole, am, im)); + list.add(new Shortcut(FPref.SHORTCUT_SHOWDEV, localizer.getMessage("lblSHORTCUT_SHOWDEV"), actShowDev, am, im)); + list.add(new Shortcut(FPref.SHORTCUT_CONCEDE, localizer.getMessage("lblSHORTCUT_CONCEDE"), actConcede, am, im)); + list.add(new Shortcut(FPref.SHORTCUT_ENDTURN, localizer.getMessage("lblSHORTCUT_ENDTURN"), actEndTurn, am, im)); + list.add(new Shortcut(FPref.SHORTCUT_ALPHASTRIKE, localizer.getMessage("lblSHORTCUT_ALPHASTRIKE"), actAllAttack, am, im)); + list.add(new Shortcut(FPref.SHORTCUT_SHOWTARGETING, localizer.getMessage("lblSHORTCUT_SHOWTARGETING"), actTgtOverlay, am, im)); + list.add(new Shortcut(FPref.SHORTCUT_AUTOYIELD_ALWAYS_YES, localizer.getMessage("lblSHORTCUT_AUTOYIELD_ALWAYS_YES"), actAutoYieldAndYes, am, im)); + list.add(new Shortcut(FPref.SHORTCUT_AUTOYIELD_ALWAYS_NO, localizer.getMessage("lblSHORTCUT_AUTOYIELD_ALWAYS_NO"), actAutoYieldAndNo, am, im)); + list.add(new Shortcut(FPref.SHORTCUT_MACRO_RECORD, localizer.getMessage("lblSHORTCUT_MACRO_RECORD"), actMacroRecord, am, im)); + list.add(new Shortcut(FPref.SHORTCUT_MACRO_NEXT_ACTION, localizer.getMessage("lblSHORTCUT_MACRO_NEXT_ACTION"), actMacroNextAction, am, im)); + list.add(new Shortcut(FPref.SHORTCUT_CARD_ZOOM, localizer.getMessage("lblSHORTCUT_CARD_ZOOM"), actZoomCard, am, im)); return list; } // End initMatchShortcuts() diff --git a/forge-gui-desktop/src/main/java/forge/screens/home/PlayerPanel.java b/forge-gui-desktop/src/main/java/forge/screens/home/PlayerPanel.java index fccc6776dbf..eeadf3c06c5 100644 --- a/forge-gui-desktop/src/main/java/forge/screens/home/PlayerPanel.java +++ b/forge-gui-desktop/src/main/java/forge/screens/home/PlayerPanel.java @@ -128,7 +128,7 @@ public class PlayerPanel extends FPanel { this.add(avatarLabel, "spany 2, width 80px, height 80px"); createNameEditor(); - this.add(lobby.newLabel("Name:"), "w 40px, h 30px, gaptop 5px"); + this.add(lobby.newLabel(localizer.getMessage("lblName") +":"), "w 40px, h 30px, gaptop 5px"); this.add(txtPlayerName, "h 30px, pushx, growx"); nameRandomiser = createNameRandomizer(); @@ -138,7 +138,7 @@ public class PlayerPanel extends FPanel { this.add(radioHuman, "gapright 5px"); this.add(radioAi, "wrap"); - this.add(lobby.newLabel("Team:"), "w 40px, h 30px"); + this.add(lobby.newLabel(localizer.getMessage("lblTeam") + ":"), "w 40px, h 30px"); populateTeamsComboBoxes(); // Set these before action listeners are added diff --git a/forge-gui-desktop/src/main/java/forge/screens/home/quest/DialogChoosePoolDistribution.java b/forge-gui-desktop/src/main/java/forge/screens/home/quest/DialogChoosePoolDistribution.java index a1970457c21..e46e0e37420 100644 --- a/forge-gui-desktop/src/main/java/forge/screens/home/quest/DialogChoosePoolDistribution.java +++ b/forge-gui-desktop/src/main/java/forge/screens/home/quest/DialogChoosePoolDistribution.java @@ -33,6 +33,8 @@ public class DialogChoosePoolDistribution { private final FRadioButton radSurpriseMe = new FRadioButton("Surprise Me"); private final FRadioButton radBoosters = new FRadioButton("Boosters"); + private final ButtonGroup poolTypeButtonGroup = new ButtonGroup(); + private final FTextField numberOfBoostersField = new FTextField.Builder().text("0").maxLength(10).build(); private final FButton btnOk = new FButton("OK"); @@ -42,6 +44,13 @@ public class DialogChoosePoolDistribution { @SuppressWarnings("serial") public DialogChoosePoolDistribution(final List preferredColors, final PoolType poolType, final boolean includeArtifacts) { + if (poolTypeButtonGroup.getButtonCount() == 0) { + poolTypeButtonGroup.add(radBalanced); + poolTypeButtonGroup.add(radRandom); + poolTypeButtonGroup.add(radSurpriseMe); + poolTypeButtonGroup.add(radBoosters); + } + for (Byte color : preferredColors) { switch (color) { case MagicColor.BLACK: @@ -70,26 +79,14 @@ public class DialogChoosePoolDistribution { switch (poolType) { case BALANCED: radBalanced.setSelected(true); - radRandom.setSelected(false); - radSurpriseMe.setSelected(false); - radBoosters.setSelected(false); break; case RANDOM: - radBalanced.setSelected(false); radRandom.setSelected(true); - radSurpriseMe.setSelected(false); - radBoosters.setSelected(false); break; case RANDOM_BALANCED: - radBalanced.setSelected(false); - radRandom.setSelected(false); radSurpriseMe.setSelected(true); - radBoosters.setSelected(false); break; case BOOSTERS: - radBalanced.setSelected(false); - radRandom.setSelected(false); - radSurpriseMe.setSelected(false); radBoosters.setSelected(true); break; } diff --git a/forge-gui-desktop/src/main/java/forge/screens/home/quest/DialogChooseSets.java b/forge-gui-desktop/src/main/java/forge/screens/home/quest/DialogChooseSets.java index 1177b4ce256..7d6a346030d 100644 --- a/forge-gui-desktop/src/main/java/forge/screens/home/quest/DialogChooseSets.java +++ b/forge-gui-desktop/src/main/java/forge/screens/home/quest/DialogChooseSets.java @@ -2,6 +2,7 @@ package forge.screens.home.quest; import forge.assets.FSkinProp; import forge.card.CardEdition; +import forge.game.GameFormat; import forge.gui.SOverlayUtils; import forge.model.FModel; import forge.toolbox.*; @@ -9,13 +10,12 @@ import forge.util.TextUtil; import net.miginfocom.swing.MigLayout; import javax.swing.*; - +import java.awt.*; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; -import java.util.ArrayList; -import java.util.Collection; -import java.util.Collections; +import java.util.*; import java.util.List; +import java.util.function.Predicate; public class DialogChooseSets { @@ -64,16 +64,204 @@ public class DialogChooseSets { } - FPanel panel = new FPanel(new MigLayout("insets 0, gap 0, center, wrap 3")); + FPanel panel = new FPanel(new MigLayout("insets 10, gap 5, center, wrap 3")); panel.setOpaque(false); panel.setBackgroundTexture(FSkin.getIcon(FSkinProp.BG_TEXTURE)); - panel.add(new FLabel.Builder().text("Choose sets").fontSize(18).build(), "center, span, wrap, gaptop 10"); + FTextField coreField = new FTextField.Builder().text("0").maxLength(3).build(); + FTextField expansionField = new FTextField.Builder().text("0").maxLength(3).build(); + FTextField otherField = new FTextField.Builder().text("0").maxLength(3).build(); + + JPanel optionsPanel = new JPanel(new MigLayout("insets 10, gap 5, center, wrap 2")); + optionsPanel.setVisible(false); + optionsPanel.setOpaque(false); + optionsPanel.add(new JSeparator(SwingConstants.HORIZONTAL), "w 100%, span 2, growx"); + optionsPanel.add(new FLabel.Builder().text("Select Random Sets").fontSize(17).fontStyle(Font.BOLD).build(), "h 40!, span 2"); + + JPanel leftOptionsPanel = new JPanel(new MigLayout("insets 10, gap 5, center, wrap 2")); + leftOptionsPanel.setOpaque(false); + leftOptionsPanel.add(new FLabel.Builder().text("Number to Select:").fontSize(14).fontStyle(Font.BOLD).build(), " span 2"); + leftOptionsPanel.add(new FLabel.Builder().text("Core:").build()); + leftOptionsPanel.add(coreField, "w 40!"); + leftOptionsPanel.add(new FLabel.Builder().text("Expansion:").build()); + leftOptionsPanel.add(expansionField, "w 40!"); + leftOptionsPanel.add(new FLabel.Builder().text("Other:").build()); + leftOptionsPanel.add(otherField, "w 40!"); + + JPanel rightOptionsPanel = new JPanel(new MigLayout("insets 10, gap 25 5, center, wrap 2")); + rightOptionsPanel.setOpaque(false); + rightOptionsPanel.add(new FLabel.Builder().text("Format Restrictions:").fontSize(14).fontStyle(Font.BOLD).build(), "span 2"); + + ButtonGroup formatButtonGroup = new ButtonGroup(); + List gameFormats = new ArrayList<>(); + FModel.getFormats().getSanctionedList().forEach(gameFormats::add); + + gameFormats.forEach(item -> { + if (item.getName().equals("Legacy")) { + FRadioButton button = new FRadioButton("Legacy/Vintage"); + button.setActionCommand(item.getName()); + formatButtonGroup.add(button); + rightOptionsPanel.add(button); + } else if (!item.getName().equals("Vintage")) { + FRadioButton button = new FRadioButton(item.getName()); + button.setActionCommand(item.getName()); + formatButtonGroup.add(button); + rightOptionsPanel.add(button); + } + }); + + FRadioButton button = new FRadioButton("Modern Card Frame"); + button.setActionCommand("Modern Card Frame"); + formatButtonGroup.add(button); + rightOptionsPanel.add(button); + + FRadioButton noFormatSelectionButton = new FRadioButton("No Format Restriction"); + noFormatSelectionButton.setActionCommand("No Format Restriction"); + formatButtonGroup.add(noFormatSelectionButton); + rightOptionsPanel.add(noFormatSelectionButton); + noFormatSelectionButton.setSelected(true); + + optionsPanel.add(leftOptionsPanel, "w 33%:40%:78%"); + optionsPanel.add(rightOptionsPanel, "w 33%:60%:78%"); + + FButton randomSelectionButton = new FButton("Randomize Sets"); + randomSelectionButton.addActionListener(actionEvent -> { + + int numberOfCoreSets = Integer.parseInt(coreField.getText()); + int numberOfExpansionSets = Integer.parseInt(expansionField.getText()); + int numberOfOtherSets = Integer.parseInt(otherField.getText()); + + for (FCheckBox coreSet : coreSets) { + coreSet.setSelected(false); + } + for (FCheckBox expansionSet : expansionSets) { + expansionSet.setSelected(false); + } + for (FCheckBox otherSet : otherSets) { + otherSet.setSelected(false); + } + + Predicate formatPredicate = null; + for (GameFormat gameFormat : gameFormats) { + if (gameFormat.getName().equals(formatButtonGroup.getSelection().getActionCommand())) { + formatPredicate = edition -> gameFormat.editionLegalPredicate.apply(edition) && (unselectableSets == null || !unselectableSets.contains(edition.getCode())); + } else if (formatButtonGroup.getSelection().getActionCommand().equals("Modern Card Frame")) { + formatPredicate = edition -> edition.getDate().after(new Date(1059350399L * 1000L)) && (unselectableSets == null || !unselectableSets.contains(edition.getCode())); + } else if (formatButtonGroup.getSelection().getActionCommand().equals("No Format Restriction")) { + formatPredicate = edition -> unselectableSets == null || !unselectableSets.contains(edition.getCode()); + } + } + + List filteredCoreSets = new ArrayList<>(); + for (CardEdition edition : editions) { + if (edition.getType() == CardEdition.Type.CORE) { + if (formatPredicate != null && formatPredicate.test(edition)) { + filteredCoreSets.add(edition); + } + } + } + + List filteredExpansionSets = new ArrayList<>(); + for (CardEdition edition : editions) { + if (edition.getType() == CardEdition.Type.EXPANSION) { + if (formatPredicate != null && formatPredicate.test(edition)) { + filteredExpansionSets.add(edition); + } + } + } + + List filteredOtherSets = new ArrayList<>(); + for (CardEdition edition : editions) { + if (edition.getType() != CardEdition.Type.CORE && edition.getType() != CardEdition.Type.EXPANSION) { + if (formatPredicate != null && formatPredicate.test(edition)) { + filteredOtherSets.add(edition); + } + } + } + + Collections.shuffle(filteredCoreSets); + Collections.shuffle(filteredExpansionSets); + Collections.shuffle(filteredOtherSets); + + for (int i = 0; i < numberOfCoreSets && i < filteredCoreSets.size(); i++) { + String name = TextUtil.concatWithSpace(filteredCoreSets.get(i).getName(), TextUtil.enclosedParen(filteredCoreSets.get(i).getCode())); + for (FCheckBox set : coreSets) { + if (set.getText().equals(name)) { + set.setSelected(true); + } + } + } + + for (int i = 0; i < numberOfExpansionSets && i < filteredExpansionSets.size(); i++) { + String name = TextUtil.concatWithSpace(filteredExpansionSets.get(i).getName(), TextUtil.enclosedParen(filteredExpansionSets.get(i).getCode())); + for (FCheckBox set : expansionSets) { + if (set.getText().equals(name)) { + set.setSelected(true); + } + } + } + + for (int i = 0; i < numberOfOtherSets && i < filteredOtherSets.size(); i++) { + String name = TextUtil.concatWithSpace(filteredOtherSets.get(i).getName(), TextUtil.enclosedParen(filteredOtherSets.get(i).getCode())); + for (FCheckBox set : otherSets) { + if (set.getText().equals(name)) { + set.setSelected(true); + } + } + } + + panel.repaintSelf(); + + }); + + FButton clearSelectionButton = new FButton("Clear Selection"); + clearSelectionButton.addActionListener(actionEvent -> { + for (FCheckBox coreSet : coreSets) { + coreSet.setSelected(false); + } + for (FCheckBox expansionSet : expansionSets) { + expansionSet.setSelected(false); + } + for (FCheckBox otherSet : otherSets) { + otherSet.setSelected(false); + } + panel.repaintSelf(); + }); + + FButton showOptionsButton = new FButton("Show Options"); + showOptionsButton.addActionListener(actionEvent -> { + optionsPanel.setVisible(true); + showOptionsButton.setVisible(false); + }); + + FButton hideOptionsButton = new FButton("Hide Options"); + hideOptionsButton.addActionListener(actionEvent -> { + optionsPanel.setVisible(false); + showOptionsButton.setVisible(true); + }); + + JPanel buttonPanel = new JPanel(new MigLayout("h 50!, center, gap 10, insets 0, ay center")); + buttonPanel.setOpaque(false); + buttonPanel.add(randomSelectionButton, "w 175!, h 28!"); + buttonPanel.add(clearSelectionButton, "w 175!, h 28!"); + buttonPanel.add(hideOptionsButton, " w 175!, h 28!"); + + optionsPanel.add(buttonPanel, "span 2, growx"); + + if (showWantReprintsCheckbox) { + optionsPanel.add(cbWantReprints, "center, span, wrap"); + } + + optionsPanel.add(new JSeparator(SwingConstants.HORIZONTAL), "w 100%, span 2, growx"); + + panel.add(new FLabel.Builder().text("Choose sets").fontSize(20).build(), "center, span, wrap, gaptop 10"); String constraints = "aligny top"; panel.add(makeCheckBoxList(coreSets, "Core sets", true), constraints); panel.add(makeCheckBoxList(expansionSets, "Expansions", false), constraints); panel.add(makeCheckBoxList(otherSets, "Other sets", false), constraints); + panel.add(showOptionsButton, "center, w 230!, h 30!, gap 10 0 20 0, span 3, hidemode 3"); + panel.add(optionsPanel, "center, w 100, span 3, growx, hidemode 3"); final JPanel overlay = FOverlay.SINGLETON_INSTANCE.getPanel(); overlay.setLayout(new MigLayout("insets 0, gap 0, wrap, ax center, ay center")); @@ -102,13 +290,10 @@ public class DialogChooseSets { } }); - JPanel southPanel = new JPanel(new MigLayout("insets 10, gap 20, ax center")); + JPanel southPanel = new JPanel(new MigLayout("insets 10, gap 30, ax center")); southPanel.setOpaque(false); - if (showWantReprintsCheckbox) { - southPanel.add(cbWantReprints, "center, span, wrap"); - } - southPanel.add(btnOk, "center, w 40%, h 20!"); - southPanel.add(btnCancel, "center, w 40%, h 20!"); + southPanel.add(btnOk, "center, w 200!, h 30!"); + southPanel.add(btnCancel, "center, w 200!, h 30!"); panel.add(southPanel, "dock south, gapBottom 10"); diff --git a/forge-gui-desktop/src/main/java/forge/screens/home/sanctioned/AvatarSelector.java b/forge-gui-desktop/src/main/java/forge/screens/home/sanctioned/AvatarSelector.java index adae3368e4e..711dba75f69 100644 --- a/forge-gui-desktop/src/main/java/forge/screens/home/sanctioned/AvatarSelector.java +++ b/forge-gui-desktop/src/main/java/forge/screens/home/sanctioned/AvatarSelector.java @@ -15,6 +15,7 @@ import forge.toolbox.FLabel; import forge.toolbox.FScrollPane; import forge.toolbox.FSkin; import forge.toolbox.FSkin.SkinImage; +import forge.util.Localizer; import forge.view.FDialog; @SuppressWarnings("serial") @@ -23,7 +24,9 @@ public class AvatarSelector extends FDialog { private final Map avatarMap = FSkin.getAvatars(); public AvatarSelector(final String playerName, final int currentIndex, final Collection usedIndices) { - this.setTitle("Select avatar for " + playerName); + final Localizer localizer = Localizer.getInstance(); + String s = localizer.getMessage("lblSelectAvatarFor"); + this.setTitle(s.replace("%s",playerName)); final JPanel pnlAvatarPics = new JPanel(new WrapLayout()); diff --git a/forge-gui-desktop/src/main/java/forge/screens/home/sanctioned/ConstructedGameMenu.java b/forge-gui-desktop/src/main/java/forge/screens/home/sanctioned/ConstructedGameMenu.java index 31d57ec9e27..7643bc86ee6 100644 --- a/forge-gui-desktop/src/main/java/forge/screens/home/sanctioned/ConstructedGameMenu.java +++ b/forge-gui-desktop/src/main/java/forge/screens/home/sanctioned/ConstructedGameMenu.java @@ -4,6 +4,7 @@ import forge.menus.MenuUtil; import forge.model.FModel; import forge.properties.ForgePreferences; import forge.properties.ForgePreferences.FPref; +import forge.util.Localizer; import javax.swing.*; @@ -21,7 +22,8 @@ public final class ConstructedGameMenu { private static ForgePreferences prefs = FModel.getPreferences(); public static JMenu getMenu() { - JMenu menu = new JMenu("Game"); + final Localizer localizer = Localizer.getInstance(); + JMenu menu = new JMenu(localizer.getMessage("lblGame")); menu.setMnemonic(KeyEvent.VK_G); menu.add(getMenuItem_SingletonMode()); menu.add(getMenuItem_ArtifactsMode()); @@ -30,8 +32,9 @@ public final class ConstructedGameMenu { } private static JMenuItem getMenuItem_SmallCreaturesMode() { - JCheckBoxMenuItem menu = new JCheckBoxMenuItem("Remove Small Creatures"); - MenuUtil.setMenuHint(menu, "Remove 1/1 and 0/X creatures in generated decks."); + final Localizer localizer = Localizer.getInstance(); + JCheckBoxMenuItem menu = new JCheckBoxMenuItem(localizer.getMessage("cbRemoveSmall")); + MenuUtil.setMenuHint(menu, localizer.getMessage("lblRemoveSmallCreatures")); menu.setState(prefs.getPrefBoolean(FPref.DECKGEN_NOSMALL)); menu.addActionListener(new ActionListener() { @Override @@ -51,8 +54,9 @@ public final class ConstructedGameMenu { } private static JMenuItem getMenuItem_ArtifactsMode() { - JCheckBoxMenuItem menu = new JCheckBoxMenuItem("Remove Artifacts"); - MenuUtil.setMenuHint(menu, "Remove artifact cards in generated decks."); + final Localizer localizer = Localizer.getInstance(); + JCheckBoxMenuItem menu = new JCheckBoxMenuItem(localizer.getMessage("cbRemoveArtifacts")); + MenuUtil.setMenuHint(menu, localizer.getMessage("lblRemoveArtifacts")); menu.setState(prefs.getPrefBoolean(FPref.DECKGEN_ARTIFACTS)); menu.addActionListener(new ActionListener() { @Override @@ -73,8 +77,9 @@ public final class ConstructedGameMenu { } private static JMenuItem getMenuItem_SingletonMode() { - JCheckBoxMenuItem menu = new JCheckBoxMenuItem("Singleton Mode"); - MenuUtil.setMenuHint(menu, "Prevent non-land duplicates in generated decks."); + final Localizer localizer = Localizer.getInstance(); + JCheckBoxMenuItem menu = new JCheckBoxMenuItem(localizer.getMessage("cbSingletons")); + MenuUtil.setMenuHint(menu, localizer.getMessage("PreventNonLandDuplicates")); menu.setState(prefs.getPrefBoolean(FPref.DECKGEN_SINGLETONS)); menu.addActionListener(new ActionListener() { @Override diff --git a/forge-gui-desktop/src/main/java/forge/screens/home/settings/CSubmenuPreferences.java b/forge-gui-desktop/src/main/java/forge/screens/home/settings/CSubmenuPreferences.java index 141c8fa44d4..3347ebd987b 100644 --- a/forge-gui-desktop/src/main/java/forge/screens/home/settings/CSubmenuPreferences.java +++ b/forge-gui-desktop/src/main/java/forge/screens/home/settings/CSubmenuPreferences.java @@ -431,7 +431,7 @@ public enum CSubmenuPreferences implements ICDoc { private void setPlayerNameButtonText() { final FLabel btn = view.getBtnPlayerName(); final String name = prefs.getPref(FPref.PLAYER_NAME); - btn.setText(StringUtils.isBlank(name) ? "Human" : name); + btn.setText(StringUtils.isBlank(name) ? localizer.getMessage("lblHuman") : name); } @SuppressWarnings("serial") diff --git a/forge-gui-desktop/src/main/java/forge/screens/home/settings/VSubmenuPreferences.java b/forge-gui-desktop/src/main/java/forge/screens/home/settings/VSubmenuPreferences.java index 5d0a836410a..7dd0f70ae1f 100644 --- a/forge-gui-desktop/src/main/java/forge/screens/home/settings/VSubmenuPreferences.java +++ b/forge-gui-desktop/src/main/java/forge/screens/home/settings/VSubmenuPreferences.java @@ -383,8 +383,7 @@ public enum VSubmenuPreferences implements IVSubmenu { */ @Override public String getMenuTitle() { - return "Preferences"; - } + return localizer.getMessage("Preferences"); } /* (non-Javadoc) * @see forge.gui.home.IVSubmenu#getItemEnum() diff --git a/forge-gui-desktop/src/main/java/forge/screens/match/VAssignDamage.java b/forge-gui-desktop/src/main/java/forge/screens/match/VAssignDamage.java index 55f26f96155..e60359a11f2 100644 --- a/forge-gui-desktop/src/main/java/forge/screens/match/VAssignDamage.java +++ b/forge-gui-desktop/src/main/java/forge/screens/match/VAssignDamage.java @@ -50,6 +50,7 @@ import forge.toolbox.FSkin; import forge.toolbox.FSkin.SkinnedPanel; import forge.view.FDialog; import forge.view.arcane.CardPanel; +import forge.util.Localizer; /** * Assembles Swing components of assign damage dialog. @@ -61,6 +62,7 @@ import forge.view.arcane.CardPanel; *

(V at beginning of class name denotes a view class.) */ public class VAssignDamage { + final Localizer localizer = Localizer.getInstance(); private final CMatchUI matchUI; // Width and height of blocker dialog @@ -78,12 +80,12 @@ public class VAssignDamage { private final GameEntityView defender; - private final JLabel lblTotalDamage = new FLabel.Builder().text("Available damage points: Unknown").build(); - private final JLabel lblAssignRemaining = new FLabel.Builder().text("Distribute the remaining damage points among lethally wounded entities").build(); + private final JLabel lblTotalDamage = new FLabel.Builder().text(localizer.getMessage("lblTotalDamageText")).build(); + private final JLabel lblAssignRemaining = new FLabel.Builder().text(localizer.getMessage("lblAssignRemainingText")).build(); // Label Buttons - private final FButton btnOK = new FButton("OK"); - private final FButton btnReset = new FButton("Reset"); - private final FButton btnAuto = new FButton("Auto"); + private final FButton btnOK = new FButton(localizer.getMessage("lblOk")); + private final FButton btnReset = new FButton(localizer.getMessage("lblReset")); + private final FButton btnAuto = new FButton(localizer.getMessage("lblAuto")); private static class DamageTarget { @@ -141,8 +143,8 @@ public class VAssignDamage { public VAssignDamage(final CMatchUI matchUI, final CardView attacker, final List blockers, final int damage0, final GameEntityView defender0, boolean overrideOrder) { this.matchUI = matchUI; - - dlg.setTitle("Assign damage dealt by " + attacker); + String s = localizer.getMessage("lbLAssignDamageDealtBy"); + dlg.setTitle(s.replace("%s",attacker.toString())); // Set damage storage vars totalDamageToAssign = damage0; @@ -165,8 +167,8 @@ public class VAssignDamage { final JPanel pnlInfo = new JPanel(new MigLayout("insets 0, gap 0, wrap")); pnlInfo.setOpaque(false); pnlInfo.add(lblTotalDamage, "gap 0 0 20px 5px"); - pnlInfo.add(new FLabel.Builder().text("Left click: Assign 1 damage. (Left Click + Control): Assign remaining damage up to lethal").build(), "gap 0 0 0 5px"); - pnlInfo.add(new FLabel.Builder().text("Right click: Unassign 1 damage. (Right Click + Control): Unassign all damage.").build(), "gap 0 0 0 5px"); + pnlInfo.add(new FLabel.Builder().text(localizer.getMessage("lblLClickDamageMessage")).build(), "gap 0 0 0 5px"); + pnlInfo.add(new FLabel.Builder().text(localizer.getMessage("lblRClickDamageMessage")).build(), "gap 0 0 0 5px"); // Defenders area final JPanel pnlDefenders = new JPanel(); @@ -401,7 +403,7 @@ public class VAssignDamage { StringBuilder sb = new StringBuilder(); sb.append(dmg); if( overkill >= 0 ) { - sb.append(" (Lethal"); + sb.append(" (" +localizer.getMessage("lblLethal")); if( overkill > 0 ) sb.append(" +").append(overkill); sb.append(")"); diff --git a/forge-gui-desktop/src/main/java/forge/screens/match/menus/GameMenu.java b/forge-gui-desktop/src/main/java/forge/screens/match/menus/GameMenu.java index b64fefeee31..c241a6113b2 100644 --- a/forge-gui-desktop/src/main/java/forge/screens/match/menus/GameMenu.java +++ b/forge-gui-desktop/src/main/java/forge/screens/match/menus/GameMenu.java @@ -22,6 +22,7 @@ import forge.toolbox.FSkin.SkinnedCheckBoxMenuItem; import forge.toolbox.FSkin.SkinnedMenu; import forge.toolbox.FSkin.SkinnedMenuItem; import forge.toolbox.FSkin.SkinnedRadioButtonMenuItem; +import forge.util.Localizer; /** * Returns a JMenu containing options associated with current game. @@ -38,7 +39,8 @@ public final class GameMenu { private static boolean showIcons; public JMenu getMenu() { - final JMenu menu = new JMenu("Game"); + final Localizer localizer = Localizer.getInstance(); + final JMenu menu = new JMenu(localizer.getMessage("lblGame")); menu.setMnemonic(KeyEvent.VK_G); menu.add(getMenuItem_Undo()); menu.add(getMenuItem_Concede()); @@ -56,7 +58,8 @@ public final class GameMenu { } private static SkinnedCheckBoxMenuItem getMenuItem_GameSoundEffects() { - SkinnedCheckBoxMenuItem menuItem = new SkinnedCheckBoxMenuItem("Sound Effects"); + final Localizer localizer = Localizer.getInstance(); + SkinnedCheckBoxMenuItem menuItem = new SkinnedCheckBoxMenuItem(localizer.getMessage("lblSoundEffects")); menuItem.setState(prefs.getPrefBoolean(FPref.UI_ENABLE_SOUNDS)); menuItem.addActionListener(getSoundEffectsAction()); return menuItem; @@ -76,7 +79,8 @@ public final class GameMenu { } private SkinnedMenuItem getMenuItem_Undo() { - final SkinnedMenuItem menuItem = new SkinnedMenuItem("Undo"); + final Localizer localizer = Localizer.getInstance(); + final SkinnedMenuItem menuItem = new SkinnedMenuItem(localizer.getMessage("lblUndo")); menuItem.setAccelerator(MenuUtil.getAcceleratorKey(KeyEvent.VK_Z)); menuItem.addActionListener(getUndoAction()); return menuItem; @@ -109,7 +113,8 @@ public final class GameMenu { } private SkinnedMenuItem getMenuItem_AlphaStrike() { - final SkinnedMenuItem menuItem = new SkinnedMenuItem("Alpha Strike"); + final Localizer localizer = Localizer.getInstance(); + final SkinnedMenuItem menuItem = new SkinnedMenuItem(localizer.getMessage("lblAlphaStrike")); menuItem.setIcon((showIcons ? MenuUtil.getMenuIcon(FSkinProp.ICO_ALPHASTRIKE) : null)); menuItem.setAccelerator(MenuUtil.getAcceleratorKey(KeyEvent.VK_A)); menuItem.addActionListener(getAlphaStrikeAction()); @@ -126,7 +131,8 @@ public final class GameMenu { } private SkinnedMenuItem getMenuItem_EndTurn() { - final SkinnedMenuItem menuItem = new SkinnedMenuItem("End Turn"); + final Localizer localizer = Localizer.getInstance(); + final SkinnedMenuItem menuItem = new SkinnedMenuItem(localizer.getMessage("lblEndTurn")); menuItem.setIcon((showIcons ? MenuUtil.getMenuIcon(FSkinProp.ICO_ENDTURN) : null)); menuItem.setAccelerator(MenuUtil.getAcceleratorKey(KeyEvent.VK_E)); menuItem.addActionListener(getEndTurnAction()); @@ -143,7 +149,8 @@ public final class GameMenu { } private SkinnedMenu getMenuItem_TargetingArcs() { - final SkinnedMenu menu = new SkinnedMenu("Targeting Arcs"); + final Localizer localizer = Localizer.getInstance(); + final SkinnedMenu menu = new SkinnedMenu(localizer.getMessage("lblTargetingArcs")); final ButtonGroup group = new ButtonGroup(); SkinIcon menuIcon = MenuUtil.getMenuIcon(FSkinProp.ICO_ARCSOFF); @@ -155,15 +162,15 @@ public final class GameMenu { } SkinnedRadioButtonMenuItem menuItem; - menuItem = getTargetingArcRadioButton("Off", FSkinProp.ICO_ARCSOFF, ArcState.OFF); + menuItem = getTargetingArcRadioButton(localizer.getMessage("lblOff"), FSkinProp.ICO_ARCSOFF, ArcState.OFF); if (menuItem.isSelected()) { menuIcon = MenuUtil.getMenuIcon(FSkinProp.ICO_ARCSOFF); } group.add(menuItem); menu.add(menuItem); - menuItem = getTargetingArcRadioButton("Card mouseover", FSkinProp.ICO_ARCSHOVER, ArcState.MOUSEOVER); + menuItem = getTargetingArcRadioButton(localizer.getMessage("lblCardMouseOver"), FSkinProp.ICO_ARCSHOVER, ArcState.MOUSEOVER); if (menuItem.isSelected()) { menuIcon = MenuUtil.getMenuIcon(FSkinProp.ICO_ARCSHOVER); } group.add(menuItem); menu.add(menuItem); - menuItem = getTargetingArcRadioButton("Always On", FSkinProp.ICO_ARCSON, ArcState.ON); + menuItem = getTargetingArcRadioButton(localizer.getMessage("lblAlwaysOn"), FSkinProp.ICO_ARCSON, ArcState.ON); if (menuItem.isSelected()) { menuIcon = MenuUtil.getMenuIcon(FSkinProp.ICO_ARCSON); } group.add(menuItem); @@ -200,7 +207,8 @@ public final class GameMenu { } private SkinnedMenuItem getMenuItem_AutoYields() { - final SkinnedMenuItem menuItem = new SkinnedMenuItem("Auto-Yields"); + final Localizer localizer = Localizer.getInstance(); + final SkinnedMenuItem menuItem = new SkinnedMenuItem(localizer.getMessage("lblAutoYields")); menuItem.setIcon((showIcons ? MenuUtil.getMenuIcon(FSkinProp.ICO_WARNING) : null)); menuItem.addActionListener(getAutoYieldsAction()); return menuItem; @@ -217,7 +225,8 @@ public final class GameMenu { } private SkinnedMenuItem getMenuItem_ViewDeckList() { - final SkinnedMenuItem menuItem = new SkinnedMenuItem("Deck List"); + final Localizer localizer = Localizer.getInstance(); + final SkinnedMenuItem menuItem = new SkinnedMenuItem(localizer.getMessage("lblDeckList")); menuItem.setIcon((showIcons ? MenuUtil.getMenuIcon(FSkinProp.ICO_DECKLIST) : null)); menuItem.addActionListener(getViewDeckListAction()); return menuItem; diff --git a/forge-gui-desktop/src/main/java/forge/view/FNavigationBar.java b/forge-gui-desktop/src/main/java/forge/view/FNavigationBar.java index 05eb0e2d3b6..06c0883873c 100644 --- a/forge-gui-desktop/src/main/java/forge/view/FNavigationBar.java +++ b/forge-gui-desktop/src/main/java/forge/view/FNavigationBar.java @@ -37,6 +37,8 @@ import forge.toolbox.FSkin; import forge.toolbox.FSkin.SkinColor; import forge.toolbox.FSkin.SkinnedLabel; import forge.util.ReflectionUtil; +import forge.util.Localizer; + @SuppressWarnings("serial") public class FNavigationBar extends FTitleBarBase { @@ -71,15 +73,16 @@ public class FNavigationBar extends FTitleBarBase { } public void updateBtnCloseTooltip() { + final Localizer localizer = Localizer.getInstance(); switch (Singletons.getControl().getCloseAction()) { case NONE: - btnClose.setToolTipText("Close"); + btnClose.setToolTipText(localizer.getMessage("lblClose")); break; case CLOSE_SCREEN: btnClose.setToolTipText(this.selectedTab.screen.getCloseButtonTooltip()); break; case EXIT_FORGE: - btnClose.setToolTipText("Exit Forge"); + btnClose.setToolTipText(localizer.getMessage("lblExitForge")); break; } } diff --git a/forge-gui-ios/pom.xml b/forge-gui-ios/pom.xml index 732d114fe9c..a3ede2b57bf 100644 --- a/forge-gui-ios/pom.xml +++ b/forge-gui-ios/pom.xml @@ -6,7 +6,7 @@ jar -Xms128m -Xmx2048m - 1.6.21.001 + 1.6.21.003 diff --git a/forge-gui-mobile/src/forge/Forge.java b/forge-gui-mobile/src/forge/Forge.java index 38206affce0..f5708da10fe 100644 --- a/forge-gui-mobile/src/forge/Forge.java +++ b/forge-gui-mobile/src/forge/Forge.java @@ -34,7 +34,7 @@ import java.util.List; import java.util.Stack; public class Forge implements ApplicationListener { - public static final String CURRENT_VERSION = "1.6.21.001"; + public static final String CURRENT_VERSION = "1.6.21.003"; private static final ApplicationListener app = new Forge(); private static Clipboard clipboard; diff --git a/forge-gui-mobile/src/forge/assets/ImageCache.java b/forge-gui-mobile/src/forge/assets/ImageCache.java index 1cab15dc9da..681e1dec9b3 100644 --- a/forge-gui-mobile/src/forge/assets/ImageCache.java +++ b/forge-gui-mobile/src/forge/assets/ImageCache.java @@ -22,18 +22,17 @@ import com.badlogic.gdx.graphics.Pixmap.Format; import com.badlogic.gdx.graphics.Texture; import com.google.common.cache.CacheBuilder; import com.google.common.cache.LoadingCache; - import forge.ImageKeys; import forge.game.player.IHasIcon; import forge.item.InventoryItem; import forge.properties.ForgeConstants; import forge.util.ImageUtil; - import org.apache.commons.lang3.StringUtils; import java.util.HashSet; import java.util.Set; import java.util.concurrent.ExecutionException; +import java.util.concurrent.TimeUnit; /** * This class stores ALL card images in a cache with soft values. this means @@ -53,7 +52,10 @@ public class ImageCache { // short prefixes to save memory private static final Set missingIconKeys = new HashSet(); - private static final LoadingCache cache = CacheBuilder.newBuilder().softValues().build(new ImageLoader()); + private static final LoadingCache cache = CacheBuilder.newBuilder() + .maximumSize(400) + .expireAfterAccess(15,TimeUnit.MINUTES) + .build(new ImageLoader()); public static final Texture defaultImage; private static boolean imageLoaded, delayLoadRequested; diff --git a/forge-gui/release-files/CHANGES.txt b/forge-gui/release-files/CHANGES.txt index 05f0bf1829e..1e2551918a7 100644 --- a/forge-gui/release-files/CHANGES.txt +++ b/forge-gui/release-files/CHANGES.txt @@ -1,2 +1,6 @@ +- Set Selection Randomizer - +There's a new randomizer available when Forge asks you to choose sets. Given a few options, it will pick out a selection of random sets for use in either the deck editor or in quest mode. + + - Bug fixes - As always, this release of Forge features an assortment of bug fixes and improvements based on user feedback during the previous release run. diff --git a/forge-gui/res/languages/en-US.properties b/forge-gui/res/languages/en-US.properties index 7c57b271f98..b143e5d2118 100644 --- a/forge-gui/res/languages/en-US.properties +++ b/forge-gui/res/languages/en-US.properties @@ -1,4 +1,5 @@ language.name = English (US) +#SplashScreen.java splash.loading.examining-cards = Loading cards, examining folder splash.loading.cards-folders = Loading cards from folders splash.loading.cards-archive = Loading cards from archive @@ -230,4 +231,57 @@ lblArticles=Articles lblGettingStarted=Getting Started lblHowtoPlay=How to Play lblForgeLicense=Forge License -lblReleaseNotes=Release Notes \ No newline at end of file +lblReleaseNotes=Release Notes +#GameMenu.java +lblGame=Game +lblSoundEffects=Sound Effects +lblUndo=Undo +lblAlphaStrike=Alpha Strike +lblEndTurn=End Turn +lblTargetingArcs=Targeting Arcs +lblOff=Off +lblCardMouseOver=Card Mouseover +lblAlwaysOn=Always On +lblAutoYields=Auto-Yields +lblDeckList = Deck List +lblClose=Close +lblExitForge=Exit Forge +#ConstructedGameMenu.java +lblSelectAvatarFor=Select avatar for %s +lblRemoveSmallCreatures=Remove 1/1 and 0/X creatures in generated decks. +lblRemoveArtifacts=Remove artifact cards in generated decks. +PreventNonLandDuplicates=Prevent non-land duplicates in generated decks. +#PlayerPanel.java +lblName=Name +lblTeam=Team +#InputConfirmMulligan.java +lblKeep=Keep +lblYouAreGoingFirst=you are going first! +lblIsGoingFirst=is going first +lblYouAreGoing=you are going +lblMulligan=Mulligan +lblDoYouWantToKeepYourHand=Do you want to keep your hand? +lblOk=Ok +lblReset=Reset +lblAuto=Auto +#VAssignDamage.java +lbLAssignDamageDealtBy=Assign damage dealt by %s +lblLClickDamageMessage=Left click: Assign 1 damage. (Left Click + Control): Assign remaining damage up to lethal +lblRClickDamageMessage=Right click: Unassign 1 damage. (Right Click + Control): Unassign all damage. +lblTotalDamageText=Available damage points: Unknown +lblAssignRemainingText=Distribute the remaining damage points among lethally wounded entities +lblLethal=Lethal +#KeyboardShortcuts.java +lblSHORTCUT_SHOWSTACK=Match: show stack panel +lblSHORTCUT_SHOWCOMBAT=Match: show combat panel +lblSHORTCUT_SHOWCONSOLE=Match: show console panel +lblSHORTCUT_SHOWDEV=Match: show dev panel +lblSHORTCUT_CONCEDE=Match: concede game +lblSHORTCUT_ENDTURN=Match: pass priority until EOT or next stack event +lblSHORTCUT_ALPHASTRIKE=Match: Alpha Strike (attack with all available) +lblSHORTCUT_SHOWTARGETING=Match: toggle targeting visual overlay +lblSHORTCUT_AUTOYIELD_ALWAYS_YES=Match: auto-yield ability on stack (Always Yes) +lblSHORTCUT_AUTOYIELD_ALWAYS_NO=Match: auto-yield ability on stack (Always No) +lblSHORTCUT_MACRO_RECORD=Match: record a macro sequence of actions +lblSHORTCUT_MACRO_NEXT_ACTION=Match: execute next action in a recorded macro +lblSHORTCUT_CARD_ZOOM=Match: zoom the currently selected card \ No newline at end of file diff --git a/forge-gui/res/puzzle/PS_RNA5.pzl b/forge-gui/res/puzzle/PS_RNA5.pzl new file mode 100644 index 00000000000..c66ddea8afa --- /dev/null +++ b/forge-gui/res/puzzle/PS_RNA5.pzl @@ -0,0 +1,18 @@ +[metadata] +Name:Possibility Storm - Ravnica Allegiance #05 +URL:http://www.possibilitystorm.com/wp-content/uploads/2019/02/102.-RNA5.jpg +Goal:Win +Turns:1 +Difficulty:Rare +Description:What the... you have no lands? Who did that? (You did that.) Start at the beginning of your first main phase as you choose targets for Fall of the Thran's second chapter ability. You just drew the final card in your library. Win this turn. +[state] +humanlife=17 +ailife=16 +turn=1 +activeplayer=human +activephase=DRAW +activephaseadvance=MAIN1 +humanhand=Enter the Unknown;Wildgrowth Walker;Depths of Desire;Merfolk Branchwalker;Song of Freyalise;Rallying Roar +humangraveyard=Plains;Hallowed Fountain;Forest;Swamp;Island;Temple Garden +humanbattlefield=Jace, Ingenious Mind-Mage|Counters:LOYALTY=3;Famished Paladin;Vona, Butcher of Magan;Tenth District Guard;Cacophodon;Path of Discovery;Fall of the Thran|Counters:LORE=1 +aibattlefield=Temple Altisaur;Everdawn Champion;Baird, Steward of Argive;Imperial Ceratops|Id:1;Dauntless Bodyguard|ChosenCards:1 diff --git a/forge-gui/src/main/java/forge/match/input/InputConfirmMulligan.java b/forge-gui/src/main/java/forge/match/input/InputConfirmMulligan.java index c39a3b40fe6..cd59ca3c93f 100644 --- a/forge-gui/src/main/java/forge/match/input/InputConfirmMulligan.java +++ b/forge-gui/src/main/java/forge/match/input/InputConfirmMulligan.java @@ -29,6 +29,7 @@ import forge.game.zone.ZoneType; import forge.player.PlayerControllerHuman; import forge.util.ITriggerEvent; import forge.util.Lang; +import forge.util.Localizer; import forge.util.ThreadUtil; /** @@ -58,19 +59,20 @@ public class InputConfirmMulligan extends InputSyncronizedBase { /** {@inheritDoc} */ @Override public final void showMessage() { + final Localizer localizer = Localizer.getInstance(); final Game game = player.getGame(); final StringBuilder sb = new StringBuilder(); if (startingPlayer == player) { - sb.append(player).append(", you are going first!\n\n"); + sb.append(player).append(", "+ localizer.getMessage("lblYouAreGoingFirst") +"\n\n"); } else { - sb.append(startingPlayer.getName()).append(" is going first.\n"); - sb.append(player).append(", you are going ").append(Lang.getOrdinal(game.getPosition(player, startingPlayer))).append(".\n\n"); + sb.append(startingPlayer.getName()).append(" " + localizer.getMessage("lblIsGoingFirst") +".\n"); + sb.append(player).append(", "+ localizer.getMessage("lblYouAreGoing") +"").append(Lang.getOrdinal(game.getPosition(player, startingPlayer))).append(".\n\n"); } - getController().getGui().updateButtons(getOwner(), "Keep", "Mulligan", true, true, true); - sb.append("Do you want to keep your hand?"); + getController().getGui().updateButtons(getOwner(), localizer.getMessage("lblKeep"), localizer.getMessage("lblMulligan"), true, true, true); + sb.append(localizer.getMessage("lblDoYouWantToKeepYourHand")); showMessage(sb.toString()); }