From 07cf5201ba18ad2445804e59d6f7e9aed08db287 Mon Sep 17 00:00:00 2001 From: Oleg Agafonov Date: Mon, 27 May 2019 16:17:15 +0400 Subject: [PATCH 01/38] * Added new game mode: Oathbreaker (#5678); --- .../mage/client/dialog/NewTableDialog.java | 13 + .../src/mage/deck/Oathbreaker.java | 215 +++++++++++ .../Mage.Game.OathbreakerFreeForAll/pom.xml | 50 +++ .../src/mage/game/OathbreakerFreeForAll.java | 141 +++++++ .../mage/game/OathbreakerFreeForAllMatch.java | 29 ++ .../mage/game/OathbreakerFreeForAllType.java | 29 ++ Mage.Server.Plugins/pom.xml | 12 +- Mage.Server/config/config.xml | 297 +++++++++----- Mage.Server/pom.xml | 8 + Mage.Server/release/config/config.xml | 361 ++++++++++++------ .../java/mage/server/util/SystemUtil.java | 6 +- ...ureSpellCastOnlyWithOathbreakerEffect.java | 61 +++ .../OathbreakerOnBattlefieldCondition.java | 51 +++ .../java/mage/game/GameCommanderImpl.java | 48 ++- Mage/src/main/java/mage/game/GameImpl.java | 2 +- .../java/mage/game/GameTinyLeadersImpl.java | 2 +- .../watchers/common/CommanderInfoWatcher.java | 11 +- 17 files changed, 1100 insertions(+), 236 deletions(-) create mode 100644 Mage.Server.Plugins/Mage.Deck.Constructed/src/mage/deck/Oathbreaker.java create mode 100644 Mage.Server.Plugins/Mage.Game.OathbreakerFreeForAll/pom.xml create mode 100644 Mage.Server.Plugins/Mage.Game.OathbreakerFreeForAll/src/mage/game/OathbreakerFreeForAll.java create mode 100644 Mage.Server.Plugins/Mage.Game.OathbreakerFreeForAll/src/mage/game/OathbreakerFreeForAllMatch.java create mode 100644 Mage.Server.Plugins/Mage.Game.OathbreakerFreeForAll/src/mage/game/OathbreakerFreeForAllType.java create mode 100644 Mage/src/main/java/mage/abilities/common/SignatureSpellCastOnlyWithOathbreakerEffect.java create mode 100644 Mage/src/main/java/mage/abilities/condition/common/OathbreakerOnBattlefieldCondition.java diff --git a/Mage.Client/src/main/java/mage/client/dialog/NewTableDialog.java b/Mage.Client/src/main/java/mage/client/dialog/NewTableDialog.java index 1fece571293..503f59e6b62 100644 --- a/Mage.Client/src/main/java/mage/client/dialog/NewTableDialog.java +++ b/Mage.Client/src/main/java/mage/client/dialog/NewTableDialog.java @@ -668,6 +668,12 @@ public class NewTableDialog extends MageDialog { return false; } break; + case "Variant Magic - Oathbreaker": + if (!options.getGameType().startsWith("Oathbreaker")) { + JOptionPane.showMessageDialog(MageFrame.getDesktop(), "Deck type Oathbreaker needs also a Oathbreaker game type", "Error", JOptionPane.ERROR_MESSAGE); + return false; + } + break; } // game => deck @@ -704,6 +710,13 @@ public class NewTableDialog extends MageDialog { return false; } break; + case "Oathbreaker Two Player Duel": + case "Oathbreaker Free For All": + if (!options.getDeckType().equals("Variant Magic - Oathbreaker")) { + JOptionPane.showMessageDialog(MageFrame.getDesktop(), "Deck type Oathbreaker needs also a Oathbreaker game type", "Error", JOptionPane.ERROR_MESSAGE); + return false; + } + break; } return true; } diff --git a/Mage.Server.Plugins/Mage.Deck.Constructed/src/mage/deck/Oathbreaker.java b/Mage.Server.Plugins/Mage.Deck.Constructed/src/mage/deck/Oathbreaker.java new file mode 100644 index 00000000000..a8223820aaf --- /dev/null +++ b/Mage.Server.Plugins/Mage.Deck.Constructed/src/mage/deck/Oathbreaker.java @@ -0,0 +1,215 @@ +package mage.deck; + +import mage.abilities.Ability; +import mage.abilities.keyword.PartnerAbility; +import mage.abilities.keyword.PartnerWithAbility; +import mage.cards.Card; +import mage.cards.decks.Deck; +import mage.filter.FilterMana; + +import java.util.*; + +/** + * @author JayDi85 + */ +public class Oathbreaker extends Vintage { + + protected List bannedCommander = new ArrayList<>(); + private static final Map pdAllowed = new HashMap<>(); + + public Oathbreaker() { + super(); + this.name = "Oathbreaker"; + + // banned = vintage + oathbreaker's list: https://weirdcards.org/oathbreaker-ban-list + // last updated 4/4/19 - High Tide banned + banned.add("Ad Nauseam"); + banned.add("Ancestral Recall"); + banned.add("Balance"); + banned.add("Biorhythm"); + banned.add("Black Lotus"); + banned.add("Channel"); + banned.add("Doomsday"); + banned.add("Emrakul, the Aeons Torn"); + banned.add("Expropriate"); + banned.add("Fastbond"); + banned.add("Gifts Ungiven"); + banned.add("Griselbrand"); + banned.add("High Tide"); + banned.add("Library of Alexandria"); + banned.add("Limited Resources"); + banned.add("Lion's Eye Diamond"); + banned.add("Mana Crypt"); + banned.add("Mana Geyser"); + banned.add("Mana Vault"); + banned.add("Mox Emerald"); + banned.add("Mox Jet"); + banned.add("Mox Pearl"); + banned.add("Mox Ruby"); + banned.add("Mox Sapphire"); + banned.add("Natural Order"); + banned.add("Painter's Servant"); + banned.add("Panoptic Mirror"); + banned.add("Primal Surge"); + banned.add("Primeval Titan"); + banned.add("Recurring Nightmare"); + banned.add("Saheeli, the Gifted"); + banned.add("Sol Ring"); + banned.add("Sundering Titan"); + banned.add("Sway of the Stars"); + banned.add("Sylvan Primordial"); + banned.add("Time Vault"); + banned.add("Time Walk"); + banned.add("Tinker"); + banned.add("Tolarian Academy"); + banned.add("Tooth and Nail"); + banned.add("Trade Secrets"); + banned.add("Upheaval"); + banned.add("Worldfire"); + banned.add("Yawgmoth's Bargain"); + } + + @Override + public int getDeckMinSize() { + return 60 - (1 + 2); // spell + 2 x partner oathbreakers + } + + @Override + public int getSideboardMinSize() { + return 2; // spell + oathbreaker + } + + @Override + public boolean validate(Deck deck) { + boolean valid = true; + FilterMana colorIdentity = new FilterMana(); + + if (deck.getCards().size() + deck.getSideboard().size() != 60) { + invalid.put("Deck", "Must contain " + 60 + " cards: has " + (deck.getCards().size() + deck.getSideboard().size()) + " cards"); + valid = false; + } + + Map counts = new HashMap<>(); + countCards(counts, deck.getCards()); + countCards(counts, deck.getSideboard()); + + for (Map.Entry entry : counts.entrySet()) { + if (entry.getValue() > 1) { + if (!basicLandNames.contains(entry.getKey()) && !anyNumberCardsAllowed.contains(entry.getKey())) { + invalid.put(entry.getKey(), "Too many: " + entry.getValue()); + valid = false; + } + } + } + + Set commanderNames = new HashSet<>(); + String signatureSpell = null; + if (deck.getSideboard().size() < 2 || deck.getSideboard().size() > 3) { + invalid.put("Oathbreaker", "Sideboard must contain only the oathbreaker(s) with signature spell"); + valid = false; + } else { + for (Card commander : deck.getSideboard()) { + if (commander.isInstantOrSorcery()) { + if (signatureSpell == null) { + signatureSpell = commander.getName(); + } else { + invalid.put("Signature spell", "Only one signature spell allows, but found: " + signatureSpell + " and " + commander.getName()); + valid = false; + } + } else { + if (commander.isPlaneswalker()) { + commanderNames.add(commander.getName()); + } else { + invalid.put("Oathbreaker", "Only planeswalker can be Oathbreaker, not " + commander.getName()); + valid = false; + } + } + } + + for (Card commander : deck.getSideboard()) { + if (commanderNames.contains(commander.getName())) { + // partner checks + if (commanderNames.size() == 2 && !commander.getAbilities().contains(PartnerAbility.getInstance())) { + boolean partnersWith = false; + for (Ability ability : commander.getAbilities()) { + if (ability instanceof PartnerWithAbility && commanderNames.contains(((PartnerWithAbility) ability).getPartnerName())) { + partnersWith = true; + break; + } + } + if (!partnersWith) { + invalid.put("Oathbreaker", "Oathbreaker without Partner (" + commander.getName() + ')'); + valid = false; + } + } + + // color identity from commanders only, not spell + FilterMana commanderColor = commander.getColorIdentity(); + if (commanderColor.isWhite()) { + colorIdentity.setWhite(true); + } + if (commanderColor.isBlue()) { + colorIdentity.setBlue(true); + } + if (commanderColor.isBlack()) { + colorIdentity.setBlack(true); + } + if (commanderColor.isRed()) { + colorIdentity.setRed(true); + } + if (commanderColor.isGreen()) { + colorIdentity.setGreen(true); + } + } + } + + if (commanderNames.size() == 0) { + invalid.put("Sideboard", "Can't find any oathbreaker"); + valid = false; + } + if (signatureSpell == null) { + invalid.put("Sideboard", "Can't find signature spell"); + valid = false; + } + } + + // signature spell color + for (Card card : deck.getSideboard()) { + if (card.getName().equals(signatureSpell) && !cardHasValidColor(colorIdentity, card)) { + invalid.put(card.getName(), "Invalid color for signature spell (" + colorIdentity.toString() + ')'); + valid = false; + } + } + + // no needs in cards check on wrong commanders + if (!valid) { + return false; + } + + for (Card card : deck.getCards()) { + if (!cardHasValidColor(colorIdentity, card)) { + invalid.put(card.getName(), "Invalid color (" + colorIdentity.toString() + ')'); + valid = false; + } + } + + for (Card card : deck.getSideboard()) { + if (!isSetAllowed(card.getExpansionSetCode())) { + if (!legalSets(card)) { + invalid.put(card.getName(), "Not allowed Set: " + card.getExpansionSetCode()); + valid = false; + } + } + } + return valid; + } + + public boolean cardHasValidColor(FilterMana commander, Card card) { + FilterMana cardColor = card.getColorIdentity(); + return !(cardColor.isBlack() && !commander.isBlack() + || cardColor.isBlue() && !commander.isBlue() + || cardColor.isGreen() && !commander.isGreen() + || cardColor.isRed() && !commander.isRed() + || cardColor.isWhite() && !commander.isWhite()); + } +} diff --git a/Mage.Server.Plugins/Mage.Game.OathbreakerFreeForAll/pom.xml b/Mage.Server.Plugins/Mage.Game.OathbreakerFreeForAll/pom.xml new file mode 100644 index 00000000000..b7f1d06232b --- /dev/null +++ b/Mage.Server.Plugins/Mage.Game.OathbreakerFreeForAll/pom.xml @@ -0,0 +1,50 @@ + + + 4.0.0 + + + org.mage + mage-server-plugins + 1.4.35 + + + mage-game-oathbreakerfreeforall + jar + Mage Game Oathbreaker Free For All + + + + ${project.groupId} + mage + ${project.version} + + + + + src + + + org.apache.maven.plugins + maven-compiler-plugin + + 1.8 + 1.8 + + + + maven-resources-plugin + + UTF-8 + + + + + + mage-game-freeforall + + + + + diff --git a/Mage.Server.Plugins/Mage.Game.OathbreakerFreeForAll/src/mage/game/OathbreakerFreeForAll.java b/Mage.Server.Plugins/Mage.Game.OathbreakerFreeForAll/src/mage/game/OathbreakerFreeForAll.java new file mode 100644 index 00000000000..323fda1d684 --- /dev/null +++ b/Mage.Server.Plugins/Mage.Game.OathbreakerFreeForAll/src/mage/game/OathbreakerFreeForAll.java @@ -0,0 +1,141 @@ +package mage.game; + +import mage.abilities.Ability; +import mage.abilities.common.SignatureSpellCastOnlyWithOathbreakerEffect; +import mage.abilities.common.SimpleStaticAbility; +import mage.abilities.condition.Condition; +import mage.abilities.condition.common.OathbreakerOnBattlefieldCondition; +import mage.abilities.effects.common.InfoEffect; +import mage.abilities.hint.ConditionHint; +import mage.cards.Card; +import mage.constants.MultiplayerAttackOption; +import mage.constants.RangeOfInfluence; +import mage.game.match.MatchType; +import mage.game.mulligan.Mulligan; +import mage.players.Player; +import mage.watchers.common.CommanderInfoWatcher; + +import java.util.*; + +/** + * @author JayDi85 + */ +public class OathbreakerFreeForAll extends GameCommanderImpl { + + private int numPlayers; + private Map playerSignatureSpell = new HashMap<>(); + private Map> playerCommanders = new HashMap<>(); + + public OathbreakerFreeForAll(MultiplayerAttackOption attackOption, RangeOfInfluence range, Mulligan mulligan, int startLife) { + super(attackOption, range, mulligan, startLife); + } + + public OathbreakerFreeForAll(final OathbreakerFreeForAll game) { + super(game); + this.numPlayers = game.numPlayers; + this.playerSignatureSpell.putAll(game.playerSignatureSpell); + game.playerCommanders.forEach((key, value) -> this.playerCommanders.put(key, new ArrayList<>(value))); + } + + @Override + protected void init(UUID choosingPlayerId) { + /* + // prepare commanders and signature spells info + playerSignatureSpell.clear(); + playerCommanders.clear(); + for (UUID playerId : state.getPlayerList(startingPlayerId)) { + UUID signatureSpell = null; + List commanders = new ArrayList<>(); + + Player player = getPlayer(playerId); + List searchList = new ArrayList<>(); + searchList.addAll(player.getCommandersIds()); + searchList.addAll(new ArrayList<>(player.getSideboard())); + for (UUID id : searchList) { + Card commander = this.getCard(id); + if (commander != null) { + if (commander.isInstantOrSorcery()) { + signatureSpell = commander.getId(); + } else if (!commanders.contains(commander.getId())) { + commanders.add(commander.getId()); + } + } + } + + playerSignatureSpell.put(playerId, signatureSpell); + playerCommanders.put(playerId, commanders); + } + */ + + // init base commander game + startingPlayerSkipsDraw = false; + super.init(choosingPlayerId); + } + + @Override + public CommanderInfoWatcher initCommanderWatcher(Card commander, boolean checkCommanderDamage) { + String commanderType; + if (commander.isInstantOrSorcery()) { + commanderType = "Signature Spell"; + } else { + commanderType = "Oathbreaker"; + } + return new CommanderInfoWatcher(commanderType, commander.getId(), checkCommanderDamage); + } + + @Override + public void initCommanderEffects(Card commander, Player player, Ability commanderAbility) { + // all commander effects must be independent from sourceId or controllerId + super.initCommanderEffects(commander, player, commanderAbility); + + // signature spell restrict (spell can be casted on player's commander on battlefield) + if (commander.getId().equals(this.playerSignatureSpell.getOrDefault(player.getId(), null))) { + Condition condition = new OathbreakerOnBattlefieldCondition(player.getId(), this.playerCommanders.getOrDefault(player.getId(), null)); + commanderAbility.addEffect(new SignatureSpellCastOnlyWithOathbreakerEffect(condition, commander.getId())); + + // hint must be added to card, not global ability + Ability ability = new SimpleStaticAbility(new InfoEffect("Signature spell hint")); + ability.addHint(new ConditionHint(condition, "Oathbreaker on battlefield")); + ability.setRuleVisible(false); + commander.addAbility(ability); + } + } + + @Override + public void addCommander(Card card, Player player) { + super.addCommander(card, player); + + // prepare signature and commanders info + if (card.isInstantOrSorcery()) { + this.playerSignatureSpell.put(player.getId(), card.getId()); + } else { + List list = this.playerCommanders.getOrDefault(player.getId(), null); + if (list == null) { + list = new ArrayList<>(); + this.playerCommanders.put(player.getId(), list); + } + if (!list.contains(card.getId())) { + list.add(card.getId()); + } + } + } + + @Override + public MatchType getGameType() { + return new OathbreakerFreeForAllType(); + } + + @Override + public int getNumPlayers() { + return numPlayers; + } + + public void setNumPlayers(int numPlayers) { + this.numPlayers = numPlayers; + } + + @Override + public OathbreakerFreeForAll copy() { + return new OathbreakerFreeForAll(this); + } +} diff --git a/Mage.Server.Plugins/Mage.Game.OathbreakerFreeForAll/src/mage/game/OathbreakerFreeForAllMatch.java b/Mage.Server.Plugins/Mage.Game.OathbreakerFreeForAll/src/mage/game/OathbreakerFreeForAllMatch.java new file mode 100644 index 00000000000..0a7086a7c28 --- /dev/null +++ b/Mage.Server.Plugins/Mage.Game.OathbreakerFreeForAll/src/mage/game/OathbreakerFreeForAllMatch.java @@ -0,0 +1,29 @@ +package mage.game; + +import mage.game.match.MatchImpl; +import mage.game.match.MatchOptions; +import mage.game.mulligan.Mulligan; + +/** + * @author JayDi85 + */ +public class OathbreakerFreeForAllMatch extends MatchImpl { + + public OathbreakerFreeForAllMatch(MatchOptions options) { + super(options); + } + + @Override + public void startGame() throws GameException { + int startLife = 20; + boolean alsoHand = true; + Mulligan mulligan = options.getMulliganType().getMulligan(options.getFreeMulligans()); + OathbreakerFreeForAll game = new OathbreakerFreeForAll(options.getAttackOption(), options.getRange(), mulligan, startLife); + game.setStartMessage(this.createGameStartMessage()); + game.setAlsoHand(alsoHand); + game.setAlsoLibrary(true); + initGame(game); + games.add(game); + } + +} diff --git a/Mage.Server.Plugins/Mage.Game.OathbreakerFreeForAll/src/mage/game/OathbreakerFreeForAllType.java b/Mage.Server.Plugins/Mage.Game.OathbreakerFreeForAll/src/mage/game/OathbreakerFreeForAllType.java new file mode 100644 index 00000000000..ab867ce0468 --- /dev/null +++ b/Mage.Server.Plugins/Mage.Game.OathbreakerFreeForAll/src/mage/game/OathbreakerFreeForAllType.java @@ -0,0 +1,29 @@ +package mage.game; + +import mage.game.match.MatchType; + + +/** + * @author JayDi85 + */ +public class OathbreakerFreeForAllType extends MatchType { + + public OathbreakerFreeForAllType() { + this.name = "Oathbreaker Free For All"; + this.maxPlayers = 10; + this.minPlayers = 3; + this.numTeams = 0; + this.useAttackOption = true; + this.useRange = true; + this.sideboardingAllowed = false; + } + + protected OathbreakerFreeForAllType(final OathbreakerFreeForAllType matchType) { + super(matchType); + } + + @Override + public OathbreakerFreeForAllType copy() { + return new OathbreakerFreeForAllType(this); + } +} diff --git a/Mage.Server.Plugins/pom.xml b/Mage.Server.Plugins/pom.xml index 248976e2124..497e462c37d 100644 --- a/Mage.Server.Plugins/pom.xml +++ b/Mage.Server.Plugins/pom.xml @@ -1,5 +1,6 @@ - + 4.0.0 @@ -26,19 +27,20 @@ Mage.Game.CanadianHighlanderDuel Mage.Game.PennyDreadfulCommanderFreeForAll Mage.Game.FreeformCommanderDuel - Mage.Game.FreeformCommanderFreeForAll - Mage.Game.BrawlDuel + Mage.Game.FreeformCommanderFreeForAll + Mage.Game.BrawlDuel Mage.Game.BrawlFreeForAll + Mage.Game.OathbreakerFreeForAll Mage.Game.TwoPlayerDuel Mage.Player.AI Mage.Player.AIMinimax Mage.Player.AI.MA Mage.Player.AIMCTS - Mage.Player.AI.DraftBot + Mage.Player.AI.DraftBot Mage.Player.Human Mage.Tournament.BoosterDraft Mage.Tournament.Constructed - Mage.Tournament.Sealed + Mage.Tournament.Sealed diff --git a/Mage.Server/config/config.xml b/Mage.Server/config/config.xml index aa2223ceab4..500b4c29b2c 100644 --- a/Mage.Server/config/config.xml +++ b/Mage.Server/config/config.xml @@ -69,123 +69,234 @@ - + - - - - - - - - - - - - - + + + + + + + + + + + + + + - - - - - - - - - - - - - - + + + + + + + + + + + + + + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - + - + - - - - - - - - + + + + + + + + - - - + + + - - + + - - - + + + + - - - + + + - - - - - + + + + + - - + + diff --git a/Mage.Server/pom.xml b/Mage.Server/pom.xml index 72d63a77d60..b835f3e7df0 100644 --- a/Mage.Server/pom.xml +++ b/Mage.Server/pom.xml @@ -178,6 +178,7 @@ ${project.version} runtime + ${project.groupId} mage-game-freeformcommanderfreeforall @@ -191,6 +192,13 @@ runtime + + ${project.groupId} + mage-game-oathbreakerfreeforall + ${project.version} + runtime + + ${project.groupId} mage-game-momirduel diff --git a/Mage.Server/release/config/config.xml b/Mage.Server/release/config/config.xml index bea0cd3d653..37cdb35f4c6 100644 --- a/Mage.Server/release/config/config.xml +++ b/Mage.Server/release/config/config.xml @@ -61,125 +61,264 @@ mailFromAddress="" /> - - - + + + - - - - - - - - - - - - - + + + + + + + + + + + + + + - - - - - - - - - - - - - - + + + + + + + + + + + + + + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Mage.Server/src/main/java/mage/server/util/SystemUtil.java b/Mage.Server/src/main/java/mage/server/util/SystemUtil.java index ae2a758128b..ab298d44b5b 100644 --- a/Mage.Server/src/main/java/mage/server/util/SystemUtil.java +++ b/Mage.Server/src/main/java/mage/server/util/SystemUtil.java @@ -522,10 +522,8 @@ public final class SystemUtil { // as commander (only commander games, look at init code in GameCommanderImpl) if (game instanceof GameCommanderImpl) { GameCommanderImpl gameCommander = (GameCommanderImpl) game; - for (Card card : cardsToLoad) { - player.addCommanderId(card.getId()); - gameCommander.initCommander(card, player); - } + cardsToLoad.forEach(card -> gameCommander.addCommander(card, player)); + cardsToLoad.forEach(card -> gameCommander.initCommander(card, player)); } else { logger.fatal("Commander card can be used in commander game only: " + command.cardName); } diff --git a/Mage/src/main/java/mage/abilities/common/SignatureSpellCastOnlyWithOathbreakerEffect.java b/Mage/src/main/java/mage/abilities/common/SignatureSpellCastOnlyWithOathbreakerEffect.java new file mode 100644 index 00000000000..ad64d77eb88 --- /dev/null +++ b/Mage/src/main/java/mage/abilities/common/SignatureSpellCastOnlyWithOathbreakerEffect.java @@ -0,0 +1,61 @@ +package mage.abilities.common; + +import mage.abilities.Ability; +import mage.abilities.condition.Condition; +import mage.abilities.effects.ContinuousRuleModifyingEffectImpl; +import mage.constants.Duration; +import mage.constants.Outcome; +import mage.game.Game; +import mage.game.events.GameEvent; + +import java.util.UUID; + +/** + * For oathbreaker game mode + * + * @author JayDi85 + */ +public class SignatureSpellCastOnlyWithOathbreakerEffect extends ContinuousRuleModifyingEffectImpl { + + private final Condition condition; + private final UUID signatureSpell; + + public SignatureSpellCastOnlyWithOathbreakerEffect(Condition condition, UUID signatureSpell) { + super(Duration.EndOfGame, Outcome.Detriment); + this.condition = condition; + this.signatureSpell = signatureSpell; + staticText = setText(); + } + + private SignatureSpellCastOnlyWithOathbreakerEffect(final SignatureSpellCastOnlyWithOathbreakerEffect effect) { + super(effect); + this.condition = effect.condition; + this.signatureSpell = effect.signatureSpell; + } + + @Override + public boolean checksEventType(GameEvent event, Game game) { + return event.getType() == GameEvent.EventType.CAST_SPELL; + } + + @Override + public boolean applies(GameEvent event, Ability source, Game game) { + if (event.getSourceId().equals(signatureSpell)) { + return condition != null && !condition.apply(game, source); + } + return false; // cast not prevented by this effect + } + + @Override + public SignatureSpellCastOnlyWithOathbreakerEffect copy() { + return new SignatureSpellCastOnlyWithOathbreakerEffect(this); + } + + private String setText() { + StringBuilder sb = new StringBuilder("cast this spell only "); + if (condition != null) { + sb.append(' ').append(condition.toString()); + } + return sb.toString(); + } +} diff --git a/Mage/src/main/java/mage/abilities/condition/common/OathbreakerOnBattlefieldCondition.java b/Mage/src/main/java/mage/abilities/condition/common/OathbreakerOnBattlefieldCondition.java new file mode 100644 index 00000000000..06b9e57718d --- /dev/null +++ b/Mage/src/main/java/mage/abilities/condition/common/OathbreakerOnBattlefieldCondition.java @@ -0,0 +1,51 @@ +package mage.abilities.condition.common; + +import mage.abilities.Ability; +import mage.abilities.condition.Condition; +import mage.filter.common.FilterControlledPermanent; +import mage.filter.predicate.Predicates; +import mage.filter.predicate.permanent.PermanentIdPredicate; +import mage.game.Game; + +import java.util.ArrayList; +import java.util.List; +import java.util.UUID; + +/** + * For Oathbreaker game mode + * + * @author JayDi85 + */ +public class OathbreakerOnBattlefieldCondition implements Condition { + + private UUID playerId; + private FilterControlledPermanent filter; + + public OathbreakerOnBattlefieldCondition(UUID playerId, List oathbreakersToSearch) { + this.playerId = playerId; + this.filter = new FilterControlledPermanent("oathbreaker on battlefield"); + if (oathbreakersToSearch != null && !oathbreakersToSearch.isEmpty()) { + // any commander on battlefield + List idsList = new ArrayList<>(); + for (UUID id : oathbreakersToSearch) { + idsList.add(new PermanentIdPredicate(id)); + } + this.filter.add(Predicates.or(idsList)); + } else { + // random id to disable condition + this.filter.add(new PermanentIdPredicate(UUID.randomUUID())); + } + } + + @Override + public boolean apply(Game game, Ability source) { + // source.getSourceId() is null for commander's effects + int permanentsOnBattlefield = game.getBattlefield().count(this.filter, source.getSourceId(), playerId, game); + return permanentsOnBattlefield > 0; + } + + @Override + public String toString() { + return filter.getMessage(); + } +} diff --git a/Mage/src/main/java/mage/game/GameCommanderImpl.java b/Mage/src/main/java/mage/game/GameCommanderImpl.java index eb5094f735b..c36b09fff95 100644 --- a/Mage/src/main/java/mage/game/GameCommanderImpl.java +++ b/Mage/src/main/java/mage/game/GameCommanderImpl.java @@ -41,6 +41,7 @@ public abstract class GameCommanderImpl extends GameImpl { @Override protected void init(UUID choosingPlayerId) { + // Karn Liberated calls it to restart game, all data and commanders must be re-initialized // plays watcher state.addWatcher(new CommanderPlaysCountWatcher()); @@ -49,20 +50,19 @@ public abstract class GameCommanderImpl extends GameImpl { for (UUID playerId : state.getPlayerList(startingPlayerId)) { Player player = getPlayer(playerId); if (player != null) { - if (player.getSideboard().isEmpty()) { // needed for restart game of e.g. Karn Liberated - for (UUID commanderId : player.getCommandersIds()) { - Card commander = this.getCard(commanderId); - if (commander != null) { - initCommander(commander, player); - } + // add new commanders + for (UUID id : player.getSideboard()) { + Card commander = this.getCard(id); + if (commander != null) { + addCommander(commander, player); } - } else { - while (!player.getSideboard().isEmpty()) { - Card commander = this.getCard(player.getSideboard().iterator().next()); - if (commander != null) { - player.addCommanderId(commander.getId()); - initCommander(commander, player); - } + } + + // init commanders + for (UUID commanderId : player.getCommandersIds()) { + Card commander = this.getCard(commanderId); + if (commander != null) { + initCommander(commander, player); } } } @@ -75,17 +75,27 @@ public abstract class GameCommanderImpl extends GameImpl { } public void initCommander(Card commander, Player player) { - Ability ability = new SimpleStaticAbility(Zone.COMMAND, new InfoEffect("Commander effects")); commander.moveToZone(Zone.COMMAND, null, this, true); commander.getAbilities().setControllerId(player.getId()); - ability.addEffect(new CommanderReplacementEffect(commander.getId(), alsoHand, alsoLibrary)); - ability.addEffect(new CommanderCostModification(commander.getId())); - CommanderInfoWatcher watcher = new CommanderInfoWatcher(commander.getId(), checkCommanderDamage); + + Ability ability = new SimpleStaticAbility(Zone.COMMAND, new InfoEffect("Commander effects")); + initCommanderEffects(commander, player, ability); + CommanderInfoWatcher watcher = initCommanderWatcher(commander, checkCommanderDamage); getState().addWatcher(watcher); watcher.addCardInfoToCommander(this); this.getState().addAbility(ability, null); } + public CommanderInfoWatcher initCommanderWatcher(Card commander, boolean checkCommanderDamage) { + return new CommanderInfoWatcher("Commander", commander.getId(), checkCommanderDamage); + } + + public void initCommanderEffects(Card commander, Player player, Ability commanderAbility) { + // all commander effects must be independent from sourceId or controllerId + commanderAbility.addEffect(new CommanderReplacementEffect(commander.getId(), alsoHand, alsoLibrary)); + commanderAbility.addEffect(new CommanderCostModification(commander.getId())); + } + //20130711 /*903.8. The Commander variant uses an alternate mulligan rule. * Each time a player takes a mulligan, rather than shuffling their entire hand of cards into their library, that player exiles any number of cards from their hand face down. @@ -207,4 +217,8 @@ public abstract class GameCommanderImpl extends GameImpl { this.checkCommanderDamage = checkCommanderDamage; } + public void addCommander(Card card, Player player) { + player.addCommanderId(card.getId()); + } + } diff --git a/Mage/src/main/java/mage/game/GameImpl.java b/Mage/src/main/java/mage/game/GameImpl.java index a2d57f858c5..5994ff0ca26 100644 --- a/Mage/src/main/java/mage/game/GameImpl.java +++ b/Mage/src/main/java/mage/game/GameImpl.java @@ -2871,7 +2871,7 @@ public abstract class GameImpl implements Game, Serializable { // as commander (only commander games, look at init code in GameCommanderImpl) if (this instanceof GameCommanderImpl) { for (Card card : command) { - player.addCommanderId(card.getId()); + ((GameCommanderImpl) this).addCommander(card, player); // no needs in initCommander call -- it's uses on game startup (init) } } else if (!command.isEmpty()) { diff --git a/Mage/src/main/java/mage/game/GameTinyLeadersImpl.java b/Mage/src/main/java/mage/game/GameTinyLeadersImpl.java index f89c542c844..83f17e0126b 100644 --- a/Mage/src/main/java/mage/game/GameTinyLeadersImpl.java +++ b/Mage/src/main/java/mage/game/GameTinyLeadersImpl.java @@ -62,7 +62,7 @@ public abstract class GameTinyLeadersImpl extends GameImpl { ability.addEffect(new CommanderCostModification(commander.getId())); // Commander rule #4 was removed Jan. 18, 2016 // ability.addEffect(new CommanderManaReplacementEffect(player.getId(), CardUtil.getColorIdentity(commander))); - CommanderInfoWatcher watcher = new CommanderInfoWatcher(commander.getId(), false); + CommanderInfoWatcher watcher = new CommanderInfoWatcher("Commander", commander.getId(), false); getState().addWatcher(watcher); watcher.addCardInfoToCommander(this); this.getState().addAbility(ability, null); diff --git a/Mage/src/main/java/mage/watchers/common/CommanderInfoWatcher.java b/Mage/src/main/java/mage/watchers/common/CommanderInfoWatcher.java index d72635b4006..0cfc776fc30 100644 --- a/Mage/src/main/java/mage/watchers/common/CommanderInfoWatcher.java +++ b/Mage/src/main/java/mage/watchers/common/CommanderInfoWatcher.java @@ -26,17 +26,20 @@ public class CommanderInfoWatcher extends Watcher { private final Map damageToPlayer = new HashMap<>(); private final boolean checkCommanderDamage; + private final String commanderTypeName; - public CommanderInfoWatcher(UUID commander, boolean checkCommanderDamage) { + public CommanderInfoWatcher(String commanderTypeName, UUID commander, boolean checkCommanderDamage) { super(WatcherScope.CARD); this.sourceId = commander; this.checkCommanderDamage = checkCommanderDamage; + this.commanderTypeName = commanderTypeName; } public CommanderInfoWatcher(final CommanderInfoWatcher watcher) { super(watcher); this.damageToPlayer.putAll(watcher.damageToPlayer); this.checkCommanderDamage = watcher.checkCommanderDamage; + this.commanderTypeName = watcher.commanderTypeName; } @Override @@ -78,7 +81,7 @@ public class CommanderInfoWatcher extends Watcher { } if (object != null) { StringBuilder sb = new StringBuilder(); - sb.append("Commander"); + sb.append("" + commanderTypeName + ""); CommanderPlaysCountWatcher watcher = game.getState().getWatcher(CommanderPlaysCountWatcher.class); int playsCount = watcher.getPlaysCount(sourceId); if (playsCount > 0) { @@ -89,9 +92,9 @@ public class CommanderInfoWatcher extends Watcher { if (checkCommanderDamage) { for (Map.Entry entry : damageToPlayer.entrySet()) { Player damagedPlayer = game.getPlayer(entry.getKey()); - sb.append("Commander did ").append(entry.getValue()).append(" combat damage to player ").append(damagedPlayer.getLogName()).append('.'); + sb.append("" + commanderTypeName + " did ").append(entry.getValue()).append(" combat damage to player ").append(damagedPlayer.getLogName()).append('.'); this.addInfo(object, "Commander" + entry.getKey(), - "Commander did " + entry.getValue() + " combat damage to player " + damagedPlayer.getLogName() + '.', game); + "" + commanderTypeName + " did " + entry.getValue() + " combat damage to player " + damagedPlayer.getLogName() + '.', game); } } } From 2f04a0d979b17669dbbaf386c6f1978f5a44b693 Mon Sep 17 00:00:00 2001 From: Oleg Agafonov Date: Mon, 27 May 2019 16:18:20 +0400 Subject: [PATCH 02/38] Fixed bloated error messages on commander deck check; --- .../src/mage/deck/Commander.java | 6 ++++++ .../src/mage/deck/FreeformCommander.java | 11 +++++------ .../src/mage/deck/PennyDreadfulCommander.java | 6 ++++++ 3 files changed, 17 insertions(+), 6 deletions(-) diff --git a/Mage.Server.Plugins/Mage.Deck.Constructed/src/mage/deck/Commander.java b/Mage.Server.Plugins/Mage.Deck.Constructed/src/mage/deck/Commander.java index d944f8068f9..720de03ebf9 100644 --- a/Mage.Server.Plugins/Mage.Deck.Constructed/src/mage/deck/Commander.java +++ b/Mage.Server.Plugins/Mage.Deck.Constructed/src/mage/deck/Commander.java @@ -166,6 +166,12 @@ public class Commander extends Constructed { } } } + + // no needs in cards check on wrong commanders + if (!valid) { + return false; + } + for (Card card : deck.getCards()) { if (!cardHasValidColor(colorIdentity, card)) { invalid.put(card.getName(), "Invalid color (" + colorIdentity.toString() + ')'); diff --git a/Mage.Server.Plugins/Mage.Deck.Constructed/src/mage/deck/FreeformCommander.java b/Mage.Server.Plugins/Mage.Deck.Constructed/src/mage/deck/FreeformCommander.java index 5e2ce9b0d27..4a066bf665a 100644 --- a/Mage.Server.Plugins/Mage.Deck.Constructed/src/mage/deck/FreeformCommander.java +++ b/Mage.Server.Plugins/Mage.Deck.Constructed/src/mage/deck/FreeformCommander.java @@ -67,8 +67,6 @@ public class FreeformCommander extends Constructed { } } - generateFreeformHash(); - if (deck.getSideboard().size() < 1 || deck.getSideboard().size() > 2) { invalid.put("Commander", "Sideboard must contain only the commander(s)"); valid = false; @@ -116,6 +114,11 @@ public class FreeformCommander extends Constructed { } } + // no needs in cards check on wrong commanders + if (!valid) { + return false; + } + for (Card card : deck.getCards()) { if (!cardHasValidColor(colorIdentity, card)) { invalid.put(card.getName(), "Invalid color (" + colorIdentity.toString() + ')'); @@ -142,8 +145,4 @@ public class FreeformCommander extends Constructed { || cardColor.isRed() && !commander.isRed() || cardColor.isWhite() && !commander.isWhite()); } - - public void generateFreeformHash() { - return; - } } diff --git a/Mage.Server.Plugins/Mage.Deck.Constructed/src/mage/deck/PennyDreadfulCommander.java b/Mage.Server.Plugins/Mage.Deck.Constructed/src/mage/deck/PennyDreadfulCommander.java index 6479df83be2..2e8acf10d8b 100644 --- a/Mage.Server.Plugins/Mage.Deck.Constructed/src/mage/deck/PennyDreadfulCommander.java +++ b/Mage.Server.Plugins/Mage.Deck.Constructed/src/mage/deck/PennyDreadfulCommander.java @@ -124,6 +124,12 @@ public class PennyDreadfulCommander extends Constructed { } } } + + // no needs in cards check on wrong commanders + if (!valid) { + return false; + } + for (Card card : deck.getCards()) { if (!cardHasValidColor(colorIdentity, card)) { invalid.put(card.getName(), "Invalid color (" + colorIdentity.toString() + ')'); From e1259d0dd6668daf8ab05b88d1b998b83b6e69a1 Mon Sep 17 00:00:00 2001 From: Oleg Agafonov Date: Mon, 27 May 2019 16:21:22 +0400 Subject: [PATCH 03/38] Merge fix --- .../src/mage/game/OathbreakerFreeForAllMatch.java | 1 + 1 file changed, 1 insertion(+) diff --git a/Mage.Server.Plugins/Mage.Game.OathbreakerFreeForAll/src/mage/game/OathbreakerFreeForAllMatch.java b/Mage.Server.Plugins/Mage.Game.OathbreakerFreeForAll/src/mage/game/OathbreakerFreeForAllMatch.java index 0a7086a7c28..2e2d239e287 100644 --- a/Mage.Server.Plugins/Mage.Game.OathbreakerFreeForAll/src/mage/game/OathbreakerFreeForAllMatch.java +++ b/Mage.Server.Plugins/Mage.Game.OathbreakerFreeForAll/src/mage/game/OathbreakerFreeForAllMatch.java @@ -19,6 +19,7 @@ public class OathbreakerFreeForAllMatch extends MatchImpl { boolean alsoHand = true; Mulligan mulligan = options.getMulliganType().getMulligan(options.getFreeMulligans()); OathbreakerFreeForAll game = new OathbreakerFreeForAll(options.getAttackOption(), options.getRange(), mulligan, startLife); + game.setCheckCommanderDamage(false); game.setStartMessage(this.createGameStartMessage()); game.setAlsoHand(alsoHand); game.setAlsoLibrary(true); From 913ee65f36c76315935f18f96b676071f8afe745 Mon Sep 17 00:00:00 2001 From: Oleg Agafonov Date: Mon, 27 May 2019 17:21:17 +0400 Subject: [PATCH 04/38] Cards compatibility with oathbreaker format; --- .../src/mage/game/OathbreakerFreeForAll.java | 30 +++++++++++++++++++ .../src/mage/cards/a/ArcaneAdaptation.java | 2 +- Mage.Sets/src/mage/cards/c/CommandBeacon.java | 20 ++++++------- Mage.Sets/src/mage/cards/c/Conspiracy.java | 2 +- Mage.Sets/src/mage/cards/k/KarnLiberated.java | 5 ++-- Mage.Sets/src/mage/cards/m/MythUnbound.java | 2 +- Mage.Sets/src/mage/cards/o/OpalPalace.java | 2 +- .../src/mage/cards/p/PathOfAncestry.java | 14 +++++---- .../src/mage/cards/t/TeferiMageOfZhalfir.java | 2 +- .../java/org/mage/test/player/TestPlayer.java | 2 +- .../common/CommanderInPlayCondition.java | 4 +-- .../keyword/CommanderStormAbility.java | 3 +- .../abilities/keyword/NinjutsuAbility.java | 13 ++++---- .../CommanderColorIdentityManaAbility.java | 12 ++++---- .../mage/constants/CommanderCardType.java | 10 +++++++ .../permanent/CommanderPredicate.java | 2 +- Mage/src/main/java/mage/game/Game.java | 5 ++++ .../java/mage/game/GameCommanderImpl.java | 4 +-- Mage/src/main/java/mage/game/GameImpl.java | 5 ++++ Mage/src/main/java/mage/players/Player.java | 2 ++ .../main/java/mage/players/PlayerImpl.java | 2 +- .../common/CommanderPlaysCountWatcher.java | 2 +- 22 files changed, 99 insertions(+), 46 deletions(-) create mode 100644 Mage/src/main/java/mage/constants/CommanderCardType.java diff --git a/Mage.Server.Plugins/Mage.Game.OathbreakerFreeForAll/src/mage/game/OathbreakerFreeForAll.java b/Mage.Server.Plugins/Mage.Game.OathbreakerFreeForAll/src/mage/game/OathbreakerFreeForAll.java index 323fda1d684..55066b6f6f5 100644 --- a/Mage.Server.Plugins/Mage.Game.OathbreakerFreeForAll/src/mage/game/OathbreakerFreeForAll.java +++ b/Mage.Server.Plugins/Mage.Game.OathbreakerFreeForAll/src/mage/game/OathbreakerFreeForAll.java @@ -8,6 +8,7 @@ import mage.abilities.condition.common.OathbreakerOnBattlefieldCondition; import mage.abilities.effects.common.InfoEffect; import mage.abilities.hint.ConditionHint; import mage.cards.Card; +import mage.constants.CommanderCardType; import mage.constants.MultiplayerAttackOption; import mage.constants.RangeOfInfluence; import mage.game.match.MatchType; @@ -138,4 +139,33 @@ public class OathbreakerFreeForAll extends GameCommanderImpl { public OathbreakerFreeForAll copy() { return new OathbreakerFreeForAll(this); } + + @Override + public Set getCommandersIds(Player player, CommanderCardType commanderCardType) { + Set res = new HashSet<>(); + if (player != null) { + List commanders = this.playerCommanders.getOrDefault(player.getId(), new ArrayList<>()); + UUID spell = this.playerSignatureSpell.getOrDefault(player.getId(), null); + for (UUID id : player.getCommandersIds()) { + switch (commanderCardType) { + case ANY: + res.add(id); + break; + case COMMANDER_OR_OATHBREAKER: + if (commanders.contains(id)) { + res.add(id); + } + break; + case SIGNATURE_SPELL: + if (id.equals(spell)) { + res.add(id); + } + break; + default: + throw new IllegalStateException("Unknown commander type " + commanderCardType); + } + } + } + return res; + } } diff --git a/Mage.Sets/src/mage/cards/a/ArcaneAdaptation.java b/Mage.Sets/src/mage/cards/a/ArcaneAdaptation.java index 56674534e04..fb1a7691d33 100644 --- a/Mage.Sets/src/mage/cards/a/ArcaneAdaptation.java +++ b/Mage.Sets/src/mage/cards/a/ArcaneAdaptation.java @@ -93,7 +93,7 @@ class ConspyEffect extends ContinuousEffectImpl { } } // commander in command zone - for (UUID commanderId : controller.getCommandersIds()) { + for (UUID commanderId : game.getCommandersIds(controller)) { if (game.getState().getZone(commanderId) == Zone.COMMAND) { Card card = game.getCard(commanderId); if (card != null && card.isCreature() && !card.hasSubtype(subType, game)) { diff --git a/Mage.Sets/src/mage/cards/c/CommandBeacon.java b/Mage.Sets/src/mage/cards/c/CommandBeacon.java index 22413ce686e..cedd962fac9 100644 --- a/Mage.Sets/src/mage/cards/c/CommandBeacon.java +++ b/Mage.Sets/src/mage/cards/c/CommandBeacon.java @@ -1,9 +1,5 @@ - package mage.cards.c; -import java.util.ArrayList; -import java.util.List; -import java.util.UUID; import mage.abilities.Ability; import mage.abilities.common.SimpleActivatedAbility; import mage.abilities.costs.common.SacrificeSourceCost; @@ -14,19 +10,23 @@ import mage.cards.Card; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; +import mage.constants.CommanderCardType; import mage.constants.Outcome; import mage.constants.Zone; import mage.game.Game; import mage.players.Player; +import java.util.ArrayList; +import java.util.List; +import java.util.UUID; + /** - * * @author emerald000 */ public final class CommandBeacon extends CardImpl { public CommandBeacon(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.LAND},""); + super(ownerId, setInfo, new CardType[]{CardType.LAND}, ""); // {T}: Add {C}. this.addAbility(new ColorlessManaAbility()); @@ -67,7 +67,7 @@ class CommandBeaconEffect extends OneShotEffect { Player controller = game.getPlayer(source.getControllerId()); if (controller != null) { List commandersInCommandZone = new ArrayList<>(1); - for (UUID commanderId : controller.getCommandersIds()) { + for (UUID commanderId : game.getCommandersIds(controller, CommanderCardType.COMMANDER_OR_OATHBREAKER)) { Card commander = game.getCard(commanderId); if (commander != null && game.getState().getZone(commander.getId()) == Zone.COMMAND) { commandersInCommandZone.add(commander); @@ -75,14 +75,12 @@ class CommandBeaconEffect extends OneShotEffect { } if (commandersInCommandZone.size() == 1) { controller.moveCards(commandersInCommandZone.get(0), Zone.HAND, source, game); - } - else if (commandersInCommandZone.size() == 2) { + } else if (commandersInCommandZone.size() == 2) { Card firstCommander = commandersInCommandZone.get(0); Card secondCommander = commandersInCommandZone.get(1); if (controller.chooseUse(Outcome.ReturnToHand, "Return which commander to hand?", null, firstCommander.getName(), secondCommander.getName(), source, game)) { controller.moveCards(firstCommander, Zone.HAND, source, game); - } - else { + } else { controller.moveCards(secondCommander, Zone.HAND, source, game); } } diff --git a/Mage.Sets/src/mage/cards/c/Conspiracy.java b/Mage.Sets/src/mage/cards/c/Conspiracy.java index 934ebd7db95..2fb5ee65265 100644 --- a/Mage.Sets/src/mage/cards/c/Conspiracy.java +++ b/Mage.Sets/src/mage/cards/c/Conspiracy.java @@ -95,7 +95,7 @@ class ConspiracyEffect extends ContinuousEffectImpl { } } // commander in command zone - for (UUID commanderId : controller.getCommandersIds()) { + for (UUID commanderId : game.getCommandersIds(controller)) { if (game.getState().getZone(commanderId) == Zone.COMMAND) { Card card = game.getCard(commanderId); if (card != null && card.isCreature()) { diff --git a/Mage.Sets/src/mage/cards/k/KarnLiberated.java b/Mage.Sets/src/mage/cards/k/KarnLiberated.java index 1c3779d9e49..ecc83a1a607 100644 --- a/Mage.Sets/src/mage/cards/k/KarnLiberated.java +++ b/Mage.Sets/src/mage/cards/k/KarnLiberated.java @@ -109,8 +109,9 @@ class KarnLiberatedEffect extends OneShotEffect { if (card.isOwnedBy(player.getId()) && !card.isCopy() // no copies && !player.getSideboard().contains(card.getId()) && !cards.contains(card)) { // not the exiled cards - if (player.getCommandersIds().contains(card.getId())) { - game.addCommander(new Commander(card)); + if (game.getCommandersIds(player).contains(card.getId())) { + game.addCommander(new Commander(card)); // TODO: check restart and init + // no needs in initCommander call -- it's uses on game startup (init) game.setZone(card.getId(), Zone.COMMAND); } else { player.getLibrary().putOnTop(card, game); diff --git a/Mage.Sets/src/mage/cards/m/MythUnbound.java b/Mage.Sets/src/mage/cards/m/MythUnbound.java index 6e23fdbbc8c..cf9ce5e0134 100644 --- a/Mage.Sets/src/mage/cards/m/MythUnbound.java +++ b/Mage.Sets/src/mage/cards/m/MythUnbound.java @@ -95,7 +95,7 @@ class MythUnboundCostReductionEffect extends CostModificationEffectImpl { if (abilityToModify instanceof SpellAbility || abilityToModify instanceof PlayLandAbility) { if (abilityToModify.isControlledBy(source.getControllerId())) { - return player.getCommandersIds().contains(abilityToModify.getSourceId()); + return game.getCommandersIds(player).contains(abilityToModify.getSourceId()); } } return false; diff --git a/Mage.Sets/src/mage/cards/o/OpalPalace.java b/Mage.Sets/src/mage/cards/o/OpalPalace.java index 92fa165d6a4..1ab89afe676 100644 --- a/Mage.Sets/src/mage/cards/o/OpalPalace.java +++ b/Mage.Sets/src/mage/cards/o/OpalPalace.java @@ -93,7 +93,7 @@ class OpalPalaceWatcher extends Watcher { for (UUID playerId : game.getPlayerList()) { Player player = game.getPlayer(playerId); if (player != null) { - if (player.getCommandersIds().contains(card.getId())) { + if (game.getCommandersIds(player).contains(card.getId())) { commanderId.add(card.getId()); break; } diff --git a/Mage.Sets/src/mage/cards/p/PathOfAncestry.java b/Mage.Sets/src/mage/cards/p/PathOfAncestry.java index 9e490d07baf..82a171c7a79 100644 --- a/Mage.Sets/src/mage/cards/p/PathOfAncestry.java +++ b/Mage.Sets/src/mage/cards/p/PathOfAncestry.java @@ -1,7 +1,5 @@ package mage.cards.p; -import java.util.Iterator; -import java.util.UUID; import mage.MageObject; import mage.abilities.Ability; import mage.abilities.TriggeredAbilityImpl; @@ -22,8 +20,11 @@ import mage.game.permanent.Permanent; import mage.game.stack.Spell; import mage.players.Player; +import java.util.Iterator; +import java.util.Set; +import java.util.UUID; + /** - * * @author TheElk801 */ public final class PathOfAncestry extends CardImpl { @@ -88,9 +89,10 @@ class PathOfAncestryTriggeredAbility extends TriggeredAbilityImpl { Spell spell = game.getStack().getSpell(event.getTargetId()); if (spell != null && spell.isCreature()) { Player controller = game.getPlayer(getControllerId()); - if (controller != null && controller.getCommandersIds() != null && !controller.getCommandersIds().isEmpty()) { + Set commanders = game.getCommandersIds(controller); + if (controller != null && commanders != null && !commanders.isEmpty()) { if (spell.getAbilities().contains(ChangelingAbility.getInstance())) { - for (UUID cmdr : controller.getCommandersIds()) { + for (UUID cmdr : commanders) { MageObject commander = game.getObject(cmdr); if (commander != null) { if (commander.getAbilities().contains(ChangelingAbility.getInstance())) { @@ -110,7 +112,7 @@ class PathOfAncestryTriggeredAbility extends TriggeredAbilityImpl { while (spellSubs.hasNext()) { SubType sType = spellSubs.next(); if (sType.getSubTypeSet() == SubTypeSet.CreatureType) { - for (UUID cmdr : controller.getCommandersIds()) { + for (UUID cmdr : commanders) { MageObject commander = game.getObject(cmdr); if (commander != null && (commander.hasSubtype(sType, game) || commander.getAbilities().contains(ChangelingAbility.getInstance()))) { return true; diff --git a/Mage.Sets/src/mage/cards/t/TeferiMageOfZhalfir.java b/Mage.Sets/src/mage/cards/t/TeferiMageOfZhalfir.java index cdc5ecb0c9a..e1efa6ce2df 100644 --- a/Mage.Sets/src/mage/cards/t/TeferiMageOfZhalfir.java +++ b/Mage.Sets/src/mage/cards/t/TeferiMageOfZhalfir.java @@ -99,7 +99,7 @@ class TeferiMageOfZhalfirAddFlashEffect extends ContinuousEffectImpl { } } // commander in command zone - for (UUID commanderId : controller.getCommandersIds()) { + for (UUID commanderId : game.getCommandersIds(controller)) { if (game.getState().getZone(commanderId) == Zone.COMMAND) { Card card = game.getCard(commanderId); if (card != null && card.isCreature()) { diff --git a/Mage.Tests/src/test/java/org/mage/test/player/TestPlayer.java b/Mage.Tests/src/test/java/org/mage/test/player/TestPlayer.java index e0e3b0006b3..2f11fbd5307 100644 --- a/Mage.Tests/src/test/java/org/mage/test/player/TestPlayer.java +++ b/Mage.Tests/src/test/java/org/mage/test/player/TestPlayer.java @@ -750,7 +750,7 @@ public class TestPlayer implements Player { // show command if (params[0].equals(SHOW_COMMAND_COMMAND) && params.length == 1) { printStart(action.getActionName()); - CardsImpl cards = new CardsImpl(computerPlayer.getCommandersIds()); + CardsImpl cards = new CardsImpl(game.getCommandersIds(computerPlayer)); printCards(cards.getCards(game)); printEnd(); actions.remove(action); diff --git a/Mage/src/main/java/mage/abilities/condition/common/CommanderInPlayCondition.java b/Mage/src/main/java/mage/abilities/condition/common/CommanderInPlayCondition.java index ac0d85ce0e3..28e8f13ca8f 100644 --- a/Mage/src/main/java/mage/abilities/condition/common/CommanderInPlayCondition.java +++ b/Mage/src/main/java/mage/abilities/condition/common/CommanderInPlayCondition.java @@ -1,8 +1,8 @@ - package mage.abilities.condition.common; import mage.abilities.Ability; import mage.abilities.condition.Condition; +import mage.constants.CommanderCardType; import mage.game.Game; import mage.game.permanent.Permanent; import mage.players.Player; @@ -22,7 +22,7 @@ public enum CommanderInPlayCondition implements Condition { public boolean apply(Game game, Ability source) { Player controller = game.getPlayer(source.getControllerId()); if (controller != null) { - for (UUID commanderId : controller.getCommandersIds()) { + for (UUID commanderId : game.getCommandersIds(controller, CommanderCardType.COMMANDER_OR_OATHBREAKER)) { Permanent commander = game.getPermanent(commanderId); if (commander != null && commander.isControlledBy(source.getControllerId())) { return true; diff --git a/Mage/src/main/java/mage/abilities/keyword/CommanderStormAbility.java b/Mage/src/main/java/mage/abilities/keyword/CommanderStormAbility.java index fb0d3beb18b..7a7e10b7406 100644 --- a/Mage/src/main/java/mage/abilities/keyword/CommanderStormAbility.java +++ b/Mage/src/main/java/mage/abilities/keyword/CommanderStormAbility.java @@ -5,6 +5,7 @@ import mage.abilities.Ability; import mage.abilities.TriggeredAbilityImpl; import mage.abilities.effects.Effect; import mage.abilities.effects.OneShotEffect; +import mage.constants.CommanderCardType; import mage.constants.Outcome; import mage.constants.Zone; import mage.game.Game; @@ -83,7 +84,7 @@ class CommanderStormEffect extends OneShotEffect { if (player == null) { return false; } - stormCount = player.getCommandersIds().stream() + stormCount = game.getCommandersIds(player, CommanderCardType.COMMANDER_OR_OATHBREAKER).stream() .map((commanderId) -> game.getState().getWatcher(CommanderPlaysCountWatcher.class).getPlaysCount(commanderId)) .reduce(stormCount, Integer::sum); if (stormCount == 0) { diff --git a/Mage/src/main/java/mage/abilities/keyword/NinjutsuAbility.java b/Mage/src/main/java/mage/abilities/keyword/NinjutsuAbility.java index e63ae4d5a2d..157a173354b 100644 --- a/Mage/src/main/java/mage/abilities/keyword/NinjutsuAbility.java +++ b/Mage/src/main/java/mage/abilities/keyword/NinjutsuAbility.java @@ -1,6 +1,5 @@ package mage.abilities.keyword; -import java.util.UUID; import mage.abilities.Ability; import mage.abilities.ActivatedAbilityImpl; import mage.abilities.costs.Cost; @@ -21,24 +20,25 @@ import mage.players.Player; import mage.target.common.TargetControlledCreaturePermanent; import mage.target.common.TargetControlledPermanent; +import java.util.UUID; + /** * 702.47. Ninjutsu - * + *

* 702.47a Ninjutsu is an activated ability that functions only while the card * with ninjutsu is in a player's hand. "Ninjutsu [cost]" means "[Cost], Reveal * this card from your hand, Return an unblocked attacking creature you control * to its owner's hand: Put this card onto the battlefield from your hand tapped * and attacking." - * + *

* 702.47b The card with ninjutsu remains revealed from the time the ability is * announced until the ability leaves the stack. - * + *

* 702.47c A ninjutsu ability may be activated only while a creature on the * battlefield is unblocked (see rule 509.1h). The creature with ninjutsu is put * onto the battlefield unblocked. It will be attacking the same player or * planeswalker as the creature that was returned to its owner's hand. * - * * @author LevelX2 */ public class NinjutsuAbility extends ActivatedAbilityImpl { @@ -51,7 +51,6 @@ public class NinjutsuAbility extends ActivatedAbilityImpl { } /** - * * @param manaCost ninjutsu mana cost */ public NinjutsuAbility(ManaCost manaCost) { @@ -195,7 +194,7 @@ class RevealNinjutsuCardCost extends CostImpl { Card card = player.getHand().get(ability.getSourceId(), game); if (card == null && commander - && player.getCommandersIds().contains(ability.getSourceId())) { + && game.getCommandersIds(player).contains(ability.getSourceId())) { for (CommandObject coj : game.getState().getCommand()) { if (coj != null && coj.getId().equals(ability.getSourceId())) { card = game.getCard(ability.getSourceId()); diff --git a/Mage/src/main/java/mage/abilities/mana/CommanderColorIdentityManaAbility.java b/Mage/src/main/java/mage/abilities/mana/CommanderColorIdentityManaAbility.java index 44ad62ff232..47f7d1dea56 100644 --- a/Mage/src/main/java/mage/abilities/mana/CommanderColorIdentityManaAbility.java +++ b/Mage/src/main/java/mage/abilities/mana/CommanderColorIdentityManaAbility.java @@ -1,8 +1,5 @@ package mage.abilities.mana; -import java.util.ArrayList; -import java.util.List; -import java.util.UUID; import mage.Mana; import mage.abilities.Ability; import mage.abilities.costs.Cost; @@ -17,8 +14,11 @@ import mage.filter.FilterMana; import mage.game.Game; import mage.players.Player; +import java.util.ArrayList; +import java.util.List; +import java.util.UUID; + /** - * * @author LevelX2 */ public class CommanderColorIdentityManaAbility extends ActivatedManaAbilityImpl { @@ -46,7 +46,7 @@ public class CommanderColorIdentityManaAbility extends ActivatedManaAbilityImpl if (netMana.isEmpty() && game != null) { Player controller = game.getPlayer(getControllerId()); if (controller != null) { - for (UUID commanderId : controller.getCommandersIds()) { + for (UUID commanderId : game.getCommandersIds(controller)) { Card commander = game.getCard(commanderId); if (commander != null) { FilterMana commanderMana = commander.getColorIdentity(); @@ -114,7 +114,7 @@ class CommanderIdentityManaEffect extends ManaEffect { if (controller != null) { Choice choice = new ChoiceImpl(); choice.setMessage("Pick a mana color"); - for (UUID commanderId : controller.getCommandersIds()) { + for (UUID commanderId : game.getCommandersIds(controller)) { Card commander = game.getCard(commanderId); if (commander != null) { FilterMana commanderMana = commander.getColorIdentity(); diff --git a/Mage/src/main/java/mage/constants/CommanderCardType.java b/Mage/src/main/java/mage/constants/CommanderCardType.java new file mode 100644 index 00000000000..a4c3e007d26 --- /dev/null +++ b/Mage/src/main/java/mage/constants/CommanderCardType.java @@ -0,0 +1,10 @@ +package mage.constants; + +/** + * @author JayDi85 + */ +public enum CommanderCardType { + ANY, + COMMANDER_OR_OATHBREAKER, + SIGNATURE_SPELL +} diff --git a/Mage/src/main/java/mage/filter/predicate/permanent/CommanderPredicate.java b/Mage/src/main/java/mage/filter/predicate/permanent/CommanderPredicate.java index 58bc4269b22..ada3bcbaeaa 100644 --- a/Mage/src/main/java/mage/filter/predicate/permanent/CommanderPredicate.java +++ b/Mage/src/main/java/mage/filter/predicate/permanent/CommanderPredicate.java @@ -20,7 +20,7 @@ public enum CommanderPredicate implements Predicate { public boolean apply(Permanent input, Game game) { Player owner = game.getPlayer(input.getOwnerId()); return owner != null - && owner.getCommandersIds().contains(input.getId()); + && game.getCommandersIds(owner).contains(input.getId()); } @Override diff --git a/Mage/src/main/java/mage/game/Game.java b/Mage/src/main/java/mage/game/Game.java index 30638c63a1c..af5ce5a1ead 100644 --- a/Mage/src/main/java/mage/game/Game.java +++ b/Mage/src/main/java/mage/game/Game.java @@ -476,4 +476,9 @@ public interface Game extends MageItem, Serializable { Mulligan getMulligan(); + Set getCommandersIds(Player player, CommanderCardType commanderCardType); + + default Set getCommandersIds(Player player) { + return getCommandersIds(player, CommanderCardType.ANY); + } } diff --git a/Mage/src/main/java/mage/game/GameCommanderImpl.java b/Mage/src/main/java/mage/game/GameCommanderImpl.java index c36b09fff95..1430103aca7 100644 --- a/Mage/src/main/java/mage/game/GameCommanderImpl.java +++ b/Mage/src/main/java/mage/game/GameCommanderImpl.java @@ -59,7 +59,7 @@ public abstract class GameCommanderImpl extends GameImpl { } // init commanders - for (UUID commanderId : player.getCommandersIds()) { + for (UUID commanderId : this.getCommandersIds(player)) { Card commander = this.getCard(commanderId); if (commander != null) { initCommander(commander, player); @@ -183,7 +183,7 @@ public abstract class GameCommanderImpl extends GameImpl { @Override protected boolean checkStateBasedActions() { for (Player player : getPlayers().values()) { - for (UUID commanderId : player.getCommandersIds()) { + for (UUID commanderId : this.getCommandersIds(player)) { CommanderInfoWatcher damageWatcher = getState().getWatcher(CommanderInfoWatcher.class, commanderId); if (damageWatcher == null) { continue; diff --git a/Mage/src/main/java/mage/game/GameImpl.java b/Mage/src/main/java/mage/game/GameImpl.java index 5994ff0ca26..f3f48ac1436 100644 --- a/Mage/src/main/java/mage/game/GameImpl.java +++ b/Mage/src/main/java/mage/game/GameImpl.java @@ -3193,4 +3193,9 @@ public abstract class GameImpl implements Game, Serializable { return mulligan; } + @Override + public Set getCommandersIds(Player player, CommanderCardType commanderCardType) { + return player.getCommandersIds(); + } + } diff --git a/Mage/src/main/java/mage/players/Player.java b/Mage/src/main/java/mage/players/Player.java index 6dc09c8f9dd..bef24d471ef 100644 --- a/Mage/src/main/java/mage/players/Player.java +++ b/Mage/src/main/java/mage/players/Player.java @@ -696,9 +696,11 @@ public interface Player extends MageItem, Copyable { /** * Get the commanderIds of the player + * Deprecated, use game.getCommandersIds(xxx) instead * * @return */ + @Deprecated Set getCommandersIds(); /** diff --git a/Mage/src/main/java/mage/players/PlayerImpl.java b/Mage/src/main/java/mage/players/PlayerImpl.java index c39eff82b06..569f68e1811 100644 --- a/Mage/src/main/java/mage/players/PlayerImpl.java +++ b/Mage/src/main/java/mage/players/PlayerImpl.java @@ -302,7 +302,7 @@ public abstract class PlayerImpl implements Player, Serializable { this.sideboard = player.getSideboard().copy(); this.hand = player.getHand().copy(); this.graveyard = player.getGraveyard().copy(); - this.commandersIds = player.getCommandersIds(); + this.commandersIds = new HashSet<>(player.getCommandersIds()); this.abilities = player.getAbilities().copy(); this.counters = player.getCounters().copy(); diff --git a/Mage/src/main/java/mage/watchers/common/CommanderPlaysCountWatcher.java b/Mage/src/main/java/mage/watchers/common/CommanderPlaysCountWatcher.java index 789cb2d2c84..43c7a19b8d8 100644 --- a/Mage/src/main/java/mage/watchers/common/CommanderPlaysCountWatcher.java +++ b/Mage/src/main/java/mage/watchers/common/CommanderPlaysCountWatcher.java @@ -43,7 +43,7 @@ public class CommanderPlaysCountWatcher extends Watcher { UUID possibleCommanderId = event.getSourceId(); boolean isCommanderObject = false; for (Player player : game.getPlayers().values()) { - if (player.getCommandersIds().contains(possibleCommanderId)) { + if (game.getCommandersIds(player).contains(possibleCommanderId)) { isCommanderObject = true; break; } From 1465e505c0ef5471b87ca58222e771b791c9ade1 Mon Sep 17 00:00:00 2001 From: Oleg Agafonov Date: Mon, 27 May 2019 18:02:28 +0400 Subject: [PATCH 05/38] Added duel mode for oathbreaker --- .../Mage.Game.OathbreakerDuel/pom.xml | 55 +++ .../src/mage/game/OathbreakerDuel.java | 36 ++ .../src/mage/game/OathbreakerDuelMatch.java | 29 ++ .../src/mage/game/OathbreakerDuelType.java | 29 ++ .../src/mage/game/OathbreakerFreeForAll.java | 28 -- Mage.Server.Plugins/pom.xml | 1 + Mage.Server/config/config.xml | 298 +++++--------- Mage.Server/pom.xml | 6 + Mage.Server/release/config/config.xml | 364 ++++++------------ 9 files changed, 365 insertions(+), 481 deletions(-) create mode 100644 Mage.Server.Plugins/Mage.Game.OathbreakerDuel/pom.xml create mode 100644 Mage.Server.Plugins/Mage.Game.OathbreakerDuel/src/mage/game/OathbreakerDuel.java create mode 100644 Mage.Server.Plugins/Mage.Game.OathbreakerDuel/src/mage/game/OathbreakerDuelMatch.java create mode 100644 Mage.Server.Plugins/Mage.Game.OathbreakerDuel/src/mage/game/OathbreakerDuelType.java diff --git a/Mage.Server.Plugins/Mage.Game.OathbreakerDuel/pom.xml b/Mage.Server.Plugins/Mage.Game.OathbreakerDuel/pom.xml new file mode 100644 index 00000000000..717a09c791f --- /dev/null +++ b/Mage.Server.Plugins/Mage.Game.OathbreakerDuel/pom.xml @@ -0,0 +1,55 @@ + + + 4.0.0 + + + org.mage + mage-server-plugins + 1.4.35 + + + mage-game-oathbreakerduel + jar + Mage Game Oathbreaker Two Player + + + + ${project.groupId} + mage + ${project.version} + + + org.mage + mage-game-oathbreakerfreeforall + 1.4.35 + compile + + + + + src + + + org.apache.maven.plugins + maven-compiler-plugin + + 1.8 + 1.8 + + + + maven-resources-plugin + + UTF-8 + + + + + + mage-game-oathbreakerduel + + + + + diff --git a/Mage.Server.Plugins/Mage.Game.OathbreakerDuel/src/mage/game/OathbreakerDuel.java b/Mage.Server.Plugins/Mage.Game.OathbreakerDuel/src/mage/game/OathbreakerDuel.java new file mode 100644 index 00000000000..6979861ee8e --- /dev/null +++ b/Mage.Server.Plugins/Mage.Game.OathbreakerDuel/src/mage/game/OathbreakerDuel.java @@ -0,0 +1,36 @@ +package mage.game; + +import mage.constants.MultiplayerAttackOption; +import mage.constants.RangeOfInfluence; +import mage.game.match.MatchType; +import mage.game.mulligan.Mulligan; + +/** + * @author JayDi85 + */ +public class OathbreakerDuel extends OathbreakerFreeForAll { + + public OathbreakerDuel(MultiplayerAttackOption attackOption, RangeOfInfluence range, Mulligan mulligan, int startLife) { + super(attackOption, range, mulligan, startLife); + } + + public OathbreakerDuel(final OathbreakerDuel game) { + super(game); + } + + @Override + public MatchType getGameType() { + return new OathbreakerDuelType(); + } + + @Override + public int getNumPlayers() { + return 2; + } + + @Override + public OathbreakerDuel copy() { + return new OathbreakerDuel(this); + } + +} diff --git a/Mage.Server.Plugins/Mage.Game.OathbreakerDuel/src/mage/game/OathbreakerDuelMatch.java b/Mage.Server.Plugins/Mage.Game.OathbreakerDuel/src/mage/game/OathbreakerDuelMatch.java new file mode 100644 index 00000000000..2d2491e2a14 --- /dev/null +++ b/Mage.Server.Plugins/Mage.Game.OathbreakerDuel/src/mage/game/OathbreakerDuelMatch.java @@ -0,0 +1,29 @@ +package mage.game; + +import mage.game.match.MatchImpl; +import mage.game.match.MatchOptions; +import mage.game.mulligan.Mulligan; + +/** + * @author JayDi85 + */ +public class OathbreakerDuelMatch extends MatchImpl { + + public OathbreakerDuelMatch(MatchOptions options) { + super(options); + } + + @Override + public void startGame() throws GameException { + int startLife = 20; + boolean alsoHand = true; + Mulligan mulligan = options.getMulliganType().getMulligan(options.getFreeMulligans()); + OathbreakerDuel game = new OathbreakerDuel(options.getAttackOption(), options.getRange(), mulligan, startLife); + game.setCheckCommanderDamage(false); + game.setStartMessage(this.createGameStartMessage()); + game.setAlsoHand(alsoHand); + game.setAlsoLibrary(true); + initGame(game); + games.add(game); + } +} diff --git a/Mage.Server.Plugins/Mage.Game.OathbreakerDuel/src/mage/game/OathbreakerDuelType.java b/Mage.Server.Plugins/Mage.Game.OathbreakerDuel/src/mage/game/OathbreakerDuelType.java new file mode 100644 index 00000000000..ad52c5cce78 --- /dev/null +++ b/Mage.Server.Plugins/Mage.Game.OathbreakerDuel/src/mage/game/OathbreakerDuelType.java @@ -0,0 +1,29 @@ +package mage.game; + +import mage.game.match.MatchType; + +/** + * @author JayDi85 + */ +public class OathbreakerDuelType extends MatchType { + + public OathbreakerDuelType() { + this.name = "Oathbreaker Two Player Duel"; + this.maxPlayers = 2; + this.minPlayers = 2; + this.numTeams = 0; + this.useAttackOption = false; + this.useRange = false; + this.sideboardingAllowed = false; + } + + protected OathbreakerDuelType(final OathbreakerDuelType matchType) { + super(matchType); + } + + @Override + public OathbreakerDuelType copy() { + return new OathbreakerDuelType(this); + } + +} diff --git a/Mage.Server.Plugins/Mage.Game.OathbreakerFreeForAll/src/mage/game/OathbreakerFreeForAll.java b/Mage.Server.Plugins/Mage.Game.OathbreakerFreeForAll/src/mage/game/OathbreakerFreeForAll.java index 55066b6f6f5..4add5af79e6 100644 --- a/Mage.Server.Plugins/Mage.Game.OathbreakerFreeForAll/src/mage/game/OathbreakerFreeForAll.java +++ b/Mage.Server.Plugins/Mage.Game.OathbreakerFreeForAll/src/mage/game/OathbreakerFreeForAll.java @@ -40,34 +40,6 @@ public class OathbreakerFreeForAll extends GameCommanderImpl { @Override protected void init(UUID choosingPlayerId) { - /* - // prepare commanders and signature spells info - playerSignatureSpell.clear(); - playerCommanders.clear(); - for (UUID playerId : state.getPlayerList(startingPlayerId)) { - UUID signatureSpell = null; - List commanders = new ArrayList<>(); - - Player player = getPlayer(playerId); - List searchList = new ArrayList<>(); - searchList.addAll(player.getCommandersIds()); - searchList.addAll(new ArrayList<>(player.getSideboard())); - for (UUID id : searchList) { - Card commander = this.getCard(id); - if (commander != null) { - if (commander.isInstantOrSorcery()) { - signatureSpell = commander.getId(); - } else if (!commanders.contains(commander.getId())) { - commanders.add(commander.getId()); - } - } - } - - playerSignatureSpell.put(playerId, signatureSpell); - playerCommanders.put(playerId, commanders); - } - */ - // init base commander game startingPlayerSkipsDraw = false; super.init(choosingPlayerId); diff --git a/Mage.Server.Plugins/pom.xml b/Mage.Server.Plugins/pom.xml index 497e462c37d..96c567750d3 100644 --- a/Mage.Server.Plugins/pom.xml +++ b/Mage.Server.Plugins/pom.xml @@ -30,6 +30,7 @@ Mage.Game.FreeformCommanderFreeForAll Mage.Game.BrawlDuel Mage.Game.BrawlFreeForAll + Mage.Game.OathbreakerDuel Mage.Game.OathbreakerFreeForAll Mage.Game.TwoPlayerDuel Mage.Player.AI diff --git a/Mage.Server/config/config.xml b/Mage.Server/config/config.xml index 500b4c29b2c..baac728b02b 100644 --- a/Mage.Server/config/config.xml +++ b/Mage.Server/config/config.xml @@ -69,234 +69,126 @@ - + - - - - - - - - - - - - - - + + + + + + + + + + + + + + + - - - - - - - - - - - - - - + + + + + + + + + + + + + + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - + - + - - - - - - - + + + + + + + - - - + + + - - + + - - - + + + - - - + + + - - - - - + + + + + - - + + - + \ No newline at end of file diff --git a/Mage.Server/pom.xml b/Mage.Server/pom.xml index b835f3e7df0..b66193422e9 100644 --- a/Mage.Server/pom.xml +++ b/Mage.Server/pom.xml @@ -192,6 +192,12 @@ runtime + + ${project.groupId} + mage-game-oathbreakerduel + ${project.version} + runtime + ${project.groupId} mage-game-oathbreakerfreeforall diff --git a/Mage.Server/release/config/config.xml b/Mage.Server/release/config/config.xml index 37cdb35f4c6..fcaffeb49a0 100644 --- a/Mage.Server/release/config/config.xml +++ b/Mage.Server/release/config/config.xml @@ -61,264 +61,128 @@ mailFromAddress="" /> - - - + + + - - - - - - - - - - - - - - + + + + + + + + + + + + + + + - - - - - - - - - - - - - - + + + + + + + + + + + + + + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + From 8ca5a3ec2edbf6b7bf8aa2023a980ac7d5f5aed6 Mon Sep 17 00:00:00 2001 From: Oleg Agafonov Date: Mon, 27 May 2019 18:17:34 +0400 Subject: [PATCH 06/38] UI: added filter button for oathbreaker format --- .../java/mage/client/table/TablesPanel.form | 26 ++++++++-- .../java/mage/client/table/TablesPanel.java | 51 ++++++++++--------- 2 files changed, 49 insertions(+), 28 deletions(-) diff --git a/Mage.Client/src/main/java/mage/client/table/TablesPanel.form b/Mage.Client/src/main/java/mage/client/table/TablesPanel.form index 70f04d7ec34..41e7b06a4c9 100644 --- a/Mage.Client/src/main/java/mage/client/table/TablesPanel.form +++ b/Mage.Client/src/main/java/mage/client/table/TablesPanel.form @@ -47,7 +47,7 @@ - + @@ -290,7 +290,7 @@ - + @@ -307,7 +307,7 @@ - + @@ -396,7 +396,7 @@ - + @@ -412,7 +412,7 @@ - + @@ -433,6 +433,22 @@ + + + + + + + + + + + + + + + + diff --git a/Mage.Client/src/main/java/mage/client/table/TablesPanel.java b/Mage.Client/src/main/java/mage/client/table/TablesPanel.java index 9544426506d..5d01790591a 100644 --- a/Mage.Client/src/main/java/mage/client/table/TablesPanel.java +++ b/Mage.Client/src/main/java/mage/client/table/TablesPanel.java @@ -329,11 +329,11 @@ public class TablesPanel extends javax.swing.JPanel { chatPanelMain.getUserChatPanel().setBorder(null); chatPanelMain.getUserChatPanel().setChatType(ChatPanelBasic.ChatType.TABLES); - // 4. BUTTONS + // 4. BUTTONS (add new buttons to the end of the list -- if not then users lost their filter settings) filterButtons = new JToggleButton[]{btnStateWaiting, btnStateActive, btnStateFinished, btnTypeMatch, btnTypeTourneyConstructed, btnTypeTourneyLimited, btnFormatBlock, btnFormatStandard, btnFormatModern, btnFormatLegacy, btnFormatVintage, btnFormatPremodern, btnFormatCommander, btnFormatTinyLeader, btnFormatLimited, btnFormatOther, - btnSkillBeginner, btnSkillCasual, btnSkillSerious, btnRated, btnUnrated, btnOpen, btnPassword}; + btnSkillBeginner, btnSkillCasual, btnSkillSerious, btnRated, btnUnrated, btnOpen, btnPassword, btnFormatOathbreaker}; JComponent[] components = new JComponent[]{chatPanelMain, jSplitPane1, jScrollPaneTablesActive, jScrollPaneTablesFinished, jPanelTop, jPanelTables}; for (JComponent component : components) { @@ -817,6 +817,9 @@ public class TablesPanel extends javax.swing.JPanel { if (btnFormatTinyLeader.isSelected()) { formatFilterList.add(RowFilter.regexFilter("^Tiny", TablesTableModel.COLUMN_DECK_TYPE)); } + if (btnFormatOathbreaker.isSelected()) { + formatFilterList.add(RowFilter.regexFilter("^Oathbreaker", TablesTableModel.COLUMN_DECK_TYPE)); + } if (btnFormatLimited.isSelected()) { formatFilterList.add(RowFilter.regexFilter("^Limited", TablesTableModel.COLUMN_DECK_TYPE)); } @@ -967,6 +970,7 @@ public class TablesPanel extends javax.swing.JPanel { btnFormatPremodern = new javax.swing.JToggleButton(); jSeparator3 = new javax.swing.JToolBar.Separator(); btnFormatCommander = new javax.swing.JToggleButton(); + btnFormatOathbreaker = new javax.swing.JToggleButton(); btnFormatTinyLeader = new javax.swing.JToggleButton(); jSeparator2 = new javax.swing.JToolBar.Separator(); btnFormatLimited = new javax.swing.JToggleButton(); @@ -1180,7 +1184,7 @@ public class TablesPanel extends javax.swing.JPanel { btnRated.setVerticalTextPosition(javax.swing.SwingConstants.BOTTOM); btnRated.addActionListener(new java.awt.event.ActionListener() { public void actionPerformed(java.awt.event.ActionEvent evt) { - btnRatedbtnFilterActionPerformed(evt); + btnFilterActionPerformed(evt); } }); filterBar1.add(btnRated); @@ -1197,7 +1201,7 @@ public class TablesPanel extends javax.swing.JPanel { btnUnrated.setVerticalTextPosition(javax.swing.SwingConstants.BOTTOM); btnUnrated.addActionListener(new java.awt.event.ActionListener() { public void actionPerformed(java.awt.event.ActionEvent evt) { - btnUnratedbtnFilterActionPerformed(evt); + btnFilterActionPerformed(evt); } }); filterBar1.add(btnUnrated); @@ -1279,7 +1283,7 @@ public class TablesPanel extends javax.swing.JPanel { btnFormatVintage.setVerticalTextPosition(javax.swing.SwingConstants.BOTTOM); btnFormatVintage.addActionListener(new java.awt.event.ActionListener() { public void actionPerformed(java.awt.event.ActionEvent evt) { - btnFormatVintageActionPerformed(evt); + btnFilterActionPerformed(evt); } }); filterBar2.add(btnFormatVintage); @@ -1295,7 +1299,7 @@ public class TablesPanel extends javax.swing.JPanel { btnFormatPremodern.setVerticalTextPosition(javax.swing.SwingConstants.BOTTOM); btnFormatPremodern.addActionListener(new java.awt.event.ActionListener() { public void actionPerformed(java.awt.event.ActionEvent evt) { - btnFormatPremodernActionPerformed(evt); + btnFilterActionPerformed(evt); } }); filterBar2.add(btnFormatPremodern); @@ -1317,6 +1321,22 @@ public class TablesPanel extends javax.swing.JPanel { }); filterBar2.add(btnFormatCommander); + btnFormatOathbreaker.setSelected(true); + btnFormatOathbreaker.setText("Oathbreaker"); + btnFormatOathbreaker.setToolTipText("Oathbreaker format."); + btnFormatOathbreaker.setFocusPainted(false); + btnFormatOathbreaker.setFocusable(false); + btnFormatOathbreaker.setHorizontalTextPosition(javax.swing.SwingConstants.CENTER); + btnFormatOathbreaker.setRequestFocusEnabled(false); + btnFormatOathbreaker.setVerifyInputWhenFocusTarget(false); + btnFormatOathbreaker.setVerticalTextPosition(javax.swing.SwingConstants.BOTTOM); + btnFormatOathbreaker.addActionListener(new java.awt.event.ActionListener() { + public void actionPerformed(java.awt.event.ActionEvent evt) { + btnFilterActionPerformed(evt); + } + }); + filterBar2.add(btnFormatOathbreaker); + btnFormatTinyLeader.setSelected(true); btnFormatTinyLeader.setText("Tiny Leader"); btnFormatTinyLeader.setToolTipText("Tiny Leader format."); @@ -1432,7 +1452,7 @@ public class TablesPanel extends javax.swing.JPanel { .addGroup(jPanelTopLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) .addComponent(btnQuickStartDuel) .addComponent(btnQuickStartCommander)) - .addContainerGap(734, Short.MAX_VALUE)) + .addContainerGap(667, Short.MAX_VALUE)) ); jPanelTopLayout.setVerticalGroup( jPanelTopLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) @@ -1631,22 +1651,6 @@ public class TablesPanel extends javax.swing.JPanel { this.startUpdateTasks(true); }//GEN-LAST:event_btnStateFinishedActionPerformed - private void btnRatedbtnFilterActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_btnRatedbtnFilterActionPerformed - setTableFilter(); - }//GEN-LAST:event_btnRatedbtnFilterActionPerformed - - private void btnUnratedbtnFilterActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_btnUnratedbtnFilterActionPerformed - setTableFilter(); - }//GEN-LAST:event_btnUnratedbtnFilterActionPerformed - - private void btnFormatPremodernActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_btnFormatPremodernActionPerformed - setTableFilter(); - }//GEN-LAST:event_btnFormatPremodernActionPerformed - - private void btnFormatVintageActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_btnFormatVintageActionPerformed - setTableFilter(); - }//GEN-LAST:event_btnFormatVintageActionPerformed - private void buttonWhatsNewActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_buttonWhatsNewActionPerformed MageFrame.getInstance().showWhatsNewDialog(true); }//GEN-LAST:event_buttonWhatsNewActionPerformed @@ -1666,6 +1670,7 @@ public class TablesPanel extends javax.swing.JPanel { private javax.swing.JToggleButton btnFormatLegacy; private javax.swing.JToggleButton btnFormatLimited; private javax.swing.JToggleButton btnFormatModern; + private javax.swing.JToggleButton btnFormatOathbreaker; private javax.swing.JToggleButton btnFormatOther; private javax.swing.JToggleButton btnFormatPremodern; private javax.swing.JToggleButton btnFormatStandard; From 6951ec920a521a842854d9dafaaf544e24804e35 Mon Sep 17 00:00:00 2001 From: Evan Kranzler Date: Mon, 27 May 2019 11:17:06 -0400 Subject: [PATCH 07/38] updated MH1 spoiler --- Utils/mtg-cards-data.txt | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/Utils/mtg-cards-data.txt b/Utils/mtg-cards-data.txt index 783e3ce4813..8cd37961ad1 100644 --- a/Utils/mtg-cards-data.txt +++ b/Utils/mtg-cards-data.txt @@ -35155,15 +35155,17 @@ Feaster of Fools|Modern Horizons|90|U|{4}{B}{B}|Creature - Demon|3|3|Convoke$Fly Force of Despair|Modern Horizons|92|R|{1}{B}{B}|Instant|||If it's not your turn, you may exile a black card from your hand rather than pay this spell's mana cost.$Destroy all creatures that entered the battlefield this turn.| Headless Specter|Modern Horizons|95|C|{1}{B}{B}|Creature - Specter|2|2|Flying$Hellbent — Whenever Headless Specter deals combat damage to a player, if you have no cards in hand, that player discards a card at random.| Plague Engineer|Modern Horizons|100|R|{2}{B}|Creature - Carrier|2|2|Deathtouch$As Plague Engineer enters the battlefield, choose a creature type.$Creatures of the chosen type your opponents control get -1/-1.| -Sling-Gang Lieutenant|Modern Horizons|108|U|{3}{B}|Creature - Goblin|||When Sling-Gang Lieutenant enters the battlefield, create two 1/1 red Goblin creature tokens.$Sacrifice a Goblin: Target player loses 1 life and you gain 1 life.| +Sling-Gang Lieutenant|Modern Horizons|108|U|{3}{B}|Creature - Goblin|1|1|When Sling-Gang Lieutenant enters the battlefield, create two 1/1 red Goblin creature tokens.$Sacrifice a Goblin: Target player loses 1 life and you gain 1 life.| Umezawa's Charm|Modern Horizons|111|C|{1}{B}|Instant|||Choose one—$• Target creature gets +2/+2 until end of turn.$• Target creature gets -1/-1 until end of turn.$• You gain 2 life.| Undead Augur|Modern Horizons|112|U|{B}{B}|Creature - Zombie Wizard|2|2|Whenever Undead Augur or another Zombie you control dies, you draw a card and you lose 1 life.| Venomous Changeling|Modern Horizons|114|C|{2}{B}|Creature - Shapeshifter|1|3|Changeling$Deathtouch| +Yawgmoth, Thran Physician|Modern Horizons|116|M|{2}{B}{B}|Legendary Creature - Human Cleric|2|4|Protection from Humans.$Pay 1 life, Sacrifice another creature: Put a -1/-1 counter on up to one target creature and draw a card.${B}{B}, Discard a card: Proliferate.| Aria of Flame|Modern Horizons|118|R|{2}{R}|Enchantment|||When Aria of Flame enters the battlefield, each opponent gains 10 life.$Whenever you cast an instant or sorcery spell, put a verse counter on Aria of Flame, then it deals damage equal to the number of verse counters on it to target player or planeswalker.| Firebolt|Modern Horizons|122|U|{R}|Sorcery|||Firebolt deals 2 damage to any target.$Flashback {4}{R}| Fists of Flame|Modern Horizons|123|C|{1}{R}|Instant|||Draw a card. Until end of turn, target creature gains trample and gets +1/+0 for each card you've drawn this turn.| Force of Rage|Modern Horizons|124|R|{1}{R}{R}|Instant|||If it's not your turn, you may exile a red card from your hand rather than pay this spell's mana cost.$Create two 3/1 red Elemental creature tokens with trample and haste. Sacrifice those tokens at the beginning of your next upkeep.| Goatnap|Modern Horizons|126|C|{2}{R}|Sorcery|||Gain control of target creature until end of turn. Untap that creature. It gains haste until end of turn. If that creature is a Goat, it also gets +3/+0 until end of turn.| +Goblin Champion|Modern Horizons|127|C|{R}|Creature - Goblin Warrior|0|1|Haste$Exalted| Goblin Engineer|Modern Horizons|128|R|{1}{R}|Creature - Goblin Artificer|1|2|When Goblin Engineer enters the battlefield, you may search your library for an artifact card, put it into your graveyard, then shuffle your library.${R}, {T}, Sacrifice an artifact: Return target artifact card with converted mana cost 3 or less from your graveyard to the battlefield.| Goblin Matron|Modern Horizons|129|U|{2}{R}|Creature - Goblin|1|1|When Goblin Matron enters the battlefield, you may search your library for a Goblin card, reveal that card, and put it into your hand. If you do, shuffle your library.| Goblin War Party|Modern Horizons|131|C|{3}{R}|Sorcery|||Choose one —$• Create three 1/1 red Goblin creature tokens.$• Creatures you control get +1/+1 and gain haste until end of turn.$Entwine {2}{R}| @@ -35177,6 +35179,7 @@ Ravenous Giant|Modern Horizons|143|U|{2}{R}{R}|Creature - Giant|5|5|At the begin Seasoned Pyromancer|Modern Horizons|145|M|{1}{R}{R}|Creature - Human Shaman|2|2|When Seasoned Pyromancer enters the battlefield, discard two cards, then draw two cards. For each nonland card discarded this way, create a 1/1 red Elemental creature token.${3}{R}{R}, Exile Seasoned Pyromancer from your graveyard: Create two 1/1 red Elemental creature tokens.| Ayula, Queen Among Bears|Modern Horizons|155|R|{1}{G}|Legendary Creature - Bear|2|2|Whenever another Bear enters the battlefield under your control, choose one —$• Put two +1/+1 counters on target Bear.$• Target Bear you control fights target creature you don't control.| Ayula's Influence|Modern Horizons|156|R|{G}{G}{G}|Enchantment|||Discard a land card: Create a 2/2 green Bear creature token.| +Collector Ouphe|Modern Horizons|158|R|{1}{G}|Creature - Ouphe|2|2|Activated abilities of artifacts can't be activated.| Deep Forest Hermit|Modern Horizons|161|R|{3}{G}{G}|Creature - Elf Druid|1|1|Vanishing 3$When Deep Forest Hermit enters the battlefield, create four 1/1 green Squirrel creature tokens.$Squirrels you control get +1/+1.| Elvish Fury|Modern Horizons|162|C|{G}|Instant|||Buyback {4}$Target creature gets +2/+2 until end of turn.| Force of Vigor|Modern Horizons|164|R|{2}{G}{G}|Instant|||If it's not your turn, you may exile a green card from your hand rather than pay this spell's mana cost.$Destroy up to two target artifacts and/or enchantments.| From ab5036fcfb89be7bdda6a8ff0b46488c0282b996 Mon Sep 17 00:00:00 2001 From: Evan Kranzler Date: Mon, 27 May 2019 11:18:06 -0400 Subject: [PATCH 08/38] Implemented Goblin Champion --- .../src/mage/cards/g/GoblinChampion.java | 41 +++++++++++++++++++ Mage.Sets/src/mage/sets/ModernHorizons.java | 1 + 2 files changed, 42 insertions(+) create mode 100644 Mage.Sets/src/mage/cards/g/GoblinChampion.java diff --git a/Mage.Sets/src/mage/cards/g/GoblinChampion.java b/Mage.Sets/src/mage/cards/g/GoblinChampion.java new file mode 100644 index 00000000000..3bd4c125b5d --- /dev/null +++ b/Mage.Sets/src/mage/cards/g/GoblinChampion.java @@ -0,0 +1,41 @@ +package mage.cards.g; + +import mage.MageInt; +import mage.abilities.keyword.ExaltedAbility; +import mage.abilities.keyword.HasteAbility; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.SubType; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class GoblinChampion extends CardImpl { + + public GoblinChampion(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{R}"); + + this.subtype.add(SubType.GOBLIN); + this.subtype.add(SubType.WARRIOR); + this.power = new MageInt(0); + this.toughness = new MageInt(1); + + // Haste + this.addAbility(HasteAbility.getInstance()); + + // Exalted + this.addAbility(new ExaltedAbility()); + } + + private GoblinChampion(final GoblinChampion card) { + super(card); + } + + @Override + public GoblinChampion copy() { + return new GoblinChampion(this); + } +} diff --git a/Mage.Sets/src/mage/sets/ModernHorizons.java b/Mage.Sets/src/mage/sets/ModernHorizons.java index 208398cc2f3..36b0aafc521 100644 --- a/Mage.Sets/src/mage/sets/ModernHorizons.java +++ b/Mage.Sets/src/mage/sets/ModernHorizons.java @@ -68,6 +68,7 @@ public final class ModernHorizons extends ExpansionSet { cards.add(new SetCardInfo("Giver of Runes", 13, Rarity.RARE, mage.cards.g.GiverOfRunes.class)); cards.add(new SetCardInfo("Glacial Revelation", 167, Rarity.UNCOMMON, mage.cards.g.GlacialRevelation.class)); cards.add(new SetCardInfo("Goatnap", 126, Rarity.COMMON, mage.cards.g.Goatnap.class)); + cards.add(new SetCardInfo("Goblin Champion", 127, Rarity.COMMON, mage.cards.g.GoblinChampion.class)); cards.add(new SetCardInfo("Goblin Engineer", 128, Rarity.RARE, mage.cards.g.GoblinEngineer.class)); cards.add(new SetCardInfo("Goblin Matron", 129, Rarity.UNCOMMON, mage.cards.g.GoblinMatron.class)); cards.add(new SetCardInfo("Goblin War Party", 131, Rarity.COMMON, mage.cards.g.GoblinWarParty.class)); From a2f149f7e4aa6409cb24c37ffb1c91239e6a4ffa Mon Sep 17 00:00:00 2001 From: Evan Kranzler Date: Mon, 27 May 2019 11:19:53 -0400 Subject: [PATCH 09/38] Implemented Collector Ouphe --- .../src/mage/cards/c/CollectorOuphe.java | 69 +++++++++++++++++++ Mage.Sets/src/mage/sets/ModernHorizons.java | 1 + 2 files changed, 70 insertions(+) create mode 100644 Mage.Sets/src/mage/cards/c/CollectorOuphe.java diff --git a/Mage.Sets/src/mage/cards/c/CollectorOuphe.java b/Mage.Sets/src/mage/cards/c/CollectorOuphe.java new file mode 100644 index 00000000000..48cf57ace37 --- /dev/null +++ b/Mage.Sets/src/mage/cards/c/CollectorOuphe.java @@ -0,0 +1,69 @@ +package mage.cards.c; + +import mage.MageInt; +import mage.abilities.Ability; +import mage.abilities.common.SimpleStaticAbility; +import mage.abilities.effects.RestrictionEffect; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.Duration; +import mage.constants.SubType; +import mage.game.Game; +import mage.game.permanent.Permanent; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class CollectorOuphe extends CardImpl { + + public CollectorOuphe(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{1}{G}"); + + this.subtype.add(SubType.OUPHE); + this.power = new MageInt(2); + this.toughness = new MageInt(2); + + // Activated abilities of artifacts can't be activated. + this.addAbility(new SimpleStaticAbility(new CollectorOupheEffect())); + } + + private CollectorOuphe(final CollectorOuphe card) { + super(card); + } + + @Override + public CollectorOuphe copy() { + return new CollectorOuphe(this); + } +} + +class CollectorOupheEffect extends RestrictionEffect { + + CollectorOupheEffect() { + super(Duration.WhileOnBattlefield); + staticText = "Activated abilities of artifacts can't be activated"; + } + + private CollectorOupheEffect(final CollectorOupheEffect effect) { + super(effect); + } + + @Override + public boolean applies(Permanent permanent, Ability source, Game game) { + return permanent.isArtifact(); + } + + @Override + public boolean canUseActivatedAbilities(Permanent permanent, Ability source, Game game, boolean canUseChooseDialogs) { + return false; + } + + @Override + public CollectorOupheEffect copy() { + return new CollectorOupheEffect(this); + } + +} \ No newline at end of file diff --git a/Mage.Sets/src/mage/sets/ModernHorizons.java b/Mage.Sets/src/mage/sets/ModernHorizons.java index 36b0aafc521..b91a6ab280f 100644 --- a/Mage.Sets/src/mage/sets/ModernHorizons.java +++ b/Mage.Sets/src/mage/sets/ModernHorizons.java @@ -41,6 +41,7 @@ public final class ModernHorizons extends ExpansionSet { cards.add(new SetCardInfo("Choking Tethers", 44, Rarity.COMMON, mage.cards.c.ChokingTethers.class)); cards.add(new SetCardInfo("Cloudshredder Sliver", 195, Rarity.RARE, mage.cards.c.CloudshredderSliver.class)); cards.add(new SetCardInfo("Collected Conjuring", 196, Rarity.RARE, mage.cards.c.CollectedConjuring.class)); + cards.add(new SetCardInfo("Collector Ouphe", 158, Rarity.RARE, mage.cards.c.CollectorOuphe.class)); cards.add(new SetCardInfo("Crypt Rats", 84, Rarity.UNCOMMON, mage.cards.c.CryptRats.class)); cards.add(new SetCardInfo("Deep Forest Hermit", 161, Rarity.RARE, mage.cards.d.DeepForestHermit.class)); cards.add(new SetCardInfo("Diabolic Edict", 87, Rarity.COMMON, mage.cards.d.DiabolicEdict.class)); From 2060035b32ce126ad8b259a18b755e487a40341d Mon Sep 17 00:00:00 2001 From: Evan Kranzler Date: Mon, 27 May 2019 11:26:33 -0400 Subject: [PATCH 10/38] Implemented Yawgmoth, Thran Physician --- .../mage/cards/y/YawgmothThranPhysician.java | 72 +++++++++++++++++++ Mage.Sets/src/mage/sets/ModernHorizons.java | 1 + 2 files changed, 73 insertions(+) create mode 100644 Mage.Sets/src/mage/cards/y/YawgmothThranPhysician.java diff --git a/Mage.Sets/src/mage/cards/y/YawgmothThranPhysician.java b/Mage.Sets/src/mage/cards/y/YawgmothThranPhysician.java new file mode 100644 index 00000000000..b9dab388ccb --- /dev/null +++ b/Mage.Sets/src/mage/cards/y/YawgmothThranPhysician.java @@ -0,0 +1,72 @@ +package mage.cards.y; + +import mage.MageInt; +import mage.abilities.Ability; +import mage.abilities.common.SimpleActivatedAbility; +import mage.abilities.costs.common.DiscardCardCost; +import mage.abilities.costs.common.PayLifeCost; +import mage.abilities.costs.common.SacrificeTargetCost; +import mage.abilities.costs.mana.ManaCostsImpl; +import mage.abilities.effects.common.DrawCardSourceControllerEffect; +import mage.abilities.effects.common.counter.AddCountersTargetEffect; +import mage.abilities.effects.common.counter.ProliferateEffect; +import mage.abilities.keyword.ProtectionAbility; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.SubType; +import mage.constants.SuperType; +import mage.counters.CounterType; +import mage.filter.FilterPermanent; +import mage.filter.StaticFilters; +import mage.filter.common.FilterCreaturePermanent; +import mage.target.common.TargetControlledPermanent; +import mage.target.common.TargetCreaturePermanent; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class YawgmothThranPhysician extends CardImpl { + + private static final FilterPermanent filter = new FilterCreaturePermanent(SubType.HUMAN, "Humans"); + + public YawgmothThranPhysician(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{2}{B}{B}"); + + this.addSuperType(SuperType.LEGENDARY); + this.subtype.add(SubType.HUMAN); + this.subtype.add(SubType.CLERIC); + this.power = new MageInt(2); + this.toughness = new MageInt(4); + + // Protection from Humans. + this.addAbility(new ProtectionAbility(filter)); + + // Pay 1 life, Sacrifice another creature: Put a -1/-1 counter on up to one target creature and draw a card. + Ability ability = new SimpleActivatedAbility( + new AddCountersTargetEffect(CounterType.M1M1.createInstance()), new PayLifeCost(1) + ); + ability.addCost(new SacrificeTargetCost( + new TargetControlledPermanent(StaticFilters.FILTER_CONTROLLED_ANOTHER_CREATURE) + )); + ability.addEffect(new DrawCardSourceControllerEffect(1).concatBy("and")); + ability.addTarget(new TargetCreaturePermanent(0, 1)); + this.addAbility(ability); + + // {B}{B}, Discard a card: Proliferate. + ability = new SimpleActivatedAbility(new ProliferateEffect(), new ManaCostsImpl("{B}{B}")); + ability.addCost(new DiscardCardCost()); + this.addAbility(ability); + } + + private YawgmothThranPhysician(final YawgmothThranPhysician card) { + super(card); + } + + @Override + public YawgmothThranPhysician copy() { + return new YawgmothThranPhysician(this); + } +} diff --git a/Mage.Sets/src/mage/sets/ModernHorizons.java b/Mage.Sets/src/mage/sets/ModernHorizons.java index b91a6ab280f..bf8318e909f 100644 --- a/Mage.Sets/src/mage/sets/ModernHorizons.java +++ b/Mage.Sets/src/mage/sets/ModernHorizons.java @@ -139,6 +139,7 @@ public final class ModernHorizons extends ExpansionSet { cards.add(new SetCardInfo("Winds of Abandon", 37, Rarity.RARE, mage.cards.w.WindsOfAbandon.class)); cards.add(new SetCardInfo("Wing Shards", 38, Rarity.UNCOMMON, mage.cards.w.WingShards.class)); cards.add(new SetCardInfo("Wrenn and Six", 217, Rarity.MYTHIC, mage.cards.w.WrennAndSix.class)); + cards.add(new SetCardInfo("Yawgmoth, Thran Physician", 116, Rarity.MYTHIC, mage.cards.y.YawgmothThranPhysician.class)); cards.add(new SetCardInfo("Zhalfirin Decoy", 39, Rarity.UNCOMMON, mage.cards.z.ZhalfirinDecoy.class)); } } From 970ce4733f0e6eefb7cef88b41290eb4fb650e78 Mon Sep 17 00:00:00 2001 From: Oleg Agafonov Date: Mon, 27 May 2019 19:31:26 +0400 Subject: [PATCH 11/38] Geode Golem - improved work with multiple commanders and lands; --- Mage.Sets/src/mage/cards/g/GeodeGolem.java | 79 ++++++++++++++-------- 1 file changed, 49 insertions(+), 30 deletions(-) diff --git a/Mage.Sets/src/mage/cards/g/GeodeGolem.java b/Mage.Sets/src/mage/cards/g/GeodeGolem.java index d35482b02e4..a164d1f6aab 100644 --- a/Mage.Sets/src/mage/cards/g/GeodeGolem.java +++ b/Mage.Sets/src/mage/cards/g/GeodeGolem.java @@ -3,26 +3,28 @@ package mage.cards.g; import mage.MageInt; import mage.MageObjectReference; import mage.abilities.Ability; -import mage.abilities.SpellAbility; import mage.abilities.common.DealsCombatDamageToAPlayerTriggeredAbility; -import mage.abilities.costs.Cost; import mage.abilities.costs.mana.GenericManaCost; +import mage.abilities.costs.mana.ManaCost; import mage.abilities.effects.OneShotEffect; import mage.abilities.keyword.TrampleAbility; -import mage.cards.Card; -import mage.cards.CardImpl; -import mage.cards.CardSetInfo; +import mage.cards.*; import mage.constants.CardType; import mage.constants.Outcome; import mage.constants.SubType; import mage.constants.Zone; +import mage.filter.FilterCard; import mage.game.Game; import mage.players.Player; +import mage.target.TargetCard; +import mage.watchers.common.CommanderPlaysCountWatcher; +import java.util.HashSet; +import java.util.Set; import java.util.UUID; /** - * @author spjspj + * @author spjspj, JayDi85 */ public final class GeodeGolem extends CardImpl { @@ -65,36 +67,53 @@ class GeodeGolemEffect extends OneShotEffect { public boolean apply(Game game, Ability source) { Player controller = game.getPlayer(source.getControllerId()); if (controller != null) { - for (UUID commanderId : controller.getCommandersIds()) { - if (game.getState().getZone(commanderId) == Zone.COMMAND) { - Card commander = game.getCard(commanderId); - if (commander != null && game.getState().getZone(commanderId) == Zone.COMMAND) { - SpellAbility ability = commander.getSpellAbility(); - SpellAbility newAbility = commander.getSpellAbility().copy(); - newAbility.getCosts().clear(); + UUID selectedCommanderId = null; + Set possibleCommanders = new HashSet<>(); + for (UUID id : game.getCommandersIds(controller)) { + if (game.getState().getZone(id) == Zone.COMMAND) { + possibleCommanders.add(id); + } + } - Integer castCount = (Integer) game.getState().getValue(commander.getId() + "_castCount"); - Cost cost = null; - if (castCount > 0) { - cost = new GenericManaCost(castCount * 2); - } + if (possibleCommanders.size() == 0) { + return false; + } - if ((castCount == 0 || castCount > 0 && cost.pay(source, game, source.getSourceId(), controller.getId(), false, null)) - && controller.cast(newAbility, game, true, new MageObjectReference(source.getSourceObject(game), game))) { - // save amount of times commander was cast - if (castCount == null) { - castCount = 1; - } else { - castCount++; - } - game.getState().setValue(commander.getId() + "_castCount", castCount); - return true; - } + // select from commanders + if (possibleCommanders.size() == 1) { + selectedCommanderId = possibleCommanders.iterator().next(); + } else { + TargetCard target = new TargetCard(Zone.COMMAND, new FilterCard("commander to cast without mana cost")); + Cards cards = new CardsImpl(possibleCommanders); + target.setNotTarget(true); + if (controller.canRespond() && controller.choose(Outcome.Benefit, cards, target, game)) { + if (target.getFirstTarget() != null) { + selectedCommanderId = target.getFirstTarget(); } } } - return true; + Card commander = game.getCard(selectedCommanderId); + if (commander == null) { + return false; + } + + // PAY + ManaCost cost = null; + CommanderPlaysCountWatcher watcher = game.getState().getWatcher(CommanderPlaysCountWatcher.class); + int castCount = watcher.getPlaysCount(commander.getId()); + if (castCount > 0) { + cost = new GenericManaCost(castCount * 2); + } + + // CAST: as spell or as land + if (cost == null || cost.pay(source, game, source.getSourceId(), controller.getId(), false, null)) { + if (commander.getSpellAbility() != null) { + return controller.cast(commander.getSpellAbility().copy(), game, true, new MageObjectReference(source.getSourceObject(game), game)); + } else { + return controller.playLand(commander, game, true); + } + } } return false; } From eec7809875ceacafd25217548a9e27570fa05362 Mon Sep 17 00:00:00 2001 From: Evan Kranzler Date: Mon, 27 May 2019 13:33:30 -0400 Subject: [PATCH 12/38] updated MH1 spoiler --- Utils/mtg-cards-data.txt | 2 ++ 1 file changed, 2 insertions(+) diff --git a/Utils/mtg-cards-data.txt b/Utils/mtg-cards-data.txt index 8cd37961ad1..1fcd3240830 100644 --- a/Utils/mtg-cards-data.txt +++ b/Utils/mtg-cards-data.txt @@ -35125,6 +35125,7 @@ Impostor of the Sixth Pride|Modern Horizons|14|C|{1}{W}|Creature - Shapeshifter| King of the Pride|Modern Horizons|16|U|{2}{W}|Creature - Cat|2|1|Other Cats you control get +2/+1.| Martyr's Soul|Modern Horizons|19|C|{2}{W}|Creature - Spirit Soldier|3|2|Convoke$When Martyr's Soul enters the battlefield, if you control no tapped lands, put two +1/+1 counters on it.| Ranger-Captain of Eos|Modern Horizons|21|M|{1}{W}{W}|Creature - Human Soldier|3|3|When Ranger-Captain of Eos enters the battlefield, you may search your library for a creature card with converted mana cost 1 or less, reveal it, put it into your hand, then shuffle your library.$Sacrifice Ranger-Captain of Eos: Your opponents can't cast noncreature spells this turn.| +Segovian Angel|Modern Horizons|25|C|{W}|Creature - Angel|1|1|Flying, vigilance| Serra the Benevolent|Modern Horizons|26|M|{2}{W}{W}|Legendary Planeswalker - Serra|4|+2: Creatures you control with flying get +1/+1 until end of turn.$-3: Create a 4/4 white Angel creature token with flying and vigilance.$-6: You get an emblem with "If you control a creature, damage that would reduce your life total to less than 1 reduces it to 1 instead."| Sisay, Weatherlight Captain|Modern Horizons|29|R|{2}{W}|Legendary Creature - Human Soldier|2|2|Sisay, Weatherlight Captain gets +1/+1 for each color among other legendary permanents you control.${W}{U}{B}{R}{G}: Search your library for a legendary permanent card with converted mana cost less than Sisay's power, put that card onto the battlefield, then shuffle your library.| Splicer's Skill|Modern Horizons|31|U|{2}{W}|Sorcery|||Create a 3/3 colorless Golem artifact creature token.$Splice onto instant or sorcery {3}{W}| @@ -35145,6 +35146,7 @@ Prohibit|Modern Horizons|64|C|{1}{U}|Instant|||Kicker {2}$Counter target spell i Scour All Possibilities|Modern Horizons|67|C|{1}{U}|Sorcery|||Scry 2, then draw a card.$Flashback {4}{U}| Scuttling Sliver|Modern Horizons|68|U|{2}{U}|Creature - Sliver Trilobite|2|2|Sliver creatures you control have "{2}: Untap this creature."| Stream of Thought|Modern Horizons|71|C|{U}|Sorcery|||Target player puts the top four cards of their library into their graveyard. You shuffle up to four cards from your graveyard into your library.$Replicate {2}{U}{U}| +String of Disappearances|Modern Horizons|72|C|{U}|Instant|||Return target creature to its owner's hand. Then that creature's controller may pay {U}{U}. If the player does, they may copy this spell and may choose a new target for that copy.| Urza, Lord High Artificer|Modern Horizons|75|M|{2}{U}{U}|Legendary Creature - Human Artificer|1|4|When Urza, Lord High Artificer enters the battlefield, create a 0/0 colorless Construct artifact creature token with "This creature gets +1/+1 for each artifact you control."$Tap an untapped artifact you control: Add {U}.${5}: Shuffle your library, then exile the top card. Until end of turn, you may play that card without paying its mana cost.| Cabal Therapist|Modern Horizons|80|R|{B}|Creature - Horror|1|1|Menace$At the beginning of your precombat main phase, you may sacrifice a creature. When you do, choose a nonland card name, then target player reveals their hand and discards all cards with that name.| Changeling Outcast|Modern Horizons|82|C|{B}|Creature - Shapeshifter|1|1|Changeling$Changeling Outcast can't block and can't be blocked.| From 2082e5aa00afd07c804159eab62210fe9bb90721 Mon Sep 17 00:00:00 2001 From: Evan Kranzler Date: Mon, 27 May 2019 13:34:11 -0400 Subject: [PATCH 13/38] Implemented Segovian Angel --- Mage.Sets/src/mage/cards/s/SegovianAngel.java | 40 +++++++++++++++++++ Mage.Sets/src/mage/sets/ModernHorizons.java | 1 + 2 files changed, 41 insertions(+) create mode 100644 Mage.Sets/src/mage/cards/s/SegovianAngel.java diff --git a/Mage.Sets/src/mage/cards/s/SegovianAngel.java b/Mage.Sets/src/mage/cards/s/SegovianAngel.java new file mode 100644 index 00000000000..93e6e6464d2 --- /dev/null +++ b/Mage.Sets/src/mage/cards/s/SegovianAngel.java @@ -0,0 +1,40 @@ +package mage.cards.s; + +import mage.MageInt; +import mage.abilities.keyword.FlyingAbility; +import mage.abilities.keyword.VigilanceAbility; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.SubType; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class SegovianAngel extends CardImpl { + + public SegovianAngel(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{W}"); + + this.subtype.add(SubType.ANGEL); + this.power = new MageInt(1); + this.toughness = new MageInt(1); + + // Flying + this.addAbility(FlyingAbility.getInstance()); + + // Vigilance + this.addAbility(VigilanceAbility.getInstance()); + } + + private SegovianAngel(final SegovianAngel card) { + super(card); + } + + @Override + public SegovianAngel copy() { + return new SegovianAngel(this); + } +} diff --git a/Mage.Sets/src/mage/sets/ModernHorizons.java b/Mage.Sets/src/mage/sets/ModernHorizons.java index bf8318e909f..de06672b575 100644 --- a/Mage.Sets/src/mage/sets/ModernHorizons.java +++ b/Mage.Sets/src/mage/sets/ModernHorizons.java @@ -110,6 +110,7 @@ public final class ModernHorizons extends ExpansionSet { cards.add(new SetCardInfo("Scrapyard Recombiner", 227, Rarity.RARE, mage.cards.s.ScrapyardRecombiner.class)); cards.add(new SetCardInfo("Scuttling Sliver", 68, Rarity.UNCOMMON, mage.cards.s.ScuttlingSliver.class)); cards.add(new SetCardInfo("Seasoned Pyromancer", 145, Rarity.MYTHIC, mage.cards.s.SeasonedPyromancer.class)); + cards.add(new SetCardInfo("Segovian Angel", 25, Rarity.COMMON, mage.cards.s.SegovianAngel.class)); cards.add(new SetCardInfo("Serra the Benevolent", 26, Rarity.MYTHIC, mage.cards.s.SerraTheBenevolent.class)); cards.add(new SetCardInfo("Silent Clearing", 246, Rarity.RARE, mage.cards.s.SilentClearing.class)); cards.add(new SetCardInfo("Sisay, Weatherlight Captain", 29, Rarity.RARE, mage.cards.s.SisayWeatherlightCaptain.class)); From 010f1c0367e1b97e6363b2ff14a6992d22be6a77 Mon Sep 17 00:00:00 2001 From: Evan Kranzler Date: Mon, 27 May 2019 13:43:58 -0400 Subject: [PATCH 14/38] Implemented String of Disappearances --- .../mage/cards/s/StringOfDisappearances.java | 88 +++++++++++++++++++ Mage.Sets/src/mage/sets/ModernHorizons.java | 1 + 2 files changed, 89 insertions(+) create mode 100644 Mage.Sets/src/mage/cards/s/StringOfDisappearances.java diff --git a/Mage.Sets/src/mage/cards/s/StringOfDisappearances.java b/Mage.Sets/src/mage/cards/s/StringOfDisappearances.java new file mode 100644 index 00000000000..980102ebd6d --- /dev/null +++ b/Mage.Sets/src/mage/cards/s/StringOfDisappearances.java @@ -0,0 +1,88 @@ +package mage.cards.s; + +import mage.abilities.Ability; +import mage.abilities.costs.Cost; +import mage.abilities.costs.mana.ManaCostsImpl; +import mage.abilities.effects.OneShotEffect; +import mage.abilities.effects.common.ReturnToHandTargetEffect; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.Outcome; +import mage.game.Game; +import mage.game.permanent.Permanent; +import mage.game.stack.Spell; +import mage.players.Player; +import mage.target.common.TargetCreaturePermanent; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class StringOfDisappearances extends CardImpl { + + public StringOfDisappearances(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.INSTANT}, "{U}"); + + // Return target creature to its owner's hand. Then that creature's controller may pay {U}{U}. If the player does, they may copy this spell and may choose a new target for that copy. + this.getSpellAbility().addEffect(new StringOfDisappearancesEffect()); + this.getSpellAbility().addTarget(new TargetCreaturePermanent()); + } + + private StringOfDisappearances(final StringOfDisappearances card) { + super(card); + } + + @Override + public StringOfDisappearances copy() { + return new StringOfDisappearances(this); + } +} + +class StringOfDisappearancesEffect extends OneShotEffect { + + StringOfDisappearancesEffect() { + super(Outcome.Damage); + this.staticText = "Return target creature to its owner's hand. " + + "Then that creature's controller may pay {U}{U}. " + + "If the player does, they may copy this spell " + + "and may choose a new target for that copy."; + } + + private StringOfDisappearancesEffect(final StringOfDisappearancesEffect effect) { + super(effect); + } + + @Override + public StringOfDisappearancesEffect copy() { + return new StringOfDisappearancesEffect(this); + } + + @Override + public boolean apply(Game game, Ability source) { + Permanent permanent = game.getPermanent(source.getFirstTarget()); + if (permanent == null) { + return false; + } + Player affectedPlayer = game.getPlayer(permanent.getControllerId()); + new ReturnToHandTargetEffect().apply(game, source); + if (affectedPlayer == null) { + return false; + } + if (!affectedPlayer.chooseUse(Outcome.Copy, "Pay {U}{U} to copy the spell?", source, game)) { + return true; + } + Cost cost = new ManaCostsImpl("{U}{U}"); + if (!cost.pay(source, game, source.getSourceId(), affectedPlayer.getId(), false, null)) { + return true; + } + Spell spell = game.getStack().getSpell(source.getSourceId()); + if (spell == null) { + return true; + } + spell.createCopyOnStack(game, source, affectedPlayer.getId(), true); + game.informPlayers(affectedPlayer.getLogName() + " copies " + spell.getName() + '.'); + return true; + } +} diff --git a/Mage.Sets/src/mage/sets/ModernHorizons.java b/Mage.Sets/src/mage/sets/ModernHorizons.java index de06672b575..1843f482926 100644 --- a/Mage.Sets/src/mage/sets/ModernHorizons.java +++ b/Mage.Sets/src/mage/sets/ModernHorizons.java @@ -125,6 +125,7 @@ public final class ModernHorizons extends ExpansionSet { cards.add(new SetCardInfo("Springbloom Druid", 181, Rarity.COMMON, mage.cards.s.SpringbloomDruid.class)); cards.add(new SetCardInfo("Squirrel Nest", 182, Rarity.UNCOMMON, mage.cards.s.SquirrelNest.class)); cards.add(new SetCardInfo("Stream of Thought", 71, Rarity.COMMON, mage.cards.s.StreamOfThought.class)); + cards.add(new SetCardInfo("String of Disappearances", 72, Rarity.COMMON, mage.cards.s.StringOfDisappearances.class)); cards.add(new SetCardInfo("Sunbaked Canyon", 247, Rarity.RARE, mage.cards.s.SunbakedCanyon.class)); cards.add(new SetCardInfo("Sword of Sinew and Steel", 228, Rarity.MYTHIC, mage.cards.s.SwordOfSinewAndSteel.class)); cards.add(new SetCardInfo("Sword of Truth and Justice", 229, Rarity.MYTHIC, mage.cards.s.SwordOfTruthAndJustice.class)); From 2613a1bb43b9e4c4ed479f0dfd5bbb4da05c5bfd Mon Sep 17 00:00:00 2001 From: Evan Kranzler Date: Mon, 27 May 2019 16:47:21 -0400 Subject: [PATCH 15/38] updated MH1 spoiler and reprints --- Mage.Sets/src/mage/sets/ModernHorizons.java | 2 ++ Utils/mtg-cards-data.txt | 10 +++++++++- 2 files changed, 11 insertions(+), 1 deletion(-) diff --git a/Mage.Sets/src/mage/sets/ModernHorizons.java b/Mage.Sets/src/mage/sets/ModernHorizons.java index 1843f482926..f26cb395ad6 100644 --- a/Mage.Sets/src/mage/sets/ModernHorizons.java +++ b/Mage.Sets/src/mage/sets/ModernHorizons.java @@ -47,6 +47,7 @@ public final class ModernHorizons extends ExpansionSet { cards.add(new SetCardInfo("Diabolic Edict", 87, Rarity.COMMON, mage.cards.d.DiabolicEdict.class)); cards.add(new SetCardInfo("Dismantling Blow", 5, Rarity.UNCOMMON, mage.cards.d.DismantlingBlow.class)); cards.add(new SetCardInfo("Dregscape Sliver", 88, Rarity.UNCOMMON, mage.cards.d.DregscapeSliver.class)); + cards.add(new SetCardInfo("Eladamri's Call", 197, Rarity.RARE, mage.cards.e.EladamrisCall.class)); cards.add(new SetCardInfo("Elvish Fury", 162, Rarity.COMMON, mage.cards.e.ElvishFury.class)); cards.add(new SetCardInfo("Etchings of the Chosen", 198, Rarity.UNCOMMON, mage.cards.e.EtchingsOfTheChosen.class)); cards.add(new SetCardInfo("Exclude", 48, Rarity.UNCOMMON, mage.cards.e.Exclude.class)); @@ -79,6 +80,7 @@ public final class ModernHorizons extends ExpansionSet { cards.add(new SetCardInfo("Hollowhead Sliver", 132, Rarity.UNCOMMON, mage.cards.h.HollowheadSliver.class)); cards.add(new SetCardInfo("Ice-Fang Coatl", 203, Rarity.RARE, mage.cards.i.IceFangCoatl.class)); cards.add(new SetCardInfo("Impostor of the Sixth Pride", 14, Rarity.COMMON, mage.cards.i.ImpostorOfTheSixthPride.class)); + cards.add(new SetCardInfo("Kess, Dissident Mage", 206, Rarity.MYTHIC, mage.cards.k.KessDissidentMage.class)); cards.add(new SetCardInfo("King of the Pride", 16, Rarity.UNCOMMON, mage.cards.k.KingOfThePride.class)); cards.add(new SetCardInfo("Lava Dart", 134, Rarity.COMMON, mage.cards.l.LavaDart.class)); cards.add(new SetCardInfo("Lavabelly Sliver", 207, Rarity.UNCOMMON, mage.cards.l.LavabellySliver.class)); diff --git a/Utils/mtg-cards-data.txt b/Utils/mtg-cards-data.txt index 1fcd3240830..b4a93ff56b2 100644 --- a/Utils/mtg-cards-data.txt +++ b/Utils/mtg-cards-data.txt @@ -35145,6 +35145,7 @@ Pondering Mage|Modern Horizons|63|C|{3}{U}{U}|Creature - Human Wizard|3|4|When P Prohibit|Modern Horizons|64|C|{1}{U}|Instant|||Kicker {2}$Counter target spell if its converted mana cost is 2 or less. If this spell was kicked, counter that spell if its converted mana cost is 4 or less instead.| Scour All Possibilities|Modern Horizons|67|C|{1}{U}|Sorcery|||Scry 2, then draw a card.$Flashback {4}{U}| Scuttling Sliver|Modern Horizons|68|U|{2}{U}|Creature - Sliver Trilobite|2|2|Sliver creatures you control have "{2}: Untap this creature."| +Spell Snuff|Modern Horizons|70|C|{1}{U}{U}|Instant|||Counter target spell.$Fateful hour — If you have 5 or less life, draw a card.| Stream of Thought|Modern Horizons|71|C|{U}|Sorcery|||Target player puts the top four cards of their library into their graveyard. You shuffle up to four cards from your graveyard into your library.$Replicate {2}{U}{U}| String of Disappearances|Modern Horizons|72|C|{U}|Instant|||Return target creature to its owner's hand. Then that creature's controller may pay {U}{U}. If the player does, they may copy this spell and may choose a new target for that copy.| Urza, Lord High Artificer|Modern Horizons|75|M|{2}{U}{U}|Legendary Creature - Human Artificer|1|4|When Urza, Lord High Artificer enters the battlefield, create a 0/0 colorless Construct artifact creature token with "This creature gets +1/+1 for each artifact you control."$Tap an untapped artifact you control: Add {U}.${5}: Shuffle your library, then exile the top card. Until end of turn, you may play that card without paying its mana cost.| @@ -35161,7 +35162,7 @@ Sling-Gang Lieutenant|Modern Horizons|108|U|{3}{B}|Creature - Goblin|1|1|When Sl Umezawa's Charm|Modern Horizons|111|C|{1}{B}|Instant|||Choose one—$• Target creature gets +2/+2 until end of turn.$• Target creature gets -1/-1 until end of turn.$• You gain 2 life.| Undead Augur|Modern Horizons|112|U|{B}{B}|Creature - Zombie Wizard|2|2|Whenever Undead Augur or another Zombie you control dies, you draw a card and you lose 1 life.| Venomous Changeling|Modern Horizons|114|C|{2}{B}|Creature - Shapeshifter|1|3|Changeling$Deathtouch| -Yawgmoth, Thran Physician|Modern Horizons|116|M|{2}{B}{B}|Legendary Creature - Human Cleric|2|4|Protection from Humans.$Pay 1 life, Sacrifice another creature: Put a -1/-1 counter on up to one target creature and draw a card.${B}{B}, Discard a card: Proliferate.| +Yawgmoth, Thran Physician|Modern Horizons|116|M|{2}{B}{B}|Legendary Creature - Human Cleric|2|4|Protection from Humans$Pay 1 life, Sacrifice another creature: Put a -1/-1 counter on up to one target creature and draw a card.${B}{B}, Discard a card: Proliferate.| Aria of Flame|Modern Horizons|118|R|{2}{R}|Enchantment|||When Aria of Flame enters the battlefield, each opponent gains 10 life.$Whenever you cast an instant or sorcery spell, put a verse counter on Aria of Flame, then it deals damage equal to the number of verse counters on it to target player or planeswalker.| Firebolt|Modern Horizons|122|U|{R}|Sorcery|||Firebolt deals 2 damage to any target.$Flashback {4}{R}| Fists of Flame|Modern Horizons|123|C|{1}{R}|Instant|||Draw a card. Until end of turn, target creature gains trample and gets +1/+0 for each card you've drawn this turn.| @@ -35201,11 +35202,13 @@ Unbound Flourishing|Modern Horizons|189|M|{2}{G}|Enchantment|||Whenever you cast Abominable Treefolk|Modern Horizons|194|U|{2}{G}{U}|Snow Creature - Treefolk|*|*|Trample$Abominable Treefolk's power and toughness are each equal to the number of snow permanents you control.$When Abominable Treefolk enters the battlefield, tap target creature an opponent controls. That creature doesn't untap during its controller's next untap step.| Cloudshredder Sliver|Modern Horizons|195|R|{R}{W}|Creature - Sliver|1|1|Sliver creatures you control have flying and haste.| Collected Conjuring|Modern Horizons|196|R|{2}{U}{R}|Sorcery|||Exile the top six cards of your library. You may cast up to two sorcery cards with converted mana costs 3 or less from among them without paying their mana cost. Put the exiled cards not cast this way on the bottom of your library in a random order.| +Eladamri's Call|Modern Horizons|197|R|{G}{W}|Instant|||Search your library for a creature card, reveal that card, put it into your hand, then shuffle your library.| Etchings of the Chosen|Modern Horizons|198|U|{1}{W}{B}|Enchantment|||As Etchings of the Chosen enters the battlefield, choose a creature type.$Creatures you control of the chosen type get +1/+1.${1}, Sacrifice a creature of the chosen type: Target creature you control gains indestructible until end of turn.| Fallen Shinobi|Modern Horizons|199|R|{3}{U}{B}|Creature - Zombie Ninja|5|4|Ninjutsu {2}{U}{B}$Whenever Fallen Shinobi deals combat damage to a player, that player exiles the top two cards of their library. Until end of turn, you may play those cards without paying their mana cost.| The First Sliver|Modern Horizons|200|M|{W}{U}{B}{R}{G}|Legendary Creature - Sliver|7|7|Cascade$Sliver spells you cast have cascade.| Good-Fortune Unicorn|Modern Horizons|201|U|{1}{G}{W}|Creature - Unicorn|2|2|Whenever another creature enters the battlefield under your control, put a +1/+1 counter on that creature.| Ice-Fang Coatl|Modern Horizons|203|R|{G}{U}|Snow Creature - Snake|1|1|Flash$Flying$When Ice-Fang Coatl enters the battlefield, draw a card.$Ice-Fang Coatl has deathtouch as long as you control at least three other snow permanents.| +Kess, Dissident Mage|Modern Horizons|206|M|{1}{U}{B}{R}|Legendary Creature - Human Wizard|3|4|Flying$During each of your turns, you may cast an instant or sorcery card from your graveyard. If a card cast this way would be put into your graveyard, exile it instead.| Lavabelly Sliver|Modern Horizons|207|U|{1}{R}{W}|Creature - Sliver|2|2|Sliver creatures you control have "When this creature enters the battlefield, it deals 1 damage to target player or planeswalker and you gain 1 life."| Lightning Skelemental|Modern Horizons|208|R|{B}{R}{R}|Creature - Elemental Skeleton|6|1|Trample, haste$Whenever Lightning Skelemental deals combat damage to a player, that player discards two cards.$At the beginning of the end step, sacrifice Lightning Skelemental.| Munitions Expert|Modern Horizons|209|U|{B}{R}|Creature - Goblin|1|1|Flash$When Munitions Expert enters the battlefield, you may have it deal damage to target creature or planeswalker equal to the number of Goblins you control.| @@ -35219,6 +35222,11 @@ Mox Tantalite|Modern Horizons|226|M||Artifact|||Suspend 3—{0}${T}: Add one man Scrapyard Recombiner|Modern Horizons|227|R|{3}|Artifact Creature - Construct|0|0|Modular 2${T}, Sacrifice an artifact: Search your library for a Construct card, reveal it, put it into your hand, then shuffle your library.| Sword of Sinew and Steel|Modern Horizons|228|M|{3}|Artifact - Equipment|||Equipped creature gets +2/+2 and has protection from black and from red.$Whenever equipped creature deals combat damage to a player, destroy up to one target planeswalker and up to one target artifact.$Equip {2}| Sword of Truth and Justice|Modern Horizons|229|M|{3}|Artifact - Equipment|||Equipped creature gets +2/+2 and has protection from white and from blue.$Whenever equipped creature deals combat damage to a player, put a +1/+1 counter on a creature you control, then proliferate.$Equip {2}| +Talisman of Conviction|Modern Horizons|230|U|{2}|Artifact|||{T}: Add {C}.${T}: Add {R} or {W}. Talisman of Conviction deals 1 damage to you.| +Talisman of Creativity|Modern Horizons|231|U|{2}|Artifact|||{T}: Add {C}.${T}: Add {U} or {R}. Talisman of Creativity deals 1 damage to you.| +Talisman of Curiosity|Modern Horizons|232|C|{2}|Artifact|||{T}: Add {C}.${T}: Add {G} or {U}. Talisman of Curiosity deals 1 damage to you.| +Talisman of Hierarchy|Modern Horizons|233|U|{2}|Artifact|||{T}: Add {C}.${T}: Add {W} or {B}. Talisman of Hierarchy deals 1 damage to you.| +Talisman of Resilience|Modern Horizons|234|U|{2}|Artifact|||{T}: Add {C}.${T}: Add {B} or {G}. Talisman of Resilience deals 1 damage to you.| Fiery Islet|Modern Horizons|238|R||Land|||{T}, Pay 1 life: Add {U} or {R}.${1}, {T}, Sacrifice Fiery Islet: Draw a card.| Frostwalk Bastion|Modern Horizons|240|U||Snow Land|||{T}: Add {C}.${1}{S}: Until end of turn, Frostwalk Bastion becomes a 2/3 Construct artifact creature. It's still a land.$Whenever Frostwalk Bastion deals combat damage to a creature, tap that creature and it doesn't untap during its controller's next untap step.| Nurturing Peatland|Modern Horizons|243|R||Land|||{T}, Pay 1 life: Add {B} or {G}.${1}, {T}, Sacrifice Nurturing Peatland: Draw a card.| From 17543bcc8ce98c74c34f33c1d275cd8ce26fc6b5 Mon Sep 17 00:00:00 2001 From: Evan Kranzler Date: Mon, 27 May 2019 16:56:55 -0400 Subject: [PATCH 16/38] Implemented Spell Snuff --- Mage.Sets/src/mage/cards/s/SpellSnuff.java | 41 +++++++++++++++++++++ Mage.Sets/src/mage/sets/ModernHorizons.java | 1 + 2 files changed, 42 insertions(+) create mode 100644 Mage.Sets/src/mage/cards/s/SpellSnuff.java diff --git a/Mage.Sets/src/mage/cards/s/SpellSnuff.java b/Mage.Sets/src/mage/cards/s/SpellSnuff.java new file mode 100644 index 00000000000..369266e8c95 --- /dev/null +++ b/Mage.Sets/src/mage/cards/s/SpellSnuff.java @@ -0,0 +1,41 @@ +package mage.cards.s; + +import mage.abilities.condition.common.FatefulHourCondition; +import mage.abilities.decorator.ConditionalOneShotEffect; +import mage.abilities.effects.common.CounterTargetEffect; +import mage.abilities.effects.common.DrawCardSourceControllerEffect; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.target.TargetSpell; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class SpellSnuff extends CardImpl { + + public SpellSnuff(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.INSTANT}, "{1}{U}{U}"); + + // Counter target spell. + this.getSpellAbility().addEffect(new CounterTargetEffect()); + this.getSpellAbility().addTarget(new TargetSpell()); + + // Fateful hour — If you have 5 or less life, draw a card. + this.getSpellAbility().addEffect(new ConditionalOneShotEffect( + new DrawCardSourceControllerEffect(1), FatefulHourCondition.instance, + "
Fateful Hour — If you have 5 or less life, draw a card." + )); + } + + private SpellSnuff(final SpellSnuff card) { + super(card); + } + + @Override + public SpellSnuff copy() { + return new SpellSnuff(this); + } +} diff --git a/Mage.Sets/src/mage/sets/ModernHorizons.java b/Mage.Sets/src/mage/sets/ModernHorizons.java index f26cb395ad6..72e04008dc0 100644 --- a/Mage.Sets/src/mage/sets/ModernHorizons.java +++ b/Mage.Sets/src/mage/sets/ModernHorizons.java @@ -122,6 +122,7 @@ public final class ModernHorizons extends ExpansionSet { cards.add(new SetCardInfo("Snow-Covered Mountain", 253, Rarity.LAND, mage.cards.s.SnowCoveredMountain.class, FULL_ART_BFZ_VARIOUS)); cards.add(new SetCardInfo("Snow-Covered Plains", 250, Rarity.LAND, mage.cards.s.SnowCoveredPlains.class, FULL_ART_BFZ_VARIOUS)); cards.add(new SetCardInfo("Snow-Covered Swamp", 252, Rarity.LAND, mage.cards.s.SnowCoveredSwamp.class, FULL_ART_BFZ_VARIOUS)); + cards.add(new SetCardInfo("Spell Snuff", 70, Rarity.COMMON, mage.cards.s.SpellSnuff.class)); cards.add(new SetCardInfo("Splicer's Skill", 31, Rarity.UNCOMMON, mage.cards.s.SplicersSkill.class)); cards.add(new SetCardInfo("Spore Frog", 180, Rarity.COMMON, mage.cards.s.SporeFrog.class)); cards.add(new SetCardInfo("Springbloom Druid", 181, Rarity.COMMON, mage.cards.s.SpringbloomDruid.class)); From 68bf7aa3383065ff3efd2fa0ae536e4046dd97f2 Mon Sep 17 00:00:00 2001 From: Evan Kranzler Date: Mon, 27 May 2019 17:01:28 -0400 Subject: [PATCH 17/38] fixed fateful hour text --- Mage.Sets/src/mage/cards/b/BreakOfDay.java | 22 ++++++++++--------- Mage.Sets/src/mage/cards/c/ClingingMists.java | 14 ++++++------ .../src/mage/cards/g/GatherTheTownsfolk.java | 10 ++++----- .../src/mage/cards/g/GavonyIronwright.java | 14 +++++------- Mage.Sets/src/mage/cards/s/SpellSnuff.java | 2 +- .../src/mage/cards/t/ThrabenDoomsayer.java | 11 +++++----- .../src/mage/cards/v/VillageSurvivors.java | 9 ++++---- 7 files changed, 39 insertions(+), 43 deletions(-) diff --git a/Mage.Sets/src/mage/cards/b/BreakOfDay.java b/Mage.Sets/src/mage/cards/b/BreakOfDay.java index 3b0fbb2c78e..9c22e8a4c35 100644 --- a/Mage.Sets/src/mage/cards/b/BreakOfDay.java +++ b/Mage.Sets/src/mage/cards/b/BreakOfDay.java @@ -1,7 +1,5 @@ - package mage.cards.b; -import java.util.UUID; import mage.abilities.condition.LockedInCondition; import mage.abilities.condition.common.FatefulHourCondition; import mage.abilities.decorator.ConditionalContinuousEffect; @@ -12,26 +10,30 @@ import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; import mage.constants.Duration; -import mage.filter.common.FilterControlledCreaturePermanent; +import mage.filter.StaticFilters; + +import java.util.UUID; /** - * * @author Loki - */ public final class BreakOfDay extends CardImpl { public BreakOfDay(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.INSTANT},"{1}{W}"); - + super(ownerId, setInfo, new CardType[]{CardType.INSTANT}, "{1}{W}"); // Creatures you control get +1/+1 until end of turn. this.getSpellAbility().addEffect(new BoostControlledEffect(1, 1, Duration.EndOfTurn)); + // Fateful hour - If you have 5 or less life, those creatures also are indestructible this turn. this.getSpellAbility().addEffect(new ConditionalContinuousEffect( - new GainAbilityAllEffect(IndestructibleAbility.getInstance(), Duration.EndOfTurn, new FilterControlledCreaturePermanent("creatures you control"), false), - new LockedInCondition(FatefulHourCondition.instance), - "If you have 5 or less life, those creatures also are indestructible this turn")); + new GainAbilityAllEffect( + IndestructibleAbility.getInstance(), Duration.EndOfTurn, + StaticFilters.FILTER_PERMANENT_CREATURES, false + ), new LockedInCondition(FatefulHourCondition.instance), + "
Fateful hour — If you have 5 or less life, " + + "those creatures also are indestructible this turn" + )); } public BreakOfDay(final BreakOfDay card) { diff --git a/Mage.Sets/src/mage/cards/c/ClingingMists.java b/Mage.Sets/src/mage/cards/c/ClingingMists.java index 7d0a944e1db..ca0a2c8e530 100644 --- a/Mage.Sets/src/mage/cards/c/ClingingMists.java +++ b/Mage.Sets/src/mage/cards/c/ClingingMists.java @@ -1,9 +1,5 @@ - package mage.cards.c; -import java.util.ArrayList; -import java.util.List; -import java.util.UUID; import mage.abilities.Ability; import mage.abilities.condition.common.FatefulHourCondition; import mage.abilities.decorator.ConditionalOneShotEffect; @@ -21,21 +17,25 @@ import mage.game.Game; import mage.game.permanent.Permanent; import mage.target.targetpointer.FixedTargets; +import java.util.ArrayList; +import java.util.List; +import java.util.UUID; + /** - * * @author BetaSteward */ public final class ClingingMists extends CardImpl { public ClingingMists(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.INSTANT},"{2}{G}"); + super(ownerId, setInfo, new CardType[]{CardType.INSTANT}, "{2}{G}"); // Prevent all combat damage that would be dealt this turn. this.getSpellAbility().addEffect(new PreventAllDamageByAllPermanentsEffect(null, Duration.EndOfTurn, true)); // Fateful hour - If you have 5 or less life, tap all attacking creatures. Those creatures don't untap during their controller's next untap step. this.getSpellAbility().addEffect(new ConditionalOneShotEffect(new ClingingMistsEffect(), - FatefulHourCondition.instance, "If you have 5 or less life, tap all attacking creatures. Those creatures don't untap during their controller's next untap step.")); + FatefulHourCondition.instance, "
Fateful hour — If you have 5 or less life, " + + "tap all attacking creatures. Those creatures don't untap during their controller's next untap step.")); } diff --git a/Mage.Sets/src/mage/cards/g/GatherTheTownsfolk.java b/Mage.Sets/src/mage/cards/g/GatherTheTownsfolk.java index defe2255111..ef74d21c1c8 100644 --- a/Mage.Sets/src/mage/cards/g/GatherTheTownsfolk.java +++ b/Mage.Sets/src/mage/cards/g/GatherTheTownsfolk.java @@ -1,7 +1,5 @@ - package mage.cards.g; -import java.util.UUID; import mage.abilities.condition.common.FatefulHourCondition; import mage.abilities.decorator.ConditionalOneShotEffect; import mage.abilities.effects.common.CreateTokenEffect; @@ -10,20 +8,20 @@ import mage.cards.CardSetInfo; import mage.constants.CardType; import mage.game.permanent.token.HumanToken; +import java.util.UUID; + /** - * * @author anonymous */ public final class GatherTheTownsfolk extends CardImpl { public GatherTheTownsfolk(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.SORCERY},"{1}{W}"); - + super(ownerId, setInfo, new CardType[]{CardType.SORCERY}, "{1}{W}"); // Create two 1/1 white Human creature tokens. // Fateful hour - If you have 5 or less life, create five of those tokens instead. this.getSpellAbility().addEffect(new ConditionalOneShotEffect(new CreateTokenEffect(new HumanToken(), 5), new CreateTokenEffect(new HumanToken(), 2), - FatefulHourCondition.instance, "Create two 1/1 white Human creature tokens. If you have 5 or less life, create five of those tokens instead")); + FatefulHourCondition.instance, "Create two 1/1 white Human creature tokens.
Fateful hour — If you have 5 or less life, create five of those tokens instead")); } public GatherTheTownsfolk(final GatherTheTownsfolk card) { diff --git a/Mage.Sets/src/mage/cards/g/GavonyIronwright.java b/Mage.Sets/src/mage/cards/g/GavonyIronwright.java index a3a9f10b0c4..d618ee560ab 100644 --- a/Mage.Sets/src/mage/cards/g/GavonyIronwright.java +++ b/Mage.Sets/src/mage/cards/g/GavonyIronwright.java @@ -1,7 +1,5 @@ - package mage.cards.g; -import java.util.UUID; import mage.MageInt; import mage.abilities.common.SimpleStaticAbility; import mage.abilities.condition.common.FatefulHourCondition; @@ -10,19 +8,19 @@ import mage.abilities.effects.common.continuous.BoostControlledEffect; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; -import mage.constants.SubType; import mage.constants.Duration; +import mage.constants.SubType; import mage.constants.Zone; -/** - * - * @author Loki +import java.util.UUID; +/** + * @author Loki */ public final class GavonyIronwright extends CardImpl { public GavonyIronwright(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.CREATURE},"{2}{W}"); + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{2}{W}"); this.subtype.add(SubType.HUMAN); this.subtype.add(SubType.SOLDIER); @@ -31,7 +29,7 @@ public final class GavonyIronwright extends CardImpl { // Fateful hour - As long as you have 5 or less life, other creatures you control get +1/+4. this.addAbility(new SimpleStaticAbility(Zone.BATTLEFIELD, new ConditionalContinuousEffect(new BoostControlledEffect(1, 4, Duration.WhileOnBattlefield, false), - FatefulHourCondition.instance, "As long as you have 5 or less life, other creatures you control get +1/+4"))); + FatefulHourCondition.instance, "
Fateful hour — As long as you have 5 or less life, other creatures you control get +1/+4"))); } public GavonyIronwright(final GavonyIronwright card) { diff --git a/Mage.Sets/src/mage/cards/s/SpellSnuff.java b/Mage.Sets/src/mage/cards/s/SpellSnuff.java index 369266e8c95..2cf1cd729fe 100644 --- a/Mage.Sets/src/mage/cards/s/SpellSnuff.java +++ b/Mage.Sets/src/mage/cards/s/SpellSnuff.java @@ -26,7 +26,7 @@ public final class SpellSnuff extends CardImpl { // Fateful hour — If you have 5 or less life, draw a card. this.getSpellAbility().addEffect(new ConditionalOneShotEffect( new DrawCardSourceControllerEffect(1), FatefulHourCondition.instance, - "
Fateful Hour — If you have 5 or less life, draw a card." + "
Fateful hour — If you have 5 or less life, draw a card." )); } diff --git a/Mage.Sets/src/mage/cards/t/ThrabenDoomsayer.java b/Mage.Sets/src/mage/cards/t/ThrabenDoomsayer.java index b75dc39925a..82b95a2e988 100644 --- a/Mage.Sets/src/mage/cards/t/ThrabenDoomsayer.java +++ b/Mage.Sets/src/mage/cards/t/ThrabenDoomsayer.java @@ -1,7 +1,5 @@ - package mage.cards.t; -import java.util.UUID; import mage.MageInt; import mage.abilities.common.SimpleActivatedAbility; import mage.abilities.common.SimpleStaticAbility; @@ -13,19 +11,20 @@ import mage.abilities.effects.common.continuous.BoostControlledEffect; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; -import mage.constants.SubType; import mage.constants.Duration; +import mage.constants.SubType; import mage.constants.Zone; import mage.game.permanent.token.HumanToken; +import java.util.UUID; + /** - * * @author anonymous */ public final class ThrabenDoomsayer extends CardImpl { public ThrabenDoomsayer(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.CREATURE},"{1}{W}{W}"); + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{1}{W}{W}"); this.subtype.add(SubType.HUMAN); this.subtype.add(SubType.CLERIC); @@ -36,7 +35,7 @@ public final class ThrabenDoomsayer extends CardImpl { this.addAbility(new SimpleActivatedAbility(Zone.BATTLEFIELD, new CreateTokenEffect(new HumanToken()), new TapSourceCost())); // Fateful hour - As long as you have 5 or less life, other creatures you control get +2/+2. this.addAbility(new SimpleStaticAbility(Zone.BATTLEFIELD, new ConditionalContinuousEffect(new BoostControlledEffect(2, 2, Duration.WhileOnBattlefield, true), - FatefulHourCondition.instance, "As long as you have 5 or less life, other creatures you control get +2/+2"))); + FatefulHourCondition.instance, "
Fateful hour — As long as you have 5 or less life, other creatures you control get +2/+2"))); } public ThrabenDoomsayer(final ThrabenDoomsayer card) { diff --git a/Mage.Sets/src/mage/cards/v/VillageSurvivors.java b/Mage.Sets/src/mage/cards/v/VillageSurvivors.java index 57c8a88208b..7eac629e4d5 100644 --- a/Mage.Sets/src/mage/cards/v/VillageSurvivors.java +++ b/Mage.Sets/src/mage/cards/v/VillageSurvivors.java @@ -1,7 +1,5 @@ - package mage.cards.v; -import java.util.UUID; import mage.MageInt; import mage.abilities.common.SimpleStaticAbility; import mage.abilities.condition.common.FatefulHourCondition; @@ -11,13 +9,14 @@ import mage.abilities.keyword.VigilanceAbility; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; -import mage.constants.SubType; import mage.constants.Duration; +import mage.constants.SubType; import mage.constants.Zone; import mage.filter.StaticFilters; +import java.util.UUID; + /** - * * @author Loki */ public final class VillageSurvivors extends CardImpl { @@ -34,7 +33,7 @@ public final class VillageSurvivors extends CardImpl { this.addAbility(new SimpleStaticAbility(Zone.BATTLEFIELD, new ConditionalContinuousEffect( new GainAbilityControlledEffect(VigilanceAbility.getInstance(), Duration.WhileOnBattlefield, StaticFilters.FILTER_PERMANENT_CREATURE, true), FatefulHourCondition.instance, - "Fateful hour - As long as you have 5 or less life, other creatures you control have vigilance"))); + "
Fateful hour — As long as you have 5 or less life, other creatures you control have vigilance"))); } public VillageSurvivors(final VillageSurvivors card) { From 946a166c55661576d126db643a3f6e556de4bfd3 Mon Sep 17 00:00:00 2001 From: Evan Kranzler Date: Mon, 27 May 2019 17:04:29 -0400 Subject: [PATCH 18/38] Implemented Talisman of Curiosity --- .../src/mage/cards/t/TalismanOfCuriosity.java | 42 +++++++++++++++++++ Mage.Sets/src/mage/sets/ModernHorizons.java | 1 + 2 files changed, 43 insertions(+) create mode 100644 Mage.Sets/src/mage/cards/t/TalismanOfCuriosity.java diff --git a/Mage.Sets/src/mage/cards/t/TalismanOfCuriosity.java b/Mage.Sets/src/mage/cards/t/TalismanOfCuriosity.java new file mode 100644 index 00000000000..4f01e250726 --- /dev/null +++ b/Mage.Sets/src/mage/cards/t/TalismanOfCuriosity.java @@ -0,0 +1,42 @@ +package mage.cards.t; + +import mage.abilities.Ability; +import mage.abilities.effects.common.DamageControllerEffect; +import mage.abilities.mana.BlueManaAbility; +import mage.abilities.mana.ColorlessManaAbility; +import mage.abilities.mana.GreenManaAbility; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class TalismanOfCuriosity extends CardImpl { + + public TalismanOfCuriosity(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.ARTIFACT}, "{2}"); + + // {T}: Add {C}. + this.addAbility(new ColorlessManaAbility()); + + // {T}: Add {G} or {U}. Talisman of Curiosity deals 1 damage to you. + Ability ability = new GreenManaAbility(); + ability.addEffect(new DamageControllerEffect(1)); + this.addAbility(ability); + ability = new BlueManaAbility(); + ability.addEffect(new DamageControllerEffect(1)); + this.addAbility(ability); + } + + private TalismanOfCuriosity(final TalismanOfCuriosity card) { + super(card); + } + + @Override + public TalismanOfCuriosity copy() { + return new TalismanOfCuriosity(this); + } +} diff --git a/Mage.Sets/src/mage/sets/ModernHorizons.java b/Mage.Sets/src/mage/sets/ModernHorizons.java index 72e04008dc0..451133d8c18 100644 --- a/Mage.Sets/src/mage/sets/ModernHorizons.java +++ b/Mage.Sets/src/mage/sets/ModernHorizons.java @@ -132,6 +132,7 @@ public final class ModernHorizons extends ExpansionSet { cards.add(new SetCardInfo("Sunbaked Canyon", 247, Rarity.RARE, mage.cards.s.SunbakedCanyon.class)); cards.add(new SetCardInfo("Sword of Sinew and Steel", 228, Rarity.MYTHIC, mage.cards.s.SwordOfSinewAndSteel.class)); cards.add(new SetCardInfo("Sword of Truth and Justice", 229, Rarity.MYTHIC, mage.cards.s.SwordOfTruthAndJustice.class)); + cards.add(new SetCardInfo("Talisman of Curiosity", 232, Rarity.COMMON, mage.cards.t.TalismanOfCuriosity.class)); cards.add(new SetCardInfo("Tempered Sliver", 183, Rarity.UNCOMMON, mage.cards.t.TemperedSliver.class)); cards.add(new SetCardInfo("The First Sliver", 200, Rarity.MYTHIC, mage.cards.t.TheFirstSliver.class)); cards.add(new SetCardInfo("Thundering Djinn", 215, Rarity.UNCOMMON, mage.cards.t.ThunderingDjinn.class)); From de8510dbe67092f75f774a488d4398eb48d76403 Mon Sep 17 00:00:00 2001 From: Evan Kranzler Date: Mon, 27 May 2019 17:06:59 -0400 Subject: [PATCH 19/38] Implemented Talisman of Resistance --- .../mage/cards/t/TalismanOfResilience.java | 42 +++++++++++++++++++ Mage.Sets/src/mage/sets/ModernHorizons.java | 1 + 2 files changed, 43 insertions(+) create mode 100644 Mage.Sets/src/mage/cards/t/TalismanOfResilience.java diff --git a/Mage.Sets/src/mage/cards/t/TalismanOfResilience.java b/Mage.Sets/src/mage/cards/t/TalismanOfResilience.java new file mode 100644 index 00000000000..595794ab99e --- /dev/null +++ b/Mage.Sets/src/mage/cards/t/TalismanOfResilience.java @@ -0,0 +1,42 @@ +package mage.cards.t; + +import mage.abilities.Ability; +import mage.abilities.effects.common.DamageControllerEffect; +import mage.abilities.mana.BlackManaAbility; +import mage.abilities.mana.ColorlessManaAbility; +import mage.abilities.mana.GreenManaAbility; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class TalismanOfResilience extends CardImpl { + + public TalismanOfResilience(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.ARTIFACT}, "{2}"); + + // {T}: Add {C}. + this.addAbility(new ColorlessManaAbility()); + + // {T}: Add {B} or {G}. Talisman of Resilience deals 1 damage to you. + Ability ability = new BlackManaAbility(); + ability.addEffect(new DamageControllerEffect(1)); + this.addAbility(ability); + ability = new GreenManaAbility(); + ability.addEffect(new DamageControllerEffect(1)); + this.addAbility(ability); + } + + private TalismanOfResilience(final TalismanOfResilience card) { + super(card); + } + + @Override + public TalismanOfResilience copy() { + return new TalismanOfResilience(this); + } +} diff --git a/Mage.Sets/src/mage/sets/ModernHorizons.java b/Mage.Sets/src/mage/sets/ModernHorizons.java index 451133d8c18..612ac031e51 100644 --- a/Mage.Sets/src/mage/sets/ModernHorizons.java +++ b/Mage.Sets/src/mage/sets/ModernHorizons.java @@ -133,6 +133,7 @@ public final class ModernHorizons extends ExpansionSet { cards.add(new SetCardInfo("Sword of Sinew and Steel", 228, Rarity.MYTHIC, mage.cards.s.SwordOfSinewAndSteel.class)); cards.add(new SetCardInfo("Sword of Truth and Justice", 229, Rarity.MYTHIC, mage.cards.s.SwordOfTruthAndJustice.class)); cards.add(new SetCardInfo("Talisman of Curiosity", 232, Rarity.COMMON, mage.cards.t.TalismanOfCuriosity.class)); + cards.add(new SetCardInfo("Talisman of Resilience", 234, Rarity.UNCOMMON, mage.cards.t.TalismanOfResilience.class)); cards.add(new SetCardInfo("Tempered Sliver", 183, Rarity.UNCOMMON, mage.cards.t.TemperedSliver.class)); cards.add(new SetCardInfo("The First Sliver", 200, Rarity.MYTHIC, mage.cards.t.TheFirstSliver.class)); cards.add(new SetCardInfo("Thundering Djinn", 215, Rarity.UNCOMMON, mage.cards.t.ThunderingDjinn.class)); From 9585040cbfc33d17f2e8578dc45366e1f62c09d6 Mon Sep 17 00:00:00 2001 From: Evan Kranzler Date: Mon, 27 May 2019 17:09:03 -0400 Subject: [PATCH 20/38] Implemented Talisman of Creativity --- .../mage/cards/t/TalismanOfCreativity.java | 42 +++++++++++++++++++ Mage.Sets/src/mage/sets/ModernHorizons.java | 1 + 2 files changed, 43 insertions(+) create mode 100644 Mage.Sets/src/mage/cards/t/TalismanOfCreativity.java diff --git a/Mage.Sets/src/mage/cards/t/TalismanOfCreativity.java b/Mage.Sets/src/mage/cards/t/TalismanOfCreativity.java new file mode 100644 index 00000000000..ab2215147ef --- /dev/null +++ b/Mage.Sets/src/mage/cards/t/TalismanOfCreativity.java @@ -0,0 +1,42 @@ +package mage.cards.t; + +import mage.abilities.Ability; +import mage.abilities.effects.common.DamageControllerEffect; +import mage.abilities.mana.BlueManaAbility; +import mage.abilities.mana.ColorlessManaAbility; +import mage.abilities.mana.RedManaAbility; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class TalismanOfCreativity extends CardImpl { + + public TalismanOfCreativity(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.ARTIFACT}, "{2}"); + + // {T}: Add {C}. + this.addAbility(new ColorlessManaAbility()); + + // {T}: Add {U} or {R}. Talisman of Creativity deals 1 damage to you. + Ability ability = new BlueManaAbility(); + ability.addEffect(new DamageControllerEffect(1)); + this.addAbility(ability); + ability = new RedManaAbility(); + ability.addEffect(new DamageControllerEffect(1)); + this.addAbility(ability); + } + + private TalismanOfCreativity(final TalismanOfCreativity card) { + super(card); + } + + @Override + public TalismanOfCreativity copy() { + return new TalismanOfCreativity(this); + } +} diff --git a/Mage.Sets/src/mage/sets/ModernHorizons.java b/Mage.Sets/src/mage/sets/ModernHorizons.java index 612ac031e51..bfc943e9b2b 100644 --- a/Mage.Sets/src/mage/sets/ModernHorizons.java +++ b/Mage.Sets/src/mage/sets/ModernHorizons.java @@ -132,6 +132,7 @@ public final class ModernHorizons extends ExpansionSet { cards.add(new SetCardInfo("Sunbaked Canyon", 247, Rarity.RARE, mage.cards.s.SunbakedCanyon.class)); cards.add(new SetCardInfo("Sword of Sinew and Steel", 228, Rarity.MYTHIC, mage.cards.s.SwordOfSinewAndSteel.class)); cards.add(new SetCardInfo("Sword of Truth and Justice", 229, Rarity.MYTHIC, mage.cards.s.SwordOfTruthAndJustice.class)); + cards.add(new SetCardInfo("Talisman of Creativity", 231, Rarity.UNCOMMON, mage.cards.t.TalismanOfCreativity.class)); cards.add(new SetCardInfo("Talisman of Curiosity", 232, Rarity.COMMON, mage.cards.t.TalismanOfCuriosity.class)); cards.add(new SetCardInfo("Talisman of Resilience", 234, Rarity.UNCOMMON, mage.cards.t.TalismanOfResilience.class)); cards.add(new SetCardInfo("Tempered Sliver", 183, Rarity.UNCOMMON, mage.cards.t.TemperedSliver.class)); From 6fc1c4b2e175e545fa378d8c4fb65d5b5f1a3e55 Mon Sep 17 00:00:00 2001 From: Evan Kranzler Date: Mon, 27 May 2019 17:12:41 -0400 Subject: [PATCH 21/38] Implemented Talisman of Conviction --- .../mage/cards/t/TalismanOfConviction.java | 42 +++++++++++++++++++ Mage.Sets/src/mage/sets/ModernHorizons.java | 1 + 2 files changed, 43 insertions(+) create mode 100644 Mage.Sets/src/mage/cards/t/TalismanOfConviction.java diff --git a/Mage.Sets/src/mage/cards/t/TalismanOfConviction.java b/Mage.Sets/src/mage/cards/t/TalismanOfConviction.java new file mode 100644 index 00000000000..df0fb5d534a --- /dev/null +++ b/Mage.Sets/src/mage/cards/t/TalismanOfConviction.java @@ -0,0 +1,42 @@ +package mage.cards.t; + +import mage.abilities.Ability; +import mage.abilities.effects.common.DamageControllerEffect; +import mage.abilities.mana.ColorlessManaAbility; +import mage.abilities.mana.RedManaAbility; +import mage.abilities.mana.WhiteManaAbility; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class TalismanOfConviction extends CardImpl { + + public TalismanOfConviction(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.ARTIFACT}, "{2}"); + + // {T}: Add {C}. + this.addAbility(new ColorlessManaAbility()); + + // {T}: Add {R} or {W}. Talisman of Conviction deals 1 damage to you. + Ability ability = new RedManaAbility(); + ability.addEffect(new DamageControllerEffect(1)); + this.addAbility(ability); + ability = new WhiteManaAbility(); + ability.addEffect(new DamageControllerEffect(1)); + this.addAbility(ability); + } + + private TalismanOfConviction(final TalismanOfConviction card) { + super(card); + } + + @Override + public TalismanOfConviction copy() { + return new TalismanOfConviction(this); + } +} diff --git a/Mage.Sets/src/mage/sets/ModernHorizons.java b/Mage.Sets/src/mage/sets/ModernHorizons.java index bfc943e9b2b..af304306064 100644 --- a/Mage.Sets/src/mage/sets/ModernHorizons.java +++ b/Mage.Sets/src/mage/sets/ModernHorizons.java @@ -132,6 +132,7 @@ public final class ModernHorizons extends ExpansionSet { cards.add(new SetCardInfo("Sunbaked Canyon", 247, Rarity.RARE, mage.cards.s.SunbakedCanyon.class)); cards.add(new SetCardInfo("Sword of Sinew and Steel", 228, Rarity.MYTHIC, mage.cards.s.SwordOfSinewAndSteel.class)); cards.add(new SetCardInfo("Sword of Truth and Justice", 229, Rarity.MYTHIC, mage.cards.s.SwordOfTruthAndJustice.class)); + cards.add(new SetCardInfo("Talisman of Conviction", 230, Rarity.UNCOMMON, mage.cards.t.TalismanOfConviction.class)); cards.add(new SetCardInfo("Talisman of Creativity", 231, Rarity.UNCOMMON, mage.cards.t.TalismanOfCreativity.class)); cards.add(new SetCardInfo("Talisman of Curiosity", 232, Rarity.COMMON, mage.cards.t.TalismanOfCuriosity.class)); cards.add(new SetCardInfo("Talisman of Resilience", 234, Rarity.UNCOMMON, mage.cards.t.TalismanOfResilience.class)); From 5dccc381aa3b7373dba46f9809716dcd8b512de1 Mon Sep 17 00:00:00 2001 From: Evan Kranzler Date: Mon, 27 May 2019 17:14:07 -0400 Subject: [PATCH 22/38] Implemented Talisman of Hierarchy --- .../src/mage/cards/t/TalismanOfHierarchy.java | 42 +++++++++++++++++++ Mage.Sets/src/mage/sets/ModernHorizons.java | 1 + 2 files changed, 43 insertions(+) create mode 100644 Mage.Sets/src/mage/cards/t/TalismanOfHierarchy.java diff --git a/Mage.Sets/src/mage/cards/t/TalismanOfHierarchy.java b/Mage.Sets/src/mage/cards/t/TalismanOfHierarchy.java new file mode 100644 index 00000000000..ceed35cbbd3 --- /dev/null +++ b/Mage.Sets/src/mage/cards/t/TalismanOfHierarchy.java @@ -0,0 +1,42 @@ +package mage.cards.t; + +import mage.abilities.Ability; +import mage.abilities.effects.common.DamageControllerEffect; +import mage.abilities.mana.BlackManaAbility; +import mage.abilities.mana.ColorlessManaAbility; +import mage.abilities.mana.WhiteManaAbility; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class TalismanOfHierarchy extends CardImpl { + + public TalismanOfHierarchy(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.ARTIFACT}, "{2}"); + + // {T}: Add {C}. + this.addAbility(new ColorlessManaAbility()); + + // {T}: Add {W} or {B}. Talisman of Hierarchy deals 1 damage to you. + Ability ability = new WhiteManaAbility(); + ability.addEffect(new DamageControllerEffect(1)); + this.addAbility(ability); + ability = new BlackManaAbility(); + ability.addEffect(new DamageControllerEffect(1)); + this.addAbility(ability); + } + + private TalismanOfHierarchy(final TalismanOfHierarchy card) { + super(card); + } + + @Override + public TalismanOfHierarchy copy() { + return new TalismanOfHierarchy(this); + } +} diff --git a/Mage.Sets/src/mage/sets/ModernHorizons.java b/Mage.Sets/src/mage/sets/ModernHorizons.java index af304306064..a175beadaad 100644 --- a/Mage.Sets/src/mage/sets/ModernHorizons.java +++ b/Mage.Sets/src/mage/sets/ModernHorizons.java @@ -135,6 +135,7 @@ public final class ModernHorizons extends ExpansionSet { cards.add(new SetCardInfo("Talisman of Conviction", 230, Rarity.UNCOMMON, mage.cards.t.TalismanOfConviction.class)); cards.add(new SetCardInfo("Talisman of Creativity", 231, Rarity.UNCOMMON, mage.cards.t.TalismanOfCreativity.class)); cards.add(new SetCardInfo("Talisman of Curiosity", 232, Rarity.COMMON, mage.cards.t.TalismanOfCuriosity.class)); + cards.add(new SetCardInfo("Talisman of Hierarchy", 233, Rarity.UNCOMMON, mage.cards.t.TalismanOfHierarchy.class)); cards.add(new SetCardInfo("Talisman of Resilience", 234, Rarity.UNCOMMON, mage.cards.t.TalismanOfResilience.class)); cards.add(new SetCardInfo("Tempered Sliver", 183, Rarity.UNCOMMON, mage.cards.t.TemperedSliver.class)); cards.add(new SetCardInfo("The First Sliver", 200, Rarity.MYTHIC, mage.cards.t.TheFirstSliver.class)); From ce3c67f29b41bfd206c6cc8ecc2f52bd3b1f082d Mon Sep 17 00:00:00 2001 From: Evan Kranzler Date: Mon, 27 May 2019 17:42:53 -0400 Subject: [PATCH 23/38] updated MH1 spoiler --- Utils/mtg-cards-data.txt | 1 + 1 file changed, 1 insertion(+) diff --git a/Utils/mtg-cards-data.txt b/Utils/mtg-cards-data.txt index b4a93ff56b2..1d57b982974 100644 --- a/Utils/mtg-cards-data.txt +++ b/Utils/mtg-cards-data.txt @@ -35199,6 +35199,7 @@ Springbloom Druid|Modern Horizons|181|C|{2}{G}|Creature - Elf Druid|1|1|When Spr Squirrel Nest|Modern Horizons|182|U|{1}{G}{G}|Enchantment - Aura|||Enchant land$Enchanted land has "{T}: Create a 1/1 green Squirrel creature token."| Tempered Sliver|Modern Horizons|183|U|{2}{G}|Creature - Sliver|2|2|Sliver creatures you control have "Whenever this creature deals combat damage to a player, put a +1/+1 counter on it."| Unbound Flourishing|Modern Horizons|189|M|{2}{G}|Enchantment|||Whenever you cast a permanent spell with a mana cost that contains {X}, double the value of X.$Whenever you cast an instant or sorcery spell or activate an ability, if that spell's mana cost or that ability's activation cost contains {X}, copy that spell or ability. You may choose new targets for the copy.| +Weather the Storm|Modern Horizons|191|C|{1}{G}|Instant|||You gain 3 life.$Storm| Abominable Treefolk|Modern Horizons|194|U|{2}{G}{U}|Snow Creature - Treefolk|*|*|Trample$Abominable Treefolk's power and toughness are each equal to the number of snow permanents you control.$When Abominable Treefolk enters the battlefield, tap target creature an opponent controls. That creature doesn't untap during its controller's next untap step.| Cloudshredder Sliver|Modern Horizons|195|R|{R}{W}|Creature - Sliver|1|1|Sliver creatures you control have flying and haste.| Collected Conjuring|Modern Horizons|196|R|{2}{U}{R}|Sorcery|||Exile the top six cards of your library. You may cast up to two sorcery cards with converted mana costs 3 or less from among them without paying their mana cost. Put the exiled cards not cast this way on the bottom of your library in a random order.| From 01a97038d36831b2b4455acb7e386c82b59f1512 Mon Sep 17 00:00:00 2001 From: Evan Kranzler Date: Mon, 27 May 2019 17:44:44 -0400 Subject: [PATCH 24/38] Implemented Weather the Storm --- .../src/mage/cards/w/WeatherTheStorm.java | 34 +++++++++++++++++++ Mage.Sets/src/mage/sets/ModernHorizons.java | 1 + 2 files changed, 35 insertions(+) create mode 100644 Mage.Sets/src/mage/cards/w/WeatherTheStorm.java diff --git a/Mage.Sets/src/mage/cards/w/WeatherTheStorm.java b/Mage.Sets/src/mage/cards/w/WeatherTheStorm.java new file mode 100644 index 00000000000..1773a0d8322 --- /dev/null +++ b/Mage.Sets/src/mage/cards/w/WeatherTheStorm.java @@ -0,0 +1,34 @@ +package mage.cards.w; + +import mage.abilities.effects.common.GainLifeEffect; +import mage.abilities.keyword.StormAbility; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class WeatherTheStorm extends CardImpl { + + public WeatherTheStorm(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.INSTANT}, "{1}{G}"); + + // You gain 3 life. + this.getSpellAbility().addEffect(new GainLifeEffect(3)); + + // Storm + this.addAbility(new StormAbility()); + } + + private WeatherTheStorm(final WeatherTheStorm card) { + super(card); + } + + @Override + public WeatherTheStorm copy() { + return new WeatherTheStorm(this); + } +} diff --git a/Mage.Sets/src/mage/sets/ModernHorizons.java b/Mage.Sets/src/mage/sets/ModernHorizons.java index a175beadaad..11b6fcc5f4c 100644 --- a/Mage.Sets/src/mage/sets/ModernHorizons.java +++ b/Mage.Sets/src/mage/sets/ModernHorizons.java @@ -146,6 +146,7 @@ public final class ModernHorizons extends ExpansionSet { cards.add(new SetCardInfo("Venomous Changeling", 114, Rarity.COMMON, mage.cards.v.VenomousChangeling.class)); cards.add(new SetCardInfo("Wall of One Thousand Cuts", 36, Rarity.COMMON, mage.cards.w.WallOfOneThousandCuts.class)); cards.add(new SetCardInfo("Waterlogged Grove", 249, Rarity.RARE, mage.cards.w.WaterloggedGrove.class)); + cards.add(new SetCardInfo("Weather the Storm", 191, Rarity.COMMON, mage.cards.w.WeatherTheStorm.class)); cards.add(new SetCardInfo("Winds of Abandon", 37, Rarity.RARE, mage.cards.w.WindsOfAbandon.class)); cards.add(new SetCardInfo("Wing Shards", 38, Rarity.UNCOMMON, mage.cards.w.WingShards.class)); cards.add(new SetCardInfo("Wrenn and Six", 217, Rarity.MYTHIC, mage.cards.w.WrennAndSix.class)); From 6e170c561082fd3787802763e646479b7788f2ee Mon Sep 17 00:00:00 2001 From: Evan Kranzler Date: Mon, 27 May 2019 18:15:19 -0400 Subject: [PATCH 25/38] updated MH1 spoiler and reprints --- Mage.Sets/src/mage/sets/ModernHorizons.java | 1 + Utils/mtg-cards-data.txt | 3 +++ 2 files changed, 4 insertions(+) diff --git a/Mage.Sets/src/mage/sets/ModernHorizons.java b/Mage.Sets/src/mage/sets/ModernHorizons.java index 11b6fcc5f4c..ae767affaf6 100644 --- a/Mage.Sets/src/mage/sets/ModernHorizons.java +++ b/Mage.Sets/src/mage/sets/ModernHorizons.java @@ -92,6 +92,7 @@ public final class ModernHorizons extends ExpansionSet { cards.add(new SetCardInfo("Mother Bear", 171, Rarity.COMMON, mage.cards.m.MotherBear.class)); cards.add(new SetCardInfo("Mox Tantalite", 226, Rarity.MYTHIC, mage.cards.m.MoxTantalite.class)); cards.add(new SetCardInfo("Munitions Expert", 209, Rarity.UNCOMMON, mage.cards.m.MunitionsExpert.class)); + cards.add(new SetCardInfo("Nantuko Cultivator", 173, Rarity.UNCOMMON, mage.cards.n.NantukoCultivator.class)); cards.add(new SetCardInfo("Nature's Chant", 210, Rarity.COMMON, mage.cards.n.NaturesChant.class)); cards.add(new SetCardInfo("Nimble Mongoose", 174, Rarity.COMMON, mage.cards.n.NimbleMongoose.class)); cards.add(new SetCardInfo("Nurturing Peatland", 243, Rarity.RARE, mage.cards.n.NurturingPeatland.class)); diff --git a/Utils/mtg-cards-data.txt b/Utils/mtg-cards-data.txt index 1d57b982974..5b90cef1ab0 100644 --- a/Utils/mtg-cards-data.txt +++ b/Utils/mtg-cards-data.txt @@ -35171,6 +35171,7 @@ Goatnap|Modern Horizons|126|C|{2}{R}|Sorcery|||Gain control of target creature u Goblin Champion|Modern Horizons|127|C|{R}|Creature - Goblin Warrior|0|1|Haste$Exalted| Goblin Engineer|Modern Horizons|128|R|{1}{R}|Creature - Goblin Artificer|1|2|When Goblin Engineer enters the battlefield, you may search your library for an artifact card, put it into your graveyard, then shuffle your library.${R}, {T}, Sacrifice an artifact: Return target artifact card with converted mana cost 3 or less from your graveyard to the battlefield.| Goblin Matron|Modern Horizons|129|U|{2}{R}|Creature - Goblin|1|1|When Goblin Matron enters the battlefield, you may search your library for a Goblin card, reveal that card, and put it into your hand. If you do, shuffle your library.| +Goblin Oriflamme|Modern Horizons|130|U|{1}{R}|Enchantment|||Attacking creatures you control get +1/+0.| Goblin War Party|Modern Horizons|131|C|{3}{R}|Sorcery|||Choose one —$• Create three 1/1 red Goblin creature tokens.$• Creatures you control get +1/+1 and gain haste until end of turn.$Entwine {2}{R}| Hollowhead Sliver|Modern Horizons|132|U|{2}{R}|Creature - Sliver|2|2|Sliver creatures you control have "{T}, Discard a card: Draw a card."| Lava Dart|Modern Horizons|134|C|{R}|Instant|||Lava Dart deals 1 damage to any target.$Flashback—Sacrifice a Mountain.| @@ -35190,6 +35191,7 @@ Genesis|Modern Horizons|166|R|{4}{G}|Creature - Incarnation|4|4|At the beginning Glacial Revelation|Modern Horizons|167|U|{2}{G}|Sorcery|||Reveal the top six cards of your library. You may put any number of snow permanent cards from among them into your hand. Put the rest into your graveyard.| Hexdrinker|Modern Horizons|168|M|{G}|Creature - Snake|2|1|Level up {1}$LEVEL 3-7$4/4$Protection from instants$LEVEL 8+$6/6$Protection from everything| Mother Bear|Modern Horizons|171|C|{1}{G}|Creature - Bear|2|2|{3}{G}{G}, Exile Mother Bear from your graveyard: Create two 2/2 green Bear creature tokens. Activate this ability only any time you could cast a sorcery.| +Nantuko Cultivator|Modern Horizons|173|U|{3}{G}|Creature - Insect Druid|2|2|When Nantuko Cultivator enters the battlefield, you may discard any number of land cards. Put that many +1/+1 counters on Nantuko Cultivator and draw that many cards.| Nimble Mongoose|Modern Horizons|174|C|{G}|Creature - Mongoose|1|1|Shroud$Threshold — Nimble Mongoose gets +2/+2 as long as seven or more cards are in your graveyard.| Regrowth|Modern Horizons|175|U|{1}{G}|Sorcery|||Return target card from your graveyard to your hand.| Savage Swipe|Modern Horizons|178|C|{G}|Sorcery|||Target creature you control gets +2/+2 until end of turn if its power is 2. Then it fights target creature you don't control.| @@ -35209,6 +35211,7 @@ Fallen Shinobi|Modern Horizons|199|R|{3}{U}{B}|Creature - Zombie Ninja|5|4|Ninju The First Sliver|Modern Horizons|200|M|{W}{U}{B}{R}{G}|Legendary Creature - Sliver|7|7|Cascade$Sliver spells you cast have cascade.| Good-Fortune Unicorn|Modern Horizons|201|U|{1}{G}{W}|Creature - Unicorn|2|2|Whenever another creature enters the battlefield under your control, put a +1/+1 counter on that creature.| Ice-Fang Coatl|Modern Horizons|203|R|{G}{U}|Snow Creature - Snake|1|1|Flash$Flying$When Ice-Fang Coatl enters the battlefield, draw a card.$Ice-Fang Coatl has deathtouch as long as you control at least three other snow permanents.| +Ingenious Infiltrator|Modern Horizons|204|U|{2}{U}{B}|Creature - Vedalken Ninja|2|3|Ninjutsu {U}{B}$Whenever a Ninja you control deals combat damage to a player, draw a card.| Kess, Dissident Mage|Modern Horizons|206|M|{1}{U}{B}{R}|Legendary Creature - Human Wizard|3|4|Flying$During each of your turns, you may cast an instant or sorcery card from your graveyard. If a card cast this way would be put into your graveyard, exile it instead.| Lavabelly Sliver|Modern Horizons|207|U|{1}{R}{W}|Creature - Sliver|2|2|Sliver creatures you control have "When this creature enters the battlefield, it deals 1 damage to target player or planeswalker and you gain 1 life."| Lightning Skelemental|Modern Horizons|208|R|{B}{R}{R}|Creature - Elemental Skeleton|6|1|Trample, haste$Whenever Lightning Skelemental deals combat damage to a player, that player discards two cards.$At the beginning of the end step, sacrifice Lightning Skelemental.| From 5dfac2524031716d74a2f8f5acf00f56ef704d94 Mon Sep 17 00:00:00 2001 From: Evan Kranzler Date: Mon, 27 May 2019 18:17:06 -0400 Subject: [PATCH 26/38] Implemented Goblin Oriflamme --- .../src/mage/cards/g/GoblinOriflamme.java | 36 +++++++++++++++++++ Mage.Sets/src/mage/sets/ModernHorizons.java | 1 + 2 files changed, 37 insertions(+) create mode 100644 Mage.Sets/src/mage/cards/g/GoblinOriflamme.java diff --git a/Mage.Sets/src/mage/cards/g/GoblinOriflamme.java b/Mage.Sets/src/mage/cards/g/GoblinOriflamme.java new file mode 100644 index 00000000000..ed1749a197a --- /dev/null +++ b/Mage.Sets/src/mage/cards/g/GoblinOriflamme.java @@ -0,0 +1,36 @@ +package mage.cards.g; + +import mage.abilities.common.SimpleStaticAbility; +import mage.abilities.effects.common.continuous.BoostControlledEffect; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.Duration; +import mage.filter.StaticFilters; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class GoblinOriflamme extends CardImpl { + + public GoblinOriflamme(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.ENCHANTMENT}, "{1}{R}"); + + // Attacking creatures you control get +1/+0. + this.addAbility(new SimpleStaticAbility(new BoostControlledEffect( + 1, 0, Duration.EndOfTurn, + StaticFilters.FILTER_ATTACKING_CREATURES + ))); + } + + private GoblinOriflamme(final GoblinOriflamme card) { + super(card); + } + + @Override + public GoblinOriflamme copy() { + return new GoblinOriflamme(this); + } +} diff --git a/Mage.Sets/src/mage/sets/ModernHorizons.java b/Mage.Sets/src/mage/sets/ModernHorizons.java index ae767affaf6..20496969a30 100644 --- a/Mage.Sets/src/mage/sets/ModernHorizons.java +++ b/Mage.Sets/src/mage/sets/ModernHorizons.java @@ -73,6 +73,7 @@ public final class ModernHorizons extends ExpansionSet { cards.add(new SetCardInfo("Goblin Champion", 127, Rarity.COMMON, mage.cards.g.GoblinChampion.class)); cards.add(new SetCardInfo("Goblin Engineer", 128, Rarity.RARE, mage.cards.g.GoblinEngineer.class)); cards.add(new SetCardInfo("Goblin Matron", 129, Rarity.UNCOMMON, mage.cards.g.GoblinMatron.class)); + cards.add(new SetCardInfo("Goblin Oriflamme", 130, Rarity.UNCOMMON, mage.cards.g.GoblinOriflamme.class)); cards.add(new SetCardInfo("Goblin War Party", 131, Rarity.COMMON, mage.cards.g.GoblinWarParty.class)); cards.add(new SetCardInfo("Good-Fortune Unicorn", 201, Rarity.UNCOMMON, mage.cards.g.GoodFortuneUnicorn.class)); cards.add(new SetCardInfo("Headless Specter", 95, Rarity.COMMON, mage.cards.h.HeadlessSpecter.class)); From c4e5182640eed1bffc7901b3c2b1a0c38f2643a9 Mon Sep 17 00:00:00 2001 From: Evan Kranzler Date: Mon, 27 May 2019 18:21:30 -0400 Subject: [PATCH 27/38] Implemented Ingenious Infiltrator --- .../mage/cards/i/IngeniousInfiltrator.java | 52 +++++++++++++++++++ Mage.Sets/src/mage/sets/ModernHorizons.java | 1 + 2 files changed, 53 insertions(+) create mode 100644 Mage.Sets/src/mage/cards/i/IngeniousInfiltrator.java diff --git a/Mage.Sets/src/mage/cards/i/IngeniousInfiltrator.java b/Mage.Sets/src/mage/cards/i/IngeniousInfiltrator.java new file mode 100644 index 00000000000..9ce8fe19550 --- /dev/null +++ b/Mage.Sets/src/mage/cards/i/IngeniousInfiltrator.java @@ -0,0 +1,52 @@ +package mage.cards.i; + +import mage.MageInt; +import mage.abilities.common.DealsDamageToAPlayerAllTriggeredAbility; +import mage.abilities.costs.mana.ManaCostsImpl; +import mage.abilities.effects.common.DrawCardSourceControllerEffect; +import mage.abilities.keyword.NinjutsuAbility; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.SetTargetPointer; +import mage.constants.SubType; +import mage.filter.FilterPermanent; +import mage.filter.common.FilterControlledCreaturePermanent; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class IngeniousInfiltrator extends CardImpl { + + private static final FilterPermanent filter + = new FilterControlledCreaturePermanent(SubType.NINJA, "a Ninja you control"); + + public IngeniousInfiltrator(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{2}{U}{B}"); + + this.subtype.add(SubType.VEDALKEN); + this.subtype.add(SubType.NINJA); + this.power = new MageInt(2); + this.toughness = new MageInt(3); + + // Ninjutsu {U}{B} + this.addAbility(new NinjutsuAbility(new ManaCostsImpl("{1}{U}"))); + + // Whenever a Ninja you control deals combat damage to a player, draw a card. + this.addAbility(new DealsDamageToAPlayerAllTriggeredAbility( + new DrawCardSourceControllerEffect(1), filter, + false, SetTargetPointer.NONE, true + )); + } + + private IngeniousInfiltrator(final IngeniousInfiltrator card) { + super(card); + } + + @Override + public IngeniousInfiltrator copy() { + return new IngeniousInfiltrator(this); + } +} diff --git a/Mage.Sets/src/mage/sets/ModernHorizons.java b/Mage.Sets/src/mage/sets/ModernHorizons.java index 20496969a30..404a7dede30 100644 --- a/Mage.Sets/src/mage/sets/ModernHorizons.java +++ b/Mage.Sets/src/mage/sets/ModernHorizons.java @@ -81,6 +81,7 @@ public final class ModernHorizons extends ExpansionSet { cards.add(new SetCardInfo("Hollowhead Sliver", 132, Rarity.UNCOMMON, mage.cards.h.HollowheadSliver.class)); cards.add(new SetCardInfo("Ice-Fang Coatl", 203, Rarity.RARE, mage.cards.i.IceFangCoatl.class)); cards.add(new SetCardInfo("Impostor of the Sixth Pride", 14, Rarity.COMMON, mage.cards.i.ImpostorOfTheSixthPride.class)); + cards.add(new SetCardInfo("Ingenious Infiltrator", 204, Rarity.UNCOMMON, mage.cards.i.IngeniousInfiltrator.class)); cards.add(new SetCardInfo("Kess, Dissident Mage", 206, Rarity.MYTHIC, mage.cards.k.KessDissidentMage.class)); cards.add(new SetCardInfo("King of the Pride", 16, Rarity.UNCOMMON, mage.cards.k.KingOfThePride.class)); cards.add(new SetCardInfo("Lava Dart", 134, Rarity.COMMON, mage.cards.l.LavaDart.class)); From 31f9d698d7ed222cf8e7e5440128ef9e9272e73f Mon Sep 17 00:00:00 2001 From: Evan Kranzler Date: Mon, 27 May 2019 19:41:21 -0400 Subject: [PATCH 28/38] updated MH1 spoiler --- Mage.Sets/src/mage/sets/ModernHorizons.java | 2 +- Utils/mtg-cards-data.txt | 7 ++++++- 2 files changed, 7 insertions(+), 2 deletions(-) diff --git a/Mage.Sets/src/mage/sets/ModernHorizons.java b/Mage.Sets/src/mage/sets/ModernHorizons.java index 404a7dede30..84cb937ecb9 100644 --- a/Mage.Sets/src/mage/sets/ModernHorizons.java +++ b/Mage.Sets/src/mage/sets/ModernHorizons.java @@ -137,7 +137,7 @@ public final class ModernHorizons extends ExpansionSet { cards.add(new SetCardInfo("Sword of Truth and Justice", 229, Rarity.MYTHIC, mage.cards.s.SwordOfTruthAndJustice.class)); cards.add(new SetCardInfo("Talisman of Conviction", 230, Rarity.UNCOMMON, mage.cards.t.TalismanOfConviction.class)); cards.add(new SetCardInfo("Talisman of Creativity", 231, Rarity.UNCOMMON, mage.cards.t.TalismanOfCreativity.class)); - cards.add(new SetCardInfo("Talisman of Curiosity", 232, Rarity.COMMON, mage.cards.t.TalismanOfCuriosity.class)); + cards.add(new SetCardInfo("Talisman of Curiosity", 232, Rarity.UNCOMMON, mage.cards.t.TalismanOfCuriosity.class)); cards.add(new SetCardInfo("Talisman of Hierarchy", 233, Rarity.UNCOMMON, mage.cards.t.TalismanOfHierarchy.class)); cards.add(new SetCardInfo("Talisman of Resilience", 234, Rarity.UNCOMMON, mage.cards.t.TalismanOfResilience.class)); cards.add(new SetCardInfo("Tempered Sliver", 183, Rarity.UNCOMMON, mage.cards.t.TemperedSliver.class)); diff --git a/Utils/mtg-cards-data.txt b/Utils/mtg-cards-data.txt index 5b90cef1ab0..192407b4ccb 100644 --- a/Utils/mtg-cards-data.txt +++ b/Utils/mtg-cards-data.txt @@ -35118,6 +35118,7 @@ Morophon, the Boundless|Modern Horizons|1|M|{7}|Legendary Creature - Shapeshifte Astral Drift|Modern Horizons|3|R|{2}{W}|Enchantment|||Whenever you cycle Astral Drift or cycle another card while Astral Drift is on the battlefield, you may exile target creature. If you do, return that card to the battlefield under its owner's control at the beginning of the next end step.$Cycling {2}{W}| Battle Screech|Modern Horizons|4|U|{2}{W}{W}|Sorcery|||Create two 1/1 white Bird creature tokens with flying.$Flashback—Tap three untapped white creatures you control.| Dismantling Blow|Modern Horizons|5|U|{2}{W}|Instant|||Kicker {2}{U}$Destroy target artifact or enchantment. If this spell was kicked, draw two cards.| +Enduring Sliver|Modern Horizons|8|C|{1}{W}|Creature - Sliver|2|2|Outlast {2}$Other sliver creatures you control have outlast {2}.| Force of Virtue|Modern Horizons|10|R|{2}{W}{W}|Enchantment|||If it's not your turn, you may exile a white card from your hand rather than pay this spell's mana cost.$Flash$Creatures you control get +1/+1.| Generous Gift|Modern Horizons|11|U|{2}{W}|Instant|||Destroy target permanent. Its controller creates a 3/3 green Elephant creature token.| Giver of Runes|Modern Horizons|13|R|{W}|Creature - Kor Cleric|1|2|{T}: Another target creature you control gains protection from colorless or from the color of your choice until end of turn.| @@ -35129,6 +35130,7 @@ Segovian Angel|Modern Horizons|25|C|{W}|Creature - Angel|1|1|Flying, vigilance| Serra the Benevolent|Modern Horizons|26|M|{2}{W}{W}|Legendary Planeswalker - Serra|4|+2: Creatures you control with flying get +1/+1 until end of turn.$-3: Create a 4/4 white Angel creature token with flying and vigilance.$-6: You get an emblem with "If you control a creature, damage that would reduce your life total to less than 1 reduces it to 1 instead."| Sisay, Weatherlight Captain|Modern Horizons|29|R|{2}{W}|Legendary Creature - Human Soldier|2|2|Sisay, Weatherlight Captain gets +1/+1 for each color among other legendary permanents you control.${W}{U}{B}{R}{G}: Search your library for a legendary permanent card with converted mana cost less than Sisay's power, put that card onto the battlefield, then shuffle your library.| Splicer's Skill|Modern Horizons|31|U|{2}{W}|Sorcery|||Create a 3/3 colorless Golem artifact creature token.$Splice onto instant or sorcery {3}{W}| +Valiant Changeling|Modern Horizons|34|U|{5}{W}{W}|Creature - Shapeshifter|3|3|This spell costs {1} less to cast for each creature type among creatures you control. This effect can't reduce the amount of mana this spell costs by more than {5}.$Changeling$Double strike| Wall of One Thousand Cuts|Modern Horizons|36|C|{3}{W}{W}|Creature - Wall|3|5|Defender, flying${W}: Wall of One Thousand Cuts can attack this turn as though it didn't have defender.| Winds of Abandon|Modern Horizons|37|R|{1}{W}|Sorcery|||Exile target creature you don't control. For each creature exiled this way, its controller searches their library for a basic land card. Those players put those cards onto the battlefield tapped, then shuffle their libraries.$Overload {4}{W}{W}| Wing Shards|Modern Horizons|38|U|{1}{W}{W}|Instant|||Target player sacrifices an attacking creature.$Storm| @@ -35164,6 +35166,7 @@ Undead Augur|Modern Horizons|112|U|{B}{B}|Creature - Zombie Wizard|2|2|Whenever Venomous Changeling|Modern Horizons|114|C|{2}{B}|Creature - Shapeshifter|1|3|Changeling$Deathtouch| Yawgmoth, Thran Physician|Modern Horizons|116|M|{2}{B}{B}|Legendary Creature - Human Cleric|2|4|Protection from Humans$Pay 1 life, Sacrifice another creature: Put a -1/-1 counter on up to one target creature and draw a card.${B}{B}, Discard a card: Proliferate.| Aria of Flame|Modern Horizons|118|R|{2}{R}|Enchantment|||When Aria of Flame enters the battlefield, each opponent gains 10 life.$Whenever you cast an instant or sorcery spell, put a verse counter on Aria of Flame, then it deals damage equal to the number of verse counters on it to target player or planeswalker.| +Bladeback Sliver|Modern Horizons|119|C|{1}{R}|Creature - Sliver|2|2|Hellbent — As long as you have no cards in hand, Sliver creatures you control have "{T}: This creature deals 1 damage to target player or planeswalker."| Firebolt|Modern Horizons|122|U|{R}|Sorcery|||Firebolt deals 2 damage to any target.$Flashback {4}{R}| Fists of Flame|Modern Horizons|123|C|{1}{R}|Instant|||Draw a card. Until end of turn, target creature gains trample and gets +1/+0 for each card you've drawn this turn.| Force of Rage|Modern Horizons|124|R|{1}{R}{R}|Instant|||If it's not your turn, you may exile a red card from your hand rather than pay this spell's mana cost.$Create two 3/1 red Elemental creature tokens with trample and haste. Sacrifice those tokens at the beginning of your next upkeep.| @@ -35202,6 +35205,7 @@ Squirrel Nest|Modern Horizons|182|U|{1}{G}{G}|Enchantment - Aura|||Enchant land$ Tempered Sliver|Modern Horizons|183|U|{2}{G}|Creature - Sliver|2|2|Sliver creatures you control have "Whenever this creature deals combat damage to a player, put a +1/+1 counter on it."| Unbound Flourishing|Modern Horizons|189|M|{2}{G}|Enchantment|||Whenever you cast a permanent spell with a mana cost that contains {X}, double the value of X.$Whenever you cast an instant or sorcery spell or activate an ability, if that spell's mana cost or that ability's activation cost contains {X}, copy that spell or ability. You may choose new targets for the copy.| Weather the Storm|Modern Horizons|191|C|{1}{G}|Instant|||You gain 3 life.$Storm| +Webweaver Changeling|Modern Horizons|192|U|{3}{G}{G}|Creature - Shapeshifter|3|5|Changeling$Reach$When Webweaver Changeling enters the battlefield, if there are three or more creature cards in your graveyard, you gain 5 life.| Abominable Treefolk|Modern Horizons|194|U|{2}{G}{U}|Snow Creature - Treefolk|*|*|Trample$Abominable Treefolk's power and toughness are each equal to the number of snow permanents you control.$When Abominable Treefolk enters the battlefield, tap target creature an opponent controls. That creature doesn't untap during its controller's next untap step.| Cloudshredder Sliver|Modern Horizons|195|R|{R}{W}|Creature - Sliver|1|1|Sliver creatures you control have flying and haste.| Collected Conjuring|Modern Horizons|196|R|{2}{U}{R}|Sorcery|||Exile the top six cards of your library. You may cast up to two sorcery cards with converted mana costs 3 or less from among them without paying their mana cost. Put the exiled cards not cast this way on the bottom of your library in a random order.| @@ -35212,6 +35216,7 @@ The First Sliver|Modern Horizons|200|M|{W}{U}{B}{R}{G}|Legendary Creature - Sliv Good-Fortune Unicorn|Modern Horizons|201|U|{1}{G}{W}|Creature - Unicorn|2|2|Whenever another creature enters the battlefield under your control, put a +1/+1 counter on that creature.| Ice-Fang Coatl|Modern Horizons|203|R|{G}{U}|Snow Creature - Snake|1|1|Flash$Flying$When Ice-Fang Coatl enters the battlefield, draw a card.$Ice-Fang Coatl has deathtouch as long as you control at least three other snow permanents.| Ingenious Infiltrator|Modern Horizons|204|U|{2}{U}{B}|Creature - Vedalken Ninja|2|3|Ninjutsu {U}{B}$Whenever a Ninja you control deals combat damage to a player, draw a card.| +Kaya's Guile|Modern Horizons|205|R|{1}{W}{B}|Instant|||Choose two —$• Each opponent sacrifices a creature.$• Exile all cards from each opponent's graveyard.$• Create a 1/1 white and black Spirit creature token with flying.$• You gain 4 life.$Entwine {3}| Kess, Dissident Mage|Modern Horizons|206|M|{1}{U}{B}{R}|Legendary Creature - Human Wizard|3|4|Flying$During each of your turns, you may cast an instant or sorcery card from your graveyard. If a card cast this way would be put into your graveyard, exile it instead.| Lavabelly Sliver|Modern Horizons|207|U|{1}{R}{W}|Creature - Sliver|2|2|Sliver creatures you control have "When this creature enters the battlefield, it deals 1 damage to target player or planeswalker and you gain 1 life."| Lightning Skelemental|Modern Horizons|208|R|{B}{R}{R}|Creature - Elemental Skeleton|6|1|Trample, haste$Whenever Lightning Skelemental deals combat damage to a player, that player discards two cards.$At the beginning of the end step, sacrifice Lightning Skelemental.| @@ -35228,7 +35233,7 @@ Sword of Sinew and Steel|Modern Horizons|228|M|{3}|Artifact - Equipment|||Equipp Sword of Truth and Justice|Modern Horizons|229|M|{3}|Artifact - Equipment|||Equipped creature gets +2/+2 and has protection from white and from blue.$Whenever equipped creature deals combat damage to a player, put a +1/+1 counter on a creature you control, then proliferate.$Equip {2}| Talisman of Conviction|Modern Horizons|230|U|{2}|Artifact|||{T}: Add {C}.${T}: Add {R} or {W}. Talisman of Conviction deals 1 damage to you.| Talisman of Creativity|Modern Horizons|231|U|{2}|Artifact|||{T}: Add {C}.${T}: Add {U} or {R}. Talisman of Creativity deals 1 damage to you.| -Talisman of Curiosity|Modern Horizons|232|C|{2}|Artifact|||{T}: Add {C}.${T}: Add {G} or {U}. Talisman of Curiosity deals 1 damage to you.| +Talisman of Curiosity|Modern Horizons|232|U|{2}|Artifact|||{T}: Add {C}.${T}: Add {G} or {U}. Talisman of Curiosity deals 1 damage to you.| Talisman of Hierarchy|Modern Horizons|233|U|{2}|Artifact|||{T}: Add {C}.${T}: Add {W} or {B}. Talisman of Hierarchy deals 1 damage to you.| Talisman of Resilience|Modern Horizons|234|U|{2}|Artifact|||{T}: Add {C}.${T}: Add {B} or {G}. Talisman of Resilience deals 1 damage to you.| Fiery Islet|Modern Horizons|238|R||Land|||{T}, Pay 1 life: Add {U} or {R}.${1}, {T}, Sacrifice Fiery Islet: Draw a card.| From 6b200e00e710630dc94ec82725142b1e60b00ef5 Mon Sep 17 00:00:00 2001 From: Evan Kranzler Date: Mon, 27 May 2019 20:29:58 -0400 Subject: [PATCH 29/38] Implemented Valiant Changeling --- .../src/mage/cards/v/ValiantChangeling.java | 101 ++++++++++++++++++ Mage.Sets/src/mage/sets/ModernHorizons.java | 1 + 2 files changed, 102 insertions(+) create mode 100644 Mage.Sets/src/mage/cards/v/ValiantChangeling.java diff --git a/Mage.Sets/src/mage/cards/v/ValiantChangeling.java b/Mage.Sets/src/mage/cards/v/ValiantChangeling.java new file mode 100644 index 00000000000..6a4d65c1505 --- /dev/null +++ b/Mage.Sets/src/mage/cards/v/ValiantChangeling.java @@ -0,0 +1,101 @@ +package mage.cards.v; + +import mage.MageInt; +import mage.abilities.Ability; +import mage.abilities.SpellAbility; +import mage.abilities.common.SimpleStaticAbility; +import mage.abilities.effects.common.cost.CostModificationEffectImpl; +import mage.abilities.keyword.ChangelingAbility; +import mage.abilities.keyword.DoubleStrikeAbility; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.*; +import mage.filter.StaticFilters; +import mage.game.Game; +import mage.game.permanent.Permanent; +import mage.util.CardUtil; + +import java.util.HashSet; +import java.util.Set; +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class ValiantChangeling extends CardImpl { + + public ValiantChangeling(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{5}{W}{W}"); + + this.subtype.add(SubType.SHAPESHIFTER); + this.power = new MageInt(3); + this.toughness = new MageInt(3); + + // This spell costs {1} less to cast for each creature type among creatures you control. This effect can't reduce the amount of mana this spell costs by more than {5}. + this.addAbility(new SimpleStaticAbility(Zone.ALL, new ValiantChangelingCostReductionEffect())); + + // Changeling + this.addAbility(ChangelingAbility.getInstance()); + + // Double strike + this.addAbility(DoubleStrikeAbility.getInstance()); + } + + private ValiantChangeling(final ValiantChangeling card) { + super(card); + } + + @Override + public ValiantChangeling copy() { + return new ValiantChangeling(this); + } +} + +class ValiantChangelingCostReductionEffect extends CostModificationEffectImpl { + + ValiantChangelingCostReductionEffect() { + super(Duration.WhileOnStack, Outcome.Benefit, CostModificationType.REDUCE_COST); + staticText = "This spell costs {1} less to cast for each creature type among creatures you control. " + + "This effect can't reduce the amount of mana this spell costs by more than {5}."; + } + + private ValiantChangelingCostReductionEffect(ValiantChangelingCostReductionEffect effect) { + super(effect); + } + + @Override + public boolean apply(Game game, Ability source, Ability abilityToModify) { + Set subTypes = new HashSet(); + int reductionAmount = 0; + for (Permanent permanent : game.getBattlefield().getActivePermanents( + StaticFilters.FILTER_PERMANENT_CREATURE, source.getControllerId(), source.getSourceId(), game + )) { + if (permanent.getAbilities().contains(ChangelingAbility.getInstance()) + || permanent.isAllCreatureTypes()) { + reductionAmount = 5; + break; + } + subTypes.addAll(permanent.getSubtype(game)); + reductionAmount = subTypes.size(); + if (reductionAmount > 4) { + break; + } + } + CardUtil.reduceCost(abilityToModify, Math.max(reductionAmount, 5)); + return true; + } + + @Override + public boolean applies(Ability abilityToModify, Ability source, Game game) { + if ((abilityToModify instanceof SpellAbility) + && abilityToModify.getSourceId().equals(source.getSourceId())) { + return game.getCard(abilityToModify.getSourceId()) != null; + } + return false; + } + + @Override + public ValiantChangelingCostReductionEffect copy() { + return new ValiantChangelingCostReductionEffect(this); + } +} diff --git a/Mage.Sets/src/mage/sets/ModernHorizons.java b/Mage.Sets/src/mage/sets/ModernHorizons.java index 84cb937ecb9..cf46108ba44 100644 --- a/Mage.Sets/src/mage/sets/ModernHorizons.java +++ b/Mage.Sets/src/mage/sets/ModernHorizons.java @@ -146,6 +146,7 @@ public final class ModernHorizons extends ExpansionSet { cards.add(new SetCardInfo("Umezawa's Charm", 111, Rarity.COMMON, mage.cards.u.UmezawasCharm.class)); cards.add(new SetCardInfo("Undead Augur", 112, Rarity.UNCOMMON, mage.cards.u.UndeadAugur.class)); cards.add(new SetCardInfo("Urza, Lord High Artificer", 75, Rarity.MYTHIC, mage.cards.u.UrzaLordHighArtificer.class)); + cards.add(new SetCardInfo("Valiant Changeling", 34, Rarity.UNCOMMON, mage.cards.v.ValiantChangeling.class)); cards.add(new SetCardInfo("Venomous Changeling", 114, Rarity.COMMON, mage.cards.v.VenomousChangeling.class)); cards.add(new SetCardInfo("Wall of One Thousand Cuts", 36, Rarity.COMMON, mage.cards.w.WallOfOneThousandCuts.class)); cards.add(new SetCardInfo("Waterlogged Grove", 249, Rarity.RARE, mage.cards.w.WaterloggedGrove.class)); From 9c427af90a0d9cf4c5c38f12d9d783622371767f Mon Sep 17 00:00:00 2001 From: Evan Kranzler Date: Mon, 27 May 2019 20:35:32 -0400 Subject: [PATCH 30/38] Implemented Bladeback Sliver --- .../src/mage/cards/b/BladebackSliver.java | 57 +++++++++++++++++++ Mage.Sets/src/mage/sets/ModernHorizons.java | 1 + 2 files changed, 58 insertions(+) create mode 100644 Mage.Sets/src/mage/cards/b/BladebackSliver.java diff --git a/Mage.Sets/src/mage/cards/b/BladebackSliver.java b/Mage.Sets/src/mage/cards/b/BladebackSliver.java new file mode 100644 index 00000000000..de3440775f2 --- /dev/null +++ b/Mage.Sets/src/mage/cards/b/BladebackSliver.java @@ -0,0 +1,57 @@ +package mage.cards.b; + +import mage.MageInt; +import mage.abilities.Ability; +import mage.abilities.common.SimpleActivatedAbility; +import mage.abilities.common.SimpleStaticAbility; +import mage.abilities.condition.common.HellbentCondition; +import mage.abilities.costs.common.TapSourceCost; +import mage.abilities.decorator.ConditionalContinuousEffect; +import mage.abilities.effects.common.DamageTargetEffect; +import mage.abilities.effects.common.continuous.GainAbilityControlledEffect; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.Duration; +import mage.constants.SubType; +import mage.filter.StaticFilters; +import mage.target.common.TargetPlayerOrPlaneswalker; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class BladebackSliver extends CardImpl { + + public BladebackSliver(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{1}{R}"); + + this.subtype.add(SubType.SLIVER); + this.power = new MageInt(2); + this.toughness = new MageInt(2); + + // Hellbent — As long as you have no cards in hand, Sliver creatures you control have "{T}: This creature deals 1 damage to target player or planeswalker." + Ability ability = new SimpleActivatedAbility( + new DamageTargetEffect(1, "this creature"), new TapSourceCost() + ); + ability.addTarget(new TargetPlayerOrPlaneswalker()); + this.addAbility(new SimpleStaticAbility(new ConditionalContinuousEffect( + new GainAbilityControlledEffect( + ability, Duration.WhileOnBattlefield, + StaticFilters.FILTER_PERMANENT_CREATURE_SLIVERS + ), HellbentCondition.instance, "Hellbent — " + + "As long as you have no cards in hand, Sliver creatures you control have " + + "\"{T}: This creature deals 1 damage to target player or planeswalker.\"" + ))); + } + + private BladebackSliver(final BladebackSliver card) { + super(card); + } + + @Override + public BladebackSliver copy() { + return new BladebackSliver(this); + } +} diff --git a/Mage.Sets/src/mage/sets/ModernHorizons.java b/Mage.Sets/src/mage/sets/ModernHorizons.java index cf46108ba44..58d55d12001 100644 --- a/Mage.Sets/src/mage/sets/ModernHorizons.java +++ b/Mage.Sets/src/mage/sets/ModernHorizons.java @@ -35,6 +35,7 @@ public final class ModernHorizons extends ExpansionSet { cards.add(new SetCardInfo("Ayula, Queen Among Bears", 155, Rarity.RARE, mage.cards.a.AyulaQueenAmongBears.class)); cards.add(new SetCardInfo("Battle Screech", 4, Rarity.UNCOMMON, mage.cards.b.BattleScreech.class)); cards.add(new SetCardInfo("Bazaar Trademage", 41, Rarity.RARE, mage.cards.b.BazaarTrademage.class)); + cards.add(new SetCardInfo("Bladeback Sliver", 119, Rarity.COMMON, mage.cards.b.BladebackSliver.class)); cards.add(new SetCardInfo("Cabal Therapist", 80, Rarity.RARE, mage.cards.c.CabalTherapist.class)); cards.add(new SetCardInfo("Changeling Outcast", 82, Rarity.COMMON, mage.cards.c.ChangelingOutcast.class)); cards.add(new SetCardInfo("Chillerpillar", 43, Rarity.COMMON, mage.cards.c.Chillerpillar.class)); From b6ba4e939d07f10b2698c77b383333a6a70cb358 Mon Sep 17 00:00:00 2001 From: Evan Kranzler Date: Mon, 27 May 2019 20:40:55 -0400 Subject: [PATCH 31/38] Implemented Enduring Sliver --- .../src/mage/cards/e/EnduringSliver.java | 47 +++++++++++++++++++ Mage.Sets/src/mage/sets/ModernHorizons.java | 1 + 2 files changed, 48 insertions(+) create mode 100644 Mage.Sets/src/mage/cards/e/EnduringSliver.java diff --git a/Mage.Sets/src/mage/cards/e/EnduringSliver.java b/Mage.Sets/src/mage/cards/e/EnduringSliver.java new file mode 100644 index 00000000000..b3085255b6f --- /dev/null +++ b/Mage.Sets/src/mage/cards/e/EnduringSliver.java @@ -0,0 +1,47 @@ +package mage.cards.e; + +import mage.MageInt; +import mage.abilities.common.SimpleStaticAbility; +import mage.abilities.costs.mana.ManaCostsImpl; +import mage.abilities.effects.common.continuous.GainAbilityControlledEffect; +import mage.abilities.keyword.OutlastAbility; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.Duration; +import mage.constants.SubType; +import mage.filter.StaticFilters; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class EnduringSliver extends CardImpl { + + public EnduringSliver(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{1}{W}"); + + this.subtype.add(SubType.SLIVER); + this.power = new MageInt(2); + this.toughness = new MageInt(2); + + // Outlast {2} + this.addAbility(new OutlastAbility(new ManaCostsImpl("{2}"))); + + // Other sliver creatures you control have outlast {2}. + this.addAbility(new SimpleStaticAbility(new GainAbilityControlledEffect( + new OutlastAbility(new ManaCostsImpl("{2}")), Duration.WhileOnBattlefield, + StaticFilters.FILTER_PERMANENT_CREATURE_SLIVERS, true + ).setText("Other sliver creatures you control have outlast {2}."))); + } + + private EnduringSliver(final EnduringSliver card) { + super(card); + } + + @Override + public EnduringSliver copy() { + return new EnduringSliver(this); + } +} diff --git a/Mage.Sets/src/mage/sets/ModernHorizons.java b/Mage.Sets/src/mage/sets/ModernHorizons.java index 58d55d12001..bb429099590 100644 --- a/Mage.Sets/src/mage/sets/ModernHorizons.java +++ b/Mage.Sets/src/mage/sets/ModernHorizons.java @@ -50,6 +50,7 @@ public final class ModernHorizons extends ExpansionSet { cards.add(new SetCardInfo("Dregscape Sliver", 88, Rarity.UNCOMMON, mage.cards.d.DregscapeSliver.class)); cards.add(new SetCardInfo("Eladamri's Call", 197, Rarity.RARE, mage.cards.e.EladamrisCall.class)); cards.add(new SetCardInfo("Elvish Fury", 162, Rarity.COMMON, mage.cards.e.ElvishFury.class)); + cards.add(new SetCardInfo("Enduring Sliver", 8, Rarity.COMMON, mage.cards.e.EnduringSliver.class)); cards.add(new SetCardInfo("Etchings of the Chosen", 198, Rarity.UNCOMMON, mage.cards.e.EtchingsOfTheChosen.class)); cards.add(new SetCardInfo("Exclude", 48, Rarity.UNCOMMON, mage.cards.e.Exclude.class)); cards.add(new SetCardInfo("Fact or Fiction", 50, Rarity.UNCOMMON, mage.cards.f.FactOrFiction.class)); From d4c633dd70e73e830ae597dab4278b4ead7adf16 Mon Sep 17 00:00:00 2001 From: Evan Kranzler Date: Mon, 27 May 2019 20:47:07 -0400 Subject: [PATCH 32/38] Implemented Webweaver Changeling --- .../src/mage/cards/w/WebweaverChangeling.java | 54 +++++++++++++++++++ Mage.Sets/src/mage/sets/ModernHorizons.java | 1 + 2 files changed, 55 insertions(+) create mode 100644 Mage.Sets/src/mage/cards/w/WebweaverChangeling.java diff --git a/Mage.Sets/src/mage/cards/w/WebweaverChangeling.java b/Mage.Sets/src/mage/cards/w/WebweaverChangeling.java new file mode 100644 index 00000000000..3dc320e565a --- /dev/null +++ b/Mage.Sets/src/mage/cards/w/WebweaverChangeling.java @@ -0,0 +1,54 @@ +package mage.cards.w; + +import mage.MageInt; +import mage.abilities.common.EntersBattlefieldTriggeredAbility; +import mage.abilities.condition.common.CardsInControllerGraveCondition; +import mage.abilities.decorator.ConditionalOneShotEffect; +import mage.abilities.effects.common.GainLifeEffect; +import mage.abilities.keyword.ChangelingAbility; +import mage.abilities.keyword.ReachAbility; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.SubType; +import mage.filter.StaticFilters; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class WebweaverChangeling extends CardImpl { + + public WebweaverChangeling(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{3}{G}{G}"); + + this.subtype.add(SubType.SHAPESHIFTER); + this.power = new MageInt(3); + this.toughness = new MageInt(5); + + // Changeling + this.addAbility(ChangelingAbility.getInstance()); + + // Reach + this.addAbility(ReachAbility.getInstance()); + + // When Webweaver Changeling enters the battlefield, if there are three or more creature cards in your graveyard, you gain 5 life. + this.addAbility(new EntersBattlefieldTriggeredAbility(new ConditionalOneShotEffect( + new GainLifeEffect(5), + new CardsInControllerGraveCondition( + 3, StaticFilters.FILTER_CARD_CREATURE + ), "When {this} enters the battlefield, if there are three or more " + + "creature cards in your graveyard, you gain 5 life." + ))); + } + + private WebweaverChangeling(final WebweaverChangeling card) { + super(card); + } + + @Override + public WebweaverChangeling copy() { + return new WebweaverChangeling(this); + } +} diff --git a/Mage.Sets/src/mage/sets/ModernHorizons.java b/Mage.Sets/src/mage/sets/ModernHorizons.java index bb429099590..cff73b770b3 100644 --- a/Mage.Sets/src/mage/sets/ModernHorizons.java +++ b/Mage.Sets/src/mage/sets/ModernHorizons.java @@ -153,6 +153,7 @@ public final class ModernHorizons extends ExpansionSet { cards.add(new SetCardInfo("Wall of One Thousand Cuts", 36, Rarity.COMMON, mage.cards.w.WallOfOneThousandCuts.class)); cards.add(new SetCardInfo("Waterlogged Grove", 249, Rarity.RARE, mage.cards.w.WaterloggedGrove.class)); cards.add(new SetCardInfo("Weather the Storm", 191, Rarity.COMMON, mage.cards.w.WeatherTheStorm.class)); + cards.add(new SetCardInfo("Webweaver Changeling", 192, Rarity.UNCOMMON, mage.cards.w.WebweaverChangeling.class)); cards.add(new SetCardInfo("Winds of Abandon", 37, Rarity.RARE, mage.cards.w.WindsOfAbandon.class)); cards.add(new SetCardInfo("Wing Shards", 38, Rarity.UNCOMMON, mage.cards.w.WingShards.class)); cards.add(new SetCardInfo("Wrenn and Six", 217, Rarity.MYTHIC, mage.cards.w.WrennAndSix.class)); From a18c3e1d888459bbb70f518424f3b1c4a4c5d1b4 Mon Sep 17 00:00:00 2001 From: Evan Kranzler Date: Mon, 27 May 2019 21:00:15 -0400 Subject: [PATCH 33/38] Implemented Kaya's Guile --- Mage.Sets/src/mage/cards/k/KayasGuile.java | 59 +++++++++++++++++++ Mage.Sets/src/mage/sets/ModernHorizons.java | 1 + .../abilities/keyword/EntwineAbility.java | 54 +++++++++-------- 3 files changed, 89 insertions(+), 25 deletions(-) create mode 100644 Mage.Sets/src/mage/cards/k/KayasGuile.java diff --git a/Mage.Sets/src/mage/cards/k/KayasGuile.java b/Mage.Sets/src/mage/cards/k/KayasGuile.java new file mode 100644 index 00000000000..feb8b1d6fc0 --- /dev/null +++ b/Mage.Sets/src/mage/cards/k/KayasGuile.java @@ -0,0 +1,59 @@ +package mage.cards.k; + +import mage.abilities.Mode; +import mage.abilities.costs.mana.ManaCostsImpl; +import mage.abilities.effects.common.CreateTokenEffect; +import mage.abilities.effects.common.ExileGraveyardAllPlayersEffect; +import mage.abilities.effects.common.GainLifeEffect; +import mage.abilities.effects.common.SacrificeOpponentsEffect; +import mage.abilities.keyword.EntwineAbility; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.TargetController; +import mage.filter.StaticFilters; +import mage.game.permanent.token.WhiteBlackSpiritToken; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class KayasGuile extends CardImpl { + + public KayasGuile(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.INSTANT}, "{1}{W}{B}"); + + // Choose two — + this.getSpellAbility().getModes().setMinModes(2); + this.getSpellAbility().getModes().setMaxModes(2); + + // • Each opponent sacrifices a creature. + this.getSpellAbility().addEffect(new SacrificeOpponentsEffect( + StaticFilters.FILTER_CONTROLLED_CREATURE_SHORT_TEXT + )); + + // • Exile all cards from each opponent's graveyard. + this.getSpellAbility().addMode(new Mode(new ExileGraveyardAllPlayersEffect( + StaticFilters.FILTER_CARD_CARDS, TargetController.OPPONENT + ))); + + // • Create a 1/1 white and black Spirit creature token with flying. + this.getSpellAbility().addMode(new Mode(new CreateTokenEffect(new WhiteBlackSpiritToken()))); + + // • You gain 4 life. + this.getSpellAbility().addMode(new Mode(new GainLifeEffect(4))); + + // Entwine {3} + this.addAbility(new EntwineAbility(new ManaCostsImpl("{3}"), "Choose all if you pay the entwine cost.")); + } + + private KayasGuile(final KayasGuile card) { + super(card); + } + + @Override + public KayasGuile copy() { + return new KayasGuile(this); + } +} diff --git a/Mage.Sets/src/mage/sets/ModernHorizons.java b/Mage.Sets/src/mage/sets/ModernHorizons.java index cff73b770b3..f794e50eb96 100644 --- a/Mage.Sets/src/mage/sets/ModernHorizons.java +++ b/Mage.Sets/src/mage/sets/ModernHorizons.java @@ -84,6 +84,7 @@ public final class ModernHorizons extends ExpansionSet { cards.add(new SetCardInfo("Ice-Fang Coatl", 203, Rarity.RARE, mage.cards.i.IceFangCoatl.class)); cards.add(new SetCardInfo("Impostor of the Sixth Pride", 14, Rarity.COMMON, mage.cards.i.ImpostorOfTheSixthPride.class)); cards.add(new SetCardInfo("Ingenious Infiltrator", 204, Rarity.UNCOMMON, mage.cards.i.IngeniousInfiltrator.class)); + cards.add(new SetCardInfo("Kaya's Guile", 205, Rarity.RARE, mage.cards.k.KayasGuile.class)); cards.add(new SetCardInfo("Kess, Dissident Mage", 206, Rarity.MYTHIC, mage.cards.k.KessDissidentMage.class)); cards.add(new SetCardInfo("King of the Pride", 16, Rarity.UNCOMMON, mage.cards.k.KingOfThePride.class)); cards.add(new SetCardInfo("Lava Dart", 134, Rarity.COMMON, mage.cards.l.LavaDart.class)); diff --git a/Mage/src/main/java/mage/abilities/keyword/EntwineAbility.java b/Mage/src/main/java/mage/abilities/keyword/EntwineAbility.java index ebbc8c89015..6b4b95043ef 100644 --- a/Mage/src/main/java/mage/abilities/keyword/EntwineAbility.java +++ b/Mage/src/main/java/mage/abilities/keyword/EntwineAbility.java @@ -1,30 +1,27 @@ package mage.abilities.keyword; -import java.util.Iterator; import mage.abilities.Ability; import mage.abilities.SpellAbility; import mage.abilities.StaticAbility; -import mage.abilities.costs.Cost; -import mage.abilities.costs.Costs; -import mage.abilities.costs.OptionalAdditionalCost; -import mage.abilities.costs.OptionalAdditionalCostImpl; -import mage.abilities.costs.OptionalAdditionalModeSourceCosts; +import mage.abilities.costs.*; import mage.abilities.costs.mana.ManaCostsImpl; import mage.constants.Outcome; import mage.constants.Zone; import mage.game.Game; import mage.players.Player; +import java.util.Iterator; + /** * 702.40. Entwine - * + *

* 702.40a Entwine is a static ability of modal spells (see rule 700.2) that * functions while the spell is on the stack. "Entwine [cost]" means "You may * choose all modes of this spell instead of just one. If you do, you pay an * additional [cost]." Using the entwine ability follows the rules for choosing * modes and paying additional costs in rules 601.2b and 601.2e-g. - * + *

* 702.40b If the entwine cost was paid, follow the text of each of the modes in * the order written on the card when the spell resolves. * @@ -33,15 +30,18 @@ import mage.players.Player; public class EntwineAbility extends StaticAbility implements OptionalAdditionalModeSourceCosts { private static final String keywordText = "Entwine"; - private static final String reminderText = "Choose both if you pay the entwine cost."; protected OptionalAdditionalCost additionalCost; public EntwineAbility(String manaString) { super(Zone.STACK, null); - this.additionalCost = new OptionalAdditionalCostImpl(keywordText, reminderText, new ManaCostsImpl(manaString)); + this.additionalCost = new OptionalAdditionalCostImpl(keywordText, "Choose both if you pay the entwine cost.", new ManaCostsImpl(manaString)); } public EntwineAbility(Cost cost) { + this(cost, "Choose both if you pay the entwine cost."); + } + + public EntwineAbility(Cost cost, String reminderText) { super(Zone.STACK, null); this.additionalCost = new OptionalAdditionalCostImpl(keywordText, "-", reminderText, cost); setRuleAtTheTop(true); @@ -80,28 +80,32 @@ public class EntwineAbility extends StaticAbility implements OptionalAdditionalM @Override public void changeModes(Ability ability, Game game) { - if (ability instanceof SpellAbility) { - Player player = game.getPlayer(controllerId); - if (player != null) { - this.resetCosts(); - if (additionalCost != null) { - if (additionalCost.canPay(ability, ability.getSourceId(), ability.getControllerId(), game) - && player.chooseUse(Outcome.Benefit, "Pay " + additionalCost.getText(false) + " ?", ability, game)) { + if (!(ability instanceof SpellAbility)) { + return; + } + Player player = game.getPlayer(controllerId); + if (player == null) { + return; + } + this.resetCosts(); + if (additionalCost == null) { + return; + } + if (additionalCost.canPay(ability, ability.getSourceId(), ability.getControllerId(), game) + && player.chooseUse(Outcome.Benefit, "Pay " + additionalCost.getText(false) + " ?", ability, game)) { - additionalCost.activate(); - ability.getModes().setAdditionalCost(this); - ability.getModes().setMinModes(2); - ability.getModes().setMaxModes(2); - } - } - } + additionalCost.activate(); + int modeCount = ability.getModes().size(); + ability.getModes().setAdditionalCost(this); + ability.getModes().setMinModes(modeCount); + ability.getModes().setMaxModes(modeCount); } } @Override public void addOptionalAdditionalModeCosts(Ability ability, Game game) { if (additionalCost.isActivated()) { - for (Iterator it = ((Costs) additionalCost).iterator(); it.hasNext();) { + for (Iterator it = ((Costs) additionalCost).iterator(); it.hasNext(); ) { Cost cost = (Cost) it.next(); if (cost instanceof ManaCostsImpl) { ability.getManaCostsToPay().add((ManaCostsImpl) cost.copy()); From 9a9b304fd593b16da40e26180fe24e39863ec8de Mon Sep 17 00:00:00 2001 From: Oleg Agafonov Date: Tue, 28 May 2019 13:46:29 +0400 Subject: [PATCH 34/38] * UI: improved hand request dialog (users can ask your hand once per game, reset it by re-activate button); --- .../java/mage/client/game/PlayAreaPanel.java | 63 +++++++------------ .../src/main/java/mage/view/UserDataView.java | 12 +--- .../java/mage/server/game/GameController.java | 4 +- .../java/org/mage/test/player/TestPlayer.java | 9 ++- .../java/org/mage/test/stub/PlayerStub.java | 7 ++- Mage/src/main/java/mage/players/Player.java | 4 +- .../main/java/mage/players/PlayerImpl.java | 10 ++- .../main/java/mage/players/net/UserData.java | 32 ++++++++-- 8 files changed, 82 insertions(+), 59 deletions(-) diff --git a/Mage.Client/src/main/java/mage/client/game/PlayAreaPanel.java b/Mage.Client/src/main/java/mage/client/game/PlayAreaPanel.java index b266d991c88..0243fa0d9a9 100644 --- a/Mage.Client/src/main/java/mage/client/game/PlayAreaPanel.java +++ b/Mage.Client/src/main/java/mage/client/game/PlayAreaPanel.java @@ -1,42 +1,27 @@ - package mage.client.game; -import java.awt.Color; -import java.awt.Dimension; -import java.awt.event.ActionListener; -import java.awt.event.KeyEvent; -import java.awt.event.MouseAdapter; -import java.awt.event.MouseEvent; -import java.awt.event.MouseListener; -import java.lang.reflect.Field; -import java.util.UUID; -import javax.swing.BorderFactory; -import javax.swing.GroupLayout; -import javax.swing.GroupLayout.Alignment; -import javax.swing.JCheckBoxMenuItem; -import javax.swing.JMenu; -import javax.swing.JMenuItem; -import javax.swing.JPopupMenu; -import javax.swing.LayoutStyle.ComponentPlacement; -import javax.swing.MenuSelectionManager; -import javax.swing.event.ChangeListener; - import mage.cards.decks.importer.DeckImporter; import mage.client.MageFrame; import mage.client.SessionHandler; import mage.client.cards.BigCard; import mage.client.dialog.PreferencesDialog; -import static mage.client.dialog.PreferencesDialog.KEY_GAME_ALLOW_REQUEST_SHOW_HAND_CARDS; -import static mage.client.dialog.PreferencesDialog.KEY_GAME_MANA_AUTOPAYMENT; -import static mage.client.dialog.PreferencesDialog.KEY_GAME_MANA_AUTOPAYMENT_ONLY_ONE; -import static mage.client.dialog.PreferencesDialog.KEY_USE_FIRST_MANA_ABILITY; import mage.client.util.GUISizeHelper; import mage.constants.PlayerAction; import mage.view.PlayerView; import mage.view.UserRequestMessage; +import javax.swing.*; +import javax.swing.GroupLayout.Alignment; +import javax.swing.LayoutStyle.ComponentPlacement; +import javax.swing.event.ChangeListener; +import java.awt.*; +import java.awt.event.*; +import java.lang.reflect.Field; +import java.util.UUID; + +import static mage.client.dialog.PreferencesDialog.*; + /** - * * @author BetaSteward_at_googlemail.com */ public class PlayAreaPanel extends javax.swing.JPanel { @@ -77,7 +62,7 @@ public class PlayAreaPanel extends javax.swing.JPanel { popupMenu = new JPopupMenu(); if (options.isPlayer) { - addPopupMenuPlayer(player.getUserData().isAllowRequestShowHandCards()); + addPopupMenuPlayer(player.getUserData().isAllowRequestHandToAll()); } else { addPopupMenuWatcher(); } @@ -331,12 +316,12 @@ public class PlayAreaPanel extends javax.swing.JPanel { // Request to see hand cards menuItem.addActionListener(e -> SessionHandler.sendPlayerAction(PlayerAction.REQUEST_PERMISSION_TO_SEE_HAND_CARDS, gameId, playerId)); } else { - allowViewHandCardsMenuItem = new JCheckBoxMenuItem("Allow requests to show from other users", allowRequestToShowHandCards); + allowViewHandCardsMenuItem = new JCheckBoxMenuItem("Allow hand requests from other users", allowRequestToShowHandCards); allowViewHandCardsMenuItem.setMnemonic(KeyEvent.VK_A); - allowViewHandCardsMenuItem.setToolTipText("If activated watchers or other players can request to see your hand cards. If you grant this to a user, it's valid for the complete match."); + allowViewHandCardsMenuItem.setToolTipText("Watchers or other players can request your hand cards once per game. Re-activate it to allow new requests."); handCardsMenu.add(allowViewHandCardsMenuItem); - // Requests allowed + // requests allowed (disable -> enable to reset requested list) allowViewHandCardsMenuItem.addActionListener(e -> { boolean requestsAllowed = ((JCheckBoxMenuItem) e.getSource()).getState(); PreferencesDialog.setPrefValue(KEY_GAME_ALLOW_REQUEST_SHOW_HAND_CARDS, requestsAllowed); @@ -451,13 +436,13 @@ public class PlayAreaPanel extends javax.swing.JPanel { } }); - + popupMenu.addSeparator(); - + menuItem = new JMenuItem("View current deck"); menuItem.setMnemonic(KeyEvent.VK_V); popupMenu.add(menuItem); - + // View limited deck menuItem.addActionListener(e -> { SessionHandler.sendPlayerAction(PlayerAction.VIEW_LIMITED_DECK, gameId, null); @@ -522,7 +507,7 @@ public class PlayAreaPanel extends javax.swing.JPanel { this.playerPanel.update(player); this.battlefieldPanel.update(player.getBattlefield()); if (this.allowViewHandCardsMenuItem != null) { - this.allowViewHandCardsMenuItem.setSelected(player.getUserData().isAllowRequestShowHandCards()); + this.allowViewHandCardsMenuItem.setSelected(player.getUserData().isAllowRequestHandToAll()); } } @@ -547,14 +532,14 @@ public class PlayAreaPanel extends javax.swing.JPanel { javax.swing.GroupLayout layout = new javax.swing.GroupLayout(this); layout.setHorizontalGroup( layout.createSequentialGroup() - .addComponent(playerPanel, GroupLayout.PREFERRED_SIZE, GroupLayout.DEFAULT_SIZE, GroupLayout.PREFERRED_SIZE) - .addPreferredGap(ComponentPlacement.RELATED) - .addComponent(battlefieldPanel, 0, GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) + .addComponent(playerPanel, GroupLayout.PREFERRED_SIZE, GroupLayout.DEFAULT_SIZE, GroupLayout.PREFERRED_SIZE) + .addPreferredGap(ComponentPlacement.RELATED) + .addComponent(battlefieldPanel, 0, GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) ); layout.setVerticalGroup( layout.createParallelGroup(Alignment.LEADING) - .addComponent(playerPanel, GroupLayout.PREFERRED_SIZE, GroupLayout.DEFAULT_SIZE, GroupLayout.PREFERRED_SIZE) - .addComponent(battlefieldPanel, GroupLayout.DEFAULT_SIZE, 160, Short.MAX_VALUE) + .addComponent(playerPanel, GroupLayout.PREFERRED_SIZE, GroupLayout.DEFAULT_SIZE, GroupLayout.PREFERRED_SIZE) + .addComponent(battlefieldPanel, GroupLayout.DEFAULT_SIZE, 160, Short.MAX_VALUE) ); this.setLayout(layout); } diff --git a/Mage.Common/src/main/java/mage/view/UserDataView.java b/Mage.Common/src/main/java/mage/view/UserDataView.java index 3e8b222d2b2..23dd025db9e 100644 --- a/Mage.Common/src/main/java/mage/view/UserDataView.java +++ b/Mage.Common/src/main/java/mage/view/UserDataView.java @@ -1,9 +1,10 @@ package mage.view; -import java.io.Serializable; import mage.players.net.UserData; import mage.players.net.UserSkipPrioritySteps; +import java.io.Serializable; + /** * Transfer object for {@link mage.players.net.UserData} * @@ -14,7 +15,6 @@ public class UserDataView implements Serializable { protected int avatarId; protected int userGroup; protected boolean showAbilityPickerForced; - protected boolean allowRequestShowHandCards; protected boolean confirmEmptyManaPool; protected UserSkipPrioritySteps userSkipPrioritySteps; String flagName; @@ -29,10 +29,9 @@ public class UserDataView implements Serializable { } public UserDataView(int avatarId, boolean showAbilityPickerForced, boolean allowRequestShowHandCards, - boolean confirmEmptyManaPool, UserSkipPrioritySteps userSkipPrioritySteps, String flagName, boolean askMoveToGraveOrder) { + boolean confirmEmptyManaPool, UserSkipPrioritySteps userSkipPrioritySteps, String flagName, boolean askMoveToGraveOrder) { this.avatarId = avatarId; this.showAbilityPickerForced = showAbilityPickerForced; - this.allowRequestShowHandCards = allowRequestShowHandCards; this.userSkipPrioritySteps = userSkipPrioritySteps; this.confirmEmptyManaPool = confirmEmptyManaPool; this.flagName = flagName; @@ -43,7 +42,6 @@ public class UserDataView implements Serializable { public UserDataView(UserData userData) { this.avatarId = userData.getAvatarId(); this.userGroup = userData.getGroupId(); - this.allowRequestShowHandCards = userData.isAllowRequestShowHandCards(); this.showAbilityPickerForced = userData.isShowAbilityPickerForced(); this.userSkipPrioritySteps = userData.getUserSkipPrioritySteps(); this.confirmEmptyManaPool = userData.confirmEmptyManaPool(); @@ -59,10 +57,6 @@ public class UserDataView implements Serializable { return showAbilityPickerForced; } - public boolean allowRequestShowHandCards() { - return allowRequestShowHandCards; - } - public UserSkipPrioritySteps getUserSkipPrioritySteps() { return userSkipPrioritySteps; } diff --git a/Mage.Server/src/main/java/mage/server/game/GameController.java b/Mage.Server/src/main/java/mage/server/game/GameController.java index 8ec068a48e5..3aaed581430 100644 --- a/Mage.Server/src/main/java/mage/server/game/GameController.java +++ b/Mage.Server/src/main/java/mage/server/game/GameController.java @@ -596,7 +596,9 @@ public class GameController implements GameCallback { if (gameSession != null) { UUID requestingPlayerId = getPlayerId(userIdRequester); if (requestingPlayerId == null || !requestingPlayerId.equals(grantingPlayer.getId())) { // don't allow request for your own cards - if (grantingPlayer.isRequestToShowHandCardsAllowed()) { + if (grantingPlayer.isPlayerAllowedToRequestHand(game.getId(), requestingPlayerId)) { + // one time request per user restrict, enable request will reset users list and allows again + grantingPlayer.addPlayerToRequestedHandList(game.getId(), requestingPlayerId); gameSession.requestPermissionToSeeHandCards(userIdRequester); } else { // player does not allow the request diff --git a/Mage.Tests/src/test/java/org/mage/test/player/TestPlayer.java b/Mage.Tests/src/test/java/org/mage/test/player/TestPlayer.java index 2f11fbd5307..f01b2856551 100644 --- a/Mage.Tests/src/test/java/org/mage/test/player/TestPlayer.java +++ b/Mage.Tests/src/test/java/org/mage/test/player/TestPlayer.java @@ -3077,8 +3077,13 @@ public class TestPlayer implements Player { } @Override - public boolean isRequestToShowHandCardsAllowed() { - return computerPlayer.isRequestToShowHandCardsAllowed(); + public boolean isPlayerAllowedToRequestHand(UUID gameId, UUID requesterPlayerId) { + return computerPlayer.isPlayerAllowedToRequestHand(gameId, requesterPlayerId); + } + + @Override + public void addPlayerToRequestedHandList(UUID gameId, UUID requesterPlayerId) { + computerPlayer.addPlayerToRequestedHandList(gameId, requesterPlayerId); } @Override diff --git a/Mage.Tests/src/test/java/org/mage/test/stub/PlayerStub.java b/Mage.Tests/src/test/java/org/mage/test/stub/PlayerStub.java index 6fe462512fe..ef25e0469b9 100644 --- a/Mage.Tests/src/test/java/org/mage/test/stub/PlayerStub.java +++ b/Mage.Tests/src/test/java/org/mage/test/stub/PlayerStub.java @@ -1242,10 +1242,15 @@ public class PlayerStub implements Player { } @Override - public boolean isRequestToShowHandCardsAllowed() { + public boolean isPlayerAllowedToRequestHand(UUID gameId, UUID requesterPlayerId) { return false; } + @Override + public void addPlayerToRequestedHandList(UUID gameId, UUID requesterPlayerId) { + // + } + @Override public Set getUsersAllowedToSeeHandCards() { return null; diff --git a/Mage/src/main/java/mage/players/Player.java b/Mage/src/main/java/mage/players/Player.java index bef24d471ef..d6f8bb8bfc2 100644 --- a/Mage/src/main/java/mage/players/Player.java +++ b/Mage/src/main/java/mage/players/Player.java @@ -855,7 +855,9 @@ public interface Player extends MageItem, Copyable { void revokePermissionToSeeHandCards(); - boolean isRequestToShowHandCardsAllowed(); + boolean isPlayerAllowedToRequestHand(UUID gameId, UUID requesterPlayerId); + + void addPlayerToRequestedHandList(UUID gameId, UUID requesterPlayerId); Set getUsersAllowedToSeeHandCards(); diff --git a/Mage/src/main/java/mage/players/PlayerImpl.java b/Mage/src/main/java/mage/players/PlayerImpl.java index 569f68e1811..6dd3cbbe366 100644 --- a/Mage/src/main/java/mage/players/PlayerImpl.java +++ b/Mage/src/main/java/mage/players/PlayerImpl.java @@ -2284,6 +2284,7 @@ public abstract class PlayerImpl implements Player, Serializable { break; case PERMISSION_REQUESTS_ALLOWED_ON: userData.setAllowRequestShowHandCards(true); + userData.resetRequestedHandPlayersList(game.getId()); // users can send request again break; } logger.trace("PASS Priority: " + playerAction.toString()); @@ -3969,8 +3970,13 @@ public abstract class PlayerImpl implements Player, Serializable { } @Override - public boolean isRequestToShowHandCardsAllowed() { - return userData.isAllowRequestShowHandCards(); + public boolean isPlayerAllowedToRequestHand(UUID gameId, UUID requesterPlayerId) { + return userData.isAllowRequestHandToPlayer(gameId, requesterPlayerId); + } + + @Override + public void addPlayerToRequestedHandList(UUID gameId, UUID requesterPlayerId) { + userData.addPlayerToRequestedHandList(gameId, requesterPlayerId); } @Override diff --git a/Mage/src/main/java/mage/players/net/UserData.java b/Mage/src/main/java/mage/players/net/UserData.java index fec7fbcba2c..06f2aff9224 100644 --- a/Mage/src/main/java/mage/players/net/UserData.java +++ b/Mage/src/main/java/mage/players/net/UserData.java @@ -1,6 +1,7 @@ package mage.players.net; import java.io.Serializable; +import java.util.*; /** * User data that is passed during connection to the server. @@ -24,6 +25,7 @@ public class UserData implements Serializable { protected boolean autoOrderTrigger; protected boolean useFirstManaAbility = false; private String userIdStr; + protected Map> requestedHandPlayersList; // game -> players list protected String matchHistory; protected int matchQuitRatio; @@ -35,9 +37,9 @@ public class UserData implements Serializable { private int limitedRating; public UserData(UserGroup userGroup, int avatarId, boolean showAbilityPickerForced, - boolean allowRequestShowHandCards, boolean confirmEmptyManaPool, UserSkipPrioritySteps userSkipPrioritySteps, - String flagName, boolean askMoveToGraveOrder, boolean manaPoolAutomatic, boolean manaPoolAutomaticRestricted, - boolean passPriorityCast, boolean passPriorityActivation, boolean autoOrderTrigger, boolean useFirstManaAbility, String userIdStr) { + boolean allowRequestShowHandCards, boolean confirmEmptyManaPool, UserSkipPrioritySteps userSkipPrioritySteps, + String flagName, boolean askMoveToGraveOrder, boolean manaPoolAutomatic, boolean manaPoolAutomaticRestricted, + boolean passPriorityCast, boolean passPriorityActivation, boolean autoOrderTrigger, boolean useFirstManaAbility, String userIdStr) { this.groupId = userGroup.getGroupId(); this.avatarId = avatarId; this.showAbilityPickerForced = showAbilityPickerForced; @@ -57,6 +59,7 @@ public class UserData implements Serializable { this.tourneyHistory = ""; this.tourneyQuitRatio = 0; this.userIdStr = userIdStr; + this.requestedHandPlayersList = new HashMap<>(); } public void update(UserData userData) { @@ -106,14 +109,35 @@ public class UserData implements Serializable { this.showAbilityPickerForced = showAbilityPickerForced; } - public boolean isAllowRequestShowHandCards() { + public boolean isAllowRequestHandToAll() { return allowRequestShowHandCards; } + public boolean isAllowRequestHandToPlayer(UUID gameId, UUID requesterPlayerId) { + // once per game + boolean allowToPlayer = true; + if (requestedHandPlayersList.containsKey(gameId) && requestedHandPlayersList.get(gameId).contains(requesterPlayerId)) { + allowToPlayer = false; + } + return isAllowRequestHandToAll() && allowToPlayer; + } + + public void addPlayerToRequestedHandList(UUID gameId, UUID requesterPlayerId) { + if (!requestedHandPlayersList.containsKey(gameId)) { + requestedHandPlayersList.put(gameId, new HashSet<>()); + } + Set requestedPlayers = requestedHandPlayersList.get(gameId); + requestedPlayers.add(requesterPlayerId); + } + public void setAllowRequestShowHandCards(boolean allowRequestShowHandCards) { this.allowRequestShowHandCards = allowRequestShowHandCards; } + public void resetRequestedHandPlayersList(UUID gameId) { + this.requestedHandPlayersList.remove(gameId); + } + public UserSkipPrioritySteps getUserSkipPrioritySteps() { return userSkipPrioritySteps; } From 37f7c8b4255c9cae5f6534f6b3ea260a9aa44e28 Mon Sep 17 00:00:00 2001 From: Evan Kranzler Date: Tue, 28 May 2019 08:00:27 -0400 Subject: [PATCH 35/38] updated MH1 spoiler --- Utils/mtg-cards-data.txt | 2 ++ 1 file changed, 2 insertions(+) diff --git a/Utils/mtg-cards-data.txt b/Utils/mtg-cards-data.txt index 192407b4ccb..50af935a091 100644 --- a/Utils/mtg-cards-data.txt +++ b/Utils/mtg-cards-data.txt @@ -35187,6 +35187,7 @@ Seasoned Pyromancer|Modern Horizons|145|M|{1}{R}{R}|Creature - Human Shaman|2|2| Ayula, Queen Among Bears|Modern Horizons|155|R|{1}{G}|Legendary Creature - Bear|2|2|Whenever another Bear enters the battlefield under your control, choose one —$• Put two +1/+1 counters on target Bear.$• Target Bear you control fights target creature you don't control.| Ayula's Influence|Modern Horizons|156|R|{G}{G}{G}|Enchantment|||Discard a land card: Create a 2/2 green Bear creature token.| Collector Ouphe|Modern Horizons|158|R|{1}{G}|Creature - Ouphe|2|2|Activated abilities of artifacts can't be activated.| +Crashing Footfalls|Modern Horizons|160|R||Sorcery|||Suspend 4—{G}$Create two 4/4 green Rhino creature tokens with trample.| Deep Forest Hermit|Modern Horizons|161|R|{3}{G}{G}|Creature - Elf Druid|1|1|Vanishing 3$When Deep Forest Hermit enters the battlefield, create four 1/1 green Squirrel creature tokens.$Squirrels you control get +1/+1.| Elvish Fury|Modern Horizons|162|C|{G}|Instant|||Buyback {4}$Target creature gets +2/+2 until end of turn.| Force of Vigor|Modern Horizons|164|R|{2}{G}{G}|Instant|||If it's not your turn, you may exile a green card from your hand rather than pay this spell's mana cost.$Destroy up to two target artifacts and/or enchantments.| @@ -35225,6 +35226,7 @@ Nature's Chant|Modern Horizons|210|C|{1}{G/W}|Instant|||Destroy target artifact Thundering Djinn|Modern Horizons|215|U|{3}{U}{R}|Creature - Djinn|3|4|Flying$Whenever Thundering Djinn attacks, it deals damage to any target equal to the number of cards you've drawn this turn.| Wrenn and Six|Modern Horizons|217|M|{R}{G}|Legendary Planeswalker - Wrenn|3|+1: Return up to one target land card from your graveyard to your hand.$-1: Wrenn and Six deals 1 damage to any target.$-7: You get an emblem with "Instant and sorcery cards in your graveyard have retrace."| Altar of Dementia|Modern Horizons|218|R|{2}|Artifact|||Sacrifice a creature: Target player puts a number of cards equal to the sacrificed creature's power from the top of their library into their graveyard.| +Arcum's Astrolabe|Modern Horizons|220|C|{S}|Snow Artifact|||({S} can be paid with one mana from a snow permanent.)$When Arcum's Astrolabe enters the battlefield, draw a card.${1}, {T}: Add one mana of any color.| Farmstead Gleaner|Modern Horizons|222|U|{3}|Artifact Creature - Scarecrow|2|2|Farmstead Gleaner doesn't untap during your untap step.${2}, {Q}: Put a +1/+1 counter on Farmstead Gleaner.| Lesser Masticore|Modern Horizons|225|U|{2}|Artifact Creature - Masticore|2|2|As an additional cost to cast this spell, discard a card.${4}: Lesser Masticore deals 1 damage to target creature.$Persist| Mox Tantalite|Modern Horizons|226|M||Artifact|||Suspend 3—{0}${T}: Add one mana of any color.| From b41745ef9f6b24fd3b6f6485ed0886930d00507d Mon Sep 17 00:00:00 2001 From: Evan Kranzler Date: Tue, 28 May 2019 08:03:18 -0400 Subject: [PATCH 36/38] Implemented Arcum's Astrolabe --- .../src/mage/cards/a/ArcumsAstrolabe.java | 50 +++++++++++++++++++ Mage.Sets/src/mage/sets/ModernHorizons.java | 1 + 2 files changed, 51 insertions(+) create mode 100644 Mage.Sets/src/mage/cards/a/ArcumsAstrolabe.java diff --git a/Mage.Sets/src/mage/cards/a/ArcumsAstrolabe.java b/Mage.Sets/src/mage/cards/a/ArcumsAstrolabe.java new file mode 100644 index 00000000000..9e4a487f5d2 --- /dev/null +++ b/Mage.Sets/src/mage/cards/a/ArcumsAstrolabe.java @@ -0,0 +1,50 @@ +package mage.cards.a; + +import mage.abilities.Ability; +import mage.abilities.common.EntersBattlefieldTriggeredAbility; +import mage.abilities.common.SimpleStaticAbility; +import mage.abilities.costs.common.TapSourceCost; +import mage.abilities.costs.mana.GenericManaCost; +import mage.abilities.effects.common.DrawCardSourceControllerEffect; +import mage.abilities.effects.common.InfoEffect; +import mage.abilities.mana.AnyColorManaAbility; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.SuperType; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class ArcumsAstrolabe extends CardImpl { + + public ArcumsAstrolabe(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.ARTIFACT}, "{S}"); + + this.addSuperType(SuperType.SNOW); + + // ({S} can be paid with one mana from a snow permanent.) + this.addAbility(new SimpleStaticAbility( + new InfoEffect("({S} can be paid with one mana from a snow permanent.)") + )); + + // When Arcum's Astrolabe enters the battlefield, draw a card. + this.addAbility(new EntersBattlefieldTriggeredAbility(new DrawCardSourceControllerEffect(1))); + + // {1}, {T}: Add one mana of any color. + Ability ability = new AnyColorManaAbility(new GenericManaCost(1)); + ability.addCost(new TapSourceCost()); + this.addAbility(ability); + } + + private ArcumsAstrolabe(final ArcumsAstrolabe card) { + super(card); + } + + @Override + public ArcumsAstrolabe copy() { + return new ArcumsAstrolabe(this); + } +} diff --git a/Mage.Sets/src/mage/sets/ModernHorizons.java b/Mage.Sets/src/mage/sets/ModernHorizons.java index f794e50eb96..933740cd286 100644 --- a/Mage.Sets/src/mage/sets/ModernHorizons.java +++ b/Mage.Sets/src/mage/sets/ModernHorizons.java @@ -29,6 +29,7 @@ public final class ModernHorizons extends ExpansionSet { cards.add(new SetCardInfo("Abominable Treefolk", 194, Rarity.UNCOMMON, mage.cards.a.AbominableTreefolk.class)); cards.add(new SetCardInfo("Altar of Dementia", 218, Rarity.RARE, mage.cards.a.AltarOfDementia.class)); cards.add(new SetCardInfo("Archmage's Charm", 40, Rarity.RARE, mage.cards.a.ArchmagesCharm.class)); + cards.add(new SetCardInfo("Arcum's Astrolabe", 220, Rarity.COMMON, mage.cards.a.ArcumsAstrolabe.class)); cards.add(new SetCardInfo("Aria of Flame", 118, Rarity.RARE, mage.cards.a.AriaOfFlame.class)); cards.add(new SetCardInfo("Astral Drift", 3, Rarity.RARE, mage.cards.a.AstralDrift.class)); cards.add(new SetCardInfo("Ayula's Influence", 156, Rarity.RARE, mage.cards.a.AyulasInfluence.class)); From a7d86c6c09c5f934afdf52c617cbb9474b530fdb Mon Sep 17 00:00:00 2001 From: Evan Kranzler Date: Tue, 28 May 2019 08:05:44 -0400 Subject: [PATCH 37/38] Implemented Crashing Footfalls --- .../src/mage/cards/c/CrashingFootfalls.java | 37 +++++++++++++++++++ Mage.Sets/src/mage/sets/ModernHorizons.java | 1 + 2 files changed, 38 insertions(+) create mode 100644 Mage.Sets/src/mage/cards/c/CrashingFootfalls.java diff --git a/Mage.Sets/src/mage/cards/c/CrashingFootfalls.java b/Mage.Sets/src/mage/cards/c/CrashingFootfalls.java new file mode 100644 index 00000000000..d520e84462c --- /dev/null +++ b/Mage.Sets/src/mage/cards/c/CrashingFootfalls.java @@ -0,0 +1,37 @@ +package mage.cards.c; + +import mage.abilities.costs.mana.ManaCostsImpl; +import mage.abilities.effects.common.CreateTokenEffect; +import mage.abilities.keyword.SuspendAbility; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.game.permanent.token.RhinoToken; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class CrashingFootfalls extends CardImpl { + + public CrashingFootfalls(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.SORCERY}, ""); + this.color.setGreen(true); + + // Suspend 4—{G} + this.addAbility(new SuspendAbility(4, new ManaCostsImpl("{G}"), this)); + + // Create two 4/4 green Rhino creature tokens with trample. + this.getSpellAbility().addEffect(new CreateTokenEffect(new RhinoToken(), 2)); + } + + private CrashingFootfalls(final CrashingFootfalls card) { + super(card); + } + + @Override + public CrashingFootfalls copy() { + return new CrashingFootfalls(this); + } +} diff --git a/Mage.Sets/src/mage/sets/ModernHorizons.java b/Mage.Sets/src/mage/sets/ModernHorizons.java index 933740cd286..5dc325f72f5 100644 --- a/Mage.Sets/src/mage/sets/ModernHorizons.java +++ b/Mage.Sets/src/mage/sets/ModernHorizons.java @@ -44,6 +44,7 @@ public final class ModernHorizons extends ExpansionSet { cards.add(new SetCardInfo("Cloudshredder Sliver", 195, Rarity.RARE, mage.cards.c.CloudshredderSliver.class)); cards.add(new SetCardInfo("Collected Conjuring", 196, Rarity.RARE, mage.cards.c.CollectedConjuring.class)); cards.add(new SetCardInfo("Collector Ouphe", 158, Rarity.RARE, mage.cards.c.CollectorOuphe.class)); + cards.add(new SetCardInfo("Crashing Footfalls", 160, Rarity.RARE, mage.cards.c.CrashingFootfalls.class)); cards.add(new SetCardInfo("Crypt Rats", 84, Rarity.UNCOMMON, mage.cards.c.CryptRats.class)); cards.add(new SetCardInfo("Deep Forest Hermit", 161, Rarity.RARE, mage.cards.d.DeepForestHermit.class)); cards.add(new SetCardInfo("Diabolic Edict", 87, Rarity.COMMON, mage.cards.d.DiabolicEdict.class)); From 7154e685d1addf8cae57cadbb6fe14c743f39d86 Mon Sep 17 00:00:00 2001 From: Oleg Agafonov Date: Tue, 28 May 2019 16:37:21 +0400 Subject: [PATCH 38/38] * Fixed Zendikar lands download from scryfall --- .../src/mage/sets/BattleForZendikar.java | 71 +++++++------- Mage.Sets/src/mage/sets/Zendikar.java | 96 +++++++++---------- .../main/java/mage/cards/ExpansionSet.java | 2 +- 3 files changed, 82 insertions(+), 87 deletions(-) diff --git a/Mage.Sets/src/mage/sets/BattleForZendikar.java b/Mage.Sets/src/mage/sets/BattleForZendikar.java index 79ce230f3dd..ff90d62d61f 100644 --- a/Mage.Sets/src/mage/sets/BattleForZendikar.java +++ b/Mage.Sets/src/mage/sets/BattleForZendikar.java @@ -1,4 +1,3 @@ - package mage.sets; import mage.cards.ExpansionSet; @@ -36,6 +35,7 @@ public final class BattleForZendikar extends ExpansionSet { this.ratioBoosterMythic = 8; this.numBoosterSpecial = 0; this.ratioBoosterSpecialLand = 144; + cards.add(new SetCardInfo("Adverse Conditions", 54, Rarity.UNCOMMON, mage.cards.a.AdverseConditions.class)); cards.add(new SetCardInfo("Akoum Firebird", 138, Rarity.MYTHIC, mage.cards.a.AkoumFirebird.class)); cards.add(new SetCardInfo("Akoum Hellkite", 139, Rarity.RARE, mage.cards.a.AkoumHellkite.class)); @@ -43,21 +43,21 @@ public final class BattleForZendikar extends ExpansionSet { cards.add(new SetCardInfo("Aligned Hedron Network", 222, Rarity.RARE, mage.cards.a.AlignedHedronNetwork.class)); cards.add(new SetCardInfo("Ally Encampment", 228, Rarity.RARE, mage.cards.a.AllyEncampment.class)); cards.add(new SetCardInfo("Altar's Reap", 103, Rarity.COMMON, mage.cards.a.AltarsReap.class)); + cards.add(new SetCardInfo("Angel of Renewal", 18, Rarity.UNCOMMON, mage.cards.a.AngelOfRenewal.class)); cards.add(new SetCardInfo("Angelic Captain", 208, Rarity.RARE, mage.cards.a.AngelicCaptain.class)); cards.add(new SetCardInfo("Angelic Gift", 19, Rarity.COMMON, mage.cards.a.AngelicGift.class)); - cards.add(new SetCardInfo("Angel of Renewal", 18, Rarity.UNCOMMON, mage.cards.a.AngelOfRenewal.class)); cards.add(new SetCardInfo("Anticipate", 69, Rarity.COMMON, mage.cards.a.Anticipate.class)); cards.add(new SetCardInfo("Bane of Bala Ged", 1, Rarity.UNCOMMON, mage.cards.b.BaneOfBalaGed.class)); cards.add(new SetCardInfo("Barrage Tyrant", 127, Rarity.RARE, mage.cards.b.BarrageTyrant.class)); cards.add(new SetCardInfo("Beastcaller Savant", 170, Rarity.RARE, mage.cards.b.BeastcallerSavant.class)); cards.add(new SetCardInfo("Belligerent Whiptail", 141, Rarity.COMMON, mage.cards.b.BelligerentWhiptail.class)); cards.add(new SetCardInfo("Benthic Infiltrator", 55, Rarity.COMMON, mage.cards.b.BenthicInfiltrator.class)); + cards.add(new SetCardInfo("Blight Herder", 2, Rarity.RARE, mage.cards.b.BlightHerder.class)); cards.add(new SetCardInfo("Blighted Cataract", 229, Rarity.UNCOMMON, mage.cards.b.BlightedCataract.class)); cards.add(new SetCardInfo("Blighted Fen", 230, Rarity.UNCOMMON, mage.cards.b.BlightedFen.class)); cards.add(new SetCardInfo("Blighted Gorge", 231, Rarity.UNCOMMON, mage.cards.b.BlightedGorge.class)); cards.add(new SetCardInfo("Blighted Steppe", 232, Rarity.UNCOMMON, mage.cards.b.BlightedSteppe.class)); cards.add(new SetCardInfo("Blighted Woodland", 233, Rarity.UNCOMMON, mage.cards.b.BlightedWoodland.class)); - cards.add(new SetCardInfo("Blight Herder", 2, Rarity.RARE, mage.cards.b.BlightHerder.class)); cards.add(new SetCardInfo("Blisterpod", 163, Rarity.COMMON, mage.cards.b.Blisterpod.class)); cards.add(new SetCardInfo("Bloodbond Vampire", 104, Rarity.UNCOMMON, mage.cards.b.BloodbondVampire.class)); cards.add(new SetCardInfo("Boiling Earth", 142, Rarity.COMMON, mage.cards.b.BoilingEarth.class)); @@ -66,8 +66,8 @@ public final class BattleForZendikar extends ExpansionSet { cards.add(new SetCardInfo("Brilliant Spectrum", 70, Rarity.COMMON, mage.cards.b.BrilliantSpectrum.class)); cards.add(new SetCardInfo("Bring to Light", 209, Rarity.RARE, mage.cards.b.BringToLight.class)); cards.add(new SetCardInfo("Brood Butcher", 199, Rarity.RARE, mage.cards.b.BroodButcher.class)); - cards.add(new SetCardInfo("Broodhunter Wurm", 171, Rarity.COMMON, mage.cards.b.BroodhunterWurm.class)); cards.add(new SetCardInfo("Brood Monitor", 164, Rarity.UNCOMMON, mage.cards.b.BroodMonitor.class)); + cards.add(new SetCardInfo("Broodhunter Wurm", 171, Rarity.COMMON, mage.cards.b.BroodhunterWurm.class)); cards.add(new SetCardInfo("Brutal Expulsion", 200, Rarity.RARE, mage.cards.b.BrutalExpulsion.class)); cards.add(new SetCardInfo("Call the Scions", 165, Rarity.COMMON, mage.cards.c.CallTheScions.class)); cards.add(new SetCardInfo("Canopy Vista", 234, Rarity.RARE, mage.cards.c.CanopyVista.class)); @@ -94,8 +94,8 @@ public final class BattleForZendikar extends ExpansionSet { cards.add(new SetCardInfo("Dispel", 76, Rarity.COMMON, mage.cards.d.Dispel.class)); cards.add(new SetCardInfo("Dominator Drone", 92, Rarity.COMMON, mage.cards.d.DominatorDrone.class)); cards.add(new SetCardInfo("Dragonmaster Outcast", 144, Rarity.MYTHIC, mage.cards.d.DragonmasterOutcast.class)); - cards.add(new SetCardInfo("Drana, Liberator of Malakir", 109, Rarity.MYTHIC, mage.cards.d.DranaLiberatorOfMalakir.class)); cards.add(new SetCardInfo("Drana's Emissary", 210, Rarity.UNCOMMON, mage.cards.d.DranasEmissary.class)); + cards.add(new SetCardInfo("Drana, Liberator of Malakir", 109, Rarity.MYTHIC, mage.cards.d.DranaLiberatorOfMalakir.class)); cards.add(new SetCardInfo("Drowner of Hope", 57, Rarity.RARE, mage.cards.d.DrownerOfHope.class)); cards.add(new SetCardInfo("Dust Stalker", 202, Rarity.RARE, mage.cards.d.DustStalker.class)); cards.add(new SetCardInfo("Dutiful Return", 110, Rarity.COMMON, mage.cards.d.DutifulReturn.class)); @@ -116,22 +116,22 @@ public final class BattleForZendikar extends ExpansionSet { cards.add(new SetCardInfo("Firemantle Mage", 145, Rarity.UNCOMMON, mage.cards.f.FiremantleMage.class)); cards.add(new SetCardInfo("Forerunner of Slaughter", 204, Rarity.UNCOMMON, mage.cards.f.ForerunnerOfSlaughter.class)); cards.add(new SetCardInfo("Forest", "270a", Rarity.LAND, mage.cards.basiclands.Forest.class, NON_FULL_USE_VARIOUS)); - cards.add(new SetCardInfo("Forest", "274b", Rarity.LAND, mage.cards.basiclands.Forest.class, FULL_ART_BFZ_VARIOUS)); cards.add(new SetCardInfo("Forest", "271a", Rarity.LAND, mage.cards.basiclands.Forest.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Forest", "272a", Rarity.LAND, mage.cards.basiclands.Forest.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Forest", "273a", Rarity.LAND, mage.cards.basiclands.Forest.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Forest", "274a", Rarity.LAND, mage.cards.basiclands.Forest.class, NON_FULL_USE_VARIOUS)); - cards.add(new SetCardInfo("Forest", "270b", Rarity.LAND, mage.cards.basiclands.Forest.class, FULL_ART_BFZ_VARIOUS)); - cards.add(new SetCardInfo("Forest", "271b", Rarity.LAND, mage.cards.basiclands.Forest.class, FULL_ART_BFZ_VARIOUS)); - cards.add(new SetCardInfo("Forest", "272b", Rarity.LAND, mage.cards.basiclands.Forest.class, FULL_ART_BFZ_VARIOUS)); - cards.add(new SetCardInfo("Forest", "273b", Rarity.LAND, mage.cards.basiclands.Forest.class, FULL_ART_BFZ_VARIOUS)); + cards.add(new SetCardInfo("Forest", 270, Rarity.LAND, mage.cards.basiclands.Forest.class, FULL_ART_BFZ_VARIOUS)); + cards.add(new SetCardInfo("Forest", 271, Rarity.LAND, mage.cards.basiclands.Forest.class, FULL_ART_BFZ_VARIOUS)); + cards.add(new SetCardInfo("Forest", 272, Rarity.LAND, mage.cards.basiclands.Forest.class, FULL_ART_BFZ_VARIOUS)); + cards.add(new SetCardInfo("Forest", 273, Rarity.LAND, mage.cards.basiclands.Forest.class, FULL_ART_BFZ_VARIOUS)); + cards.add(new SetCardInfo("Forest", 274, Rarity.LAND, mage.cards.basiclands.Forest.class, FULL_ART_BFZ_VARIOUS)); cards.add(new SetCardInfo("Fortified Rampart", 27, Rarity.COMMON, mage.cards.f.FortifiedRampart.class)); cards.add(new SetCardInfo("From Beyond", 167, Rarity.RARE, mage.cards.f.FromBeyond.class)); cards.add(new SetCardInfo("Geyserfield Stalker", 111, Rarity.COMMON, mage.cards.g.GeyserfieldStalker.class)); cards.add(new SetCardInfo("Ghostly Sentinel", 28, Rarity.COMMON, mage.cards.g.GhostlySentinel.class)); cards.add(new SetCardInfo("Giant Mantis", 173, Rarity.COMMON, mage.cards.g.GiantMantis.class)); - cards.add(new SetCardInfo("Gideon, Ally of Zendikar", 29, Rarity.MYTHIC, mage.cards.g.GideonAllyOfZendikar.class)); cards.add(new SetCardInfo("Gideon's Reproach", 30, Rarity.COMMON, mage.cards.g.GideonsReproach.class)); + cards.add(new SetCardInfo("Gideon, Ally of Zendikar", 29, Rarity.MYTHIC, mage.cards.g.GideonAllyOfZendikar.class)); cards.add(new SetCardInfo("Goblin War Paint", 146, Rarity.COMMON, mage.cards.g.GoblinWarPaint.class)); cards.add(new SetCardInfo("Grave Birthing", 93, Rarity.COMMON, mage.cards.g.GraveBirthing.class)); cards.add(new SetCardInfo("Greenwarden of Murasa", 174, Rarity.MYTHIC, mage.cards.g.GreenwardenOfMurasa.class)); @@ -152,15 +152,15 @@ public final class BattleForZendikar extends ExpansionSet { cards.add(new SetCardInfo("Infuse with the Elements", 175, Rarity.UNCOMMON, mage.cards.i.InfuseWithTheElements.class)); cards.add(new SetCardInfo("Inspired Charge", 32, Rarity.COMMON, mage.cards.i.InspiredCharge.class)); cards.add(new SetCardInfo("Island", "255a", Rarity.LAND, mage.cards.basiclands.Island.class, NON_FULL_USE_VARIOUS)); - cards.add(new SetCardInfo("Island", "259b", Rarity.LAND, mage.cards.basiclands.Island.class, FULL_ART_BFZ_VARIOUS)); cards.add(new SetCardInfo("Island", "256a", Rarity.LAND, mage.cards.basiclands.Island.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Island", "257a", Rarity.LAND, mage.cards.basiclands.Island.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Island", "258a", Rarity.LAND, mage.cards.basiclands.Island.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Island", "259a", Rarity.LAND, mage.cards.basiclands.Island.class, NON_FULL_USE_VARIOUS)); - cards.add(new SetCardInfo("Island", "255b", Rarity.LAND, mage.cards.basiclands.Island.class, FULL_ART_BFZ_VARIOUS)); - cards.add(new SetCardInfo("Island", "256b", Rarity.LAND, mage.cards.basiclands.Island.class, FULL_ART_BFZ_VARIOUS)); - cards.add(new SetCardInfo("Island", "257b", Rarity.LAND, mage.cards.basiclands.Island.class, FULL_ART_BFZ_VARIOUS)); - cards.add(new SetCardInfo("Island", "258b", Rarity.LAND, mage.cards.basiclands.Island.class, FULL_ART_BFZ_VARIOUS)); + cards.add(new SetCardInfo("Island", 255, Rarity.LAND, mage.cards.basiclands.Island.class, FULL_ART_BFZ_VARIOUS)); + cards.add(new SetCardInfo("Island", 256, Rarity.LAND, mage.cards.basiclands.Island.class, FULL_ART_BFZ_VARIOUS)); + cards.add(new SetCardInfo("Island", 257, Rarity.LAND, mage.cards.basiclands.Island.class, FULL_ART_BFZ_VARIOUS)); + cards.add(new SetCardInfo("Island", 258, Rarity.LAND, mage.cards.basiclands.Island.class, FULL_ART_BFZ_VARIOUS)); + cards.add(new SetCardInfo("Island", 259, Rarity.LAND, mage.cards.basiclands.Island.class, FULL_ART_BFZ_VARIOUS)); cards.add(new SetCardInfo("Jaddi Offshoot", 176, Rarity.UNCOMMON, mage.cards.j.JaddiOffshoot.class)); cards.add(new SetCardInfo("Kalastria Healer", 114, Rarity.COMMON, mage.cards.k.KalastriaHealer.class)); cards.add(new SetCardInfo("Kalastria Nightwatch", 115, Rarity.COMMON, mage.cards.k.KalastriaNightwatch.class)); @@ -187,16 +187,15 @@ public final class BattleForZendikar extends ExpansionSet { cards.add(new SetCardInfo("Molten Nursery", 130, Rarity.UNCOMMON, mage.cards.m.MoltenNursery.class)); cards.add(new SetCardInfo("Mortuary Mire", 240, Rarity.COMMON, mage.cards.m.MortuaryMire.class)); cards.add(new SetCardInfo("Mountain", "265a", Rarity.LAND, mage.cards.basiclands.Mountain.class, NON_FULL_USE_VARIOUS)); - - cards.add(new SetCardInfo("Mountain", "269b", Rarity.LAND, mage.cards.basiclands.Mountain.class, FULL_ART_BFZ_VARIOUS)); cards.add(new SetCardInfo("Mountain", "266a", Rarity.LAND, mage.cards.basiclands.Mountain.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Mountain", "267a", Rarity.LAND, mage.cards.basiclands.Mountain.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Mountain", "268a", Rarity.LAND, mage.cards.basiclands.Mountain.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Mountain", "269a", Rarity.LAND, mage.cards.basiclands.Mountain.class, NON_FULL_USE_VARIOUS)); - cards.add(new SetCardInfo("Mountain", "265b", Rarity.LAND, mage.cards.basiclands.Mountain.class, FULL_ART_BFZ_VARIOUS)); - cards.add(new SetCardInfo("Mountain", "266b", Rarity.LAND, mage.cards.basiclands.Mountain.class, FULL_ART_BFZ_VARIOUS)); - cards.add(new SetCardInfo("Mountain", "267b", Rarity.LAND, mage.cards.basiclands.Mountain.class, FULL_ART_BFZ_VARIOUS)); - cards.add(new SetCardInfo("Mountain", "268b", Rarity.LAND, mage.cards.basiclands.Mountain.class, FULL_ART_BFZ_VARIOUS)); + cards.add(new SetCardInfo("Mountain", 265, Rarity.LAND, mage.cards.basiclands.Mountain.class, FULL_ART_BFZ_VARIOUS)); + cards.add(new SetCardInfo("Mountain", 266, Rarity.LAND, mage.cards.basiclands.Mountain.class, FULL_ART_BFZ_VARIOUS)); + cards.add(new SetCardInfo("Mountain", 267, Rarity.LAND, mage.cards.basiclands.Mountain.class, FULL_ART_BFZ_VARIOUS)); + cards.add(new SetCardInfo("Mountain", 268, Rarity.LAND, mage.cards.basiclands.Mountain.class, FULL_ART_BFZ_VARIOUS)); + cards.add(new SetCardInfo("Mountain", 269, Rarity.LAND, mage.cards.basiclands.Mountain.class, FULL_ART_BFZ_VARIOUS)); cards.add(new SetCardInfo("Munda, Ambush Leader", 215, Rarity.RARE, mage.cards.m.MundaAmbushLeader.class)); cards.add(new SetCardInfo("Murasa Ranger", 178, Rarity.UNCOMMON, mage.cards.m.MurasaRanger.class)); cards.add(new SetCardInfo("Murk Strider", 62, Rarity.COMMON, mage.cards.m.MurkStrider.class)); @@ -205,8 +204,8 @@ public final class BattleForZendikar extends ExpansionSet { cards.add(new SetCardInfo("Nirkana Assassin", 118, Rarity.COMMON, mage.cards.n.NirkanaAssassin.class)); cards.add(new SetCardInfo("Nissa's Renewal", 180, Rarity.RARE, mage.cards.n.NissasRenewal.class)); cards.add(new SetCardInfo("Noyan Dar, Roil Shaper", 216, Rarity.RARE, mage.cards.n.NoyanDarRoilShaper.class)); - cards.add(new SetCardInfo("Oblivion Sower", 11, Rarity.MYTHIC, mage.cards.o.OblivionSower.class)); cards.add(new SetCardInfo("Ob Nixilis Reignited", 119, Rarity.MYTHIC, mage.cards.o.ObNixilisReignited.class)); + cards.add(new SetCardInfo("Oblivion Sower", 11, Rarity.MYTHIC, mage.cards.o.OblivionSower.class)); cards.add(new SetCardInfo("Omnath, Locus of Rage", 217, Rarity.MYTHIC, mage.cards.o.OmnathLocusOfRage.class)); cards.add(new SetCardInfo("Ondu Champion", 149, Rarity.COMMON, mage.cards.o.OnduChampion.class)); cards.add(new SetCardInfo("Ondu Greathorn", 40, Rarity.COMMON, mage.cards.o.OnduGreathorn.class)); @@ -220,15 +219,15 @@ public final class BattleForZendikar extends ExpansionSet { cards.add(new SetCardInfo("Pathway Arrows", 225, Rarity.UNCOMMON, mage.cards.p.PathwayArrows.class)); cards.add(new SetCardInfo("Pilgrim's Eye", 226, Rarity.UNCOMMON, mage.cards.p.PilgrimsEye.class)); cards.add(new SetCardInfo("Plains", "250a", Rarity.LAND, mage.cards.basiclands.Plains.class, NON_FULL_USE_VARIOUS)); - cards.add(new SetCardInfo("Plains", "254b", Rarity.LAND, mage.cards.basiclands.Plains.class, FULL_ART_BFZ_VARIOUS)); cards.add(new SetCardInfo("Plains", "251a", Rarity.LAND, mage.cards.basiclands.Plains.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Plains", "252a", Rarity.LAND, mage.cards.basiclands.Plains.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Plains", "253a", Rarity.LAND, mage.cards.basiclands.Plains.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Plains", "254a", Rarity.LAND, mage.cards.basiclands.Plains.class, NON_FULL_USE_VARIOUS)); - cards.add(new SetCardInfo("Plains", "250b", Rarity.LAND, mage.cards.basiclands.Plains.class, FULL_ART_BFZ_VARIOUS)); - cards.add(new SetCardInfo("Plains", "251b", Rarity.LAND, mage.cards.basiclands.Plains.class, FULL_ART_BFZ_VARIOUS)); - cards.add(new SetCardInfo("Plains", "252b", Rarity.LAND, mage.cards.basiclands.Plains.class, FULL_ART_BFZ_VARIOUS)); - cards.add(new SetCardInfo("Plains", "253b", Rarity.LAND, mage.cards.basiclands.Plains.class, FULL_ART_BFZ_VARIOUS)); + cards.add(new SetCardInfo("Plains", 250, Rarity.LAND, mage.cards.basiclands.Plains.class, FULL_ART_BFZ_VARIOUS)); + cards.add(new SetCardInfo("Plains", 251, Rarity.LAND, mage.cards.basiclands.Plains.class, FULL_ART_BFZ_VARIOUS)); + cards.add(new SetCardInfo("Plains", 252, Rarity.LAND, mage.cards.basiclands.Plains.class, FULL_ART_BFZ_VARIOUS)); + cards.add(new SetCardInfo("Plains", 253, Rarity.LAND, mage.cards.basiclands.Plains.class, FULL_ART_BFZ_VARIOUS)); + cards.add(new SetCardInfo("Plains", 254, Rarity.LAND, mage.cards.basiclands.Plains.class, FULL_ART_BFZ_VARIOUS)); cards.add(new SetCardInfo("Planar Outburst", 42, Rarity.RARE, mage.cards.p.PlanarOutburst.class)); cards.add(new SetCardInfo("Plated Crusher", 183, Rarity.UNCOMMON, mage.cards.p.PlatedCrusher.class)); cards.add(new SetCardInfo("Plummet", 184, Rarity.COMMON, mage.cards.p.Plummet.class)); @@ -246,14 +245,14 @@ public final class BattleForZendikar extends ExpansionSet { cards.add(new SetCardInfo("Retreat to Kazandu", 186, Rarity.UNCOMMON, mage.cards.r.RetreatToKazandu.class)); cards.add(new SetCardInfo("Retreat to Valakut", 153, Rarity.UNCOMMON, mage.cards.r.RetreatToValakut.class)); cards.add(new SetCardInfo("Rising Miasma", 122, Rarity.UNCOMMON, mage.cards.r.RisingMiasma.class)); - cards.add(new SetCardInfo("Roilmage's Trick", 83, Rarity.COMMON, mage.cards.r.RoilmagesTrick.class)); cards.add(new SetCardInfo("Roil Spout", 219, Rarity.UNCOMMON, mage.cards.r.RoilSpout.class)); cards.add(new SetCardInfo("Roil's Retribution", 45, Rarity.UNCOMMON, mage.cards.r.RoilsRetribution.class)); + cards.add(new SetCardInfo("Roilmage's Trick", 83, Rarity.COMMON, mage.cards.r.RoilmagesTrick.class)); cards.add(new SetCardInfo("Rolling Thunder", 154, Rarity.UNCOMMON, mage.cards.r.RollingThunder.class)); cards.add(new SetCardInfo("Rot Shambler", 187, Rarity.UNCOMMON, mage.cards.r.RotShambler.class)); + cards.add(new SetCardInfo("Ruin Processor", 12, Rarity.COMMON, mage.cards.r.RuinProcessor.class)); cards.add(new SetCardInfo("Ruination Guide", 64, Rarity.UNCOMMON, mage.cards.r.RuinationGuide.class)); cards.add(new SetCardInfo("Ruinous Path", 123, Rarity.RARE, mage.cards.r.RuinousPath.class)); - cards.add(new SetCardInfo("Ruin Processor", 12, Rarity.COMMON, mage.cards.r.RuinProcessor.class)); cards.add(new SetCardInfo("Rush of Ice", 84, Rarity.COMMON, mage.cards.r.RushOfIce.class)); cards.add(new SetCardInfo("Salvage Drone", 65, Rarity.COMMON, mage.cards.s.SalvageDrone.class)); cards.add(new SetCardInfo("Sanctum of Ugin", 242, Rarity.RARE, mage.cards.s.SanctumOfUgin.class)); @@ -283,20 +282,20 @@ public final class BattleForZendikar extends ExpansionSet { cards.add(new SetCardInfo("Spawning Bed", 248, Rarity.UNCOMMON, mage.cards.s.SpawningBed.class)); cards.add(new SetCardInfo("Spell Shrivel", 66, Rarity.COMMON, mage.cards.s.SpellShrivel.class)); cards.add(new SetCardInfo("Stasis Snare", 50, Rarity.UNCOMMON, mage.cards.s.StasisSnare.class)); - cards.add(new SetCardInfo("Stonefury", 156, Rarity.COMMON, mage.cards.s.Stonefury.class)); cards.add(new SetCardInfo("Stone Haven Medic", 51, Rarity.COMMON, mage.cards.s.StoneHavenMedic.class)); + cards.add(new SetCardInfo("Stonefury", 156, Rarity.COMMON, mage.cards.s.Stonefury.class)); cards.add(new SetCardInfo("Sunken Hollow", 249, Rarity.RARE, mage.cards.s.SunkenHollow.class)); cards.add(new SetCardInfo("Sure Strike", 157, Rarity.COMMON, mage.cards.s.SureStrike.class)); cards.add(new SetCardInfo("Swamp", "260a", Rarity.LAND, mage.cards.basiclands.Swamp.class, NON_FULL_USE_VARIOUS)); - cards.add(new SetCardInfo("Swamp", "264b", Rarity.LAND, mage.cards.basiclands.Swamp.class, FULL_ART_BFZ_VARIOUS)); cards.add(new SetCardInfo("Swamp", "261a", Rarity.LAND, mage.cards.basiclands.Swamp.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Swamp", "262a", Rarity.LAND, mage.cards.basiclands.Swamp.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Swamp", "263a", Rarity.LAND, mage.cards.basiclands.Swamp.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Swamp", "264a", Rarity.LAND, mage.cards.basiclands.Swamp.class, NON_FULL_USE_VARIOUS)); - cards.add(new SetCardInfo("Swamp", "260b", Rarity.LAND, mage.cards.basiclands.Swamp.class, FULL_ART_BFZ_VARIOUS)); - cards.add(new SetCardInfo("Swamp", "261b", Rarity.LAND, mage.cards.basiclands.Swamp.class, FULL_ART_BFZ_VARIOUS)); - cards.add(new SetCardInfo("Swamp", "262b", Rarity.LAND, mage.cards.basiclands.Swamp.class, FULL_ART_BFZ_VARIOUS)); - cards.add(new SetCardInfo("Swamp", "263b", Rarity.LAND, mage.cards.basiclands.Swamp.class, FULL_ART_BFZ_VARIOUS)); + cards.add(new SetCardInfo("Swamp", 260, Rarity.LAND, mage.cards.basiclands.Swamp.class, FULL_ART_BFZ_VARIOUS)); + cards.add(new SetCardInfo("Swamp", 261, Rarity.LAND, mage.cards.basiclands.Swamp.class, FULL_ART_BFZ_VARIOUS)); + cards.add(new SetCardInfo("Swamp", 262, Rarity.LAND, mage.cards.basiclands.Swamp.class, FULL_ART_BFZ_VARIOUS)); + cards.add(new SetCardInfo("Swamp", 263, Rarity.LAND, mage.cards.basiclands.Swamp.class, FULL_ART_BFZ_VARIOUS)); + cards.add(new SetCardInfo("Swamp", 264, Rarity.LAND, mage.cards.basiclands.Swamp.class, FULL_ART_BFZ_VARIOUS)); cards.add(new SetCardInfo("Swarm Surge", 100, Rarity.COMMON, mage.cards.s.SwarmSurge.class)); cards.add(new SetCardInfo("Swell of Growth", 191, Rarity.COMMON, mage.cards.s.SwellOfGrowth.class)); cards.add(new SetCardInfo("Sylvan Scrying", 192, Rarity.UNCOMMON, mage.cards.s.SylvanScrying.class)); diff --git a/Mage.Sets/src/mage/sets/Zendikar.java b/Mage.Sets/src/mage/sets/Zendikar.java index acd60c53cb4..5656790fcc0 100644 --- a/Mage.Sets/src/mage/sets/Zendikar.java +++ b/Mage.Sets/src/mage/sets/Zendikar.java @@ -1,15 +1,12 @@ - package mage.sets; import mage.ObjectColor; import mage.cards.CardGraphicInfo; import mage.cards.ExpansionSet; -import mage.cards.FrameStyle; import mage.constants.Rarity; import mage.constants.SetType; /** - * * @author BetaSteward_at_googlemail.com */ public final class Zendikar extends ExpansionSet { @@ -29,6 +26,7 @@ public final class Zendikar extends ExpansionSet { this.numBoosterUncommon = 3; this.numBoosterRare = 1; this.ratioBoosterMythic = 8; + cards.add(new SetCardInfo("Adventuring Gear", 195, Rarity.COMMON, mage.cards.a.AdventuringGear.class)); cards.add(new SetCardInfo("Aether Figment", 40, Rarity.UNCOMMON, mage.cards.a.AetherFigment.class)); cards.add(new SetCardInfo("Akoum Refuge", 210, Rarity.UNCOMMON, mage.cards.a.AkoumRefuge.class)); @@ -45,10 +43,10 @@ public final class Zendikar extends ExpansionSet { cards.add(new SetCardInfo("Blade of the Bloodchief", 196, Rarity.RARE, mage.cards.b.BladeOfTheBloodchief.class)); cards.add(new SetCardInfo("Bladetusk Boar", 118, Rarity.COMMON, mage.cards.b.BladetuskBoar.class)); cards.add(new SetCardInfo("Blazing Torch", 197, Rarity.UNCOMMON, mage.cards.b.BlazingTorch.class)); - cards.add(new SetCardInfo("Bloodchief Ascension", 82, Rarity.RARE, mage.cards.b.BloodchiefAscension.class)); - cards.add(new SetCardInfo("Bloodghast", 83, Rarity.RARE, mage.cards.b.Bloodghast.class)); cards.add(new SetCardInfo("Blood Seeker", 80, Rarity.COMMON, mage.cards.b.BloodSeeker.class)); cards.add(new SetCardInfo("Blood Tribute", 81, Rarity.RARE, mage.cards.b.BloodTribute.class)); + cards.add(new SetCardInfo("Bloodchief Ascension", 82, Rarity.RARE, mage.cards.b.BloodchiefAscension.class)); + cards.add(new SetCardInfo("Bloodghast", 83, Rarity.RARE, mage.cards.b.Bloodghast.class)); cards.add(new SetCardInfo("Bog Tatters", 84, Rarity.COMMON, mage.cards.b.BogTatters.class)); cards.add(new SetCardInfo("Bold Defense", 3, Rarity.COMMON, mage.cards.b.BoldDefense.class)); cards.add(new SetCardInfo("Brave the Elements", 4, Rarity.UNCOMMON, mage.cards.b.BraveTheElements.class)); @@ -80,14 +78,14 @@ public final class Zendikar extends ExpansionSet { cards.add(new SetCardInfo("Explorer's Scope", 202, Rarity.COMMON, mage.cards.e.ExplorersScope.class)); cards.add(new SetCardInfo("Feast of Blood", 88, Rarity.UNCOMMON, mage.cards.f.FeastOfBlood.class)); cards.add(new SetCardInfo("Felidar Sovereign", 12, Rarity.MYTHIC, mage.cards.f.FelidarSovereign.class)); - cards.add(new SetCardInfo("Forest", 246, Rarity.LAND, mage.cards.basiclands.Forest.class, new CardGraphicInfo(FrameStyle.ZEN_FULL_ART_BASIC, true))); - cards.add(new SetCardInfo("Forest", 247, Rarity.LAND, mage.cards.basiclands.Forest.class, new CardGraphicInfo(FrameStyle.ZEN_FULL_ART_BASIC, true))); - cards.add(new SetCardInfo("Forest", 248, Rarity.LAND, mage.cards.basiclands.Forest.class, new CardGraphicInfo(FrameStyle.ZEN_FULL_ART_BASIC, true))); - cards.add(new SetCardInfo("Forest", 249, Rarity.LAND, mage.cards.basiclands.Forest.class, new CardGraphicInfo(FrameStyle.ZEN_FULL_ART_BASIC, true))); - cards.add(new SetCardInfo("Forest", 266, Rarity.LAND, mage.cards.basiclands.Forest.class, NON_FULL_USE_VARIOUS)); - cards.add(new SetCardInfo("Forest", 267, Rarity.LAND, mage.cards.basiclands.Forest.class, NON_FULL_USE_VARIOUS)); - cards.add(new SetCardInfo("Forest", 268, Rarity.LAND, mage.cards.basiclands.Forest.class, NON_FULL_USE_VARIOUS)); - cards.add(new SetCardInfo("Forest", 269, Rarity.LAND, mage.cards.basiclands.Forest.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Forest", "246a", Rarity.LAND, mage.cards.basiclands.Forest.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Forest", "247a", Rarity.LAND, mage.cards.basiclands.Forest.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Forest", "248a", Rarity.LAND, mage.cards.basiclands.Forest.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Forest", "249a", Rarity.LAND, mage.cards.basiclands.Forest.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Forest", 246, Rarity.LAND, mage.cards.basiclands.Forest.class, FULL_ART_ZEN_VARIOUS)); + cards.add(new SetCardInfo("Forest", 247, Rarity.LAND, mage.cards.basiclands.Forest.class, FULL_ART_ZEN_VARIOUS)); + cards.add(new SetCardInfo("Forest", 248, Rarity.LAND, mage.cards.basiclands.Forest.class, FULL_ART_ZEN_VARIOUS)); + cards.add(new SetCardInfo("Forest", 249, Rarity.LAND, mage.cards.basiclands.Forest.class, FULL_ART_ZEN_VARIOUS)); cards.add(new SetCardInfo("Frontier Guide", 161, Rarity.UNCOMMON, mage.cards.f.FrontierGuide.class)); cards.add(new SetCardInfo("Gatekeeper of Malakir", 89, Rarity.UNCOMMON, mage.cards.g.GatekeeperOfMalakir.class)); cards.add(new SetCardInfo("Geyser Glider", 124, Rarity.UNCOMMON, mage.cards.g.GeyserGlider.class)); @@ -121,14 +119,14 @@ public final class Zendikar extends ExpansionSet { cards.add(new SetCardInfo("Into the Roil", 48, Rarity.COMMON, mage.cards.i.IntoTheRoil.class)); cards.add(new SetCardInfo("Iona, Shield of Emeria", 13, Rarity.MYTHIC, mage.cards.i.IonaShieldOfEmeria.class)); cards.add(new SetCardInfo("Ior Ruin Expedition", 49, Rarity.COMMON, mage.cards.i.IorRuinExpedition.class)); - cards.add(new SetCardInfo("Island", 234, Rarity.LAND, mage.cards.basiclands.Island.class, new CardGraphicInfo(FrameStyle.ZEN_FULL_ART_BASIC, true))); - cards.add(new SetCardInfo("Island", 235, Rarity.LAND, mage.cards.basiclands.Island.class, new CardGraphicInfo(FrameStyle.ZEN_FULL_ART_BASIC, true))); - cards.add(new SetCardInfo("Island", 236, Rarity.LAND, mage.cards.basiclands.Island.class, new CardGraphicInfo(FrameStyle.ZEN_FULL_ART_BASIC, true))); - cards.add(new SetCardInfo("Island", 237, Rarity.LAND, mage.cards.basiclands.Island.class, new CardGraphicInfo(FrameStyle.ZEN_FULL_ART_BASIC, true))); - cards.add(new SetCardInfo("Island", 254, Rarity.LAND, mage.cards.basiclands.Island.class, NON_FULL_USE_VARIOUS)); - cards.add(new SetCardInfo("Island", 255, Rarity.LAND, mage.cards.basiclands.Island.class, NON_FULL_USE_VARIOUS)); - cards.add(new SetCardInfo("Island", 256, Rarity.LAND, mage.cards.basiclands.Island.class, NON_FULL_USE_VARIOUS)); - cards.add(new SetCardInfo("Island", 257, Rarity.LAND, mage.cards.basiclands.Island.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Island", "234a", Rarity.LAND, mage.cards.basiclands.Island.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Island", "235a", Rarity.LAND, mage.cards.basiclands.Island.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Island", "236a", Rarity.LAND, mage.cards.basiclands.Island.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Island", "237a", Rarity.LAND, mage.cards.basiclands.Island.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Island", 234, Rarity.LAND, mage.cards.basiclands.Island.class, FULL_ART_ZEN_VARIOUS)); + cards.add(new SetCardInfo("Island", 235, Rarity.LAND, mage.cards.basiclands.Island.class, FULL_ART_ZEN_VARIOUS)); + cards.add(new SetCardInfo("Island", 236, Rarity.LAND, mage.cards.basiclands.Island.class, FULL_ART_ZEN_VARIOUS)); + cards.add(new SetCardInfo("Island", 237, Rarity.LAND, mage.cards.basiclands.Island.class, FULL_ART_ZEN_VARIOUS)); cards.add(new SetCardInfo("Joraga Bard", 166, Rarity.COMMON, mage.cards.j.JoragaBard.class)); cards.add(new SetCardInfo("Journey to Nowhere", 14, Rarity.COMMON, mage.cards.j.JourneyToNowhere.class)); cards.add(new SetCardInfo("Jwar Isle Refuge", 215, Rarity.UNCOMMON, mage.cards.j.JwarIsleRefuge.class)); @@ -165,22 +163,21 @@ public final class Zendikar extends ExpansionSet { cards.add(new SetCardInfo("Marsh Flats", 219, Rarity.RARE, mage.cards.m.MarshFlats.class, new CardGraphicInfo(new ObjectColor("WB"), null, false))); cards.add(new SetCardInfo("Merfolk Seastalkers", 55, Rarity.UNCOMMON, mage.cards.m.MerfolkSeastalkers.class)); cards.add(new SetCardInfo("Merfolk Wayfinder", 56, Rarity.UNCOMMON, mage.cards.m.MerfolkWayfinder.class)); + cards.add(new SetCardInfo("Mind Sludge", 102, Rarity.UNCOMMON, mage.cards.m.MindSludge.class)); cards.add(new SetCardInfo("Mindbreak Trap", 57, Rarity.MYTHIC, mage.cards.m.MindbreakTrap.class)); cards.add(new SetCardInfo("Mindless Null", 103, Rarity.COMMON, mage.cards.m.MindlessNull.class)); - cards.add(new SetCardInfo("Mind Sludge", 102, Rarity.UNCOMMON, mage.cards.m.MindSludge.class)); cards.add(new SetCardInfo("Mire Blight", 104, Rarity.COMMON, mage.cards.m.MireBlight.class)); - cards.add(new SetCardInfo("Misty Rainforest", 220, Rarity.RARE, mage.cards.m.MistyRainforest.class, new CardGraphicInfo(new ObjectColor("UG"), null, - false))); + cards.add(new SetCardInfo("Misty Rainforest", 220, Rarity.RARE, mage.cards.m.MistyRainforest.class, new CardGraphicInfo(new ObjectColor("UG"), null, false))); cards.add(new SetCardInfo("Mold Shambler", 169, Rarity.COMMON, mage.cards.m.MoldShambler.class)); cards.add(new SetCardInfo("Molten Ravager", 138, Rarity.COMMON, mage.cards.m.MoltenRavager.class)); - cards.add(new SetCardInfo("Mountain", 242, Rarity.LAND, mage.cards.basiclands.Mountain.class, new CardGraphicInfo(FrameStyle.ZEN_FULL_ART_BASIC, true))); - cards.add(new SetCardInfo("Mountain", 243, Rarity.LAND, mage.cards.basiclands.Mountain.class, new CardGraphicInfo(FrameStyle.ZEN_FULL_ART_BASIC, true))); - cards.add(new SetCardInfo("Mountain", 244, Rarity.LAND, mage.cards.basiclands.Mountain.class, new CardGraphicInfo(FrameStyle.ZEN_FULL_ART_BASIC, true))); - cards.add(new SetCardInfo("Mountain", 245, Rarity.LAND, mage.cards.basiclands.Mountain.class, new CardGraphicInfo(FrameStyle.ZEN_FULL_ART_BASIC, true))); - cards.add(new SetCardInfo("Mountain", 262, Rarity.LAND, mage.cards.basiclands.Mountain.class, NON_FULL_USE_VARIOUS)); - cards.add(new SetCardInfo("Mountain", 263, Rarity.LAND, mage.cards.basiclands.Mountain.class, NON_FULL_USE_VARIOUS)); - cards.add(new SetCardInfo("Mountain", 264, Rarity.LAND, mage.cards.basiclands.Mountain.class, NON_FULL_USE_VARIOUS)); - cards.add(new SetCardInfo("Mountain", 265, Rarity.LAND, mage.cards.basiclands.Mountain.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Mountain", "242a", Rarity.LAND, mage.cards.basiclands.Mountain.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Mountain", "243a", Rarity.LAND, mage.cards.basiclands.Mountain.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Mountain", "244a", Rarity.LAND, mage.cards.basiclands.Mountain.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Mountain", "245a", Rarity.LAND, mage.cards.basiclands.Mountain.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Mountain", 242, Rarity.LAND, mage.cards.basiclands.Mountain.class, FULL_ART_ZEN_VARIOUS)); + cards.add(new SetCardInfo("Mountain", 243, Rarity.LAND, mage.cards.basiclands.Mountain.class, FULL_ART_ZEN_VARIOUS)); + cards.add(new SetCardInfo("Mountain", 244, Rarity.LAND, mage.cards.basiclands.Mountain.class, FULL_ART_ZEN_VARIOUS)); + cards.add(new SetCardInfo("Mountain", 245, Rarity.LAND, mage.cards.basiclands.Mountain.class, FULL_ART_ZEN_VARIOUS)); cards.add(new SetCardInfo("Murasa Pyromancer", 139, Rarity.UNCOMMON, mage.cards.m.MurasaPyromancer.class)); cards.add(new SetCardInfo("Narrow Escape", 27, Rarity.COMMON, mage.cards.n.NarrowEscape.class)); cards.add(new SetCardInfo("Needlebite Trap", 105, Rarity.UNCOMMON, mage.cards.n.NeedlebiteTrap.class)); @@ -200,14 +197,14 @@ public final class Zendikar extends ExpansionSet { cards.add(new SetCardInfo("Pillarfield Ox", 31, Rarity.COMMON, mage.cards.p.PillarfieldOx.class)); cards.add(new SetCardInfo("Piranha Marsh", 222, Rarity.COMMON, mage.cards.p.PiranhaMarsh.class)); cards.add(new SetCardInfo("Pitfall Trap", 32, Rarity.UNCOMMON, mage.cards.p.PitfallTrap.class)); - cards.add(new SetCardInfo("Plains", 230, Rarity.LAND, mage.cards.basiclands.Plains.class, new CardGraphicInfo(FrameStyle.ZEN_FULL_ART_BASIC, true))); - cards.add(new SetCardInfo("Plains", 231, Rarity.LAND, mage.cards.basiclands.Plains.class, new CardGraphicInfo(FrameStyle.ZEN_FULL_ART_BASIC, true))); - cards.add(new SetCardInfo("Plains", 232, Rarity.LAND, mage.cards.basiclands.Plains.class, new CardGraphicInfo(FrameStyle.ZEN_FULL_ART_BASIC, true))); - cards.add(new SetCardInfo("Plains", 233, Rarity.LAND, mage.cards.basiclands.Plains.class, new CardGraphicInfo(FrameStyle.ZEN_FULL_ART_BASIC, true))); - cards.add(new SetCardInfo("Plains", 250, Rarity.LAND, mage.cards.basiclands.Plains.class, NON_FULL_USE_VARIOUS)); - cards.add(new SetCardInfo("Plains", 251, Rarity.LAND, mage.cards.basiclands.Plains.class, NON_FULL_USE_VARIOUS)); - cards.add(new SetCardInfo("Plains", 252, Rarity.LAND, mage.cards.basiclands.Plains.class, NON_FULL_USE_VARIOUS)); - cards.add(new SetCardInfo("Plains", 253, Rarity.LAND, mage.cards.basiclands.Plains.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Plains", "230a", Rarity.LAND, mage.cards.basiclands.Plains.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Plains", "231a", Rarity.LAND, mage.cards.basiclands.Plains.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Plains", "232a", Rarity.LAND, mage.cards.basiclands.Plains.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Plains", "233a", Rarity.LAND, mage.cards.basiclands.Plains.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Plains", 230, Rarity.LAND, mage.cards.basiclands.Plains.class, FULL_ART_ZEN_VARIOUS)); + cards.add(new SetCardInfo("Plains", 231, Rarity.LAND, mage.cards.basiclands.Plains.class, FULL_ART_ZEN_VARIOUS)); + cards.add(new SetCardInfo("Plains", 232, Rarity.LAND, mage.cards.basiclands.Plains.class, FULL_ART_ZEN_VARIOUS)); + cards.add(new SetCardInfo("Plains", 233, Rarity.LAND, mage.cards.basiclands.Plains.class, FULL_ART_ZEN_VARIOUS)); cards.add(new SetCardInfo("Plated Geopede", 141, Rarity.COMMON, mage.cards.p.PlatedGeopede.class)); cards.add(new SetCardInfo("Predatory Urge", 175, Rarity.RARE, mage.cards.p.PredatoryUrge.class)); cards.add(new SetCardInfo("Primal Bellow", 176, Rarity.UNCOMMON, mage.cards.p.PrimalBellow.class)); @@ -257,14 +254,14 @@ public final class Zendikar extends ExpansionSet { cards.add(new SetCardInfo("Summoning Trap", 184, Rarity.RARE, mage.cards.s.SummoningTrap.class)); cards.add(new SetCardInfo("Sunspring Expedition", 37, Rarity.COMMON, mage.cards.s.SunspringExpedition.class)); cards.add(new SetCardInfo("Surrakar Marauder", 113, Rarity.COMMON, mage.cards.s.SurrakarMarauder.class)); - cards.add(new SetCardInfo("Swamp", 238, Rarity.LAND, mage.cards.basiclands.Swamp.class, new CardGraphicInfo(FrameStyle.ZEN_FULL_ART_BASIC, true))); - cards.add(new SetCardInfo("Swamp", 239, Rarity.LAND, mage.cards.basiclands.Swamp.class, new CardGraphicInfo(FrameStyle.ZEN_FULL_ART_BASIC, true))); - cards.add(new SetCardInfo("Swamp", 240, Rarity.LAND, mage.cards.basiclands.Swamp.class, new CardGraphicInfo(FrameStyle.ZEN_FULL_ART_BASIC, true))); - cards.add(new SetCardInfo("Swamp", 241, Rarity.LAND, mage.cards.basiclands.Swamp.class, new CardGraphicInfo(FrameStyle.ZEN_FULL_ART_BASIC, true))); - cards.add(new SetCardInfo("Swamp", 258, Rarity.LAND, mage.cards.basiclands.Swamp.class, NON_FULL_USE_VARIOUS)); - cards.add(new SetCardInfo("Swamp", 259, Rarity.LAND, mage.cards.basiclands.Swamp.class, NON_FULL_USE_VARIOUS)); - cards.add(new SetCardInfo("Swamp", 260, Rarity.LAND, mage.cards.basiclands.Swamp.class, NON_FULL_USE_VARIOUS)); - cards.add(new SetCardInfo("Swamp", 261, Rarity.LAND, mage.cards.basiclands.Swamp.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Swamp", "238a", Rarity.LAND, mage.cards.basiclands.Swamp.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Swamp", "239a", Rarity.LAND, mage.cards.basiclands.Swamp.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Swamp", "240a", Rarity.LAND, mage.cards.basiclands.Swamp.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Swamp", "241a", Rarity.LAND, mage.cards.basiclands.Swamp.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Swamp", 238, Rarity.LAND, mage.cards.basiclands.Swamp.class, FULL_ART_ZEN_VARIOUS)); + cards.add(new SetCardInfo("Swamp", 239, Rarity.LAND, mage.cards.basiclands.Swamp.class, FULL_ART_ZEN_VARIOUS)); + cards.add(new SetCardInfo("Swamp", 240, Rarity.LAND, mage.cards.basiclands.Swamp.class, FULL_ART_ZEN_VARIOUS)); + cards.add(new SetCardInfo("Swamp", 241, Rarity.LAND, mage.cards.basiclands.Swamp.class, FULL_ART_ZEN_VARIOUS)); cards.add(new SetCardInfo("Tajuru Archer", 185, Rarity.UNCOMMON, mage.cards.t.TajuruArcher.class)); cards.add(new SetCardInfo("Tanglesap", 186, Rarity.COMMON, mage.cards.t.Tanglesap.class)); cards.add(new SetCardInfo("Teetering Peaks", 226, Rarity.COMMON, mage.cards.t.TeeteringPeaks.class)); @@ -289,8 +286,7 @@ public final class Zendikar extends ExpansionSet { cards.add(new SetCardInfo("Vampire Nighthawk", 116, Rarity.UNCOMMON, mage.cards.v.VampireNighthawk.class)); cards.add(new SetCardInfo("Vampire's Bite", 117, Rarity.COMMON, mage.cards.v.VampiresBite.class)); cards.add(new SetCardInfo("Vastwood Gorger", 192, Rarity.COMMON, mage.cards.v.VastwoodGorger.class)); - cards.add(new SetCardInfo("Verdant Catacombs", 229, Rarity.RARE, mage.cards.v.VerdantCatacombs.class, new CardGraphicInfo(new ObjectColor("BG"), null, - false))); + cards.add(new SetCardInfo("Verdant Catacombs", 229, Rarity.RARE, mage.cards.v.VerdantCatacombs.class, new CardGraphicInfo(new ObjectColor("BG"), null, false))); cards.add(new SetCardInfo("Vines of Vastwood", 193, Rarity.COMMON, mage.cards.v.VinesOfVastwood.class)); cards.add(new SetCardInfo("Warren Instigator", 154, Rarity.MYTHIC, mage.cards.w.WarrenInstigator.class)); cards.add(new SetCardInfo("Welkin Tern", 76, Rarity.COMMON, mage.cards.w.WelkinTern.class)); diff --git a/Mage/src/main/java/mage/cards/ExpansionSet.java b/Mage/src/main/java/mage/cards/ExpansionSet.java index ba8ac8073f4..3a362676025 100644 --- a/Mage/src/main/java/mage/cards/ExpansionSet.java +++ b/Mage/src/main/java/mage/cards/ExpansionSet.java @@ -24,7 +24,7 @@ public abstract class ExpansionSet implements Serializable { private static final Logger logger = Logger.getLogger(ExpansionSet.class); public static final CardGraphicInfo NON_FULL_USE_VARIOUS = new CardGraphicInfo(null, true); public static final CardGraphicInfo FULL_ART_BFZ_VARIOUS = new CardGraphicInfo(FrameStyle.BFZ_FULL_ART_BASIC, true); - + public static final CardGraphicInfo FULL_ART_ZEN_VARIOUS = new CardGraphicInfo(FrameStyle.ZEN_FULL_ART_BASIC, true); public class SetCardInfo implements Serializable {