From f1e0158102a538ae90f4380d6880e3f24d7e063a Mon Sep 17 00:00:00 2001 From: Dan Demp Date: Tue, 20 Aug 2019 04:34:14 +0000 Subject: [PATCH] Add menu item for setting Oathbreaker Allow double-tapping to set Commander or Oathbreaker if one hasn't yet been set --- .../src/main/java/forge/StaticData.java | 18 +- .../src/main/java/forge/card/CardDb.java | 2 +- .../src/main/java/forge/card/CardRules.java | 12 +- .../java/forge/card/CardRulesPredicates.java | 13 + forge-core/src/main/java/forge/deck/Deck.java | 36 +++ .../src/main/java/forge/deck/DeckFormat.java | 149 +++++----- .../src/main/java/forge/game/GameFormat.java | 2 +- .../src/main/java/forge/game/GameRules.java | 1 + .../src/main/java/forge/game/GameType.java | 2 + .../main/java/forge/game/card/CardView.java | 27 +- .../main/java/forge/game/player/Player.java | 43 ++- .../forge/game/player/RegisteredPlayer.java | 5 +- .../src/main/java/forge/game/zone/Zone.java | 12 +- .../forge/trackable/TrackableProperty.java | 1 + .../java/forge/deckchooser/FDeckChooser.java | 35 ++- .../main/java/forge/gui/framework/EDocID.java | 2 + .../java/forge/gui/framework/FScreen.java | 9 + .../java/forge/itemmanager/DeckManager.java | 6 + .../screens/deckeditor/CDeckEditorUI.java | 4 + .../deckeditor/controllers/ACEditorBase.java | 7 +- .../deckeditor/controllers/CBrawlDecks.java | 2 +- .../deckeditor/controllers/CDeckEditor.java | 6 +- .../controllers/CEditorCommander.java | 51 +++- .../controllers/CEditorConstructed.java | 82 ++++- .../controllers/CEditorDraftingProcess.java | 21 +- .../controllers/CEditorLimited.java | 22 +- .../deckeditor/controllers/CEditorQuest.java | 11 +- .../controllers/CEditorQuestCardShop.java | 9 +- .../CEditorQuestDraftingProcess.java | 21 +- .../controllers/CEditorQuestLimited.java | 9 +- .../controllers/CEditorTokenViewer.java | 9 +- .../controllers/CEditorVariant.java | 9 +- .../controllers/CEditorWinstonProcess.java | 9 +- .../controllers/COathbreakerDecks.java | 44 +++ .../controllers/CTinyLeadersDecks.java | 2 +- .../deckeditor/views/VOathbreakerDecks.java | 100 +++++++ .../main/java/forge/screens/home/CLobby.java | 16 +- .../java/forge/screens/home/PlayerPanel.java | 9 +- .../main/java/forge/screens/home/VLobby.java | 136 ++++----- .../src/forge/deck/FDeckChooser.java | 150 ++++++---- .../src/forge/deck/FDeckEditor.java | 281 +++++++++++------- .../screens/constructed/LobbyScreen.java | 20 +- .../screens/constructed/PlayerPanel.java | 52 +++- forge-gui/res/defaults/editor.xml | 1 + forge-gui/res/formats/Casual/Oathbreaker.txt | 6 + forge-gui/res/languages/de-DE.properties | 6 + forge-gui/res/languages/en-US.properties | 8 +- forge-gui/res/languages/es-es.properties | 8 +- .../achievement/ConstructedAchievements.java | 1 + .../deck/CardRelationMatrixGenerator.java | 46 ++- .../forge/deck/CommanderDeckGenerator.java | 28 +- .../src/main/java/forge/deck/DeckProxy.java | 9 + .../src/main/java/forge/deck/DeckType.java | 13 +- .../src/main/java/forge/deck/DeckgenUtil.java | 88 ++++-- .../java/forge/deck/RandomDeckGenerator.java | 8 + .../java/forge/deck/io/DeckPreferences.java | 27 +- .../forge/itemmanager/ItemManagerConfig.java | 2 + .../CardThemedCommanderDeckBuilder.java | 4 +- .../src/main/java/forge/match/GameLobby.java | 26 +- .../java/forge/model/CardCollections.java | 9 + .../src/main/java/forge/model/FModel.java | 4 +- .../forge/planarconquest/ConquestUtil.java | 2 +- .../java/forge/properties/ForgeConstants.java | 2 + .../forge/properties/ForgePreferences.java | 14 + 64 files changed, 1227 insertions(+), 542 deletions(-) create mode 100644 forge-gui-desktop/src/main/java/forge/screens/deckeditor/controllers/COathbreakerDecks.java create mode 100644 forge-gui-desktop/src/main/java/forge/screens/deckeditor/views/VOathbreakerDecks.java create mode 100644 forge-gui/res/formats/Casual/Oathbreaker.txt diff --git a/forge-core/src/main/java/forge/StaticData.java b/forge-core/src/main/java/forge/StaticData.java index 99f05389bca..7ff30567465 100644 --- a/forge-core/src/main/java/forge/StaticData.java +++ b/forge-core/src/main/java/forge/StaticData.java @@ -36,6 +36,8 @@ public class StaticData { private Predicate standardPredicate; private Predicate brawlPredicate; private Predicate modernPredicate; + private Predicate commanderPredicate; + private Predicate oathbreakerPredicate; private boolean filteredHandsEnabled = false; @@ -201,17 +203,23 @@ public class StaticData { public void setStandardPredicate(Predicate standardPredicate) { this.standardPredicate = standardPredicate; } - public void setBrawlPredicate(Predicate brawlPredicate) { this.brawlPredicate = brawlPredicate; } - public void setModernPredicate(Predicate modernPredicate) { this.modernPredicate = standardPredicate; } + public void setCommanderPredicate(Predicate commanderPredicate) { this.commanderPredicate = commanderPredicate; } + + public void setOathbreakerPredicate(Predicate oathbreakerPredicate) { this.oathbreakerPredicate = oathbreakerPredicate; } + + public void setBrawlPredicate(Predicate brawlPredicate) { this.brawlPredicate = brawlPredicate; } + public Predicate getModernPredicate() { return modernPredicate; } - public Predicate getBrawlPredicate() { - return brawlPredicate; - } + public Predicate getCommanderPredicate() { return commanderPredicate; } + + public Predicate getOathbreakerPredicate() { return oathbreakerPredicate; } + + public Predicate getBrawlPredicate() { return brawlPredicate; } public void setFilteredHandsEnabled(boolean filteredHandsEnabled){ this.filteredHandsEnabled = filteredHandsEnabled; diff --git a/forge-core/src/main/java/forge/card/CardDb.java b/forge-core/src/main/java/forge/card/CardDb.java index 16af453f57a..0c4071e4cf4 100644 --- a/forge-core/src/main/java/forge/card/CardDb.java +++ b/forge-core/src/main/java/forge/card/CardDb.java @@ -219,7 +219,7 @@ public final class CardDb implements ICardDatabase, IDeckGenPool { if (upcomingSet != null) { addCard(new PaperCard(cr, upcomingSet.getCode(), CardRarity.Unknown, 1)); } else { - System.err.println("The card " + cr.getName() + " was not assigned to any set. Adding it to UNKNOWN set... to fix see res/cardeditions/ folder. "); + System.err.println("The card " + cr.getName() + " was not assigned to any set. Adding it to UNKNOWN set... to fix see res/editions/ folder. "); addCard(new PaperCard(cr, CardEdition.UNKNOWN.getCode(), CardRarity.Special, 1)); } } diff --git a/forge-core/src/main/java/forge/card/CardRules.java b/forge-core/src/main/java/forge/card/CardRules.java index 75e54aae2ab..322c003b6f2 100644 --- a/forge-core/src/main/java/forge/card/CardRules.java +++ b/forge-core/src/main/java/forge/card/CardRules.java @@ -210,6 +210,16 @@ public final class CardRules implements ICardCharacteristics { return canBeCommander() && (hasKeyword("Partner") || !this.partnerWith.isEmpty()); } + public boolean canBeOathbreaker() { + CardType type = mainPart.getType(); + return type.isPlaneswalker(); + } + + public boolean canBeSignatureSpell() { + CardType type = mainPart.getType(); + return type.isInstant() || type.isSorcery(); + } + public boolean canBeBrawlCommander() { CardType type = mainPart.getType(); return (type.isLegendary() && type.isCreature()) || type.isPlaneswalker(); @@ -219,7 +229,7 @@ public final class CardRules implements ICardCharacteristics { return meldWith; } - public String getParterWith() { + public String getPartnerWith() { return partnerWith; } diff --git a/forge-core/src/main/java/forge/card/CardRulesPredicates.java b/forge-core/src/main/java/forge/card/CardRulesPredicates.java index efc8d4add4e..e6b200b1a94 100644 --- a/forge-core/src/main/java/forge/card/CardRulesPredicates.java +++ b/forge-core/src/main/java/forge/card/CardRulesPredicates.java @@ -570,6 +570,19 @@ public final class CardRulesPredicates { } }; + public static final Predicate CAN_BE_OATHBREAKER = new Predicate() { + @Override + public boolean apply(final CardRules subject) { + return subject.canBeOathbreaker(); + } + }; + public static final Predicate CAN_BE_SIGNATURE_SPELL = new Predicate() { + @Override + public boolean apply(final CardRules subject) { + return subject.canBeSignatureSpell(); + } + }; + public static final Predicate IS_PLANESWALKER = CardRulesPredicates.coreType(true, CardType.CoreType.Planeswalker); public static final Predicate IS_INSTANT = CardRulesPredicates.coreType(true, CardType.CoreType.Instant); public static final Predicate IS_SORCERY = CardRulesPredicates.coreType(true, CardType.CoreType.Sorcery); diff --git a/forge-core/src/main/java/forge/deck/Deck.java b/forge-core/src/main/java/forge/deck/Deck.java index a4b43b51efd..3dee5c15371 100644 --- a/forge-core/src/main/java/forge/deck/Deck.java +++ b/forge-core/src/main/java/forge/deck/Deck.java @@ -122,9 +122,45 @@ public class Deck extends DeckBase implements Iterable c : cp) { result.add(c.getKey()); } + if (result.size() > 1) { //sort by type so signature spell comes after oathbreaker + Collections.sort(result, new Comparator() { + @Override + public int compare(final PaperCard c1, final PaperCard c2) { + return Boolean.compare(c1.getRules().canBeSignatureSpell(), c2.getRules().canBeSignatureSpell()); + } + }); + } return result; } + //at least for now, Oathbreaker will only support one oathbreaker and one signature spell + public PaperCard getOathbreaker() { + final CardPool cp = get(DeckSection.Commander); + if (cp == null) { + return null; + } + for (final Entry c : cp) { + PaperCard card = c.getKey(); + if (card.getRules().canBeOathbreaker()) { + return card; + } + } + return null; + } + public PaperCard getSignatureSpell() { + final CardPool cp = get(DeckSection.Commander); + if (cp == null) { + return null; + } + for (final Entry c : cp) { + PaperCard card = c.getKey(); + if (card.getRules().canBeSignatureSpell()) { + return card; + } + } + return null; + } + // may return nulls public CardPool get(DeckSection deckSection) { loadDeferredSections(); diff --git a/forge-core/src/main/java/forge/deck/DeckFormat.java b/forge-core/src/main/java/forge/deck/DeckFormat.java index d44b93c0141..5d9f651828b 100644 --- a/forge-core/src/main/java/forge/deck/DeckFormat.java +++ b/forge-core/src/main/java/forge/deck/DeckFormat.java @@ -48,48 +48,25 @@ public enum DeckFormat { Constructed ( Range.between(60, Integer.MAX_VALUE), Range.between(0, 15), 4), QuestDeck ( Range.between(40, Integer.MAX_VALUE), Range.between(0, 15), 4), Limited ( Range.between(40, Integer.MAX_VALUE), null, Integer.MAX_VALUE), - Commander ( Range.is(99), Range.between(0, 10), 1, new Predicate() { - private final Set bannedCards = ImmutableSet.of( - "Adriana's Valor", "Advantageous Proclamation", "Amulet of Quoz", "Ancestral Recall", "Assemble the Rank and Vile", - "Backup Plan", "Balance", "Biorhythm", "Black Lotus", "Brago's Favor", "Braids, Cabal Minion", "Bronze Tablet", - "Channel", "Chaos Orb", "Coalition Victory", "Contract from Below", "Darkpact", "Demonic Attorney", "Double Stroke", - "Echoing Boon", "Emissary's Ploy", "Emrakul, the Aeons Torn", "Erayo, Soratami Ascendant", "Falling Star", - "Fastbond", "Gifts Ungiven", "Griselbrand", "Hired Heist", "Hold the Perimeter", "Hymn of the Wilds", "Immediate Action", - "Incendiary Dissent", "Iterative Analysis", "Jeweled Bird", "Karakas", "Leovold, Emissary of Trest", "Library of Alexandria", - "Limited Resources", "Mox Emerald", "Mox Jet", "Mox Pearl", "Mox Ruby", "Mox Sapphire", "Muzzio's Preparations", - "Natural Unity", "Painter's Servant", "Panoptic Mirror", "Power Play", "Primeval Titan", "Prophet of Kruphix", - "Rebirth", "Recurring Nightmare", "Rofellos, Llanowar Emissary", "Secret Summoning", "Secrets of Paradise", - "Sentinel Dispatch", "Shahrazad", "Sovereign's Realm", "Summoner's Bond", "Sundering Titan", "Sway of the Stars", - "Sylvan Primordial", "Tempest Efreet", "Time Vault", "Time Walk", "Timmerian Fiends", "Tinker", "Tolarian Academy", - "Trade Secrets", "Unexpected Potential", "Upheaval", "Weight Advantage", "Worldfire", "Worldknit", "Yawgmoth's Bargain"); + Commander ( Range.is(99), Range.between(0, 10), 1, null, new Predicate() { @Override - public boolean apply(CardRules rules) { - if (bannedCards.contains(rules.getName())) { - return false; - } - return true; + public boolean apply(PaperCard card) { + return StaticData.instance().getCommanderPredicate().apply(card); + } + }), + Oathbreaker ( Range.is(58), Range.between(0, 10), 1, null, new Predicate() { + @Override + public boolean apply(PaperCard card) { + return StaticData.instance().getOathbreakerPredicate().apply(card); } }), Pauper ( Range.is(60), Range.between(0, 10), 1), Brawl ( Range.is(59), Range.between(0, 15), 1, null, new Predicate() { - private final Set bannedCards = ImmutableSet.of( - "Baral, Chief of Compliance","Smuggler's Copter","Sorcerous Spyglass"); @Override public boolean apply(PaperCard card) { - //why do we need to hard code the bannings here - they are defined in the GameFormat predicate used below - if (bannedCards.contains(card.getName())) { - return false; - } - return StaticData.instance() == null ? false : StaticData.instance().getBrawlPredicate().apply(card); + return StaticData.instance().getBrawlPredicate().apply(card); } - }) { - private final Set bannedCommanders = ImmutableSet.of("Baral, Chief of Compliance"); - - @Override - public boolean isLegalCommander(CardRules rules) { - return super.isLegalCommander(rules) && !bannedCommanders.contains(rules.getName()); - } - }, + }), TinyLeaders ( Range.is(49), Range.between(0, 10), 1, new Predicate() { private final Set bannedCards = ImmutableSet.of( "Ancestral Recall", "Balance", "Black Lotus", "Black Vise", "Channel", "Chaos Orb", "Contract From Below", "Counterbalance", "Darkpact", "Demonic Attorney", "Demonic Tutor", "Earthcraft", "Edric, Spymaster of Trest", "Falling Star", @@ -167,8 +144,12 @@ public enum DeckFormat { cardPoolFilter = null; } - private boolean hasCommander() { - return this == Commander || this == TinyLeaders || this == Brawl; + public boolean hasCommander() { + return this == Commander || this == Oathbreaker || this == TinyLeaders || this == Brawl; + } + + public boolean hasSignatureSpell() { + return this == Oathbreaker; } /** @@ -232,41 +213,56 @@ public enum DeckFormat { noBasicLands = conspiracies.countByName(SOVREALM, false) > 0; } - if (hasCommander()) { // 1 Commander, or 2 Partner Commanders - final List commanders = deck.getCommanders(); - - if (commanders.isEmpty()) { - return "is missing a commander"; - } - - if (commanders.size() > 2) { - return "too many commanders"; - } - + if (hasCommander()) { byte cmdCI = 0; - for (PaperCard pc : commanders) { - if (!isLegalCommander(pc.getRules())) { - return "has an illegal commander"; + if (equals(DeckFormat.Oathbreaker)) { // 1 Oathbreaker and 1 Signature Spell + PaperCard oathbreaker = deck.getOathbreaker(); + if (oathbreaker == null) { + return "is missing an oathbreaker"; } - cmdCI |= pc.getRules().getColorIdentity().getColor(); + if (deck.getSignatureSpell() == null) { + return "is missing a signature spell"; + } + if (deck.getCommanders().size() > 2) { + return "has too many commanders"; + } + cmdCI = oathbreaker.getRules().getColorIdentity().getColor(); } + else { // 1 Commander or 2 Partner Commanders + final List commanders = deck.getCommanders(); - // special check for Partner - if (commanders.size() == 2) { - // two commander = 98 cards - min--; - max--; + if (commanders.isEmpty()) { + return "is missing a commander"; + } - PaperCard a = commanders.get(0); - PaperCard b = commanders.get(1); + if (commanders.size() > 2) { + return "has too many commanders"; + } - if (a.getRules().hasKeyword("Partner") && b.getRules().hasKeyword("Partner")) { - // normal partner commander - } else if (a.getName().equals(b.getRules().getParterWith()) - && b.getName().equals(a.getRules().getParterWith())) { - // paired partner commander - } else { - return "has an illegal commander partnership"; + for (PaperCard pc : commanders) { + if (!isLegalCommander(pc.getRules())) { + return "has an illegal commander"; + } + cmdCI |= pc.getRules().getColorIdentity().getColor(); + } + + // special check for Partner + if (commanders.size() == 2) { + // two commander = 98 cards + min--; + max--; + + PaperCard a = commanders.get(0); + PaperCard b = commanders.get(1); + + if (a.getRules().hasKeyword("Partner") && b.getRules().hasKeyword("Partner")) { + // normal partner commander + } else if (a.getName().equals(b.getRules().getPartnerWith()) + && b.getName().equals(a.getRules().getPartnerWith())) { + // paired partner commander + } else { + return "has an illegal commander partnership"; + } } } @@ -443,7 +439,10 @@ public enum DeckFormat { if (cardPoolFilter != null && !cardPoolFilter.apply(rules)) { return false; } - if(this.equals(DeckFormat.Brawl)) { + if (this.equals(DeckFormat.Oathbreaker)) { + return rules.canBeOathbreaker(); + } + if (this.equals(DeckFormat.Brawl)) { return rules.canBeBrawlCommander(); } return rules.canBeCommander(); @@ -505,19 +504,17 @@ public enum DeckFormat { public Predicate isLegalCardForCommanderPredicate(List commanders) { byte cmdCI = 0; + boolean hasPartner = false; for (final PaperCard p : commanders) { cmdCI |= p.getRules().getColorIdentity().getColor(); + if (p.getRules().canBePartnerCommander()) { + hasPartner = true; + } } - return Predicates.compose(CardRulesPredicates.hasColorIdentity(cmdCI), PaperCard.FN_GET_RULES); - } - - public Predicate isLegalCardForCommanderOrLegalPartnerPredicate(List commanders) { - byte cmdCI = 0; - for (final PaperCard p : commanders) { - cmdCI |= p.getRules().getColorIdentity().getColor(); + Predicate predicate = CardRulesPredicates.hasColorIdentity(cmdCI); + if (hasPartner) { //also show available partners a commander can have a partner + predicate = Predicates.or(predicate, CardRulesPredicates.Presets.CAN_BE_PARTNER_COMMANDER); } - // TODO : check commander what kind of Partner it needs - return Predicates.compose(Predicates.or(CardRulesPredicates.hasColorIdentity(cmdCI), - CardRulesPredicates.Presets.CAN_BE_PARTNER_COMMANDER), PaperCard.FN_GET_RULES); + return Predicates.compose(predicate, PaperCard.FN_GET_RULES); } } diff --git a/forge-game/src/main/java/forge/game/GameFormat.java b/forge-game/src/main/java/forge/game/GameFormat.java index 27122eb2da9..2790a759a64 100644 --- a/forge-game/src/main/java/forge/game/GameFormat.java +++ b/forge-game/src/main/java/forge/game/GameFormat.java @@ -296,7 +296,7 @@ public class GameFormat implements Comparable { coreFormats.add("Commander.txt"); coreFormats.add("Extended.txt"); coreFormats.add("Brawl.txt"); - + coreFormats.add("Oathbreaker.txt"); } public Reader(File forgeFormats, File customFormats, boolean includeHistoric) { diff --git a/forge-game/src/main/java/forge/game/GameRules.java b/forge-game/src/main/java/forge/game/GameRules.java index 46ceb450cb5..6433002e5d8 100644 --- a/forge-game/src/main/java/forge/game/GameRules.java +++ b/forge-game/src/main/java/forge/game/GameRules.java @@ -88,6 +88,7 @@ public class GameRules { public boolean hasCommander() { return appliedVariants.contains(GameType.Commander) + || appliedVariants.contains(GameType.Oathbreaker) || appliedVariants.contains(GameType.TinyLeaders) || appliedVariants.contains(GameType.Brawl); } diff --git a/forge-game/src/main/java/forge/game/GameType.java b/forge-game/src/main/java/forge/game/GameType.java index 7b027a1161e..dc63a482d3f 100644 --- a/forge-game/src/main/java/forge/game/GameType.java +++ b/forge-game/src/main/java/forge/game/GameType.java @@ -24,6 +24,7 @@ public enum GameType { DeckManager (DeckFormat.Constructed, false, true, true, "lblDeckManager", ""), Vanguard (DeckFormat.Vanguard, true, true, true, "lblVanguard", "lblVanguardDesc"), Commander (DeckFormat.Commander, false, false, false, "lblCommander", "lblCommanderDesc"), + Oathbreaker (DeckFormat.Oathbreaker, false, false, false, "lblOathbreaker", "lblOathbreakerDesc"), TinyLeaders (DeckFormat.TinyLeaders, false, false, false, "lblTinyLeaders", "lblTinyLeadersDesc"), Brawl (DeckFormat.Brawl, false, false, false, "lblBrawl", "lblBrawlDesc"), Planeswalker (DeckFormat.PlanarConquest, false, false, true, "lblPlaneswalker", "lblPlaneswalkerDesc"), @@ -126,6 +127,7 @@ public enum GameType { /*switch (this) { case Archenemy: case Commander: + case Oathbreaker: case TinyLeaders: case Planechase: case Vanguard: diff --git a/forge-game/src/main/java/forge/game/card/CardView.java b/forge-game/src/main/java/forge/game/card/CardView.java index b7727f2caa6..5afd53b06ca 100644 --- a/forge-game/src/main/java/forge/game/card/CardView.java +++ b/forge-game/src/main/java/forge/game/card/CardView.java @@ -7,6 +7,7 @@ import forge.card.*; import forge.card.mana.ManaCost; import forge.game.Direction; import forge.game.GameEntityView; +import forge.game.GameType; import forge.game.combat.Combat; import forge.game.keyword.Keyword; import forge.game.player.Player; @@ -195,7 +196,29 @@ public class CardView extends GameEntityView { return get(TrackableProperty.IsCommander); } void updateCommander(Card c) { - set(TrackableProperty.IsCommander, c.isCommander()); + boolean isCommander = c.isCommander(); + set(TrackableProperty.IsCommander, isCommander); + if (c.getGame().getRules().hasAppliedVariant(GameType.Oathbreaker)) { + //store alternate type for oathbreaker or signature spell for display in card text + if (isCommander) { + if (c.getPaperCard().getRules().canBeSignatureSpell()) { + set(TrackableProperty.CommanderAltType, "Signature Spell"); + } + else { + set(TrackableProperty.CommanderAltType, "Oathbreaker"); + } + } + else { + set(TrackableProperty.CommanderAltType, null); + } + } + } + public String getCommanderType() { + String type = get(TrackableProperty.CommanderAltType); + if (type == null) { + type = "Commander"; + } + return type; } public Map getCounters() { @@ -542,7 +565,7 @@ public class CardView extends GameEntityView { sb.append(rulesText).append("\r\n\r\n"); } if (isCommander()) { - sb.append(getOwner()).append("'s Commander\r\n"); + sb.append(getOwner()).append("'s " + getCommanderType() + "\r\n"); sb.append(getOwner().getCommanderInfo(this)).append("\r\n"); } diff --git a/forge-game/src/main/java/forge/game/player/Player.java b/forge-game/src/main/java/forge/game/player/Player.java index 78b040024ba..2607b412d75 100644 --- a/forge-game/src/main/java/forge/game/player/Player.java +++ b/forge-game/src/main/java/forge/game/player/Player.java @@ -598,9 +598,11 @@ public class Player extends GameEntity implements Comparable { } } - //Tiny Leaders and Brawl ignore commander damage rule. - if (source.isCommander() && isCombat && this.getGame().getRules().getGameType() != GameType.TinyLeaders - && this.getGame().getRules().getGameType() != GameType.Brawl) { + //Oathbreaker, Tiny Leaders, and Brawl ignore commander damage rule + if (source.isCommander() && isCombat + && !this.getGame().getRules().hasAppliedVariant(GameType.Oathbreaker) + && !this.getGame().getRules().hasAppliedVariant(GameType.TinyLeaders) + && !this.getGame().getRules().hasAppliedVariant(GameType.Brawl)) { commanderDamage.put(source, getCommanderDamage(source) + amount); view.updateCommanderDamage(this); } @@ -2641,9 +2643,9 @@ public class Player extends GameEntity implements Comparable { public List getCommanders() { return commanders; } - public void setCommanders(List commander0) { - if (commander0 == commanders) { return; } - commanders = commander0; + public void setCommanders(List commanders0) { + if (commanders0 == commanders) { return; } + commanders = commanders0; view.updateCommander(this); } @@ -2767,15 +2769,30 @@ public class Player extends GameEntity implements Comparable { final String name = Lang.getPossesive(commander.getName()) + " Commander Effect"; DetachedCardEffect eff = new DetachedCardEffect(commander, name); - eff.setSVar("CommanderMoveReplacement", "DB$ ChangeZone | Origin$ Battlefield,Graveyard,Exile,Library,Hand | Destination$ Command | Defined$ ReplacedCard"); + if (game.getRules().hasAppliedVariant(GameType.Oathbreaker) && commander.getRules().canBeSignatureSpell()) { + //signature spells can only reside on the stack or in the command zone + eff.setSVar("SignatureSpellMoveReplacement", "DB$ ChangeZone | Origin$ Stack | Destination$ Command | Defined$ ReplacedCard"); - String moved = "Event$ Moved | ValidCard$ Card.EffectSource+YouOwn | Secondary$ True | Optional$ True | OptionalDecider$ You | ReplaceWith$ CommanderMoveReplacement "; - if (game.getRules().hasAppliedVariant(GameType.TinyLeaders)) { - moved += " | Destination$ Graveyard,Exile | Description$ If a commander would be put into its owner's graveyard or exile from anywhere, that player may put it into the command zone instead."; - } else { - moved += " | Destination$ Graveyard,Exile,Hand,Library | Description$ If a commander would be exiled or put into hand, graveyard, or library from anywhere, that player may put it into the command zone instead."; + String moved = "Event$ Moved | ValidCard$ Card.EffectSource+YouOwn | Secondary$ True | ReplaceWith$ SignatureSpellMoveReplacement | Destination$ Graveyard,Exile,Hand,Library | " + + "Description$ If a signature spell would be put into another zone from the stack, put it into the command zone instead."; + eff.addReplacementEffect(ReplacementHandler.parseReplacement(moved, eff, true)); + + //signature spells can only be cast if your oathbreaker is in on the battlefield under your control + String castRestriction = "Mode$ CantBeCast | ValidCard$ Card.EffectSource+YouOwn | EffectZone$ Command | IsPresent$ Card.IsCommander+YouOwn+YouCtrl | PresentZone$ Battlefield | PresentCompare$ EQ0 | " + + "Description$ Signature spell can only be cast if your oathbreaker is on the battlefield under your control."; + eff.addStaticAbility(castRestriction); + } + else { + eff.setSVar("CommanderMoveReplacement", "DB$ ChangeZone | Origin$ Battlefield,Graveyard,Exile,Library,Hand | Destination$ Command | Defined$ ReplacedCard"); + + String moved = "Event$ Moved | ValidCard$ Card.EffectSource+YouOwn | Secondary$ True | Optional$ True | OptionalDecider$ You | ReplaceWith$ CommanderMoveReplacement "; + if (game.getRules().hasAppliedVariant(GameType.TinyLeaders)) { + moved += " | Destination$ Graveyard,Exile | Description$ If a commander would be put into its owner's graveyard or exile from anywhere, that player may put it into the command zone instead."; + } else { + moved += " | Destination$ Graveyard,Exile,Hand,Library | Description$ If a commander would be exiled or put into hand, graveyard, or library from anywhere, that player may put it into the command zone instead."; + } + eff.addReplacementEffect(ReplacementHandler.parseReplacement(moved, eff, true)); } - eff.addReplacementEffect(ReplacementHandler.parseReplacement(moved, eff, true)); String mayBePlayedAbility = "Mode$ Continuous | EffectZone$ Command | MayPlay$ True | Affected$ Card.YouOwn+EffectSource | AffectedZone$ Command"; if (game.getRules().hasAppliedVariant(GameType.Planeswalker)) { //support paying for Planeswalker with any color mana diff --git a/forge-game/src/main/java/forge/game/player/RegisteredPlayer.java b/forge-game/src/main/java/forge/game/player/RegisteredPlayer.java index 3084424a6df..aedf99e5774 100644 --- a/forge-game/src/main/java/forge/game/player/RegisteredPlayer.java +++ b/forge-game/src/main/java/forge/game/player/RegisteredPlayer.java @@ -120,7 +120,10 @@ public class RegisteredPlayer { start.setStartingLife(start.getStartingLife() + 20); // 903.7: ...each player sets his or her life total to 40 // Modified for layering of variants to life +20 } - if (appliedVariants.contains(GameType.TinyLeaders)) { + if (appliedVariants.contains(GameType.Oathbreaker)) { + start.commanders = deck.getCommanders(); + } + if (appliedVariants.contains(GameType.TinyLeaders)) { start.commanders = deck.getCommanders(); start.setStartingLife(start.getStartingLife() + 5); } diff --git a/forge-game/src/main/java/forge/game/zone/Zone.java b/forge-game/src/main/java/forge/game/zone/Zone.java index 229efd04468..7800e400519 100644 --- a/forge-game/src/main/java/forge/game/zone/Zone.java +++ b/forge-game/src/main/java/forge/game/zone/Zone.java @@ -20,6 +20,7 @@ package forge.game.zone; import com.google.common.base.Predicate; import com.google.common.collect.Iterables; import forge.game.Game; +import forge.game.GameType; import forge.game.card.Card; import forge.game.card.CardCollection; import forge.game.card.CardCollectionView; @@ -80,7 +81,7 @@ public class Zone implements java.io.Serializable, Iterable { add(c, index, null); } - public void add(final Card c, final Integer index, final Card latestState) { + public void add(final Card c, Integer index, final Card latestState) { if (index != null && cardList.isEmpty() && index.intValue() > 0) { // something went wrong, most likely the method fired when the game was in an unexpected state // (e.g. conceding during the mana payment prompt) @@ -88,6 +89,15 @@ public class Zone implements java.io.Serializable, Iterable { return; } + //ensure commander returns to being first card in command zone + if (index == null && zoneType == ZoneType.Command && c.isCommander()) { + index = 0; + if (game.getRules().hasAppliedVariant(GameType.Oathbreaker) && c.getRules().canBeSignatureSpell() + && !cardList.isEmpty() && cardList.get(0).isCommander()) { + index = 1; //signature spell should return to being second card in command zone if oathbreaker is there too + } + } + // Immutable cards are usually emblems and effects if (!c.isImmutable()) { final Zone oldZone = game.getZoneOf(c); diff --git a/forge-game/src/main/java/forge/trackable/TrackableProperty.java b/forge-game/src/main/java/forge/trackable/TrackableProperty.java index e91068e2715..bae4622580e 100644 --- a/forge-game/src/main/java/forge/trackable/TrackableProperty.java +++ b/forge-game/src/main/java/forge/trackable/TrackableProperty.java @@ -37,6 +37,7 @@ public enum TrackableProperty { Tapped(TrackableTypes.BooleanType), Token(TrackableTypes.BooleanType), IsCommander(TrackableTypes.BooleanType), + CommanderAltType(TrackableTypes.StringType), Damage(TrackableTypes.IntegerType), AssignedDamage(TrackableTypes.IntegerType), ShieldCount(TrackableTypes.IntegerType), diff --git a/forge-gui-desktop/src/main/java/forge/deckchooser/FDeckChooser.java b/forge-gui-desktop/src/main/java/forge/deckchooser/FDeckChooser.java index 4050aed6580..3d218ce0fd8 100644 --- a/forge-gui-desktop/src/main/java/forge/deckchooser/FDeckChooser.java +++ b/forge-gui-desktop/src/main/java/forge/deckchooser/FDeckChooser.java @@ -136,14 +136,22 @@ public class FDeckChooser extends JPanel implements IDecksComboBoxListener { private void updateCustom() { DeckFormat deckFormat = lstDecks.getGameType().getDeckFormat(); - if(deckFormat.equals(DeckFormat.Commander)){ + switch (deckFormat) { + case Commander: updateDecks(DeckProxy.getAllCommanderDecks(), ItemManagerConfig.COMMANDER_DECKS); - }else if(deckFormat.equals(DeckFormat.TinyLeaders)){ - updateDecks(DeckProxy.getAllTinyLeadersDecks(), ItemManagerConfig.COMMANDER_DECKS); - }else if(deckFormat.equals(DeckFormat.Brawl)){ + break; + case Oathbreaker: + updateDecks(DeckProxy.getAllOathbreakerDecks(), ItemManagerConfig.COMMANDER_DECKS); + break; + case Brawl: updateDecks(DeckProxy.getAllBrawlDecks(), ItemManagerConfig.COMMANDER_DECKS); - }else { + break; + case TinyLeaders: + updateDecks(DeckProxy.getAllTinyLeadersDecks(), ItemManagerConfig.COMMANDER_DECKS); + break; + default: updateDecks(DeckProxy.getAllConstructedDecks(), ItemManagerConfig.CONSTRUCTED_DECKS); + break; } } @@ -184,14 +192,13 @@ public class FDeckChooser extends JPanel implements IDecksComboBoxListener { } private void updateRandomCommander() { - if((!lstDecks.getGameType().getDeckFormat().equals(DeckFormat.Commander))&& - !(lstDecks.getGameType().getDeckFormat().equals(DeckFormat.TinyLeaders))&& - !(lstDecks.getGameType().getDeckFormat().equals(DeckFormat.Brawl))){ + DeckFormat deckFormat = lstDecks.getGameType().getDeckFormat(); + if (!deckFormat.hasCommander()) { return; } - lstDecks.setAllowMultipleSelections(false); - lstDecks.setPool(CommanderDeckGenerator.getCommanderDecks(lstDecks.getGameType().getDeckFormat(), isAi, false)); + lstDecks.setAllowMultipleSelections(false); + lstDecks.setPool(CommanderDeckGenerator.getCommanderDecks(deckFormat, isAi, false)); lstDecks.setup(ItemManagerConfig.STRING_ONLY); btnRandom.setText("Random"); @@ -207,13 +214,13 @@ public class FDeckChooser extends JPanel implements IDecksComboBoxListener { } private void updateRandomCardGenCommander() { - if((!lstDecks.getGameType().getDeckFormat().equals(DeckFormat.Commander))&& - !(lstDecks.getGameType().getDeckFormat().equals(DeckFormat.TinyLeaders))&& - !(lstDecks.getGameType().getDeckFormat().equals(DeckFormat.Brawl))){ + DeckFormat deckFormat = lstDecks.getGameType().getDeckFormat(); + if (!deckFormat.hasCommander()) { return; } + lstDecks.setAllowMultipleSelections(false); - lstDecks.setPool(CommanderDeckGenerator.getCommanderDecks(lstDecks.getGameType().getDeckFormat(), isAi, true)); + lstDecks.setPool(CommanderDeckGenerator.getCommanderDecks(deckFormat, isAi, true)); lstDecks.setup(ItemManagerConfig.STRING_ONLY); btnRandom.setText("Random"); diff --git a/forge-gui-desktop/src/main/java/forge/gui/framework/EDocID.java b/forge-gui-desktop/src/main/java/forge/gui/framework/EDocID.java index 5bd1a176508..a80140ba441 100644 --- a/forge-gui-desktop/src/main/java/forge/gui/framework/EDocID.java +++ b/forge-gui-desktop/src/main/java/forge/gui/framework/EDocID.java @@ -14,6 +14,7 @@ import forge.screens.deckeditor.views.VDeckgen; import forge.screens.deckeditor.views.VProbabilities; import forge.screens.deckeditor.views.VStatistics; import forge.screens.deckeditor.views.VTinyLeadersDecks; +import forge.screens.deckeditor.views.VOathbreakerDecks; import forge.screens.home.gauntlet.VSubmenuGauntletBuild; import forge.screens.home.gauntlet.VSubmenuGauntletContests; import forge.screens.home.gauntlet.VSubmenuGauntletLoad; @@ -60,6 +61,7 @@ public enum EDocID { EDITOR_COMMANDER (VCommanderDecks.SINGLETON_INSTANCE), EDITOR_BRAWL (VBrawlDecks.SINGLETON_INSTANCE), EDITOR_TINY_LEADERS (VTinyLeadersDecks.SINGLETON_INSTANCE), + EDITOR_OATHBREAKER (VOathbreakerDecks.SINGLETON_INSTANCE), WORKSHOP_CATALOG (VWorkshopCatalog.SINGLETON_INSTANCE), WORKSHOP_CARDDESIGNER (VCardDesigner.SINGLETON_INSTANCE), diff --git a/forge-gui-desktop/src/main/java/forge/gui/framework/FScreen.java b/forge-gui-desktop/src/main/java/forge/gui/framework/FScreen.java index 487d8837261..04c6e7f225c 100644 --- a/forge-gui-desktop/src/main/java/forge/gui/framework/FScreen.java +++ b/forge-gui-desktop/src/main/java/forge/gui/framework/FScreen.java @@ -88,6 +88,15 @@ public class FScreen { "Close Editor", ForgeConstants.EDITOR_LAYOUT_FILE, false); + public static final FScreen DECK_EDITOR_OATHBREAKER = new FScreen( + VDeckEditorUI.SINGLETON_INSTANCE, + CDeckEditorUI.SINGLETON_INSTANCE, + "Oathbreaker Deck Editor", + FSkin.getImage(FSkinProp.IMG_PACK), + true, + "Close Editor", + ForgeConstants.EDITOR_LAYOUT_FILE, + false); public static final FScreen DECK_EDITOR_PLANECHASE = new FScreen( VDeckEditorUI.SINGLETON_INSTANCE, CDeckEditorUI.SINGLETON_INSTANCE, diff --git a/forge-gui-desktop/src/main/java/forge/itemmanager/DeckManager.java b/forge-gui-desktop/src/main/java/forge/itemmanager/DeckManager.java index 9284329e600..b5d1755ebc0 100644 --- a/forge-gui-desktop/src/main/java/forge/itemmanager/DeckManager.java +++ b/forge-gui-desktop/src/main/java/forge/itemmanager/DeckManager.java @@ -338,6 +338,11 @@ public final class DeckManager extends ItemManager implements IHasGam DeckPreferences.setCommanderDeck((deck != null) ? deck.toString() : ""); editorCtrl = new CEditorConstructed(getCDetailPicture(), this.gameType); break; + case Oathbreaker: + screen = FScreen.DECK_EDITOR_CONSTRUCTED; // re-use "Deck Editor", rather than creating a new top level tab + DeckPreferences.setCommanderDeck((deck != null) ? deck.toString() : ""); + editorCtrl = new CEditorConstructed(getCDetailPicture(), this.gameType); + break; case Brawl: screen = FScreen.DECK_EDITOR_CONSTRUCTED; // re-use "Deck Editor", rather than creating a new top level tab DeckPreferences.setBrawlDeck((deck != null) ? deck.toString() : ""); @@ -397,6 +402,7 @@ public final class DeckManager extends ItemManager implements IHasGam switch(this.gameType) { case Brawl: case Commander: + case Oathbreaker: case TinyLeaders: case Constructed: case Draft: diff --git a/forge-gui-desktop/src/main/java/forge/screens/deckeditor/CDeckEditorUI.java b/forge-gui-desktop/src/main/java/forge/screens/deckeditor/CDeckEditorUI.java index 674b9c9f191..3fd7cf4f62b 100644 --- a/forge-gui-desktop/src/main/java/forge/screens/deckeditor/CDeckEditorUI.java +++ b/forge-gui-desktop/src/main/java/forge/screens/deckeditor/CDeckEditorUI.java @@ -42,6 +42,7 @@ import forge.screens.deckeditor.views.VBrawlDecks; import forge.screens.deckeditor.views.VCardCatalog; import forge.screens.deckeditor.views.VCommanderDecks; import forge.screens.deckeditor.views.VCurrentDeck; +import forge.screens.deckeditor.views.VOathbreakerDecks; import forge.screens.deckeditor.views.VTinyLeadersDecks; import forge.screens.match.controllers.CDetailPicture; import forge.util.ItemPool; @@ -63,6 +64,7 @@ public enum CDeckEditorUI implements ICDoc { private final CDetailPicture cDetailPicture; private final VAllDecks vAllDecks; private final VCommanderDecks vCommanderDecks; + private final VOathbreakerDecks vOathbreakerDecks; private final VBrawlDecks vBrawlDecks; private final VTinyLeadersDecks vTinyLeadersDecks; @@ -73,6 +75,8 @@ public enum CDeckEditorUI implements ICDoc { this.vAllDecks.setCDetailPicture(cDetailPicture); this.vCommanderDecks = VCommanderDecks.SINGLETON_INSTANCE; this.vCommanderDecks.setCDetailPicture(cDetailPicture); + this.vOathbreakerDecks = VOathbreakerDecks.SINGLETON_INSTANCE; + this.vOathbreakerDecks.setCDetailPicture(cDetailPicture); this.vBrawlDecks = VBrawlDecks.SINGLETON_INSTANCE; this.vBrawlDecks.setCDetailPicture(cDetailPicture); this.vTinyLeadersDecks = VTinyLeadersDecks.SINGLETON_INSTANCE; diff --git a/forge-gui-desktop/src/main/java/forge/screens/deckeditor/controllers/ACEditorBase.java b/forge-gui-desktop/src/main/java/forge/screens/deckeditor/controllers/ACEditorBase.java index 76fdaf507d4..4fc4420725a 100644 --- a/forge-gui-desktop/src/main/java/forge/screens/deckeditor/controllers/ACEditorBase.java +++ b/forge-gui-desktop/src/main/java/forge/screens/deckeditor/controllers/ACEditorBase.java @@ -22,6 +22,7 @@ import com.google.common.collect.Iterables; import forge.UiCommand; import forge.assets.FSkinProp; import forge.deck.*; +import forge.game.GameType; import forge.gui.GuiChoose; import forge.gui.GuiUtils; import forge.gui.framework.*; @@ -76,6 +77,7 @@ public abstract class ACEditorBase deckManager; protected DeckSection sectionMode = DeckSection.Main; private final CDetailPicture cDetailPicture; + protected final GameType gameType; // card transfer buttons final Localizer localizer = Localizer.getInstance(); @@ -114,9 +116,10 @@ public abstract class ACEditorBase
(C at beginning of class name denotes a control class.) * diff --git a/forge-gui-desktop/src/main/java/forge/screens/deckeditor/controllers/CDeckEditor.java b/forge-gui-desktop/src/main/java/forge/screens/deckeditor/controllers/CDeckEditor.java index 60cc606fb33..ad290237eff 100644 --- a/forge-gui-desktop/src/main/java/forge/screens/deckeditor/controllers/CDeckEditor.java +++ b/forge-gui-desktop/src/main/java/forge/screens/deckeditor/controllers/CDeckEditor.java @@ -1,6 +1,7 @@ package forge.screens.deckeditor.controllers; import forge.deck.*; +import forge.game.GameType; import forge.gui.framework.FScreen; import forge.item.PaperCard; import forge.screens.match.controllers.CDetailPicture; @@ -8,9 +9,8 @@ import forge.screens.match.controllers.CDetailPicture; import java.util.*; public abstract class CDeckEditor extends ACEditorBase { - - protected CDeckEditor(FScreen screen0, CDetailPicture cDetailPicture) { - super(screen0, cDetailPicture); + protected CDeckEditor(FScreen screen0, CDetailPicture cDetailPicture0, GameType gameType0) { + super(screen0, cDetailPicture0, gameType0); } /** diff --git a/forge-gui-desktop/src/main/java/forge/screens/deckeditor/controllers/CEditorCommander.java b/forge-gui-desktop/src/main/java/forge/screens/deckeditor/controllers/CEditorCommander.java index 63d1b81b477..1271ca3925c 100644 --- a/forge-gui-desktop/src/main/java/forge/screens/deckeditor/controllers/CEditorCommander.java +++ b/forge-gui-desktop/src/main/java/forge/screens/deckeditor/controllers/CEditorCommander.java @@ -21,15 +21,19 @@ import com.google.common.base.Predicate; import com.google.common.base.Predicates; import com.google.common.base.Supplier; import forge.UiCommand; +import forge.card.CardDb; import forge.card.CardRules; import forge.card.CardRulesPredicates; import forge.deck.Deck; import forge.deck.DeckSection; +import forge.game.GameFormat; +import forge.game.GameType; import forge.gui.framework.DragCell; import forge.gui.framework.FScreen; import forge.item.PaperCard; import forge.itemmanager.CardManager; import forge.itemmanager.ItemManagerConfig; +import forge.model.CardCollections; import forge.model.FModel; import forge.screens.deckeditor.SEditorIO; import forge.screens.deckeditor.views.VAllDecks; @@ -70,26 +74,27 @@ public final class CEditorCommander extends CDeckEditor { * all cards are available. */ @SuppressWarnings("serial") - public CEditorCommander(final CDetailPicture cDetailPicture, boolean tinyLeaders, boolean brawl) { - super(tinyLeaders ? FScreen.DECK_EDITOR_TINY_LEADERS : brawl ? FScreen.DECK_EDITOR_BRAWL : FScreen.DECK_EDITOR_COMMANDER, cDetailPicture); + public CEditorCommander(final CDetailPicture cDetailPicture, GameType gameType0) { + super(gameType0 == GameType.TinyLeaders ? FScreen.DECK_EDITOR_TINY_LEADERS : gameType0 == GameType.Brawl ? FScreen.DECK_EDITOR_BRAWL : + gameType0 == GameType.Oathbreaker ? FScreen.DECK_EDITOR_OATHBREAKER : FScreen.DECK_EDITOR_COMMANDER, cDetailPicture, gameType0); allSections.add(DeckSection.Main); allSections.add(DeckSection.Sideboard); allSections.add(DeckSection.Commander); - if(brawl){ + CardDb commonCards = FModel.getMagicDb().getCommonCards(); + if (gameType == GameType.Brawl){ + GameFormat format = FModel.getFormats().get("Brawl"); Predicate commanderFilter = CardRulesPredicates.Presets.CAN_BE_BRAWL_COMMANDER; - commanderPool = ItemPool.createFrom(FModel.getMagicDb().getCommonCards().getAllCards(Predicates.and( - FModel.getFormats().get("Brawl").getFilterPrinted(),Predicates.compose(commanderFilter, PaperCard.FN_GET_RULES))),PaperCard.class); - }else{ - Predicate commanderFilter = CardRulesPredicates.Presets.CAN_BE_COMMANDER ; - commanderPool = ItemPool.createFrom(FModel.getMagicDb().getCommonCards().getAllCards(Predicates.compose(commanderFilter, PaperCard.FN_GET_RULES)),PaperCard.class); + commanderPool = ItemPool.createFrom(commonCards.getAllCards(Predicates.and( + format.getFilterPrinted(), Predicates.compose(commanderFilter, PaperCard.FN_GET_RULES))), PaperCard.class); + normalPool = ItemPool.createFrom(format.getAllCards(), PaperCard.class); } - - - if(brawl){ - normalPool = ItemPool.createFrom(FModel.getFormats().get("Brawl").getAllCards(), PaperCard.class); - }else { - normalPool = ItemPool.createFrom(FModel.getMagicDb().getCommonCards().getAllCards(), PaperCard.class); + else { + Predicate commanderFilter = gameType == GameType.Oathbreaker + ? Predicates.or(CardRulesPredicates.Presets.CAN_BE_OATHBREAKER, CardRulesPredicates.Presets.CAN_BE_SIGNATURE_SPELL) + : CardRulesPredicates.Presets.CAN_BE_COMMANDER; + commanderPool = ItemPool.createFrom(commonCards.getAllCards(Predicates.compose(commanderFilter, PaperCard.FN_GET_RULES)),PaperCard.class); + normalPool = ItemPool.createFrom(commonCards.getAllCards(), PaperCard.class); } CardManager catalogManager = new CardManager(getCDetailPicture(), true, false); @@ -106,7 +111,21 @@ public final class CEditorCommander extends CDeckEditor { return new Deck(); } }; - this.controller = new DeckController(tinyLeaders ? FModel.getDecks().getTinyLeaders() :brawl ? FModel.getDecks().getBrawl(): FModel.getDecks().getCommander(), this, newCreator); + CardCollections decks = FModel.getDecks(); + switch (gameType) { + case TinyLeaders: + this.controller = new DeckController(decks.getTinyLeaders(), this, newCreator); + break; + case Brawl: + this.controller = new DeckController(decks.getBrawl(), this, newCreator); + break; + case Oathbreaker: + this.controller = new DeckController(decks.getOathbreaker(), this, newCreator); + break; + default: + this.controller = new DeckController(decks.getCommander(), this, newCreator); + break; + } getBtnAddBasicLands().setCommand(new UiCommand() { @Override @@ -144,7 +163,7 @@ public final class CEditorCommander extends CDeckEditor { */ @Override protected void buildAddContextMenu(EditorContextMenuBuilder cmb) { - CEditorConstructed.buildAddContextMenu(cmb, sectionMode); + CEditorConstructed.buildAddContextMenu(cmb, sectionMode, gameType); } /* (non-Javadoc) diff --git a/forge-gui-desktop/src/main/java/forge/screens/deckeditor/controllers/CEditorConstructed.java b/forge-gui-desktop/src/main/java/forge/screens/deckeditor/controllers/CEditorConstructed.java index b1f1faa55df..1acfb3064d5 100644 --- a/forge-gui-desktop/src/main/java/forge/screens/deckeditor/controllers/CEditorConstructed.java +++ b/forge-gui-desktop/src/main/java/forge/screens/deckeditor/controllers/CEditorConstructed.java @@ -61,8 +61,6 @@ public final class CEditorConstructed extends CDeckEditor { private final List allSections = new ArrayList(); private ItemPool normalPool, avatarPool, planePool, schemePool, conspiracyPool, commanderPool; - private final GameType gameType; - Predicate commanderFilter; CardManager catalogManager; @@ -75,13 +73,12 @@ public final class CEditorConstructed extends CDeckEditor { * all cards are available. */ @SuppressWarnings("serial") - public CEditorConstructed(final CDetailPicture cDetailPicture) { - this(cDetailPicture, GameType.Constructed); + public CEditorConstructed(final CDetailPicture cDetailPicture0) { + this(cDetailPicture0, GameType.Constructed); } - public CEditorConstructed(final CDetailPicture cDetailPicture, final GameType gameType) { - super(FScreen.DECK_EDITOR_CONSTRUCTED, cDetailPicture); - this.gameType = gameType; + public CEditorConstructed(final CDetailPicture cDetailPicture0, final GameType gameType0) { + super(FScreen.DECK_EDITOR_CONSTRUCTED, cDetailPicture0, gameType0); boolean wantUnique = false; @@ -110,6 +107,15 @@ public final class CEditorConstructed extends CDeckEditor { commanderPool = ItemPool.createFrom(FModel.getMagicDb().getCommonCards().getAllCards(Predicates.compose(commanderFilter, PaperCard.FN_GET_RULES)), PaperCard.class); normalPool = ItemPool.createFrom(FModel.getMagicDb().getCommonCards().getAllCards(), PaperCard.class); + wantUnique = true; + break; + case Oathbreaker: + allSections.add(DeckSection.Commander); + + commanderFilter = Predicates.or(CardRulesPredicates.Presets.CAN_BE_OATHBREAKER, CardRulesPredicates.Presets.CAN_BE_SIGNATURE_SPELL); + commanderPool = ItemPool.createFrom(FModel.getMagicDb().getCommonCards().getAllCards(Predicates.compose(commanderFilter, PaperCard.FN_GET_RULES)), PaperCard.class); + normalPool = ItemPool.createFrom(FModel.getMagicDb().getCommonCards().getAllCards(), PaperCard.class); + wantUnique = true; break; case Brawl: @@ -148,6 +154,9 @@ public final class CEditorConstructed extends CDeckEditor { case Commander: this.controller = new DeckController(FModel.getDecks().getCommander(), this, newCreator); break; + case Oathbreaker: + this.controller = new DeckController(FModel.getDecks().getOathbreaker(), this, newCreator); + break; case Brawl: this.controller = new DeckController(FModel.getDecks().getBrawl(), this, newCreator); break; @@ -176,6 +185,7 @@ public final class CEditorConstructed extends CDeckEditor { case Constructed: return CardLimit.Default; case Commander: + case Oathbreaker: case TinyLeaders: case Brawl: return CardLimit.Singleton; @@ -188,8 +198,37 @@ public final class CEditorConstructed extends CDeckEditor { DeckSection sectionMode = editor.sectionMode; DeckController controller = editor.getDeckController(); - if (sectionMode == DeckSection.Commander || sectionMode == DeckSection.Avatar) { + switch (sectionMode) { + case Commander: + int count = editor.getDeckManager().getItemCount(); + if (count > 0) { + PaperCard newCard = items.iterator().next().getKey(); //can only add one card at a time when on commander section + if (editor.gameType == GameType.Oathbreaker) { //replace oathbreaker or signature spell if needed + for (Entry entry : editor.getDeckManager().getPool()) { + if (entry.getKey().getRules().canBeOathbreaker() == newCard.getRules().canBeOathbreaker()) { + editor.getDeckManager().removeItem(entry.getKey(), entry.getValue()); + break; + } + } + } + else { //replace existing commander unless new commander is valid partner commander + if (count == 1 && newCard.getRules().canBePartnerCommander()) { //replace existing partners regardless + PaperCard commander = editor.getDeckManager().getPool().toFlatList().get(0); + if (!commander.getRules().canBePartnerCommander()) { + editor.getDeckManager().removeAllItems(); + } + } + else { + editor.getDeckManager().removeAllItems(); + } + } + } + break; + case Avatar: editor.getDeckManager().removeAllItems(); + break; + default: + break; } ItemPool itemsToAdd = editor.getAllowedAdditions(items); @@ -260,7 +299,7 @@ public final class CEditorConstructed extends CDeckEditor { onRemoveItems(this, items, toAlternate); } - public static void buildAddContextMenu(EditorContextMenuBuilder cmb, DeckSection sectionMode) { + public static void buildAddContextMenu(EditorContextMenuBuilder cmb, DeckSection sectionMode, GameType gameType) { final Localizer localizer = Localizer.getInstance(); switch (sectionMode) { case Main: @@ -271,7 +310,18 @@ public final class CEditorConstructed extends CDeckEditor { cmb.addMoveItems(localizer.getMessage("lblAdd"), localizer.getMessage("lbltosideboard")); break; case Commander: - cmb.addMoveItems(localizer.getMessage("lblSet2"), localizer.getMessage("lblascommander")); + if (gameType == GameType.Oathbreaker) { + PaperCard pc = cmb.getItemManager().getSelectedItem(); + if (pc != null && pc.getRules().canBeSignatureSpell()) { + cmb.addMoveItems(localizer.getMessage("lblSet2"), localizer.getMessage("lblassignaturespell")); + } + else { + cmb.addMoveItems(localizer.getMessage("lblSet2"), localizer.getMessage("lblasoathbreaker")); + } + } + else { + cmb.addMoveItems(localizer.getMessage("lblSet2"), localizer.getMessage("lblascommander")); + } break; case Avatar: cmb.addMoveItems(localizer.getMessage("lblSet2"), localizer.getMessage("lblasavatar")); @@ -325,7 +375,7 @@ public final class CEditorConstructed extends CDeckEditor { */ @Override protected void buildAddContextMenu(EditorContextMenuBuilder cmb) { - buildAddContextMenu(cmb, sectionMode); + buildAddContextMenu(cmb, sectionMode, gameType); } /* (non-Javadoc) @@ -377,26 +427,31 @@ public final class CEditorConstructed extends CDeckEditor { case Main: this.getCatalogManager().setup(ItemManagerConfig.CARD_CATALOG); this.getCatalogManager().setPool(normalPool, true); + this.getCatalogManager().setAllowMultipleSelections(true); this.getDeckManager().setPool(this.controller.getModel().getMain()); break; case Sideboard: this.getCatalogManager().setup(ItemManagerConfig.CARD_CATALOG); this.getCatalogManager().setPool(normalPool, true); + this.getCatalogManager().setAllowMultipleSelections(true); this.getDeckManager().setPool(this.controller.getModel().getOrCreate(DeckSection.Sideboard)); break; case Avatar: this.getCatalogManager().setup(ItemManagerConfig.AVATAR_POOL); this.getCatalogManager().setPool(avatarPool, true); + this.getCatalogManager().setAllowMultipleSelections(false); this.getDeckManager().setPool(this.controller.getModel().getOrCreate(DeckSection.Avatar)); break; case Planes: this.getCatalogManager().setup(ItemManagerConfig.PLANAR_POOL); this.getCatalogManager().setPool(planePool, true); + this.getCatalogManager().setAllowMultipleSelections(true); this.getDeckManager().setPool(this.controller.getModel().getOrCreate(DeckSection.Planes)); break; case Schemes: this.getCatalogManager().setup(ItemManagerConfig.SCHEME_POOL); this.getCatalogManager().setPool(schemePool, true); + this.getCatalogManager().setAllowMultipleSelections(true); this.getDeckManager().setPool(this.controller.getModel().getOrCreate(DeckSection.Schemes)); break; case Commander: @@ -404,25 +459,30 @@ public final class CEditorConstructed extends CDeckEditor { case Conspiracy: this.getCatalogManager().setup(ItemManagerConfig.CONSPIRACY_DECKS); this.getCatalogManager().setPool(conspiracyPool, true); + this.getCatalogManager().setAllowMultipleSelections(true); this.getDeckManager().setPool(this.controller.getModel().getOrCreate(DeckSection.Conspiracy)); } case Commander: + case Oathbreaker: case TinyLeaders: case Brawl: switch(sectionMode) { case Main: this.getCatalogManager().setup(ItemManagerConfig.CARD_CATALOG); this.getCatalogManager().setPool(normalPool, true); + this.getCatalogManager().setAllowMultipleSelections(true); this.getDeckManager().setPool(this.controller.getModel().getMain()); break; case Sideboard: this.getCatalogManager().setup(ItemManagerConfig.CARD_CATALOG); this.getCatalogManager().setPool(normalPool, true); + this.getCatalogManager().setAllowMultipleSelections(true); this.getDeckManager().setPool(this.controller.getModel().getOrCreate(DeckSection.Sideboard)); break; case Commander: this.getCatalogManager().setup(ItemManagerConfig.COMMANDER_POOL); this.getCatalogManager().setPool(commanderPool, true); + this.getCatalogManager().setAllowMultipleSelections(false); this.getDeckManager().setPool(this.controller.getModel().getOrCreate(DeckSection.Commander)); break; default: diff --git a/forge-gui-desktop/src/main/java/forge/screens/deckeditor/controllers/CEditorDraftingProcess.java b/forge-gui-desktop/src/main/java/forge/screens/deckeditor/controllers/CEditorDraftingProcess.java index a86a76904fb..56f02b0d925 100644 --- a/forge-gui-desktop/src/main/java/forge/screens/deckeditor/controllers/CEditorDraftingProcess.java +++ b/forge-gui-desktop/src/main/java/forge/screens/deckeditor/controllers/CEditorDraftingProcess.java @@ -21,6 +21,7 @@ import forge.Singletons; import forge.deck.Deck; import forge.deck.DeckGroup; import forge.deck.DeckSection; +import forge.game.GameType; import forge.gui.framework.DragCell; import forge.gui.framework.FScreen; import forge.item.PaperCard; @@ -30,12 +31,7 @@ import forge.limited.BoosterDraft; import forge.limited.IBoosterDraft; import forge.model.FModel; import forge.screens.deckeditor.CDeckEditorUI; -import forge.screens.deckeditor.views.VAllDecks; -import forge.screens.deckeditor.views.VBrawlDecks; -import forge.screens.deckeditor.views.VCommanderDecks; -import forge.screens.deckeditor.views.VCurrentDeck; -import forge.screens.deckeditor.views.VDeckgen; -import forge.screens.deckeditor.views.VTinyLeadersDecks; +import forge.screens.deckeditor.views.*; import forge.screens.home.sanctioned.CSubmenuDraft; import forge.screens.match.controllers.CDetailPicture; import forge.toolbox.FOptionPane; @@ -58,6 +54,7 @@ public class CEditorDraftingProcess extends ACEditorBase { private String ccAddLabel = "Add card"; private DragCell constructedDecksParent = null; private DragCell commanderDecksParent = null; + private DragCell oathbreakerDecksParent = null; private DragCell brawlDecksParent = null; private DragCell tinyLeadersDecksParent = null; private DragCell deckGenParent = null; @@ -68,11 +65,11 @@ public class CEditorDraftingProcess extends ACEditorBase { /** * Updates the deck editor UI as necessary draft selection mode. */ - public CEditorDraftingProcess(final CDetailPicture cDetailPicture) { - super(FScreen.DRAFTING_PROCESS, cDetailPicture); + public CEditorDraftingProcess(final CDetailPicture cDetailPicture0) { + super(FScreen.DRAFTING_PROCESS, cDetailPicture0, GameType.Draft); - final CardManager catalogManager = new CardManager(getCDetailPicture(), false, false); - final CardManager deckManager = new CardManager(getCDetailPicture(), false, false); + final CardManager catalogManager = new CardManager(cDetailPicture0, false, false); + final CardManager deckManager = new CardManager(cDetailPicture0, false, false); //hide filters and options panel so more of pack is visible by default catalogManager.setHideViewOptions(1, true); @@ -285,6 +282,7 @@ public class CEditorDraftingProcess extends ACEditorBase { deckGenParent = removeTab(VDeckgen.SINGLETON_INSTANCE); constructedDecksParent = removeTab(VAllDecks.SINGLETON_INSTANCE); commanderDecksParent = removeTab(VCommanderDecks.SINGLETON_INSTANCE); + oathbreakerDecksParent = removeTab(VOathbreakerDecks.SINGLETON_INSTANCE); brawlDecksParent = removeTab(VBrawlDecks.SINGLETON_INSTANCE); tinyLeadersDecksParent = removeTab(VTinyLeadersDecks.SINGLETON_INSTANCE); @@ -334,6 +332,9 @@ public class CEditorDraftingProcess extends ACEditorBase { if (commanderDecksParent != null) { commanderDecksParent.addDoc(VCommanderDecks.SINGLETON_INSTANCE); } + if (oathbreakerDecksParent != null) { + oathbreakerDecksParent.addDoc(VOathbreakerDecks.SINGLETON_INSTANCE); + } if (brawlDecksParent!= null) { brawlDecksParent.addDoc(VBrawlDecks.SINGLETON_INSTANCE); } diff --git a/forge-gui-desktop/src/main/java/forge/screens/deckeditor/controllers/CEditorLimited.java b/forge-gui-desktop/src/main/java/forge/screens/deckeditor/controllers/CEditorLimited.java index 93288c4cb16..e2c6b928827 100644 --- a/forge-gui-desktop/src/main/java/forge/screens/deckeditor/controllers/CEditorLimited.java +++ b/forge-gui-desktop/src/main/java/forge/screens/deckeditor/controllers/CEditorLimited.java @@ -24,6 +24,7 @@ import forge.deck.CardPool; import forge.deck.Deck; import forge.deck.DeckGroup; import forge.deck.DeckSection; +import forge.game.GameType; import forge.gui.framework.DragCell; import forge.gui.framework.FScreen; import forge.item.PaperCard; @@ -32,12 +33,7 @@ import forge.itemmanager.ItemManagerConfig; import forge.model.FModel; import forge.screens.deckeditor.AddBasicLandsDialog; import forge.screens.deckeditor.SEditorIO; -import forge.screens.deckeditor.views.VAllDecks; -import forge.screens.deckeditor.views.VBrawlDecks; -import forge.screens.deckeditor.views.VCommanderDecks; -import forge.screens.deckeditor.views.VCurrentDeck; -import forge.screens.deckeditor.views.VDeckgen; -import forge.screens.deckeditor.views.VTinyLeadersDecks; +import forge.screens.deckeditor.views.*; import forge.screens.home.sanctioned.CSubmenuDraft; import forge.screens.home.sanctioned.CSubmenuSealed; import forge.screens.match.controllers.CDetailPicture; @@ -62,6 +58,7 @@ public final class CEditorLimited extends CDeckEditor { private final DeckController controller; private DragCell constructedDecksParent = null; private DragCell commanderDecksParent = null; + private DragCell oathbreakerDecksParent = null; private DragCell brawlDecksParent = null; private DragCell tinyLeadersDecksParent = null; private DragCell deckGenParent = null; @@ -75,11 +72,11 @@ public final class CEditorLimited extends CDeckEditor { * @param deckMap0   {@link forge.deck.DeckGroup}<{@link forge.util.storage.IStorage}> */ @SuppressWarnings("serial") - public CEditorLimited(final IStorage deckMap0, final FScreen screen0, final CDetailPicture cDetailPicture) { - super(screen0, cDetailPicture); + public CEditorLimited(final IStorage deckMap0, final FScreen screen0, final CDetailPicture cDetailPicture0) { + super(screen0, cDetailPicture0, GameType.Sealed); - final CardManager catalogManager = new CardManager(getCDetailPicture(), false, false); - final CardManager deckManager = new CardManager(getCDetailPicture(), false, false); + final CardManager catalogManager = new CardManager(cDetailPicture0, false, false); + final CardManager deckManager = new CardManager(cDetailPicture0, false, false); catalogManager.setCaption("Sideboard"); @@ -208,7 +205,6 @@ public final class CEditorLimited extends CDeckEditor { } } - public void setEditorMode(DeckSection sectionMode) { switch(sectionMode) { case Conspiracy: @@ -244,6 +240,7 @@ public final class CEditorLimited extends CDeckEditor { deckGenParent = removeTab(VDeckgen.SINGLETON_INSTANCE); constructedDecksParent = removeTab(VAllDecks.SINGLETON_INSTANCE); commanderDecksParent = removeTab(VCommanderDecks.SINGLETON_INSTANCE); + oathbreakerDecksParent = removeTab(VOathbreakerDecks.SINGLETON_INSTANCE); brawlDecksParent = removeTab(VBrawlDecks.SINGLETON_INSTANCE); tinyLeadersDecksParent = removeTab(VTinyLeadersDecks.SINGLETON_INSTANCE); } @@ -274,6 +271,9 @@ public final class CEditorLimited extends CDeckEditor { if (commanderDecksParent != null) { commanderDecksParent.addDoc(VCommanderDecks.SINGLETON_INSTANCE); } + if (oathbreakerDecksParent != null) { + oathbreakerDecksParent.addDoc(VOathbreakerDecks.SINGLETON_INSTANCE); + } if (brawlDecksParent!= null) { brawlDecksParent.addDoc(VBrawlDecks.SINGLETON_INSTANCE); } diff --git a/forge-gui-desktop/src/main/java/forge/screens/deckeditor/controllers/CEditorQuest.java b/forge-gui-desktop/src/main/java/forge/screens/deckeditor/controllers/CEditorQuest.java index 1d4bc47c248..4bafc436d96 100644 --- a/forge-gui-desktop/src/main/java/forge/screens/deckeditor/controllers/CEditorQuest.java +++ b/forge-gui-desktop/src/main/java/forge/screens/deckeditor/controllers/CEditorQuest.java @@ -29,6 +29,7 @@ import forge.card.mana.ManaCost; import forge.deck.CardPool; import forge.deck.Deck; import forge.deck.DeckSection; +import forge.game.GameType; import forge.gui.GuiUtils; import forge.gui.framework.DragCell; import forge.gui.framework.FScreen; @@ -104,8 +105,8 @@ public final class CEditorQuest extends CDeckEditor { * @param questData0   {@link forge.quest.QuestController} */ @SuppressWarnings("serial") - public CEditorQuest(final QuestController questData0, final CDetailPicture cDetailPicture) { - super(FScreen.DECK_EDITOR_QUEST, cDetailPicture); + public CEditorQuest(final QuestController questData0, final CDetailPicture cDetailPicture0) { + super(FScreen.DECK_EDITOR_QUEST, cDetailPicture0, GameType.Quest); allSections.add(DeckSection.Main); allSections.add(DeckSection.Sideboard); @@ -120,8 +121,8 @@ public final class CEditorQuest extends CDeckEditor { this.questData = questData0; - final CardManager catalogManager = new CardManager(cDetailPicture, false, true); - final CardManager deckManager = new CardManager(cDetailPicture, false, true); + final CardManager catalogManager = new CardManager(cDetailPicture0, false, true); + final CardManager deckManager = new CardManager(cDetailPicture0, false, true); catalogManager.setCaption("Quest Inventory"); @@ -203,7 +204,7 @@ public final class CEditorQuest extends CDeckEditor { */ @Override protected void buildAddContextMenu(final EditorContextMenuBuilder cmb) { - CEditorConstructed.buildAddContextMenu(cmb, sectionMode); + CEditorConstructed.buildAddContextMenu(cmb, sectionMode, GameType.Quest); AddRatingItem(cmb, 1); AddRatingItem(cmb, 2); AddRatingItem(cmb, 3); diff --git a/forge-gui-desktop/src/main/java/forge/screens/deckeditor/controllers/CEditorQuestCardShop.java b/forge-gui-desktop/src/main/java/forge/screens/deckeditor/controllers/CEditorQuestCardShop.java index 2589ab879fb..c9f8f5c0fb2 100644 --- a/forge-gui-desktop/src/main/java/forge/screens/deckeditor/controllers/CEditorQuestCardShop.java +++ b/forge-gui-desktop/src/main/java/forge/screens/deckeditor/controllers/CEditorQuestCardShop.java @@ -20,6 +20,7 @@ package forge.screens.deckeditor.controllers; import forge.UiCommand; import forge.assets.FSkinProp; import forge.deck.DeckBase; +import forge.game.GameType; import forge.gui.framework.DragCell; import forge.gui.framework.FScreen; import forge.item.*; @@ -96,13 +97,13 @@ public final class CEditorQuestCardShop extends ACEditorBase { * @param questData0   {@link forge.quest.QuestController} */ @SuppressWarnings("serial") - public CEditorQuestLimited(final QuestController questData0, final CDetailPicture cDetailPicture) { - super(FScreen.DECK_EDITOR_QUEST_TOURNAMENT, cDetailPicture); + public CEditorQuestLimited(final QuestController questData0, final CDetailPicture cDetailPicture0) { + super(FScreen.DECK_EDITOR_QUEST_TOURNAMENT, cDetailPicture0, GameType.QuestDraft); allSections.add(DeckSection.Main); allSections.add(DeckSection.Sideboard); this.questData = questData0; - final CardManager catalogManager = new CardManager(cDetailPicture, false, true); - final CardManager deckManager = new CardManager(cDetailPicture, false, true); + final CardManager catalogManager = new CardManager(cDetailPicture0, false, true); + final CardManager deckManager = new CardManager(cDetailPicture0, false, true); catalogManager.setCaption("Sideboard"); diff --git a/forge-gui-desktop/src/main/java/forge/screens/deckeditor/controllers/CEditorTokenViewer.java b/forge-gui-desktop/src/main/java/forge/screens/deckeditor/controllers/CEditorTokenViewer.java index 29bff60b75c..152d0cf10e2 100644 --- a/forge-gui-desktop/src/main/java/forge/screens/deckeditor/controllers/CEditorTokenViewer.java +++ b/forge-gui-desktop/src/main/java/forge/screens/deckeditor/controllers/CEditorTokenViewer.java @@ -2,6 +2,7 @@ package forge.screens.deckeditor.controllers; import forge.deck.DeckBase; +import forge.game.GameType; import forge.gui.framework.DragCell; import forge.gui.framework.FScreen; import forge.item.PaperToken; @@ -35,14 +36,14 @@ public class CEditorTokenViewer extends ACEditorBase { * Child controller for quest card shop UI. * */ - public CEditorTokenViewer(final CDetailPicture cDetailPicture) { - super(FScreen.TOKEN_VIEWER, cDetailPicture); + public CEditorTokenViewer(final CDetailPicture cDetailPicture0) { + super(FScreen.TOKEN_VIEWER, cDetailPicture0, GameType.Quest); FModel.getMagicDb().getAllTokens().preloadTokens(); fullCatalogCards = FModel.getMagicDb().getAllTokens().getAllTokens(); - final TokenManager catalogManager = new TokenManager(getCDetailPicture(), false); - final TokenManager deckManager = new TokenManager(cDetailPicture, false); + final TokenManager catalogManager = new TokenManager(cDetailPicture0, false); + final TokenManager deckManager = new TokenManager(cDetailPicture0, false); catalogManager.setCaption("All Tokens"); catalogManager.setAlwaysNonUnique(true); this.setCatalogManager(catalogManager); diff --git a/forge-gui-desktop/src/main/java/forge/screens/deckeditor/controllers/CEditorVariant.java b/forge-gui-desktop/src/main/java/forge/screens/deckeditor/controllers/CEditorVariant.java index 69953f07822..a032572d708 100644 --- a/forge-gui-desktop/src/main/java/forge/screens/deckeditor/controllers/CEditorVariant.java +++ b/forge-gui-desktop/src/main/java/forge/screens/deckeditor/controllers/CEditorVariant.java @@ -23,6 +23,7 @@ import com.google.common.collect.Iterables; import forge.UiCommand; import forge.deck.Deck; import forge.deck.DeckSection; +import forge.game.GameType; import forge.gui.framework.DragCell; import forge.gui.framework.FScreen; import forge.item.PaperCard; @@ -63,14 +64,14 @@ public final class CEditorVariant extends CDeckEditor { * all cards are available. */ @SuppressWarnings("serial") - public CEditorVariant(final IStorage folder, final Predicate poolCondition, final DeckSection deckSection0, final FScreen screen0, final CDetailPicture cDetailPicture) { - super(screen0, cDetailPicture); + public CEditorVariant(final IStorage folder, final Predicate poolCondition, final DeckSection deckSection0, final FScreen screen0, final CDetailPicture cDetailPicture0) { + super(screen0, cDetailPicture0, GameType.Constructed); this.cardPoolCondition = poolCondition; this.sectionMode = deckSection0; - final CardManager catalogManager = new CardManager(cDetailPicture, true, false); - final CardManager deckManager = new CardManager(cDetailPicture, true, false); + final CardManager catalogManager = new CardManager(cDetailPicture0, true, false); + final CardManager deckManager = new CardManager(cDetailPicture0, true, false); final Localizer localizer = Localizer.getInstance(); catalogManager.setCaption(localizer.getMessage("lblCatalog")); diff --git a/forge-gui-desktop/src/main/java/forge/screens/deckeditor/controllers/CEditorWinstonProcess.java b/forge-gui-desktop/src/main/java/forge/screens/deckeditor/controllers/CEditorWinstonProcess.java index 94a0750cac2..2a2926dfcfc 100644 --- a/forge-gui-desktop/src/main/java/forge/screens/deckeditor/controllers/CEditorWinstonProcess.java +++ b/forge-gui-desktop/src/main/java/forge/screens/deckeditor/controllers/CEditorWinstonProcess.java @@ -24,6 +24,7 @@ import forge.deck.CardPool; import forge.deck.Deck; import forge.deck.DeckGroup; import forge.deck.DeckSection; +import forge.game.GameType; import forge.gui.framework.DragCell; import forge.gui.framework.FScreen; import forge.item.PaperCard; @@ -75,11 +76,11 @@ public class CEditorWinstonProcess extends ACEditorBase { * Updates the deck editor UI as necessary draft selection mode. */ @SuppressWarnings("serial") - public CEditorWinstonProcess(final CDetailPicture cDetailPicture) { - super(FScreen.DRAFTING_PROCESS, cDetailPicture); + public CEditorWinstonProcess(final CDetailPicture cDetailPicture0) { + super(FScreen.DRAFTING_PROCESS, cDetailPicture0, GameType.Draft); - final CardManager catalogManager = new CardManager(cDetailPicture, false, false); - final CardManager deckManager = new CardManager(cDetailPicture, false, false); + final CardManager catalogManager = new CardManager(cDetailPicture0, false, false); + final CardManager deckManager = new CardManager(cDetailPicture0, false, false); //hide filters and options panel so more of pack is visible by default catalogManager.setHideViewOptions(1, true); diff --git a/forge-gui-desktop/src/main/java/forge/screens/deckeditor/controllers/COathbreakerDecks.java b/forge-gui-desktop/src/main/java/forge/screens/deckeditor/controllers/COathbreakerDecks.java new file mode 100644 index 00000000000..2b720a6bfa3 --- /dev/null +++ b/forge-gui-desktop/src/main/java/forge/screens/deckeditor/controllers/COathbreakerDecks.java @@ -0,0 +1,44 @@ +package forge.screens.deckeditor.controllers; + +import forge.deck.DeckProxy; +import forge.gui.framework.ICDoc; +import forge.itemmanager.ItemManagerConfig; +import forge.screens.deckeditor.views.VOathbreakerDecks; + +/** + * Controls the "Oathbreaker Decks" panel in the deck editor UI. + * + *

(C at beginning of class name denotes a control class.) + * + */ +public enum COathbreakerDecks implements ICDoc { + SINGLETON_INSTANCE; + + private final VOathbreakerDecks view = VOathbreakerDecks.SINGLETON_INSTANCE; + + //========== Overridden methods + + @Override + public void register() { + } + + /* (non-Javadoc) + * @see forge.gui.framework.ICDoc#initialize() + */ + @Override + public void initialize() { + refresh(); + } + + public void refresh() { + view.getLstDecks().setPool(DeckProxy.getAllOathbreakerDecks()); + } + + /* (non-Javadoc) + * @see forge.gui.framework.ICDoc#update() + */ + @Override + public void update() { + view.getLstDecks().setup(ItemManagerConfig.CONSTRUCTED_DECKS); + } +} diff --git a/forge-gui-desktop/src/main/java/forge/screens/deckeditor/controllers/CTinyLeadersDecks.java b/forge-gui-desktop/src/main/java/forge/screens/deckeditor/controllers/CTinyLeadersDecks.java index a20e47aa8f1..5a8027041c4 100644 --- a/forge-gui-desktop/src/main/java/forge/screens/deckeditor/controllers/CTinyLeadersDecks.java +++ b/forge-gui-desktop/src/main/java/forge/screens/deckeditor/controllers/CTinyLeadersDecks.java @@ -6,7 +6,7 @@ import forge.itemmanager.ItemManagerConfig; import forge.screens.deckeditor.views.VTinyLeadersDecks; /** - * Controls the "Commander Decks" panel in the deck editor UI. + * Controls the "Tiny Leaders Decks" panel in the deck editor UI. * *

(C at beginning of class name denotes a control class.) * diff --git a/forge-gui-desktop/src/main/java/forge/screens/deckeditor/views/VOathbreakerDecks.java b/forge-gui-desktop/src/main/java/forge/screens/deckeditor/views/VOathbreakerDecks.java new file mode 100644 index 00000000000..85d514b501b --- /dev/null +++ b/forge-gui-desktop/src/main/java/forge/screens/deckeditor/views/VOathbreakerDecks.java @@ -0,0 +1,100 @@ +package forge.screens.deckeditor.views; + +import forge.deck.io.DeckPreferences; +import forge.game.GameType; +import forge.gui.framework.DragCell; +import forge.gui.framework.DragTab; +import forge.gui.framework.EDocID; +import forge.gui.framework.IVDoc; +import forge.itemmanager.DeckManager; +import forge.itemmanager.ItemManagerContainer; +import forge.screens.deckeditor.controllers.COathbreakerDecks; +import forge.screens.match.controllers.CDetailPicture; +import forge.util.Localizer; +import net.miginfocom.swing.MigLayout; + +import javax.swing.*; + +/** + * Assembles Swing components of all deck viewer in deck editor. + * + *

(V at beginning of class name denotes a view class.) + */ +public enum VOathbreakerDecks implements IVDoc { + /** */ + SINGLETON_INSTANCE; + + // Fields used with interface IVDoc + private DragCell parentCell; + final Localizer localizer = Localizer.getInstance(); + private final DragTab tab = new DragTab(localizer.getMessage("lblOathbreaker")); + + private DeckManager lstDecks; + + //========== Overridden methods + + /* (non-Javadoc) + * @see forge.gui.framework.IVDoc#getDocumentID() + */ + @Override + public EDocID getDocumentID() { + return EDocID.EDITOR_OATHBREAKER; + } + + /* (non-Javadoc) + * @see forge.gui.framework.IVDoc#getTabLabel() + */ + @Override + public DragTab getTabLabel() { + return tab; + } + + /* (non-Javadoc) + * @see forge.gui.framework.IVDoc#getLayoutControl() + */ + @Override + public COathbreakerDecks getLayoutControl() { + return COathbreakerDecks.SINGLETON_INSTANCE; + } + + /* (non-Javadoc) + * @see forge.gui.framework.IVDoc#setParentCell(forge.gui.framework.DragCell) + */ + @Override + public void setParentCell(DragCell cell0) { + this.parentCell = cell0; + } + + /* (non-Javadoc) + * @see forge.gui.framework.IVDoc#getParentCell() + */ + @Override + public DragCell getParentCell() { + return this.parentCell; + } + + /* (non-Javadoc) + * @see forge.gui.framework.IVDoc#populate() + */ + @Override + public void populate() { + COathbreakerDecks.SINGLETON_INSTANCE.refresh(); //ensure decks refreshed in case any deleted or added since last loaded + + JPanel parentBody = parentCell.getBody(); + parentBody.setLayout(new MigLayout("insets 5, gap 0, wrap, hidemode 3")); + parentBody.add(new ItemManagerContainer(lstDecks), "push, grow"); + String preferredDeck = DeckPreferences.getOathbreakerDeck(); + lstDecks.editDeck(lstDecks.stringToItem(preferredDeck)); + } + + //========== Retrieval methods + /** @return {@link JPanel} */ + public DeckManager getLstDecks() { + return lstDecks; + } + + public void setCDetailPicture(final CDetailPicture cDetailPicture) { + this.lstDecks = new DeckManager(GameType.Oathbreaker, cDetailPicture); + this.lstDecks.setCaption(localizer.getMessage("lblOathbreakerDecks")); + } +} diff --git a/forge-gui-desktop/src/main/java/forge/screens/home/CLobby.java b/forge-gui-desktop/src/main/java/forge/screens/home/CLobby.java index ccc540ea363..fc09b9c4033 100644 --- a/forge-gui-desktop/src/main/java/forge/screens/home/CLobby.java +++ b/forge-gui-desktop/src/main/java/forge/screens/home/CLobby.java @@ -86,6 +86,14 @@ public class CLobby { view.focusOnAvatar(); } }); + final FDeckChooser fdobcom = view.getOathbreakerDeckChooser(iSlot); + fdobcom.initialize(FPref.OATHBREAKER_DECK_STATES[iSlot], defaultDeckTypeForOathbreakerSlot(iSlot)); + fdobcom.populate(); + fdobcom.getDecksComboBox().addListener(new IDecksComboBoxListener() { + @Override public final void deckTypeSelected(final DecksComboBoxEvent ev) { + view.focusOnAvatar(); + } + }); final FDeckChooser fdtlcom = view.getTinyLeaderDeckChooser(iSlot); fdtlcom.initialize(FPref.TINY_LEADER_DECK_STATES[iSlot], defaultDeckTypeForTinyLeaderSlot(iSlot)); fdtlcom.populate(); @@ -135,11 +143,15 @@ public class CLobby { return iSlot == 0 ? DeckType.COMMANDER_DECK : DeckType.RANDOM_CARDGEN_COMMANDER_DECK; } + private static DeckType defaultDeckTypeForOathbreakerSlot(final int iSlot) { + return iSlot == 0 ? DeckType.OATHBREAKER_DECK : DeckType.RANDOM_CARDGEN_COMMANDER_DECK; + } + private static DeckType defaultDeckTypeForTinyLeaderSlot(final int iSlot) { - return iSlot == 0 ? DeckType.TINY_LEADERS_DECKS : DeckType.RANDOM_CARDGEN_COMMANDER_DECK; + return iSlot == 0 ? DeckType.TINY_LEADERS_DECK : DeckType.RANDOM_CARDGEN_COMMANDER_DECK; } private static DeckType defaultDeckTypeForBrawlSlot(final int iSlot) { - return iSlot == 0 ? DeckType.BRAWL_DECKS : DeckType.CUSTOM_DECK; + return iSlot == 0 ? DeckType.BRAWL_DECK : DeckType.CUSTOM_DECK; } } 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 c41c4db5c7d..d983a97902d 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 @@ -333,9 +333,10 @@ public class PlayerPanel extends FPanel { }; private void updateVariantControlsVisibility() { + final boolean isOathbreaker = lobby.hasVariant(GameType.Oathbreaker); final boolean isTinyLeaders = lobby.hasVariant(GameType.TinyLeaders); final boolean isBrawl = lobby.hasVariant(GameType.Brawl); - final boolean isCommanderApplied = mayEdit && (lobby.hasVariant(GameType.Commander) || isTinyLeaders || isBrawl); + final boolean isCommanderApplied = mayEdit && (lobby.hasVariant(GameType.Commander) || isOathbreaker || isTinyLeaders || isBrawl); final boolean isPlanechaseApplied = mayEdit && lobby.hasVariant(GameType.Planechase); final boolean isVanguardApplied = mayEdit && lobby.hasVariant(GameType.Vanguard); final boolean isArchenemyApplied = mayEdit && lobby.hasVariant(GameType.Archenemy); @@ -507,7 +508,11 @@ public class PlayerPanel extends FPanel { cmdDeckSelectorBtn.setCommand(new Runnable() { @Override public void run() { - lobby.setCurrentGameMode(lobby.hasVariant(GameType.TinyLeaders) ? GameType.TinyLeaders : lobby.hasVariant(GameType.Brawl) ? GameType.Brawl : GameType.Commander); + lobby.setCurrentGameMode( + lobby.hasVariant(GameType.Oathbreaker) ? GameType.Oathbreaker : + lobby.hasVariant(GameType.TinyLeaders) ? GameType.TinyLeaders : + lobby.hasVariant(GameType.Brawl) ? GameType.Brawl : + GameType.Commander); cmdDeckSelectorBtn.requestFocusInWindow(); lobby.changePlayerFocus(index); } diff --git a/forge-gui-desktop/src/main/java/forge/screens/home/VLobby.java b/forge-gui-desktop/src/main/java/forge/screens/home/VLobby.java index c3daa6db574..4fafd123966 100644 --- a/forge-gui-desktop/src/main/java/forge/screens/home/VLobby.java +++ b/forge-gui-desktop/src/main/java/forge/screens/home/VLobby.java @@ -68,15 +68,16 @@ public class VLobby implements ILobbyView { private final VariantCheckBox vntMomirBasic = new VariantCheckBox(GameType.MomirBasic); private final VariantCheckBox vntMoJhoSto = new VariantCheckBox(GameType.MoJhoSto); private final VariantCheckBox vntCommander = new VariantCheckBox(GameType.Commander); + private final VariantCheckBox vntOathbreaker = new VariantCheckBox(GameType.Oathbreaker); private final VariantCheckBox vntTinyLeaders = new VariantCheckBox(GameType.TinyLeaders); private final VariantCheckBox vntBrawl = new VariantCheckBox(GameType.Brawl); private final VariantCheckBox vntPlanechase = new VariantCheckBox(GameType.Planechase); private final VariantCheckBox vntArchenemy = new VariantCheckBox(GameType.Archenemy); private final VariantCheckBox vntArchenemyRumble = new VariantCheckBox(GameType.ArchenemyRumble); private final ImmutableList vntBoxesLocal = - ImmutableList.of(vntVanguard, vntMomirBasic, vntMoJhoSto, vntCommander, vntBrawl, vntTinyLeaders, vntPlanechase, vntArchenemy, vntArchenemyRumble); + ImmutableList.of(vntVanguard, vntMomirBasic, vntMoJhoSto, vntCommander, vntOathbreaker, vntBrawl, vntTinyLeaders, vntPlanechase, vntArchenemy, vntArchenemyRumble); private final ImmutableList vntBoxesNetwork = - ImmutableList.of(vntVanguard, vntMomirBasic, vntMoJhoSto, vntCommander, vntBrawl, vntTinyLeaders /*, vntPlanechase, vntArchenemy, vntArchenemyRumble */); + ImmutableList.of(vntVanguard, vntMomirBasic, vntMoJhoSto, vntCommander, vntOathbreaker, vntBrawl, vntTinyLeaders /*, vntPlanechase, vntArchenemy, vntArchenemyRumble */); // Player frame elements private final JPanel playersFrame = new JPanel(new MigLayout("insets 0, gap 0 5, wrap, hidemode 3")); @@ -93,16 +94,8 @@ public class VLobby implements ILobbyView { private final Deck[] decks = new Deck[MAX_PLAYERS]; // Variants - private final List> commanderDeckLists = new ArrayList>(); - private final List commanderDeckPanels = new ArrayList(MAX_PLAYERS); - - private final List> tinyLeadersDeckLists = new ArrayList>(); - private final List tinyLeadersDeckPanels = new ArrayList(MAX_PLAYERS); - - private final List> brawlDeckLists = new ArrayList>(); - private final List brawlDeckPanels = new ArrayList(MAX_PLAYERS); - private final List commanderDeckChoosers = Lists.newArrayListWithCapacity(MAX_PLAYERS); + private final List oathbreakerDeckChoosers = Lists.newArrayListWithCapacity(MAX_PLAYERS); private final List tinyLeadersDeckChoosers = Lists.newArrayListWithCapacity(MAX_PLAYERS); private final List brawlDeckChoosers = Lists.newArrayListWithCapacity(MAX_PLAYERS); @@ -209,6 +202,8 @@ public class VLobby implements ILobbyView { fdc.restoreSavedState(); final FDeckChooser fdcom = getCommanderDeckChooser(iPlayer); fdcom.restoreSavedState(); + final FDeckChooser fdob = getOathbreakerDeckChooser(iPlayer); + fdob.restoreSavedState(); final FDeckChooser fdtl = getTinyLeaderDeckChooser(iPlayer); fdtl.restoreSavedState(); final FDeckChooser fdbr = getBrawlDeckChooser(iPlayer); @@ -238,38 +233,22 @@ public class VLobby implements ILobbyView { default: break; } - final FDeckChooser commanderDeckChooser = getCommanderDeckChooser(slot); - commanderDeckChooser.setIsAi(type==LobbySlotType.AI); - selectedDeckType = commanderDeckChooser.getSelectedDeckType(); + updateCommanderStyleDeckChooser(getCommanderDeckChooser(slot), type); + updateCommanderStyleDeckChooser(getOathbreakerDeckChooser(slot), type); + updateCommanderStyleDeckChooser(getTinyLeaderDeckChooser(slot), type); + updateCommanderStyleDeckChooser(getBrawlDeckChooser(slot), type); + } + + private void updateCommanderStyleDeckChooser(final FDeckChooser deckChooser, final LobbySlotType type) { + deckChooser.setIsAi(type==LobbySlotType.AI); + DeckType selectedDeckType = deckChooser.getSelectedDeckType(); switch (selectedDeckType){ - case RANDOM_CARDGEN_COMMANDER_DECK: - case RANDOM_COMMANDER_DECK: - commanderDeckChooser.refreshDeckListForAI(); - break; - default: - break; - } - final FDeckChooser tinyLeaderDeckChooser = getTinyLeaderDeckChooser(slot); - tinyLeaderDeckChooser.setIsAi(type==LobbySlotType.AI); - selectedDeckType = tinyLeaderDeckChooser.getSelectedDeckType(); - switch (selectedDeckType){ - case RANDOM_CARDGEN_COMMANDER_DECK: - case RANDOM_COMMANDER_DECK: - tinyLeaderDeckChooser.refreshDeckListForAI(); - break; - default: - break; - } - final FDeckChooser brawlDeckChooser = getBrawlDeckChooser(slot); - brawlDeckChooser.setIsAi(type==LobbySlotType.AI); - selectedDeckType = brawlDeckChooser.getSelectedDeckType(); - switch (selectedDeckType){ - case RANDOM_CARDGEN_COMMANDER_DECK: - case RANDOM_COMMANDER_DECK: - brawlDeckChooser.refreshDeckListForAI(); - break; - default: - break; + case RANDOM_CARDGEN_COMMANDER_DECK: + case RANDOM_COMMANDER_DECK: + deckChooser.refreshDeckListForAI(); + break; + default: + break; } } @@ -297,6 +276,7 @@ public class VLobby implements ILobbyView { final LobbySlot slot = lobby.getSlot(i); final FDeckChooser deckChooser = getDeckChooser(i); final FDeckChooser commanderDeckChooser = getCommanderDeckChooser(i); + final FDeckChooser oathbreakerDeckChooser = getOathbreakerDeckChooser(i); final FDeckChooser tinyLeaderDeckChooser = getTinyLeaderDeckChooser(i); final FDeckChooser brawlDeckChooser = getBrawlDeckChooser(i); final PlayerPanel panel; @@ -314,6 +294,7 @@ public class VLobby implements ILobbyView { playersScroll.add(panel, constraints); deckChooser.restoreSavedState(); commanderDeckChooser.restoreSavedState(); + oathbreakerDeckChooser.restoreSavedState(); tinyLeaderDeckChooser.restoreSavedState(); brawlDeckChooser.restoreSavedState(); if (i == 0) { @@ -341,6 +322,7 @@ public class VLobby implements ILobbyView { deckChooser.setIsAi(isSlotAI); commanderDeckChooser.setIsAi(isSlotAI); + oathbreakerDeckChooser.setIsAi(isSlotAI); tinyLeaderDeckChooser.setIsAi(isSlotAI); brawlDeckChooser.setIsAi(isSlotAI); if (fullUpdate && (type == LobbySlotType.LOCAL || isSlotAI)) { @@ -439,12 +421,6 @@ public class VLobby implements ILobbyView { } }); - // Commander deck list - /*buildDeckPanel("Commander Deck", playerIndex, commanderDeckLists, commanderDeckPanels, new ListSelectionListener() { - @Override public final void valueChanged(final ListSelectionEvent e) { - selectCommanderDeck(playerIndex); - } - });*/ final FDeckChooser commanderChooser = new FDeckChooser(null, isPlayerAI(playerIndex), GameType.Commander, true); commanderChooser.getLstDecks().setSelectCommand(new UiCommand() { @Override public final void run() { @@ -454,6 +430,15 @@ public class VLobby implements ILobbyView { commanderChooser.initialize(); commanderDeckChoosers.add(commanderChooser); + final FDeckChooser oathbreakerChooser = new FDeckChooser(null, isPlayerAI(playerIndex), GameType.Oathbreaker, true); + oathbreakerChooser.getLstDecks().setSelectCommand(new UiCommand() { + @Override public final void run() { + selectOathbreakerDeck(playerIndex); + } + }); + oathbreakerChooser.initialize(); + oathbreakerDeckChoosers.add(oathbreakerChooser); + final FDeckChooser tinyLeaderChooser = new FDeckChooser(null, isPlayerAI(playerIndex), GameType.TinyLeaders, true); tinyLeaderChooser.getLstDecks().setSelectCommand(new UiCommand() { @Override public final void run() { @@ -472,14 +457,6 @@ public class VLobby implements ILobbyView { brawlChooser.initialize(); brawlDeckChoosers.add(brawlChooser); - -/* // Tiny Leaders deck list - buildDeckPanel("Tiny Leaders Deck", playerIndex, tinyLeadersDeckLists, tinyLeadersDeckPanels, new ListSelectionListener() { - @Override public final void valueChanged(final ListSelectionEvent e) { - selectTinyLeadersDeck(playerIndex); - } - });*/ - // Planar deck list buildDeckPanel(localizer.getMessage("lblPlanarDeck"), playerIndex, planarDeckLists, planarDeckPanels, new ListSelectionListener() { @Override public final void valueChanged(final ListSelectionEvent e) { @@ -525,7 +502,9 @@ public class VLobby implements ILobbyView { // Full deck selection selectMainDeck(playerIndex); selectCommanderDeck(playerIndex); + selectOathbreakerDeck(playerIndex); selectTinyLeadersDeck(playerIndex); + selectBrawlDeck(playerIndex); // Deck section selection selectSchemeDeck(playerIndex); @@ -534,7 +513,7 @@ public class VLobby implements ILobbyView { } private void selectMainDeck(final int playerIndex) { - if (hasVariant(GameType.Commander) || hasVariant(GameType.TinyLeaders) || hasVariant(GameType.Brawl)) { + if (hasVariant(GameType.Commander) || hasVariant(GameType.Oathbreaker) || hasVariant(GameType.TinyLeaders) || hasVariant(GameType.Brawl)) { // These game types use specific deck panel return; } @@ -551,7 +530,7 @@ public class VLobby implements ILobbyView { } private void selectCommanderDeck(final int playerIndex) { - if (!hasVariant(GameType.Commander)) { + if (!hasVariant(GameType.Commander) && !hasVariant(GameType.Oathbreaker) && !hasVariant(GameType.TinyLeaders) && !hasVariant(GameType.Brawl)) { // Only these game types use this specific deck panel return; } @@ -567,6 +546,23 @@ public class VLobby implements ILobbyView { mainChooser.saveState(); } + private void selectOathbreakerDeck(final int playerIndex) { + if (!hasVariant(GameType.Oathbreaker)) { + // Only these game types use this specific deck panel + return; + } + final FDeckChooser mainChooser = getOathbreakerDeckChooser(playerIndex); + final DeckType type = mainChooser.getSelectedDeckType(); + final Deck deck = mainChooser.getDeck(); + final Collection selectedDecks = mainChooser.getLstDecks().getSelectedItems(); + if (playerIndex < activePlayersNum && lobby.mayEdit(playerIndex)) { + final String text = type.toString() + ": " + Lang.joinHomogenous(selectedDecks, DeckProxy.FN_GET_NAME); + playerPanels.get(playerIndex).setCommanderDeckSelectorButtonText(text); + fireDeckChangeListener(playerIndex, deck); + } + mainChooser.saveState(); + } + private void selectTinyLeadersDeck(final int playerIndex) { if (!hasVariant(GameType.TinyLeaders)) { // Only these game types use this specific deck panel @@ -601,8 +597,6 @@ public class VLobby implements ILobbyView { mainChooser.saveState(); } - - private void selectSchemeDeck(final int playerIndex) { if (playerIndex >= activePlayersNum || !(hasVariant(GameType.Archenemy) || hasVariant(GameType.ArchenemyRumble))) { return; @@ -737,6 +731,9 @@ public class VLobby implements ILobbyView { case Commander: decksFrame.add(commanderDeckChoosers.get(playerWithFocus), "grow, push"); break; + case Oathbreaker: + decksFrame.add(oathbreakerDeckChoosers.get(playerWithFocus), "grow, push"); + break; case TinyLeaders: decksFrame.add(tinyLeadersDeckChoosers.get(playerWithFocus), "grow, push"); break; @@ -790,6 +787,10 @@ public class VLobby implements ILobbyView { return commanderDeckChoosers.get(playernum); } + public final FDeckChooser getOathbreakerDeckChooser(final int playernum) { + return oathbreakerDeckChoosers.get(playernum); + } + public final FDeckChooser getTinyLeaderDeckChooser(final int playernum) { return tinyLeadersDeckChoosers.get(playernum); } @@ -946,21 +947,6 @@ public class VLobby implements ILobbyView { return planarDeckLists; } - /** Gets the list of commander deck lists. */ - public List> getCommanderDeckLists() { - return commanderDeckLists; - } - - /** Gets the list of tiny leaders deck lists. */ - public List> getTinyLeadersDeckLists() { - return tinyLeadersDeckLists; - } - - /** Gets the list of tiny leaders deck lists. */ - public List> getBrawlDeckLists() { - return brawlDeckLists; - } - /** Gets the list of scheme deck lists. */ public List> getSchemeDeckLists() { return schemeDeckLists; diff --git a/forge-gui-mobile/src/forge/deck/FDeckChooser.java b/forge-gui-mobile/src/forge/deck/FDeckChooser.java index 74b0729000d..0d88d4d63dd 100644 --- a/forge-gui-mobile/src/forge/deck/FDeckChooser.java +++ b/forge-gui-mobile/src/forge/deck/FDeckChooser.java @@ -189,13 +189,14 @@ public class FDeckChooser extends FScreen { case Constructed: break; //delay initialize for constructed until saved decks can be reloaded case Commander: + case Oathbreaker: case TinyLeaders: case Brawl: case Gauntlet: initialize(null, DeckType.CUSTOM_DECK); break; case DeckManager: - initialize(null, DeckType.CONSTRUCTED_DECK); + initialize(null, DeckPreferences.getSelectedDeckType()); break; default: initialize(null, DeckType.RANDOM_DECK); @@ -225,6 +226,9 @@ public class FDeckChooser extends FScreen { case Commander: lstDecks.setSelectedString(DeckPreferences.getCommanderDeck()); break; + case Oathbreaker: + lstDecks.setSelectedString(DeckPreferences.getOathbreakerDeck()); + break; case TinyLeaders: lstDecks.setSelectedString(DeckPreferences.getTinyLeadersDeck()); break; @@ -242,22 +246,25 @@ public class FDeckChooser extends FScreen { case COMMANDER_DECK: lstDecks.setSelectedString(DeckPreferences.getCommanderDeck()); break; - case TINY_LEADERS_DECKS: + case OATHBREAKER_DECK: + lstDecks.setSelectedString(DeckPreferences.getOathbreakerDeck()); + break; + case TINY_LEADERS_DECK: lstDecks.setSelectedString(DeckPreferences.getTinyLeadersDeck()); break; - case BRAWL_DECKS: + case BRAWL_DECK: lstDecks.setSelectedString(DeckPreferences.getBrawlDeck()); break; - case SCHEME_DECKS: + case SCHEME_DECK: lstDecks.setSelectedString(DeckPreferences.getSchemeDeck()); break; - case PLANAR_DECKS: + case PLANAR_DECK: lstDecks.setSelectedString(DeckPreferences.getPlanarDeck()); break; - case DRAFT_DECKS: + case DRAFT_DECK: lstDecks.setSelectedString(DeckPreferences.getDraftDeck()); break; - case SEALED_DECKS: + case SEALED_DECK: lstDecks.setSelectedString(DeckPreferences.getSealedDeck()); break; default: @@ -275,10 +282,10 @@ public class FDeckChooser extends FScreen { private void createNewDeck() { FDeckEditor editor; switch (selectedDeckType) { - case DRAFT_DECKS: + case DRAFT_DECK: NewGameScreen.BoosterDraft.open(); return; - case SEALED_DECKS: + case SEALED_DECK: NewGameScreen.SealedDeck.open(); return; case COLOR_DECK: @@ -318,12 +325,13 @@ public class FDeckChooser extends FScreen { if (lstDecks.getGameType() == GameType.DeckManager) { switch (selectedDeckType) { case COMMANDER_DECK: - case TINY_LEADERS_DECKS: - case BRAWL_DECKS: - case SCHEME_DECKS: - case PLANAR_DECKS: - case DRAFT_DECKS: - case SEALED_DECKS: + case OATHBREAKER_DECK: + case TINY_LEADERS_DECK: + case BRAWL_DECK: + case SCHEME_DECK: + case PLANAR_DECK: + case DRAFT_DECK: + case SEALED_DECK: break; default: setSelectedDeckType(DeckType.CONSTRUCTED_DECK); @@ -347,12 +355,13 @@ public class FDeckChooser extends FScreen { case CUSTOM_DECK: case CONSTRUCTED_DECK: case COMMANDER_DECK: - case TINY_LEADERS_DECKS: - case BRAWL_DECKS: - case SCHEME_DECKS: - case PLANAR_DECKS: - case DRAFT_DECKS: - case SEALED_DECKS: + case OATHBREAKER_DECK: + case TINY_LEADERS_DECK: + case BRAWL_DECK: + case SCHEME_DECK: + case PLANAR_DECK: + case DRAFT_DECK: + case SEALED_DECK: editDeck(deck); break; default: @@ -390,23 +399,27 @@ public class FDeckChooser extends FScreen { switch (selectedDeckType) { case COMMANDER_DECK: return EditorType.Commander; - case TINY_LEADERS_DECKS: + case OATHBREAKER_DECK: + return EditorType.Oathbreaker; + case TINY_LEADERS_DECK: return EditorType.TinyLeaders; - case BRAWL_DECKS: + case BRAWL_DECK: return EditorType.Brawl; - case SCHEME_DECKS: + case SCHEME_DECK: return EditorType.Archenemy; - case PLANAR_DECKS: + case PLANAR_DECK: return EditorType.Planechase; - case DRAFT_DECKS: + case DRAFT_DECK: return EditorType.Draft; - case SEALED_DECKS: + case SEALED_DECK: return EditorType.Sealed; default: return EditorType.Constructed; } case Commander: return EditorType.Commander; + case Oathbreaker: + return EditorType.Oathbreaker; case TinyLeaders: return EditorType.TinyLeaders; case Brawl: @@ -426,6 +439,9 @@ public class FDeckChooser extends FScreen { case Commander: DeckPreferences.setCommanderDeck(deck.getName()); break; + case Oathbreaker: + DeckPreferences.setOathbreakerDeck(deck.getName()); + break; case TinyLeaders: DeckPreferences.setTinyLeadersDeck(deck.getName()); break; @@ -477,6 +493,7 @@ public class FDeckChooser extends FScreen { cmbDeckTypes.addItem(DeckType.NET_DECK); break; case Commander: + case Oathbreaker: case TinyLeaders: case Brawl: cmbDeckTypes.addItem(DeckType.CUSTOM_DECK); @@ -490,12 +507,13 @@ public class FDeckChooser extends FScreen { case DeckManager: cmbDeckTypes.addItem(DeckType.CONSTRUCTED_DECK); cmbDeckTypes.addItem(DeckType.COMMANDER_DECK); - cmbDeckTypes.addItem(DeckType.TINY_LEADERS_DECKS); - cmbDeckTypes.addItem(DeckType.BRAWL_DECKS); - cmbDeckTypes.addItem(DeckType.SCHEME_DECKS); - cmbDeckTypes.addItem(DeckType.PLANAR_DECKS); - cmbDeckTypes.addItem(DeckType.DRAFT_DECKS); - cmbDeckTypes.addItem(DeckType.SEALED_DECKS); + cmbDeckTypes.addItem(DeckType.OATHBREAKER_DECK); + cmbDeckTypes.addItem(DeckType.TINY_LEADERS_DECK); + cmbDeckTypes.addItem(DeckType.BRAWL_DECK); + cmbDeckTypes.addItem(DeckType.SCHEME_DECK); + cmbDeckTypes.addItem(DeckType.PLANAR_DECK); + cmbDeckTypes.addItem(DeckType.DRAFT_DECK); + cmbDeckTypes.addItem(DeckType.SEALED_DECK); cmbDeckTypes.addItem(DeckType.PRECONSTRUCTED_DECK); cmbDeckTypes.addItem(DeckType.QUEST_OPPONENT_DECK); cmbDeckTypes.addItem(DeckType.NET_DECK); @@ -586,6 +604,10 @@ public class FDeckChooser extends FScreen { pool = DeckProxy.getAllCommanderDecks(); config = ItemManagerConfig.COMMANDER_DECKS; break; + case Oathbreaker: + pool = DeckProxy.getAllOathbreakerDecks(); + config = ItemManagerConfig.COMMANDER_DECKS; + break; case TinyLeaders: pool = DeckProxy.getAllTinyLeadersDecks(); config = ItemManagerConfig.COMMANDER_DECKS; @@ -616,11 +638,15 @@ public class FDeckChooser extends FScreen { pool = DeckProxy.getAllCommanderDecks(); config = ItemManagerConfig.COMMANDER_DECKS; break; - case TINY_LEADERS_DECKS: + case OATHBREAKER_DECK: + pool = DeckProxy.getAllOathbreakerDecks(); + config = ItemManagerConfig.COMMANDER_DECKS; + break; + case TINY_LEADERS_DECK: pool = DeckProxy.getAllTinyLeadersDecks(); config = ItemManagerConfig.COMMANDER_DECKS; break; - case BRAWL_DECKS: + case BRAWL_DECK: pool = DeckProxy.getAllBrawlDecks(); config = ItemManagerConfig.COMMANDER_DECKS; break; @@ -635,19 +661,19 @@ public class FDeckChooser extends FScreen { } config = ItemManagerConfig.STRING_ONLY; break; - case SCHEME_DECKS: + case SCHEME_DECK: pool = DeckProxy.getAllSchemeDecks(); config = ItemManagerConfig.SCHEME_DECKS; break; - case PLANAR_DECKS: + case PLANAR_DECK: pool = DeckProxy.getAllPlanarDecks(); config = ItemManagerConfig.PLANAR_DECKS; break; - case DRAFT_DECKS: + case DRAFT_DECK: pool = DeckProxy.getAllDraftDecks(); config = ItemManagerConfig.DRAFT_DECKS; break; - case SEALED_DECKS: + case SEALED_DECK: pool = DeckProxy.getAllSealedDecks(); config = ItemManagerConfig.SEALED_DECKS; break; @@ -678,22 +704,21 @@ public class FDeckChooser extends FScreen { config = ItemManagerConfig.STRING_ONLY; break; case LEGACY_CARDGEN_DECK: - maxSelections = 1; - pool= new ArrayList<>(); - if(FModel.isdeckGenMatrixLoaded()) { - pool = ArchetypeDeckGenerator.getMatrixDecks(FModel.getFormats().get("Legacy"), isAi); - } - config = ItemManagerConfig.STRING_ONLY; - break; + maxSelections = 1; + pool= new ArrayList<>(); + if(FModel.isdeckGenMatrixLoaded()) { + pool = ArchetypeDeckGenerator.getMatrixDecks(FModel.getFormats().get("Legacy"), isAi); + } + config = ItemManagerConfig.STRING_ONLY; + break; case VINTAGE_CARDGEN_DECK: - maxSelections = 1; - pool= new ArrayList<>(); - if(FModel.isdeckGenMatrixLoaded()) { - pool = ArchetypeDeckGenerator.getMatrixDecks(FModel.getFormats().get("Vintage"), isAi); - } - config = ItemManagerConfig.STRING_ONLY; - break; - + maxSelections = 1; + pool= new ArrayList<>(); + if(FModel.isdeckGenMatrixLoaded()) { + pool = ArchetypeDeckGenerator.getMatrixDecks(FModel.getFormats().get("Vintage"), isAi); + } + config = ItemManagerConfig.STRING_ONLY; + break; case MODERN_COLOR_DECK: maxSelections = 3; pool = ColorDeckGenerator.getColorDecks(lstDecks, FModel.getFormats().getModern().getFilterPrinted(), isAi); @@ -770,8 +795,8 @@ public class FDeckChooser extends FScreen { btnRandom.setText("Test Deck"); switch (selectedDeckType) { - case SCHEME_DECKS: - case PLANAR_DECKS: //don't allow testing secondary decks this way + case SCHEME_DECK: + case PLANAR_DECK: //don't allow testing secondary decks this way btnRandom.setEnabled(false); break; default: @@ -794,6 +819,9 @@ public class FDeckChooser extends FScreen { else { lstDecks.setSelectedIndex(0); } + if (lstDecks.getGameType() == GameType.DeckManager) { + DeckPreferences.setSelectedDeckType(deckType); //update saved Deck Manager type + } } } @@ -1016,13 +1044,19 @@ public class FDeckChooser extends FScreen { return; } - if (selectedDeckType == DeckType.TINY_LEADERS_DECKS) { + if (selectedDeckType == DeckType.OATHBREAKER_DECK) { + //cannot create gauntlet for oathbreaker decks, so just start single match + testVariantDeck(userDeck, GameType.Oathbreaker); + return; + } + + if (selectedDeckType == DeckType.TINY_LEADERS_DECK) { //cannot create gauntlet for tiny leaders decks, so just start single match testVariantDeck(userDeck, GameType.TinyLeaders); return; } - if (selectedDeckType == DeckType.BRAWL_DECKS) { + if (selectedDeckType == DeckType.BRAWL_DECK) { //cannot create gauntlet for tiny leaders decks, so just start single match testVariantDeck(userDeck, GameType.Brawl); return; diff --git a/forge-gui-mobile/src/forge/deck/FDeckEditor.java b/forge-gui-mobile/src/forge/deck/FDeckEditor.java index 3026afdf8b5..f88f93a1537 100644 --- a/forge-gui-mobile/src/forge/deck/FDeckEditor.java +++ b/forge-gui-mobile/src/forge/deck/FDeckEditor.java @@ -79,6 +79,12 @@ public class FDeckEditor extends TabPageScreen { return new Deck(); } }), null), + Oathbreaker(new DeckController(FModel.getDecks().getOathbreaker(), new Supplier() { + @Override + public Deck get() { + return new Deck(); + } + }), null), TinyLeaders(new DeckController(FModel.getDecks().getTinyLeaders(), new Supplier() { @Override public Deck get() { @@ -185,6 +191,13 @@ public class FDeckEditor extends TabPageScreen { new DeckSectionPage(DeckSection.Commander, ItemManagerConfig.COMMANDER_SECTION), new DeckSectionPage(DeckSection.Sideboard) }; + case Oathbreaker: + return new DeckEditorPage[] { + new CatalogPage(ItemManagerConfig.CARD_CATALOG), + new DeckSectionPage(DeckSection.Main), + new DeckSectionPage(DeckSection.Commander, ItemManagerConfig.OATHBREAKER_SECTION, "Oathbreaker", FSkinImage.COMMANDER), + new DeckSectionPage(DeckSection.Sideboard) + }; case Archenemy: return new DeckEditorPage[] { new CatalogPage(ItemManagerConfig.SCHEME_POOL), @@ -509,6 +522,7 @@ public class FDeckEditor extends TabPageScreen { case QuestDraft: return CardLimit.None; case Commander: + case Oathbreaker: case TinyLeaders: case Brawl: case PlanarConquest: @@ -782,7 +796,7 @@ public class FDeckEditor extends TabPageScreen { return additions; } - private int getMaxMoveQuantity(boolean isAddMenu, boolean isAddSource) { + protected int getMaxMoveQuantity(boolean isAddMenu, boolean isAddSource) { ItemPool selectedItemPool = cardManager.getSelectedItemPool(); if (isAddMenu) { selectedItemPool = getAllowedAdditions(selectedItemPool, isAddSource); @@ -820,6 +834,119 @@ public class FDeckEditor extends TabPageScreen { })); } + protected void addCommanderItems(final FDropDownMenu menu, final PaperCard card, boolean isAddMenu, boolean isAddSource) { + if (parentScreen.getCommanderPage() == null) { + return; + } + boolean isLegalCommander; + String captionSuffix = "Commander"; + switch (parentScreen.editorType) { + case Brawl: + isLegalCommander = card.getRules().canBeBrawlCommander(); + break; + case Oathbreaker: + isLegalCommander = card.getRules().canBeOathbreaker(); + captionSuffix = "Oathbreaker"; + break; + case PlanarConquest: + isLegalCommander = false; //don't set commander this way in Planar Conquest + break; + default: + isLegalCommander = DeckFormat.Commander.isLegalCommander(card.getRules()); + break; + } + if (isLegalCommander && !parentScreen.getCommanderPage().cardManager.getPool().contains(card)) { + addItem(menu, "Set", "as " + captionSuffix, parentScreen.getCommanderPage().getIcon(), isAddMenu, isAddSource, new Callback() { + @Override + public void run(Integer result) { + if (result == null || result <= 0) { return; } + setCommander(card); + } + }); + } + if (canHavePartnerCommander() && card.getRules().canBePartnerCommander()) { + addItem(menu, "Set", "as Partner " + captionSuffix, parentScreen.getCommanderPage().getIcon(), isAddMenu, isAddSource, new Callback() { + @Override + public void run(Integer result) { + if (result == null || result <= 0) { return; } + setPartnerCommander(card); + } + }); + } + if (canHaveSignatureSpell() && card.getRules().canBeSignatureSpell()) { + addItem(menu, "Set", "as Signature Spell", FSkinImage.SORCERY, isAddMenu, isAddSource, new Callback() { + @Override + public void run(Integer result) { + if (result == null || result <= 0) { return; } + setSignatureSpell(card); + } + }); + } + } + + protected boolean needsCommander() { + return parentScreen.getCommanderPage() != null && parentScreen.getDeck().getCommanders().isEmpty(); + } + + protected boolean canHavePartnerCommander() { + if (parentScreen.editorType == EditorType.Oathbreaker) { + return false; //at least for now, simplify Oathbreaker by not supporting partners, since there's only one set of partner planeswalkers anyway + } + return parentScreen.getCommanderPage() != null && parentScreen.getDeck().getCommanders().size() == 1 + && parentScreen.getDeck().getCommanders().get(0).getRules().canBePartnerCommander(); + } + + protected boolean canOnlyBePartnerCommander(final PaperCard card) { + if (parentScreen.getCommanderPage() == null) { + return false; + } + + byte cmdCI = 0; + for (final PaperCard p : parentScreen.getDeck().getCommanders()) { + cmdCI |= p.getRules().getColorIdentity().getColor(); + } + + return !card.getRules().getColorIdentity().hasNoColorsExcept(cmdCI); + } + + protected boolean canHaveSignatureSpell() { + return parentScreen.editorType == EditorType.Oathbreaker && parentScreen.getDeck().getOathbreaker() != null; + } + + protected void setCommander(PaperCard card) { + if (!cardManager.isInfinite()) { + removeCard(card); + } + CardPool newPool = new CardPool(); + newPool.add(card); + parentScreen.getCommanderPage().setCards(newPool); + refresh(); //refresh so cards shown that match commander's color identity + } + + protected void setPartnerCommander(PaperCard card) { + if (!cardManager.isInfinite()) { + removeCard(card); + } + parentScreen.getCommanderPage().addCard(card); + refresh(); //refresh so cards shown that match commander's color identity + } + + protected void setSignatureSpell(PaperCard card) { + if (!cardManager.isInfinite()) { + removeCard(card); + } + PaperCard signatureSpell = parentScreen.getDeck().getSignatureSpell(); + if (signatureSpell != null) { + parentScreen.getCommanderPage().removeCard(signatureSpell); //remove existing signature spell if any + } + parentScreen.getCommanderPage().addCard(card); + //refreshing isn't needed since color identity won't change from signature spell + } + + public void refresh() { + //not needed by default + } + @Override protected void doLayout(float width, float height) { float x = 0; @@ -887,6 +1014,7 @@ public class FDeckEditor extends TabPageScreen { } } + @Override public void refresh() { Predicate additionalFilter = null; final EditorType editorType = parentScreen.getEditorType(); @@ -910,36 +1038,50 @@ public class FDeckEditor extends TabPageScreen { cardManager.setPool(ConquestUtil.getAvailablePool(parentScreen.getDeck())); break; case Commander: + case Oathbreaker: case TinyLeaders: case Brawl: final List commanders = parentScreen.getDeck().getCommanders(); if (commanders.isEmpty()) { //if no commander set for deck, only show valid commanders switch (editorType) { - case TinyLeaders: - case Commander: - additionalFilter = DeckFormat.Commander.isLegalCommanderPredicate(); - break; - case Brawl: - additionalFilter = DeckFormat.Brawl.isLegalCommanderPredicate(); - break; - default: - // Do nothing + case Commander: + additionalFilter = DeckFormat.Commander.isLegalCommanderPredicate(); + cardManager.setCaption("Commanders"); + break; + case Oathbreaker: + additionalFilter = DeckFormat.Oathbreaker.isLegalCommanderPredicate(); + cardManager.setCaption("Oathbreakers"); + break; + case TinyLeaders: + additionalFilter = DeckFormat.TinyLeaders.isLegalCommanderPredicate(); + cardManager.setCaption("Commanders"); + break; + case Brawl: + additionalFilter = DeckFormat.Brawl.isLegalCommanderPredicate(); + cardManager.setCaption("Commanders"); + break; + default: + // Do nothing } - cardManager.setCaption("Commanders"); } else { //if a commander has been set, only show cards that match its color identity switch (editorType) { - case TinyLeaders: - case Commander: - additionalFilter = DeckFormat.Commander.isLegalCardForCommanderOrLegalPartnerPredicate(commanders); - break; - case Brawl: - additionalFilter = DeckFormat.Brawl.isLegalCardForCommanderOrLegalPartnerPredicate(commanders); - break; - default: - // Do nothing + case Commander: + additionalFilter = DeckFormat.Commander.isLegalCardForCommanderPredicate(commanders); + break; + case Oathbreaker: + additionalFilter = DeckFormat.Oathbreaker.isLegalCardForCommanderPredicate(commanders); + break; + case TinyLeaders: + additionalFilter = DeckFormat.TinyLeaders.isLegalCardForCommanderPredicate(commanders); + break; + case Brawl: + additionalFilter = DeckFormat.Brawl.isLegalCardForCommanderPredicate(commanders); + break; + default: + // Do nothing } cardManager.setCaption("Cards"); } @@ -957,59 +1099,22 @@ public class FDeckEditor extends TabPageScreen { @Override protected void onCardActivated(PaperCard card) { - if (canOnlyBePartnerCommander(card)) { - return; // don't auto-change commander unexpectedly + if (getMaxMoveQuantity(true, true) == 0) { + return; //don't add card if maximum copies of card already in deck } if (needsCommander()) { setCommander(card); //handle special case of setting commander return; } + if (canOnlyBePartnerCommander(card)) { + return; //don't auto-change commander unexpectedly + } if (!cardManager.isInfinite()) { removeCard(card); } parentScreen.getMainDeckPage().addCard(card); } - private boolean needsCommander() { - return parentScreen.getCommanderPage() != null && parentScreen.getDeck().getCommanders().isEmpty(); - } - - private boolean canHavePartnerCommander() { - return parentScreen.getCommanderPage() != null && parentScreen.getDeck().getCommanders().size() == 1 - && parentScreen.getDeck().getCommanders().get(0).getRules().canBePartnerCommander(); - } - - private boolean canOnlyBePartnerCommander(final PaperCard card) { - if (parentScreen.getCommanderPage() == null) { - return false; - } - - byte cmdCI = 0; - for (final PaperCard p : parentScreen.getDeck().getCommanders()) { - cmdCI |= p.getRules().getColorIdentity().getColor(); - } - - return !card.getRules().getColorIdentity().hasNoColorsExcept(cmdCI); - } - - private void setCommander(PaperCard card) { - if (!cardManager.isInfinite()) { - removeCard(card); - } - CardPool newPool = new CardPool(); - newPool.add(card); - parentScreen.getCommanderPage().setCards(newPool); - refresh(); //refresh so cards shown that match commander's color identity - } - - private void setPartnerCommander(PaperCard card) { - if (!cardManager.isInfinite()) { - removeCard(card); - } - parentScreen.getCommanderPage().addCard(card, 1); - refresh(); //refresh so cards shown that match commander's color identity - } - @Override protected void buildMenu(final FDropDownMenu menu, final PaperCard card) { if (!needsCommander() && !canOnlyBePartnerCommander(card)) { @@ -1038,32 +1143,8 @@ public class FDeckEditor extends TabPageScreen { }); } } - if (parentScreen.getCommanderPage() != null) { - boolean isLegalCommander; - if(parentScreen.editorType.equals(EditorType.Brawl)){ - isLegalCommander = card.getRules().canBeBrawlCommander(); - }else{ - isLegalCommander = DeckFormat.Commander.isLegalCommander(card.getRules()); - } - if (parentScreen.editorType != EditorType.PlanarConquest && isLegalCommander && !parentScreen.getCommanderPage().cardManager.getPool().contains(card)) { - addItem(menu, "Set", "as Commander", parentScreen.getCommanderPage().getIcon(), true, true, new Callback() { - @Override - public void run(Integer result) { - if (result == null || result <= 0) { return; } - setCommander(card); - } - }); - } - if (canHavePartnerCommander() && card.getRules().canBePartnerCommander()) { - addItem(menu, "Set", "as Partner Commander", parentScreen.getCommanderPage().getIcon(), true, true, new Callback() { - @Override - public void run(Integer result) { - if (result == null || result <= 0) { return; } - setPartnerCommander(card); - } - }); - } - } + + addCommanderItems(menu, card, true, true); if (parentScreen.getEditorType() == EditorType.Constructed) { //add option to add or remove card from favorites @@ -1277,6 +1358,7 @@ public class FDeckEditor extends TabPageScreen { } }); } + addCommanderItems(menu, card, false, false); break; case Sideboard: addItem(menu, "Add", null, FSkinImage.PLUS, true, false, new Callback() { @@ -1315,6 +1397,7 @@ public class FDeckEditor extends TabPageScreen { parentScreen.getMainDeckPage().addCard(card, result); } }); + addCommanderItems(menu, card, false, false); break; case Commander: if (parentScreen.editorType != EditorType.PlanarConquest || isPartnerCommander(card)) { @@ -1379,24 +1462,6 @@ public class FDeckEditor extends TabPageScreen { }); break; } - - if (parentScreen.editorType != EditorType.PlanarConquest && parentScreen.getCommanderPage() != null && deckSection != DeckSection.Commander) { - if (card.getRules().getType().isLegendary() && card.getRules().getType().isCreature() && !parentScreen.getCommanderPage().cardManager.getPool().contains(card)) { - addItem(menu, "Set", "as Commander", parentScreen.getCommanderPage().getIcon(), false, false, new Callback() { - @Override - public void run(Integer result) { - if (result == null || result <= 0) { return; } - - removeCard(card, result); - - CardPool newPool = new CardPool(); - newPool.add(card, result); - parentScreen.getCommanderPage().setCards(newPool); - parentScreen.getCatalogPage().refresh(); //ensure available cards updated based on color identity - } - }); - } - } } private boolean isPartnerCommander(final PaperCard card) { @@ -1407,7 +1472,6 @@ public class FDeckEditor extends TabPageScreen { PaperCard firstCmdr = parentScreen.getDeck().getCommanders().get(0); return !card.getName().equals(firstCmdr.getName()); } - } private static class DraftPackPage extends CatalogPage { @@ -1629,6 +1693,9 @@ public class FDeckEditor extends TabPageScreen { case Commander: DeckPreferences.setCommanderDeck(deckStr); break; + case Oathbreaker: + DeckPreferences.setOathbreakerDeck(deckStr); + break; case TinyLeaders: DeckPreferences.setTinyLeadersDeck(deckStr); break; diff --git a/forge-gui-mobile/src/forge/screens/constructed/LobbyScreen.java b/forge-gui-mobile/src/forge/screens/constructed/LobbyScreen.java index c486061be93..856048571fa 100644 --- a/forge-gui-mobile/src/forge/screens/constructed/LobbyScreen.java +++ b/forge-gui-mobile/src/forge/screens/constructed/LobbyScreen.java @@ -122,6 +122,7 @@ public abstract class LobbyScreen extends LaunchScreen implements ILobbyView { cbVariants.addItem(GameType.MomirBasic); cbVariants.addItem(GameType.MoJhoSto); cbVariants.addItem(GameType.Commander); + cbVariants.addItem(GameType.Oathbreaker); cbVariants.addItem(GameType.TinyLeaders); cbVariants.addItem(GameType.Brawl); cbVariants.addItem(GameType.Planechase); @@ -156,13 +157,13 @@ public abstract class LobbyScreen extends LaunchScreen implements ILobbyView { FThreads.invokeInBackgroundThread(new Runnable() { @Override public void run() { - playerPanels.get(0).initialize(FPref.CONSTRUCTED_P1_DECK_STATE, FPref.COMMANDER_P1_DECK_STATE, FPref.TINY_LEADER_P1_DECK_STATE, FPref.BRAWL_P1_DECK_STATE, DeckType.PRECONSTRUCTED_DECK); - playerPanels.get(1).initialize(FPref.CONSTRUCTED_P2_DECK_STATE, FPref.COMMANDER_P2_DECK_STATE, FPref.TINY_LEADER_P2_DECK_STATE, FPref.BRAWL_P2_DECK_STATE, DeckType.COLOR_DECK); + playerPanels.get(0).initialize(FPref.CONSTRUCTED_P1_DECK_STATE, FPref.COMMANDER_P1_DECK_STATE, FPref.OATHBREAKER_P1_DECK_STATE, FPref.TINY_LEADER_P1_DECK_STATE, FPref.BRAWL_P1_DECK_STATE, DeckType.PRECONSTRUCTED_DECK); + playerPanels.get(1).initialize(FPref.CONSTRUCTED_P2_DECK_STATE, FPref.COMMANDER_P2_DECK_STATE, FPref.OATHBREAKER_P2_DECK_STATE, FPref.TINY_LEADER_P2_DECK_STATE, FPref.BRAWL_P2_DECK_STATE, DeckType.COLOR_DECK); if (getNumPlayers() > 2) { - playerPanels.get(2).initialize(FPref.CONSTRUCTED_P3_DECK_STATE, FPref.COMMANDER_P3_DECK_STATE, FPref.TINY_LEADER_P3_DECK_STATE, FPref.BRAWL_P3_DECK_STATE, DeckType.COLOR_DECK); + playerPanels.get(2).initialize(FPref.CONSTRUCTED_P3_DECK_STATE, FPref.COMMANDER_P3_DECK_STATE, FPref.OATHBREAKER_P3_DECK_STATE, FPref.TINY_LEADER_P3_DECK_STATE, FPref.BRAWL_P3_DECK_STATE, DeckType.COLOR_DECK); } if (getNumPlayers() > 3) { - playerPanels.get(3).initialize(FPref.CONSTRUCTED_P4_DECK_STATE, FPref.COMMANDER_P4_DECK_STATE, FPref.TINY_LEADER_P4_DECK_STATE, FPref.BRAWL_P4_DECK_STATE, DeckType.COLOR_DECK); + playerPanels.get(3).initialize(FPref.CONSTRUCTED_P4_DECK_STATE, FPref.COMMANDER_P4_DECK_STATE, FPref.OATHBREAKER_P3_DECK_STATE, FPref.TINY_LEADER_P4_DECK_STATE, FPref.BRAWL_P4_DECK_STATE, DeckType.COLOR_DECK); } /*playerPanels.get(4).initialize(FPref.CONSTRUCTED_P5_DECK_STATE, DeckType.COLOR_DECK); playerPanels.get(5).initialize(FPref.CONSTRUCTED_P6_DECK_STATE, DeckType.COLOR_DECK); @@ -350,6 +351,7 @@ public abstract class LobbyScreen extends LaunchScreen implements ILobbyView { lstVariants.addItem(new Variant(GameType.MomirBasic)); lstVariants.addItem(new Variant(GameType.MoJhoSto)); lstVariants.addItem(new Variant(GameType.Commander)); + lstVariants.addItem(new Variant(GameType.Oathbreaker)); lstVariants.addItem(new Variant(GameType.TinyLeaders)); lstVariants.addItem(new Variant(GameType.Brawl)); lstVariants.addItem(new Variant(GameType.Planechase)); @@ -497,9 +499,9 @@ public abstract class LobbyScreen extends LaunchScreen implements ILobbyView { else { panel = new PlayerPanel(this, allowNetworking, i, slot, lobby.mayEdit(i), lobby.hasControl()); if (i == 2) { - panel.initialize(FPref.CONSTRUCTED_P3_DECK_STATE, FPref.COMMANDER_P3_DECK_STATE, FPref.TINY_LEADER_P3_DECK_STATE, FPref.BRAWL_P3_DECK_STATE, DeckType.COLOR_DECK); + panel.initialize(FPref.CONSTRUCTED_P3_DECK_STATE, FPref.COMMANDER_P3_DECK_STATE, FPref.OATHBREAKER_P3_DECK_STATE, FPref.TINY_LEADER_P3_DECK_STATE, FPref.BRAWL_P3_DECK_STATE, DeckType.COLOR_DECK); } else if (i == 3) { - panel.initialize(FPref.CONSTRUCTED_P4_DECK_STATE, FPref.COMMANDER_P4_DECK_STATE, FPref.TINY_LEADER_P4_DECK_STATE, FPref.BRAWL_P4_DECK_STATE, DeckType.COLOR_DECK); + panel.initialize(FPref.CONSTRUCTED_P4_DECK_STATE, FPref.COMMANDER_P4_DECK_STATE, FPref.OATHBREAKER_P4_DECK_STATE, FPref.TINY_LEADER_P4_DECK_STATE, FPref.BRAWL_P4_DECK_STATE, DeckType.COLOR_DECK); } playerPanels.add(panel); playersScroll.add(panel); @@ -554,6 +556,12 @@ public abstract class LobbyScreen extends LaunchScreen implements ILobbyView { playerPanel.getCommanderDeckChooser().saveState(); } } + else if (hasVariant(GameType.Oathbreaker)) { + deck = playerPanel.getOathbreakerDeck(); + if (deck != null) { + playerPanel.getOathbreakerDeckChooser().saveState(); + } + } else if (hasVariant(GameType.TinyLeaders)) { deck = playerPanel.getTinyLeadersDeck(); if (deck != null) { diff --git a/forge-gui-mobile/src/forge/screens/constructed/PlayerPanel.java b/forge-gui-mobile/src/forge/screens/constructed/PlayerPanel.java index f712bf87370..166d6cc7aa5 100644 --- a/forge-gui-mobile/src/forge/screens/constructed/PlayerPanel.java +++ b/forge-gui-mobile/src/forge/screens/constructed/PlayerPanel.java @@ -71,12 +71,13 @@ public class PlayerPanel extends FContainer { private final FLabel btnDeck = new FLabel.ButtonBuilder().text("Loading Deck...").build(); private final FLabel btnSchemeDeck = new FLabel.ButtonBuilder().text("Scheme Deck: Random Generated Deck").build(); private final FLabel btnCommanderDeck = new FLabel.ButtonBuilder().text("Commander Deck: Random Generated Deck").build(); + private final FLabel btnOathbreakDeck = new FLabel.ButtonBuilder().text("Oathbreaker Deck: Random Generated Deck").build(); private final FLabel btnTinyLeadersDeck = new FLabel.ButtonBuilder().text("Tiny Leaders Deck: Random Generated Deck").build(); private final FLabel btnBrawlDeck = new FLabel.ButtonBuilder().text("Brawl Deck: Random Generated Deck").build(); private final FLabel btnPlanarDeck = new FLabel.ButtonBuilder().text("Planar Deck: Random Generated Deck").build(); private final FLabel btnVanguardAvatar = new FLabel.ButtonBuilder().text("Vanguard Avatar: Random").build(); - private final FDeckChooser deckChooser, lstSchemeDecks, lstCommanderDecks, lstTinyLeadersDecks, lstBrawlDecks, lstPlanarDecks; + private final FDeckChooser deckChooser, lstSchemeDecks, lstCommanderDecks, lstOathbreakerDecks, lstTinyLeadersDecks, lstBrawlDecks, lstPlanarDecks; private final FVanguardChooser lstVanguardAvatars; public PlayerPanel(final LobbyScreen screen0, final boolean allowNetworking0, final int index0, final LobbySlot slot, final boolean mayEdit0, final boolean mayControl0) { @@ -124,6 +125,17 @@ public class PlayerPanel extends FContainer { } } }); + lstOathbreakerDecks = new FDeckChooser(GameType.Oathbreaker, isAi, new FEventHandler() { + @Override + public void handleEvent(FEvent e) { + if( ((DeckManager)e.getSource()).getSelectedItem() != null) { + btnOathbreakDeck.setText("Oathbreaker Deck: " + ((DeckManager) e.getSource()).getSelectedItem().getName()); + lstOathbreakerDecks.saveState(); + }else{ + btnOathbreakDeck.setText("Oathbreaker Deck"); + } + } + }); lstTinyLeadersDecks = new FDeckChooser(GameType.TinyLeaders, isAi, new FEventHandler() { @Override public void handleEvent(FEvent e) { @@ -212,6 +224,14 @@ public class PlayerPanel extends FContainer { Forge.openScreen(lstCommanderDecks); } }); + add(btnOathbreakDeck); + btnOathbreakDeck.setCommand(new FEventHandler() { + @Override + public void handleEvent(FEvent e) { + lstOathbreakerDecks.setHeaderCaption("Select Oathbreaker Deck for " + txtPlayerName.getText()); + Forge.openScreen(lstOathbreakerDecks); + } + }); add(btnTinyLeadersDeck); btnTinyLeadersDeck.setCommand(new FEventHandler() { @Override @@ -262,11 +282,12 @@ public class PlayerPanel extends FContainer { setMayControl(mayControl0); } - public void initialize(FPref savedStateSetting, FPref savedStateSettingCommander, FPref savedStateSettingTinyLeader, FPref savedStateSettingBrawl, DeckType defaultDeckType) { + public void initialize(FPref savedStateSetting, FPref savedStateSettingCommander, FPref savedStateSettingOathbreaker, FPref savedStateSettingTinyLeader, FPref savedStateSettingBrawl, DeckType defaultDeckType) { deckChooser.initialize(savedStateSetting, defaultDeckType); lstCommanderDecks.initialize(savedStateSettingCommander, DeckType.COMMANDER_DECK); - lstTinyLeadersDecks.initialize(savedStateSettingTinyLeader, DeckType.TINY_LEADERS_DECKS); - lstBrawlDecks.initialize(savedStateSettingBrawl, DeckType.BRAWL_DECKS); + lstOathbreakerDecks.initialize(savedStateSettingOathbreaker, DeckType.OATHBREAKER_DECK); + lstTinyLeadersDecks.initialize(savedStateSettingTinyLeader, DeckType.TINY_LEADERS_DECK); + lstBrawlDecks.initialize(savedStateSettingBrawl, DeckType.BRAWL_DECK); lstPlanarDecks.initialize(null, DeckType.RANDOM_DECK); lstSchemeDecks.initialize(null, DeckType.RANDOM_DECK); } @@ -312,6 +333,10 @@ public class PlayerPanel extends FContainer { btnCommanderDeck.setBounds(x, y, w, fieldHeight); y += dy; } + else if (btnOathbreakDeck.isVisible()) { + btnOathbreakDeck.setBounds(x, y, w, fieldHeight); + y += dy; + } else if (btnTinyLeadersDeck.isVisible()) { btnTinyLeadersDeck.setBounds(x, y, w, fieldHeight); y += dy; @@ -342,7 +367,7 @@ public class PlayerPanel extends FContainer { if (!btnDeck.isVisible()) { rows--; } - if (btnCommanderDeck.isVisible() || btnTinyLeadersDeck.isVisible() || btnBrawlDeck.isVisible()) { + if (btnCommanderDeck.isVisible() || btnOathbreakDeck.isVisible() || btnTinyLeadersDeck.isVisible() || btnBrawlDeck.isVisible()) { rows++; } if (btnSchemeDeck.isVisible()) { @@ -460,6 +485,7 @@ public class PlayerPanel extends FContainer { public void updateVariantControlsVisibility() { boolean isCommanderApplied = false; + boolean isOathbreakerApplied = false; boolean isTinyLeadersApplied = false; boolean isBrawlApplied = false; boolean isPlanechaseApplied = false; @@ -483,6 +509,10 @@ public class PlayerPanel extends FContainer { isCommanderApplied = true; isDeckBuildingAllowed = false; //Commander deck replaces basic deck, so hide that break; + case Oathbreaker: + isOathbreakerApplied = true; + isDeckBuildingAllowed = false; //Oathbreaker deck replaces basic deck, so hide that + break; case TinyLeaders: isTinyLeadersApplied = true; isDeckBuildingAllowed = false; //Tiny Leaders deck replaces basic deck, so hide that @@ -507,6 +537,7 @@ public class PlayerPanel extends FContainer { btnDeck.setVisible(isDeckBuildingAllowed); btnCommanderDeck.setVisible(isCommanderApplied && mayEdit); + btnOathbreakDeck.setVisible(isOathbreakerApplied && mayEdit); btnTinyLeadersDeck.setVisible(isTinyLeadersApplied && mayEdit); btnBrawlDeck.setVisible(isBrawlApplied && mayEdit); @@ -760,6 +791,10 @@ public class PlayerPanel extends FContainer { return lstCommanderDecks; } + public FDeckChooser getOathbreakerDeckChooser() { + return lstOathbreakerDecks; + } + public FDeckChooser getTinyLeadersDeckChooser() { return lstTinyLeadersDecks; } @@ -768,13 +803,14 @@ public class PlayerPanel extends FContainer { return lstBrawlDecks; } - public Deck getDeck() { return deckChooser.getDeck(); } - public Deck getCommanderDeck() { - return lstCommanderDecks.getDeck(); + public Deck getCommanderDeck() { return lstCommanderDecks.getDeck(); } + + public Deck getOathbreakerDeck() { + return lstOathbreakerDecks.getDeck(); } public Deck getTinyLeadersDeck() { diff --git a/forge-gui/res/defaults/editor.xml b/forge-gui/res/defaults/editor.xml index 8beb854381d..558ea9e46a9 100644 --- a/forge-gui/res/defaults/editor.xml +++ b/forge-gui/res/defaults/editor.xml @@ -15,6 +15,7 @@ EDITOR_CATALOG EDITOR_ALLDECKS EDITOR_COMMANDER + EDITOR_OATHBREAKER EDITOR_BRAWL EDITOR_TINY_LEADERS EDITOR_DECKGEN diff --git a/forge-gui/res/formats/Casual/Oathbreaker.txt b/forge-gui/res/formats/Casual/Oathbreaker.txt new file mode 100644 index 00000000000..7fda97d3b03 --- /dev/null +++ b/forge-gui/res/formats/Casual/Oathbreaker.txt @@ -0,0 +1,6 @@ +[format] +Name:Oathbreaker +Type:Casual +Subtype:Commander +Order:141 +Banned:Adriana's Valor; Advantageous Proclamation; Assemble the Rank and Vile; Backup Plan; Brago's Favor; Double Stroke; Echoing Boon; Emissary's Ploy; Hired Heist; Hold the Perimeter; Hymn of the Wilds; Immediate Action; Incendiary Dissent; Iterative Analysis; Muzzio's Preparations; Natural Unity; Power Play; Secret Summoning; Secrets of Paradise; Sentinel Dispatch; Sovereign's Realm; Summoner's Bond; Unexpected Potential; Weight Advantage; Worldknit; Amulet of Quoz; Bronze Tablet; Contract from Below; Darkpact; Demonic Attorney; Jeweled Bird; Rebirth; Tempest Efreet; Timmerian Fiends; Chaos Orb; Falling Star; Shahrazad; Ad Nauseam; Ancestral Recall; Balance; Biorhythm; Black Lotus; Channel; Doomsday; Emrakul, the Aeons Torn; Expropriate; Fastbond; Gifts Ungiven; Griselbrand; High Tide; Library of Alexandria; Limited Resources; Lion’s Eye Diamond; Mana Crypt; Mana Geyser; Mana Vault; Mox Emerald; Mox Jet; Mox Pearl; Mox Ruby; Mox Sapphire; Natural Order; Painter's Servant; Panoptic Mirror; Primal Surge; Recurring Nightmare; Saheeli, the Gifted; Sol Ring; Sundering Titan; Sway of the Stars; Sylvan Primordial; Time Vault; Time Walk; Tinker; Tolarian Academy; Tooth and Nail; Trade Secrets; Upheaval; Worldfire; Yawgmoth's Bargain diff --git a/forge-gui/res/languages/de-DE.properties b/forge-gui/res/languages/de-DE.properties index f88c0475c08..d7a138eb8db 100644 --- a/forge-gui/res/languages/de-DE.properties +++ b/forge-gui/res/languages/de-DE.properties @@ -23,6 +23,7 @@ lblBacktoHome=Zum Hauptmenü lblDeckEditor=Deck-Editor lblCloseEditor=Schließe Editor lblCommanderDeckEditor=Commander-Deck-Editor +lblOathbreakerDeckEditor=Eidbrecher-Deck-Editor lblTinyLeadersDeckEditor=Kleine-Anführer-Deck-Editor lblBrawlDeckEditor=Brawl-Deck-Editor lblDraftDeckEditor=Draft-Deck-Editor @@ -387,6 +388,8 @@ lblDeckManager=Deck Manager lblVanguardDesc=Jeder Spieler hat eine eigene spielbeeinflussende \"Avatar\"-Karte. lblCommander=Commander lblCommanderDesc=Jeder Spieler hat eine legendäre \"General\"-Karte, welche (fast) jederzeit gespielt werden kann und die Farben des Decks bestimmt. +lblOathbreaker=Eidbrecher +lblOathbreakerDesc=Jeder Spieler hat eine Planeswalker-Karte als "Eidbrecher", die jederzeit gewirkt werden kann und die Deckfarben festlegt. Jeder Spieler hat auch einen Signaturzauber, der gewirkt werden kann, wenn sein Eidbrecher auf dem Schlachtfeld ist. lblTinyLeaders=Kleine Anführer lblTinyLeadersDesc=Jeder Spieler hat eine legendäre \"General\"-Karte, welche (fast) jederzeit gespielt werden kann und die Farben des Decks bestimmt. Alle Karten haben umgewandelte Manakosten von max. 3. lblBrawl=Brawl @@ -525,6 +528,7 @@ lblConstructedDecks=Konstruierte Decks lblCommanderDecks=Commander Decks lblRandomCommanderDecks=Zufälliges Commander Deck lblRandomCommanderCard-basedDecks=Zufälliges Commander Deck (kartenbasiert) +lblOathbreakerDecks=Eidbrecher-Decks lblTinyLeadersDecks=Kleine-Anführer-Decks lblBrawlDecks=Brawl Decks lblSchemeDecks=Komplott-Decks @@ -781,6 +785,8 @@ lblfromdeck=vom Deck lbltosideboard=zum Sideboard lblfromsideboard=vom Sideboard lblascommander=als Kommandeur +lblasoathbreaker=als Eidbrecher +lblassignaturespell=als Signaturzauber lblasavatar=als Avatar lblfromschemedeck=vom Komplottdeck lblfromplanardeck=vom Weltendeck diff --git a/forge-gui/res/languages/en-US.properties b/forge-gui/res/languages/en-US.properties index 79e6b35169f..00acfcb4c03 100644 --- a/forge-gui/res/languages/en-US.properties +++ b/forge-gui/res/languages/en-US.properties @@ -23,7 +23,8 @@ lblBacktoHome=Back to Home lblDeckEditor=Deck Editor lblCloseEditor=Close Editor lblCommanderDeckEditor=Commander Deck Editor -lblTinyLeadersDeckEditor=Tiny Leaders DeckEditor +lblOathbreakerDeckEditor=Oathbreaker Deck Editor +lblTinyLeadersDeckEditor=Tiny Leaders Deck Editor lblBrawlDeckEditor=Brawl Deck Editor lblDraftDeckEditor=Draft Deck Editor lblSealedDeckEditor=Sealed Deck Editor @@ -387,6 +388,8 @@ lblDeckManager=Deck Manager lblVanguardDesc=Each player has a special \"Avatar\" card that affects the game. lblCommander=Commander lblCommanderDesc=Each player has a legendary "General" card which can be cast at any time and determines deck colors. +lblOathbreaker=Oathbreaker +lblOathbreakerDesc=Each player has a Planeswalker card as their "Oathbreaker" which can be cast at any time and determines deck colors. Each player also has a signature spell that can be cast when their Oathbreaker is on the battlefield. lblTinyLeaders=Tiny Leaders lblTinyLeadersDesc=Each player has a legendary \"General\" card which can be cast at any time and determines deck colors. Each card must have CMC less than 4. lblBrawl=Brawl @@ -525,6 +528,7 @@ lblConstructedDecks=Constructed Decks lblCommanderDecks=Commander Decks lblRandomCommanderDecks=Random Commander Decks lblRandomCommanderCard-basedDecks=Random Commander Card-based Decks +lblOathbreakerDecks=Oathbreaker Decks lblTinyLeadersDecks=Tiny Leaders Decks lblBrawlDecks=Brawl Decks lblSchemeDecks=Scheme Decks @@ -781,6 +785,8 @@ lblfromdeck=from deck lbltosideboard=to sideboard lblfromsideboard=from sideboard lblascommander=as commander +lblasoathbreaker=as oathbreaker +lblassignaturespell=as signature spell lblasavatar=as avatar lblfromschemedeck=from scheme deck lblfromplanardeck=from planar deck diff --git a/forge-gui/res/languages/es-es.properties b/forge-gui/res/languages/es-es.properties index c31b9b22dab..bb8da556c04 100644 --- a/forge-gui/res/languages/es-es.properties +++ b/forge-gui/res/languages/es-es.properties @@ -23,8 +23,9 @@ lblBacktoHome=Volver a Inicio lblDeckEditor=Editor de Mazos lblCloseEditor=Cerrar Editor lblCommanderDeckEditor=Editor Mazos Commander +lblOathbreakerDeckEditor=Editor Mazos Oathbreaker lblTinyLeadersDeckEditor=Editor Mazos Tiny Leaders -lblBrawlDeckEditor=Editor Mazos Brawl +lblBrawlDeckEditor=Editor Mazos Brawl lblDraftDeckEditor=Editor Mazo Draft lblSealedDeckEditor=Editor Mazo Sellao lblTokenViewer=Visor de Tokens @@ -387,6 +388,8 @@ lblDeckManager=Gestor de Mazos lblVanguardDesc=Cada jugador tiene una carta especial de "Avatar" que afecta el juego. lblCommander=Commander lblCommanderDesc=Cada jugador tiene una carta legendaria "Comandante" que se puede lanzar en cualquier momento y determina los colores de la baraja. +lblOathbreaker=Oathbreaker +lblOathbreakerDesc=Cada jugador tiene una carta de Planeswalker como su "Oathbreaker" que se puede lanzar en cualquier momento y determina los colores de la baraja. Cada jugador también tiene un hechizo de firma que se puede lanzar cuando su Oathbreaker está en el campo de batalla. lblTinyLeaders=Tiny Leaders lblTinyLeadersDesc=Cada jugador tiene una carta legendaria "Comandante" que se puede lanzar en cualquier momento y determina los colores de la baraja. Cada carta debe tener CMC menos de 4. lblBrawl=Brawl @@ -525,6 +528,7 @@ lblConstructedDecks=Mazos Construido lblCommanderDecks=Mazos Commander lblRandomCommanderDecks=Mazos Commander Aleatorios lblRandomCommanderCard-basedDecks=Mazos Commander Aleatorios Basados en Cartas +lblOathbreakerDecks=Mazos Oathbreaker lblTinyLeadersDecks=Mazos Tiny Leaders lblBrawlDecks=Mazos Brawl lblSchemeDecks=Mazos de Fenómenos (Scheme) @@ -781,6 +785,8 @@ lblfromdeck=del mazo lbltosideboard=al banquillo lblfromsideboard=del banquillo lblascommander=como comandante +lblasoathbreaker=como oathbreaker +lblassignaturespell=como hechizo de firma lblasavatar=como avatar lblfromschemedeck=del mazo de escenario lblfromplanardeck=del mazo planar diff --git a/forge-gui/src/main/java/forge/achievement/ConstructedAchievements.java b/forge-gui/src/main/java/forge/achievement/ConstructedAchievements.java index ba76a031eb9..1c55df40b6f 100644 --- a/forge-gui/src/main/java/forge/achievement/ConstructedAchievements.java +++ b/forge-gui/src/main/java/forge/achievement/ConstructedAchievements.java @@ -15,6 +15,7 @@ public class ConstructedAchievements extends AchievementCollection { add(new VariantWins(GameType.MomirBasic, 25, 50, 100)); add(new VariantWins(GameType.MoJhoSto, 25, 50, 100)); add(new VariantWins(GameType.Commander, 25, 50, 100)); + add(new VariantWins(GameType.Oathbreaker, 25, 50, 100)); add(new VariantWins(GameType.TinyLeaders, 25, 50, 100)); add(new VariantWins(GameType.Brawl, 25, 50, 100)); add(new VariantWins(GameType.Planechase, 25, 50, 100)); diff --git a/forge-gui/src/main/java/forge/deck/CardRelationMatrixGenerator.java b/forge-gui/src/main/java/forge/deck/CardRelationMatrixGenerator.java index 440b6d3950f..c8ef0a89a58 100644 --- a/forge-gui/src/main/java/forge/deck/CardRelationMatrixGenerator.java +++ b/forge-gui/src/main/java/forge/deck/CardRelationMatrixGenerator.java @@ -34,42 +34,34 @@ public final class CardRelationMatrixGenerator { public static final int MIN_REQUIRED_CONNECTIONS = 14; public static boolean initialize(){ - List formatStrings = new ArrayList<>(); -/* formatStrings.add(FModel.getFormats().getStandard().getName()); - formatStrings.add(FModel.getFormats().getModern().getName());*/ - formatStrings.add(DeckFormat.Commander.toString()); - - for (String formatString : formatStrings){ - if(!initializeFormat(formatString)){ - return false; - } - } - return true; + return initializeFormat(DeckFormat.Commander) && initializeFormat(DeckFormat.Oathbreaker); } /** Try to load matrix .dat files, otherwise check for deck folders and build .dat, otherwise return false **/ - public static boolean initializeFormat(String format){ - HashMap>> formatMap = CardThemedMatrixIO.loadMatrix(format); - if(formatMap==null) { - if (CardThemedMatrixIO.getMatrixFolder(format).exists()) { - if(format.equals(FModel.getFormats().getStandard().getName())){ + public static boolean initializeFormat(DeckFormat format){ + String formatName = format.toString(); + HashMap>> formatMap = CardThemedMatrixIO.loadMatrix(formatName); + if (formatMap==null) { + if (CardThemedMatrixIO.getMatrixFolder(formatName).exists()) { + if (formatName.equals(FModel.getFormats().getStandard().getName())){ formatMap=initializeFormat(FModel.getFormats().getStandard()); - }else if(format.equals(FModel.getFormats().getModern().getName())){ - formatMap=initializeFormat(FModel.getFormats().getModern()); - }else{ - formatMap=initializeCommanderFormat(); } - CardThemedMatrixIO.saveMatrix(format, formatMap); + else if (formatName.equals(FModel.getFormats().getModern().getName())){ + formatMap=initializeFormat(FModel.getFormats().getModern()); + } + else{ + formatMap=initializeCommanderFormat(format); + } + CardThemedMatrixIO.saveMatrix(formatName, formatMap); } else { return false; } } - cardPools.put(format, formatMap); + cardPools.put(formatName, formatMap); return true; } public static HashMap>> initializeFormat(GameFormat format){ - IStorage decks = new StorageImmediatelySerialized("Generator", new DeckStorage(new File(ForgeConstants.DECK_GEN_DIR+ForgeConstants.PATH_SEPARATOR+format.getName()), ForgeConstants.DECK_GEN_DIR, false), true); @@ -100,7 +92,6 @@ public final class CardRelationMatrixGenerator { //Todo: Not sure what was failing here } } - } } } @@ -137,10 +128,9 @@ public final class CardRelationMatrixGenerator { return cardPools; } - public static HashMap>> initializeCommanderFormat(){ - + public static HashMap>> initializeCommanderFormat(DeckFormat format){ IStorage decks = new StorageImmediatelySerialized("Generator", - new DeckStorage(new File(ForgeConstants.DECK_GEN_DIR,DeckFormat.Commander.toString()), + new DeckStorage(new File(ForgeConstants.DECK_GEN_DIR, format.toString()), ForgeConstants.DECK_GEN_DIR, false), true); @@ -164,7 +154,7 @@ public final class CardRelationMatrixGenerator { new Predicate() { @Override public boolean apply(CardRules rules) { - return DeckFormat.Commander.isLegalCommander(rules); + return format.isLegalCommander(rules); } }, PaperCard.FN_GET_RULES))); diff --git a/forge-gui/src/main/java/forge/deck/CommanderDeckGenerator.java b/forge-gui/src/main/java/forge/deck/CommanderDeckGenerator.java index 269a6fc482b..88938d11d34 100644 --- a/forge-gui/src/main/java/forge/deck/CommanderDeckGenerator.java +++ b/forge-gui/src/main/java/forge/deck/CommanderDeckGenerator.java @@ -19,17 +19,19 @@ import java.util.List; */ public class CommanderDeckGenerator extends DeckProxy implements Comparable { public static List getCommanderDecks(final DeckFormat format, boolean isForAi, boolean isCardGen){ - if(format.equals(DeckFormat.Brawl)){ + if (format.equals(DeckFormat.Brawl)){ return getBrawlDecks(format, isForAi, isCardGen); } ItemPool uniqueCards; - if(isCardGen){ + if (isCardGen){ uniqueCards = new ItemPool(PaperCard.class); - Iterable legendNames=CardRelationMatrixGenerator.cardPools.get(DeckFormat.Commander.toString()).keySet(); - for(String legendName:legendNames) { + String matrixKey = (format.equals(DeckFormat.TinyLeaders) ? DeckFormat.Commander : format).toString(); //use Commander for Tiny Leaders + Iterable legendNames = CardRelationMatrixGenerator.cardPools.get(matrixKey).keySet(); + for (String legendName : legendNames) { uniqueCards.add(FModel.getMagicDb().getCommonCards().getUniqueByName(legendName)); } - }else { + } + else { uniqueCards = ItemPool.createFrom(FModel.getMagicDb().getCommonCards().getUniqueCards(), PaperCard.class); } Predicate canPlay = isForAi ? DeckGeneratorBase.AI_CAN_PLAY : DeckGeneratorBase.HUMAN_CAN_PLAY; @@ -43,7 +45,7 @@ public class CommanderDeckGenerator extends DeckProxy implements Comparable decks = new ArrayList(); - for(PaperCard legend: legends) { + for (PaperCard legend: legends) { decks.add(new CommanderDeckGenerator(legend, format, isForAi, isCardGen)); } return decks; @@ -51,14 +53,15 @@ public class CommanderDeckGenerator extends DeckProxy implements Comparable getBrawlDecks(final DeckFormat format, boolean isForAi, boolean isCardGen){ ItemPool uniqueCards; - if(isCardGen){ + if (isCardGen){ uniqueCards = new ItemPool(PaperCard.class); - //TODO: upate to actual Brawl model from real Brawl decks + //TODO: update to actual Brawl model from real Brawl decks Iterable legendNames=CardArchetypeLDAGenerator.ldaPools.get(FModel.getFormats().getStandard().getName()).keySet(); - for(String legendName:legendNames) { + for (String legendName : legendNames) { uniqueCards.add(FModel.getMagicDb().getCommonCards().getUniqueByName(legendName)); } - }else { + } + else { uniqueCards = ItemPool.createFrom(FModel.getMagicDb().getCommonCards().getUniqueCards(), PaperCard.class); } Predicate canPlay = isForAi ? DeckGeneratorBase.AI_CAN_PLAY : DeckGeneratorBase.HUMAN_CAN_PLAY; @@ -68,7 +71,7 @@ public class CommanderDeckGenerator extends DeckProxy implements Comparable decks = new ArrayList(); - for(PaperCard legend: legends) { + for (PaperCard legend: legends) { decks.add(new CommanderDeckGenerator(legend, format, isForAi, isCardGen)); } return decks; @@ -80,7 +83,6 @@ public class CommanderDeckGenerator extends DeckProxy implements Comparable getAllOathbreakerDecks() { + return getAllOathbreakerDecks(null); + } + public static Iterable getAllOathbreakerDecks(final Predicate filter) { + final List result = new ArrayList(); + addDecksRecursivelly("Oathbreaker", GameType.Oathbreaker, result, "", FModel.getDecks().getOathbreaker(), filter); + return result; + } + public static Iterable getAllTinyLeadersDecks() { return getAllTinyLeadersDecks(null); } diff --git a/forge-gui/src/main/java/forge/deck/DeckType.java b/forge-gui/src/main/java/forge/deck/DeckType.java index 4448180c5c4..2b25e3533a4 100644 --- a/forge-gui/src/main/java/forge/deck/DeckType.java +++ b/forge-gui/src/main/java/forge/deck/DeckType.java @@ -9,12 +9,13 @@ public enum DeckType { COMMANDER_DECK("lblCommanderDecks"), RANDOM_COMMANDER_DECK("lblRandomCommanderDecks"), RANDOM_CARDGEN_COMMANDER_DECK("lblRandomCommanderCard-basedDecks"), - TINY_LEADERS_DECKS("lblTinyLeadersDecks"), - BRAWL_DECKS("lblBrawlDecks"), - SCHEME_DECKS("lblSchemeDecks"), - PLANAR_DECKS("lblPlanarDecks"), - DRAFT_DECKS("lblDraftDecks"), - SEALED_DECKS("lblSealedDecks"), + OATHBREAKER_DECK("lblOathbreakerDecks"), + TINY_LEADERS_DECK("lblTinyLeadersDecks"), + BRAWL_DECK("lblBrawlDecks"), + SCHEME_DECK("lblSchemeDecks"), + PLANAR_DECK("lblPlanarDecks"), + DRAFT_DECK("lblDraftDecks"), + SEALED_DECK("lblSealedDecks"), PRECONSTRUCTED_DECK("lblPreconstructedDecks"), QUEST_OPPONENT_DECK("lblQuestOpponentDecks"), COLOR_DECK("lblRandomColorDecks"), diff --git a/forge-gui/src/main/java/forge/deck/DeckgenUtil.java b/forge-gui/src/main/java/forge/deck/DeckgenUtil.java index 9ace1b8cbbd..0f27b16d038 100644 --- a/forge-gui/src/main/java/forge/deck/DeckgenUtil.java +++ b/forge-gui/src/main/java/forge/deck/DeckgenUtil.java @@ -603,7 +603,7 @@ public class DeckgenUtil { final Deck deck; IDeckGenPool cardDb; DeckGeneratorBase gen = null; - PaperCard selectedPartner=null; + PaperCard selectedPartner = null; List preSelectedCards = new ArrayList<>(); if(isCardGen){ if(format.equals(DeckFormat.Brawl)){//TODO: replace with actual Brawl based data @@ -623,7 +623,8 @@ public class DeckgenUtil { } }else { List> potentialCards = new ArrayList<>(); - potentialCards.addAll(CardRelationMatrixGenerator.cardPools.get(DeckFormat.Commander.toString()).get(commander.getName())); + String matrixKey = (format.equals(DeckFormat.TinyLeaders) ? DeckFormat.Commander : format).toString(); //use Commander for Tiny Leaders + potentialCards.addAll(CardRelationMatrixGenerator.cardPools.get(matrixKey).get(commander.getName())); Collections.shuffle(potentialCards, MyRandom.getRandom()); for(Map.Entry pair:potentialCards){ if(format.isLegalCard(pair.getKey())) { @@ -632,18 +633,33 @@ public class DeckgenUtil { } } + if (format.equals(DeckFormat.Oathbreaker)) { + //check for signature spells + List signatureSpells = new ArrayList<>(); + for (PaperCard c : preSelectedCards) { + if (c.getRules().canBeSignatureSpell()) { + signatureSpells.add(c); + } + } - //check for partner commanders - List partners=new ArrayList<>(); - for(PaperCard c:preSelectedCards){ - if(c.getRules().canBePartnerCommander()){ - partners.add(c); + if (signatureSpells.size() > 0) { //pass signature spell as partner for simplicity + selectedPartner = signatureSpells.get(MyRandom.getRandom().nextInt(signatureSpells.size())); + preSelectedCards.removeAll(StaticData.instance().getCommonCards().getAllCards(selectedPartner.getName())); } } + else if (commander.getRules().canBePartnerCommander()) { + //check for partner commanders + List partners = new ArrayList<>(); + for (PaperCard c : preSelectedCards) { + if (c.getRules().canBePartnerCommander()) { + partners.add(c); + } + } - if(partners.size()>0&&commander.getRules().canBePartnerCommander()){ - selectedPartner=partners.get(MyRandom.getRandom().nextInt(partners.size())); - preSelectedCards.removeAll(StaticData.instance().getCommonCards().getAllCards(selectedPartner.getName())); + if (partners.size() > 0) { + selectedPartner = partners.get(MyRandom.getRandom().nextInt(partners.size())); + preSelectedCards.removeAll(StaticData.instance().getCommonCards().getAllCards(selectedPartner.getName())); + } } //randomly remove cards int removeCount=0; @@ -666,7 +682,7 @@ public class DeckgenUtil { } preSelectedCards.removeAll(toRemove); preSelectedCards.removeAll(StaticData.instance().getCommonCards().getAllCards(commander.getName())); - gen = new CardThemedCommanderDeckBuilder(commander, selectedPartner,preSelectedCards,forAi,format); + gen = new CardThemedCommanderDeckBuilder(commander, selectedPartner, preSelectedCards, forAi, format); }else{ cardDb = FModel.getMagicDb().getCommonCards(); //shuffle first 400 random cards @@ -674,9 +690,38 @@ public class DeckgenUtil { Predicates.and(format.isLegalCardPredicate(),Predicates.compose(Predicates.or( new CardThemedDeckBuilder.MatchColorIdentity(commander.getRules().getColorIdentity()), DeckGeneratorBase.COLORLESS_CARDS), PaperCard.FN_GET_RULES))); - if(format.equals(DeckFormat.Brawl)){//for Brawl - add additional filterprinted rule to remove old reprints for a consistent look - Iterable colorListFiltered = Iterables.filter(colorList,FModel.getFormats().getStandard().getFilterPrinted()); - colorList=colorListFiltered; + switch (format) { + case Brawl: //for Brawl - add additional filterprinted rule to remove old reprints for a consistent look + colorList = Iterables.filter(colorList,FModel.getFormats().getStandard().getFilterPrinted()); + break; + case Oathbreaker: + //check for signature spells + List signatureSpells = new ArrayList<>(); + for (PaperCard c : colorList) { + if (c.getRules().canBeSignatureSpell()) { + signatureSpells.add(c); + } + } + + if (signatureSpells.size() > 0) { //pass signature spell as partner for simplicity + selectedPartner = signatureSpells.get(MyRandom.getRandom().nextInt(signatureSpells.size())); + } + break; + default: + if (commander.getRules().canBePartnerCommander()) { + //check for partner commanders + List partners = new ArrayList<>(); + for (PaperCard c : colorList) { + if (c.getRules().canBePartnerCommander()) { + partners.add(c); + } + } + + if (partners.size() > 0) { + selectedPartner = partners.get(MyRandom.getRandom().nextInt(partners.size())); + } + } + break; } List cardList = Lists.newArrayList(colorList); Collections.shuffle(cardList, MyRandom.getRandom()); @@ -684,15 +729,16 @@ public class DeckgenUtil { if(cardList.size() shortList = cardList.subList(1, shortlistlength); + List shortList = cardList.subList(0, shortlistlength); shortList.remove(commander); shortList.removeAll(StaticData.instance().getCommonCards().getAllCards(commander.getName())); - gen = new CardThemedCommanderDeckBuilder(commander, selectedPartner,shortList,forAi,format); - + if (selectedPartner != null) { + shortList.remove(selectedPartner); + shortList.removeAll(StaticData.instance().getCommonCards().getAllCards(selectedPartner.getName())); + } + gen = new CardThemedCommanderDeckBuilder(commander, selectedPartner, shortList, forAi, format); } - - gen.setSingleton(true); gen.setUseArtifacts(!FModel.getPreferences().getPrefBoolean(FPref.DECKGEN_ARTIFACTS)); CardPool cards = gen.getDeck(format.getMainRange().getMaximum(), forAi); @@ -707,8 +753,8 @@ public class DeckgenUtil { deck.setDirectory("generated/commander"); deck.getMain().addAll(cards); deck.getOrCreate(DeckSection.Commander).add(commander); - if(selectedPartner!=null){ - deck.getOrCreate(DeckSection.Commander).add(selectedPartner); + if (selectedPartner!=null){ + deck.get(DeckSection.Commander).add(selectedPartner); } return deck; diff --git a/forge-gui/src/main/java/forge/deck/RandomDeckGenerator.java b/forge-gui/src/main/java/forge/deck/RandomDeckGenerator.java index 5b377c50d53..4c2d999abce 100644 --- a/forge-gui/src/main/java/forge/deck/RandomDeckGenerator.java +++ b/forge-gui/src/main/java/forge/deck/RandomDeckGenerator.java @@ -78,6 +78,8 @@ public class RandomDeckGenerator extends DeckProxy implements Comparable allPrefs = new HashMap(); + public static DeckType getSelectedDeckType() { + return selectedDeckType.isEmpty() ? DeckType.CONSTRUCTED_DECK : DeckType.valueOf(selectedDeckType); + } + public static void setSelectedDeckType(DeckType selectedDeckType0) { + String selectedDeckTypeStr = selectedDeckType0 == DeckType.CONSTRUCTED_DECK ? "" : selectedDeckType0.name(); + if (selectedDeckTypeStr.equals(selectedDeckType)) { return; } + selectedDeckType = selectedDeckTypeStr; + save(); + } + public static String getCurrentDeck() { return currentDeck; } @@ -60,6 +72,15 @@ public class DeckPreferences { save(); } + public static String getOathbreakerDeck() { + return oathbreakerDeck; + } + public static void setOathbreakerDeck(String oathbreakerDeck0) { + if (oathbreakerDeck.equals(oathbreakerDeck0)) { return; } + oathbreakerDeck = oathbreakerDeck0; + save(); + } + public static String getTinyLeadersDeck() { return tinyLeadersDeck; } @@ -114,10 +135,12 @@ public class DeckPreferences { final Document document = builder.parse(new File(ForgeConstants.DECK_PREFS_FILE)); final Element root = (Element)document.getElementsByTagName("preferences").item(0); + selectedDeckType = root.getAttribute("selectedDeckType"); currentDeck = root.getAttribute("currentDeck"); draftDeck = root.getAttribute("draftDeck"); sealedDeck = root.getAttribute("sealedDeck"); commanderDeck = root.getAttribute("commanderDeck"); + oathbreakerDeck = root.getAttribute("oathbreakerDeck"); brawlDeck = root.getAttribute("brawlDeck"); tinyLeadersDeck = root.getAttribute("tinyLeadersDeck"); planarDeck = root.getAttribute("planarDeck"); @@ -145,10 +168,12 @@ public class DeckPreferences { Document document = builder.newDocument(); Element root = document.createElement("preferences"); root.setAttribute("type", "decks"); + root.setAttribute("selectedDeckType", selectedDeckType); root.setAttribute("currentDeck", currentDeck); root.setAttribute("draftDeck", draftDeck); root.setAttribute("sealedDeck", sealedDeck); root.setAttribute("commanderDeck", commanderDeck); + root.setAttribute("oathbreakerDeck", oathbreakerDeck); root.setAttribute("brawlDeck", brawlDeck); root.setAttribute("tinyLeadersDeck", tinyLeadersDeck); root.setAttribute("planarDeck", planarDeck); diff --git a/forge-gui/src/main/java/forge/itemmanager/ItemManagerConfig.java b/forge-gui/src/main/java/forge/itemmanager/ItemManagerConfig.java index ddcb85ae686..0280c8ab604 100644 --- a/forge-gui/src/main/java/forge/itemmanager/ItemManagerConfig.java +++ b/forge-gui/src/main/java/forge/itemmanager/ItemManagerConfig.java @@ -70,6 +70,8 @@ public enum ItemManagerConfig { null, null, 4, 0), COMMANDER_SECTION(SColumnUtil.getCatalogDefaultColumns(true), true, false, true, null, null, 1, 1), + OATHBREAKER_SECTION(SColumnUtil.getCatalogDefaultColumns(true), true, false, true, + null, null, 2, 1), WORKSHOP_CATALOG(SColumnUtil.getCatalogDefaultColumns(true), true, true, false, null, null, 4, 0), DECK_VIEWER(SColumnUtil.getDeckViewerDefaultColumns(), false, false, false, diff --git a/forge-gui/src/main/java/forge/limited/CardThemedCommanderDeckBuilder.java b/forge-gui/src/main/java/forge/limited/CardThemedCommanderDeckBuilder.java index ecd7052557e..f981abbc50c 100644 --- a/forge-gui/src/main/java/forge/limited/CardThemedCommanderDeckBuilder.java +++ b/forge-gui/src/main/java/forge/limited/CardThemedCommanderDeckBuilder.java @@ -34,13 +34,13 @@ public class CardThemedCommanderDeckBuilder extends CardThemedDeckBuilder { targetSize=format.getMainRange().getMinimum(); colors = keyCard.getRules().getColorIdentity(); colors = ColorSet.fromMask(colors.getColor() | keyCard.getRules().getColorIdentity().getColor()); - if(secondKeyCard!=null) { + if (secondKeyCard != null && !format.equals(DeckFormat.Oathbreaker)) { colors = ColorSet.fromMask(colors.getColor() | secondKeyCard.getRules().getColorIdentity().getColor()); targetSize--; } numSpellsNeeded = ((Double)Math.floor(targetSize*(getCreaturePercentage()+getSpellPercentage()))).intValue(); numCreaturesToStart = ((Double)Math.ceil(targetSize*(getCreaturePercentage()))).intValue(); - landsNeeded = ((Double)Math.ceil(targetSize*(getLandPercentage()))).intValue();; + landsNeeded = ((Double)Math.ceil(targetSize*(getLandPercentage()))).intValue(); if (logColorsToConsole) { System.out.println(keyCard.getName()); System.out.println("Pre Colors: " + colors.toEnumSet().toString()); diff --git a/forge-gui/src/main/java/forge/match/GameLobby.java b/forge-gui/src/main/java/forge/match/GameLobby.java index 2ba4f814204..9951217dcb3 100644 --- a/forge-gui/src/main/java/forge/match/GameLobby.java +++ b/forge-gui/src/main/java/forge/match/GameLobby.java @@ -231,6 +231,14 @@ public abstract class GameLobby implements IHasGameType { data.appliedVariants.remove(GameType.Archenemy); break; case Commander: + data.appliedVariants.remove(GameType.Oathbreaker); + data.appliedVariants.remove(GameType.TinyLeaders); + data.appliedVariants.remove(GameType.Brawl); + data.appliedVariants.remove(GameType.MomirBasic); + data.appliedVariants.remove(GameType.MoJhoSto); + break; + case Oathbreaker: + data.appliedVariants.remove(GameType.Commander); data.appliedVariants.remove(GameType.TinyLeaders); data.appliedVariants.remove(GameType.Brawl); data.appliedVariants.remove(GameType.MomirBasic); @@ -238,12 +246,14 @@ public abstract class GameLobby implements IHasGameType { break; case TinyLeaders: data.appliedVariants.remove(GameType.Commander); + data.appliedVariants.remove(GameType.Oathbreaker); data.appliedVariants.remove(GameType.Brawl); data.appliedVariants.remove(GameType.MomirBasic); data.appliedVariants.remove(GameType.MoJhoSto); break; case Brawl: data.appliedVariants.remove(GameType.Commander); + data.appliedVariants.remove(GameType.Oathbreaker); data.appliedVariants.remove(GameType.TinyLeaders); data.appliedVariants.remove(GameType.MomirBasic); data.appliedVariants.remove(GameType.MoJhoSto); @@ -254,6 +264,7 @@ public abstract class GameLobby implements IHasGameType { break; case MomirBasic: data.appliedVariants.remove(GameType.Commander); + data.appliedVariants.remove(GameType.Oathbreaker); data.appliedVariants.remove(GameType.TinyLeaders); data.appliedVariants.remove(GameType.Brawl); data.appliedVariants.remove(GameType.Vanguard); @@ -261,6 +272,7 @@ public abstract class GameLobby implements IHasGameType { break; case MoJhoSto: data.appliedVariants.remove(GameType.Commander); + data.appliedVariants.remove(GameType.Oathbreaker); data.appliedVariants.remove(GameType.TinyLeaders); data.appliedVariants.remove(GameType.Brawl); data.appliedVariants.remove(GameType.Vanguard); @@ -281,6 +293,8 @@ public abstract class GameLobby implements IHasGameType { if (variant == currentGameType) { if (hasVariant(GameType.Commander)) { currentGameType = GameType.Commander; + } else if (hasVariant(GameType.Oathbreaker)) { + currentGameType = GameType.Oathbreaker; } else if (hasVariant(GameType.TinyLeaders)) { currentGameType = GameType.TinyLeaders; } else if (hasVariant(GameType.Brawl)) { @@ -348,7 +362,7 @@ public abstract class GameLobby implements IHasGameType { SOptionPane.showMessageDialog(TextUtil.concatNoSpace("Please specify a deck for ", slot.getName())); return null; } - if (hasVariant(GameType.Commander) || hasVariant(GameType.TinyLeaders) || hasVariant(GameType.Brawl)) { + if (hasVariant(GameType.Commander) || hasVariant(GameType.Oathbreaker) || hasVariant(GameType.TinyLeaders) || hasVariant(GameType.Brawl)) { if (!slot.getDeck().has(DeckSection.Commander)) { SOptionPane.showMessageDialog(TextUtil.concatNoSpace(slot.getName(), " doesn't have a commander")); return null; @@ -360,12 +374,14 @@ public abstract class GameLobby implements IHasGameType { GameType autoGenerateVariant = null; boolean isCommanderMatch = false; + boolean isOathbreakerMatch = false; boolean isTinyLeadersMatch = false; boolean isBrawlMatch = false; if (!variantTypes.isEmpty()) { + isOathbreakerMatch = variantTypes.contains(GameType.Oathbreaker); isTinyLeadersMatch = variantTypes.contains(GameType.TinyLeaders); isBrawlMatch = variantTypes.contains(GameType.Brawl); - isCommanderMatch = isBrawlMatch || isTinyLeadersMatch || variantTypes.contains(GameType.Commander); + isCommanderMatch = isBrawlMatch || isTinyLeadersMatch || isOathbreakerMatch || variantTypes.contains(GameType.Commander); if (!isCommanderMatch) { for (final GameType variant : variantTypes) { if (variant.isAutoGenerated()) { @@ -426,7 +442,11 @@ public abstract class GameLobby implements IHasGameType { } else { if (isCommanderMatch) { - final GameType commanderGameType = isTinyLeadersMatch ? GameType.TinyLeaders : isBrawlMatch ? GameType.Brawl : GameType.Commander; + final GameType commanderGameType = + isOathbreakerMatch ? GameType.Oathbreaker : + isTinyLeadersMatch ? GameType.TinyLeaders : + isBrawlMatch ? GameType.Brawl : + GameType.Commander; if (checkLegality) { final String errMsg = commanderGameType.getDeckFormat().getDeckConformanceProblem(deck); if (errMsg != null) { diff --git a/forge-gui/src/main/java/forge/model/CardCollections.java b/forge-gui/src/main/java/forge/model/CardCollections.java index 611cf8ebd69..9f1e16d5598 100644 --- a/forge-gui/src/main/java/forge/model/CardCollections.java +++ b/forge-gui/src/main/java/forge/model/CardCollections.java @@ -41,6 +41,7 @@ public class CardCollections { private IStorage scheme; private IStorage plane; private IStorage commander; + private IStorage oathbreaker; private IStorage tinyLeaders; private IStorage brawl; @@ -112,6 +113,14 @@ public class CardCollections { return commander; } + public IStorage getOathbreaker() { + if (oathbreaker == null) { + oathbreaker = new StorageImmediatelySerialized("Oathbreaker decks", + new DeckStorage(new File(ForgeConstants.DECK_OATHBREAKER_DIR), ForgeConstants.DECK_BASE_DIR)); + } + return oathbreaker; + } + public IStorage getTinyLeaders() { if (tinyLeaders == null) { tinyLeaders = new StorageImmediatelySerialized("Tiny Leaders decks", diff --git a/forge-gui/src/main/java/forge/model/FModel.java b/forge-gui/src/main/java/forge/model/FModel.java index 549c7ca966e..edbe8779551 100644 --- a/forge-gui/src/main/java/forge/model/FModel.java +++ b/forge-gui/src/main/java/forge/model/FModel.java @@ -166,8 +166,10 @@ public final class FModel { new File(ForgeConstants.USER_FORMATS_DIR), preferences.getPrefBoolean(FPref.LOAD_HISTORIC_FORMATS))); magicDb.setStandardPredicate(formats.getStandard().getFilterRules()); - magicDb.setBrawlPredicate(formats.get("Brawl").getFilterRules()); magicDb.setModernPredicate(formats.getModern().getFilterRules()); + magicDb.setCommanderPredicate(formats.get("Commander").getFilterRules()); + magicDb.setOathbreakerPredicate(formats.get("Oathbreaker").getFilterRules()); + magicDb.setBrawlPredicate(formats.get("Brawl").getFilterRules()); magicDb.setFilteredHandsEnabled(preferences.getPrefBoolean(FPref.FILTERED_HANDS)); magicDb.setMulliganRule(MulliganDefs.MulliganRule.valueOf(preferences.getPref(FPref.MULLIGAN_RULE))); diff --git a/forge-gui/src/main/java/forge/planarconquest/ConquestUtil.java b/forge-gui/src/main/java/forge/planarconquest/ConquestUtil.java index 8a2256eb8c8..0ec44d20da0 100644 --- a/forge-gui/src/main/java/forge/planarconquest/ConquestUtil.java +++ b/forge-gui/src/main/java/forge/planarconquest/ConquestUtil.java @@ -143,7 +143,7 @@ public class ConquestUtil { //remove any cards that aren't allowed in deck due to color identity if (colorIdentity != MagicColor.ALL_COLORS) { - Predicate pred = DeckFormat.Commander.isLegalCardForCommanderOrLegalPartnerPredicate(deck.getCommanders()); + Predicate pred = DeckFormat.Commander.isLegalCardForCommanderPredicate(deck.getCommanders()); availableCards.retainAll(Lists.newArrayList(Iterables.filter(availableCards, pred))); } diff --git a/forge-gui/src/main/java/forge/properties/ForgeConstants.java b/forge-gui/src/main/java/forge/properties/ForgeConstants.java index 44d5a6e0c5e..342d2184991 100644 --- a/forge-gui/src/main/java/forge/properties/ForgeConstants.java +++ b/forge-gui/src/main/java/forge/properties/ForgeConstants.java @@ -217,6 +217,7 @@ public final class ForgeConstants { public static final String DECK_SCHEME_DIR = DECK_BASE_DIR + "scheme" + PATH_SEPARATOR; public static final String DECK_PLANE_DIR = DECK_BASE_DIR + "planar" + PATH_SEPARATOR; public static final String DECK_COMMANDER_DIR = DECK_BASE_DIR + "commander" + PATH_SEPARATOR; + public static final String DECK_OATHBREAKER_DIR = DECK_BASE_DIR + "oathbreaker" + PATH_SEPARATOR; public static final String DECK_NET_DIR = DECK_BASE_DIR + "net" + PATH_SEPARATOR; public static final String QUEST_SAVE_DIR = USER_QUEST_DIR + "saves" + PATH_SEPARATOR; public static final String CONQUEST_SAVE_DIR = USER_CONQUEST_DIR + "saves" + PATH_SEPARATOR; @@ -268,6 +269,7 @@ public final class ForgeConstants { DECK_SCHEME_DIR, DECK_PLANE_DIR, DECK_COMMANDER_DIR, + DECK_OATHBREAKER_DIR, DECK_NET_DIR, QUEST_SAVE_DIR, CACHE_TOKEN_PICS_DIR, diff --git a/forge-gui/src/main/java/forge/properties/ForgePreferences.java b/forge-gui/src/main/java/forge/properties/ForgePreferences.java index 517cd3560cd..d4a35b4db97 100644 --- a/forge-gui/src/main/java/forge/properties/ForgePreferences.java +++ b/forge-gui/src/main/java/forge/properties/ForgePreferences.java @@ -43,6 +43,14 @@ public class ForgePreferences extends PreferencesStore { COMMANDER_P6_DECK_STATE(""), COMMANDER_P7_DECK_STATE(""), COMMANDER_P8_DECK_STATE(""), + OATHBREAKER_P1_DECK_STATE(""), + OATHBREAKER_P2_DECK_STATE(""), + OATHBREAKER_P3_DECK_STATE(""), + OATHBREAKER_P4_DECK_STATE(""), + OATHBREAKER_P5_DECK_STATE(""), + OATHBREAKER_P6_DECK_STATE(""), + OATHBREAKER_P7_DECK_STATE(""), + OATHBREAKER_P8_DECK_STATE(""), TINY_LEADER_P1_DECK_STATE(""), TINY_LEADER_P2_DECK_STATE(""), TINY_LEADER_P3_DECK_STATE(""), @@ -252,6 +260,12 @@ public class ForgePreferences extends PreferencesStore { COMMANDER_P5_DECK_STATE, COMMANDER_P6_DECK_STATE, COMMANDER_P7_DECK_STATE, COMMANDER_P8_DECK_STATE }; + public static FPref[] OATHBREAKER_DECK_STATES = { + OATHBREAKER_P1_DECK_STATE, OATHBREAKER_P2_DECK_STATE, + OATHBREAKER_P3_DECK_STATE, OATHBREAKER_P4_DECK_STATE, + OATHBREAKER_P5_DECK_STATE, OATHBREAKER_P6_DECK_STATE, + OATHBREAKER_P7_DECK_STATE, OATHBREAKER_P8_DECK_STATE }; + public static FPref[] TINY_LEADER_DECK_STATES = { TINY_LEADER_P1_DECK_STATE, TINY_LEADER_P2_DECK_STATE, TINY_LEADER_P3_DECK_STATE, TINY_LEADER_P4_DECK_STATE,