diff --git a/.gitignore b/.gitignore index c14e808037..d084fe143d 100644 --- a/.gitignore +++ b/.gitignore @@ -44,6 +44,7 @@ Mage.Server.Plugins/Mage.Game.CommanderDuel/target Mage.Server.Plugins/Mage.Game.CommanderFreeForAll/target/ Mage.Server.Plugins/Mage.Game.FreeForAll/target Mage.Server.Plugins/Mage.Game.MomirDuel/target +Mage.Server.Plugins/Mage.Game.MomirGame/target/ Mage.Server.Plugins/Mage.Game.PennyDreadfulCommanderFreeForAll/target Mage.Server.Plugins/Mage.Game.TinyLeadersDuel/target Mage.Server.Plugins/Mage.Game.TwoPlayerDuel/target @@ -132,3 +133,4 @@ Mage.Client/serverlist.txt client_secrets.json dependency-reduced-pom.xml +mage-bundle diff --git a/Mage.Client/src/main/java/org/mage/card/arcane/ModernCardRenderer.java b/Mage.Client/src/main/java/org/mage/card/arcane/ModernCardRenderer.java index 5436c39af3..a3de811495 100644 --- a/Mage.Client/src/main/java/org/mage/card/arcane/ModernCardRenderer.java +++ b/Mage.Client/src/main/java/org/mage/card/arcane/ModernCardRenderer.java @@ -5,19 +5,6 @@ */ package org.mage.card.arcane; -import mage.ObjectColor; -import mage.cards.ArtRect; -import mage.cards.FrameStyle; -import mage.client.dialog.PreferencesDialog; -import mage.constants.CardType; -import mage.constants.MageObjectType; -import mage.constants.SubType; -import mage.util.SubTypeList; -import mage.view.CardView; -import mage.view.PermanentView; -import org.apache.log4j.Logger; - -import javax.swing.*; import java.awt.*; import java.awt.font.*; import java.awt.geom.Rectangle2D; @@ -31,6 +18,18 @@ import java.text.CharacterIterator; import java.util.ArrayList; import java.util.Collection; import java.util.List; +import javax.swing.*; +import mage.ObjectColor; +import mage.cards.ArtRect; +import mage.cards.FrameStyle; +import mage.client.dialog.PreferencesDialog; +import mage.constants.CardType; +import mage.constants.MageObjectType; +import mage.constants.SubType; +import mage.util.SubTypeList; +import mage.view.CardView; +import mage.view.PermanentView; +import org.apache.log4j.Logger; /* @@ -77,9 +76,9 @@ public class ModernCardRenderer extends CardRenderer { } private static Font loadFont(String name) { - try(InputStream in = ModernCardRenderer.class.getResourceAsStream("/cardrender/" + name + ".ttf")) { + try (InputStream in = ModernCardRenderer.class.getResourceAsStream("/cardrender/" + name + ".ttf")) { return Font.createFont( - Font.TRUETYPE_FONT,in); + Font.TRUETYPE_FONT, in); } catch (IOException e) { LOGGER.info("Failed to load font `" + name + "`, couldn't find resource."); } catch (FontFormatException e) { @@ -353,7 +352,7 @@ public class ModernCardRenderer extends CardRenderer { if (useInventionFrame()) { drawArtIntoRect(g, borderWidth, borderWidth, - cardWidth - 2*borderWidth, cardHeight - 2*borderWidth, + cardWidth - 2 * borderWidth, cardHeight - 2 * borderWidth, getArtRect(), false); } @@ -367,11 +366,11 @@ public class ModernCardRenderer extends CardRenderer { // each filling half of the art rect drawArtIntoRect(g, totalContentInset + 1, totalContentInset + boxHeight, - contentWidth - 2, (typeLineY - totalContentInset - boxHeight)/2, + contentWidth - 2, (typeLineY - totalContentInset - boxHeight) / 2, ArtRect.SPLIT_LEFT.rect, useInventionFrame()); drawArtIntoRect(g, - totalContentInset + 1, totalContentInset + boxHeight + (typeLineY - totalContentInset - boxHeight)/2, - contentWidth - 2, (typeLineY - totalContentInset - boxHeight)/2, + totalContentInset + 1, totalContentInset + boxHeight + (typeLineY - totalContentInset - boxHeight) / 2, + contentWidth - 2, (typeLineY - totalContentInset - boxHeight) / 2, ArtRect.SPLIT_RIGHT.rect, useInventionFrame()); return; } else if (rect != ArtRect.NORMAL) { @@ -849,6 +848,9 @@ public class ModernCardRenderer extends CardRenderer { inset = cardWidth / 12; } int availWidth = w - inset; + if (availWidth < 0) { + return 0; + } FontRenderContext frc = g.getFontRenderContext(); AttributedCharacterIterator textIter = text.getIterator(); diff --git a/Mage.Client/src/main/java/org/mage/plugins/card/utils/CardImageUtils.java b/Mage.Client/src/main/java/org/mage/plugins/card/utils/CardImageUtils.java index ac45d2a2f8..7cbe1ec9a0 100644 --- a/Mage.Client/src/main/java/org/mage/plugins/card/utils/CardImageUtils.java +++ b/Mage.Client/src/main/java/org/mage/plugins/card/utils/CardImageUtils.java @@ -184,7 +184,7 @@ public final class CardImageUtils { String imageName; String type = card.getType() != 0 ? ' ' + Integer.toString(card.getType()) : ""; - String name = card.getFileName().isEmpty() ? card.getName().replace(":", "").replace("//", "-") : card.getFileName(); + String name = card.getFileName().isEmpty() ? card.getName().replace(":", "").replace("\"", "").replace("//", "-") : card.getFileName(); if (card.getUsesVariousArt()) { imageName = name + '.' + card.getCollectorId() + ".full.jpg"; diff --git a/Mage.Common/src/main/java/mage/utils/MageVersion.java b/Mage.Common/src/main/java/mage/utils/MageVersion.java index 00d203ef6c..ac35216c02 100644 --- a/Mage.Common/src/main/java/mage/utils/MageVersion.java +++ b/Mage.Common/src/main/java/mage/utils/MageVersion.java @@ -41,7 +41,7 @@ public class MageVersion implements Serializable, Comparable { public final static int MAGE_VERSION_MAJOR = 1; public final static int MAGE_VERSION_MINOR = 4; public final static int MAGE_VERSION_PATCH = 26; - public final static String MAGE_VERSION_MINOR_PATCH = "V7"; + public final static String MAGE_VERSION_MINOR_PATCH = "V8"; public final static String MAGE_VERSION_INFO = ""; private final int major; diff --git a/Mage.Server.Plugins/Mage.Deck.Constructed/src/mage/deck/CanadianHighlander.java b/Mage.Server.Plugins/Mage.Deck.Constructed/src/mage/deck/CanadianHighlander.java index 93c0266014..75babb9a1b 100644 --- a/Mage.Server.Plugins/Mage.Deck.Constructed/src/mage/deck/CanadianHighlander.java +++ b/Mage.Server.Plugins/Mage.Deck.Constructed/src/mage/deck/CanadianHighlander.java @@ -92,15 +92,14 @@ public class CanadianHighlander extends Constructed { String cn = entry.getKey(); if (cn.equals("Balance") || cn.equals("Dig Through Time") + || cn.equals("Doomsday") || cn.equals("Enlightened Tutor") || cn.equals("Fastbond") || cn.equals("Intuition") || cn.equals("Library of Alexandria") - || cn.equals("Lim-Dul's Vault") || cn.equals("Mana Vault") || cn.equals("Merchant Scroll") || cn.equals("Mind Twist") - || cn.equals("Oath of Druids") || cn.equals("Personal Tutor") || cn.equals("Stoneforge Mystic") || cn.equals("Tainted Pact") @@ -112,32 +111,32 @@ public class CanadianHighlander extends Constructed { totalPoints += 1; invalid.put(entry.getKey(), " 1 point " + cn); } - if (cn.equals("Doomsday") - || cn.equals("Gifts Ungiven") + if (cn.equals("Gifts Ungiven") + || cn.equals("Hermit Druid") || cn.equals("Imperial Seal") || cn.equals("Mana Crypt") || cn.equals("Mystical Tutor") || cn.equals("Strip Mine") - || cn.equals("Summoner's Pact") + || cn.equals("Summoner’s Pact") || cn.equals("Survival of the Fittest") - || cn.equals("Umezawa's Jitte")) { + || cn.equals("Umezawa’s Jitte")) { totalPoints += 2; invalid.put(entry.getKey(), " 2 points " + cn); } if (cn.equals("Birthing Pod") - || cn.equals("Hermit Druid") || cn.equals("Mox Emerald") || cn.equals("Mox Jet") || cn.equals("Mox Pearl") || cn.equals("Mox Ruby") || cn.equals("Mox Sapphire") || cn.equals("Protean Hulk") + || cn.equals("Sol Ring") || cn.equals("Vampiric Tutor")) { totalPoints += 3; invalid.put(entry.getKey(), " 3 points " + cn); } if (cn.equals("Demonic Tutor") - || cn.equals("Sol Ring")) { + || cn.equals("Tinker")) { totalPoints += 4; invalid.put(entry.getKey(), " 4 points " + cn); } @@ -147,13 +146,12 @@ public class CanadianHighlander extends Constructed { invalid.put(entry.getKey(), " 5 points " + cn); } if (cn.equals("Ancestral Recall") - || cn.equals("Time Walk")) { + || cn.equals("Time Vault")) { totalPoints += 6; - invalid.put(entry.getKey(), " 5 points " + cn); + invalid.put(entry.getKey(), " 6 points " + cn); } if (cn.equals("Black Lotus") - || cn.equals("Flash") - || cn.equals("Time Vault")) { + || cn.equals("Flash")) { totalPoints += 7; invalid.put(entry.getKey(), " 7 points " + cn); } diff --git a/Mage.Server.Plugins/Mage.Game.MomirGame/pom.xml b/Mage.Server.Plugins/Mage.Game.MomirGame/pom.xml new file mode 100644 index 0000000000..209ffd70c3 --- /dev/null +++ b/Mage.Server.Plugins/Mage.Game.MomirGame/pom.xml @@ -0,0 +1,55 @@ + + + + 4.0.0 + + + org.mage + mage-server-plugins + 1.4.26 + + + mage-game-momirfreeforall + jar + Mage Game Momir Basic Free for All + + + + ${project.groupId} + mage + ${project.version} + + + ${project.groupId} + mage-game-freeforall + ${project.version} + + + + + src + + + org.apache.maven.plugins + maven-compiler-plugin + + 1.7 + 1.7 + + + + maven-resources-plugin + + UTF-8 + + + + + + mage-game-momir + + + + + diff --git a/Mage.Server.Plugins/Mage.Game.MomirGame/src/mage/game/MomirFreeForAllMatch.java b/Mage.Server.Plugins/Mage.Game.MomirGame/src/mage/game/MomirFreeForAllMatch.java new file mode 100644 index 0000000000..a46aa486ca --- /dev/null +++ b/Mage.Server.Plugins/Mage.Game.MomirGame/src/mage/game/MomirFreeForAllMatch.java @@ -0,0 +1,55 @@ +/* + * Copyright 2010 BetaSteward_at_googlemail.com. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are + * permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this list of + * conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, this list + * of conditions and the following disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY BetaSteward_at_googlemail.com ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BetaSteward_at_googlemail.com OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * The views and conclusions contained in the software and documentation are those of the + * authors and should not be interpreted as representing official policies, either expressed + * or implied, of BetaSteward_at_googlemail.com. + */ +package mage.game; + +import mage.game.match.MatchImpl; +import mage.game.match.MatchOptions; + +/** + * + * @author nigelzor + */ +public class MomirFreeForAllMatch extends MatchImpl { + + public MomirFreeForAllMatch(MatchOptions options) { + super(options); + } + + @Override + public void startGame() throws GameException { + // Momir Vig, Simic Visionary gives +4 starting life + int startLife = 24; + + MomirGame game = new MomirGame(options.getAttackOption(), options.getRange(), options.getFreeMulligans(), startLife); + game.setStartMessage(this.createGameStartMessage()); + + this.initGame(game); + games.add(game); + } + +} diff --git a/Mage.Server.Plugins/Mage.Game.MomirGame/src/mage/game/MomirFreeForAllType.java b/Mage.Server.Plugins/Mage.Game.MomirGame/src/mage/game/MomirFreeForAllType.java new file mode 100644 index 0000000000..5eb6c30170 --- /dev/null +++ b/Mage.Server.Plugins/Mage.Game.MomirGame/src/mage/game/MomirFreeForAllType.java @@ -0,0 +1,57 @@ +/* + * Copyright 2010 BetaSteward_at_googlemail.com. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are + * permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this list of + * conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, this list + * of conditions and the following disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY BetaSteward_at_googlemail.com ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BetaSteward_at_googlemail.com OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * The views and conclusions contained in the software and documentation are those of the + * authors and should not be interpreted as representing official policies, either expressed + * or implied, of BetaSteward_at_googlemail.com. + */ +package mage.game; + +import mage.game.match.MatchType; + +/** + * + * @author nigelzor + */ +public class MomirFreeForAllType extends MatchType { + + public MomirFreeForAllType() { + this.name = "Momir Basic Free For All"; + this.maxPlayers = 10; + this.minPlayers = 2; + this.numTeams = 0; + this.useAttackOption = true; + this.useRange = true; + this.sideboardingAllowed = false; + } + + protected MomirFreeForAllType(final MomirFreeForAllType matchType){ + super(matchType); + } + + @Override + public MomirFreeForAllType copy() { + return new MomirFreeForAllType(this); + } + +} diff --git a/Mage.Server.Plugins/Mage.Game.MomirGame/src/mage/game/MomirGame.java b/Mage.Server.Plugins/Mage.Game.MomirGame/src/mage/game/MomirGame.java new file mode 100644 index 0000000000..5627da1695 --- /dev/null +++ b/Mage.Server.Plugins/Mage.Game.MomirGame/src/mage/game/MomirGame.java @@ -0,0 +1,105 @@ +/* + * Copyright 2010 BetaSteward_at_googlemail.com. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are + * permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this list of + * conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, this list + * of conditions and the following disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY BetaSteward_at_googlemail.com ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BetaSteward_at_googlemail.com OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * The views and conclusions contained in the software and documentation are those of the + * authors and should not be interpreted as representing official policies, either expressed + * or implied, of BetaSteward_at_googlemail.com. + */ +package mage.game; + +import java.util.HashSet; +import java.util.Set; +import java.util.UUID; +import mage.abilities.Ability; +import mage.abilities.common.SimpleStaticAbility; +import mage.abilities.effects.common.InfoEffect; +import mage.cards.repository.CardInfo; +import mage.cards.repository.CardRepository; +import mage.constants.MultiplayerAttackOption; +import mage.constants.PhaseStep; +import mage.constants.RangeOfInfluence; +import mage.constants.Zone; +import mage.game.command.emblems.MomirEmblem; +import mage.game.match.MatchType; +import mage.game.turn.TurnMod; +import mage.players.Player; + + +/** + * + * @author nigelzor + */ +public class MomirGame extends FreeForAll { + + private int numPlayers; + + public MomirGame(MultiplayerAttackOption attackOption, RangeOfInfluence range, int freeMulligans, int startLife) { + super(attackOption, range, freeMulligans, startLife); + } + + public MomirGame(final MomirGame game) { + super(game); + } + + @Override + public MatchType getGameType() { + return new MomirFreeForAllType(); + } + + @Override + public int getNumPlayers() { + return numPlayers; + } + + @Override + protected void init(UUID choosingPlayerId) { + Ability ability = new SimpleStaticAbility(Zone.COMMAND, new InfoEffect("Vanguard effects")); + for (UUID playerId : state.getPlayerList(startingPlayerId)) { + Player player = getPlayer(playerId); + if (player != null) { + CardInfo cardInfo = CardRepository.instance.findCard("Momir Vig, Simic Visionary"); + addEmblem(new MomirEmblem(), cardInfo.getCard(), playerId); + } + } + getState().addAbility(ability, null); + super.init(choosingPlayerId); + state.getTurnMods().add(new TurnMod(startingPlayerId, PhaseStep.DRAW)); + } + + @Override + public Set getOpponents(UUID playerId) { + Set opponents = new HashSet<>(); + for (UUID opponentId : this.getPlayer(playerId).getInRange()) { + if (!opponentId.equals(playerId)) { + opponents.add(opponentId); + } + } + return opponents; + } + + @Override + public MomirGame copy() { + return new MomirGame(this); + } + +} diff --git a/Mage.Server.Plugins/Mage.Game.PennyDreadfulCommanderFreeForAll/target/maven-archiver/pom.properties b/Mage.Server.Plugins/Mage.Game.PennyDreadfulCommanderFreeForAll/target/maven-archiver/pom.properties index 9ea86aa6e9..8603daf326 100644 --- a/Mage.Server.Plugins/Mage.Game.PennyDreadfulCommanderFreeForAll/target/maven-archiver/pom.properties +++ b/Mage.Server.Plugins/Mage.Game.PennyDreadfulCommanderFreeForAll/target/maven-archiver/pom.properties @@ -1,5 +1,5 @@ #Generated by Maven -#Fri Sep 15 22:14:29 CEST 2017 +#Sun Oct 22 00:34:49 EDT 2017 version=1.4.26 groupId=org.mage artifactId=mage-game-pennydreadfulcommanderfreeforall diff --git a/Mage.Server.Plugins/Mage.Player.AI.MA/src/mage/player/ai/ComputerPlayer6.java b/Mage.Server.Plugins/Mage.Player.AI.MA/src/mage/player/ai/ComputerPlayer6.java index db6da80b74..f281d360e2 100644 --- a/Mage.Server.Plugins/Mage.Player.AI.MA/src/mage/player/ai/ComputerPlayer6.java +++ b/Mage.Server.Plugins/Mage.Player.AI.MA/src/mage/player/ai/ComputerPlayer6.java @@ -519,7 +519,7 @@ public class ComputerPlayer6 extends ComputerPlayer /*implements Player*/ { logger.trace("interrupted - " + val); return val; } - if (depth <= 0 || SimulationNode2.nodeCount > maxNodes || game.gameOver(null)) { + if (depth <= 0 || SimulationNode2.nodeCount > maxNodes || game.checkIfGameIsOver()) { logger.trace("Add actions -- reached end state, node count=" + SimulationNode2.nodeCount + ", depth=" + depth); val = GameStateEvaluator2.evaluate(playerId, game); UUID currentPlayerId = node.getGame().getPlayerList().get(); @@ -540,7 +540,7 @@ public class ComputerPlayer6 extends ComputerPlayer /*implements Player*/ { } } - if (game.gameOver(null)) { + if (game.checkIfGameIsOver()) { val = GameStateEvaluator2.evaluate(playerId, game); } else if (!node.getChildren().isEmpty()) { //declared attackers or blockers or triggered abilities @@ -588,7 +588,7 @@ public class ComputerPlayer6 extends ComputerPlayer /*implements Player*/ { logger.debug("Sim Prio [" + depth + "] -- repeated action: " + action.toString()); continue; } - if (!sim.gameOver(null) && action.isUsesStack()) { + if (!sim.checkIfGameIsOver() && action.isUsesStack()) { // only pass if the last action uses the stack UUID nextPlayerId = sim.getPlayerList().get(); do { @@ -864,7 +864,7 @@ public class ComputerPlayer6 extends ComputerPlayer /*implements Player*/ { break; case CLEANUP: game.getPhase().getStep().beginStep(game, activePlayerId); - if (!game.checkStateAndTriggered() && !game.gameOver(null)) { + if (!game.checkStateAndTriggered() && !game.checkIfGameIsOver()) { game.getState().setActivePlayerId(game.getState().getPlayerList(game.getActivePlayerId()).getNext()); game.getTurn().setPhase(new BeginningPhase()); game.getPhase().setStep(new UntapStep()); diff --git a/Mage.Server.Plugins/Mage.Player.AI.MA/src/mage/player/ai/ComputerPlayer7.java b/Mage.Server.Plugins/Mage.Player.AI.MA/src/mage/player/ai/ComputerPlayer7.java index 99bce93ce8..28cd4879ae 100644 --- a/Mage.Server.Plugins/Mage.Player.AI.MA/src/mage/player/ai/ComputerPlayer7.java +++ b/Mage.Server.Plugins/Mage.Player.AI.MA/src/mage/player/ai/ComputerPlayer7.java @@ -161,10 +161,9 @@ public class ComputerPlayer7 extends ComputerPlayer6 { Game sim = createSimulation(game); SimulationNode2.resetCount(); root = new SimulationNode2(null, sim, maxDepth, playerId); - addActionsTimed(); - logger.trace("After add actions timed: root.children.size = " + root.children.size()); - if (!root.children.isEmpty()) { + if (root.children != null && !root.children.isEmpty()) { + logger.trace("After add actions timed: root.children.size = " + root.children.size()); root = root.children.get(0); // int bestScore = root.getScore(); // if (bestScore > currentScore || allowBadMoves) { @@ -233,7 +232,7 @@ public class ComputerPlayer7 extends ComputerPlayer6 { return GameStateEvaluator2.evaluate(playerId, game); } // Condition to stop deeper simulation - if (depth <= 0 || SimulationNode2.nodeCount > maxNodes || game.gameOver(null)) { + if (depth <= 0 || SimulationNode2.nodeCount > maxNodes || game.checkIfGameIsOver()) { val = GameStateEvaluator2.evaluate(playerId, game); if (logger.isTraceEnabled()) { StringBuilder sb = new StringBuilder("Add Actions -- reached end state <").append(val).append('>'); @@ -267,7 +266,7 @@ public class ComputerPlayer7 extends ComputerPlayer6 { } } - if (game.gameOver(null)) { + if (game.checkIfGameIsOver()) { val = GameStateEvaluator2.evaluate(playerId, game); } else if (stepFinished) { logger.debug("Step finished"); @@ -481,7 +480,7 @@ public class ComputerPlayer7 extends ComputerPlayer6 { sim.fireEvent(GameEvent.getEvent(GameEvent.EventType.DECLARE_BLOCKERS_STEP_POST, sim.getActivePlayerId(), sim.getActivePlayerId())); Combat simCombat = sim.getCombat().copy(); finishCombat(sim); - if (sim.gameOver(null)) { + if (sim.checkIfGameIsOver()) { val = GameStateEvaluator2.evaluate(playerId, sim); } else if (!counter) { val = simulatePostCombatMain(sim, newNode, depth - 1, alpha, beta); @@ -549,7 +548,7 @@ public class ComputerPlayer7 extends ComputerPlayer6 { logger.debug("interrupted"); return; } - if (!game.gameOver(null)) { + if (!game.checkIfGameIsOver()) { game.getPhase().setStep(step); if (!step.skipStep(game, game.getActivePlayerId())) { step.beginStep(game, game.getActivePlayerId()); @@ -598,7 +597,7 @@ public class ComputerPlayer7 extends ComputerPlayer6 { logger.debug("interrupted"); return; } - if (!game.gameOver(null)) { + if (!game.checkIfGameIsOver()) { game.getTurn().getPhase().endPhase(game, game.getActivePlayerId()); game.getTurn().setPhase(new EndPhase()); if (game.getTurn().getPhase().beginPhase(game, game.getActivePlayerId())) { diff --git a/Mage.Server.Plugins/Mage.Player.AI.MA/src/mage/player/ai/GameStateEvaluator2.java b/Mage.Server.Plugins/Mage.Player.AI.MA/src/mage/player/ai/GameStateEvaluator2.java index 09f8b29123..580f47ba32 100644 --- a/Mage.Server.Plugins/Mage.Player.AI.MA/src/mage/player/ai/GameStateEvaluator2.java +++ b/Mage.Server.Plugins/Mage.Player.AI.MA/src/mage/player/ai/GameStateEvaluator2.java @@ -33,7 +33,7 @@ public final class GameStateEvaluator2 { public static int evaluate(UUID playerId, Game game) { Player player = game.getPlayer(playerId); Player opponent = game.getPlayer(game.getOpponents(playerId).iterator().next()); - if (game.gameOver(null)) { + if (game.checkIfGameIsOver()) { if (player.hasLost() || opponent.hasWon()) { return LOSE_GAME_SCORE; } diff --git a/Mage.Server.Plugins/Mage.Player.AI/src/main/java/mage/player/ai/simulators/ActionSimulator.java b/Mage.Server.Plugins/Mage.Player.AI/src/main/java/mage/player/ai/simulators/ActionSimulator.java index b18c34dec5..e466891d3e 100644 --- a/Mage.Server.Plugins/Mage.Player.AI/src/main/java/mage/player/ai/simulators/ActionSimulator.java +++ b/Mage.Server.Plugins/Mage.Player.AI/src/main/java/mage/player/ai/simulators/ActionSimulator.java @@ -61,7 +61,7 @@ public class ActionSimulator { public int evaluateState() { Player opponent = game.getPlayer(game.getOpponents(player.getId()).iterator().next()); - if (game.gameOver(null)) { + if (game.checkIfGameIsOver()) { if (player.hasLost() || opponent.hasWon()) { return Integer.MIN_VALUE; } diff --git a/Mage.Server.Plugins/Mage.Player.AIMCTS/src/mage/player/ai/MCTSNode.java b/Mage.Server.Plugins/Mage.Player.AIMCTS/src/mage/player/ai/MCTSNode.java index 7eef75f10e..86a6096798 100644 --- a/Mage.Server.Plugins/Mage.Player.AIMCTS/src/mage/player/ai/MCTSNode.java +++ b/Mage.Server.Plugins/Mage.Player.AIMCTS/src/mage/player/ai/MCTSNode.java @@ -79,7 +79,7 @@ public class MCTSNode { this.game = game; this.stateValue = game.getState().getValue(game, targetPlayer); this.fullStateValue = game.getState().getValue(true, game); - this.terminal = game.gameOver(null); + this.terminal = game.checkIfGameIsOver(); setPlayer(); nodeCount = 1; // logger.info(this.stateValue); @@ -90,7 +90,7 @@ public class MCTSNode { this.game = game; this.stateValue = game.getState().getValue(game, targetPlayer); this.fullStateValue = game.getState().getValue(true, game); - this.terminal = game.gameOver(null); + this.terminal = game.checkIfGameIsOver(); this.parent = parent; this.action = action; setPlayer(); @@ -104,7 +104,7 @@ public class MCTSNode { this.combat = combat; this.stateValue = game.getState().getValue(game, targetPlayer); this.fullStateValue = game.getState().getValue(true, game); - this.terminal = game.gameOver(null); + this.terminal = game.checkIfGameIsOver(); this.parent = parent; setPlayer(); nodeCount++; diff --git a/Mage.Server.Plugins/Mage.Player.AIMinimax/src/mage/player/ai/ComputerPlayer2.java b/Mage.Server.Plugins/Mage.Player.AIMinimax/src/mage/player/ai/ComputerPlayer2.java index 681fcac0fb..fa86b2205a 100644 --- a/Mage.Server.Plugins/Mage.Player.AIMinimax/src/mage/player/ai/ComputerPlayer2.java +++ b/Mage.Server.Plugins/Mage.Player.AIMinimax/src/mage/player/ai/ComputerPlayer2.java @@ -330,7 +330,7 @@ public class ComputerPlayer2 extends ComputerPlayer implements Player { return GameStateEvaluator.evaluate(playerId, game); } int val; - if (node.depth > maxDepth || game.gameOver(null)) { + if (node.depth > maxDepth || game.checkIfGameIsOver()) { logger.debug(indent(node.depth) + "simulating -- reached end state"); val = GameStateEvaluator.evaluate(playerId, game); } @@ -357,7 +357,7 @@ public class ComputerPlayer2 extends ComputerPlayer implements Player { } } - if (game.gameOver(null)) { + if (game.checkIfGameIsOver()) { val = GameStateEvaluator.evaluate(playerId, game); } else if (!node.getChildren().isEmpty()) { @@ -403,7 +403,7 @@ public class ComputerPlayer2 extends ComputerPlayer implements Player { logger.debug(indent(node.depth) + "found useless action: " + action); continue; } - if (!sim.gameOver(null) && action.isUsesStack()) { + if (!sim.checkIfGameIsOver() && action.isUsesStack()) { // only pass if the last action uses the stack sim.getPlayer(currentPlayer.getId()).pass(game); sim.getPlayerList().getNext(); @@ -588,7 +588,7 @@ public class ComputerPlayer2 extends ComputerPlayer implements Player { break; case CLEANUP: game.getPhase().getStep().beginStep(game, activePlayerId); - if (!game.checkStateAndTriggered() && !game.gameOver(null)) { + if (!game.checkStateAndTriggered() && !game.checkIfGameIsOver()) { game.getState().setActivePlayerId(game.getState().getPlayerList(game.getActivePlayerId()).getNext()); game.getTurn().setPhase(new BeginningPhase()); game.getPhase().setStep(new UntapStep()); diff --git a/Mage.Server.Plugins/Mage.Player.AIMinimax/src/mage/player/ai/ComputerPlayer3.java b/Mage.Server.Plugins/Mage.Player.AIMinimax/src/mage/player/ai/ComputerPlayer3.java index b523360807..ec7c6f409d 100644 --- a/Mage.Server.Plugins/Mage.Player.AIMinimax/src/mage/player/ai/ComputerPlayer3.java +++ b/Mage.Server.Plugins/Mage.Player.AIMinimax/src/mage/player/ai/ComputerPlayer3.java @@ -184,7 +184,7 @@ public class ComputerPlayer3 extends ComputerPlayer2 implements Player { logger.debug(indent(node.depth) + "interrupted"); return GameStateEvaluator.evaluate(playerId, game); } - if (node.depth > maxDepth || game.gameOver(null)) { + if (node.depth > maxDepth || game.checkIfGameIsOver()) { logger.debug(indent(node.depth) + "simulating -- reached end state"); val = GameStateEvaluator.evaluate(playerId, game); } @@ -204,7 +204,7 @@ public class ComputerPlayer3 extends ComputerPlayer2 implements Player { } } - if (game.gameOver(null)) { + if (game.checkIfGameIsOver()) { val = GameStateEvaluator.evaluate(playerId, game); } else if (stepFinished) { @@ -408,7 +408,7 @@ public class ComputerPlayer3 extends ComputerPlayer2 implements Player { sim.fireEvent(GameEvent.getEvent(GameEvent.EventType.DECLARE_BLOCKERS_STEP_POST, sim.getActivePlayerId(), sim.getActivePlayerId())); Combat simCombat = sim.getCombat().copy(); finishCombat(sim); - if (sim.gameOver(null)) { + if (sim.checkIfGameIsOver()) { val = GameStateEvaluator.evaluate(playerId, sim); } else if (!counter) { @@ -450,7 +450,7 @@ public class ComputerPlayer3 extends ComputerPlayer2 implements Player { return GameStateEvaluator.evaluate(playerId, game); } Integer val = null; - if (!game.gameOver(null)) { + if (!game.checkIfGameIsOver()) { logger.debug(indent(node.depth) + "simulating -- ending turn"); simulateToEnd(game); game.getState().setActivePlayerId(game.getState().getPlayerList(game.getActivePlayerId()).getNext()); @@ -478,7 +478,7 @@ public class ComputerPlayer3 extends ComputerPlayer2 implements Player { logger.debug("interrupted"); return; } - if (!game.gameOver(null)) { + if (!game.checkIfGameIsOver()) { game.getPhase().setStep(step); if (!step.skipStep(game, game.getActivePlayerId())) { step.beginStep(game, game.getActivePlayerId()); @@ -526,7 +526,7 @@ public class ComputerPlayer3 extends ComputerPlayer2 implements Player { logger.debug("interrupted"); return; } - if (!game.gameOver(null)) { + if (!game.checkIfGameIsOver()) { game.getTurn().getPhase().endPhase(game, game.getActivePlayerId()); game.getTurn().setPhase(new EndPhase()); if (game.getTurn().getPhase().beginPhase(game, game.getActivePlayerId())) { diff --git a/Mage.Server.Plugins/Mage.Player.AIMinimax/src/mage/player/ai/GameStateEvaluator.java b/Mage.Server.Plugins/Mage.Player.AIMinimax/src/mage/player/ai/GameStateEvaluator.java index e45943dad8..df9e389d03 100644 --- a/Mage.Server.Plugins/Mage.Player.AIMinimax/src/mage/player/ai/GameStateEvaluator.java +++ b/Mage.Server.Plugins/Mage.Player.AIMinimax/src/mage/player/ai/GameStateEvaluator.java @@ -70,7 +70,7 @@ public final class GameStateEvaluator { public static int evaluate(UUID playerId, Game game, boolean ignoreTapped) { Player player = game.getPlayer(playerId); Player opponent = game.getPlayer(game.getOpponents(playerId).iterator().next()); - if (game.gameOver(null)) { + if (game.checkIfGameIsOver()) { if (player.hasLost() || opponent.hasWon()) return LOSE_SCORE; if (opponent.hasLost() || player.hasWon()) diff --git a/Mage.Server.Plugins/Mage.Player.Human/src/mage/player/human/HumanPlayer.java b/Mage.Server.Plugins/Mage.Player.Human/src/mage/player/human/HumanPlayer.java index 1e934e1915..97fa23bab8 100644 --- a/Mage.Server.Plugins/Mage.Player.Human/src/mage/player/human/HumanPlayer.java +++ b/Mage.Server.Plugins/Mage.Player.Human/src/mage/player/human/HumanPlayer.java @@ -53,6 +53,7 @@ import mage.filter.common.FilterCreatureForCombat; import mage.filter.common.FilterCreatureForCombatBlock; import mage.filter.predicate.permanent.ControllerIdPredicate; import mage.game.Game; +import mage.game.GameImpl; import mage.game.combat.CombatGroup; import mage.game.draft.Draft; import mage.game.events.GameEvent; @@ -186,13 +187,27 @@ public class HumanPlayer extends PlayerImpl { response.clear(); logger.debug("Waiting response from player: " + getId()); game.resumeTimer(getTurnControlledBy()); - synchronized (response) { - try { - response.wait(); - } catch (InterruptedException ex) { - logger.error("Response error for player " + getName() + " gameId: " + game.getId(), ex); - } finally { - game.pauseTimer(getTurnControlledBy()); + boolean loop = true; + while (loop) { + loop = false; + synchronized (response) { + try { + response.wait(); + } catch (InterruptedException ex) { + logger.error("Response error for player " + getName() + " gameId: " + game.getId(), ex); + } finally { + game.pauseTimer(getTurnControlledBy()); + } + } + if (response.getResponseConcedeCheck()) { + ((GameImpl) game).checkConcede(); + if (game.hasEnded()) { + return; + } + response.clear(); + if (isInGame()) { + loop = true; + } } } if (recordingMacro && !macroTriggeredSelectionFlag) { @@ -1706,6 +1721,15 @@ public class HumanPlayer extends PlayerImpl { } } + @Override + public void signalPlayerConcede() { + synchronized (response) { + response.setResponseConcedeCheck(); + response.notifyAll(); + logger.debug("Set check concede for waiting player: " + getId()); + } + } + @Override public void skip() { synchronized (response) { diff --git a/Mage.Server.Plugins/Mage.Player.Human/src/mage/player/human/PlayerResponse.java b/Mage.Server.Plugins/Mage.Player.Human/src/mage/player/human/PlayerResponse.java index 2f1e5871c2..b4e7b063bd 100644 --- a/Mage.Server.Plugins/Mage.Player.Human/src/mage/player/human/PlayerResponse.java +++ b/Mage.Server.Plugins/Mage.Player.Human/src/mage/player/human/PlayerResponse.java @@ -43,6 +43,7 @@ public class PlayerResponse implements Serializable { private Integer responseInteger; private ManaType responseManaType; private UUID responseManaTypePlayerId; + private Boolean responseConcedeCheck; public PlayerResponse() { clear(); @@ -55,7 +56,8 @@ public class PlayerResponse implements Serializable { + ',' + responseBoolean + ',' + responseInteger + ',' + responseManaType - + ',' + responseManaTypePlayerId; + + ',' + responseManaTypePlayerId + + ',' + responseConcedeCheck; } public PlayerResponse(PlayerResponse other) { @@ -69,6 +71,7 @@ public class PlayerResponse implements Serializable { responseInteger = other.responseInteger; responseManaType = other.responseManaType; responseManaTypePlayerId = other.responseManaTypePlayerId; + responseConcedeCheck = other.responseConcedeCheck; } public void clear() { @@ -78,6 +81,7 @@ public class PlayerResponse implements Serializable { responseInteger = null; responseManaType = null; responseManaTypePlayerId = null; + responseConcedeCheck = null; } public String getString() { @@ -104,6 +108,17 @@ public class PlayerResponse implements Serializable { this.responseBoolean = responseBoolean; } + public Boolean getResponseConcedeCheck() { + if (responseConcedeCheck == null) { + return false; + } + return responseConcedeCheck; + } + + public void setResponseConcedeCheck() { + this.responseConcedeCheck = true; + } + public Integer getInteger() { return responseInteger; } diff --git a/Mage.Server.Plugins/Mage.Tournament.BoosterDraft/src/mage/tournament/cubes/AdamStyborskisPauperCube.java b/Mage.Server.Plugins/Mage.Tournament.BoosterDraft/src/mage/tournament/cubes/AdamStyborskisPauperCube.java index ba99a83ba6..4ef11e8d50 100644 --- a/Mage.Server.Plugins/Mage.Tournament.BoosterDraft/src/mage/tournament/cubes/AdamStyborskisPauperCube.java +++ b/Mage.Server.Plugins/Mage.Tournament.BoosterDraft/src/mage/tournament/cubes/AdamStyborskisPauperCube.java @@ -35,9 +35,9 @@ import mage.game.draft.DraftCube; */ public class AdamStyborskisPauperCube extends DraftCube { -public AdamStyborskisPauperCube() { + public AdamStyborskisPauperCube() { super("Adam Styborkski's Pauper Cube"); // https://docs.google.com/spreadsheets/d/12iQhC4bHqFW7hEWxPBjyC8yBDehFZ0_4DkqzyA8EL3o/edit#gid=0 - // last updated with Amonkhet 6/12/17 + // last updated with Hour of Devastation, Iconic Masters and Ixalan 10/18/17 cubeCards.add(new CardIdentity("Act of Treason", "")); cubeCards.add(new CardIdentity("Adventuring Gear", "")); cubeCards.add(new CardIdentity("Aerie Ouphes", "")); @@ -45,6 +45,7 @@ public AdamStyborskisPauperCube() { cubeCards.add(new CardIdentity("Aethersnipe", "")); cubeCards.add(new CardIdentity("Agony Warp", "")); cubeCards.add(new CardIdentity("Aim High", "")); + cubeCards.add(new CardIdentity("Ambuscade", "")); cubeCards.add(new CardIdentity("Ambush Viper", "")); cubeCards.add(new CardIdentity("Angelic Purge", "")); cubeCards.add(new CardIdentity("Arachnus Web", "")); @@ -55,18 +56,18 @@ public AdamStyborskisPauperCube() { cubeCards.add(new CardIdentity("Ashes to Ashes", "")); cubeCards.add(new CardIdentity("Assault Zeppelid", "")); cubeCards.add(new CardIdentity("Attended Knight", "")); - cubeCards.add(new CardIdentity("Augur of Bolas", "")); cubeCards.add(new CardIdentity("Auger Spree", "")); + cubeCards.add(new CardIdentity("Augur of Bolas", "")); cubeCards.add(new CardIdentity("Aven Riftwatcher", "")); cubeCards.add(new CardIdentity("Aven Surveyor", "")); cubeCards.add(new CardIdentity("Azorius Guildgate", "")); cubeCards.add(new CardIdentity("Baleful Eidolon", "")); cubeCards.add(new CardIdentity("Barbed Lightning", "")); - cubeCards.add(new CardIdentity("Barren Moor", "")); cubeCards.add(new CardIdentity("Basking Rootwalla", "")); cubeCards.add(new CardIdentity("Battle Screech", "")); cubeCards.add(new CardIdentity("Beetleback Chief", "")); cubeCards.add(new CardIdentity("Beetleform Mage", "")); + cubeCards.add(new CardIdentity("Beneath the Sands", "")); cubeCards.add(new CardIdentity("Blastoderm", "")); cubeCards.add(new CardIdentity("Blazing Torch", "")); cubeCards.add(new CardIdentity("Blightning", "")); @@ -78,8 +79,9 @@ public AdamStyborskisPauperCube() { cubeCards.add(new CardIdentity("Bonesplitter", "")); cubeCards.add(new CardIdentity("Borderland Marauder", "")); cubeCards.add(new CardIdentity("Boros Guildgate", "")); - cubeCards.add(new CardIdentity("Borrowed Grave", "")); + cubeCards.add(new CardIdentity("Borrowed Grace", "")); cubeCards.add(new CardIdentity("Branching Bolt", "")); + cubeCards.add(new CardIdentity("Brazen Buccaneers", "")); cubeCards.add(new CardIdentity("Brazen Wolves", "")); cubeCards.add(new CardIdentity("Burning-Tree Emissary", "")); cubeCards.add(new CardIdentity("Burst Lightning", "")); @@ -97,6 +99,7 @@ public AdamStyborskisPauperCube() { cubeCards.add(new CardIdentity("Chain Lightning", "")); cubeCards.add(new CardIdentity("Chainer's Edict", "")); cubeCards.add(new CardIdentity("Chatter of the Squirrel", "")); + cubeCards.add(new CardIdentity("Cinder Barrens", "")); cubeCards.add(new CardIdentity("Citanul Woodreaders", "")); cubeCards.add(new CardIdentity("Claustrophobia", "")); cubeCards.add(new CardIdentity("Clay Statue", "")); @@ -108,15 +111,12 @@ public AdamStyborskisPauperCube() { cubeCards.add(new CardIdentity("Compulsive Research", "")); cubeCards.add(new CardIdentity("Compulsory Rest", "")); cubeCards.add(new CardIdentity("Consume Strength", "")); - cubeCards.add(new CardIdentity("Corpse Churn", "")); cubeCards.add(new CardIdentity("Corrupted Zendikon", "")); cubeCards.add(new CardIdentity("Counterspell", "")); cubeCards.add(new CardIdentity("Crippling Fatigue", "")); cubeCards.add(new CardIdentity("Crow of Dark Tidings", "")); cubeCards.add(new CardIdentity("Crypt Rats", "")); cubeCards.add(new CardIdentity("Crystallization", "")); - cubeCards.add(new CardIdentity("Cultist's Staff", "")); - cubeCards.add(new CardIdentity("Cultivate", "")); cubeCards.add(new CardIdentity("Cunning Strike", "")); cubeCards.add(new CardIdentity("Curse of Chains", "")); cubeCards.add(new CardIdentity("Custodi Squire", "")); @@ -124,9 +124,11 @@ public AdamStyborskisPauperCube() { cubeCards.add(new CardIdentity("Dauntless Cathar", "")); cubeCards.add(new CardIdentity("Dead Reveler", "")); cubeCards.add(new CardIdentity("Dead Weight", "")); + cubeCards.add(new CardIdentity("Deadeye Tormentor", "")); cubeCards.add(new CardIdentity("Death Denied", "")); cubeCards.add(new CardIdentity("Deep Analysis", "")); cubeCards.add(new CardIdentity("Deprive", "")); + cubeCards.add(new CardIdentity("Depths of Desire", "")); cubeCards.add(new CardIdentity("Deputy of Acquittals", "")); cubeCards.add(new CardIdentity("Desert", "")); cubeCards.add(new CardIdentity("Desperate Sentry", "")); @@ -134,6 +136,7 @@ public AdamStyborskisPauperCube() { cubeCards.add(new CardIdentity("Diabolic Edict", "")); cubeCards.add(new CardIdentity("Dimir Guildgate", "")); cubeCards.add(new CardIdentity("Dinrova Horror", "")); + cubeCards.add(new CardIdentity("Dire Fleet Hoarder", "")); cubeCards.add(new CardIdentity("Disfigure", "")); cubeCards.add(new CardIdentity("Dismal Backwater", "")); cubeCards.add(new CardIdentity("Disowned Ancestor", "")); @@ -152,20 +155,21 @@ public AdamStyborskisPauperCube() { cubeCards.add(new CardIdentity("Epic Confrontation", "")); cubeCards.add(new CardIdentity("Errant Ephemeron", "")); cubeCards.add(new CardIdentity("Esper Cormorants", "")); - cubeCards.add(new CardIdentity("Essence Scatter", "")); cubeCards.add(new CardIdentity("Evincar's Justice", "")); cubeCards.add(new CardIdentity("Evolving Wilds", "")); cubeCards.add(new CardIdentity("Faceless Butcher", "")); cubeCards.add(new CardIdentity("Faith's Fetters", "")); + cubeCards.add(new CardIdentity("Falkenrath Noble", "")); cubeCards.add(new CardIdentity("Feeling of Dread", "")); - cubeCards.add(new CardIdentity("Fertile Thicket", "")); cubeCards.add(new CardIdentity("Fervent Cathar", "")); cubeCards.add(new CardIdentity("Firebolt", "")); cubeCards.add(new CardIdentity("Fireslinger", "")); cubeCards.add(new CardIdentity("Flayer Husk", "")); cubeCards.add(new CardIdentity("Flurry of Horns", "")); cubeCards.add(new CardIdentity("Forked Bolt", "")); + cubeCards.add(new CardIdentity("Forsaken Sanctuary", "")); cubeCards.add(new CardIdentity("Fortify", "")); + cubeCards.add(new CardIdentity("Foul Orchard", "")); cubeCards.add(new CardIdentity("Frilled Oculus", "")); cubeCards.add(new CardIdentity("Frostburn Weird", "")); cubeCards.add(new CardIdentity("Gathan Raiders", "")); @@ -182,21 +186,22 @@ public AdamStyborskisPauperCube() { cubeCards.add(new CardIdentity("Gods Willing", "")); cubeCards.add(new CardIdentity("Goldmeadow Harrier", "")); cubeCards.add(new CardIdentity("Golgari Guildgate", "")); - cubeCards.add(new CardIdentity("Grapple with the Past", "")); cubeCards.add(new CardIdentity("Gravedigger", "")); cubeCards.add(new CardIdentity("Gray Merchant of Asphodel", "")); + cubeCards.add(new CardIdentity("Grazing Whiptail", "")); cubeCards.add(new CardIdentity("Grim Contest", "")); cubeCards.add(new CardIdentity("Grisly Salvage", "")); cubeCards.add(new CardIdentity("Grixis Slavedriver", "")); cubeCards.add(new CardIdentity("Gruul Guildgate", "")); cubeCards.add(new CardIdentity("Gryff Vanguard", "")); cubeCards.add(new CardIdentity("Guardian Automaton", "")); + cubeCards.add(new CardIdentity("Guardian Idol", "")); cubeCards.add(new CardIdentity("Guardian of the Guildpact", "")); cubeCards.add(new CardIdentity("Gurmag Angler", "")); - cubeCards.add(new CardIdentity("Halimar Depths", "")); cubeCards.add(new CardIdentity("Halimar Wavewatch", "")); cubeCards.add(new CardIdentity("Harrow", "")); cubeCards.add(new CardIdentity("Harsh Sustenance", "")); + cubeCards.add(new CardIdentity("Highland Lake", "")); cubeCards.add(new CardIdentity("Hissing Iguanar", "")); cubeCards.add(new CardIdentity("Hooting Mandrills", "")); cubeCards.add(new CardIdentity("Humble", "")); @@ -206,6 +211,7 @@ public AdamStyborskisPauperCube() { cubeCards.add(new CardIdentity("Insolent Neonate", "")); cubeCards.add(new CardIdentity("Into the Roil", "")); cubeCards.add(new CardIdentity("Isolation Zone", "")); + cubeCards.add(new CardIdentity("Ivy Elemental", "")); cubeCards.add(new CardIdentity("Izzet Chronarch", "")); cubeCards.add(new CardIdentity("Izzet Guildgate", "")); cubeCards.add(new CardIdentity("Jilt", "")); @@ -214,7 +220,6 @@ public AdamStyborskisPauperCube() { cubeCards.add(new CardIdentity("Kabuto Moth", "")); cubeCards.add(new CardIdentity("Keldon Marauders", "")); cubeCards.add(new CardIdentity("Kingpin's Pet", "")); - cubeCards.add(new CardIdentity("Kodama's Reach", "")); cubeCards.add(new CardIdentity("Kor Skyfisher", "")); cubeCards.add(new CardIdentity("Kozilek's Channeler", "")); cubeCards.add(new CardIdentity("Krenko's Command", "")); @@ -222,25 +227,24 @@ public AdamStyborskisPauperCube() { cubeCards.add(new CardIdentity("Kruin Striker", "")); cubeCards.add(new CardIdentity("Lash Out", "")); cubeCards.add(new CardIdentity("Last Gasp", "")); - cubeCards.add(new CardIdentity("Lawless Broker", "")); + cubeCards.add(new CardIdentity("Leave in the Dust", "")); cubeCards.add(new CardIdentity("Leonin Bola", "")); - cubeCards.add(new CardIdentity("Leonin Scimitar", "")); + cubeCards.add(new CardIdentity("Lifecraft Cavalry", "")); cubeCards.add(new CardIdentity("Lightning Bolt", "")); cubeCards.add(new CardIdentity("Liliana's Specter", "")); - cubeCards.add(new CardIdentity("Looming Spires", "")); cubeCards.add(new CardIdentity("Lotus Path Djinn", "")); cubeCards.add(new CardIdentity("Loyal Pegasus", "")); cubeCards.add(new CardIdentity("Lurking Automaton", "")); cubeCards.add(new CardIdentity("Magma Jet", "")); cubeCards.add(new CardIdentity("Makeshift Mauler", "")); + cubeCards.add(new CardIdentity("Man-o'-War", "")); cubeCards.add(new CardIdentity("Mana Leak", "")); cubeCards.add(new CardIdentity("Manticore of the Gauntlet", "")); - cubeCards.add(new CardIdentity("Man-o'-War", "")); cubeCards.add(new CardIdentity("Mardu Hordechief", "")); cubeCards.add(new CardIdentity("Mardu Skullhunter", "")); cubeCards.add(new CardIdentity("Maul Splicer", "")); - cubeCards.add(new CardIdentity("Maulfist Squad", "")); cubeCards.add(new CardIdentity("Maze of Ith", "")); + cubeCards.add(new CardIdentity("Meandering River", "")); cubeCards.add(new CardIdentity("Mental Note", "")); cubeCards.add(new CardIdentity("Midnight Scavengers", "")); cubeCards.add(new CardIdentity("Mind Stone", "")); @@ -249,6 +253,7 @@ public AdamStyborskisPauperCube() { cubeCards.add(new CardIdentity("Mishra's Factory", "")); cubeCards.add(new CardIdentity("Mist Raven", "")); cubeCards.add(new CardIdentity("Mistral Charger", "")); + cubeCards.add(new CardIdentity("Mobile Garrison", "")); cubeCards.add(new CardIdentity("Mogg Fanatic", "")); cubeCards.add(new CardIdentity("Mogg Flunkies", "")); cubeCards.add(new CardIdentity("Mogg War Marshal", "")); @@ -260,17 +265,17 @@ public AdamStyborskisPauperCube() { cubeCards.add(new CardIdentity("Narcolepsy", "")); cubeCards.add(new CardIdentity("Necromancer's Assistant", "")); cubeCards.add(new CardIdentity("Nessian Asp", "")); + cubeCards.add(new CardIdentity("Nest Robber", "")); cubeCards.add(new CardIdentity("Nezumi Cutthroat", "")); cubeCards.add(new CardIdentity("Night's Whisper", "")); cubeCards.add(new CardIdentity("Nightscape Familiar", "")); cubeCards.add(new CardIdentity("Ninja of the Deep Hours", "")); cubeCards.add(new CardIdentity("Oblivion Ring", "")); cubeCards.add(new CardIdentity("Oona's Grace", "")); - cubeCards.add(new CardIdentity("Orcish Oriflamme", "")); cubeCards.add(new CardIdentity("Orzhov Guildgate", "")); cubeCards.add(new CardIdentity("Otherworldly Journey", "")); cubeCards.add(new CardIdentity("Pacifism", "")); - cubeCards.add(new CardIdentity("Palace Sentinels", "")); + cubeCards.add(new CardIdentity("Paladin of the Bloodstained", "")); cubeCards.add(new CardIdentity("Peema Outrider", "")); cubeCards.add(new CardIdentity("Penumbra Spider", "")); cubeCards.add(new CardIdentity("Peregrine Drake", "")); @@ -287,7 +292,7 @@ public AdamStyborskisPauperCube() { cubeCards.add(new CardIdentity("Plated Geopede", "")); cubeCards.add(new CardIdentity("Plover Knights", "")); cubeCards.add(new CardIdentity("Porcelain Legionnaire", "")); - cubeCards.add(new CardIdentity("Pouncing Kavu", "")); + cubeCards.add(new CardIdentity("Pounce", "")); cubeCards.add(new CardIdentity("Predatory Nightstalker", "")); cubeCards.add(new CardIdentity("Preordain", "")); cubeCards.add(new CardIdentity("Prey Upon", "")); @@ -316,27 +321,27 @@ public AdamStyborskisPauperCube() { cubeCards.add(new CardIdentity("Renegade Freighter", "")); cubeCards.add(new CardIdentity("Rift Bolt", "")); cubeCards.add(new CardIdentity("Rishadan Airship", "")); - cubeCards.add(new CardIdentity("River Serpent", "")); cubeCards.add(new CardIdentity("Ronin Houndmaster", "")); cubeCards.add(new CardIdentity("Rugged Highlands", "")); cubeCards.add(new CardIdentity("Runed Servitor", "")); cubeCards.add(new CardIdentity("Rushing River", "")); + cubeCards.add(new CardIdentity("Sailor of Means", "")); cubeCards.add(new CardIdentity("Sakura-Tribe Elder", "")); cubeCards.add(new CardIdentity("Sandsteppe Outcast", "")); cubeCards.add(new CardIdentity("Sangrite Backlash", "")); cubeCards.add(new CardIdentity("Sarkhan's Rage", "")); cubeCards.add(new CardIdentity("Savage Punch", "")); - cubeCards.add(new CardIdentity("Savage Surge", "")); cubeCards.add(new CardIdentity("Scatter the Seeds", "")); - cubeCards.add(new CardIdentity("Scion of the Wild", "")); cubeCards.add(new CardIdentity("Scion Summoner", "")); + cubeCards.add(new CardIdentity("Scion of the Wild", "")); cubeCards.add(new CardIdentity("Scoured Barrens", "")); cubeCards.add(new CardIdentity("Scourge Devil", "")); cubeCards.add(new CardIdentity("Screeching Skaab", "")); cubeCards.add(new CardIdentity("Scuzzback Marauders", "")); + cubeCards.add(new CardIdentity("Search for Tomorrow", "")); cubeCards.add(new CardIdentity("Searing Blaze", "")); cubeCards.add(new CardIdentity("Seeker of Insight", "")); - cubeCards.add(new CardIdentity("Sejiri Steppe", "")); + cubeCards.add(new CardIdentity("Seeker of the Way", "")); cubeCards.add(new CardIdentity("Selesnya Guildgate", "")); cubeCards.add(new CardIdentity("Sentinel Spider", "")); cubeCards.add(new CardIdentity("Separatist Voidmage", "")); @@ -349,7 +354,6 @@ public AdamStyborskisPauperCube() { cubeCards.add(new CardIdentity("Sigil Blessing", "")); cubeCards.add(new CardIdentity("Silent Departure", "")); cubeCards.add(new CardIdentity("Simic Guildgate", "")); - cubeCards.add(new CardIdentity("Skinthinner", "")); cubeCards.add(new CardIdentity("Skirk Marauder", "")); cubeCards.add(new CardIdentity("Skyknight Legionnaire", "")); cubeCards.add(new CardIdentity("Slash Panther", "")); @@ -362,21 +366,21 @@ public AdamStyborskisPauperCube() { cubeCards.add(new CardIdentity("Spined Thopter", "")); cubeCards.add(new CardIdentity("Splatter Thug", "")); cubeCards.add(new CardIdentity("Staggershock", "")); - cubeCards.add(new CardIdentity("Stave Off", "")); + cubeCards.add(new CardIdentity("Star Compass", "")); cubeCards.add(new CardIdentity("Stitched Drake", "")); + cubeCards.add(new CardIdentity("Stone Quarry", "")); + cubeCards.add(new CardIdentity("Storm Fleet Pyromancer", "")); cubeCards.add(new CardIdentity("Stormfront Pegasus", "")); cubeCards.add(new CardIdentity("Stormscape Apprentice", "")); cubeCards.add(new CardIdentity("Strip Mine", "")); + cubeCards.add(new CardIdentity("Striped Riverwinder", "")); + cubeCards.add(new CardIdentity("Submerged Boneyard", "")); cubeCards.add(new CardIdentity("Sultai Scavenger", "")); cubeCards.add(new CardIdentity("Suppression Bonds", "")); - cubeCards.add(new CardIdentity("Swift Spinner", "")); cubeCards.add(new CardIdentity("Swiftwater Cliffs", "")); cubeCards.add(new CardIdentity("Sylvan Might", "")); cubeCards.add(new CardIdentity("Sylvok Lifestaff", "")); cubeCards.add(new CardIdentity("Tah-Crop Elite", "")); - cubeCards.add(new CardIdentity("Tajuru Pathwarden", "")); - cubeCards.add(new CardIdentity("Talruum Minotaur", "")); - cubeCards.add(new CardIdentity("Tandem Lookout", "")); cubeCards.add(new CardIdentity("Temporal Isolation", "")); cubeCards.add(new CardIdentity("Tenement Crasher", "")); cubeCards.add(new CardIdentity("Terminate", "")); @@ -387,25 +391,26 @@ public AdamStyborskisPauperCube() { cubeCards.add(new CardIdentity("Thornwood Falls", "")); cubeCards.add(new CardIdentity("Thought Scour", "")); cubeCards.add(new CardIdentity("Thraben Inspector", "")); + cubeCards.add(new CardIdentity("Thrill-Kill Assassin", "")); cubeCards.add(new CardIdentity("Thundering Giant", "")); cubeCards.add(new CardIdentity("Thundering Tanadon", "")); cubeCards.add(new CardIdentity("Thunderous Wrath", "")); + cubeCards.add(new CardIdentity("Timber Gorge", "")); cubeCards.add(new CardIdentity("Time to Feed", "")); cubeCards.add(new CardIdentity("Tithe Drinker", "")); cubeCards.add(new CardIdentity("Totem-Guide Hartebeest", "")); cubeCards.add(new CardIdentity("Tragic Slip", "")); cubeCards.add(new CardIdentity("Tranquil Cove", "")); + cubeCards.add(new CardIdentity("Tranquil Expanse", "")); cubeCards.add(new CardIdentity("Travel Preparations", "")); cubeCards.add(new CardIdentity("Treasure Cruise", "")); cubeCards.add(new CardIdentity("Triplicate Spirits", "")); - cubeCards.add(new CardIdentity("Tumble Magnet", "")); cubeCards.add(new CardIdentity("Typhoid Rats", "")); cubeCards.add(new CardIdentity("Ulamog's Crusher", "")); cubeCards.add(new CardIdentity("Ulvenwald Captive", "")); cubeCards.add(new CardIdentity("Undying Rage", "")); cubeCards.add(new CardIdentity("Unearth", "")); cubeCards.add(new CardIdentity("Unmake", "")); - cubeCards.add(new CardIdentity("Unnatural Aggression", "")); cubeCards.add(new CardIdentity("Vampire Interloper", "")); cubeCards.add(new CardIdentity("Vault Skirge", "")); cubeCards.add(new CardIdentity("Viashino Firstblade", "")); @@ -424,7 +429,6 @@ public AdamStyborskisPauperCube() { cubeCards.add(new CardIdentity("Wasteland Scorpion", "")); cubeCards.add(new CardIdentity("Wayfarer's Bauble", "")); cubeCards.add(new CardIdentity("Werebear", "")); - cubeCards.add(new CardIdentity("Whirlpool Whelm", "")); cubeCards.add(new CardIdentity("Whitemane Lion", "")); cubeCards.add(new CardIdentity("Wild Instincts", "")); cubeCards.add(new CardIdentity("Wild Mongrel", "")); @@ -435,6 +439,7 @@ public AdamStyborskisPauperCube() { cubeCards.add(new CardIdentity("Winds of Rebuke", "")); cubeCards.add(new CardIdentity("Winged Coatl", "")); cubeCards.add(new CardIdentity("Wojek Halberdiers", "")); + cubeCards.add(new CardIdentity("Woodland Stream", "")); cubeCards.add(new CardIdentity("Wrecking Ball", "")); cubeCards.add(new CardIdentity("Wretched Gryff", "")); cubeCards.add(new CardIdentity("Yavimaya Elder", "")); diff --git a/Mage.Server.Plugins/pom.xml b/Mage.Server.Plugins/pom.xml index 4f23171181..6088bbe80d 100644 --- a/Mage.Server.Plugins/pom.xml +++ b/Mage.Server.Plugins/pom.xml @@ -21,6 +21,7 @@ Mage.Game.CommanderFreeForAll Mage.Game.FreeForAll Mage.Game.MomirDuel + Mage.Game.MomirGame Mage.Game.TinyLeadersDuel Mage.Game.CanadianHighlanderDuel Mage.Game.PennyDreadfulCommanderFreeForAll diff --git a/Mage.Server/config/config.xml b/Mage.Server/config/config.xml index 877f1756e3..ba16d20cc3 100644 --- a/Mage.Server/config/config.xml +++ b/Mage.Server/config/config.xml @@ -77,6 +77,7 @@ + diff --git a/Mage.Server/pom.xml b/Mage.Server/pom.xml index eb547da404..364875c081 100644 --- a/Mage.Server/pom.xml +++ b/Mage.Server/pom.xml @@ -160,6 +160,12 @@ ${project.version} runtime + + ${project.groupId} + mage-game-momirfreeforall + ${project.version} + runtime + org.apache.shiro shiro-core diff --git a/Mage.Sets/src/mage/cards/a/AssassinsBlade.java b/Mage.Sets/src/mage/cards/a/AssassinsBlade.java new file mode 100644 index 0000000000..88c4ebf61d --- /dev/null +++ b/Mage.Sets/src/mage/cards/a/AssassinsBlade.java @@ -0,0 +1,85 @@ +/* + * Copyright 2010 BetaSteward_at_googlemail.com. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are + * permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this list of + * conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, this list + * of conditions and the following disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY BetaSteward_at_googlemail.com ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BetaSteward_at_googlemail.com OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * The views and conclusions contained in the software and documentation are those of the + * authors and should not be interpreted as representing official policies, either expressed + * or implied, of BetaSteward_at_googlemail.com. + */ +package mage.cards.a; + +import java.util.UUID; +import mage.ObjectColor; +import mage.abilities.Ability; +import mage.abilities.common.CastOnlyDuringPhaseStepSourceAbility; +import mage.abilities.condition.common.AttackedThisStepCondition; +import mage.abilities.effects.common.DestroyTargetEffect; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.PhaseStep; +import mage.constants.TurnPhase; +import mage.filter.common.FilterCreaturePermanent; +import mage.filter.predicate.Predicates; +import mage.filter.predicate.mageobject.ColorPredicate; +import mage.filter.predicate.permanent.AttackingPredicate; +import mage.target.common.TargetCreaturePermanent; +import mage.watchers.common.PlayerAttackedStepWatcher; + +/** + * + * @author TheElk801 + */ +public class AssassinsBlade extends CardImpl { + + private static final FilterCreaturePermanent filter = new FilterCreaturePermanent("nonblack attacking creature"); + + static { + filter.add(Predicates.not(new ColorPredicate(ObjectColor.BLACK))); + filter.add(new AttackingPredicate()); + } + + public AssassinsBlade(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.INSTANT}, "{1}{B}"); + + // Cast Assassin's Blade only during the declare attackers step and only if you've been attacked this step. + Ability ability = new CastOnlyDuringPhaseStepSourceAbility( + TurnPhase.COMBAT, PhaseStep.DECLARE_ATTACKERS, AttackedThisStepCondition.instance, + "Cast {this} only during the declare attackers step and only if you've been attacked this step." + ); + ability.addWatcher(new PlayerAttackedStepWatcher()); + this.addAbility(ability); + + // Destroy target nonblack attacking creature. + this.getSpellAbility().addEffect(new DestroyTargetEffect()); + this.getSpellAbility().addTarget(new TargetCreaturePermanent(filter)); + } + + public AssassinsBlade(final AssassinsBlade card) { + super(card); + } + + @Override + public AssassinsBlade copy() { + return new AssassinsBlade(this); + } +} diff --git a/Mage.Sets/src/mage/cards/b/BatheInLight.java b/Mage.Sets/src/mage/cards/b/BatheInLight.java index 12dd48dcb4..396666f53d 100644 --- a/Mage.Sets/src/mage/cards/b/BatheInLight.java +++ b/Mage.Sets/src/mage/cards/b/BatheInLight.java @@ -31,16 +31,22 @@ import java.util.UUID; import mage.ObjectColor; import mage.abilities.Ability; import mage.abilities.effects.ContinuousEffect; +import mage.abilities.effects.ContinuousEffectImpl; import mage.abilities.effects.OneShotEffect; -import mage.abilities.effects.common.ChooseColorEffect; import mage.abilities.effects.common.continuous.GainProtectionFromColorTargetEffect; +import mage.abilities.keyword.ProtectionAbility; import mage.cards.CardImpl; import mage.cards.CardSetInfo; +import mage.choices.ChoiceColor; import mage.constants.AbilityWord; import mage.constants.CardType; import mage.constants.Duration; +import mage.constants.Layer; import mage.constants.Outcome; +import mage.constants.SubLayer; +import mage.filter.FilterObject; import mage.filter.StaticFilters; +import mage.filter.predicate.mageobject.ColorPredicate; import mage.game.Game; import mage.game.permanent.Permanent; import mage.players.Player; @@ -49,7 +55,7 @@ import mage.target.targetpointer.FixedTarget; /** * - * @author LevelX2 + * @author LevelX2 & L_J */ public class BatheInLight extends CardImpl { @@ -57,7 +63,6 @@ public class BatheInLight extends CardImpl { super(ownerId, setInfo, new CardType[]{CardType.INSTANT}, "{1}{W}"); // Radiance - Choose a color. Target creature and each other creature that shares a color with it gain protection from the chosen color until end of turn. - this.getSpellAbility().addEffect(new ChooseColorEffect(Outcome.Benefit)); this.getSpellAbility().addEffect(new BatheInLightEffect()); this.getSpellAbility().addTarget(new TargetCreaturePermanent()); this.getSpellAbility().setAbilityWord(AbilityWord.RADIANCE); @@ -95,19 +100,71 @@ class BatheInLightEffect extends OneShotEffect { if (controller != null) { Permanent target = game.getPermanent(getTargetPointer().getFirst(game, source)); if (target != null) { - ObjectColor protectColor = (ObjectColor) game.getState().getValue(target.getId() + "_color"); - if (protectColor != null) { - ObjectColor color = target.getColor(game); - for (Permanent permanent : game.getBattlefield().getActivePermanents(StaticFilters.FILTER_PERMANENT_CREATURE, source.getControllerId(), source.getSourceId(), game)) { - if (permanent.getColor(game).shares(color)) { - ContinuousEffect effect = new GainProtectionFromColorTargetEffect(Duration.EndOfTurn, protectColor); - effect.setTargetPointer(new FixedTarget(permanent, game)); - game.addEffect(effect, source); + ChoiceColor colorChoice = new ChoiceColor(); + if (controller.choose(Outcome.Benefit, colorChoice, game)) { + game.informPlayers(target.getName() + ": " + controller.getLogName() + " has chosen " + colorChoice.getChoice()); + game.getState().setValue(target.getId() + "_color", colorChoice.getColor()); + + ObjectColor protectColor = (ObjectColor) game.getState().getValue(target.getId() + "_color"); + if (protectColor != null) { + ContinuousEffect effect = new ProtectionChosenColorTargetEffect(); + game.addEffect(effect, source); + ObjectColor color = target.getColor(game); + for (Permanent permanent : game.getBattlefield().getActivePermanents(StaticFilters.FILTER_PERMANENT_CREATURE, source.getControllerId(), source.getSourceId(), game)) { + if (permanent != target && permanent.getColor(game).shares(color)) { + game.getState().setValue(permanent.getId() + "_color", colorChoice.getColor()); + effect.setTargetPointer(new FixedTarget(permanent, game)); + game.addEffect(effect, source); + } } } } - } return true; + } + } + return false; + } +} + +class ProtectionChosenColorTargetEffect extends ContinuousEffectImpl { + + protected ObjectColor chosenColor; + protected ProtectionAbility protectionAbility; + + public ProtectionChosenColorTargetEffect() { + super(Duration.EndOfTurn, Layer.AbilityAddingRemovingEffects_6, SubLayer.NA, Outcome.AddAbility); + } + + public ProtectionChosenColorTargetEffect(final ProtectionChosenColorTargetEffect effect) { + super(effect); + if (effect.chosenColor != null) { + this.chosenColor = effect.chosenColor.copy(); + } + if (effect.protectionAbility != null) { + this.protectionAbility = effect.protectionAbility.copy(); + } + } + + @Override + public ProtectionChosenColorTargetEffect copy() { + return new ProtectionChosenColorTargetEffect(this); + } + + @Override + public boolean apply(Game game, Ability source) { + Permanent permanent = game.getPermanent(getTargetPointer().getFirst(game, source)); + if (permanent != null) { + ObjectColor color = (ObjectColor) game.getState().getValue(permanent.getId() + "_color"); + if (color != null && (protectionAbility == null || !color.equals(chosenColor))) { + chosenColor = color; + FilterObject protectionFilter = new FilterObject(chosenColor.getDescription()); + protectionFilter.add(new ColorPredicate(chosenColor)); + protectionAbility = new ProtectionAbility(protectionFilter); + } + if (protectionAbility != null) { + permanent.addAbility(protectionAbility, source.getSourceId(), game); + return true; + } } return false; } diff --git a/Mage.Sets/src/mage/cards/b/BrutalHordechief.java b/Mage.Sets/src/mage/cards/b/BrutalHordechief.java index 9add26359b..e9068ea94b 100644 --- a/Mage.Sets/src/mage/cards/b/BrutalHordechief.java +++ b/Mage.Sets/src/mage/cards/b/BrutalHordechief.java @@ -33,7 +33,8 @@ import mage.abilities.Ability; import mage.abilities.TriggeredAbilityImpl; import mage.abilities.common.SimpleActivatedAbility; import mage.abilities.costs.mana.ManaCostsImpl; -import mage.abilities.effects.ReplacementEffectImpl; +import mage.abilities.effects.ContinuousRuleModifyingEffectImpl; +import mage.abilities.effects.OneShotEffect; import mage.abilities.effects.common.GainLifeEffect; import mage.abilities.effects.common.LoseLifeTargetEffect; import mage.abilities.effects.common.combat.BlocksIfAbleAllEffect; @@ -47,6 +48,7 @@ import mage.game.events.GameEvent; import mage.game.permanent.Permanent; import mage.players.Player; import mage.target.targetpointer.FixedTarget; +import mage.watchers.common.ChooseBlockersRedundancyWatcher; /** * @@ -71,7 +73,9 @@ public class BrutalHordechief extends CardImpl { // {3}{R/W}{R/W}: Creatures your opponents control block this turn if able, and you choose how those creatures block. Ability ability = new SimpleActivatedAbility(Zone.BATTLEFIELD, new BlocksIfAbleAllEffect(filter, Duration.EndOfTurn), new ManaCostsImpl("{3}{R/W}{R/W}")); - ability.addEffect(new BrutalHordechiefReplacementEffect()); + ability.addEffect(new BrutalHordechiefChooseBlockersEffect()); + ability.addWatcher(new ChooseBlockersRedundancyWatcher()); + ability.addEffect(new ChooseBlockersRedundancyWatcherIncrementEffect()); this.addAbility(ability); } @@ -83,6 +87,32 @@ public class BrutalHordechief extends CardImpl { public BrutalHordechief copy() { return new BrutalHordechief(this); } + + private class ChooseBlockersRedundancyWatcherIncrementEffect extends OneShotEffect { + + ChooseBlockersRedundancyWatcherIncrementEffect() { + super(Outcome.Neutral); + } + + ChooseBlockersRedundancyWatcherIncrementEffect(final ChooseBlockersRedundancyWatcherIncrementEffect effect) { + super(effect); + } + + @Override + public boolean apply(Game game, Ability source) { + ChooseBlockersRedundancyWatcher watcher = (ChooseBlockersRedundancyWatcher) game.getState().getWatchers().get(ChooseBlockersRedundancyWatcher.class.getSimpleName()); + if (watcher != null) { + watcher.increment(); + return true; + } + return false; + } + + @Override + public ChooseBlockersRedundancyWatcherIncrementEffect copy() { + return new ChooseBlockersRedundancyWatcherIncrementEffect(this); + } + } } class BrutalHordechiefTriggeredAbility extends TriggeredAbilityImpl { @@ -123,20 +153,20 @@ class BrutalHordechiefTriggeredAbility extends TriggeredAbilityImpl { } } -class BrutalHordechiefReplacementEffect extends ReplacementEffectImpl { +class BrutalHordechiefChooseBlockersEffect extends ContinuousRuleModifyingEffectImpl { - public BrutalHordechiefReplacementEffect() { - super(Duration.EndOfCombat, Outcome.Benefit); - staticText = ", and you choose how those creatures block"; + public BrutalHordechiefChooseBlockersEffect() { + super(Duration.EndOfTurn, Outcome.Benefit, false, false); + staticText = "You choose which creatures block this turn and how those creatures block"; } - public BrutalHordechiefReplacementEffect(final BrutalHordechiefReplacementEffect effect) { + public BrutalHordechiefChooseBlockersEffect(final BrutalHordechiefChooseBlockersEffect effect) { super(effect); } @Override - public BrutalHordechiefReplacementEffect copy() { - return new BrutalHordechiefReplacementEffect(this); + public BrutalHordechiefChooseBlockersEffect copy() { + return new BrutalHordechiefChooseBlockersEffect(this); } @Override @@ -151,16 +181,18 @@ class BrutalHordechiefReplacementEffect extends ReplacementEffectImpl { @Override public boolean applies(GameEvent event, Ability source, Game game) { - return event.getPlayerId().equals(source.getControllerId()); - } - - @Override - public boolean replaceEvent(GameEvent event, Ability source, Game game) { + ChooseBlockersRedundancyWatcher watcher = (ChooseBlockersRedundancyWatcher) game.getState().getWatchers().get(ChooseBlockersRedundancyWatcher.class.getSimpleName()); + watcher.decrement(); + if (watcher.copyCountApply > 0) { + game.informPlayers(source.getSourceObject(game).getIdName() + " didn't apply"); + return false; + } + watcher.copyCountApply = watcher.copyCount; Player blockController = game.getPlayer(source.getControllerId()); if (blockController != null) { game.getCombat().selectBlockers(blockController, game); return true; } return false; - } + } } diff --git a/Mage.Sets/src/mage/cards/c/ChaliceOfTheVoid.java b/Mage.Sets/src/mage/cards/c/ChaliceOfTheVoid.java index d6b829d2be..cc53c2feb4 100644 --- a/Mage.Sets/src/mage/cards/c/ChaliceOfTheVoid.java +++ b/Mage.Sets/src/mage/cards/c/ChaliceOfTheVoid.java @@ -28,16 +28,14 @@ package mage.cards.c; import java.util.UUID; -import mage.abilities.Ability; import mage.abilities.TriggeredAbilityImpl; import mage.abilities.common.EntersBattlefieldAbility; import mage.abilities.effects.Effect; -import mage.abilities.effects.OneShotEffect; +import mage.abilities.effects.common.CounterTargetEffect; import mage.abilities.effects.common.EntersBattlefieldWithXCountersEffect; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; -import mage.constants.Outcome; import mage.constants.Zone; import mage.counters.CounterType; import mage.game.Game; @@ -53,7 +51,7 @@ import mage.target.targetpointer.FixedTarget; public class ChaliceOfTheVoid extends CardImpl { public ChaliceOfTheVoid(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.ARTIFACT},"{X}{X}"); + super(ownerId, setInfo, new CardType[]{CardType.ARTIFACT}, "{X}{X}"); // Chalice of the Void enters the battlefield with X charge counters on it. this.addAbility(new EntersBattlefieldAbility(new EntersBattlefieldWithXCountersEffect(CounterType.CHARGE.createInstance()))); @@ -75,7 +73,7 @@ public class ChaliceOfTheVoid extends CardImpl { class ChaliceOfTheVoidTriggeredAbility extends TriggeredAbilityImpl { public ChaliceOfTheVoidTriggeredAbility() { - super(Zone.BATTLEFIELD, new CounterEffect()); + super(Zone.BATTLEFIELD, new CounterTargetEffect()); } public ChaliceOfTheVoidTriggeredAbility(final ChaliceOfTheVoidTriggeredAbility abiltity) { @@ -110,25 +108,3 @@ class ChaliceOfTheVoidTriggeredAbility extends TriggeredAbilityImpl { return "Whenever a player casts a spell with converted mana cost equal to the number of charge counters on {this}, counter that spell."; } } - -class CounterEffect extends OneShotEffect { - - public CounterEffect() { - super(Outcome.Detriment); - } - - public CounterEffect(final CounterEffect effect) { - super(effect); - } - - @Override - public CounterEffect copy() { - return new CounterEffect(this); - } - - @Override - public boolean apply(Game game, Ability source) { - return game.getStack().counter(this.getTargetPointer().getFirst(game, source), source.getSourceId(), game); - } - -} diff --git a/Mage.Sets/src/mage/cards/c/ChampionsVictory.java b/Mage.Sets/src/mage/cards/c/ChampionsVictory.java new file mode 100644 index 0000000000..a3d2222ee2 --- /dev/null +++ b/Mage.Sets/src/mage/cards/c/ChampionsVictory.java @@ -0,0 +1,73 @@ +/* + * Copyright 2010 BetaSteward_at_googlemail.com. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are + * permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this list of + * conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, this list + * of conditions and the following disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY BetaSteward_at_googlemail.com ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BetaSteward_at_googlemail.com OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * The views and conclusions contained in the software and documentation are those of the + * authors and should not be interpreted as representing official policies, either expressed + * or implied, of BetaSteward_at_googlemail.com. + */ +package mage.cards.c; + +import java.util.UUID; +import mage.abilities.Ability; +import mage.abilities.common.CastOnlyDuringPhaseStepSourceAbility; +import mage.abilities.condition.common.AttackedThisStepCondition; +import mage.abilities.effects.common.ReturnToHandTargetEffect; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.PhaseStep; +import mage.constants.TurnPhase; +import mage.target.common.TargetAttackingCreature; +import mage.watchers.common.PlayerAttackedStepWatcher; + +/** + * + * @author TheElk801 + */ +public class ChampionsVictory extends CardImpl { + + public ChampionsVictory(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.INSTANT}, "{U}"); + + // Cast Champion's Victory only during the declare attackers step and only if you've been attacked this step. + Ability ability = new CastOnlyDuringPhaseStepSourceAbility( + TurnPhase.COMBAT, PhaseStep.DECLARE_ATTACKERS, AttackedThisStepCondition.instance, + "Cast {this} only during the declare attackers step and only if you've been attacked this step." + ); + ability.addWatcher(new PlayerAttackedStepWatcher()); + this.addAbility(ability); + + // Return target attacking creature to its owner's hand. + this.getSpellAbility().addEffect(new ReturnToHandTargetEffect()); + this.getSpellAbility().addTarget(new TargetAttackingCreature()); + } + + public ChampionsVictory(final ChampionsVictory card) { + super(card); + } + + @Override + public ChampionsVictory copy() { + return new ChampionsVictory(this); + } +} diff --git a/Mage.Sets/src/mage/cards/c/CommandOfUnsummoning.java b/Mage.Sets/src/mage/cards/c/CommandOfUnsummoning.java new file mode 100644 index 0000000000..9ea9c2069f --- /dev/null +++ b/Mage.Sets/src/mage/cards/c/CommandOfUnsummoning.java @@ -0,0 +1,74 @@ +/* + * Copyright 2010 BetaSteward_at_googlemail.com. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are + * permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this list of + * conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, this list + * of conditions and the following disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY BetaSteward_at_googlemail.com ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BetaSteward_at_googlemail.com OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * The views and conclusions contained in the software and documentation are those of the + * authors and should not be interpreted as representing official policies, either expressed + * or implied, of BetaSteward_at_googlemail.com. + */ +package mage.cards.c; + +import java.util.UUID; +import mage.abilities.Ability; +import mage.abilities.common.CastOnlyDuringPhaseStepSourceAbility; +import mage.abilities.condition.common.AttackedThisStepCondition; +import mage.abilities.effects.common.ReturnToHandTargetEffect; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.PhaseStep; +import mage.constants.TurnPhase; +import mage.filter.common.FilterAttackingCreature; +import mage.target.common.TargetAttackingCreature; +import mage.watchers.common.PlayerAttackedStepWatcher; + +/** + * + * @author TheElk801 + */ +public class CommandOfUnsummoning extends CardImpl { + + public CommandOfUnsummoning(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.INSTANT}, "{2}{U}"); + + // Cast Command of Unsummoning only during the declare attackers step and only if you've been attacked this step. + Ability ability = new CastOnlyDuringPhaseStepSourceAbility( + TurnPhase.COMBAT, PhaseStep.DECLARE_ATTACKERS, AttackedThisStepCondition.instance, + "Cast {this} only during the declare attackers step and only if you've been attacked this step." + ); + ability.addWatcher(new PlayerAttackedStepWatcher()); + this.addAbility(ability); + + // Return one or two target attacking creatures to their owner's hand. + this.getSpellAbility().addEffect(new ReturnToHandTargetEffect().setText("Return one or two target attacking creatures to their owner's hand.")); + this.getSpellAbility().addTarget(new TargetAttackingCreature(1, 2, new FilterAttackingCreature(), false)); + } + + public CommandOfUnsummoning(final CommandOfUnsummoning card) { + super(card); + } + + @Override + public CommandOfUnsummoning copy() { + return new CommandOfUnsummoning(this); + } +} diff --git a/Mage.Sets/src/mage/cards/c/ConfusionInTheRanks.java b/Mage.Sets/src/mage/cards/c/ConfusionInTheRanks.java index 9ce9bb67b4..b22e6a0da9 100644 --- a/Mage.Sets/src/mage/cards/c/ConfusionInTheRanks.java +++ b/Mage.Sets/src/mage/cards/c/ConfusionInTheRanks.java @@ -60,21 +60,25 @@ public class ConfusionInTheRanks extends CardImpl { filter.add(Predicates.or( new CardTypePredicate(CardType.ARTIFACT), new CardTypePredicate(CardType.CREATURE), - new CardTypePredicate(CardType.ENCHANTMENT))); + new CardTypePredicate(CardType.ENCHANTMENT) + )); } private final UUID originalId; public ConfusionInTheRanks(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.ENCHANTMENT},"{3}{R}{R}"); + super(ownerId, setInfo, new CardType[]{CardType.ENCHANTMENT}, "{3}{R}{R}"); // Whenever an artifact, creature, or enchantment enters the battlefield, its controller chooses target permanent another player controls that shares a card type with it. Exchange control of those permanents. Ability ability = new EntersBattlefieldAllTriggeredAbility( Zone.BATTLEFIELD, - new ExchangeControlTargetEffect(Duration.EndOfGame, "its controller chooses target permanent another player controls that shares a card type with it. Exchange control of those permanents"), - filter, - false, - SetTargetPointer.PERMANENT, - null); + new ExchangeControlTargetEffect( + Duration.EndOfGame, + "its controller chooses target permanent " + + "another player controls that shares a card type with it. " + + "Exchange control of those permanents" + ), + filter, false, SetTargetPointer.PERMANENT, null + ); ability.addTarget(new TargetPermanent()); originalId = ability.getOriginalId(); this.addAbility(ability); @@ -92,28 +96,31 @@ public class ConfusionInTheRanks extends CardImpl { for (Effect effect : ability.getEffects()) { enteringPermanentId = effect.getTargetPointer().getFirst(game, ability); } - if (enteringPermanentId != null) { - Permanent enteringPermanent = game.getPermanent(enteringPermanentId); - if (enteringPermanent != null) { - ability.setControllerId(enteringPermanent.getControllerId()); - ability.getTargets().clear(); - FilterPermanent filterTarget = new FilterPermanent(); - String message = ""; - filterTarget.add(Predicates.not(new ControllerIdPredicate(enteringPermanent.getControllerId()))); - Set cardTypesPredicates = new HashSet<>(1); - for (CardType cardTypeEntering : enteringPermanent.getCardType()) { - cardTypesPredicates.add(new CardTypePredicate(cardTypeEntering)); - if (!message.isEmpty()) { - message += "or "; - } - message += cardTypeEntering.toString().toLowerCase() + ' '; - } - filterTarget.add(Predicates.or(cardTypesPredicates)); - message += "you do not control"; - filterTarget.setMessage(message); - ability.getTargets().add(new TargetPermanent(filterTarget)); - } + if (enteringPermanentId == null) { + return; } + Permanent enteringPermanent = game.getPermanent(enteringPermanentId); + if (enteringPermanent == null) { + return; + } + ability.getTargets().clear(); + FilterPermanent filterTarget = new FilterPermanent(); + String message = ""; + filterTarget.add(Predicates.not(new ControllerIdPredicate(enteringPermanent.getControllerId()))); + Set cardTypesPredicates = new HashSet<>(1); + for (CardType cardTypeEntering : enteringPermanent.getCardType()) { + cardTypesPredicates.add(new CardTypePredicate(cardTypeEntering)); + if (!message.isEmpty()) { + message += "or "; + } + message += cardTypeEntering.toString().toLowerCase() + ' '; + } + filterTarget.add(Predicates.or(cardTypesPredicates)); + message += "you don't control"; + filterTarget.setMessage(message); + TargetPermanent target = new TargetPermanent(filterTarget); + target.setTargetController(enteringPermanent.getControllerId()); + ability.getTargets().add(target); } } diff --git a/Mage.Sets/src/mage/cards/c/ConsumeStrength.java b/Mage.Sets/src/mage/cards/c/ConsumeStrength.java index 1bf9ca987f..15654f0fce 100644 --- a/Mage.Sets/src/mage/cards/c/ConsumeStrength.java +++ b/Mage.Sets/src/mage/cards/c/ConsumeStrength.java @@ -29,7 +29,9 @@ package mage.cards.c; import java.util.UUID; import mage.abilities.Ability; -import mage.abilities.effects.ContinuousEffectImpl; +import mage.abilities.effects.ContinuousEffect; +import mage.abilities.effects.OneShotEffect; +import mage.abilities.effects.common.continuous.BoostTargetEffect; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.*; @@ -38,6 +40,7 @@ import mage.filter.predicate.mageobject.AnotherTargetPredicate; import mage.game.Game; import mage.game.permanent.Permanent; import mage.target.common.TargetCreaturePermanent; +import mage.target.targetpointer.FixedTarget; /** * @@ -46,17 +49,16 @@ import mage.target.common.TargetCreaturePermanent; public class ConsumeStrength extends CardImpl { public ConsumeStrength(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.INSTANT},"{1}{B}{G}"); - + super(ownerId, setInfo, new CardType[]{CardType.INSTANT}, "{1}{B}{G}"); // Target creature gets +2/+2 until end of turn. Another target creature gets -2/-2 until end of turn. this.getSpellAbility().addEffect(new ConsumeStrengthEffect()); - + FilterCreaturePermanent filter1 = new FilterCreaturePermanent("creature to get +2/+2"); TargetCreaturePermanent target1 = new TargetCreaturePermanent(filter1); target1.setTargetTag(1); this.getSpellAbility().addTarget(target1); - + FilterCreaturePermanent filter2 = new FilterCreaturePermanent("another creature to get -2/-2"); filter2.add(new AnotherTargetPredicate(2)); TargetCreaturePermanent target2 = new TargetCreaturePermanent(filter2); @@ -74,10 +76,10 @@ public class ConsumeStrength extends CardImpl { } } -class ConsumeStrengthEffect extends ContinuousEffectImpl { +class ConsumeStrengthEffect extends OneShotEffect { public ConsumeStrengthEffect() { - super(Duration.EndOfTurn, Layer.PTChangingEffects_7, SubLayer.ModifyPT_7c, Outcome.BoostCreature); + super(Outcome.BoostCreature); this.staticText = "Target creature gets +2/+2 until end of turn. Another target creature gets -2/-2 until end of turn"; } @@ -94,14 +96,16 @@ class ConsumeStrengthEffect extends ContinuousEffectImpl { public boolean apply(Game game, Ability source) { Permanent permanent = game.getPermanent(source.getFirstTarget()); if (permanent != null) { - permanent.addPower(2); - permanent.addToughness(2); + ContinuousEffect effect = new BoostTargetEffect(2, 2, Duration.EndOfTurn); + effect.setTargetPointer(new FixedTarget(permanent, game)); + game.addEffect(effect, source); } permanent = game.getPermanent(source.getTargets().get(1).getFirstTarget()); if (permanent != null) { - permanent.addPower(-2); - permanent.addToughness(-2); + ContinuousEffect effect = new BoostTargetEffect(-2, -2, Duration.EndOfTurn); + effect.setTargetPointer(new FixedTarget(permanent, game)); + game.addEffect(effect, source); } return true; } -} \ No newline at end of file +} diff --git a/Mage.Sets/src/mage/cards/c/ConundrumSphinx.java b/Mage.Sets/src/mage/cards/c/ConundrumSphinx.java index 2c13d773f7..5b1080aba7 100644 --- a/Mage.Sets/src/mage/cards/c/ConundrumSphinx.java +++ b/Mage.Sets/src/mage/cards/c/ConundrumSphinx.java @@ -101,6 +101,7 @@ class ConundrumSphinxEffect extends OneShotEffect { if (player != null) { if (player.getLibrary().hasCards()) { cardChoice.clearChoice(); + cardChoice.setMessage("Name a card"); while (!player.choose(Outcome.DrawCard, cardChoice, game) && player.canRespond()) { if (!player.canRespond()) { continue Players; diff --git a/Mage.Sets/src/mage/cards/c/Cryptwailing.java b/Mage.Sets/src/mage/cards/c/Cryptwailing.java new file mode 100644 index 0000000000..1ad88cbebe --- /dev/null +++ b/Mage.Sets/src/mage/cards/c/Cryptwailing.java @@ -0,0 +1,67 @@ +/* + * Copyright 2010 BetaSteward_at_googlemail.com. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are + * permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this list of + * conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, this list + * of conditions and the following disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY BetaSteward_at_googlemail.com ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BetaSteward_at_googlemail.com OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * The views and conclusions contained in the software and documentation are those of the + * authors and should not be interpreted as representing official policies, either expressed + * or implied, of BetaSteward_at_googlemail.com. + */ +package mage.cards.c; + +import java.util.UUID; +import mage.abilities.common.ActivateAsSorceryActivatedAbility; +import mage.abilities.costs.common.ExileFromGraveCost; +import mage.abilities.costs.mana.GenericManaCost; +import mage.abilities.effects.common.discard.DiscardTargetEffect; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.Zone; +import mage.filter.common.FilterCreatureCard; +import mage.target.TargetPlayer; +import mage.target.common.TargetCardInYourGraveyard; + +/** + * + * @author LevelX2 & L_J + */ +public class Cryptwailing extends CardImpl { + + public Cryptwailing(UUID ownerId, CardSetInfo setInfo) { + super(ownerId,setInfo,new CardType[]{CardType.ENCHANTMENT},"{3}{B}"); + + // {1}, Exile two creature cards from your graveyard: Target player discards a card. Activate this ability only any time you could cast a sorcery. + ActivateAsSorceryActivatedAbility ability = new ActivateAsSorceryActivatedAbility(Zone.BATTLEFIELD, new DiscardTargetEffect(1), new GenericManaCost(1)); + ability.addCost(new ExileFromGraveCost(new TargetCardInYourGraveyard(2,2, new FilterCreatureCard("two creature cards from your graveyard")))); + ability.addTarget(new TargetPlayer()); + this.addAbility(ability); + } + + public Cryptwailing(final Cryptwailing card) { + super(card); + } + + @Override + public Cryptwailing copy() { + return new Cryptwailing(this); + } +} diff --git a/Mage.Sets/src/mage/cards/c/CustodiSoulcaller.java b/Mage.Sets/src/mage/cards/c/CustodiSoulcaller.java new file mode 100644 index 0000000000..eb5a9756df --- /dev/null +++ b/Mage.Sets/src/mage/cards/c/CustodiSoulcaller.java @@ -0,0 +1,136 @@ +/* + * Copyright 2010 BetaSteward_at_googlemail.com. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are + * permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this list of + * conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, this list + * of conditions and the following disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY BetaSteward_at_googlemail.com ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BetaSteward_at_googlemail.com OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * The views and conclusions contained in the software and documentation are those of the + * authors and should not be interpreted as representing official policies, either expressed + * or implied, of BetaSteward_at_googlemail.com. + */ +package mage.cards.c; + +import java.util.HashMap; +import java.util.HashSet; +import java.util.Set; +import java.util.UUID; +import mage.MageInt; +import mage.abilities.Ability; +import mage.abilities.common.AttacksTriggeredAbility; +import mage.abilities.effects.common.ReturnFromGraveyardToBattlefieldTargetEffect; +import mage.abilities.keyword.MeleeAbility; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.*; +import mage.filter.FilterCard; +import mage.filter.common.FilterCreatureCard; +import mage.filter.predicate.Predicates; +import mage.filter.predicate.mageobject.CardTypePredicate; +import mage.filter.predicate.mageobject.ConvertedManaCostPredicate; +import mage.game.Game; +import mage.game.events.GameEvent; +import mage.game.events.GameEvent.EventType; +import mage.game.permanent.Permanent; +import mage.target.common.TargetCardInYourGraveyard; +import mage.watchers.Watcher; + +/** + * + * @author L_J + */ +public class CustodiSoulcaller extends CardImpl { + + public CustodiSoulcaller(UUID ownerId, CardSetInfo setInfo) { + super(ownerId,setInfo,new CardType[]{CardType.CREATURE},"{1}{W}{W}"); + this.subtype.add(SubType.HUMAN); + this.subtype.add(SubType.CLERIC); + this.power = new MageInt(1); + this.toughness = new MageInt(2); + + // Melee + this.addAbility(new MeleeAbility()); + + // Whenever Custodi Soulcaller attacks, return target creature card with converted mana cost X or less from your graveyard to the battlefield, where X is the number of players you attacked with a creature this combat. + Ability ability = new AttacksTriggeredAbility(new ReturnFromGraveyardToBattlefieldTargetEffect(), false); + ability.addWatcher(new CustodiSoulcallerWatcher()); + ability.addTarget(new TargetCardInYourGraveyard(new FilterCreatureCard("creature card with converted mana cost X or less from your graveyard, where X is the number of players you attacked with a creature this combat"))); + this.addAbility(ability); + } + + @Override + public void adjustTargets(Ability ability, Game game) { + if (ability.getClass().equals(AttacksTriggeredAbility.class)) { + ability.getTargets().clear(); + CustodiSoulcallerWatcher watcher = (CustodiSoulcallerWatcher) game.getState().getWatchers().get(CustodiSoulcallerWatcher.class.getSimpleName()); + Permanent sourcePermanent = game.getPermanentOrLKIBattlefield(ability.getSourceId()); + if (watcher != null && watcher.playersAttacked != null) { + int xValue = watcher.getNumberOfAttackedPlayers(sourcePermanent.getControllerId()); + FilterCard filter = new FilterCard("creature card with converted mana cost " + xValue + " or less"); + filter.add(new CardTypePredicate(CardType.CREATURE)); + filter.add(Predicates.or(new ConvertedManaCostPredicate(ComparisonType.EQUAL_TO, xValue), new ConvertedManaCostPredicate(ComparisonType.FEWER_THAN, xValue))); + ability.getTargets().add(new TargetCardInYourGraveyard(filter)); + } + } + } + + public CustodiSoulcaller(final CustodiSoulcaller card) { + super(card); + } + + @Override + public CustodiSoulcaller copy() { + return new CustodiSoulcaller(this); + } +} + +class CustodiSoulcallerWatcher extends Watcher { + + protected final HashMap> playersAttacked = new HashMap<>(0); + + CustodiSoulcallerWatcher() { + super("CustodiSoulcallerWatcher", WatcherScope.GAME); + } + + CustodiSoulcallerWatcher(final CustodiSoulcallerWatcher watcher) { + super(watcher); + this.playersAttacked.putAll(watcher.playersAttacked); + } + + @Override + public void watch(GameEvent event, Game game) { + if (event.getType() == EventType.BEGIN_COMBAT_STEP_PRE) { + this.playersAttacked.clear(); + } + else if (event.getType() == EventType.ATTACKER_DECLARED) { + Set attackedPlayers = this.playersAttacked.getOrDefault(event.getPlayerId(), new HashSet<>(1)); + attackedPlayers.add(event.getTargetId()); + this.playersAttacked.put(event.getPlayerId(), attackedPlayers); + } + } + + public int getNumberOfAttackedPlayers(UUID attackerId) { + return this.playersAttacked.get(attackerId).size(); + } + + @Override + public CustodiSoulcallerWatcher copy() { + return new CustodiSoulcallerWatcher(this); + } +} diff --git a/Mage.Sets/src/mage/cards/d/DarksteelMutation.java b/Mage.Sets/src/mage/cards/d/DarksteelMutation.java index d77d6ad8ac..1be8bf04b6 100644 --- a/Mage.Sets/src/mage/cards/d/DarksteelMutation.java +++ b/Mage.Sets/src/mage/cards/d/DarksteelMutation.java @@ -53,7 +53,7 @@ import mage.target.common.TargetCreaturePermanent; public class DarksteelMutation extends CardImpl { public DarksteelMutation(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.ENCHANTMENT},"{1}{W}"); + super(ownerId, setInfo, new CardType[]{CardType.ENCHANTMENT}, "{1}{W}"); this.subtype.add(SubType.AURA); // Enchant creature @@ -67,7 +67,7 @@ public class DarksteelMutation extends CardImpl { this.addAbility(new SimpleStaticAbility(Zone.BATTLEFIELD, new BecomesCreatureAttachedEffect(new DarksteelMutationInsectToken(), "Enchanted creature is an Insect artifact creature with base power and toughness 0/1 and has indestructible, and it loses all other abilities, card types, and creature types.", - Duration.WhileOnBattlefield, BecomesCreatureAttachedEffect.LoseType.ALL))); + Duration.WhileOnBattlefield, BecomesCreatureAttachedEffect.LoseType.ALL_BUT_COLOR))); } diff --git a/Mage.Sets/src/mage/cards/d/DaughterOfAutumn.java b/Mage.Sets/src/mage/cards/d/DaughterOfAutumn.java index 464864afe5..19cb73f774 100644 --- a/Mage.Sets/src/mage/cards/d/DaughterOfAutumn.java +++ b/Mage.Sets/src/mage/cards/d/DaughterOfAutumn.java @@ -45,6 +45,7 @@ import mage.filter.common.FilterCreaturePermanent; import mage.filter.predicate.mageobject.ColorPredicate; import mage.game.Game; import mage.game.events.GameEvent; +import mage.game.permanent.Permanent; import mage.target.TargetPermanent; import mage.target.common.TargetCreaturePermanent; @@ -71,7 +72,6 @@ public class DaughterOfAutumn extends CardImpl { // {W}: The next 1 damage that would be dealt to target white creature this turn is dealt to Daughter of Autumn instead. Ability ability = new SimpleActivatedAbility(Zone.BATTLEFIELD, new DaughterOfAutumnPreventDamageTargetEffect(Duration.EndOfTurn, 1), new ManaCostsImpl("{W}")); ability.addTarget(new TargetCreaturePermanent(filter)); - this.addAbility(ability); } public DaughterOfAutumn(final DaughterOfAutumn card) { @@ -86,6 +86,8 @@ public class DaughterOfAutumn extends CardImpl { class DaughterOfAutumnPreventDamageTargetEffect extends RedirectionEffect { + private static FilterCreaturePermanent filter = new FilterCreaturePermanent(); + public DaughterOfAutumnPreventDamageTargetEffect(Duration duration, int amount) { super(duration, amount, true); staticText = "The next " + amount + " damage that would be dealt to target white creature this turn is dealt to {this} instead"; @@ -102,13 +104,19 @@ class DaughterOfAutumnPreventDamageTargetEffect extends RedirectionEffect { @Override public boolean applies(GameEvent event, Ability source, Game game) { - if (event.getTargetId().equals(getTargetPointer().getFirst(game, source))) { - TargetPermanent target = new TargetPermanent(); - target.add(source.getSourceId(), game); - redirectTarget = target; - return true; + Permanent permanent = game.getBattlefield().getPermanent(source.getSourceId()); + if (permanent != null) { + if (filter.match(permanent, permanent.getId(), permanent.getControllerId(), game)) { + if (event.getTargetId().equals(getTargetPointer().getFirst(game, source))) { + if (event.getTargetId() != null) { + TargetPermanent target = new TargetPermanent(); + target.add(source.getSourceId(), game); + redirectTarget = target; + return true; + } + } + } } return false; } - } diff --git a/Mage.Sets/src/mage/cards/d/DazzlingBeauty.java b/Mage.Sets/src/mage/cards/d/DazzlingBeauty.java new file mode 100644 index 0000000000..02cbf8dcfd --- /dev/null +++ b/Mage.Sets/src/mage/cards/d/DazzlingBeauty.java @@ -0,0 +1,118 @@ +/* + * Copyright 2010 BetaSteward_at_googlemail.com. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are + * permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this list of + * conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, this list + * of conditions and the following disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY BetaSteward_at_googlemail.com ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BetaSteward_at_googlemail.com OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * The views and conclusions contained in the software and documentation are those of the + * authors and should not be interpreted as representing official policies, either expressed + * or implied, of BetaSteward_at_googlemail.com. + */ +package mage.cards.d; + +import java.util.UUID; +import mage.abilities.Ability; +import mage.abilities.common.CastOnlyDuringPhaseStepSourceAbility; +import mage.abilities.common.delayed.AtTheBeginOfNextUpkeepDelayedTriggeredAbility; +import mage.abilities.effects.OneShotEffect; +import mage.abilities.effects.common.CreateDelayedTriggeredAbilityEffect; +import mage.abilities.effects.common.DrawCardSourceControllerEffect; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.Outcome; +import mage.constants.PhaseStep; +import mage.filter.common.FilterCreaturePermanent; +import mage.filter.predicate.Predicates; +import mage.filter.predicate.permanent.AttackingPredicate; +import mage.filter.predicate.permanent.BlockedPredicate; +import mage.game.Game; +import mage.game.combat.CombatGroup; +import mage.game.permanent.Permanent; +import mage.players.Player; +import mage.target.common.TargetCreaturePermanent; + +/** + * + * @author LevelX2 & L_J + */ +public class DazzlingBeauty extends CardImpl { + + private static final FilterCreaturePermanent filter = new FilterCreaturePermanent("unblocked attacking creature"); + + static { + filter.add(new AttackingPredicate()); + filter.add(Predicates.not(new BlockedPredicate())); + } + + public DazzlingBeauty(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.INSTANT}, "{2}{W}"); + + // Cast Dazzling Beauty only during the declare blockers step. + this.addAbility(new CastOnlyDuringPhaseStepSourceAbility(null, PhaseStep.DECLARE_BLOCKERS, null, "Cast Dazzling Beauty only during the declare blockers step")); + + // Target unblocked attacking creature becomes blocked. + this.getSpellAbility().addEffect(new DazzlingBeautyEffect()); + this.getSpellAbility().addTarget(new TargetCreaturePermanent(filter)); + + // Draw a card at the beginning of the next turn's upkeep. + this.getSpellAbility().addEffect(new CreateDelayedTriggeredAbilityEffect(new AtTheBeginOfNextUpkeepDelayedTriggeredAbility(new DrawCardSourceControllerEffect(1)), false)); + } + + public DazzlingBeauty(final DazzlingBeauty card) { + super(card); + } + + @Override + public DazzlingBeauty copy() { + return new DazzlingBeauty(this); + } +} + +class DazzlingBeautyEffect extends OneShotEffect { + + public DazzlingBeautyEffect() { + super(Outcome.Benefit); + this.staticText = "Target unblocked attacking creature becomes blocked"; + } + + public DazzlingBeautyEffect(final DazzlingBeautyEffect effect) { + super(effect); + } + + @Override + public DazzlingBeautyEffect copy() { + return new DazzlingBeautyEffect(this); + } + + @Override + public boolean apply(Game game, Ability source) { + Player controller = game.getPlayer(source.getControllerId()); + Permanent permanent = game.getPermanent(getTargetPointer().getFirst(game, source)); + if (controller != null && permanent != null) { + CombatGroup combatGroup = game.getCombat().findGroup(permanent.getId()); + if (combatGroup != null) { + combatGroup.setBlocked(true); + return true; + } + } + return false; + } +} diff --git a/Mage.Sets/src/mage/cards/d/DeadIronSledge.java b/Mage.Sets/src/mage/cards/d/DeadIronSledge.java new file mode 100644 index 0000000000..a93cad40ce --- /dev/null +++ b/Mage.Sets/src/mage/cards/d/DeadIronSledge.java @@ -0,0 +1,176 @@ +/* + * Copyright 2010 BetaSteward_at_googlemail.com. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are + * permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this list of + * conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, this list + * of conditions and the following disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY BetaSteward_at_googlemail.com ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BetaSteward_at_googlemail.com OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * The views and conclusions contained in the software and documentation are those of the + * authors and should not be interpreted as representing official policies, either expressed + * or implied, of BetaSteward_at_googlemail.com. + */ +package mage.cards.d; + +import java.util.ArrayList; +import java.util.HashSet; +import java.util.List; +import java.util.Set; +import java.util.UUID; +import mage.abilities.Ability; +import mage.abilities.TriggeredAbility; +import mage.abilities.TriggeredAbilityImpl; +import mage.abilities.costs.mana.GenericManaCost; +import mage.abilities.effects.OneShotEffect; +import mage.abilities.keyword.EquipAbility; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.Outcome; +import mage.constants.SubType; +import mage.constants.Zone; +import mage.game.Game; +import mage.game.combat.CombatGroup; +import mage.game.events.GameEvent; +import mage.game.permanent.Permanent; +import mage.target.targetpointer.FixedTargets; + +/** + * + * @author jerekwilson + */ +public class DeadIronSledge extends CardImpl { + + public DeadIronSledge(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.ARTIFACT}, "{1}"); + this.subtype.add(SubType.EQUIPMENT); + + // Whenever equipped creature blocks or becomes blocked by a creature, destroy both creatures. + this.addAbility(new DeadIronSledgeTriggeredAbility()); + + // Equip {2} + this.addAbility(new EquipAbility(Outcome.AddAbility, new GenericManaCost(2))); + } + + public DeadIronSledge(final DeadIronSledge card) { + super(card); + } + + @Override + public DeadIronSledge copy() { + return new DeadIronSledge(this); + } + +} + +class DeadIronSledgeTriggeredAbility extends TriggeredAbilityImpl { + + private Set possibleTargets = new HashSet<>(); + + DeadIronSledgeTriggeredAbility() { + super(Zone.BATTLEFIELD, new DeadIronSledgeDestroyEffect(), false); + } + + DeadIronSledgeTriggeredAbility(final DeadIronSledgeTriggeredAbility ability) { + super(ability); + } + + @Override + public boolean checkEventType(GameEvent event, Game game) { + return event.getType() == GameEvent.EventType.DECLARED_BLOCKERS; + } + + @Override + public boolean checkTrigger(GameEvent event, Game game) { + List targetPermanents = new ArrayList<>(); + Permanent equipment = game.getPermanentOrLKIBattlefield((this.getSourceId())); + if (equipment != null && equipment.getAttachedTo() != null) { + Permanent equippedPermanent = game.getPermanentOrLKIBattlefield((equipment.getAttachedTo())); + if (equippedPermanent != null) { + possibleTargets.clear(); + if (equippedPermanent.isBlocked(game)) { + possibleTargets.add(equippedPermanent.getId()); //add equipped creature to target list + } + if (equippedPermanent.isAttacking()) { + for (CombatGroup group : game.getCombat().getGroups()) { + if (group.getAttackers().contains(equippedPermanent.getId())) { + possibleTargets.addAll(group.getBlockers()); + } + } + } else if (equippedPermanent.getBlocking() > 0) { + for (CombatGroup group : game.getCombat().getGroups()) { + if (group.getBlockers().contains(equippedPermanent.getId())) { + possibleTargets.addAll(group.getAttackers()); + } + } + } + if (!possibleTargets.isEmpty()) { + this.getTargets().clear(); + + for (UUID creatureId : possibleTargets) { + Permanent target = game.getPermanentOrLKIBattlefield(creatureId); + targetPermanents.add(target); + } + + this.getEffects().get(0).setTargetPointer(new FixedTargets(targetPermanents, game)); + + return true; + } + } + } + return false; + } + + @Override + public TriggeredAbility copy() { + return new DeadIronSledgeTriggeredAbility(this); + } + + @Override + public String getRule() { + return "Whenever equipped creature blocks or becomes blocked by a creature, destroy both creatures."; + } +} + +class DeadIronSledgeDestroyEffect extends OneShotEffect { + + public DeadIronSledgeDestroyEffect() { + super(Outcome.DestroyPermanent); + this.staticText = "destroy both creatures"; + } + + public DeadIronSledgeDestroyEffect(final DeadIronSledgeDestroyEffect effect) { + super(effect); + } + + @Override + public DeadIronSledgeDestroyEffect copy() { + return new DeadIronSledgeDestroyEffect(this); + } + + @Override + public boolean apply(Game game, Ability source) { + for (UUID targetId : this.getTargetPointer().getTargets(game, source)) { + Permanent permanent = game.getPermanent(targetId); + if (permanent != null) { + permanent.destroy(targetId, game, false); + } + } + return true; + } +} diff --git a/Mage.Sets/src/mage/cards/d/DecreeOfJustice.java b/Mage.Sets/src/mage/cards/d/DecreeOfJustice.java index a812b8ff22..8b13bccdb7 100644 --- a/Mage.Sets/src/mage/cards/d/DecreeOfJustice.java +++ b/Mage.Sets/src/mage/cards/d/DecreeOfJustice.java @@ -30,9 +30,8 @@ package mage.cards.d; import java.util.UUID; import mage.abilities.Ability; import mage.abilities.common.CycleTriggeredAbility; +import mage.abilities.costs.Cost; import mage.abilities.costs.mana.GenericManaCost; -import mage.abilities.costs.mana.ManaCost; -import mage.abilities.costs.mana.ManaCosts; import mage.abilities.costs.mana.ManaCostsImpl; import mage.abilities.dynamicvalue.common.ManacostVariableValue; import mage.abilities.effects.OneShotEffect; @@ -55,15 +54,14 @@ import mage.players.Player; public class DecreeOfJustice extends CardImpl { public DecreeOfJustice(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.SORCERY},"{X}{X}{2}{W}{W}"); + super(ownerId, setInfo, new CardType[]{CardType.SORCERY}, "{X}{X}{2}{W}{W}"); - - // create X 4/4 white Angel creature tokens with flying. + // Create X 4/4 white Angel creature tokens with flying. this.getSpellAbility().addEffect(new CreateTokenEffect(new AngelToken(), new ManacostVariableValue())); - + // Cycling {2}{W} this.addAbility(new CyclingAbility(new ManaCostsImpl<>("{2}{W}"))); - + // When you cycle Decree of Justice, you may pay {X}. If you do, create X 1/1 white Soldier creature tokens. Ability ability = new CycleTriggeredAbility(new DecreeOfJusticeCycleEffect(), true); this.addAbility(ability); @@ -80,31 +78,31 @@ public class DecreeOfJustice extends CardImpl { } class DecreeOfJusticeCycleEffect extends OneShotEffect { - + DecreeOfJusticeCycleEffect() { super(Outcome.Benefit); this.staticText = "you may pay {X}. If you do, create X 1/1 white Soldier creature tokens"; } - + DecreeOfJusticeCycleEffect(final DecreeOfJusticeCycleEffect effect) { super(effect); } - + @Override public DecreeOfJusticeCycleEffect copy() { return new DecreeOfJusticeCycleEffect(this); } - + @Override public boolean apply(Game game, Ability source) { Player player = game.getPlayer(source.getControllerId()); - ManaCosts cost = new ManaCostsImpl<>("{X}"); if (player != null) { - int costX = player.announceXMana(0, Integer.MAX_VALUE, "Announce the value for {X}", game, source); - cost.add(new GenericManaCost(costX)); - if (cost.pay(source, game, source.getSourceId(), source.getControllerId(), false, null)) { + int X = player.announceXMana(0, Integer.MAX_VALUE, "Announce the value for {X}", game, source); + Cost cost = new GenericManaCost(X); + if (cost.pay(source, game, source.getSourceId(), source.getControllerId(), false)) { Token token = new SoldierToken(); - token.putOntoBattlefield(costX, game, source.getSourceId(), source.getControllerId()); + token.putOntoBattlefield(X, game, source.getSourceId(), source.getControllerId()); + return true; } } return false; diff --git a/Mage.Sets/src/mage/cards/d/DefiantStand.java b/Mage.Sets/src/mage/cards/d/DefiantStand.java new file mode 100644 index 0000000000..cc089e3303 --- /dev/null +++ b/Mage.Sets/src/mage/cards/d/DefiantStand.java @@ -0,0 +1,76 @@ +/* + * Copyright 2010 BetaSteward_at_googlemail.com. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are + * permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this list of + * conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, this list + * of conditions and the following disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY BetaSteward_at_googlemail.com ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BetaSteward_at_googlemail.com OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * The views and conclusions contained in the software and documentation are those of the + * authors and should not be interpreted as representing official policies, either expressed + * or implied, of BetaSteward_at_googlemail.com. + */ +package mage.cards.d; + +import java.util.UUID; +import mage.abilities.Ability; +import mage.abilities.common.CastOnlyDuringPhaseStepSourceAbility; +import mage.abilities.condition.common.AttackedThisStepCondition; +import mage.abilities.effects.common.UntapTargetEffect; +import mage.abilities.effects.common.continuous.BoostTargetEffect; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.Duration; +import mage.constants.PhaseStep; +import mage.constants.TurnPhase; +import mage.target.common.TargetCreaturePermanent; +import mage.watchers.common.PlayerAttackedStepWatcher; + +/** + * + * @author TheElk801 + */ +public class DefiantStand extends CardImpl { + + public DefiantStand(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.INSTANT}, "{1}{W}"); + + // Cast Defiant Stand only during the declare attackers step and only if you've been attacked this step. + Ability ability = new CastOnlyDuringPhaseStepSourceAbility( + TurnPhase.COMBAT, PhaseStep.DECLARE_ATTACKERS, AttackedThisStepCondition.instance, + "Cast {this} only during the declare attackers step and only if you've been attacked this step." + ); + ability.addWatcher(new PlayerAttackedStepWatcher()); + this.addAbility(ability); + + // Target creature gets +1/+3 until end of turn. Untap that creature. + this.getSpellAbility().addEffect(new BoostTargetEffect(1, 3, Duration.EndOfTurn)); + this.getSpellAbility().addEffect(new UntapTargetEffect().setText("Untap that creature")); + this.getSpellAbility().addTarget(new TargetCreaturePermanent()); + } + + public DefiantStand(final DefiantStand card) { + super(card); + } + + @Override + public DefiantStand copy() { + return new DefiantStand(this); + } +} diff --git a/Mage.Sets/src/mage/cards/d/DereviEmpyrialTactician.java b/Mage.Sets/src/mage/cards/d/DereviEmpyrialTactician.java index 38fd233b3a..2ac726055c 100644 --- a/Mage.Sets/src/mage/cards/d/DereviEmpyrialTactician.java +++ b/Mage.Sets/src/mage/cards/d/DereviEmpyrialTactician.java @@ -60,7 +60,7 @@ import mage.target.TargetPermanent; public class DereviEmpyrialTactician extends CardImpl { public DereviEmpyrialTactician(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.CREATURE},"{G}{W}{U}"); + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{G}{W}{U}"); addSuperType(SuperType.LEGENDARY); this.subtype.add(SubType.BIRD); this.subtype.add(SubType.WIZARD); @@ -74,7 +74,7 @@ public class DereviEmpyrialTactician extends CardImpl { Ability ability = new DereviEmpyrialTacticianTriggeredAbility(new MayTapOrUntapTargetEffect()); ability.addTarget(new TargetPermanent()); this.addAbility(ability); - + // {1}{G}{W}{U}: Put Derevi onto the battlefield from the command zone. this.addAbility(new DereviEmpyrialTacticianAbility()); } @@ -132,7 +132,7 @@ class DereviEmpyrialTacticianTriggeredAbility extends TriggeredAbilityImpl { } } - class DereviEmpyrialTacticianAbility extends ActivatedAbilityImpl { +class DereviEmpyrialTacticianAbility extends ActivatedAbilityImpl { public DereviEmpyrialTacticianAbility() { super(Zone.COMMAND, new PutCommanderOnBattlefieldEffect(), new ManaCostsImpl("{1}{G}{W}{U}")); @@ -182,7 +182,7 @@ class PutCommanderOnBattlefieldEffect extends OneShotEffect { } Card card = game.getCard(source.getSourceId()); if (card != null) { - card.putOntoBattlefield(game, Zone.COMMAND, source.getSourceId(), source.getControllerId()); + player.moveCards(card, Zone.BATTLEFIELD, source, game); return true; } return false; diff --git a/Mage.Sets/src/mage/cards/d/DesperateGambit.java b/Mage.Sets/src/mage/cards/d/DesperateGambit.java new file mode 100644 index 0000000000..1272b4c729 --- /dev/null +++ b/Mage.Sets/src/mage/cards/d/DesperateGambit.java @@ -0,0 +1,231 @@ +/* + * Copyright 2010 BetaSteward_at_googlemail.com. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are + * permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this list of + * conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, this list + * of conditions and the following disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY BetaSteward_at_googlemail.com ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BetaSteward_at_googlemail.com OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * The views and conclusions contained in the software and documentation are those of the + * authors and should not be interpreted as representing official policies, either expressed + * or implied, of BetaSteward_at_googlemail.com. + */ +package mage.cards.d; + +import java.util.HashSet; +import java.util.Set; +import java.util.UUID; +import mage.MageObject; +import mage.abilities.Ability; +import mage.abilities.effects.PreventionEffectImpl; +import mage.abilities.effects.common.PreventDamageBySourceEffect; +import mage.cards.Card; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.Duration; +import mage.constants.Outcome; +import mage.game.Game; +import mage.game.events.DamageEvent; +import mage.game.events.GameEvent; +import mage.game.permanent.Permanent; +import mage.game.stack.StackObject; +import mage.filter.FilterObject; +import mage.filter.predicate.permanent.ControllerPredicate; +import mage.players.Player; +import mage.target.TargetSource; + +/** + * + * @author L_J + */ +public class DesperateGambit extends CardImpl { + + public DesperateGambit(UUID ownerId, CardSetInfo setInfo) { + super(ownerId,setInfo,new CardType[]{CardType.INSTANT},"{R}"); + + // Choose a source you control and flip a coin. If you win the flip, the next time that source would deal damage this turn, it deals double that damage instead. If you lose the flip, the next time it would deal damage this turn, prevent that damage. + this.getSpellAbility().addEffect(new DesperateGambitEffect()); + } + + public DesperateGambit(final DesperateGambit card) { + super(card); + } + + @Override + public DesperateGambit copy() { + return new DesperateGambit(this); + } +} + +class DesperateGambitEffect extends PreventionEffectImpl { + + private final TargetSource target; + private boolean wonFlip; + + public DesperateGambitEffect() { + super(Duration.EndOfTurn, Integer.MAX_VALUE, false); + staticText = "Choose a source you control and flip a coin. If you win the flip, the next time that source would deal damage this turn, it deals double that damage instead. If you lose the flip, the next time it would deal damage this turn, prevent that damage"; + this.target = new TargetControlledSource(); + } + + public DesperateGambitEffect(final DesperateGambitEffect effect) { + super(effect); + this.target = effect.target.copy(); + } + + @Override + public void init(Ability source, Game game) { + this.target.choose(Outcome.Benefit, source.getControllerId(), source.getSourceId(), game); + this.wonFlip = game.getPlayer(source.getControllerId()).flipCoin(game); + super.init(source, game); + } + + @Override + public DesperateGambitEffect copy() { + return new DesperateGambitEffect(this); + } + + @Override + public boolean checksEventType(GameEvent event, Game game) { + return event.getType() == GameEvent.EventType.DAMAGE_CREATURE || + event.getType() == GameEvent.EventType.DAMAGE_PLANESWALKER || + event.getType() == GameEvent.EventType.DAMAGE_PLAYER; + } + + @Override + public boolean applies(GameEvent event, Ability source, Game game) { + if (event.getSourceId().equals(target.getFirstTarget())) { + // check source + MageObject object = game.getObject(event.getSourceId()); + if (object == null) { + game.informPlayers("Couldn't find source of damage"); + return false; + } + return true; + } + return false; + } + + @Override + public boolean replaceEvent(GameEvent event, Ability source, Game game) { + MageObject object = game.getObject(event.getSourceId()); + Player controller = game.getPlayer(source.getControllerId()); + if (controller != null && object != null) { + if (super.applies(event, source, game) && event instanceof DamageEvent && event.getAmount() > 0) { + if (wonFlip) { + event.setAmount(event.getAmount() * 2); + this.discard(); + } else { + preventDamageAction(event, source, game); + this.discard(); + return true; + } + } + } + return false; + } +} + +class TargetControlledSource extends TargetSource { + + public TargetControlledSource() { + super(1, 1, new FilterObject("source you control")); + } + + public TargetControlledSource(final TargetControlledSource target) { + super(target); + } + + @Override + public boolean canChoose(UUID sourceControllerId, Game game) { + int count = 0; + for (StackObject stackObject: game.getStack()) { + if (game.getState().getPlayersInRange(sourceControllerId, game).contains(stackObject.getControllerId()) + && stackObject.getControllerId() == sourceControllerId) { + count++; + if (count >= this.minNumberOfTargets) { + return true; + } + } + } + for (Permanent permanent: game.getBattlefield().getActivePermanents(sourceControllerId, game)) { + if (permanent.getControllerId() == sourceControllerId) { + count++; + if (count >= this.minNumberOfTargets) { + return true; + } + } + } + for (Player player : game.getPlayers().values()) { + if (player == game.getPlayer(sourceControllerId)) { + for (Card card : player.getGraveyard().getCards(game)) { + count++; + if (count >= this.minNumberOfTargets) { + return true; + } + } + // 108.4a If anything asks for the controller of a card that doesn’t have one (because it’s not a permanent or spell), use its owner instead. + for (Card card : game.getExile().getAllCards(game)) { + if (card.getOwnerId() == sourceControllerId) { + count++; + if (count >= this.minNumberOfTargets) { + return true; + } + } + } + } + } + return false; + } + + @Override + public Set possibleTargets(UUID sourceControllerId, Game game) { + Set possibleTargets = new HashSet<>(); + for (StackObject stackObject: game.getStack()) { + if (game.getState().getPlayersInRange(sourceControllerId, game).contains(stackObject.getControllerId()) + && stackObject.getControllerId() == sourceControllerId) { + possibleTargets.add(stackObject.getId()); + } + } + for (Permanent permanent: game.getBattlefield().getActivePermanents(sourceControllerId, game)) { + if (permanent.getControllerId() == sourceControllerId) { + possibleTargets.add(permanent.getId()); + } + } + for (Player player : game.getPlayers().values()) { + if (player == game.getPlayer(sourceControllerId)) { + for (Card card : player.getGraveyard().getCards(game)) { + possibleTargets.add(card.getId()); + } + // 108.4a If anything asks for the controller of a card that doesn’t have one (because it’s not a permanent or spell), use its owner instead. + for (Card card : game.getExile().getAllCards(game)) { + if (card.getOwnerId() == sourceControllerId) { + possibleTargets.add(card.getId()); + } + } + } + } + return possibleTargets; + } + + @Override + public TargetControlledSource copy() { + return new TargetControlledSource(this); + } +} diff --git a/Mage.Sets/src/mage/cards/d/DreamTides.java b/Mage.Sets/src/mage/cards/d/DreamTides.java new file mode 100644 index 0000000000..c47b8dc3d4 --- /dev/null +++ b/Mage.Sets/src/mage/cards/d/DreamTides.java @@ -0,0 +1,128 @@ +/* + * Copyright 2010 BetaSteward_at_googlemail.com. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are + * permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this list of + * conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, this list + * of conditions and the following disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY BetaSteward_at_googlemail.com ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BetaSteward_at_googlemail.com OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * The views and conclusions contained in the software and documentation are those of the + * authors and should not be interpreted as representing official policies, either expressed + * or implied, of BetaSteward_at_googlemail.com. + */ +package mage.cards.d; + +import java.util.UUID; +import mage.ObjectColor; +import mage.abilities.Ability; +import mage.abilities.common.BeginningOfUpkeepTriggeredAbility; +import mage.abilities.common.SimpleStaticAbility; +import mage.abilities.costs.mana.GenericManaCost; +import mage.abilities.effects.OneShotEffect; +import mage.abilities.effects.common.DontUntapInControllersUntapStepAllEffect; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.Duration; +import mage.constants.Outcome; +import mage.constants.TargetController; +import mage.constants.Zone; +import mage.filter.common.FilterControlledCreaturePermanent; +import mage.filter.common.FilterCreaturePermanent; +import mage.filter.predicate.Predicates; +import mage.filter.predicate.mageobject.ColorPredicate; +import mage.filter.predicate.permanent.TappedPredicate; +import mage.game.Game; +import mage.game.permanent.Permanent; +import mage.players.Player; +import mage.target.Target; +import mage.target.common.TargetControlledCreaturePermanent; + +/** + * + * @author spjspj & L_J + */ +public class DreamTides extends CardImpl { + + public DreamTides(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.ENCHANTMENT}, "{2}{U}{U}"); + + // Creatures don't untap during their controllers' untap steps. + this.addAbility(new SimpleStaticAbility(Zone.BATTLEFIELD, new DontUntapInControllersUntapStepAllEffect(Duration.WhileOnBattlefield, TargetController.ANY, new FilterCreaturePermanent("Creatures")))); + + // At the beginning of each player's upkeep, that player may choose any number of tapped nongreen creatures he or she controls and pay {2} for each creature chosen this way. If the player does, untap those creatures. + this.addAbility(new BeginningOfUpkeepTriggeredAbility(Zone.BATTLEFIELD, new DreamTidesEffect(), TargetController.ANY, false)); + } + + public DreamTides(final DreamTides card) { + super(card); + } + + @Override + public DreamTides copy() { + return new DreamTides(this); + } +} + +class DreamTidesEffect extends OneShotEffect { + + private static final FilterControlledCreaturePermanent filter = new FilterControlledCreaturePermanent("tapped nongreen creature"); + + static { + filter.add(Predicates.not(new ColorPredicate(ObjectColor.GREEN))); + filter.add(new TappedPredicate()); + } + + DreamTidesEffect() { + super(Outcome.Benefit); + staticText = "that player may choose any number of tapped nongreen creatures he or she controls and pay {2} for each creature chosen this way. If the player does, untap those creatures"; + } + + DreamTidesEffect(DreamTidesEffect effect) { + super(effect); + } + + @Override + public DreamTidesEffect copy() { + return new DreamTidesEffect(this); + } + + @Override + public boolean apply(Game game, Ability source) { + + Player player = game.getPlayer(targetPointer.getFirst(game, source)); + Permanent sourcePermanent = game.getPermanent(source.getSourceId()); + if (player != null && sourcePermanent != null) { + int countBattlefield = game.getBattlefield().getAllActivePermanents(filter, game.getActivePlayerId(), game).size(); + while (player.canRespond() && countBattlefield > 0 && player.chooseUse(Outcome.AIDontUseIt, "Pay {2} and untap a tapped nongreen creature under your control?", source, game)) { + Target tappedCreatureTarget = new TargetControlledCreaturePermanent(1, 1, filter, true); + if (player.choose(Outcome.Detriment, tappedCreatureTarget, source.getSourceId(), game)) { + GenericManaCost cost = new GenericManaCost(2); + Permanent tappedCreature = game.getPermanent(tappedCreatureTarget.getFirstTarget()); + + if (cost.pay(source, game, source.getSourceId(), player.getId(), false)) { + tappedCreature.untap(game); + } + } + countBattlefield = game.getBattlefield().getAllActivePermanents(filter, game.getActivePlayerId(), game).size(); + } + return true; + } + return false; + } +} diff --git a/Mage.Sets/src/mage/cards/e/EightfoldMaze.java b/Mage.Sets/src/mage/cards/e/EightfoldMaze.java new file mode 100644 index 0000000000..293c3b0792 --- /dev/null +++ b/Mage.Sets/src/mage/cards/e/EightfoldMaze.java @@ -0,0 +1,73 @@ +/* + * Copyright 2010 BetaSteward_at_googlemail.com. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are + * permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this list of + * conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, this list + * of conditions and the following disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY BetaSteward_at_googlemail.com ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BetaSteward_at_googlemail.com OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * The views and conclusions contained in the software and documentation are those of the + * authors and should not be interpreted as representing official policies, either expressed + * or implied, of BetaSteward_at_googlemail.com. + */ +package mage.cards.e; + +import java.util.UUID; +import mage.abilities.Ability; +import mage.abilities.common.CastOnlyDuringPhaseStepSourceAbility; +import mage.abilities.condition.common.AttackedThisStepCondition; +import mage.abilities.effects.common.DestroyTargetEffect; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.PhaseStep; +import mage.constants.TurnPhase; +import mage.target.common.TargetAttackingCreature; +import mage.watchers.common.PlayerAttackedStepWatcher; + +/** + * + * @author TheElk801 + */ +public class EightfoldMaze extends CardImpl { + + public EightfoldMaze(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.INSTANT}, "{2}{W}"); + + // Cast Eightfold Maze only during the declare attackers step and only if you've been attacked this step. + Ability ability = new CastOnlyDuringPhaseStepSourceAbility( + TurnPhase.COMBAT, PhaseStep.DECLARE_ATTACKERS, AttackedThisStepCondition.instance, + "Cast {this} only during the declare attackers step and only if you've been attacked this step." + ); + ability.addWatcher(new PlayerAttackedStepWatcher()); + this.addAbility(ability); + + // Destroy target attacking creature. + this.getSpellAbility().addEffect(new DestroyTargetEffect()); + this.getSpellAbility().addTarget(new TargetAttackingCreature()); + } + + public EightfoldMaze(final EightfoldMaze card) { + super(card); + } + + @Override + public EightfoldMaze copy() { + return new EightfoldMaze(this); + } +} diff --git a/Mage.Sets/src/mage/cards/e/ElkinLair.java b/Mage.Sets/src/mage/cards/e/ElkinLair.java new file mode 100644 index 0000000000..861992f639 --- /dev/null +++ b/Mage.Sets/src/mage/cards/e/ElkinLair.java @@ -0,0 +1,186 @@ +/* + * Copyright 2010 BetaSteward_at_googlemail.com. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are + * permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this list of + * conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, this list + * of conditions and the following disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY BetaSteward_at_googlemail.com ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BetaSteward_at_googlemail.com OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * The views and conclusions contained in the software and documentation are those of the + * authors and should not be interpreted as representing official policies, either expressed + * or implied, of BetaSteward_at_googlemail.com. + */ +package mage.cards.e; + +import java.util.Set; +import java.util.UUID; +import mage.abilities.Ability; +import mage.abilities.DelayedTriggeredAbility; +import mage.abilities.common.BeginningOfUpkeepTriggeredAbility; +import mage.abilities.common.delayed.AtTheBeginOfNextEndStepDelayedTriggeredAbility; +import mage.abilities.effects.AsThoughEffectImpl; +import mage.abilities.effects.ContinuousEffect; +import mage.abilities.effects.OneShotEffect; +import mage.cards.Card; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.AsThoughEffectType; +import mage.constants.CardType; +import mage.constants.Duration; +import mage.constants.Outcome; +import mage.constants.SuperType; +import mage.constants.TargetController; +import mage.constants.Zone; +import mage.game.Game; +import mage.game.permanent.Permanent; +import mage.filter.FilterCard; +import mage.players.Player; +import mage.target.targetpointer.FixedTarget; +import mage.util.RandomUtil; + +/** + * + * @author L_J + */ +public class ElkinLair extends CardImpl { + + public ElkinLair(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.ENCHANTMENT}, "{3}{R}"); + addSuperType(SuperType.WORLD); + + // At the beginning of each player's upkeep, that player exiles a card at random from his or her hand. The player may play that card this turn. At the beginning of the next end step, if the player hasn't played the card, he or she puts it into his or her graveyard. + this.addAbility(new BeginningOfUpkeepTriggeredAbility(new ElkinLairUpkeepEffect(), TargetController.ANY, false)); + + } + + public ElkinLair(final ElkinLair card) { + super(card); + } + + @Override + public ElkinLair copy() { + return new ElkinLair(this); + } + +} + +class ElkinLairUpkeepEffect extends OneShotEffect { + + public ElkinLairUpkeepEffect() { + super(Outcome.Benefit); + this.staticText = "that player exiles a card at random from his or her hand. The player may play that card this turn. At the beginning of the next end step, if the player hasn't played the card, he or she puts it into his or her graveyard"; + } + + public ElkinLairUpkeepEffect(final ElkinLairUpkeepEffect effect) { + super(effect); + } + + @Override + public ElkinLairUpkeepEffect copy() { + return new ElkinLairUpkeepEffect(this); + } + + @Override + public boolean apply(Game game, Ability source) { + Player player = game.getPlayer(game.getActivePlayerId()); + Permanent sourcePermanent = game.getPermanentOrLKIBattlefield(source.getSourceId()); + if (player != null && sourcePermanent != null) { + Card[] cards = player.getHand().getCards(new FilterCard(), game).toArray(new Card[0]); + if (cards.length > 0) { + Card card = cards[RandomUtil.nextInt(cards.length)]; + if (card != null) { + String exileName = sourcePermanent.getIdName() + " cardsInExile = game.getExile().getExileZone(source.getSourceId()).getCards(game); + if (cardsInExile != null) { + player.moveCardsToGraveyardWithInfo(cardsInExile, source, game, Zone.EXILED); + return true; + } + } + return false; + } + + @Override + public ElkinLairPutIntoGraveyardEffect copy() { + return new ElkinLairPutIntoGraveyardEffect(this); + } +} diff --git a/Mage.Sets/src/mage/cards/e/EndbringersRevel.java b/Mage.Sets/src/mage/cards/e/EndbringersRevel.java new file mode 100644 index 0000000000..0ac33742af --- /dev/null +++ b/Mage.Sets/src/mage/cards/e/EndbringersRevel.java @@ -0,0 +1,69 @@ +/* + * Copyright 2010 BetaSteward_at_googlemail.com. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are + * permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this list of + * conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, this list + * of conditions and the following disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY BetaSteward_at_googlemail.com ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BetaSteward_at_googlemail.com OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * The views and conclusions contained in the software and documentation are those of the + * authors and should not be interpreted as representing official policies, either expressed + * or implied, of BetaSteward_at_googlemail.com. + */ +package mage.cards.e; + +import java.util.UUID; +import mage.abilities.Ability; +import mage.abilities.common.ActivateAsSorceryActivatedAbility; +import mage.abilities.costs.mana.ManaCostsImpl; +import mage.abilities.effects.common.InfoEffect; +import mage.abilities.effects.common.ReturnToHandTargetEffect; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.TargetController; +import mage.constants.Zone; +import mage.filter.common.FilterCreatureCard; +import mage.target.common.TargetCardInGraveyard; + +/** + * + * @author L_J + */ +public class EndbringersRevel extends CardImpl { + + public EndbringersRevel(UUID ownerId, CardSetInfo setInfo) { + super(ownerId,setInfo,new CardType[]{CardType.ENCHANTMENT},"{2}{B}"); + + // {4}: Return target creature card from a graveyard to its owner's hand. Any player may activate this ability but only any time he or she could cast a sorcery. + ActivateAsSorceryActivatedAbility ability = new ActivateAsSorceryActivatedAbility(Zone.BATTLEFIELD, new ReturnToHandTargetEffect(), new ManaCostsImpl("{4}")); + ability.addTarget(new TargetCardInGraveyard(new FilterCreatureCard("creature card in a graveyard"))); + ability.setMayActivate(TargetController.ANY); + ability.addEffect(new InfoEffect("Any player may activate this ability")); + this.addAbility(ability); + } + + public EndbringersRevel(final EndbringersRevel card) { + super(card); + } + + @Override + public EndbringersRevel copy() { + return new EndbringersRevel(this); + } +} diff --git a/Mage.Sets/src/mage/cards/e/Equipoise.java b/Mage.Sets/src/mage/cards/e/Equipoise.java index 7f3f526804..46aafab810 100644 --- a/Mage.Sets/src/mage/cards/e/Equipoise.java +++ b/Mage.Sets/src/mage/cards/e/Equipoise.java @@ -27,11 +27,13 @@ */ package mage.cards.e; +import java.util.List; import java.util.Objects; import java.util.UUID; import mage.abilities.Ability; import mage.abilities.common.BeginningOfUpkeepTriggeredAbility; import mage.abilities.effects.OneShotEffect; +import mage.abilities.effects.common.PhaseOutAllEffect; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; @@ -55,8 +57,7 @@ import mage.target.TargetPlayer; public class Equipoise extends CardImpl { public Equipoise(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.ENCHANTMENT},"{2}{W}"); - + super(ownerId, setInfo, new CardType[]{CardType.ENCHANTMENT}, "{2}{W}"); // At the beginning of your upkeep, for each land target player controls in excess of the number you control, choose a land he or she controls, then the chosen permanents phase out. Repeat this process for artifacts and creatures. Ability ability = new BeginningOfUpkeepTriggeredAbility(new EquipoiseEffect(), TargetController.YOU, false); @@ -112,17 +113,12 @@ class EquipoiseEffect extends OneShotEffect { int numberTargetPlayer = game.getBattlefield().count(filter, source.getSourceId(), targetPlayer.getId(), game); int excess = numberTargetPlayer - numberController; if (excess > 0) { - FilterPermanent filterChoose = new FilterPermanent(cardType.toString().toLowerCase() + (excess > 1 ? "s":"") +" of target player"); + FilterPermanent filterChoose = new FilterPermanent(cardType.toString().toLowerCase() + (excess > 1 ? "s" : "") + " of target player"); filterChoose.add(new ControllerIdPredicate(targetPlayer.getId())); filterChoose.add(new CardTypePredicate(cardType)); Target target = new TargetPermanent(excess, excess, filterChoose, true); controller.chooseTarget(outcome, target, source, game); - for (UUID permanentId:target.getTargets()) { - Permanent permanent = game.getPermanent(permanentId); - if (permanent != null) { - permanent.phaseOut(game); - } - } + new PhaseOutAllEffect(target.getTargets()).apply(game, source); } } } diff --git a/Mage.Sets/src/mage/cards/e/EyeOfYawgmoth.java b/Mage.Sets/src/mage/cards/e/EyeOfYawgmoth.java new file mode 100644 index 0000000000..b597cb6fa6 --- /dev/null +++ b/Mage.Sets/src/mage/cards/e/EyeOfYawgmoth.java @@ -0,0 +1,137 @@ +/* + * Copyright 2010 BetaSteward_at_googlemail.com. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are + * permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this list of + * conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, this list + * of conditions and the following disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY BetaSteward_at_googlemail.com ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BetaSteward_at_googlemail.com OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * The views and conclusions contained in the software and documentation are those of the + * authors and should not be interpreted as representing official policies, either expressed + * or implied, of BetaSteward_at_googlemail.com. + */ +package mage.cards.e; + +import java.util.UUID; +import mage.abilities.Ability; +import mage.abilities.common.SimpleActivatedAbility; +import mage.abilities.costs.Cost; +import mage.abilities.costs.common.SacrificeTargetCost; +import mage.abilities.costs.common.TapSourceCost; +import mage.abilities.costs.mana.GenericManaCost; +import mage.abilities.effects.OneShotEffect; +import mage.cards.Card; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.cards.Cards; +import mage.cards.CardsImpl; +import mage.constants.CardType; +import mage.constants.Outcome; +import mage.constants.Zone; +import mage.filter.FilterCard; +import mage.filter.common.FilterControlledCreaturePermanent; +import mage.game.Game; +import mage.game.permanent.Permanent; +import mage.players.Player; +import mage.target.Target; +import mage.target.TargetCard; +import mage.target.common.TargetControlledCreaturePermanent; + +/** + * + * @author L_J + */ +public class EyeOfYawgmoth extends CardImpl { + + public EyeOfYawgmoth(UUID ownerId, CardSetInfo setInfo) { + super(ownerId,setInfo,new CardType[]{CardType.ARTIFACT},"{3}"); + + // {3}, {T}, Sacrifice a creature: Reveal a number of cards from the top of your library equal to the sacrificed creature's power. Put one into your hand and exile the rest. + SimpleActivatedAbility ability = new SimpleActivatedAbility(Zone.BATTLEFIELD, new EyeOfYawgmothEffect(), new GenericManaCost(3)); + ability.addCost(new TapSourceCost()); + ability.addCost(new SacrificeTargetCost(new TargetControlledCreaturePermanent(1, 1, new FilterControlledCreaturePermanent("a creature"), true))); + this.addAbility(ability); + } + + public EyeOfYawgmoth(final EyeOfYawgmoth card) { + super(card); + } + + @Override + public EyeOfYawgmoth copy() { + return new EyeOfYawgmoth(this); + } +} + +class EyeOfYawgmothEffect extends OneShotEffect { + + EyeOfYawgmothEffect() { + super(Outcome.Benefit); + this.staticText = "Reveal a number of cards from the top of your library equal to the sacrificed creature's power. Put one into your hand and exile the rest"; + } + + EyeOfYawgmothEffect(final EyeOfYawgmothEffect effect) { + super(effect); + } + + @Override + public EyeOfYawgmothEffect copy() { + return new EyeOfYawgmothEffect(this); + } + + @Override + public boolean apply(Game game, Ability source) { + Player controller = game.getPlayer(source.getControllerId()); + if (controller == null) { + return false; + } + int power = 0; + for (Cost cost: source.getCosts()) { + if (cost instanceof SacrificeTargetCost && !((SacrificeTargetCost) cost).getPermanents().isEmpty()) { + power = ((SacrificeTargetCost)cost).getPermanents().get(0).getPower().getValue(); + break; + } + } + if (power > 0) { + Cards cards = new CardsImpl(); + int count = Math.min(controller.getLibrary().size(), power); + for (int i = 0; i < count; i++) { + Card card = controller.getLibrary().removeFromTop(game); + if (card != null) { + cards.add(card); + } + } + controller.revealCards(source.getSourceObject(game).getIdName(), cards, game); + + TargetCard target = new TargetCard(Zone.LIBRARY, new FilterCard("card to put into your hand")); + if (controller.choose(Outcome.DrawCard, cards, target, game)) { + Card card = cards.get(target.getFirstTarget(), game); + if (card != null) { + cards.remove(card); + card.moveToZone(Zone.HAND, source.getSourceId(), game, false); + game.informPlayers(source.getSourceObject(game).getIdName() + ": " + controller.getLogName() + " puts " + card.getIdName() + " into his or her hand"); + } + } + for (UUID cardId : cards) { + Card card = game.getCard(cardId); + card.moveToExile(null, "", source.getSourceId(), game); + } + } + return true; + } +} diff --git a/Mage.Sets/src/mage/cards/f/FickleEfreet.java b/Mage.Sets/src/mage/cards/f/FickleEfreet.java new file mode 100644 index 0000000000..0b5e1d27fd --- /dev/null +++ b/Mage.Sets/src/mage/cards/f/FickleEfreet.java @@ -0,0 +1,158 @@ +/* + * Copyright 2010 BetaSteward_at_googlemail.com. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are + * permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this list of + * conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, this list + * of conditions and the following disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY BetaSteward_at_googlemail.com ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BetaSteward_at_googlemail.com OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * The views and conclusions contained in the software and documentation are those of the + * authors and should not be interpreted as representing official policies, either expressed + * or implied, of BetaSteward_at_googlemail.com. + */ +package mage.cards.f; + +import java.util.UUID; +import mage.MageInt; +import mage.abilities.Ability; +import mage.abilities.Mode; +import mage.abilities.common.AttacksOrBlocksTriggeredAbility; +import mage.abilities.common.delayed.AtTheEndOfCombatDelayedTriggeredAbility; +import mage.abilities.effects.ContinuousEffect; +import mage.abilities.effects.ContinuousEffectImpl; +import mage.abilities.effects.OneShotEffect; +import mage.abilities.effects.common.CreateDelayedTriggeredAbilityEffect; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.*; +import mage.game.Game; +import mage.game.permanent.Permanent; +import mage.players.Player; +import mage.target.Target; +import mage.target.common.TargetOpponent; +import mage.target.targetpointer.FixedTarget; + +/** + * + * @author L_J + */ +public class FickleEfreet extends CardImpl { + + public FickleEfreet(UUID ownerId, CardSetInfo setInfo) { + super(ownerId,setInfo,new CardType[]{CardType.CREATURE},"{3}{R}"); + this.subtype.add(SubType.EFREET); + + this.power = new MageInt(5); + this.toughness = new MageInt(2); + + // Whenever Fickle Efreet attacks or blocks, flip a coin at end of combat. If you lose the flip, an opponent gains control of Fickle Efreet. + this.addAbility(new AttacksOrBlocksTriggeredAbility(new CreateDelayedTriggeredAbilityEffect( + new AtTheEndOfCombatDelayedTriggeredAbility(new FickleEfreetChangeControlEffect()), true), false)); + } + + public FickleEfreet(final FickleEfreet card) { + super(card); + } + + @Override + public FickleEfreet copy() { + return new FickleEfreet(this); + } +} + + +class FickleEfreetChangeControlEffect extends OneShotEffect { + + public FickleEfreetChangeControlEffect() { + super(Outcome.Benefit); + this.staticText = "flip a coin at end of combat. If you lose the flip, choose one of your opponents. That player gains control of {this}"; + } + + public FickleEfreetChangeControlEffect(final FickleEfreetChangeControlEffect effect) { + super(effect); + } + + @Override + public FickleEfreetChangeControlEffect copy() { + return new FickleEfreetChangeControlEffect(this); + } + + @Override + public boolean apply(Game game, Ability source) { + Player controller = game.getPlayer(source.getControllerId()); + Permanent sourcePermanent = game.getPermanent(source.getSourceId()); + if (controller != null) { + if (!controller.flipCoin(game)) { + if (sourcePermanent != null) { + Target target = new TargetOpponent(true); + if (target.canChoose(source.getSourceId(), controller.getId(), game)) { + while (!target.isChosen() && target.canChoose(controller.getId(), game) && controller.canRespond()) { + controller.chooseTarget(outcome, target, source, game); + } + } + Player chosenOpponent = game.getPlayer(target.getFirstTarget()); + if (chosenOpponent != null) { + ContinuousEffect effect = new FickleEfreetGainControlEffect(Duration.Custom, target.getFirstTarget()); + effect.setTargetPointer(new FixedTarget(sourcePermanent.getId())); + game.addEffect(effect, source); + game.informPlayers(chosenOpponent.getLogName() + " has gained control of " + sourcePermanent.getLogName()); + return true; + } + } + } + } + return false; + } +} + +class FickleEfreetGainControlEffect extends ContinuousEffectImpl { + + UUID controller; + + public FickleEfreetGainControlEffect(Duration duration, UUID controller) { + super(duration, Layer.ControlChangingEffects_2, SubLayer.NA, Outcome.GainControl); + this.controller = controller; + } + + public FickleEfreetGainControlEffect(final FickleEfreetGainControlEffect effect) { + super(effect); + this.controller = effect.controller; + } + + @Override + public FickleEfreetGainControlEffect copy() { + return new FickleEfreetGainControlEffect(this); + } + + @Override + public boolean apply(Game game, Ability source) { + Permanent permanent = game.getPermanent(source.getFirstTarget()); + if (targetPointer != null) { + permanent = game.getPermanent(targetPointer.getFirst(game, source)); + } + if (permanent != null) { + return permanent.changeControllerId(controller, game); + } + return false; + } + + @Override + public String getText(Mode mode) { + return "That player gains control of {this}"; + } +} diff --git a/Mage.Sets/src/mage/cards/f/ForcemageAdvocate.java b/Mage.Sets/src/mage/cards/f/ForcemageAdvocate.java new file mode 100644 index 0000000000..71579beb72 --- /dev/null +++ b/Mage.Sets/src/mage/cards/f/ForcemageAdvocate.java @@ -0,0 +1,86 @@ +/* + * Copyright 2010 BetaSteward_at_googlemail.com. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are + * permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this list of + * conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, this list + * of conditions and the following disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY BetaSteward_at_googlemail.com ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BetaSteward_at_googlemail.com OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * The views and conclusions contained in the software and documentation are those of the + * authors and should not be interpreted as representing official policies, either expressed + * or implied, of BetaSteward_at_googlemail.com. + */ +package mage.cards.f; + +import java.util.UUID; +import mage.MageInt; +import mage.abilities.Ability; +import mage.abilities.common.SimpleActivatedAbility; +import mage.abilities.costs.common.TapSourceCost; +import mage.abilities.effects.Effect; +import mage.abilities.effects.common.counter.AddCountersTargetEffect; +import mage.abilities.effects.common.ReturnFromGraveyardToHandTargetEffect; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.Duration; +import mage.constants.SubType; +import mage.constants.Zone; +import mage.counters.CounterType; +import mage.filter.FilterCard; +import mage.filter.StaticFilters; +import mage.target.common.TargetCardInOpponentsGraveyard; +import mage.target.common.TargetCreaturePermanent; +import mage.target.targetpointer.SecondTargetPointer; + +/** + * + * @author L_J + */ +public class ForcemageAdvocate extends CardImpl { + + public ForcemageAdvocate(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{1}{G}"); + this.subtype.add(SubType.CENTAUR); + this.subtype.add(SubType.SHAMAN); + this.power = new MageInt(2); + this.toughness = new MageInt(1); + + // {tap}: Return target card from an opponent's graveyard to his or her hand. Put a +1/+1 counter on target creature. + Effect effect = new ReturnFromGraveyardToHandTargetEffect(); + effect.setText("Return target card from an opponent's graveyard to his or her hand"); + Ability ability = new SimpleActivatedAbility(Zone.BATTLEFIELD, effect, new TapSourceCost()); + + effect = new AddCountersTargetEffect(CounterType.P1P1.createInstance()); + effect.setText("Put a +1/+1 counter on target creature"); + effect.setTargetPointer(new SecondTargetPointer()); + ability.addEffect(effect); + ability.addTarget(new TargetCardInOpponentsGraveyard(1, 1, new FilterCard(), true)); + ability.addTarget(new TargetCreaturePermanent()); + this.addAbility(ability); + } + + public ForcemageAdvocate(final ForcemageAdvocate card) { + super(card); + } + + @Override + public ForcemageAdvocate copy() { + return new ForcemageAdvocate(this); + } +} diff --git a/Mage.Sets/src/mage/cards/g/GeneralsRegalia.java b/Mage.Sets/src/mage/cards/g/GeneralsRegalia.java new file mode 100644 index 0000000000..e3c90b0b6c --- /dev/null +++ b/Mage.Sets/src/mage/cards/g/GeneralsRegalia.java @@ -0,0 +1,126 @@ +/* + * Copyright 2010 BetaSteward_at_googlemail.com. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are + * permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this list of + * conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, this list + * of conditions and the following disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY BetaSteward_at_googlemail.com ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BetaSteward_at_googlemail.com OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * The views and conclusions contained in the software and documentation are those of the + * authors and should not be interpreted as representing official policies, either expressed + * or implied, of BetaSteward_at_googlemail.com. + */ +package mage.cards.g; + +import java.util.UUID; +import mage.MageObject; +import mage.abilities.Ability; +import mage.abilities.common.SimpleActivatedAbility; +import mage.abilities.costs.mana.GenericManaCost; +import mage.abilities.effects.RedirectionEffect; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.Duration; +import mage.constants.Outcome; +import mage.constants.Zone; +import mage.game.Game; +import mage.game.events.GameEvent; +import mage.game.permanent.Permanent; +import mage.game.stack.Spell; +import mage.players.Player; +import mage.target.TargetSource; +import mage.target.common.TargetControlledCreaturePermanent; + +/** + * + * @author L_J + */ +public class GeneralsRegalia extends CardImpl { + + public GeneralsRegalia(UUID ownerId, CardSetInfo setInfo) { + super(ownerId,setInfo,new CardType[]{CardType.ARTIFACT},"{3}"); + + // {3}: The next time a source of your choice would deal damage to you this turn, that damage is dealt to target creature you control instead. + Ability ability = new SimpleActivatedAbility(Zone.BATTLEFIELD, new GeneralsRegaliaEffect(), new GenericManaCost(3)); + ability.addTarget(new TargetControlledCreaturePermanent()); + this.addAbility(ability); + } + + public GeneralsRegalia(final GeneralsRegalia card) { + super(card); + } + + @Override + public GeneralsRegalia copy() { + return new GeneralsRegalia(this); + } +} + +class GeneralsRegaliaEffect extends RedirectionEffect { + + private final TargetSource damageSource; + + public GeneralsRegaliaEffect() { + super(Duration.EndOfTurn, Integer.MAX_VALUE, true); + staticText = "The next time a source of your choice would deal damage to you this turn, that damage is dealt to target creature you control instead"; + this.damageSource = new TargetSource(); + } + + public GeneralsRegaliaEffect(final GeneralsRegaliaEffect effect) { + super(effect); + this.damageSource = effect.damageSource.copy(); + } + + @Override + public GeneralsRegaliaEffect copy() { + return new GeneralsRegaliaEffect(this); + } + + @Override + public void init(Ability source, Game game) { + this.damageSource.choose(Outcome.PreventDamage, source.getControllerId(), source.getSourceId(), game); + super.init(source, game); + } + + @Override + public boolean applies(GameEvent event, Ability source, Game game) { + // check source + MageObject object = game.getObject(event.getSourceId()); + if (object == null) { + game.informPlayers("Couldn't find source of damage"); + return false; + } + + if (!object.getId().equals(damageSource.getFirstTarget()) + && (!(object instanceof Spell) || !((Spell) object).getSourceId().equals(damageSource.getFirstTarget()))) { + return false; + } + this.redirectTarget = source.getTargets().get(0); + + // check player + Player player = game.getPlayer(event.getTargetId()); + if (player != null) { + if (player.getId().equals(source.getControllerId())) { + return true; + } + } + return false; + } + +} diff --git a/Mage.Sets/src/mage/cards/g/GiantTrapDoorSpider.java b/Mage.Sets/src/mage/cards/g/GiantTrapDoorSpider.java index 6c0ed14e87..968ce61a78 100644 --- a/Mage.Sets/src/mage/cards/g/GiantTrapDoorSpider.java +++ b/Mage.Sets/src/mage/cards/g/GiantTrapDoorSpider.java @@ -33,7 +33,6 @@ import mage.abilities.Ability; import mage.abilities.common.SimpleActivatedAbility; import mage.abilities.costs.common.TapSourceCost; import mage.abilities.costs.mana.ManaCostsImpl; -import mage.abilities.effects.Effect; import mage.abilities.effects.common.ExileSourceEffect; import mage.abilities.effects.common.ExileTargetEffect; import mage.abilities.keyword.FlyingAbility; @@ -42,11 +41,9 @@ import mage.cards.CardSetInfo; import mage.constants.CardType; import mage.constants.SubType; import mage.constants.Zone; -import mage.filter.common.FilterAttackingCreature; import mage.filter.predicate.Predicates; import mage.filter.predicate.mageobject.AbilityPredicate; -import mage.game.Game; -import mage.game.permanent.Permanent; +import mage.target.common.FilterCreatureAttackingYou; import mage.target.common.TargetCreaturePermanent; /** @@ -55,7 +52,7 @@ import mage.target.common.TargetCreaturePermanent; */ public class GiantTrapDoorSpider extends CardImpl { - private static final HuntingKavuFilter filter = new HuntingKavuFilter(); + private static final FilterCreatureAttackingYou filter = new FilterCreatureAttackingYou("creature without flying that's attacking you"); static { filter.add(Predicates.not(new AbilityPredicate(FlyingAbility.class))); @@ -71,7 +68,7 @@ public class GiantTrapDoorSpider extends CardImpl { // {1}{R}{G}, {tap}: Exile Giant Trap Door Spider and target creature without flying that's attacking you. Ability ability = new SimpleActivatedAbility(Zone.BATTLEFIELD, new ExileSourceEffect(), new ManaCostsImpl("{1}{R}{G}")); ability.addCost(new TapSourceCost()); - ability.addEffect(new ExileTargetEffect()); + ability.addEffect(new ExileTargetEffect().setText("and target creature without flying that's attacking you")); ability.addTarget(new TargetCreaturePermanent(filter)); this.addAbility(ability); } @@ -85,26 +82,3 @@ public class GiantTrapDoorSpider extends CardImpl { return new GiantTrapDoorSpider(this); } } - -class HuntingKavuFilter extends FilterAttackingCreature { - - public HuntingKavuFilter() { - super("creature without flying that's attacking you"); - } - - public HuntingKavuFilter(final HuntingKavuFilter filter) { - super(filter); - } - - @Override - public HuntingKavuFilter copy() { - return new HuntingKavuFilter(this); - } - - @Override - public boolean match(Permanent permanent, UUID sourceId, UUID playerId, Game game) { - return super.match(permanent, sourceId, playerId, game) - && permanent.isAttacking() // to prevent unneccessary combat checking if not attacking - && playerId.equals(game.getCombat().getDefenderId(permanent.getId())); - } -} diff --git a/Mage.Sets/src/mage/cards/g/GleamOfAuthority.java b/Mage.Sets/src/mage/cards/g/GleamOfAuthority.java index 669c69b48f..87757733fa 100644 --- a/Mage.Sets/src/mage/cards/g/GleamOfAuthority.java +++ b/Mage.Sets/src/mage/cards/g/GleamOfAuthority.java @@ -78,7 +78,7 @@ public class GleamOfAuthority extends CardImpl { ability = new SimpleStaticAbility(Zone.BATTLEFIELD, new GainAbilityAttachedEffect(VigilanceAbility.getInstance(), AttachmentType.AURA)); Ability gainedAbility = new SimpleActivatedAbility(Zone.BATTLEFIELD, new BolsterEffect(1), new ManaCostsImpl("{W}")); gainedAbility.addCost(new TapSourceCost()); - ability.addEffect(new GainAbilityAttachedEffect(ability, AttachmentType.AURA).setText("and \"{W}, {T}: Bloster 1.\"")); + ability.addEffect(new GainAbilityAttachedEffect(gainedAbility, AttachmentType.AURA).setText("and \"{W}, {T}: Bloster 1.\"")); this.addAbility(ability); } diff --git a/Mage.Sets/src/mage/cards/g/GlenElendraPranksters.java b/Mage.Sets/src/mage/cards/g/GlenElendraPranksters.java index 3a12d76299..0409f1141d 100644 --- a/Mage.Sets/src/mage/cards/g/GlenElendraPranksters.java +++ b/Mage.Sets/src/mage/cards/g/GlenElendraPranksters.java @@ -48,7 +48,7 @@ import mage.target.common.TargetControlledCreaturePermanent; public class GlenElendraPranksters extends CardImpl { public GlenElendraPranksters(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.CREATURE},"{3}{U}"); + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{3}{U}"); this.subtype.add(SubType.FAERIE); this.subtype.add(SubType.WIZARD); this.power = new MageInt(1); @@ -57,8 +57,10 @@ public class GlenElendraPranksters extends CardImpl { // Flying this.addAbility(FlyingAbility.getInstance()); // Whenever you cast a spell during an opponent's turn, you may return target creature you control to its owner's hand. - Ability ability = new ConditionalTriggeredAbility(new SpellCastControllerTriggeredAbility(new ReturnToHandTargetEffect(), true), OnOpponentsTurnCondition.instance, - "Whenever you cast a spell during an opponent's turn, you may have target creature get -1/-1 until end of turn."); + Ability ability = new ConditionalTriggeredAbility( + new SpellCastControllerTriggeredAbility(new ReturnToHandTargetEffect(), true), OnOpponentsTurnCondition.instance, + "Whenever you cast a spell during an opponent's turn, you may return target creature you control to its owner's hand." + ); ability.addTarget(new TargetControlledCreaturePermanent()); this.addAbility(ability); } diff --git a/Mage.Sets/src/mage/cards/g/GoblinFestival.java b/Mage.Sets/src/mage/cards/g/GoblinFestival.java index 8a12d1021a..b6bf5778ae 100644 --- a/Mage.Sets/src/mage/cards/g/GoblinFestival.java +++ b/Mage.Sets/src/mage/cards/g/GoblinFestival.java @@ -31,7 +31,6 @@ import java.util.UUID; import mage.abilities.Ability; import mage.abilities.Mode; import mage.abilities.common.SimpleActivatedAbility; -import mage.abilities.costs.common.TapSourceCost; import mage.abilities.costs.mana.ManaCostsImpl; import mage.abilities.effects.ContinuousEffect; import mage.abilities.effects.ContinuousEffectImpl; @@ -93,15 +92,24 @@ class GoblinFestivalChangeControlEffect extends OneShotEffect { @Override public boolean apply(Game game, Ability source) { Player controller = game.getPlayer(source.getControllerId()); + Permanent sourcePermanent = game.getPermanent(source.getSourceId()); if (controller != null) { if (!controller.flipCoin(game)) { - Target target = new TargetOpponent(); - target.setNotTarget(true); - if (controller.chooseTarget(outcome, target, source, game)) { - ContinuousEffect effect = new GoblinFestivalGainControlEffect(Duration.Custom, target.getFirstTarget()); - effect.setTargetPointer(new FixedTarget(source.getSourceId())); - game.addEffect(effect, source); - return true; + if (sourcePermanent != null) { + Target target = new TargetOpponent(true); + if (target.canChoose(source.getSourceId(), controller.getId(), game)) { + while (!target.isChosen() && target.canChoose(controller.getId(), game) && controller.canRespond()) { + controller.chooseTarget(outcome, target, source, game); + } + } + Player chosenOpponent = game.getPlayer(target.getFirstTarget()); + if (chosenOpponent != null) { + ContinuousEffect effect = new GoblinFestivalGainControlEffect(Duration.Custom, chosenOpponent.getId()); + effect.setTargetPointer(new FixedTarget(sourcePermanent.getId())); + game.addEffect(effect, source); + game.informPlayers(chosenOpponent.getLogName() + " has gained control of " + sourcePermanent.getLogName()); + return true; + } } } } diff --git a/Mage.Sets/src/mage/cards/g/GoblinLyre.java b/Mage.Sets/src/mage/cards/g/GoblinLyre.java new file mode 100644 index 0000000000..96d7411cc9 --- /dev/null +++ b/Mage.Sets/src/mage/cards/g/GoblinLyre.java @@ -0,0 +1,106 @@ +/* + * Copyright 2010 BetaSteward_at_googlemail.com. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are + * permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this list of + * conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, this list + * of conditions and the following disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY BetaSteward_at_googlemail.com ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BetaSteward_at_googlemail.com OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * The views and conclusions contained in the software and documentation are those of the + * authors and should not be interpreted as representing official policies, either expressed + * or implied, of BetaSteward_at_googlemail.com. + */ +package mage.cards.g; + +import java.util.UUID; +import mage.abilities.Ability; +import mage.abilities.common.SimpleActivatedAbility; +import mage.abilities.costs.common.SacrificeSourceCost; +import mage.abilities.dynamicvalue.common.PermanentsOnBattlefieldCount; +import mage.abilities.dynamicvalue.common.PermanentsTargetOpponentControlsCount; +import mage.abilities.effects.OneShotEffect; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.Outcome; +import mage.constants.Zone; +import mage.filter.common.FilterControlledCreaturePermanent; +import mage.filter.common.FilterCreaturePermanent; +import mage.game.Game; +import mage.players.Player; +import mage.target.common.TargetOpponent; + +/** + * + * @author L_J + */ +public class GoblinLyre extends CardImpl { + + public GoblinLyre(UUID ownerId, CardSetInfo setInfo) { + super(ownerId,setInfo,new CardType[]{CardType.ARTIFACT},"{3}"); + + // Sacrifice Goblin Lyre: Flip a coin. If you win the flip, Goblin Lyre deals damage to target opponent equal to the number of creatures you control. If you lose the flip, Goblin Lyre deals damage to you equal to the number of creatures that opponent controls. + Ability ability = new SimpleActivatedAbility(Zone.BATTLEFIELD, new GoblinLyreEffect(), new SacrificeSourceCost()); + ability.addTarget(new TargetOpponent()); + this.addAbility(ability); + } + + public GoblinLyre(final GoblinLyre card) { + super(card); + } + + @Override + public GoblinLyre copy() { + return new GoblinLyre(this); + } +} + +class GoblinLyreEffect extends OneShotEffect { + + public GoblinLyreEffect() { + super(Outcome.Damage); + this.staticText = "Flip a coin. If you win the flip, {this} deals damage to target opponent equal to the number of creatures you control. If you lose the flip, {this} deals damage to you equal to the number of creatures that opponent controls"; + } + + public GoblinLyreEffect(final GoblinLyreEffect effect) { + super(effect); + } + + @Override + public GoblinLyreEffect copy() { + return new GoblinLyreEffect(this); + } + + @Override + public boolean apply(Game game, Ability source) { + Player controller = game.getPlayer(source.getControllerId()); + Player opponent = game.getPlayer(getTargetPointer().getFirst(game, source)); + if (controller != null) { + if (controller.flipCoin(game)) { + if (opponent != null) { + opponent.damage(new PermanentsOnBattlefieldCount(new FilterControlledCreaturePermanent()).calculate(game, source, this), source.getSourceId(), game, false, true); + return true; + } + } else { + controller.damage(new PermanentsTargetOpponentControlsCount(new FilterCreaturePermanent()).calculate(game, source, this), source.getSourceId(), game, false, true); + return true; + } + } + return false; + } +} diff --git a/Mage.Sets/src/mage/cards/g/GoblinMachinist.java b/Mage.Sets/src/mage/cards/g/GoblinMachinist.java new file mode 100644 index 0000000000..4253d92c1b --- /dev/null +++ b/Mage.Sets/src/mage/cards/g/GoblinMachinist.java @@ -0,0 +1,122 @@ +/* + * Copyright 2010 BetaSteward_at_googlemail.com. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are + * permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this list of + * conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, this list + * of conditions and the following disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY BetaSteward_at_googlemail.com ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BetaSteward_at_googlemail.com OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * The views and conclusions contained in the software and documentation are those of the + * authors and should not be interpreted as representing official policies, either expressed + * or implied, of BetaSteward_at_googlemail.com. + */ +package mage.cards.g; + +import java.util.UUID; +import mage.MageInt; +import mage.MageObject; +import mage.abilities.Ability; +import mage.abilities.common.SimpleActivatedAbility; +import mage.abilities.costs.mana.ManaCostsImpl; +import mage.abilities.effects.OneShotEffect; +import mage.abilities.effects.common.continuous.BoostSourceEffect; +import mage.cards.Card; +import mage.constants.SubType; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.cards.CardsImpl; +import mage.constants.CardType; +import mage.constants.Duration; +import mage.constants.Outcome; +import mage.game.Game; +import mage.players.Library; +import mage.players.Player; + +/** + * + * @author TheElk801 + */ +public class GoblinMachinist extends CardImpl { + + public GoblinMachinist(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{4}{R}"); + + this.subtype.add(SubType.GOBLIN); + this.power = new MageInt(0); + this.toughness = new MageInt(5); + + // {2}{R}: Reveal cards from the top of your library until you reveal a nonland card. Goblin Machinist gets +X/+0 until end of turn, where X is that card's converted mana cost. Put the revealed cards on the bottom of your library in any order. + this.addAbility(new SimpleActivatedAbility(new GoblinMachinistEffect(), new ManaCostsImpl("{2}{R}"))); + } + + public GoblinMachinist(final GoblinMachinist card) { + super(card); + } + + @Override + public GoblinMachinist copy() { + return new GoblinMachinist(this); + } +} + +class GoblinMachinistEffect extends OneShotEffect { + + public GoblinMachinistEffect() { + super(Outcome.DrawCard); + this.staticText = "Reveal cards from the top of your library until you reveal a nonland card. {this} gets +X/+0 until end of turn, where X is that card's converted mana cost. Put the revealed cards on the bottom of your library in any order"; + } + + public GoblinMachinistEffect(final GoblinMachinistEffect effect) { + super(effect); + } + + @Override + public GoblinMachinistEffect copy() { + return new GoblinMachinistEffect(this); + } + + @Override + public boolean apply(Game game, Ability source) { + Player controller = game.getPlayer(source.getControllerId()); + MageObject sourceObject = source.getSourceObject(game); + if (controller != null && sourceObject != null) { + if (controller.getLibrary().hasCards()) { + + CardsImpl cards = new CardsImpl(); + Library library = controller.getLibrary(); + Card card = null; + do { + card = library.removeFromTop(game); + if (card != null) { + cards.add(card); + } + } while (library.hasCards() && card != null && card.isLand()); + if (!cards.isEmpty()) { + controller.revealCards(sourceObject.getIdName(), cards, game); + } + boolean retVal = false; + if (card != null) { + retVal = new BoostSourceEffect(card.getConvertedManaCost(), 0, Duration.EndOfTurn).apply(game, source); + } + return controller.putCardsOnBottomOfLibrary(cards, game, source, true) && retVal; + } + return true; + } + return false; + } +} diff --git a/Mage.Sets/src/mage/cards/g/GoblinPsychopath.java b/Mage.Sets/src/mage/cards/g/GoblinPsychopath.java new file mode 100644 index 0000000000..a64aa20054 --- /dev/null +++ b/Mage.Sets/src/mage/cards/g/GoblinPsychopath.java @@ -0,0 +1,136 @@ +/* + * Copyright 2010 BetaSteward_at_googlemail.com. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are + * permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this list of + * conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, this list + * of conditions and the following disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY BetaSteward_at_googlemail.com ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BetaSteward_at_googlemail.com OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * The views and conclusions contained in the software and documentation are those of the + * authors and should not be interpreted as representing official policies, either expressed + * or implied, of BetaSteward_at_googlemail.com. + */ +package mage.cards.g; + +import java.util.UUID; +import mage.MageInt; +import mage.MageObject; +import mage.abilities.Ability; +import mage.abilities.common.AttacksOrBlocksTriggeredAbility; +import mage.abilities.effects.ReplacementEffectImpl; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.SubType; +import mage.constants.Duration; +import mage.constants.Outcome; +import mage.game.Game; +import mage.game.events.DamageEvent; +import mage.game.events.GameEvent; +import mage.players.Player; + +/** + * + * @author L_J + */ +public class GoblinPsychopath extends CardImpl { + + public GoblinPsychopath(UUID ownerId, CardSetInfo setInfo) { + super(ownerId,setInfo,new CardType[]{CardType.CREATURE},"{3}{R}"); + this.subtype.add(SubType.GOBLIN); + this.subtype.add(SubType.MUTANT); + this.power = new MageInt(5); + this.toughness = new MageInt(5); + + // Whenever Goblin Psychopath attacks or blocks, flip a coin. If you lose the flip, the next time it would deal combat damage this turn, it deals that damage to you instead. + this.addAbility(new AttacksOrBlocksTriggeredAbility(new GoblinPsychopathEffect(), false)); + } + + public GoblinPsychopath(final GoblinPsychopath card) { + super(card); + } + + @Override + public GoblinPsychopath copy() { + return new GoblinPsychopath(this); + } +} + +class GoblinPsychopathEffect extends ReplacementEffectImpl { + + private boolean wonFlip; + + public GoblinPsychopathEffect() { + super(Duration.EndOfTurn, Outcome.RedirectDamage); + staticText = "flip a coin. If you lose the flip, the next time it would deal combat damage this turn, it deals that damage to you instead"; + } + + public GoblinPsychopathEffect(final GoblinPsychopathEffect effect) { + super(effect); + } + + @Override + public void init(Ability source, Game game) { + this.wonFlip = game.getPlayer(source.getControllerId()).flipCoin(game); + super.init(source, game); + } + + @Override + public GoblinPsychopathEffect copy() { + return new GoblinPsychopathEffect(this); + } + + @Override + public boolean checksEventType(GameEvent event, Game game) { + return event.getType() == GameEvent.EventType.DAMAGE_CREATURE || + event.getType() == GameEvent.EventType.DAMAGE_PLANESWALKER || + event.getType() == GameEvent.EventType.DAMAGE_PLAYER; + } + + @Override + public boolean applies(GameEvent event, Ability source, Game game) { + MageObject object = game.getObject(event.getSourceId()); + if (object == null) { + game.informPlayers("Couldn't find source of damage"); + return false; + } + return event.getSourceId().equals(source.getSourceId()); + } + + @Override + public boolean replaceEvent(GameEvent event, Ability source, Game game) { + MageObject object = game.getObject(event.getSourceId()); + Player controller = game.getPlayer(source.getControllerId()); + if (controller != null && object != null) { + if (this.applies(event, source, game) && event instanceof DamageEvent && event.getAmount() > 0) { + DamageEvent damageEvent = (DamageEvent) event; + if (damageEvent.isCombatDamage()) { + if (!wonFlip) { + // TODO: make this redirect damage from all blockers + controller.damage(event.getAmount(), source.getSourceId(), game, false, true); + String sourceLogName = source != null ? game.getObject(source.getSourceId()).getLogName() + ": " : ""; + game.informPlayers(sourceLogName + "Redirected " + event.getAmount() + " damage to " + controller.getLogName()); + this.discard(); + return true; + } + } + } + } + return false; + } +} diff --git a/Mage.Sets/src/mage/cards/h/HolisticWisdom.java b/Mage.Sets/src/mage/cards/h/HolisticWisdom.java new file mode 100644 index 0000000000..0b5e4f6e6e --- /dev/null +++ b/Mage.Sets/src/mage/cards/h/HolisticWisdom.java @@ -0,0 +1,118 @@ +/* + * Copyright 2010 BetaSteward_at_googlemail.com. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are + * permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this list of + * conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, this list + * of conditions and the following disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY BetaSteward_at_googlemail.com ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BetaSteward_at_googlemail.com OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * The views and conclusions contained in the software and documentation are those of the + * authors and should not be interpreted as representing official policies, either expressed + * or implied, of BetaSteward_at_googlemail.com. + */ +package mage.cards.h; + +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.Cost; +import mage.abilities.costs.common.ExileFromHandCost; +import mage.abilities.costs.mana.ManaCostsImpl; +import mage.abilities.effects.Effect; +import mage.abilities.effects.OneShotEffect; +import mage.abilities.effects.common.ReturnToHandTargetEffect; +import mage.cards.Card; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.Outcome; +import mage.constants.Zone; +import mage.filter.FilterCard; +import mage.game.Game; +import mage.target.common.TargetCardInHand; +import mage.target.common.TargetCardInYourGraveyard; +import mage.target.targetpointer.FixedTarget; + +/** + * + * @author L_J + */ +public class HolisticWisdom extends CardImpl { + + public HolisticWisdom(UUID ownerId, CardSetInfo setInfo) { + super(ownerId,setInfo,new CardType[]{CardType.ENCHANTMENT},"{1}{G}{G}"); + + // {2}, Exile a card from your hand: Return target card from your graveyard to your hand if it shares a card type with the card exiled this way. + Ability ability = new SimpleActivatedAbility(Zone.BATTLEFIELD, new HolisticWisdomEffect(), new ManaCostsImpl("{2}")); + ability.addCost(new ExileFromHandCost(new TargetCardInHand(new FilterCard("a card from your hand")))); + ability.addTarget(new TargetCardInYourGraveyard()); + this.addAbility(ability); + } + + public HolisticWisdom(final HolisticWisdom card) { + super(card); + } + + @Override + public HolisticWisdom copy() { + return new HolisticWisdom(this); + } +} + +class HolisticWisdomEffect extends OneShotEffect { + + public HolisticWisdomEffect() { + super(Outcome.ReturnToHand); + this.staticText = "Return target card from your graveyard to your hand if it shares a card type with the card exiled this way"; + } + + public HolisticWisdomEffect(final HolisticWisdomEffect effect) { + super(effect); + } + + @Override + public HolisticWisdomEffect copy() { + return new HolisticWisdomEffect(this); + } + + @Override + public boolean apply(Game game, Ability source) { + Card card = game.getCard(source.getFirstTarget()); + if (card != null && game.getState().getZone(card.getId()) == Zone.GRAVEYARD) { + for (Cost cost : source.getCosts()) { + if (cost instanceof ExileFromHandCost) { + List cardtypes = new ArrayList<>(); + ExileFromHandCost exileCost = (ExileFromHandCost) cost; + for (CardType cardtype : exileCost.getCards().get(0).getCardType()) { + cardtypes.add(cardtype); + } + for (CardType cardtype : card.getCardType()) { + if (cardtypes.contains(cardtype)) { + Effect effect = new ReturnToHandTargetEffect(); + effect.setTargetPointer(new FixedTarget(card.getId())); + return effect.apply(game, source); + } + } + } + } + } + return false; + } +} diff --git a/Mage.Sets/src/mage/cards/h/HuntingKavu.java b/Mage.Sets/src/mage/cards/h/HuntingKavu.java index c6541cbc9d..c4444d1338 100644 --- a/Mage.Sets/src/mage/cards/h/HuntingKavu.java +++ b/Mage.Sets/src/mage/cards/h/HuntingKavu.java @@ -33,7 +33,6 @@ import mage.abilities.Ability; import mage.abilities.common.SimpleActivatedAbility; import mage.abilities.costs.common.TapSourceCost; import mage.abilities.costs.mana.ManaCostsImpl; -import mage.abilities.effects.Effect; import mage.abilities.effects.common.ExileSourceEffect; import mage.abilities.effects.common.ExileTargetEffect; import mage.abilities.keyword.FlyingAbility; @@ -42,11 +41,9 @@ import mage.cards.CardSetInfo; import mage.constants.CardType; import mage.constants.SubType; import mage.constants.Zone; -import mage.filter.common.FilterAttackingCreature; import mage.filter.predicate.Predicates; import mage.filter.predicate.mageobject.AbilityPredicate; -import mage.game.Game; -import mage.game.permanent.Permanent; +import mage.target.common.FilterCreatureAttackingYou; import mage.target.common.TargetCreaturePermanent; /** @@ -55,7 +52,7 @@ import mage.target.common.TargetCreaturePermanent; */ public class HuntingKavu extends CardImpl { - private static final HuntingKavuFilter filter = new HuntingKavuFilter(); + private static final FilterCreatureAttackingYou filter = new FilterCreatureAttackingYou("creature without flying that's attacking you"); static { filter.add(Predicates.not(new AbilityPredicate(FlyingAbility.class))); @@ -71,7 +68,7 @@ public class HuntingKavu extends CardImpl { // {1}{R}{G}, {tap}: Exile Hunting Kavu and target creature without flying that's attacking you. Ability ability = new SimpleActivatedAbility(Zone.BATTLEFIELD, new ExileSourceEffect(), new ManaCostsImpl("{1}{R}{G}")); ability.addCost(new TapSourceCost()); - ability.addEffect(new ExileTargetEffect()); + ability.addEffect(new ExileTargetEffect().setText("nd target creature without flying that's attacking you")); ability.addTarget(new TargetCreaturePermanent(filter)); this.addAbility(ability); } @@ -85,26 +82,3 @@ public class HuntingKavu extends CardImpl { return new HuntingKavu(this); } } - -class HuntingKavuFilter extends FilterAttackingCreature { - - public HuntingKavuFilter() { - super("creature without flying that's attacking you"); - } - - public HuntingKavuFilter(final HuntingKavuFilter filter) { - super(filter); - } - - @Override - public HuntingKavuFilter copy() { - return new HuntingKavuFilter(this); - } - - @Override - public boolean match(Permanent permanent, UUID sourceId, UUID playerId, Game game) { - return super.match(permanent, sourceId, playerId, game) - && permanent.isAttacking() // to prevent unneccessary combat checking if not attacking - && playerId.equals(game.getCombat().getDefenderId(permanent.getId())); - } -} diff --git a/Mage.Sets/src/mage/cards/i/IceFloe.java b/Mage.Sets/src/mage/cards/i/IceFloe.java new file mode 100644 index 0000000000..5dff988908 --- /dev/null +++ b/Mage.Sets/src/mage/cards/i/IceFloe.java @@ -0,0 +1,81 @@ +/* + * Copyright 2010 BetaSteward_at_googlemail.com. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are + * permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this list of + * conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, this list + * of conditions and the following disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY BetaSteward_at_googlemail.com ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BetaSteward_at_googlemail.com OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * The views and conclusions contained in the software and documentation are those of the + * authors and should not be interpreted as representing official policies, either expressed + * or implied, of BetaSteward_at_googlemail.com. + */ +package mage.cards.i; + +import java.util.UUID; +import mage.abilities.Ability; +import mage.abilities.common.SimpleActivatedAbility; +import mage.abilities.common.SkipUntapOptionalAbility; +import mage.abilities.costs.common.TapSourceCost; +import mage.abilities.effects.common.DontUntapAsLongAsSourceTappedEffect; +import mage.abilities.effects.common.TapTargetEffect; +import mage.abilities.keyword.FlyingAbility; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.Zone; +import mage.filter.predicate.Predicates; +import mage.filter.predicate.mageobject.AbilityPredicate; +import mage.target.common.FilterCreatureAttackingYou; +import mage.target.common.TargetCreaturePermanent; + +/** + * + * + * @author TheElk801 + */ +public class IceFloe extends CardImpl { + + private static final FilterCreatureAttackingYou filter = new FilterCreatureAttackingYou("creature without flying that's attacking you"); + + static { + filter.add(Predicates.not(new AbilityPredicate(FlyingAbility.class))); + } + + public IceFloe(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.LAND}, ""); + + // You may choose not to untap Ice Floe during your untap step. + this.addAbility(new SkipUntapOptionalAbility()); + + // {T}: Tap target creature without flying that's attacking you. It doesn't untap during its controller's untap step for as long as Ice Floe remains tapped. + Ability ability = new SimpleActivatedAbility(Zone.BATTLEFIELD, new TapTargetEffect(), new TapSourceCost()); + ability.addTarget(new TargetCreaturePermanent(filter)); + ability.addEffect(new DontUntapAsLongAsSourceTappedEffect()); + this.addAbility(ability); + } + + public IceFloe(final IceFloe card) { + super(card); + } + + @Override + public IceFloe copy() { + return new IceFloe(this); + } +} diff --git a/Mage.Sets/src/mage/cards/i/ImperialEdict.java b/Mage.Sets/src/mage/cards/i/ImperialEdict.java new file mode 100644 index 0000000000..90179d846b --- /dev/null +++ b/Mage.Sets/src/mage/cards/i/ImperialEdict.java @@ -0,0 +1,106 @@ +/* + * Copyright 2010 BetaSteward_at_googlemail.com. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are + * permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this list of + * conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, this list + * of conditions and the following disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY BetaSteward_at_googlemail.com ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BetaSteward_at_googlemail.com OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * The views and conclusions contained in the software and documentation are those of the + * authors and should not be interpreted as representing official policies, either expressed + * or implied, of BetaSteward_at_googlemail.com. + */ +package mage.cards.i; + +import java.util.UUID; +import mage.abilities.Ability; +import mage.abilities.effects.OneShotEffect; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.Outcome; +import mage.filter.common.FilterCreaturePermanent; +import mage.filter.predicate.permanent.ControllerIdPredicate; +import mage.game.Game; +import mage.game.permanent.Permanent; +import mage.players.Player; +import mage.target.Target; +import mage.target.TargetPermanent; +import mage.target.common.TargetOpponent; + +/** + * + * @author TheElk801 + */ +public class ImperialEdict extends CardImpl { + + public ImperialEdict(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.SORCERY}, "{1}{B}"); + + // Target opponent chooses a creature he or she controls. Destroy it. + this.getSpellAbility().addEffect(new ImperialEdictEffect()); + this.getSpellAbility().addTarget(new TargetOpponent()); + } + + public ImperialEdict(final ImperialEdict card) { + super(card); + } + + @Override + public ImperialEdict copy() { + return new ImperialEdict(this); + } +} + +class ImperialEdictEffect extends OneShotEffect { + + ImperialEdictEffect() { + super(Outcome.Benefit); + this.staticText = "Target opponent chooses a creature he or she controls. Destroy it."; + } + + ImperialEdictEffect(final ImperialEdictEffect effect) { + super(effect); + } + + @Override + public ImperialEdictEffect copy() { + return new ImperialEdictEffect(this); + } + + @Override + public boolean apply(Game game, Ability source) { + Player player = game.getPlayer(source.getFirstTarget()); + if (player == null) { + return false; + } + FilterCreaturePermanent filter = new FilterCreaturePermanent("creature you control"); + filter.add(new ControllerIdPredicate(player.getId())); + Target target = new TargetPermanent(1, 1, filter, true); + if (target.canChoose(source.getSourceId(), player.getId(), game)) { + while (!target.isChosen() && target.canChoose(player.getId(), game) && player.canRespond()) { + player.chooseTarget(Outcome.DestroyPermanent, target, source, game); + } + Permanent permanent = game.getPermanent(target.getFirstTarget()); + if (permanent != null) { + permanent.destroy(source.getSourceId(), game, false); + } + } + return true; + } +} diff --git a/Mage.Sets/src/mage/cards/i/ImpulsiveManeuvers.java b/Mage.Sets/src/mage/cards/i/ImpulsiveManeuvers.java new file mode 100644 index 0000000000..dd8af49bc7 --- /dev/null +++ b/Mage.Sets/src/mage/cards/i/ImpulsiveManeuvers.java @@ -0,0 +1,136 @@ +/* + * Copyright 2010 BetaSteward_at_googlemail.com. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are + * permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this list of + * conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, this list + * of conditions and the following disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY BetaSteward_at_googlemail.com ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BetaSteward_at_googlemail.com OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * The views and conclusions contained in the software and documentation are those of the + * authors and should not be interpreted as representing official policies, either expressed + * or implied, of BetaSteward_at_googlemail.com. + */ +package mage.cards.i; + +import java.util.UUID; +import mage.MageObject; +import mage.abilities.Ability; +import mage.abilities.common.AttacksAllTriggeredAbility; +import mage.abilities.effects.PreventionEffectImpl; +import mage.abilities.effects.common.PreventDamageBySourceEffect; +import mage.cards.Card; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.Duration; +import mage.constants.SetTargetPointer; +import mage.game.Game; +import mage.game.events.DamageEvent; +import mage.game.events.GameEvent; +import mage.game.permanent.Permanent; +import mage.filter.StaticFilters; +import mage.filter.predicate.permanent.ControllerPredicate; +import mage.players.Player; + +/** + * + * @author L_J + */ +public class ImpulsiveManeuvers extends CardImpl { + + public ImpulsiveManeuvers(UUID ownerId, CardSetInfo setInfo) { + super(ownerId,setInfo,new CardType[]{CardType.ENCHANTMENT},"{2}{R}{R}"); + + // Whenever a creature attacks, flip a coin. If you win the flip, the next time that creature would deal combat damage this turn, it deals double that damage instead. If you lose the flip, the next time that creature would deal combat damage this turn, prevent that damage. + this.addAbility(new AttacksAllTriggeredAbility(new ImpulsiveManeuversEffect(), false, StaticFilters.FILTER_PERMANENT_CREATURE, + SetTargetPointer.PERMANENT, false)); + } + + public ImpulsiveManeuvers(final ImpulsiveManeuvers card) { + super(card); + } + + @Override + public ImpulsiveManeuvers copy() { + return new ImpulsiveManeuvers(this); + } +} + +class ImpulsiveManeuversEffect extends PreventionEffectImpl { + + private boolean wonFlip; + + public ImpulsiveManeuversEffect() { + super(Duration.EndOfTurn, Integer.MAX_VALUE, false); + staticText = "flip a coin. If you win the flip, the next time that creature would deal combat damage this turn, it deals double that damage instead. If you lose the flip, the next time that creature would deal combat damage this turn, prevent that damage"; + } + + public ImpulsiveManeuversEffect(final ImpulsiveManeuversEffect effect) { + super(effect); + } + + @Override + public void init(Ability source, Game game) { + this.wonFlip = game.getPlayer(source.getControllerId()).flipCoin(game); + super.init(source, game); + } + + @Override + public ImpulsiveManeuversEffect copy() { + return new ImpulsiveManeuversEffect(this); + } + + @Override + public boolean checksEventType(GameEvent event, Game game) { + return event.getType() == GameEvent.EventType.DAMAGE_CREATURE || + event.getType() == GameEvent.EventType.DAMAGE_PLANESWALKER || + event.getType() == GameEvent.EventType.DAMAGE_PLAYER; + } + + @Override + public boolean applies(GameEvent event, Ability source, Game game) { + MageObject object = game.getObject(event.getSourceId()); + if (object == null) { + game.informPlayers("Couldn't find source of damage"); + return false; + } + return event.getSourceId().equals(this.getTargetPointer().getFirst(game, source)); + } + + @Override + public boolean replaceEvent(GameEvent event, Ability source, Game game) { + MageObject object = game.getObject(event.getSourceId()); + Player controller = game.getPlayer(source.getControllerId()); + if (controller != null && object != null) { + if (super.applies(event, source, game) && event instanceof DamageEvent && event.getAmount() > 0) { + DamageEvent damageEvent = (DamageEvent) event; + if (damageEvent.isCombatDamage()) { + if (wonFlip) { + event.setAmount(event.getAmount() * 2); + this.discard(); + } else { + preventDamageAction(event, source, game); + this.discard(); + return true; + } + } + } + } + return false; + } +} diff --git a/Mage.Sets/src/mage/cards/i/InvasionPlans.java b/Mage.Sets/src/mage/cards/i/InvasionPlans.java index eda59d9a81..55d41fd13d 100644 --- a/Mage.Sets/src/mage/cards/i/InvasionPlans.java +++ b/Mage.Sets/src/mage/cards/i/InvasionPlans.java @@ -37,10 +37,7 @@ import mage.cards.CardSetInfo; import mage.constants.*; import mage.game.Game; import mage.game.events.GameEvent; -import mage.game.events.GameEvent.EventType; -import mage.game.permanent.Permanent; import mage.players.Player; -import mage.players.PlayerList; import static mage.filter.StaticFilters.FILTER_PERMANENT_CREATURES; /** @@ -71,7 +68,8 @@ public class InvasionPlans extends CardImpl { class InvasionPlansEffect extends ContinuousRuleModifyingEffectImpl { public InvasionPlansEffect() { - super(Duration.WhileOnBattlefield, Outcome.Benefit, true, false); + super(Duration.WhileOnBattlefield, Outcome.Benefit, false, false); + staticText = "The attacking player chooses how each creature blocks each turn"; } public InvasionPlansEffect(final InvasionPlansEffect effect) { @@ -103,4 +101,3 @@ class InvasionPlansEffect extends ContinuousRuleModifyingEffectImpl { return false; } } - diff --git a/Mage.Sets/src/mage/cards/j/JaggedPoppet.java b/Mage.Sets/src/mage/cards/j/JaggedPoppet.java new file mode 100644 index 0000000000..7062dbf0e7 --- /dev/null +++ b/Mage.Sets/src/mage/cards/j/JaggedPoppet.java @@ -0,0 +1,153 @@ +/* + * Copyright 2010 BetaSteward_at_googlemail.com. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are + * permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this list of + * conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, this list + * of conditions and the following disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY BetaSteward_at_googlemail.com ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BetaSteward_at_googlemail.com OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * The views and conclusions contained in the software and documentation are those of the + * authors and should not be interpreted as representing official policies, either expressed + * or implied, of BetaSteward_at_googlemail.com. + */ +package mage.cards.j; + +import java.util.UUID; +import mage.MageInt; +import mage.abilities.Ability; +import mage.abilities.common.DealsCombatDamageToAPlayerTriggeredAbility; +import mage.abilities.common.DealtDamageToSourceTriggeredAbility; +import mage.abilities.condition.common.HellbentCondition; +import mage.abilities.decorator.ConditionalTriggeredAbility; +import mage.abilities.effects.OneShotEffect; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.AbilityWord; +import mage.constants.CardType; +import mage.constants.Outcome; +import mage.constants.SubType; +import mage.constants.Zone; +import mage.game.Game; +import mage.players.Player; + +/** + * + * @author jerekwilson + */ +public class JaggedPoppet extends CardImpl { + + public JaggedPoppet(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{1}{B}{R}"); + + this.subtype.add(SubType.OGRE); + this.subtype.add(SubType.WARRIOR); + this.power = new MageInt(3); + this.toughness = new MageInt(4); + + // Whenever Jagged Poppet is dealt damage, discard that many cards. + this.addAbility(new DealtDamageToSourceTriggeredAbility(Zone.BATTLEFIELD, new JaggedPoppetDealtDamageEffect(), false, false, true)); + + // Hellbent - Whenever Jagged Poppet deals combat damage to a player, if you have no cards in hand, that player discards cards equal to the damage. + Ability hellbentAbility = new ConditionalTriggeredAbility( + new DealsCombatDamageToAPlayerTriggeredAbility(new JaggedPoppetDealsDamageEffect(), false, true), + HellbentCondition.instance, + "Hellbent - Whenever {this} deals combat damage to a player, if you have no cards in hand, that player discards cards equal to the damage."); + hellbentAbility.setAbilityWord(AbilityWord.HELLBENT); + this.addAbility(hellbentAbility); + + } + + public JaggedPoppet(final JaggedPoppet card) { + super(card); + } + + @Override + public JaggedPoppet copy() { + return new JaggedPoppet(this); + } +} + +class JaggedPoppetDealsDamageEffect extends OneShotEffect { + + public JaggedPoppetDealsDamageEffect() { + super(Outcome.Discard); + //staticText = "it deals that much damage to each creature that player controls"; + } + + public JaggedPoppetDealsDamageEffect(final JaggedPoppetDealsDamageEffect effect) { + super(effect); + } + + @Override + public boolean apply(Game game, Ability source) { + //According to the Balefire Dragon code, This statement gets the player that was dealt the combat damage + Player player = game.getPlayer(targetPointer.getFirst(game, source)); + if (player != null) { + //Call the getValue method of the Effect class to retrieve the amount of damage + int amount = (Integer) getValue("damage"); + + if (amount > 0) { + //Call the player discard function discarding cards equal to damage + player.discard(amount, false, source, game); + } + return true; + } + return false; + } + + @Override + public JaggedPoppetDealsDamageEffect copy() { + return new JaggedPoppetDealsDamageEffect(this); + } +} + +class JaggedPoppetDealtDamageEffect extends OneShotEffect { + + public JaggedPoppetDealtDamageEffect() { + super(Outcome.Discard); + staticText = "discard that many cards"; + } + + public JaggedPoppetDealtDamageEffect(final JaggedPoppetDealtDamageEffect effect) { + super(effect); + } + + @Override + public boolean apply(Game game, Ability source) { + + //According to the Firedrinker Satyr code, This statement gets the player that controls Jagged Poppet + Player player = game.getPlayer(source.getControllerId()); + if (player != null) { + //Call the getValue method of the Effect class to retrieve the amount of damage + int amount = (Integer) getValue("damage"); + + if (amount > 0) { + //Call the player discard function discarding cards equal to damage + player.discard(amount, false, source, game); + } + return true; + } + return false; + + } + + @Override + public JaggedPoppetDealtDamageEffect copy() { + return new JaggedPoppetDealtDamageEffect(this); + } +} diff --git a/Mage.Sets/src/mage/cards/j/Johan.java b/Mage.Sets/src/mage/cards/j/Johan.java new file mode 100644 index 0000000000..4affd49c26 --- /dev/null +++ b/Mage.Sets/src/mage/cards/j/Johan.java @@ -0,0 +1,87 @@ +/* + * Copyright 2010 BetaSteward_at_googlemail.com. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are + * permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this list of + * conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, this list + * of conditions and the following disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY BetaSteward_at_googlemail.com ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BetaSteward_at_googlemail.com OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * The views and conclusions contained in the software and documentation are those of the + * authors and should not be interpreted as representing official policies, either expressed + * or implied, of BetaSteward_at_googlemail.com. + */ +package mage.cards.j; + +import java.util.UUID; +import mage.MageInt; +import mage.abilities.Ability; +import mage.abilities.DelayedTriggeredAbility; +import mage.abilities.common.BeginningOfCombatTriggeredAbility; +import mage.abilities.condition.CompoundCondition; +import mage.abilities.condition.Condition; +import mage.abilities.condition.InvertCondition; +import mage.abilities.condition.common.SourceOnBattlefieldCondition; +import mage.abilities.condition.common.SourceTappedCondition; +import mage.abilities.decorator.ConditionalContinuousEffect; +import mage.abilities.effects.common.combat.CantAttackSourceEffect; +import mage.abilities.effects.common.continuous.GainAbilityControlledEffect; +import mage.abilities.keyword.special.JohanVigilanceAbility; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.SubType; +import mage.constants.Duration; +import mage.constants.SuperType; +import mage.constants.TargetController; +import mage.filter.common.FilterControlledCreaturePermanent; + +/** + * + * @author L_J + */ +public class Johan extends CardImpl { + + public Johan(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{3}{R}{G}{W}"); + addSuperType(SuperType.LEGENDARY); + this.subtype.add(SubType.HUMAN); + this.subtype.add(SubType.WIZARD); + this.power = new MageInt(5); + this.toughness = new MageInt(4); + + // At the beginning of combat on your turn, you may have Johan gain "Johan can't attack" until end of combat. If you do, attacking doesn't cause creatures you control to tap this combat if Johan is untapped. + Condition condition = new CompoundCondition("if {this} is untapped", + new InvertCondition(SourceTappedCondition.instance), + SourceOnBattlefieldCondition.instance); + Ability ability = new BeginningOfCombatTriggeredAbility(new CantAttackSourceEffect(Duration.EndOfCombat).setText("you may have {this} gain \"{this} can't attack\" until end of combat"), TargetController.YOU, true); + ability.addEffect(new ConditionalContinuousEffect( + new GainAbilityControlledEffect(JohanVigilanceAbility.getInstance(), Duration.EndOfCombat, new FilterControlledCreaturePermanent("creatures")), + condition, + "If you do, attacking doesn't cause creatures you control to tap this combat if {this} is untapped")); + this.addAbility(ability); + } + + public Johan(final Johan card) { + super(card); + } + + @Override + public Johan copy() { + return new Johan(this); + } +} diff --git a/Mage.Sets/src/mage/cards/k/KopalaWardenOfWaves.java b/Mage.Sets/src/mage/cards/k/KopalaWardenOfWaves.java index 97ccc00579..6b58efb477 100644 --- a/Mage.Sets/src/mage/cards/k/KopalaWardenOfWaves.java +++ b/Mage.Sets/src/mage/cards/k/KopalaWardenOfWaves.java @@ -30,6 +30,7 @@ package mage.cards.k; import java.util.UUID; import mage.MageInt; import mage.abilities.Ability; +import mage.abilities.Mode; import mage.abilities.SpellAbility; import mage.abilities.common.SimpleStaticAbility; import mage.abilities.effects.common.cost.CostModificationEffectImpl; @@ -111,13 +112,16 @@ class KopalaWardenOfWavesCostReductionEffect extends CostModificationEffectImpl public boolean applies(Ability abilityToModify, Ability source, Game game) { if (abilityToModify.getAbilityType() == AbilityType.SPELL) { if (game.getOpponents(source.getControllerId()).contains(abilityToModify.getControllerId())) { - for (Target target : abilityToModify.getTargets()) { - for (UUID targetUUID : target.getTargets()) { - Permanent creature = game.getPermanent(targetUUID); - if (creature != null - && filter.match(creature, game) - && creature.getControllerId().equals(source.getControllerId())) { - return true; + for (UUID modeId : abilityToModify.getModes().getSelectedModes()) { + Mode mode = abilityToModify.getModes().get(modeId); + for (Target target : mode.getTargets()) { + for (UUID targetUUID : target.getTargets()) { + Permanent creature = game.getPermanent(targetUUID); + if (creature != null + && filter.match(creature, game) + && creature.getControllerId().equals(source.getControllerId())) { + return true; + } } } } diff --git a/Mage.Sets/src/mage/cards/k/KrovikanHorror.java b/Mage.Sets/src/mage/cards/k/KrovikanHorror.java new file mode 100644 index 0000000000..4b37bb97c6 --- /dev/null +++ b/Mage.Sets/src/mage/cards/k/KrovikanHorror.java @@ -0,0 +1,114 @@ +/* + * Copyright 2010 BetaSteward_at_googlemail.com. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are + * permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this list of + * conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, this list + * of conditions and the following disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY BetaSteward_at_googlemail.com ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BetaSteward_at_googlemail.com OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * The views and conclusions contained in the software and documentation are those of the + * authors and should not be interpreted as representing official policies, either expressed + * or implied, of BetaSteward_at_googlemail.com. + */ +package mage.cards.k; + +import java.util.UUID; +import mage.MageInt; +import mage.abilities.Ability; +import mage.abilities.common.BeginningOfEndStepTriggeredAbility; +import mage.abilities.common.SimpleActivatedAbility; +import mage.abilities.condition.Condition; +import mage.abilities.costs.common.SacrificeTargetCost; +import mage.abilities.costs.mana.GenericManaCost; +import mage.abilities.effects.common.DamageTargetEffect; +import mage.abilities.effects.common.ReturnSourceFromGraveyardToHandEffect; +import mage.cards.Card; +import mage.constants.SubType; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.TargetController; +import mage.constants.Zone; +import mage.game.Game; +import mage.players.Player; +import mage.target.common.TargetControlledCreaturePermanent; +import mage.target.common.TargetCreatureOrPlayer; + +/** + * + * @author TheElk801 + */ +public class KrovikanHorror extends CardImpl { + + public KrovikanHorror(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{3}{B}"); + + this.subtype.add(SubType.HORROR); + this.subtype.add(SubType.SPIRIT); + this.power = new MageInt(2); + this.toughness = new MageInt(2); + + // At the beginning of the end step, if Krovikan Horror is in your graveyard with a creature card directly above it, you may return Krovikan Horror to your hand. + this.addAbility(new BeginningOfEndStepTriggeredAbility( + Zone.GRAVEYARD, new ReturnSourceFromGraveyardToHandEffect(), + TargetController.ANY, KrovikanHorrorCondition.instance, true + )); + + // {1}, Sacrifice a creature: Krovikan Horror deals 1 damage to target creature or player. + SimpleActivatedAbility ability = new SimpleActivatedAbility(Zone.BATTLEFIELD, new DamageTargetEffect(1), new GenericManaCost(1)); + ability.addCost(new SacrificeTargetCost(new TargetControlledCreaturePermanent())); + ability.addTarget(new TargetCreatureOrPlayer()); + this.addAbility(ability); + } + + public KrovikanHorror(final KrovikanHorror card) { + super(card); + } + + @Override + public KrovikanHorror copy() { + return new KrovikanHorror(this); + } +} + +enum KrovikanHorrorCondition implements Condition { + + instance; + + @Override + public boolean apply(Game game, Ability source) { + Player controller = game.getPlayer(source.getControllerId()); + if (controller != null) { + boolean nextCard = false; + for (Card card : controller.getGraveyard().getCards(game)) { + if (nextCard) { + return card.isCreature(); + } + if (card.getId().equals(source.getSourceId())) { + nextCard = true; + } + } + } + return false; + } + + @Override + public String toString() { + return "{this} is in your graveyard with a creature card directly above it"; + } +} diff --git a/Mage.Sets/src/mage/cards/l/LaccolithGrunt.java b/Mage.Sets/src/mage/cards/l/LaccolithGrunt.java new file mode 100644 index 0000000000..78edd56552 --- /dev/null +++ b/Mage.Sets/src/mage/cards/l/LaccolithGrunt.java @@ -0,0 +1,112 @@ +/* + * Copyright 2010 BetaSteward_at_googlemail.com. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are + * permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this list of + * conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, this list + * of conditions and the following disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY BetaSteward_at_googlemail.com ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BetaSteward_at_googlemail.com OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * The views and conclusions contained in the software and documentation are those of the + * authors and should not be interpreted as representing official policies, either expressed + * or implied, of BetaSteward_at_googlemail.com. + */ +package mage.cards.l; + +import java.util.UUID; +import mage.MageInt; +import mage.abilities.Ability; +import mage.abilities.common.BecomesBlockedTriggeredAbility; +import mage.abilities.effects.OneShotEffect; +import mage.abilities.effects.common.continuous.AssignNoCombatDamageSourceEffect; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.SubType; +import mage.constants.Duration; +import mage.constants.Outcome; +import mage.constants.Zone; +import mage.game.Game; +import mage.game.permanent.Permanent; +import mage.players.Player; +import mage.target.common.TargetCreaturePermanent; + +/** + * + * @author L_J + */ +public class LaccolithGrunt extends CardImpl { + + public LaccolithGrunt(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{2}{R}"); + this.subtype.add(SubType.BEAST); + this.power = new MageInt(2); + this.toughness = new MageInt(2); + + // Whenever Laccolith Grunt becomes blocked, you may have it deal damage equal to its power to target creature. If you do, Laccolith Grunt assigns no combat damage this turn. + Ability ability = new BecomesBlockedTriggeredAbility(new LaccolithEffect().setText("you may have it deal damage equal to its power to target creature"), true); + ability.addEffect(new AssignNoCombatDamageSourceEffect(Duration.EndOfTurn, true)); + ability.addTarget(new TargetCreaturePermanent()); + this.addAbility(ability); + } + + public LaccolithGrunt(final LaccolithGrunt card) { + super(card); + } + + @Override + public LaccolithGrunt copy() { + return new LaccolithGrunt(this); + } + + class LaccolithEffect extends OneShotEffect { + public LaccolithEffect() { + super(Outcome.Damage); + staticText = "{this} deals damage equal to its power to target creature"; + } + + public LaccolithEffect(final LaccolithEffect effect) { + super(effect); + } + + @Override + public boolean apply(Game game, Ability source) { + Permanent sourcePermanent = game.getPermanent(source.getSourceId()); + if (sourcePermanent == null) { + sourcePermanent = (Permanent) game.getLastKnownInformation(source.getSourceId(), Zone.BATTLEFIELD); + } + if (sourcePermanent == null) { + return false; + } + + int damage = sourcePermanent.getPower().getValue(); + + Permanent permanent = game.getPermanent(source.getFirstTarget()); + if (permanent != null) { + permanent.damage(damage, sourcePermanent.getId(), game, false, true); + return true; + } + return false; + } + + @Override + public LaccolithEffect copy() { + return new LaccolithEffect(this); + } + + } +} diff --git a/Mage.Sets/src/mage/cards/l/LaccolithRig.java b/Mage.Sets/src/mage/cards/l/LaccolithRig.java new file mode 100644 index 0000000000..80eb97f7fa --- /dev/null +++ b/Mage.Sets/src/mage/cards/l/LaccolithRig.java @@ -0,0 +1,161 @@ +/* + * Copyright 2010 BetaSteward_at_googlemail.com. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are + * permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this list of + * conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, this list + * of conditions and the following disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY BetaSteward_at_googlemail.com ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BetaSteward_at_googlemail.com OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * The views and conclusions contained in the software and documentation are those of the + * authors and should not be interpreted as representing official policies, either expressed + * or implied, of BetaSteward_at_googlemail.com. + */ +package mage.cards.l; + +import java.util.UUID; +import mage.abilities.Ability; +import mage.abilities.common.BecomesBlockedTriggeredAbility; +import mage.abilities.common.SimpleStaticAbility; +import mage.abilities.effects.Effect; +import mage.abilities.effects.OneShotEffect; +import mage.abilities.TriggeredAbilityImpl; +import mage.abilities.effects.common.AttachEffect; +import mage.abilities.effects.common.continuous.AssignNoCombatDamageSourceEffect; +import mage.abilities.effects.common.continuous.GainAbilityTargetEffect; +import mage.abilities.keyword.EnchantAbility; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.SubType; +import mage.constants.Duration; +import mage.constants.Outcome; +import mage.constants.Zone; +import mage.game.Game; +import mage.game.events.GameEvent; +import mage.game.events.GameEvent.EventType; +import mage.game.permanent.Permanent; +import mage.players.Player; +import mage.target.TargetPermanent; +import mage.target.common.TargetCreaturePermanent; +import mage.target.targetpointer.FixedTarget; + +/** + * + * @author L_J + */ +public class LaccolithRig extends CardImpl { + + public LaccolithRig(UUID ownerId, CardSetInfo setInfo) { + super(ownerId,setInfo,new CardType[]{CardType.ENCHANTMENT},"{R}"); + this.subtype.add(SubType.AURA); + + // Enchant creature + TargetPermanent auraTarget = new TargetCreaturePermanent(); + this.getSpellAbility().addTarget(auraTarget); + this.getSpellAbility().addEffect(new AttachEffect(Outcome.Detriment)); + Ability ability = new EnchantAbility(auraTarget.getTargetName()); + this.addAbility(ability); + + // Whenever enchanted creature becomes blocked, you may have it deal damage equal to its power to target creature. If you do, the first creature assigns no combat damage this turn. + Ability ability2 = new LaccolithRigTriggeredAbility(new LaccolithRigEffect(), true); + ability2.addTarget(new TargetCreaturePermanent()); + Effect effect = new GainAbilityTargetEffect(new SimpleStaticAbility(Zone.BATTLEFIELD, new AssignNoCombatDamageSourceEffect(Duration.Custom, true).setText("")), Duration.EndOfTurn, "If you do, the first creature assigns no combat damage this turn"); + ability2.addEffect(effect); + this.addAbility(ability2); + } + + public LaccolithRig(final LaccolithRig card) { + super(card); + } + + @Override + public LaccolithRig copy() { + return new LaccolithRig(this); + } +} + +class LaccolithRigTriggeredAbility extends TriggeredAbilityImpl { + + public LaccolithRigTriggeredAbility(Effect effect, boolean optional) { + super(Zone.BATTLEFIELD, effect, optional); + } + + public LaccolithRigTriggeredAbility(final LaccolithRigTriggeredAbility ability) { + super(ability); + } + + @Override + public boolean checkEventType(GameEvent event, Game game) { + return event.getType() == EventType.CREATURE_BLOCKED; + } + + @Override + public boolean checkTrigger(GameEvent event, Game game) { + Permanent equipment = game.getPermanent(sourceId); + if (equipment != null && equipment.getAttachedTo() != null) { + Permanent equipped = game.getPermanent(equipment.getAttachedTo()); + if (equipped.getId().equals(event.getTargetId())) { + getEffects().get(1).setTargetPointer(new FixedTarget(equipped.getId())); + return true; + } + } + return false; + } + + @Override + public String getRule() { + return "Whenever enchanted creature becomes blocked by a creature, " + super.getRule(); + } + + @Override + public LaccolithRigTriggeredAbility copy() { + return new LaccolithRigTriggeredAbility(this); + } +} + +class LaccolithRigEffect extends OneShotEffect { + + public LaccolithRigEffect() { + super(Outcome.Damage); + this.staticText = "you may have it deal damage equal to its power to target creature"; + } + + public LaccolithRigEffect(final LaccolithRigEffect effect) { + super(effect); + } + + @Override + public LaccolithRigEffect copy() { + return new LaccolithRigEffect(this); + } + + @Override + public boolean apply(Game game, Ability source) { + Permanent enchantment = game.getPermanentOrLKIBattlefield(source.getSourceId()); + Permanent ownCreature = game.getPermanent(enchantment.getAttachedTo()); + if (ownCreature != null) { + int damage = ownCreature.getPower().getValue(); + Permanent targetCreature = game.getPermanent(source.getFirstTarget()); + if (targetCreature != null) { + targetCreature.damage(damage, ownCreature.getId(), game, false, true); + return true; + } + } + return false; + } +} diff --git a/Mage.Sets/src/mage/cards/l/LaccolithTitan.java b/Mage.Sets/src/mage/cards/l/LaccolithTitan.java new file mode 100644 index 0000000000..8e92108948 --- /dev/null +++ b/Mage.Sets/src/mage/cards/l/LaccolithTitan.java @@ -0,0 +1,112 @@ +/* + * Copyright 2010 BetaSteward_at_googlemail.com. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are + * permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this list of + * conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, this list + * of conditions and the following disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY BetaSteward_at_googlemail.com ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BetaSteward_at_googlemail.com OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * The views and conclusions contained in the software and documentation are those of the + * authors and should not be interpreted as representing official policies, either expressed + * or implied, of BetaSteward_at_googlemail.com. + */ +package mage.cards.l; + +import java.util.UUID; +import mage.MageInt; +import mage.abilities.Ability; +import mage.abilities.common.BecomesBlockedTriggeredAbility; +import mage.abilities.effects.OneShotEffect; +import mage.abilities.effects.common.continuous.AssignNoCombatDamageSourceEffect; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.SubType; +import mage.constants.Duration; +import mage.constants.Outcome; +import mage.constants.Zone; +import mage.game.Game; +import mage.game.permanent.Permanent; +import mage.players.Player; +import mage.target.common.TargetCreaturePermanent; + +/** + * + * @author L_J + */ +public class LaccolithTitan extends CardImpl { + + public LaccolithTitan(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{5}{R}{R}"); + this.subtype.add(SubType.BEAST); + this.power = new MageInt(6); + this.toughness = new MageInt(6); + + // Whenever Laccolith Grunt becomes blocked, you may have it deal damage equal to its power to target creature. If you do, Laccolith Grunt assigns no combat damage this turn. + Ability ability = new BecomesBlockedTriggeredAbility(new LaccolithEffect().setText("you may have it deal damage equal to its power to target creature"), true); + ability.addEffect(new AssignNoCombatDamageSourceEffect(Duration.EndOfTurn, true)); + ability.addTarget(new TargetCreaturePermanent()); + this.addAbility(ability); + } + + public LaccolithTitan(final LaccolithTitan card) { + super(card); + } + + @Override + public LaccolithTitan copy() { + return new LaccolithTitan(this); + } + + class LaccolithEffect extends OneShotEffect { + public LaccolithEffect() { + super(Outcome.Damage); + staticText = "{this} deals damage equal to its power to target creature"; + } + + public LaccolithEffect(final LaccolithEffect effect) { + super(effect); + } + + @Override + public boolean apply(Game game, Ability source) { + Permanent sourcePermanent = game.getPermanent(source.getSourceId()); + if (sourcePermanent == null) { + sourcePermanent = (Permanent) game.getLastKnownInformation(source.getSourceId(), Zone.BATTLEFIELD); + } + if (sourcePermanent == null) { + return false; + } + + int damage = sourcePermanent.getPower().getValue(); + + Permanent permanent = game.getPermanent(source.getFirstTarget()); + if (permanent != null) { + permanent.damage(damage, sourcePermanent.getId(), game, false, true); + return true; + } + return false; + } + + @Override + public LaccolithEffect copy() { + return new LaccolithEffect(this); + } + + } +} diff --git a/Mage.Sets/src/mage/cards/l/LaccolithWarrior.java b/Mage.Sets/src/mage/cards/l/LaccolithWarrior.java new file mode 100644 index 0000000000..492d9a50e8 --- /dev/null +++ b/Mage.Sets/src/mage/cards/l/LaccolithWarrior.java @@ -0,0 +1,113 @@ +/* + * Copyright 2010 BetaSteward_at_googlemail.com. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are + * permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this list of + * conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, this list + * of conditions and the following disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY BetaSteward_at_googlemail.com ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BetaSteward_at_googlemail.com OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * The views and conclusions contained in the software and documentation are those of the + * authors and should not be interpreted as representing official policies, either expressed + * or implied, of BetaSteward_at_googlemail.com. + */ +package mage.cards.l; + +import java.util.UUID; +import mage.MageInt; +import mage.abilities.Ability; +import mage.abilities.common.BecomesBlockedTriggeredAbility; +import mage.abilities.effects.OneShotEffect; +import mage.abilities.effects.common.continuous.AssignNoCombatDamageSourceEffect; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.SubType; +import mage.constants.Duration; +import mage.constants.Outcome; +import mage.constants.Zone; +import mage.game.Game; +import mage.game.permanent.Permanent; +import mage.players.Player; +import mage.target.common.TargetCreaturePermanent; + +/** + * + * @author L_J + */ +public class LaccolithWarrior extends CardImpl { + + public LaccolithWarrior(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{2}{R}{R}"); + this.subtype.add(SubType.BEAST); + this.subtype.add(SubType.WARRIOR); + this.power = new MageInt(3); + this.toughness = new MageInt(3); + + // Whenever Laccolith Grunt becomes blocked, you may have it deal damage equal to its power to target creature. If you do, Laccolith Grunt assigns no combat damage this turn. + Ability ability = new BecomesBlockedTriggeredAbility(new LaccolithEffect().setText("you may have it deal damage equal to its power to target creature"), true); + ability.addEffect(new AssignNoCombatDamageSourceEffect(Duration.EndOfTurn, true)); + ability.addTarget(new TargetCreaturePermanent()); + this.addAbility(ability); + } + + public LaccolithWarrior(final LaccolithWarrior card) { + super(card); + } + + @Override + public LaccolithWarrior copy() { + return new LaccolithWarrior(this); + } + + class LaccolithEffect extends OneShotEffect { + public LaccolithEffect() { + super(Outcome.Damage); + staticText = "{this} deals damage equal to its power to target creature"; + } + + public LaccolithEffect(final LaccolithEffect effect) { + super(effect); + } + + @Override + public boolean apply(Game game, Ability source) { + Permanent sourcePermanent = game.getPermanent(source.getSourceId()); + if (sourcePermanent == null) { + sourcePermanent = (Permanent) game.getLastKnownInformation(source.getSourceId(), Zone.BATTLEFIELD); + } + if (sourcePermanent == null) { + return false; + } + + int damage = sourcePermanent.getPower().getValue(); + + Permanent permanent = game.getPermanent(source.getFirstTarget()); + if (permanent != null) { + permanent.damage(damage, sourcePermanent.getId(), game, false, true); + return true; + } + return false; + } + + @Override + public LaccolithEffect copy() { + return new LaccolithEffect(this); + } + + } +} diff --git a/Mage.Sets/src/mage/cards/l/LaccolithWhelp.java b/Mage.Sets/src/mage/cards/l/LaccolithWhelp.java new file mode 100644 index 0000000000..0d9b155387 --- /dev/null +++ b/Mage.Sets/src/mage/cards/l/LaccolithWhelp.java @@ -0,0 +1,112 @@ +/* + * Copyright 2010 BetaSteward_at_googlemail.com. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are + * permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this list of + * conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, this list + * of conditions and the following disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY BetaSteward_at_googlemail.com ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BetaSteward_at_googlemail.com OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * The views and conclusions contained in the software and documentation are those of the + * authors and should not be interpreted as representing official policies, either expressed + * or implied, of BetaSteward_at_googlemail.com. + */ +package mage.cards.l; + +import java.util.UUID; +import mage.MageInt; +import mage.abilities.Ability; +import mage.abilities.common.BecomesBlockedTriggeredAbility; +import mage.abilities.effects.OneShotEffect; +import mage.abilities.effects.common.continuous.AssignNoCombatDamageSourceEffect; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.SubType; +import mage.constants.Duration; +import mage.constants.Outcome; +import mage.constants.Zone; +import mage.game.Game; +import mage.game.permanent.Permanent; +import mage.players.Player; +import mage.target.common.TargetCreaturePermanent; + +/** + * + * @author L_J + */ +public class LaccolithWhelp extends CardImpl { + + public LaccolithWhelp(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{R}"); + this.subtype.add(SubType.BEAST); + this.power = new MageInt(1); + this.toughness = new MageInt(1); + + // Whenever Laccolith Grunt becomes blocked, you may have it deal damage equal to its power to target creature. If you do, Laccolith Grunt assigns no combat damage this turn. + Ability ability = new BecomesBlockedTriggeredAbility(new LaccolithEffect().setText("you may have it deal damage equal to its power to target creature"), true); + ability.addEffect(new AssignNoCombatDamageSourceEffect(Duration.EndOfTurn, true)); + ability.addTarget(new TargetCreaturePermanent()); + this.addAbility(ability); + } + + public LaccolithWhelp(final LaccolithWhelp card) { + super(card); + } + + @Override + public LaccolithWhelp copy() { + return new LaccolithWhelp(this); + } + + class LaccolithEffect extends OneShotEffect { + public LaccolithEffect() { + super(Outcome.Damage); + staticText = "{this} deals damage equal to its power to target creature"; + } + + public LaccolithEffect(final LaccolithEffect effect) { + super(effect); + } + + @Override + public boolean apply(Game game, Ability source) { + Permanent sourcePermanent = game.getPermanent(source.getSourceId()); + if (sourcePermanent == null) { + sourcePermanent = (Permanent) game.getLastKnownInformation(source.getSourceId(), Zone.BATTLEFIELD); + } + if (sourcePermanent == null) { + return false; + } + + int damage = sourcePermanent.getPower().getValue(); + + Permanent permanent = game.getPermanent(source.getFirstTarget()); + if (permanent != null) { + permanent.damage(damage, sourcePermanent.getId(), game, false, true); + return true; + } + return false; + } + + @Override + public LaccolithEffect copy() { + return new LaccolithEffect(this); + } + + } +} diff --git a/Mage.Sets/src/mage/cards/l/LatullasOrders.java b/Mage.Sets/src/mage/cards/l/LatullasOrders.java new file mode 100644 index 0000000000..d11ef2b512 --- /dev/null +++ b/Mage.Sets/src/mage/cards/l/LatullasOrders.java @@ -0,0 +1,129 @@ +/* + * Copyright 2010 BetaSteward_at_googlemail.com. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are + * permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this list of + * conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, this list + * of conditions and the following disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY BetaSteward_at_googlemail.com ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BetaSteward_at_googlemail.com OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * The views and conclusions contained in the software and documentation are those of the + * authors and should not be interpreted as representing official policies, either expressed + * or implied, of BetaSteward_at_googlemail.com. + */ +package mage.cards.l; + +import java.util.UUID; +import mage.abilities.TriggeredAbilityImpl; +import mage.abilities.effects.common.AttachEffect; +import mage.abilities.effects.common.DestroyTargetEffect; +import mage.abilities.keyword.EnchantAbility; +import mage.abilities.keyword.FlashAbility; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.SubType; +import mage.constants.Outcome; +import mage.constants.Zone; +import mage.filter.FilterPermanent; +import mage.filter.predicate.mageobject.CardTypePredicate; +import mage.filter.predicate.permanent.ControllerIdPredicate; +import mage.game.Game; +import mage.game.events.DamagedPlayerEvent; +import mage.game.events.GameEvent; +import mage.game.events.GameEvent.EventType; +import mage.game.permanent.Permanent; +import mage.players.Player; +import mage.target.TargetPermanent; +import mage.target.common.TargetCreaturePermanent; + +/** + * + * @author L_J + */ +public class LatullasOrders extends CardImpl { + + public LatullasOrders(UUID ownerId, CardSetInfo setInfo) { + super(ownerId,setInfo,new CardType[]{CardType.ENCHANTMENT},"{1}{R}"); + this.subtype.add(SubType.AURA); + + // Flash + this.addAbility(FlashAbility.getInstance()); + + // Enchant creature + TargetPermanent auraTarget = new TargetCreaturePermanent(); + this.getSpellAbility().addTarget(auraTarget); + this.getSpellAbility().addEffect(new AttachEffect(Outcome.Protect)); + this.addAbility(new EnchantAbility(auraTarget.getTargetName())); + + // Whenever enchanted creature deals combat damage to defending player, you may destroy target artifact that player controls. + this.addAbility(new LatullasOrdersTriggeredAbility()); + } + + public LatullasOrders(final LatullasOrders card) { + super(card); + } + + @Override + public LatullasOrders copy() { + return new LatullasOrders(this); + } +} + +class LatullasOrdersTriggeredAbility extends TriggeredAbilityImpl { + + public LatullasOrdersTriggeredAbility() { + super(Zone.BATTLEFIELD, new DestroyTargetEffect(), true); + } + + public LatullasOrdersTriggeredAbility(final LatullasOrdersTriggeredAbility ability) { + super(ability); + } + + @Override + public LatullasOrdersTriggeredAbility copy() { + return new LatullasOrdersTriggeredAbility(this); + } + + @Override + public boolean checkEventType(GameEvent event, Game game) { + return event.getType() == EventType.DAMAGED_PLAYER; + } + + @Override + public boolean checkTrigger(GameEvent event, Game game) { + Permanent enchantment = game.getPermanentOrLKIBattlefield(this.getSourceId()); + if (event.getSourceId().equals(enchantment.getAttachedTo()) && ((DamagedPlayerEvent) event).isCombatDamage()) { + Player player = game.getPlayer(event.getTargetId()); + if (player != null) { + FilterPermanent filter = new FilterPermanent("an artifact controlled by " + player.getLogName()); + filter.add(new CardTypePredicate(CardType.ARTIFACT)); + filter.add(new ControllerIdPredicate(event.getTargetId())); + + this.getTargets().clear(); + this.addTarget(new TargetPermanent(filter)); + return true; + } + } + return false; + } + + @Override + public String getRule() { + return "Whenever enchanted creature deals combat damage to defending player, you may destroy target artifact that player controls."; + } +} diff --git a/Mage.Sets/src/mage/cards/l/LeylineOfSingularity.java b/Mage.Sets/src/mage/cards/l/LeylineOfSingularity.java index 91c380d368..4c30b1554f 100644 --- a/Mage.Sets/src/mage/cards/l/LeylineOfSingularity.java +++ b/Mage.Sets/src/mage/cards/l/LeylineOfSingularity.java @@ -36,9 +36,7 @@ import mage.abilities.keyword.LeylineAbility; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.*; -import mage.filter.FilterPermanent; -import mage.filter.predicate.Predicates; -import mage.filter.predicate.mageobject.CardTypePredicate; +import mage.filter.common.FilterNonlandPermanent; import mage.game.Game; import mage.game.permanent.Permanent; @@ -48,21 +46,14 @@ import mage.game.permanent.Permanent; */ public class LeylineOfSingularity extends CardImpl { - private static final FilterPermanent filter = new FilterPermanent("nonland permanents"); - - static { - filter.add(Predicates.not(new CardTypePredicate(CardType.LAND))); - } - public LeylineOfSingularity(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.ENCHANTMENT},"{2}{U}{U}"); - + super(ownerId, setInfo, new CardType[]{CardType.ENCHANTMENT}, "{2}{U}{U}"); + // If Leyline of Singularity is in your opening hand, you may begin the game with it on the battlefield. this.addAbility(LeylineAbility.getInstance()); // All nonland permanents are legendary. - this.addAbility(new SimpleStaticAbility(Zone.BATTLEFIELD, new SetSupertypeAllEffect(Duration.WhileOnBattlefield, filter))); - + this.addAbility(new SimpleStaticAbility(Zone.BATTLEFIELD, new SetSupertypeAllEffect())); } public LeylineOfSingularity(final LeylineOfSingularity card) { @@ -75,19 +66,16 @@ public class LeylineOfSingularity extends CardImpl { } } - class SetSupertypeAllEffect extends ContinuousEffectImpl { - private final FilterPermanent filter; + private static final FilterNonlandPermanent filter = new FilterNonlandPermanent(); - public SetSupertypeAllEffect(Duration duration, FilterPermanent filter) { - super(duration, Layer.TypeChangingEffects_4, SubLayer.NA, Outcome.Detriment); - this.filter = filter; + public SetSupertypeAllEffect() { + super(Duration.WhileOnBattlefield, Layer.TypeChangingEffects_4, SubLayer.NA, Outcome.Detriment); } public SetSupertypeAllEffect(final SetSupertypeAllEffect effect) { super(effect); - this.filter = effect.filter; } @Override @@ -97,9 +85,8 @@ class SetSupertypeAllEffect extends ContinuousEffectImpl { @Override public boolean apply(Game game, Ability source) { - for (Permanent permanent: game.getBattlefield().getActivePermanents(filter, source.getControllerId(), source.getSourceId(), game)) { - permanent.addSuperType(SuperType.LEGENDARY); - + for (Permanent permanent : game.getBattlefield().getActivePermanents(filter, source.getControllerId(), source.getSourceId(), game)) { + permanent.addSuperType(SuperType.LEGENDARY); } return true; } diff --git a/Mage.Sets/src/mage/cards/l/LiarsPendulum.java b/Mage.Sets/src/mage/cards/l/LiarsPendulum.java new file mode 100644 index 0000000000..d0117ed33f --- /dev/null +++ b/Mage.Sets/src/mage/cards/l/LiarsPendulum.java @@ -0,0 +1,143 @@ +/* + * Copyright 2010 BetaSteward_at_googlemail.com. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are + * permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this list of + * conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, this list + * of conditions and the following disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY BetaSteward_at_googlemail.com ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BetaSteward_at_googlemail.com OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * The views and conclusions contained in the software and documentation are those of the + * authors and should not be interpreted as representing official policies, either expressed + * or implied, of BetaSteward_at_googlemail.com. + */ +package mage.cards.l; + +import java.util.UUID; +import mage.abilities.Ability; +import mage.abilities.common.SimpleActivatedAbility; +import mage.abilities.costs.common.TapSourceCost; +import mage.abilities.costs.mana.GenericManaCost; +import mage.abilities.effects.OneShotEffect; +import mage.cards.Card; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.cards.SplitCard; +import mage.cards.repository.CardRepository; +import mage.choices.Choice; +import mage.choices.ChoiceImpl; +import mage.constants.CardType; +import mage.constants.Outcome; +import mage.constants.Zone; +import mage.game.Game; +import mage.players.Player; +import mage.target.common.TargetOpponent; + +/** + * + * @author L_J + */ +public class LiarsPendulum extends CardImpl { + + public LiarsPendulum(UUID ownerId, CardSetInfo setInfo) { + super(ownerId,setInfo,new CardType[]{CardType.ARTIFACT},"{1}"); + + // {2}, {T}: Choose a card name. Target opponent guesses whether a card with that name is in your hand. You may reveal your hand. If you do and your opponent guessed wrong, draw a card. + Ability ability = new SimpleActivatedAbility(Zone.BATTLEFIELD, new LiarsPendulumEffect(), new GenericManaCost(2)); + ability.addCost(new TapSourceCost()); + ability.addTarget(new TargetOpponent()); + this.addAbility(ability); + } + + public LiarsPendulum(final LiarsPendulum card) { + super(card); + } + + @Override + public LiarsPendulum copy() { + return new LiarsPendulum(this); + } +} + + +class LiarsPendulumEffect extends OneShotEffect { + + public LiarsPendulumEffect() { + super(Outcome.DrawCard); + this.staticText = "Choose a card name. Target opponent guesses whether a card with that name is in your hand. You may reveal your hand. If you do and your opponent guessed wrong, draw a card"; + } + + public LiarsPendulumEffect(final LiarsPendulumEffect effect) { + super(effect); + } + + @Override + public LiarsPendulumEffect copy() { + return new LiarsPendulumEffect(this); + } + + @Override + public boolean apply(Game game, Ability source) { + Player controller = game.getPlayer(source.getControllerId()); + Player opponent = game.getPlayer(this.getTargetPointer().getFirst(game, source)); + if (controller != null && opponent != null) { + // Name a card. + Choice choice = new ChoiceImpl(); + choice.setChoices(CardRepository.instance.getNames()); + choice.setMessage("Choose a card name"); + while (!controller.choose(Outcome.Benefit, choice, game)) { + if (!controller.canRespond()) { + return false; + } + } + String cardName = choice.getChoice(); + game.informPlayers("Card named: " + cardName); + boolean opponentGuess = false; + + if (opponent.chooseUse(Outcome.Neutral, "Is the chosen card (" + cardName + ") in " + controller.getLogName() + "'s hand?", source, game)) { + opponentGuess = true; + } + boolean rightGuess = !opponentGuess; + + for (Card card : controller.getHand().getCards(game)) { + if (card.isSplitCard()){ + SplitCard splitCard = (SplitCard) card; + if (splitCard.getLeftHalfCard().getName().equals(cardName)){ + rightGuess = opponentGuess; + } + else if (splitCard.getRightHalfCard().getName().equals(cardName)){ + rightGuess = opponentGuess; + } + } + if (card.getName().equals(cardName)) { + rightGuess = opponentGuess; + } + } + game.informPlayers(opponent.getLogName() + " guesses that " + cardName + " is " + (opponentGuess ? "" : "not") + " in " + controller.getLogName() + "'s hand"); + + if (controller.chooseUse(outcome, "Reveal your hand?", source, game)) { + controller.revealCards("hand of " + controller.getName(), controller.getHand(), game); + if (!rightGuess) { + controller.drawCards(1, game); + } + } + return true; + } + return false; + } + +} diff --git a/Mage.Sets/src/mage/cards/l/LivingInferno.java b/Mage.Sets/src/mage/cards/l/LivingInferno.java new file mode 100644 index 0000000000..aaa17b732e --- /dev/null +++ b/Mage.Sets/src/mage/cards/l/LivingInferno.java @@ -0,0 +1,132 @@ +/* + * Copyright 2010 BetaSteward_at_googlemail.com. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are + * permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this list of + * conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, this list + * of conditions and the following disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY BetaSteward_at_googlemail.com ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BetaSteward_at_googlemail.com OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * The views and conclusions contained in the software and documentation are those of the + * authors and should not be interpreted as representing official policies, either expressed + * or implied, of BetaSteward_at_googlemail.com. + */ +package mage.cards.l; + +import java.util.HashSet; +import java.util.Set; +import java.util.UUID; +import mage.MageInt; +import mage.abilities.Ability; +import mage.abilities.common.SimpleActivatedAbility; +import mage.abilities.costs.common.TapSourceCost; +import mage.abilities.effects.OneShotEffect; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.SubType; +import mage.constants.Outcome; +import mage.constants.Zone; +import mage.game.Game; +import mage.game.permanent.Permanent; +import mage.target.Target; +import mage.target.common.TargetCreaturePermanentAmount; + +/** + * + * @author LevelX2 & L_J + */ +public class LivingInferno extends CardImpl { + + private final UUID originalId; + + public LivingInferno(UUID ownerId, CardSetInfo setInfo) { + super(ownerId,setInfo,new CardType[]{CardType.CREATURE},"{6}{R}{R}"); + this.subtype.add(SubType.ELEMENTAL); + this.power = new MageInt(8); + this.toughness = new MageInt(5); + + // {T}: Living Inferno deals damage equal to its power divided as you choose among any number of target creatures. Each of those creatures deals damage equal to its power to Living Inferno. + Ability ability = new SimpleActivatedAbility(Zone.BATTLEFIELD, new LivingInfernoEffect(), new TapSourceCost()); + ability.addTarget(new TargetCreaturePermanentAmount(1)); + this.addAbility(ability); + originalId = ability.getOriginalId(); + } + + @Override + public void adjustTargets(Ability ability, Game game) { + if(ability.getOriginalId().equals(originalId)) { + Permanent sourcePermanent = game.getPermanentOrLKIBattlefield(ability.getSourceId()); + if (sourcePermanent != null) { + int xValue = sourcePermanent.getPower().getValue(); + ability.getTargets().clear(); + ability.addTarget(new TargetCreaturePermanentAmount(xValue)); + } + } + } + + public LivingInferno(final LivingInferno card) { + super(card); + this.originalId = card.originalId; + } + + @Override + public LivingInferno copy() { + return new LivingInferno(this); + } +} + +class LivingInfernoEffect extends OneShotEffect { + + public LivingInfernoEffect() { + super(Outcome.Benefit); + this.staticText = "{this} deals damage equal to its power divided as you choose among any number of target creatures. Each of those creatures deals damage equal to its power to {this}"; + } + + public LivingInfernoEffect(final LivingInfernoEffect effect) { + super(effect); + } + + @Override + public LivingInfernoEffect copy() { + return new LivingInfernoEffect(this); + } + + @Override + public boolean apply(Game game, Ability source) { + if (!source.getTargets().isEmpty()) { + Target multiTarget = source.getTargets().get(0); + Set permanents = new HashSet<>(); + for (UUID target : multiTarget.getTargets()) { + Permanent permanent = game.getPermanent(target); + if (permanent != null) { + permanents.add(permanent); + permanent.damage(multiTarget.getTargetAmount(target), source.getSourceId(), game, false, true); + } + } + // Each of those creatures deals damage equal to its power to Living Inferno + Permanent sourceCreature = game.getPermanent(source.getSourceId()); + if (sourceCreature != null) { + for (Permanent permanent : permanents) { + sourceCreature.damage(permanent.getPower().getValue(), permanent.getId(), game, false, true); + } + } + return true; + } + return false; + } +} diff --git a/Mage.Sets/src/mage/cards/l/LoxodonPeacekeeper.java b/Mage.Sets/src/mage/cards/l/LoxodonPeacekeeper.java new file mode 100644 index 0000000000..c06d39dea4 --- /dev/null +++ b/Mage.Sets/src/mage/cards/l/LoxodonPeacekeeper.java @@ -0,0 +1,162 @@ +/* + * Copyright 2010 BetaSteward_at_googlemail.com. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are + * permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this list of + * conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, this list + * of conditions and the following disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY BetaSteward_at_googlemail.com ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BetaSteward_at_googlemail.com OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * The views and conclusions contained in the software and documentation are those of the + * authors and should not be interpreted as representing official policies, either expressed + * or implied, of BetaSteward_at_googlemail.com. + */ +package mage.cards.l; + +import java.util.HashSet; +import java.util.Set; +import java.util.UUID; +import mage.MageInt; +import mage.abilities.Ability; +import mage.abilities.common.BeginningOfUpkeepTriggeredAbility; +import mage.abilities.effects.ContinuousEffect; +import mage.abilities.effects.OneShotEffect; +import mage.abilities.effects.common.continuous.GainControlTargetEffect; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.SubType; +import mage.constants.Duration; +import mage.constants.Outcome; +import mage.constants.TargetController; +import mage.filter.FilterPlayer; +import mage.filter.predicate.Predicates; +import mage.filter.predicate.other.PlayerIdPredicate; +import mage.game.Game; +import mage.game.permanent.Permanent; +import mage.players.Player; +import mage.target.TargetPlayer; +import mage.target.targetpointer.FixedTarget; + +/** + * + * @author L_J + */ +public class LoxodonPeacekeeper extends CardImpl { + + public LoxodonPeacekeeper(UUID ownerId, CardSetInfo setInfo) { + super(ownerId,setInfo,new CardType[]{CardType.CREATURE},"{1}{W}"); + this.subtype.add(SubType.ELEPHANT); + this.subtype.add(SubType.SOLDIER); + this.power = new MageInt(4); + this.toughness = new MageInt(4); + + // At the beginning of your upkeep, the player with the lowest life total gains control of Loxodon Peacekeeper. If two or more players are tied for lowest life total, you choose one of them, and that player gains control of Loxodon Peacekeeper. + this.addAbility(new BeginningOfUpkeepTriggeredAbility(new LoxodonPeacekeeperEffect(), TargetController.YOU, false)); + + } + + public LoxodonPeacekeeper(final LoxodonPeacekeeper card) { + super(card); + } + + @Override + public LoxodonPeacekeeper copy() { + return new LoxodonPeacekeeper(this); + } +} + +class LoxodonPeacekeeperEffect extends OneShotEffect { + + public LoxodonPeacekeeperEffect() { + super(Outcome.Benefit); + this.staticText = "the player with the lowest life total gains control of {this}. If two or more players are tied for lowest life total, you choose one of them, and that player gains control of {this}"; + } + + public LoxodonPeacekeeperEffect(final LoxodonPeacekeeperEffect effect) { + super(effect); + } + + @Override + public LoxodonPeacekeeperEffect copy() { + return new LoxodonPeacekeeperEffect(this); + } + + @Override + public boolean apply(Game game, Ability source) { + Player controller = game.getPlayer(source.getControllerId()); + if (controller != null) { + Permanent sourcePermanent = game.getPermanent(source.getSourceId()); + if (sourcePermanent != null) { + int lowLife = Integer.MAX_VALUE; + Set tiedPlayers = new HashSet<>(); + for (UUID playerId : game.getState().getPlayersInRange(source.getControllerId(), game)) { + Player player = game.getPlayer(playerId); + if (player != null) { + if (player.getLife() < lowLife) { + lowLife = player.getLife(); + } + } + } + for (UUID playerId : game.getState().getPlayersInRange(source.getControllerId(), game)) { + Player player = game.getPlayer(playerId); + if (player != null) { + if (player.getLife() == lowLife) { + tiedPlayers.add(playerId); + } + } + } + + if (tiedPlayers.size() > 0) { + UUID newControllerId = null; + if (tiedPlayers.size() > 1) { + FilterPlayer filter = new FilterPlayer("a player tied for lowest life total"); + for (UUID playerId : game.getState().getPlayersInRange(source.getControllerId(), game)) { + if (!tiedPlayers.contains(playerId)) { + filter.add(Predicates.not(new PlayerIdPredicate(playerId))); + } + } + TargetPlayer target = new TargetPlayer(1, 1, true, filter); + if (target.canChoose(source.getSourceId(), controller.getId(), game)) { + while (!target.isChosen() && target.canChoose(controller.getId(), game) && controller.canRespond()) { + controller.chooseTarget(outcome, target, source, game); + } + } else { + return false; + } + newControllerId = game.getPlayer(target.getFirstTarget()).getId(); + } else { + for (UUID playerId : game.getState().getPlayersInRange(source.getControllerId(), game)) { + if (tiedPlayers.contains(playerId)) { + newControllerId = playerId; + break; + } + } + } + if (newControllerId != null) { + ContinuousEffect effect = new GainControlTargetEffect(Duration.Custom, newControllerId); + effect.setTargetPointer(new FixedTarget(sourcePermanent, game)); + game.addEffect(effect, source); + game.informPlayers(game.getPlayer(newControllerId).getLogName() + " has gained control of " + sourcePermanent.getLogName()); + return true; + } + } + } + } + return false; + } +} diff --git a/Mage.Sets/src/mage/cards/l/LumengridAugur.java b/Mage.Sets/src/mage/cards/l/LumengridAugur.java new file mode 100644 index 0000000000..10c15e651c --- /dev/null +++ b/Mage.Sets/src/mage/cards/l/LumengridAugur.java @@ -0,0 +1,111 @@ +/* + * Copyright 2010 BetaSteward_at_googlemail.com. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are + * permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this list of + * conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, this list + * of conditions and the following disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY BetaSteward_at_googlemail.com ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BetaSteward_at_googlemail.com OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * The views and conclusions contained in the software and documentation are those of the + * authors and should not be interpreted as representing official policies, either expressed + * or implied, of BetaSteward_at_googlemail.com. + */ +package mage.cards.l; + +import java.util.UUID; +import mage.MageInt; +import mage.abilities.Ability; +import mage.abilities.common.SimpleActivatedAbility; +import mage.abilities.costs.common.TapSourceCost; +import mage.abilities.costs.mana.GenericManaCost; +import mage.abilities.effects.OneShotEffect; +import mage.cards.Card; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.SubType; +import mage.constants.Outcome; +import mage.constants.Zone; +import mage.game.Game; +import mage.game.permanent.Permanent; +import mage.players.Player; +import mage.target.TargetPlayer; + +/** + * + * @author L_J + */ +public class LumengridAugur extends CardImpl { + + public LumengridAugur(UUID ownerId, CardSetInfo setInfo) { + super(ownerId,setInfo,new CardType[]{CardType.CREATURE},"{3}{U}"); + this.subtype.add(SubType.VEDALKEN); + this.subtype.add(SubType.WIZARD); + this.power = new MageInt(2); + this.toughness = new MageInt(2); + + // {1}, {T}: Target player draws a card, then discards a card. If that player discards an artifact card this way, untap Lumengrid Augur. + Ability ability = new SimpleActivatedAbility(Zone.BATTLEFIELD, new LumengridAugurEffect(), new GenericManaCost(1)); + ability.addCost(new TapSourceCost()); + ability.addTarget(new TargetPlayer()); + this.addAbility(ability); + } + + public LumengridAugur(final LumengridAugur card) { + super(card); + } + + @Override + public LumengridAugur copy() { + return new LumengridAugur(this); + } +} + +class LumengridAugurEffect extends OneShotEffect { + + public LumengridAugurEffect() { + super(Outcome.DrawCard); + staticText = "Target player draws a card, then discards a card. If that player discards an artifact card this way, untap {this}"; + } + + public LumengridAugurEffect(final LumengridAugurEffect effect) { + super(effect); + } + + @Override + public LumengridAugurEffect copy() { + return new LumengridAugurEffect(this); + } + + @Override + public boolean apply(Game game, Ability source) { + Player player = game.getPlayer(getTargetPointer().getFirst(game, source)); + Permanent sourcePermanent = game.getPermanent(source.getSourceId()); + if (player != null) { + player.drawCards(1, game); + Card discardedCard = player.discardOne(false, source, game); + if (discardedCard != null && discardedCard.isArtifact()) { + if (sourcePermanent != null) { + sourcePermanent.untap(game); + } + } + return true; + } + return false; + } +} diff --git a/Mage.Sets/src/mage/cards/m/MaddeningImp.java b/Mage.Sets/src/mage/cards/m/MaddeningImp.java new file mode 100644 index 0000000000..e56010487f --- /dev/null +++ b/Mage.Sets/src/mage/cards/m/MaddeningImp.java @@ -0,0 +1,200 @@ +/* + * Copyright 2010 BetaSteward_at_googlemail.com. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are + * permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this list of + * conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, this list + * of conditions and the following disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY BetaSteward_at_googlemail.com ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BetaSteward_at_googlemail.com OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * The views and conclusions contained in the software and documentation are those of the + * authors and should not be interpreted as representing official policies, either expressed + * or implied, of BetaSteward_at_googlemail.com. + */ +package mage.cards.m; + +import java.util.HashSet; +import java.util.Set; +import java.util.UUID; +import mage.MageInt; +import mage.MageObjectReference; +import mage.abilities.Ability; +import mage.abilities.common.delayed.AtTheBeginOfNextEndStepDelayedTriggeredAbility; +import mage.abilities.condition.Condition; +import mage.abilities.condition.InvertCondition; +import mage.abilities.condition.common.TargetAttackedThisTurnCondition; +import mage.abilities.costs.common.TapSourceCost; +import mage.abilities.decorator.ConditionalActivatedAbility; +import mage.abilities.effects.OneShotEffect; +import mage.abilities.effects.common.combat.AttacksIfAbleAllEffect; +import mage.abilities.keyword.FlyingAbility; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.*; +import mage.filter.common.FilterCreaturePermanent; +import mage.filter.predicate.Predicates; +import mage.filter.predicate.mageobject.SubtypePredicate; +import mage.filter.predicate.permanent.ControllerPredicate; +import mage.game.Game; +import mage.game.permanent.Permanent; +import mage.players.Player; +import mage.watchers.common.AttackedThisTurnWatcher; + +/** + * + * @author L_J + */ +public class MaddeningImp extends CardImpl { + + private static final FilterCreaturePermanent filter = new FilterCreaturePermanent("non-Wall creatures"); + + static { + filter.add(Predicates.not(new SubtypePredicate(SubType.WALL))); + filter.add(new ControllerPredicate(TargetController.ACTIVE)); + filter.setMessage("non-Wall creatures the active player controls"); + } + + public MaddeningImp(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{2}{B}"); + this.subtype.add(SubType.IMP); + this.power = new MageInt(1); + this.toughness = new MageInt(1); + + // Flying + this.addAbility(FlyingAbility.getInstance()); + + // {T}: Non-Wall creatures the active player controls attack this turn if able. At the beginning of the next end step, destroy each of those creatures that didn't attack this turn. Activate this ability only during an opponent's turn and only before combat. + Ability ability = new ConditionalActivatedAbility(Zone.BATTLEFIELD, new AttacksIfAbleAllEffect(filter, Duration.EndOfTurn), + new TapSourceCost(), new MaddeningImpTurnCondition(), + "{T}: Non-Wall creatures the active player controls attack this turn if able. " + + "At the beginning of the next end step, destroy each of those creatures that didn't attack this turn. " + + "Activate this ability only during an opponent's turn and only before combat."); + ability.addEffect(new MaddeningImpCreateDelayedTriggeredAbilityEffect()); + this.addAbility(ability, new AttackedThisTurnWatcher()); + + } + + public MaddeningImp(final MaddeningImp card) { + super(card); + } + + @Override + public MaddeningImp copy() { + return new MaddeningImp(this); + } +} + +class MaddeningImpTurnCondition implements Condition { + + @Override + public boolean apply(Game game, Ability source) { + Player activePlayer = game.getPlayer(game.getActivePlayerId()); + return activePlayer != null && activePlayer.hasOpponent(source.getControllerId(), game) && game.getPhase().getStep().getType().getIndex() < 5; + } + + @Override + public String toString() { + return ""; + } +} + +class MaddeningImpCreateDelayedTriggeredAbilityEffect extends OneShotEffect { + + private static final FilterCreaturePermanent filter = new FilterCreaturePermanent(); + + static { + filter.add(Predicates.not(new SubtypePredicate(SubType.WALL))); + filter.add(new ControllerPredicate(TargetController.ACTIVE)); + } + + public MaddeningImpCreateDelayedTriggeredAbilityEffect() { + super(Outcome.DestroyPermanent); + this.staticText = "At the beginning of the next end step, destroy each of those creatures that didn't attack this turn"; + } + + public MaddeningImpCreateDelayedTriggeredAbilityEffect(final MaddeningImpCreateDelayedTriggeredAbilityEffect effect) { + super(effect); + } + + @Override + public MaddeningImpCreateDelayedTriggeredAbilityEffect copy() { + return new MaddeningImpCreateDelayedTriggeredAbilityEffect(this); + } + + @Override + public boolean apply(Game game, Ability source) { + Player player = game.getPlayer(game.getActivePlayerId()); + if (player != null) { + Set activeCreatures = new HashSet<>(); + for (Permanent creature : game.getBattlefield().getAllActivePermanents(filter, player.getId(), game)) { + if (creature != null) { + activeCreatures.add(new MageObjectReference(creature, game)); + } + } + AtTheBeginOfNextEndStepDelayedTriggeredAbility delayedAbility + = new AtTheBeginOfNextEndStepDelayedTriggeredAbility(Zone.ALL, new MaddeningImpDelayedDestroyEffect(activeCreatures), TargetController.ANY, new InvertCondition(TargetAttackedThisTurnCondition.instance)); + delayedAbility.getDuration(); + game.addDelayedTriggeredAbility(delayedAbility, source); + return true; + } + return false; + } +} + +class MaddeningImpDelayedDestroyEffect extends OneShotEffect { + + private Set activeCreatures; + + MaddeningImpDelayedDestroyEffect(Set activeCreatures) { + super(Outcome.DestroyPermanent); + this.activeCreatures = activeCreatures; + this.staticText = "At the beginning of the next end step, destroy each of those creatures that didn't attack this turn"; + } + + MaddeningImpDelayedDestroyEffect(final MaddeningImpDelayedDestroyEffect effect) { + super(effect); + this.activeCreatures = effect.activeCreatures; + } + + @Override + public MaddeningImpDelayedDestroyEffect copy() { + return new MaddeningImpDelayedDestroyEffect(this); + } + + public boolean apply(Game game, Ability source) { + Player player = game.getPlayer(game.getActivePlayerId()); + if (player != null) { + for (Permanent permanent : game.getBattlefield().getAllActivePermanents(player.getId())) { + + MageObjectReference mor = new MageObjectReference(permanent, game); + // Only affect permanents present when the ability resolved + if (!activeCreatures.contains(mor)) { + continue; + } + // Creatures that attacked are safe. + AttackedThisTurnWatcher watcher = (AttackedThisTurnWatcher) game.getState().getWatchers().get(AttackedThisTurnWatcher.class.getSimpleName()); + if (watcher != null && watcher.getAttackedThisTurnCreatures().contains(mor)) { + continue; + } + // Destroy the rest. + permanent.destroy(source.getSourceId(), game, false); + } + return true; + } + return false; + } +} diff --git a/Mage.Sets/src/mage/cards/m/ManaweftSliver.java b/Mage.Sets/src/mage/cards/m/ManaweftSliver.java index f26076952d..ff16a2ed6a 100644 --- a/Mage.Sets/src/mage/cards/m/ManaweftSliver.java +++ b/Mage.Sets/src/mage/cards/m/ManaweftSliver.java @@ -29,9 +29,8 @@ package mage.cards.m; import java.util.UUID; import mage.MageInt; -import mage.abilities.Ability; import mage.abilities.common.SimpleStaticAbility; -import mage.abilities.effects.common.continuous.GainAbilityAllEffect; +import mage.abilities.effects.common.continuous.GainAbilityControlledEffect; import mage.abilities.mana.AnyColorManaAbility; import mage.cards.CardImpl; import mage.cards.CardSetInfo; @@ -39,7 +38,7 @@ import mage.constants.CardType; import mage.constants.SubType; import mage.constants.Duration; import mage.constants.Zone; -import mage.filter.StaticFilters; +import mage.filter.common.FilterCreaturePermanent; /** * @@ -47,6 +46,8 @@ import mage.filter.StaticFilters; */ public class ManaweftSliver extends CardImpl { + public static final FilterCreaturePermanent filter = new FilterCreaturePermanent(SubType.SLIVER, "Sliver creatures"); + public ManaweftSliver(UUID ownerId, CardSetInfo setInfo) { super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{1}{G}"); this.subtype.add(SubType.SLIVER); @@ -55,11 +56,11 @@ public class ManaweftSliver extends CardImpl { this.toughness = new MageInt(1); // Sliver creatures you control have "{T}: Add one mana of any color to your mana pool." - Ability ability = new AnyColorManaAbility(); - this.addAbility(new SimpleStaticAbility(Zone.BATTLEFIELD, - new GainAbilityAllEffect(ability, - Duration.WhileOnBattlefield, StaticFilters.FILTER_PERMANENT_CREATURE_SLIVERS, - "Sliver creatures you control have \"{T}: Add one mana of any color to your mana pool.\""))); + this.addAbility(new SimpleStaticAbility(Zone.BATTLEFIELD, new GainAbilityControlledEffect( + new AnyColorManaAbility(), + Duration.WhileOnBattlefield, + filter + ))); } public ManaweftSliver(final ManaweftSliver card) { diff --git a/Mage.Sets/src/mage/cards/m/Martyrdom.java b/Mage.Sets/src/mage/cards/m/Martyrdom.java new file mode 100644 index 0000000000..129b444dda --- /dev/null +++ b/Mage.Sets/src/mage/cards/m/Martyrdom.java @@ -0,0 +1,192 @@ +/* + * Copyright 2010 BetaSteward_at_googlemail.com. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are + * permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this list of + * conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, this list + * of conditions and the following disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY BetaSteward_at_googlemail.com ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BetaSteward_at_googlemail.com OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * The views and conclusions contained in the software and documentation are those of the + * authors and should not be interpreted as representing official policies, either expressed + * or implied, of BetaSteward_at_googlemail.com. + */ +package mage.cards.m; + +import java.util.UUID; +import mage.MageObjectReference; +import mage.abilities.Ability; +import mage.abilities.ActivatedAbilityImpl; +import mage.abilities.costs.mana.GenericManaCost; +import mage.abilities.effects.ContinuousEffectImpl; +import mage.abilities.effects.Effect; +import mage.abilities.effects.Effects; +import mage.abilities.effects.RedirectionEffect; +import mage.abilities.effects.common.RedirectDamageFromSourceToTargetEffect; +import mage.abilities.effects.common.continuous.GainAbilityTargetEffect; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.Duration; +import mage.constants.EffectType; +import mage.constants.Layer; +import mage.constants.Outcome; +import mage.constants.SubLayer; +import mage.constants.TargetController; +import mage.constants.Zone; +import mage.filter.common.FilterCreaturePermanent; +import mage.game.Game; +import mage.game.events.GameEvent; +import mage.game.permanent.Permanent; +import mage.players.Player; +import mage.target.common.TargetControlledCreaturePermanent; +import mage.target.common.TargetCreatureOrPlayer; + +/** + * + * @author L_J + */ +public class Martyrdom extends CardImpl { + + public Martyrdom(UUID ownerId, CardSetInfo setInfo) { + super(ownerId,setInfo,new CardType[]{CardType.INSTANT},"{1}{W}{W}"); + + // Until end of turn, target creature you control gains "{0}: The next 1 damage that would be dealt to target creature or player this turn is dealt to this creature instead." Only you may activate this ability. + this.getSpellAbility().addEffect(new MartyrdomGainAbilityTargetEffect()); + this.getSpellAbility().addTarget(new TargetControlledCreaturePermanent()); + } + + public Martyrdom(final Martyrdom card) { + super(card); + } + + @Override + public Martyrdom copy() { + return new Martyrdom(this); + } +} + +class MartyrdomGainAbilityTargetEffect extends ContinuousEffectImpl { + + public MartyrdomGainAbilityTargetEffect() { + super(Duration.EndOfTurn, Layer.AbilityAddingRemovingEffects_6, SubLayer.NA, Outcome.AddAbility); + this.staticText = "Until end of turn, target creature you control gains \"{0}: The next 1 damage that would be dealt to target creature or player this turn is dealt to this creature instead.\" Only you may activate this ability"; + } + + public MartyrdomGainAbilityTargetEffect(final MartyrdomGainAbilityTargetEffect effect) { + super(effect); + } + + @Override + public boolean apply(Game game, Ability source) { + Permanent permanent = game.getPermanent(getTargetPointer().getFirst(game, source)); + if (permanent != null) { + ActivatedAbilityImpl ability = new MartyrdomActivatedAbility(source.getControllerId()); + ability.setMayActivate(TargetController.ANY); + permanent.addAbility(ability, source.getSourceId(), game, false); + return true; + } + return false; + } + + @Override + public MartyrdomGainAbilityTargetEffect copy() { + return new MartyrdomGainAbilityTargetEffect(this); + } +} + +class MartyrdomActivatedAbility extends ActivatedAbilityImpl { + + private static FilterCreaturePermanent filter = new FilterCreaturePermanent(); + private UUID caster; + + public MartyrdomActivatedAbility(UUID caster) { + super(Zone.BATTLEFIELD, new MartyrdomRedirectDamageTargetEffect(Duration.EndOfTurn, 1), new GenericManaCost(0)); + this.addTarget(new TargetCreatureOrPlayer()); + this.caster = caster; + } + + private MartyrdomActivatedAbility(final MartyrdomActivatedAbility ability) { + super(ability); + this.caster = ability.caster; + } + + @Override + public Effects getEffects(Game game, EffectType effectType) { + return super.getEffects(game, effectType); + } + + @Override + public boolean canActivate(UUID playerId, Game game) { + if (playerId == caster) { + Permanent permanent = game.getBattlefield().getPermanent(this.getSourceId()); + if (permanent != null) { + if (filter.match(permanent, permanent.getId(), permanent.getControllerId(), game)) { + return super.canActivate(playerId, game); + } + } + } + return false; + } + + @Override + public MartyrdomActivatedAbility copy() { + return new MartyrdomActivatedAbility(this); + } + + @Override + public String getRule() { + return "{0}: The next 1 damage that would be dealt to target creature or player this turn is dealt to {this} instead."; + } +} + +class MartyrdomRedirectDamageTargetEffect extends RedirectionEffect { + + private static FilterCreaturePermanent filter = new FilterCreaturePermanent(); + + public MartyrdomRedirectDamageTargetEffect(Duration duration, int amount) { + super(duration, amount, true); + staticText = "The next " + amount + " damage that would be dealt to target creature or player this turn is dealt to {this} instead"; + } + + public MartyrdomRedirectDamageTargetEffect(final MartyrdomRedirectDamageTargetEffect effect) { + super(effect); + } + + @Override + public MartyrdomRedirectDamageTargetEffect copy() { + return new MartyrdomRedirectDamageTargetEffect(this); + } + + @Override + public boolean applies(GameEvent event, Ability source, Game game) { + Permanent permanent = game.getBattlefield().getPermanent(source.getSourceId()); + if (permanent != null) { + if (filter.match(permanent, permanent.getId(), permanent.getControllerId(), game)) { + if (event.getTargetId().equals(getTargetPointer().getFirst(game, source))) { + if (event.getTargetId() != null) { + TargetCreatureOrPlayer target = new TargetCreatureOrPlayer(); + target.add(source.getSourceId(), game); + redirectTarget = target; + return true; + } + } + } + } + return false; + } +} diff --git a/Mage.Sets/src/mage/cards/m/MartyrsCry.java b/Mage.Sets/src/mage/cards/m/MartyrsCry.java new file mode 100644 index 0000000000..0441ab4f5b --- /dev/null +++ b/Mage.Sets/src/mage/cards/m/MartyrsCry.java @@ -0,0 +1,101 @@ +/* + * Copyright 2010 BetaSteward_at_googlemail.com. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are + * permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this list of + * conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, this list + * of conditions and the following disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY BetaSteward_at_googlemail.com ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BetaSteward_at_googlemail.com OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * The views and conclusions contained in the software and documentation are those of the + * authors and should not be interpreted as representing official policies, either expressed + * or implied, of BetaSteward_at_googlemail.com. + */ +package mage.cards.m; + +import java.util.HashMap; +import java.util.Iterator; +import java.util.Map; +import java.util.UUID; +import mage.abilities.Ability; +import mage.abilities.effects.OneShotEffect; +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.players.Player; + +/** + * + * @author TheElk801 + */ +public class MartyrsCry extends CardImpl { + + public MartyrsCry(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.SORCERY}, "{W}{W}"); + + // Exile all white creatures. For each creature exiled this way, its controller draws a card. + this.getSpellAbility().addEffect(new MartyrsCryEffect()); + } + + public MartyrsCry(final MartyrsCry card) { + super(card); + } + + @Override + public MartyrsCry copy() { + return new MartyrsCry(this); + } +} + +class MartyrsCryEffect extends OneShotEffect { + + MartyrsCryEffect() { + super(Outcome.Exile); + this.staticText = "Exile all white creatures. For each creature exiled this way, its controller draws a card."; + } + + MartyrsCryEffect(final MartyrsCryEffect effect) { + super(effect); + } + + @Override + public MartyrsCryEffect copy() { + return new MartyrsCryEffect(this); + } + + @Override + public boolean apply(Game game, Ability source) { + Map playerCrtCount = new HashMap<>(); + for (Iterator it = game.getBattlefield().getActivePermanents(source.getControllerId(), game).iterator(); it.hasNext();) { + Permanent perm = it.next(); + if (perm != null && perm.isCreature() && perm.getColor(game).isWhite() && perm.moveToExile(null, null, source.getSourceId(), game)) { + playerCrtCount.putIfAbsent(perm.getControllerId(), 0); + playerCrtCount.compute(perm.getControllerId(), (p, amount) -> amount + 1); + } + } + for (UUID playerId : game.getPlayerList().toList()) { + Player player = game.getPlayer(playerId); + if (player != null) { + player.drawCards(playerCrtCount.getOrDefault(playerId, 0), game); + } + } + return true; + } +} diff --git a/Mage.Sets/src/mage/cards/m/MasterWarcraft.java b/Mage.Sets/src/mage/cards/m/MasterWarcraft.java new file mode 100644 index 0000000000..a825bbebd2 --- /dev/null +++ b/Mage.Sets/src/mage/cards/m/MasterWarcraft.java @@ -0,0 +1,311 @@ +/* + * Copyright 2010 BetaSteward_at_googlemail.com. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are + * permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this list of + * conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, this list + * of conditions and the following disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY BetaSteward_at_googlemail.com ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BetaSteward_at_googlemail.com OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * The views and conclusions contained in the software and documentation are those of the + * authors and should not be interpreted as representing official policies, either expressed + * or implied, of BetaSteward_at_googlemail.com. + */ +package mage.cards.m; + +import java.util.*; +import mage.MageObject; +import mage.abilities.Ability; +import mage.abilities.Mode; +import mage.abilities.common.CastOnlyDuringPhaseStepSourceAbility; +import mage.abilities.condition.common.BeforeAttackersAreDeclaredCondition; +import mage.abilities.effects.ContinuousRuleModifyingEffectImpl; +import mage.abilities.effects.OneShotEffect; +import mage.abilities.effects.RequirementEffect; +import mage.abilities.effects.RestrictionEffect; +import mage.abilities.effects.common.CreateDelayedTriggeredAbilityEffect; +import mage.abilities.effects.common.combat.AttacksIfAbleTargetEffect; +import mage.abilities.effects.common.combat.CantAttackTargetEffect; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.*; +import mage.filter.common.FilterCreaturePermanent; +import mage.game.Game; +import mage.game.events.GameEvent; +import mage.game.events.GameEvent.EventType; +import mage.game.events.ZoneChangeEvent; +import mage.game.permanent.Permanent; +import mage.game.stack.Spell; +import mage.players.Player; +import mage.target.Target; +import mage.target.common.TargetCreaturePermanent; +import mage.filter.predicate.permanent.ControllerPredicate; +import mage.target.targetpointer.FixedTarget; +import mage.watchers.Watcher; +import mage.watchers.common.ChooseBlockersRedundancyWatcher; + +/** + * + * @author L_J + */ +public class MasterWarcraft extends CardImpl { + + public MasterWarcraft(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.INSTANT}, "{2}{R/W}{R/W}"); + + // Cast Master Warcraft only before attackers are declared. + this.addAbility(new CastOnlyDuringPhaseStepSourceAbility(null, null, BeforeAttackersAreDeclaredCondition.instance, "Cast {this} only before attackers are declared")); + + // You choose which creatures attack this turn. + this.getSpellAbility().addEffect(new MasterWarcraftChooseAttackersEffect()); + + // You choose which creatures block this turn and how those creatures block. + this.getSpellAbility().addEffect(new MasterWarcraftChooseBlockersEffect()); + + + // (only the last resolved Master Warcraft spell's effects apply) + this.getSpellAbility().addWatcher(new MasterWarcraftCastWatcher()); + this.getSpellAbility().addEffect(new MasterWarcraftCastWatcherIncrementEffect()); + this.getSpellAbility().addWatcher(new ChooseBlockersRedundancyWatcher()); + this.getSpellAbility().addEffect(new ChooseBlockersRedundancyWatcherIncrementEffect()); + } + + public MasterWarcraft(final MasterWarcraft card) { + super(card); + } + + @Override + public MasterWarcraft copy() { + return new MasterWarcraft(this); + } + + private class MasterWarcraftCastWatcherIncrementEffect extends OneShotEffect { + + MasterWarcraftCastWatcherIncrementEffect() { + super(Outcome.Neutral); + } + + MasterWarcraftCastWatcherIncrementEffect(final MasterWarcraftCastWatcherIncrementEffect effect) { + super(effect); + } + + @Override + public boolean apply(Game game, Ability source) { + MasterWarcraftCastWatcher watcher = (MasterWarcraftCastWatcher) game.getState().getWatchers().get(MasterWarcraftCastWatcher.class.getSimpleName()); + if (watcher != null) { + watcher.increment(); + return true; + } + return false; + } + + @Override + public MasterWarcraftCastWatcherIncrementEffect copy() { + return new MasterWarcraftCastWatcherIncrementEffect(this); + } + } + + private class ChooseBlockersRedundancyWatcherIncrementEffect extends OneShotEffect { + + ChooseBlockersRedundancyWatcherIncrementEffect() { + super(Outcome.Neutral); + } + + ChooseBlockersRedundancyWatcherIncrementEffect(final ChooseBlockersRedundancyWatcherIncrementEffect effect) { + super(effect); + } + + @Override + public boolean apply(Game game, Ability source) { + ChooseBlockersRedundancyWatcher watcher = (ChooseBlockersRedundancyWatcher) game.getState().getWatchers().get(ChooseBlockersRedundancyWatcher.class.getSimpleName()); + if (watcher != null) { + watcher.increment(); + return true; + } + return false; + } + + @Override + public ChooseBlockersRedundancyWatcherIncrementEffect copy() { + return new ChooseBlockersRedundancyWatcherIncrementEffect(this); + } + } +} + +class MasterWarcraftChooseAttackersEffect extends ContinuousRuleModifyingEffectImpl { + + private static final FilterCreaturePermanent filter = new FilterCreaturePermanent("creatures that will attack this combat (creatures not chosen won't attack this combat)"); + static { + filter.add(new ControllerPredicate(TargetController.ACTIVE)); + } + + public MasterWarcraftChooseAttackersEffect() { + super(Duration.EndOfTurn, Outcome.Benefit, false, false); + staticText = "You choose which creatures attack this turn"; + } + + public MasterWarcraftChooseAttackersEffect(final MasterWarcraftChooseAttackersEffect effect) { + super(effect); + } + + @Override + public MasterWarcraftChooseAttackersEffect copy() { + return new MasterWarcraftChooseAttackersEffect(this); + } + + @Override + public boolean apply(Game game, Ability source) { + return true; + } + + @Override + public boolean checksEventType(GameEvent event, Game game) { + return event.getType() == GameEvent.EventType.DECLARING_ATTACKERS; + } + + @Override + public boolean applies(GameEvent event, Ability source, Game game) { + MasterWarcraftCastWatcher watcher = (MasterWarcraftCastWatcher) game.getState().getWatchers().get(MasterWarcraftCastWatcher.class.getSimpleName()); + watcher.decrement(); + if (watcher.copyCountApply > 0) { + game.informPlayers(source.getSourceObject(game).getIdName() + " didn't apply"); + return false; + } + watcher.copyCountApply = watcher.copyCount; + Player controller = game.getPlayer(source.getControllerId()); + Player attackingPlayer = game.getPlayer(game.getCombat().getAttackingPlayerId()); + if (controller != null && attackingPlayer != null && !attackingPlayer.getAvailableAttackers(game).isEmpty()) { + Target target = new TargetCreaturePermanent(0, Integer.MAX_VALUE, filter, true); + if (controller.chooseTarget(Outcome.Benefit, target, source, game)) { + for (Permanent permanent : game.getBattlefield().getActivePermanents(new FilterCreaturePermanent(), source.getControllerId(), source.getSourceId(), game)) { + + // Choose creatures that will be attacking this combat + if (target.getTargets().contains(permanent.getId())) { + RequirementEffect effect = new AttacksIfAbleTargetEffect(Duration.EndOfCombat); + effect.setText(""); + effect.setTargetPointer(new FixedTarget(permanent.getId())); + game.addEffect(effect, source); + game.informPlayers(controller.getLogName() + " has decided that " + permanent.getLogName() + " attacks this combat if able"); + + // All other creatures can't attack (unless they must attack) + } else { + boolean hasToAttack = false; + for (Map.Entry> entry : game.getContinuousEffects().getApplicableRequirementEffects(permanent, false, game).entrySet()) { + RequirementEffect effect2 = entry.getKey(); + if (effect2.mustAttack(game)) { + hasToAttack = true; + } + } + if (!hasToAttack) { + RestrictionEffect effect = new CantAttackTargetEffect(Duration.EndOfCombat); + effect.setText(""); + effect.setTargetPointer(new FixedTarget(permanent.getId())); + game.addEffect(effect, source); + } + } + } + } + } + return false; // the attack declaration resumes for the active player as normal + } +} + +class MasterWarcraftChooseBlockersEffect extends ContinuousRuleModifyingEffectImpl { + + public MasterWarcraftChooseBlockersEffect() { + super(Duration.EndOfTurn, Outcome.Benefit, false, false); + staticText = "You choose which creatures block this turn and how those creatures block"; + } + + public MasterWarcraftChooseBlockersEffect(final MasterWarcraftChooseBlockersEffect effect) { + super(effect); + } + + @Override + public MasterWarcraftChooseBlockersEffect copy() { + return new MasterWarcraftChooseBlockersEffect(this); + } + + @Override + public boolean apply(Game game, Ability source) { + return false; + } + + @Override + public boolean checksEventType(GameEvent event, Game game) { + return event.getType() == GameEvent.EventType.DECLARING_BLOCKERS; + } + + @Override + public boolean applies(GameEvent event, Ability source, Game game) { + ChooseBlockersRedundancyWatcher watcher = (ChooseBlockersRedundancyWatcher) game.getState().getWatchers().get(ChooseBlockersRedundancyWatcher.class.getSimpleName()); + watcher.decrement(); + if (watcher.copyCountApply > 0) { + game.informPlayers(source.getSourceObject(game).getIdName() + " didn't apply"); + return false; + } + watcher.copyCountApply = watcher.copyCount; + Player blockController = game.getPlayer(source.getControllerId()); + if (blockController != null) { + game.getCombat().selectBlockers(blockController, game); + return true; + } + return false; + } +} + +class MasterWarcraftCastWatcher extends Watcher { + + public int copyCount = 0; + public int copyCountApply = 0; + + public MasterWarcraftCastWatcher() { + super(MasterWarcraftCastWatcher.class.getSimpleName(), WatcherScope.GAME); + } + + public MasterWarcraftCastWatcher(final MasterWarcraftCastWatcher watcher) { + super(watcher); + this.copyCount = watcher.copyCount; + this.copyCountApply = watcher.copyCountApply; + } + + @Override + public void reset() { + copyCount = 0; + copyCountApply = 0; + } + + @Override + public MasterWarcraftCastWatcher copy() { + return new MasterWarcraftCastWatcher(this); + } + + @Override + public void watch(GameEvent event, Game game) { + } + + public void increment() { + copyCount++; + copyCountApply = copyCount; + } + + public void decrement() { + if (copyCountApply > 0) { + copyCountApply--; + } + } +} diff --git a/Mage.Sets/src/mage/cards/m/Melee.java b/Mage.Sets/src/mage/cards/m/Melee.java new file mode 100644 index 0000000000..ac152d93f0 --- /dev/null +++ b/Mage.Sets/src/mage/cards/m/Melee.java @@ -0,0 +1,204 @@ +/* + * Copyright 2010 BetaSteward_at_googlemail.com. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are + * permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this list of + * conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, this list + * of conditions and the following disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY BetaSteward_at_googlemail.com ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BetaSteward_at_googlemail.com OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * The views and conclusions contained in the software and documentation are those of the + * authors and should not be interpreted as representing official policies, either expressed + * or implied, of BetaSteward_at_googlemail.com. + */ +package mage.cards.m; + +import java.util.UUID; +import mage.abilities.Ability; +import mage.abilities.DelayedTriggeredAbility; +import mage.abilities.common.CastOnlyDuringPhaseStepSourceAbility; +import mage.abilities.condition.CompoundCondition; +import mage.abilities.condition.Condition; +import mage.abilities.condition.common.BeforeBlockersAreDeclaredCondition; +import mage.abilities.condition.common.IsPhaseCondition; +import mage.abilities.condition.common.MyTurnCondition; +import mage.abilities.effects.ContinuousRuleModifyingEffectImpl; +import mage.abilities.effects.OneShotEffect; +import mage.abilities.effects.common.CreateDelayedTriggeredAbilityEffect; +import mage.abilities.effects.common.RemoveFromCombatTargetEffect; +import mage.abilities.effects.common.UntapTargetEffect; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.*; +import mage.game.Game; +import mage.game.combat.CombatGroup; +import mage.game.events.GameEvent; +import mage.game.events.GameEvent.EventType; +import mage.game.permanent.Permanent; +import mage.players.Player; +import mage.target.targetpointer.FixedTarget; +import mage.watchers.Watcher; +import mage.watchers.common.ChooseBlockersRedundancyWatcher; + +/** + * + * @author L_J + */ +public class Melee extends CardImpl { + + public Melee(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.INSTANT}, "{4}{R}"); + + // Cast Melee only during your turn and only during combat before blockers are declared. + Condition condition = new CompoundCondition(BeforeBlockersAreDeclaredCondition.instance, + new IsPhaseCondition(TurnPhase.COMBAT), + MyTurnCondition.instance); + this.addAbility(new CastOnlyDuringPhaseStepSourceAbility(null, null, condition, "Cast {this} only during your turn and only during combat before blockers are declared")); + + // You choose which creatures block this combat and how those creatures block. + // (only the last resolved Melee spell's blocking effect applies) + this.getSpellAbility().addEffect(new MeleeChooseBlockersEffect()); + this.getSpellAbility().addWatcher(new ChooseBlockersRedundancyWatcher()); + this.getSpellAbility().addEffect(new ChooseBlockersRedundancyWatcherIncrementEffect()); + + // Whenever a creature attacks and isn't blocked this combat, untap it and remove it from combat. + this.getSpellAbility().addEffect(new CreateDelayedTriggeredAbilityEffect(new MeleeTriggeredAbility())); + } + + public Melee(final Melee card) { + super(card); + } + + @Override + public Melee copy() { + return new Melee(this); + } + + private class ChooseBlockersRedundancyWatcherIncrementEffect extends OneShotEffect { + + ChooseBlockersRedundancyWatcherIncrementEffect() { + super(Outcome.Neutral); + } + + ChooseBlockersRedundancyWatcherIncrementEffect(final ChooseBlockersRedundancyWatcherIncrementEffect effect) { + super(effect); + } + + @Override + public boolean apply(Game game, Ability source) { + ChooseBlockersRedundancyWatcher watcher = (ChooseBlockersRedundancyWatcher) game.getState().getWatchers().get(ChooseBlockersRedundancyWatcher.class.getSimpleName()); + if (watcher != null) { + watcher.increment(); + return true; + } + return false; + } + + @Override + public ChooseBlockersRedundancyWatcherIncrementEffect copy() { + return new ChooseBlockersRedundancyWatcherIncrementEffect(this); + } + } +} + +class MeleeChooseBlockersEffect extends ContinuousRuleModifyingEffectImpl { + + public MeleeChooseBlockersEffect() { + super(Duration.EndOfCombat, Outcome.Benefit, false, false); + staticText = "You choose which creatures block this combat and how those creatures block"; + } + + public MeleeChooseBlockersEffect(final MeleeChooseBlockersEffect effect) { + super(effect); + } + + @Override + public MeleeChooseBlockersEffect copy() { + return new MeleeChooseBlockersEffect(this); + } + + @Override + public boolean apply(Game game, Ability source) { + return false; + } + + @Override + public boolean checksEventType(GameEvent event, Game game) { + return event.getType() == GameEvent.EventType.DECLARING_BLOCKERS; + } + + @Override + public boolean applies(GameEvent event, Ability source, Game game) { + ChooseBlockersRedundancyWatcher watcher = (ChooseBlockersRedundancyWatcher) game.getState().getWatchers().get(ChooseBlockersRedundancyWatcher.class.getSimpleName()); + watcher.decrement(); + watcher.copyCount--; + if (watcher.copyCountApply > 0) { + game.informPlayers(source.getSourceObject(game).getIdName() + " didn't apply"); + this.discard(); + return false; + } + watcher.copyCountApply = watcher.copyCount; + Player blockController = game.getPlayer(source.getControllerId()); + if (blockController != null) { + game.getCombat().selectBlockers(blockController, game); + return true; + } + this.discard(); + return false; + } +} + +class MeleeTriggeredAbility extends DelayedTriggeredAbility { + + public MeleeTriggeredAbility() { + super(new UntapTargetEffect(), Duration.EndOfCombat, false); + this.addEffect(new RemoveFromCombatTargetEffect()); + } + + public MeleeTriggeredAbility(MeleeTriggeredAbility ability) { + super(ability); + } + + @Override + public boolean checkEventType(GameEvent event, Game game) { + return event.getType() == GameEvent.EventType.UNBLOCKED_ATTACKER; + } + + @Override + public boolean checkTrigger(GameEvent event, Game game) { + Permanent permanent = game.getPermanent(event.getTargetId()); + if (permanent != null) { + for (CombatGroup combatGroup : game.getCombat().getGroups()) { + if (combatGroup.getBlockers().isEmpty() && combatGroup.getAttackers().contains(event.getTargetId())) { + this.getEffects().setTargetPointer(new FixedTarget(permanent, game)); + return true; + } + } + } + return false; + } + + @Override + public MeleeTriggeredAbility copy() { + return new MeleeTriggeredAbility(this); + } + + @Override + public String getRule() { + return "Whenever a creature attacks and isn't blocked this combat, untap it and remove it from combat."; + } +} diff --git a/Mage.Sets/src/mage/cards/m/Melting.java b/Mage.Sets/src/mage/cards/m/Melting.java new file mode 100644 index 0000000000..c10d6610fa --- /dev/null +++ b/Mage.Sets/src/mage/cards/m/Melting.java @@ -0,0 +1,100 @@ +/* + * Copyright 2010 BetaSteward_at_googlemail.com. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are + * permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this list of + * conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, this list + * of conditions and the following disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY BetaSteward_at_googlemail.com ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BetaSteward_at_googlemail.com OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * The views and conclusions contained in the software and documentation are those of the + * authors and should not be interpreted as representing official policies, either expressed + * or implied, of BetaSteward_at_googlemail.com. + */ +package mage.cards.m; + +import java.util.UUID; +import mage.abilities.Ability; +import mage.abilities.Mode; +import mage.abilities.common.SimpleStaticAbility; +import mage.abilities.effects.ContinuousEffectImpl; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.Duration; +import mage.constants.Layer; +import mage.constants.Outcome; +import mage.constants.SubLayer; +import mage.constants.SuperType; +import mage.constants.Zone; +import mage.filter.common.FilterLandPermanent; +import mage.game.Game; +import mage.game.permanent.Permanent; + +/** + * + * @author TheElk801 + */ +public class Melting extends CardImpl { + + public Melting(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.ENCHANTMENT}, "{3}{R}"); + + // All lands are no longer snow. + this.addAbility(new SimpleStaticAbility(Zone.BATTLEFIELD, new MeltingEffect())); + } + + public Melting(final Melting card) { + super(card); + } + + @Override + public Melting copy() { + return new Melting(this); + } +} + +class MeltingEffect extends ContinuousEffectImpl { + + private static final FilterLandPermanent filter = new FilterLandPermanent(); + + public MeltingEffect() { + super(Duration.WhileOnBattlefield, Layer.TypeChangingEffects_4, SubLayer.NA, Outcome.Detriment); + } + + public MeltingEffect(final MeltingEffect effect) { + super(effect); + } + + @Override + public MeltingEffect copy() { + return new MeltingEffect(this); + } + + @Override + public boolean apply(Game game, Ability source) { + for (Permanent permanent : game.getBattlefield().getActivePermanents(filter, source.getControllerId(), source.getSourceId(), game)) { + permanent.getSuperType().remove(SuperType.SNOW); + } + return true; + } + + @Override + public String getText(Mode mode) { + return "All lands are no longer snow"; + } +} diff --git a/Mage.Sets/src/mage/cards/m/Misinformation.java b/Mage.Sets/src/mage/cards/m/Misinformation.java new file mode 100644 index 0000000000..b146b7d17d --- /dev/null +++ b/Mage.Sets/src/mage/cards/m/Misinformation.java @@ -0,0 +1,95 @@ +/* + * Copyright 2010 BetaSteward_at_googlemail.com. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are + * permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this list of + * conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, this list + * of conditions and the following disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY BetaSteward_at_googlemail.com ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BetaSteward_at_googlemail.com OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * The views and conclusions contained in the software and documentation are those of the + * authors and should not be interpreted as representing official policies, either expressed + * or implied, of BetaSteward_at_googlemail.com. + */ +package mage.cards.m; + +import java.util.List; +import java.util.UUID; +import mage.abilities.Ability; +import mage.abilities.effects.OneShotEffect; +import mage.cards.*; +import mage.constants.CardType; +import mage.constants.Outcome; +import mage.filter.FilterCard; +import mage.game.Game; +import mage.players.Player; +import mage.target.common.TargetCardInOpponentsGraveyard; + +/** + * + * @author L_J + */ +public class Misinformation extends CardImpl { + + public Misinformation(UUID ownerId, CardSetInfo setInfo) { + super(ownerId,setInfo,new CardType[]{CardType.INSTANT},"{B}"); + + // Put up to three target cards from an opponent's graveyard on top of his or her library in any order. + this.getSpellAbility().addTarget(new TargetCardInOpponentsGraveyard(0, 3, new FilterCard("cards from an opponent's graveyard"), true)); + this.getSpellAbility().addEffect(new MisinformationEffect()); + } + + public Misinformation(final Misinformation card) { + super(card); + } + + @Override + public Misinformation copy() { + return new Misinformation(this); + } +} + +class MisinformationEffect extends OneShotEffect { + + MisinformationEffect() { + super(Outcome.Detriment); + this.staticText = "Put up to three target cards from an opponent's graveyard on top of his or her library in any order"; + } + + MisinformationEffect(final MisinformationEffect effect) { + super(effect); + } + + @Override + public MisinformationEffect copy() { + return new MisinformationEffect(this); + } + + @Override + public boolean apply(Game game, Ability source) { + Player controller = game.getPlayer(source.getControllerId()); + if (controller != null) { + List targets = this.getTargetPointer().getTargets(game, source); + if (targets != null) { + Cards cards = new CardsImpl(targets); + controller.putCardsOnTopOfLibrary(cards, game, source, true); + return true; + } + } + return false; + } +} diff --git a/Mage.Sets/src/mage/cards/m/MistOfStagnation.java b/Mage.Sets/src/mage/cards/m/MistOfStagnation.java index 5d821a7cda..9cfe18d56c 100644 --- a/Mage.Sets/src/mage/cards/m/MistOfStagnation.java +++ b/Mage.Sets/src/mage/cards/m/MistOfStagnation.java @@ -27,8 +27,6 @@ */ package mage.cards.m; -import java.util.HashSet; -import java.util.Set; import java.util.UUID; import mage.abilities.Ability; import mage.abilities.common.BeginningOfUpkeepTriggeredAbility; @@ -96,23 +94,16 @@ class MistOfStagnationEffect extends OneShotEffect { if (activePlayer != null) { int cardsInGrave = activePlayer.getGraveyard().size(); if (cardsInGrave > 0) { - Set targets = new HashSet<>(); - for (int i = 1; 1 <= cardsInGrave; i++) { - TargetPermanent target = new TargetPermanent(1, 1, new FilterPermanent(), true); - target.setTargetController(activePlayer.getId()); - target.setTargetController(activePlayer.getId()); - if (target.canChoose(source.getSourceId(), activePlayer.getId(), game) && activePlayer.chooseTarget(Outcome.Untap, target, source, game)) { - targets.add(target); - } - } - for (TargetPermanent target : targets) { - Permanent p = game.getPermanent(target.getFirstTarget()); + TargetPermanent target = new TargetPermanent(cardsInGrave, cardsInGrave, new FilterPermanent("permanents to untap"), true); + activePlayer.chooseTarget(outcome, target, source, game); + for (UUID oneTarget : target.getTargets()) { + Permanent p = game.getPermanent(oneTarget); if (p != null) { p.untap(game); } } - return true; } + return true; } return false; } diff --git a/Mage.Sets/src/mage/cards/m/MoggAssassin.java b/Mage.Sets/src/mage/cards/m/MoggAssassin.java new file mode 100644 index 0000000000..18cfb3c453 --- /dev/null +++ b/Mage.Sets/src/mage/cards/m/MoggAssassin.java @@ -0,0 +1,148 @@ +/* + * Copyright 2010 BetaSteward_at_googlemail.com. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are + * permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this list of + * conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, this list + * of conditions and the following disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY BetaSteward_at_googlemail.com ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BetaSteward_at_googlemail.com OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * The views and conclusions contained in the software and documentation are those of the + * authors and should not be interpreted as representing official policies, either expressed + * or implied, of BetaSteward_at_googlemail.com. + */ + +package mage.cards.m; + +import java.util.UUID; +import mage.MageInt; +import mage.abilities.Ability; +import mage.abilities.common.SimpleActivatedAbility; +import mage.abilities.costs.common.TapSourceCost; +import mage.abilities.effects.OneShotEffect; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.SubType; +import mage.constants.Outcome; +import mage.constants.Zone; +import mage.game.Game; +import mage.game.permanent.Permanent; +import mage.players.Player; +import mage.target.Target; +import mage.target.common.TargetCreaturePermanent; +import mage.target.common.TargetOpponentsCreaturePermanent; + +/** + * + * @author L_J + */ +public class MoggAssassin extends CardImpl { + + private final UUID originalId; + + public MoggAssassin(UUID ownerId, CardSetInfo setInfo) { + super(ownerId,setInfo,new CardType[]{CardType.CREATURE},"{2}{R}"); + this.subtype.add(SubType.GOBLIN); + this.subtype.add(SubType.ASSASSIN); + this.power = new MageInt(2); + this.toughness = new MageInt(1); + + //TODO: Make ability properly copiable + // {T}: You choose target creature an opponent controls, and that opponent chooses target creature. Flip a coin. If you win the flip, destroy the creature you chose. If you lose the flip, destroy the creature your opponent chose. + Ability ability = new SimpleActivatedAbility(Zone.BATTLEFIELD, new MoggAssassinEffect(), new TapSourceCost()); + ability.addTarget(new TargetOpponentsCreaturePermanent()); + ability.addTarget(new TargetCreaturePermanent()); + this.addAbility(ability); + originalId = ability.getOriginalId(); + } + + @Override + public void adjustTargets(Ability ability, Game game) { + if (ability.getOriginalId().equals(originalId)) { + Player controller = game.getPlayer(ability.getControllerId()); + if (controller != null) { + UUID opponentId = null; + if (game.getOpponents(controller.getId()).size() > 1) { + Target target = ability.getTargets().get(0); + if (controller.chooseTarget(Outcome.DestroyPermanent, target, ability, game)) { + Permanent permanent = game.getPermanent(target.getFirstTarget()); + opponentId = permanent.getControllerId(); + } else { + opponentId = game.getOpponents(controller.getId()).iterator().next(); + } + } else { + opponentId = game.getOpponents(controller.getId()).iterator().next(); + } + + if (opponentId != null) { + ability.getTargets().get(1).setTargetController(opponentId); + } + } + } + } + + public MoggAssassin(final MoggAssassin card) { + super(card); + this.originalId = card.originalId; + } + + @Override + public MoggAssassin copy() { + return new MoggAssassin(this); + } + +} + +class MoggAssassinEffect extends OneShotEffect { + + public MoggAssassinEffect() { + super(Outcome.DestroyPermanent); + this.staticText = "You choose target creature an opponent controls, and that opponent chooses target creature. Flip a coin. If you win the flip, destroy the creature you chose. If you lose the flip, destroy the creature your opponent chose"; + } + + public MoggAssassinEffect(final MoggAssassinEffect effect) { + super(effect); + } + + @Override + public MoggAssassinEffect copy() { + return new MoggAssassinEffect(this); + } + + @Override + public boolean apply(Game game, Ability source) { + Permanent sourcePermanent = game.getPermanentOrLKIBattlefield(source.getSourceId()); + Player controller = game.getPlayer(source.getControllerId()); + if (controller != null) { + Permanent chosenPermanent = game.getPermanent(source.getTargets().get(0).getFirstTarget()); + Permanent opponentsPermanent = game.getPermanent(source.getTargets().get(1).getFirstTarget()); + if (controller.flipCoin(game)) { + if (chosenPermanent != null) { + chosenPermanent.destroy(source.getSourceId(), game, false); + return true; + } + } else { + if (opponentsPermanent != null) { + opponentsPermanent.destroy(source.getSourceId(), game, false); + return true; + } + } + } + return false; + } +} diff --git a/Mage.Sets/src/mage/cards/m/Momentum.java b/Mage.Sets/src/mage/cards/m/Momentum.java new file mode 100644 index 0000000000..4d54ffdf88 --- /dev/null +++ b/Mage.Sets/src/mage/cards/m/Momentum.java @@ -0,0 +1,83 @@ +/* + * Copyright 2010 BetaSteward_at_googlemail.com. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are + * permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this list of + * conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, this list + * of conditions and the following disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY BetaSteward_at_googlemail.com ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BetaSteward_at_googlemail.com OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * The views and conclusions contained in the software and documentation are those of the + * authors and should not be interpreted as representing official policies, either expressed + * or implied, of BetaSteward_at_googlemail.com. + */ +package mage.cards.m; + +import java.util.UUID; +import mage.constants.SubType; +import mage.target.common.TargetCreaturePermanent; +import mage.abilities.Ability; +import mage.abilities.common.BeginningOfUpkeepTriggeredAbility; +import mage.abilities.common.SimpleStaticAbility; +import mage.abilities.dynamicvalue.common.CountersSourceCount; +import mage.abilities.effects.common.AttachEffect; +import mage.abilities.effects.common.continuous.BoostEnchantedEffect; +import mage.abilities.effects.common.counter.AddCountersSourceEffect; +import mage.constants.Outcome; +import mage.target.TargetPermanent; +import mage.abilities.keyword.EnchantAbility; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.TargetController; +import mage.constants.Zone; +import mage.counters.CounterType; + +/** + * + * @author TheElk801 + */ +public class Momentum extends CardImpl { + + public Momentum(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.ENCHANTMENT}, "{2}{G}"); + + this.subtype.add(SubType.AURA); + + // Enchant creature + TargetPermanent auraTarget = new TargetCreaturePermanent(); + this.getSpellAbility().addTarget(auraTarget); + this.getSpellAbility().addEffect(new AttachEffect(Outcome.BoostCreature)); + Ability ability = new EnchantAbility(auraTarget.getTargetName()); + this.addAbility(ability); + + // At the beginning of your upkeep, you may put a growth counter on Momentum. + this.addAbility(new BeginningOfUpkeepTriggeredAbility(new AddCountersSourceEffect(CounterType.GROWTH.createInstance(), true), TargetController.YOU, true)); + + // Enchanted creature gets +1/+1 for each growth counter on Momentum. + this.addAbility(new SimpleStaticAbility(Zone.BATTLEFIELD, new BoostEnchantedEffect(new CountersSourceCount(CounterType.GROWTH), new CountersSourceCount(CounterType.GROWTH)))); + } + + public Momentum(final Momentum card) { + super(card); + } + + @Override + public Momentum copy() { + return new Momentum(this); + } +} diff --git a/Mage.Sets/src/mage/cards/m/MuragandaPetroglyphs.java b/Mage.Sets/src/mage/cards/m/MuragandaPetroglyphs.java index 9721414ce6..8a9471676d 100644 --- a/Mage.Sets/src/mage/cards/m/MuragandaPetroglyphs.java +++ b/Mage.Sets/src/mage/cards/m/MuragandaPetroglyphs.java @@ -35,6 +35,7 @@ import mage.abilities.Ability; import mage.abilities.SpellAbility; import mage.abilities.common.SimpleStaticAbility; import mage.abilities.effects.common.continuous.BoostAllEffect; +import mage.abilities.keyword.special.JohanVigilanceAbility; import mage.cards.Card; import mage.cards.CardImpl; import mage.cards.CardSetInfo; @@ -91,7 +92,7 @@ class NoAbilityPredicate implements Predicate { } if (isFaceDown) { for (Ability ability : abilities) { - if (!ability.getSourceId().equals(input.getId())) { + if (!ability.getSourceId().equals(input.getId()) && !ability.getClass().equals(JohanVigilanceAbility.class)) { return false; } } @@ -99,8 +100,7 @@ class NoAbilityPredicate implements Predicate { } for (Ability ability : abilities) { - if (!Objects.equals(ability.getClass(), SpellAbility.class)) { - + if (!Objects.equals(ability.getClass(), SpellAbility.class) && !ability.getClass().equals(JohanVigilanceAbility.class)) { return false; } } diff --git a/Mage.Sets/src/mage/cards/m/MyrPrototype.java b/Mage.Sets/src/mage/cards/m/MyrPrototype.java new file mode 100644 index 0000000000..0a451bb293 --- /dev/null +++ b/Mage.Sets/src/mage/cards/m/MyrPrototype.java @@ -0,0 +1,112 @@ +/* + * Copyright 2010 BetaSteward_at_googlemail.com. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are + * permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this list of + * conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, this list + * of conditions and the following disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY BetaSteward_at_googlemail.com ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BetaSteward_at_googlemail.com OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * The views and conclusions contained in the software and documentation are those of the + * authors and should not be interpreted as representing official policies, either expressed + * or implied, of BetaSteward_at_googlemail.com. + */ +package mage.cards.m; + +import java.util.UUID; +import mage.MageInt; +import mage.abilities.Ability; +import mage.abilities.common.BeginningOfUpkeepTriggeredAbility; +import mage.abilities.common.SimpleStaticAbility; +import mage.abilities.costs.mana.ManaCosts; +import mage.abilities.costs.mana.ManaCostsImpl; +import mage.abilities.effects.common.combat.CantAttackBlockUnlessPaysSourceEffect; +import mage.abilities.effects.common.counter.AddCountersSourceEffect; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.SubType; +import mage.constants.TargetController; +import mage.constants.Zone; +import mage.counters.CounterType; +import mage.game.Game; +import mage.game.events.GameEvent; +import mage.game.permanent.Permanent; + +/** + * + * @author emerald000 & L_J + */ +public class MyrPrototype extends CardImpl { + + public MyrPrototype(UUID ownerId, CardSetInfo setInfo) { + super(ownerId,setInfo,new CardType[]{CardType.ARTIFACT,CardType.CREATURE},"{5}"); + this.subtype.add(SubType.MYR); + this.power = new MageInt(2); + this.toughness = new MageInt(2); + + // At the beginning of your upkeep, put a +1/+1 counter on Myr Prototype. + this.addAbility(new BeginningOfUpkeepTriggeredAbility(new AddCountersSourceEffect(CounterType.P1P1.createInstance()), TargetController.YOU, false)); + + // Myr Prototype can't attack or block unless you pay {1} for each +1/+1 counter on it. + this.addAbility(new SimpleStaticAbility(Zone.BATTLEFIELD, new MyrPrototypeCantAttackUnlessYouPayEffect())); + } + + public MyrPrototype(final MyrPrototype card) { + super(card); + } + + @Override + public MyrPrototype copy() { + return new MyrPrototype(this); + } +} + +class MyrPrototypeCantAttackUnlessYouPayEffect extends CantAttackBlockUnlessPaysSourceEffect { + + MyrPrototypeCantAttackUnlessYouPayEffect() { + super(new ManaCostsImpl("{0}"), RestrictType.ATTACK_AND_BLOCK); + staticText = "{this} can't attack or block unless you pay {1} for each +1/+1 counter on it"; + } + + MyrPrototypeCantAttackUnlessYouPayEffect(MyrPrototypeCantAttackUnlessYouPayEffect effect) { + super(effect); + } + + @Override + public boolean applies(GameEvent event, Ability source, Game game) { + return source.getSourceId().equals(event.getSourceId()); + } + + @Override + public ManaCosts getManaCostToPay(GameEvent event, Ability source, Game game) { + Permanent sourceObject = game.getPermanent(source.getSourceId()); + if (sourceObject != null) { + int counter = sourceObject.getCounters(game).getCount(CounterType.P1P1); + if (counter > 0) { + return new ManaCostsImpl<>("{" + counter + '}'); + } + } + return null; + } + + @Override + public MyrPrototypeCantAttackUnlessYouPayEffect copy() { + return new MyrPrototypeCantAttackUnlessYouPayEffect(this); + } + +} diff --git a/Mage.Sets/src/mage/cards/n/NettlingImp.java b/Mage.Sets/src/mage/cards/n/NettlingImp.java index bc84103208..7e410528d8 100644 --- a/Mage.Sets/src/mage/cards/n/NettlingImp.java +++ b/Mage.Sets/src/mage/cards/n/NettlingImp.java @@ -30,13 +30,14 @@ package mage.cards.n; import java.util.UUID; import mage.MageInt; import mage.abilities.Ability; +import mage.abilities.common.delayed.AtTheBeginOfNextEndStepDelayedTriggeredAbility; import mage.abilities.condition.Condition; import mage.abilities.condition.InvertCondition; import mage.abilities.condition.common.TargetAttackedThisTurnCondition; import mage.abilities.costs.common.TapSourceCost; import mage.abilities.decorator.ConditionalActivatedAbility; -import mage.abilities.decorator.ConditionalOneShotEffect; -import mage.abilities.effects.common.DestroyTargetAtBeginningOfNextEndStepEffect; +import mage.abilities.effects.OneShotEffect; +import mage.abilities.effects.common.DestroyTargetEffect; import mage.abilities.effects.common.combat.AttacksIfAbleTargetEffect; import mage.cards.CardImpl; import mage.cards.CardSetInfo; @@ -49,6 +50,7 @@ import mage.filter.predicate.permanent.ControllerPredicate; import mage.game.Game; import mage.players.Player; import mage.target.common.TargetCreaturePermanent; +import mage.target.targetpointer.FixedTarget; import mage.watchers.common.AttackedThisTurnWatcher; /** @@ -56,30 +58,33 @@ import mage.watchers.common.AttackedThisTurnWatcher; * @author MTGfan */ public class NettlingImp extends CardImpl { - + final static FilterCreaturePermanent filter = new FilterCreaturePermanent("non-Wall"); static { filter.add(Predicates.not(new SubtypePredicate(SubType.WALL))); - filter.add(new ControlledFromStartOfControllerTurnPredicate()); + filter.add(new ControlledFromStartOfControllerTurnPredicate()); filter.add(new ControllerPredicate(TargetController.ACTIVE)); filter.setMessage("non-Wall creature the active player has controlled continuously since the beginning of the turn."); } - public NettlingImp(UUID ownerId, CardSetInfo setInfo) { super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{2}{B}"); - + this.subtype.add(SubType.IMP); this.power = new MageInt(1); this.toughness = new MageInt(1); - // {tap}: Choose target non-Wall creature the active player has controlled continuously since the beginning of the turn. That creature attacks this turn if able. If it doesn't, destroy it at the beginning of the next end step. Activate this ability only during an opponent's turn, before attackers are declared. - Ability ability = new ConditionalActivatedAbility(Zone.BATTLEFIELD, new AttacksIfAbleTargetEffect(Duration.EndOfTurn), new TapSourceCost(), new NettlingImpTurnCondition(), "{T}: Choose target non-Wall creature the active player has controlled continuously since the beginning of the turn. That creature attacks this turn if able. If it doesn't, destroy it at the beginning of the next end step. Activate this ability only during an opponent's turn, before attackers are declared."); - ability.addEffect(new ConditionalOneShotEffect(new DestroyTargetAtBeginningOfNextEndStepEffect(), new InvertCondition(TargetAttackedThisTurnCondition.instance))); + // {T}: Choose target non-Wall creature the active player has controlled continuously since the beginning of the turn. That creature attacks this turn if able. If it doesn't, destroy it at the beginning of the next end step. Activate this ability only during an opponent's turn, before attackers are declared. + Ability ability = new ConditionalActivatedAbility(Zone.BATTLEFIELD, new AttacksIfAbleTargetEffect(Duration.EndOfTurn), + new TapSourceCost(), new NettlingImpTurnCondition(), + "{T}: Choose target non-Wall creature the active player has controlled continuously since the beginning of the turn. " + + "That creature attacks this turn if able. If it doesn't, destroy it at the beginning of the next end step. " + + "Activate this ability only during an opponent's turn, before attackers are declared."); + ability.addEffect(new NettlingImpDelayedDestroyEffect()); ability.addTarget(new TargetCreaturePermanent(filter)); this.addAbility(ability, new AttackedThisTurnWatcher()); - + } public NettlingImp(final NettlingImp card) { @@ -96,7 +101,7 @@ class NettlingImpTurnCondition implements Condition { @Override public boolean apply(Game game, Ability source) { - Player activePlayer = game.getPlayer(game.getActivePlayerId()); + Player activePlayer = game.getPlayer(game.getActivePlayerId()); return activePlayer != null && activePlayer.hasOpponent(source.getControllerId(), game) && game.getPhase().getStep().getType().getIndex() < 5; } @@ -105,3 +110,32 @@ class NettlingImpTurnCondition implements Condition { return ""; } } + +class NettlingImpDelayedDestroyEffect extends OneShotEffect { + + public NettlingImpDelayedDestroyEffect() { + super(Outcome.Detriment); + this.staticText = "If it doesn't, destroy it at the beginning of the next end step"; + } + + public NettlingImpDelayedDestroyEffect(final NettlingImpDelayedDestroyEffect effect) { + super(effect); + } + + @Override + public NettlingImpDelayedDestroyEffect copy() { + return new NettlingImpDelayedDestroyEffect(this); + } + + @Override + public boolean apply(Game game, Ability source) { + DestroyTargetEffect effect = new DestroyTargetEffect(); + effect.setTargetPointer(new FixedTarget(source.getFirstTarget())); + AtTheBeginOfNextEndStepDelayedTriggeredAbility delayedAbility + = new AtTheBeginOfNextEndStepDelayedTriggeredAbility(Zone.ALL, effect, TargetController.ANY, new InvertCondition(TargetAttackedThisTurnCondition.instance)); + delayedAbility.getDuration(); + delayedAbility.getTargets().addAll(source.getTargets()); + game.addDelayedTriggeredAbility(delayedAbility, source); + return true; + } +} diff --git a/Mage.Sets/src/mage/cards/n/NissaGenesisMage.java b/Mage.Sets/src/mage/cards/n/NissaGenesisMage.java index f06bd347c3..9322cd16cb 100644 --- a/Mage.Sets/src/mage/cards/n/NissaGenesisMage.java +++ b/Mage.Sets/src/mage/cards/n/NissaGenesisMage.java @@ -42,8 +42,7 @@ import mage.constants.SubType; import mage.constants.SuperType; import mage.constants.Zone; import mage.filter.FilterCard; -import mage.filter.common.FilterCreaturePermanent; -import mage.filter.common.FilterLandPermanent; +import mage.filter.StaticFilters; import mage.filter.predicate.Predicates; import mage.filter.predicate.mageobject.CardTypePredicate; import mage.target.common.TargetCreaturePermanent; @@ -55,6 +54,15 @@ import mage.target.common.TargetLandPermanent; */ public class NissaGenesisMage extends CardImpl { + private static final FilterCard filter = new FilterCard("any number of creature and/or land cards"); + + static { + filter.add(Predicates.or( + new CardTypePredicate(CardType.CREATURE), + new CardTypePredicate(CardType.LAND) + )); + } + public NissaGenesisMage(UUID ownerId, CardSetInfo setInfo) { super(ownerId, setInfo, new CardType[]{CardType.PLANESWALKER}, "{5}{G}{G}"); this.addSuperType(SuperType.LEGENDARY); @@ -64,8 +72,8 @@ public class NissaGenesisMage extends CardImpl { //+2: Untap up to two target creatures and up to two target lands. Ability ability = new LoyaltyAbility(new UntapTargetEffect(false).setText("Untap up to two target creatures and up to two target lands"), +2); - ability.addTarget(new TargetCreaturePermanent(0, 2, new FilterCreaturePermanent("target creatures"), false)); - ability.addTarget(new TargetLandPermanent(0, 2, new FilterLandPermanent("target land"), false)); + ability.addTarget(new TargetCreaturePermanent(0, 2, StaticFilters.FILTER_PERMANENT_CREATURES, false)); + ability.addTarget(new TargetLandPermanent(0, 2, StaticFilters.FILTER_LANDS, false)); this.addAbility(ability); //-3: Target creature gets +5/+5 until end of turn. @@ -74,10 +82,8 @@ public class NissaGenesisMage extends CardImpl { this.addAbility(ability); //-10: Look at the top ten cards of your library. You may put any number of creature and/or land cards from among them onto the battlefield. Put the rest on the bottom of your library in a random order.); - FilterCard filter = new FilterCard("creature and/or land cards"); - filter.add(Predicates.or(new CardTypePredicate(CardType.CREATURE), new CardTypePredicate(CardType.LAND))); this.addAbility(new LoyaltyAbility( - new LookLibraryAndPickControllerEffect(10, 10, filter, false, false, Zone.BATTLEFIELD, true).setBackInRandomOrder(true), + new LookLibraryAndPickControllerEffect(10, 10, filter, false, true, Zone.BATTLEFIELD, false).setBackInRandomOrder(true), -10)); } diff --git a/Mage.Sets/src/mage/cards/n/Norritt.java b/Mage.Sets/src/mage/cards/n/Norritt.java new file mode 100644 index 0000000000..3d1b0efecf --- /dev/null +++ b/Mage.Sets/src/mage/cards/n/Norritt.java @@ -0,0 +1,141 @@ +/* + * Copyright 2010 BetaSteward_at_googlemail.com. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are + * permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this list of + * conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, this list + * of conditions and the following disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY BetaSteward_at_googlemail.com ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BetaSteward_at_googlemail.com OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * The views and conclusions contained in the software and documentation are those of the + * authors and should not be interpreted as representing official policies, either expressed + * or implied, of BetaSteward_at_googlemail.com. + */ +package mage.cards.n; + +import java.util.UUID; +import mage.MageInt; +import mage.ObjectColor; +import mage.abilities.Ability; +import mage.abilities.common.SimpleActivatedAbility; +import mage.abilities.common.delayed.AtTheBeginOfNextEndStepDelayedTriggeredAbility; +import mage.abilities.condition.InvertCondition; +import mage.abilities.condition.common.BeforeAttackersAreDeclaredCondition; +import mage.abilities.condition.common.TargetAttackedThisTurnCondition; +import mage.abilities.costs.common.TapSourceCost; +import mage.abilities.decorator.ConditionalActivatedAbility; +import mage.abilities.effects.OneShotEffect; +import mage.abilities.effects.common.DestroyTargetEffect; +import mage.abilities.effects.common.UntapTargetEffect; +import mage.abilities.effects.common.combat.AttacksIfAbleTargetEffect; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.*; +import mage.filter.common.FilterCreaturePermanent; +import mage.filter.predicate.Predicates; +import mage.filter.predicate.mageobject.ColorPredicate; +import mage.filter.predicate.mageobject.SubtypePredicate; +import mage.filter.predicate.permanent.ControlledFromStartOfControllerTurnPredicate; +import mage.filter.predicate.permanent.ControllerPredicate; +import mage.game.Game; +import mage.target.common.TargetCreaturePermanent; +import mage.target.targetpointer.FixedTarget; +import mage.watchers.common.AttackedThisTurnWatcher; + +/** + * + * @author MTGfan & L_J + */ +public class Norritt extends CardImpl { + + private static final FilterCreaturePermanent filterBlue = new FilterCreaturePermanent("blue creature"); + + static { + filterBlue.add(new ColorPredicate(ObjectColor.BLUE)); + } + + private static final FilterCreaturePermanent filterCreature = new FilterCreaturePermanent("non-Wall creature"); + + static { + filterCreature.add(Predicates.not(new SubtypePredicate(SubType.WALL))); + filterCreature.add(new ControlledFromStartOfControllerTurnPredicate()); + filterCreature.add(new ControllerPredicate(TargetController.ACTIVE)); + filterCreature.setMessage("non-Wall creature the active player has controlled continuously since the beginning of the turn."); + } + + public Norritt(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{3}{B}"); + + this.subtype.add(SubType.IMP); + this.power = new MageInt(1); + this.toughness = new MageInt(1); + + // {T}: Untap target blue creature. + Ability ability1 = new SimpleActivatedAbility(Zone.BATTLEFIELD, new UntapTargetEffect(), new TapSourceCost()); + ability1.addTarget(new TargetCreaturePermanent(filterBlue)); + this.addAbility(ability1); + + // {T}: Choose target non-Wall creature the active player has controlled continuously since the beginning of the turn. That creature attacks this turn if able. If it doesn't, destroy it at the beginning of the next end step. Activate this ability only before attackers are declared. + Ability ability2 = new ConditionalActivatedAbility(Zone.BATTLEFIELD, new AttacksIfAbleTargetEffect(Duration.EndOfTurn), + new TapSourceCost(), BeforeAttackersAreDeclaredCondition.instance, + "{T}: Choose target non-Wall creature the active player has controlled continuously since the beginning of the turn. " + + "That creature attacks this turn if able. If it doesn't, destroy it at the beginning of the next end step. " + + "Activate this ability only before attackers are declared."); + ability2.addEffect(new NorrittDelayedDestroyEffect()); + ability2.addTarget(new TargetCreaturePermanent(filterCreature)); + this.addAbility(ability2, new AttackedThisTurnWatcher()); + + } + + public Norritt(final Norritt card) { + super(card); + } + + @Override + public Norritt copy() { + return new Norritt(this); + } +} + +class NorrittDelayedDestroyEffect extends OneShotEffect { + + public NorrittDelayedDestroyEffect() { + super(Outcome.Detriment); + this.staticText = "If it doesn't, destroy it at the beginning of the next end step"; + } + + public NorrittDelayedDestroyEffect(final NorrittDelayedDestroyEffect effect) { + super(effect); + } + + @Override + public NorrittDelayedDestroyEffect copy() { + return new NorrittDelayedDestroyEffect(this); + } + + @Override + public boolean apply(Game game, Ability source) { + DestroyTargetEffect effect = new DestroyTargetEffect(); + effect.setTargetPointer(new FixedTarget(source.getFirstTarget())); + AtTheBeginOfNextEndStepDelayedTriggeredAbility delayedAbility + = new AtTheBeginOfNextEndStepDelayedTriggeredAbility(Zone.ALL, effect, TargetController.ANY, new InvertCondition(TargetAttackedThisTurnCondition.instance)); + delayedAbility.getDuration(); + delayedAbility.getTargets().addAll(source.getTargets()); + game.addDelayedTriggeredAbility(delayedAbility, source); + return true; + } +} diff --git a/Mage.Sets/src/mage/cards/n/NovaPentacle.java b/Mage.Sets/src/mage/cards/n/NovaPentacle.java new file mode 100644 index 0000000000..e6571a1a87 --- /dev/null +++ b/Mage.Sets/src/mage/cards/n/NovaPentacle.java @@ -0,0 +1,129 @@ +/* + * Copyright 2010 BetaSteward_at_googlemail.com. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are + * permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this list of + * conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, this list + * of conditions and the following disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY BetaSteward_at_googlemail.com ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BetaSteward_at_googlemail.com OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * The views and conclusions contained in the software and documentation are those of the + * authors and should not be interpreted as representing official policies, either expressed + * or implied, of BetaSteward_at_googlemail.com. + */ +package mage.cards.n; + +import java.util.UUID; +import mage.MageObject; +import mage.abilities.Ability; +import mage.abilities.common.SimpleActivatedAbility; +import mage.abilities.costs.common.TapSourceCost; +import mage.abilities.costs.mana.GenericManaCost; +import mage.abilities.effects.RedirectionEffect; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.Duration; +import mage.constants.Outcome; +import mage.constants.Zone; +import mage.filter.common.FilterCreaturePermanent; +import mage.game.Game; +import mage.game.events.GameEvent; +import mage.game.permanent.Permanent; +import mage.game.stack.Spell; +import mage.players.Player; +import mage.target.TargetSource; +import mage.target.common.TargetOpponentsChoicePermanent; + +/** + * + * @author L_J + */ +public class NovaPentacle extends CardImpl { + + public NovaPentacle(UUID ownerId, CardSetInfo setInfo) { + super(ownerId,setInfo,new CardType[]{CardType.ARTIFACT},"{4}"); + + // {3}, {tap}: The next time a source of your choice would deal damage to you this turn, that damage is dealt to target creature of an opponent's choice instead + Ability ability = new SimpleActivatedAbility(Zone.BATTLEFIELD, new NovaPentacleEffect(), new GenericManaCost(3)); + ability.addCost(new TapSourceCost()); + ability.addTarget(new TargetOpponentsChoicePermanent(1, 1, new FilterCreaturePermanent(), false, true)); + this.addAbility(ability); + } + + public NovaPentacle(final NovaPentacle card) { + super(card); + } + + @Override + public NovaPentacle copy() { + return new NovaPentacle(this); + } +} + +class NovaPentacleEffect extends RedirectionEffect { + + private final TargetSource damageSource; + + public NovaPentacleEffect() { + super(Duration.EndOfTurn, Integer.MAX_VALUE, true); + staticText = "The next time a source of your choice would deal damage to you this turn, that damage is dealt to target creature of an opponent's choice instead"; + this.damageSource = new TargetSource(); + } + + public NovaPentacleEffect(final NovaPentacleEffect effect) { + super(effect); + this.damageSource = effect.damageSource.copy(); + } + + @Override + public NovaPentacleEffect copy() { + return new NovaPentacleEffect(this); + } + + @Override + public void init(Ability source, Game game) { + this.damageSource.choose(Outcome.PreventDamage, source.getControllerId(), source.getSourceId(), game); + super.init(source, game); + } + + @Override + public boolean applies(GameEvent event, Ability source, Game game) { + // check source + MageObject object = game.getObject(event.getSourceId()); + if (object == null) { + game.informPlayers("Couldn't find source of damage"); + return false; + } + + if (!object.getId().equals(damageSource.getFirstTarget()) + && (!(object instanceof Spell) || !((Spell) object).getSourceId().equals(damageSource.getFirstTarget()))) { + return false; + } + this.redirectTarget = source.getTargets().get(0); + + // check player + Player player = game.getPlayer(event.getTargetId()); + if (player != null) { + if (player.getId().equals(source.getControllerId())) { + return true; + } + } + return false; + } + +} diff --git a/Mage.Sets/src/mage/cards/o/OdricMasterTactician.java b/Mage.Sets/src/mage/cards/o/OdricMasterTactician.java index ecdb3e6d79..69b5f7aa66 100644 --- a/Mage.Sets/src/mage/cards/o/OdricMasterTactician.java +++ b/Mage.Sets/src/mage/cards/o/OdricMasterTactician.java @@ -31,7 +31,8 @@ import java.util.UUID; import mage.MageInt; import mage.abilities.Ability; import mage.abilities.TriggeredAbilityImpl; -import mage.abilities.effects.ReplacementEffectImpl; +import mage.abilities.effects.ContinuousRuleModifyingEffectImpl; +import mage.abilities.effects.OneShotEffect; import mage.abilities.keyword.FirstStrikeAbility; import mage.cards.CardImpl; import mage.cards.CardSetInfo; @@ -40,6 +41,7 @@ import mage.game.Game; import mage.game.events.GameEvent; import mage.game.events.GameEvent.EventType; import mage.players.Player; +import mage.watchers.common.ChooseBlockersRedundancyWatcher; /** * @author noxx @@ -75,7 +77,9 @@ public class OdricMasterTactician extends CardImpl { class OdricMasterTacticianTriggeredAbility extends TriggeredAbilityImpl { public OdricMasterTacticianTriggeredAbility() { - super(Zone.BATTLEFIELD, new OdricMasterTacticianEffect()); + super(Zone.BATTLEFIELD, new OdricMasterTacticianChooseBlockersEffect()); + this.addWatcher(new ChooseBlockersRedundancyWatcher()); + this.addEffect(new ChooseBlockersRedundancyWatcherIncrementEffect()); } public OdricMasterTacticianTriggeredAbility(final OdricMasterTacticianTriggeredAbility ability) { @@ -89,52 +93,55 @@ class OdricMasterTacticianTriggeredAbility extends TriggeredAbilityImpl { @Override public boolean checkEventType(GameEvent event, Game game) { - return event.getType() == EventType.DECLARED_ATTACKERS; + return event.getType() == GameEvent.EventType.DECLARED_ATTACKERS; } @Override public boolean checkTrigger(GameEvent event, Game game) { - resetEffect(); - if (game.getCombat().getAttackers().size() >= 4 && game.getCombat().getAttackers().contains(this.sourceId)) { - enableEffect(); - return true; + return game.getCombat().getAttackers().size() >= 4 && game.getCombat().getAttackers().contains(this.sourceId); + } + + private class ChooseBlockersRedundancyWatcherIncrementEffect extends OneShotEffect { + + ChooseBlockersRedundancyWatcherIncrementEffect() { + super(Outcome.Neutral); + } + + ChooseBlockersRedundancyWatcherIncrementEffect(final ChooseBlockersRedundancyWatcherIncrementEffect effect) { + super(effect); + } + + @Override + public boolean apply(Game game, Ability source) { + ChooseBlockersRedundancyWatcher watcher = (ChooseBlockersRedundancyWatcher) game.getState().getWatchers().get(ChooseBlockersRedundancyWatcher.class.getSimpleName()); + if (watcher != null) { + watcher.increment(); + return true; + } + return false; + } + + @Override + public ChooseBlockersRedundancyWatcherIncrementEffect copy() { + return new ChooseBlockersRedundancyWatcherIncrementEffect(this); } - return false; } - - @Override - public void reset(Game game) { - resetEffect(); - } - - private void resetEffect() { - getEffects().get(0).setValue("apply_" + sourceId, false); - } - - private void enableEffect() { - getEffects().get(0).setValue("apply_" + sourceId, true); - } - - @Override - public String getRule() { - return "Whenever {this} and at least three other creatures attack, you choose which creatures block this combat and how those creatures block."; - } - } -class OdricMasterTacticianEffect extends ReplacementEffectImpl { +class OdricMasterTacticianChooseBlockersEffect extends ContinuousRuleModifyingEffectImpl { - public OdricMasterTacticianEffect() { - super(Duration.EndOfCombat, Outcome.Benefit); + public OdricMasterTacticianChooseBlockersEffect() { + super(Duration.EndOfCombat, Outcome.Benefit, false, false); + staticText = "Whenever {this} and at least three other creatures attack, you choose which creatures block this combat and how those creatures block"; } - public OdricMasterTacticianEffect(final OdricMasterTacticianEffect effect) { + public OdricMasterTacticianChooseBlockersEffect(final OdricMasterTacticianChooseBlockersEffect effect) { super(effect); } @Override - public OdricMasterTacticianEffect copy() { - return new OdricMasterTacticianEffect(this); + public OdricMasterTacticianChooseBlockersEffect copy() { + return new OdricMasterTacticianChooseBlockersEffect(this); } @Override @@ -142,16 +149,6 @@ class OdricMasterTacticianEffect extends ReplacementEffectImpl { return false; } - @Override - public boolean replaceEvent(GameEvent event, Ability source, Game game) { - Player blockController = game.getPlayer(source.getControllerId()); - if (blockController != null) { - game.getCombat().selectBlockers(blockController, game); - return true; - } - return false; - } - @Override public boolean checksEventType(GameEvent event, Game game) { return event.getType() == GameEvent.EventType.DECLARING_BLOCKERS; @@ -159,12 +156,21 @@ class OdricMasterTacticianEffect extends ReplacementEffectImpl { @Override public boolean applies(GameEvent event, Ability source, Game game) { - Object object = getValue("apply_" + source.getSourceId()); - if (object != null && object instanceof Boolean) { - if ((Boolean)object) { - return true; // replace event - } + ChooseBlockersRedundancyWatcher watcher = (ChooseBlockersRedundancyWatcher) game.getState().getWatchers().get(ChooseBlockersRedundancyWatcher.class.getSimpleName()); + watcher.decrement(); + watcher.copyCount--; + if (watcher.copyCountApply > 0) { + game.informPlayers(source.getSourceObject(game).getIdName() + " didn't apply"); + this.discard(); + return false; } + watcher.copyCountApply = watcher.copyCount; + Player blockController = game.getPlayer(source.getControllerId()); + if (blockController != null) { + game.getCombat().selectBlockers(blockController, game); + return true; + } + this.discard(); return false; } } diff --git a/Mage.Sets/src/mage/cards/o/OpalEyeKondasYojimbo.java b/Mage.Sets/src/mage/cards/o/OpalEyeKondasYojimbo.java index 23b9527c5f..971e38c0d8 100644 --- a/Mage.Sets/src/mage/cards/o/OpalEyeKondasYojimbo.java +++ b/Mage.Sets/src/mage/cards/o/OpalEyeKondasYojimbo.java @@ -69,9 +69,7 @@ public class OpalEyeKondasYojimbo extends CardImpl { this.addAbility(new BushidoAbility(1)); // {T}: The next time a source of your choice would deal damage this turn, that damage is dealt to Opal-Eye, Konda's Yojimbo instead. - Ability ability = new SimpleActivatedAbility(Zone.BATTLEFIELD, new OpalEyeKondasYojimboRedirectionEffect(), new TapSourceCost()); - ability.addTarget(new TargetSource()); - this.addAbility(ability); + this.addAbility(new SimpleActivatedAbility(Zone.BATTLEFIELD, new OpalEyeKondasYojimboRedirectionEffect(), new TapSourceCost())); // {1}{W}: Prevent the next 1 damage that would be dealt to Opal-Eye this turn. this.addAbility(new SimpleActivatedAbility(Zone.BATTLEFIELD, new PreventDamageToSourceEffect(Duration.EndOfTurn, 1), new ManaCostsImpl("{1}{W}"))); diff --git a/Mage.Sets/src/mage/cards/p/PaleWayfarer.java b/Mage.Sets/src/mage/cards/p/PaleWayfarer.java index ea50659cbf..39227fe6a7 100644 --- a/Mage.Sets/src/mage/cards/p/PaleWayfarer.java +++ b/Mage.Sets/src/mage/cards/p/PaleWayfarer.java @@ -29,27 +29,36 @@ package mage.cards.p; import java.util.UUID; import mage.MageInt; +import mage.ObjectColor; import mage.abilities.Ability; import mage.abilities.common.SimpleActivatedAbility; import mage.abilities.costs.common.UntapSourceCost; import mage.abilities.costs.mana.ManaCostsImpl; +import mage.abilities.effects.ContinuousEffect; +import mage.abilities.effects.ContinuousEffectImpl; import mage.abilities.effects.OneShotEffect; +import mage.abilities.keyword.ProtectionAbility; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.choices.ChoiceColor; import mage.constants.CardType; import mage.constants.SubType; +import mage.constants.Duration; +import mage.constants.Layer; import mage.constants.Outcome; +import mage.constants.SubLayer; import mage.constants.Zone; +import mage.filter.FilterObject; +import mage.filter.predicate.mageobject.ColorPredicate; import mage.game.Game; import mage.game.permanent.Permanent; import mage.players.Player; import mage.target.common.TargetCreaturePermanent; +import mage.target.targetpointer.FixedTarget; /** * - * @author jeffwadsworth - * + * @author jeffwadsworth & L_J */ public class PaleWayfarer extends CardImpl { @@ -92,7 +101,7 @@ class PaleWayfarerEffect extends OneShotEffect { @Override public boolean apply(Game game, Ability source) { - Permanent targetCreature = game.getPermanent(source.getFirstTarget()); + Permanent targetCreature = game.getPermanent(getTargetPointer().getFirst(game, source)); if (targetCreature != null) { Player player = game.getPlayer(targetCreature.getControllerId()); if (player != null) { @@ -100,7 +109,15 @@ class PaleWayfarerEffect extends OneShotEffect { if (player.choose(Outcome.Neutral, colorChoice, game)) { game.informPlayers(targetCreature.getName() + ": " + player.getLogName() + " has chosen " + colorChoice.getChoice()); game.getState().setValue(targetCreature.getId() + "_color", colorChoice.getColor()); + + ObjectColor protectColor = (ObjectColor) game.getState().getValue(targetCreature.getId() + "_color"); + if (protectColor != null) { + ContinuousEffect effect = new ProtectionChosenColorTargetEffect(); + effect.setTargetPointer(new FixedTarget(targetCreature, game)); + game.addEffect(effect, source); + } } + return true; } } return false; @@ -110,4 +127,49 @@ class PaleWayfarerEffect extends OneShotEffect { public PaleWayfarerEffect copy() { return new PaleWayfarerEffect(this); } -} \ No newline at end of file +} + + +class ProtectionChosenColorTargetEffect extends ContinuousEffectImpl { + + protected ObjectColor chosenColor; + protected ProtectionAbility protectionAbility; + + public ProtectionChosenColorTargetEffect() { + super(Duration.EndOfTurn, Layer.AbilityAddingRemovingEffects_6, SubLayer.NA, Outcome.AddAbility); + } + + public ProtectionChosenColorTargetEffect(final ProtectionChosenColorTargetEffect effect) { + super(effect); + if (effect.chosenColor != null) { + this.chosenColor = effect.chosenColor.copy(); + } + if (effect.protectionAbility != null) { + this.protectionAbility = effect.protectionAbility.copy(); + } + } + + @Override + public ProtectionChosenColorTargetEffect copy() { + return new ProtectionChosenColorTargetEffect(this); + } + + @Override + public boolean apply(Game game, Ability source) { + Permanent permanent = game.getPermanent(getTargetPointer().getFirst(game, source)); + if (permanent != null) { + ObjectColor color = (ObjectColor) game.getState().getValue(permanent.getId() + "_color"); + if (color != null && (protectionAbility == null || !color.equals(chosenColor))) { + chosenColor = color; + FilterObject protectionFilter = new FilterObject(chosenColor.getDescription()); + protectionFilter.add(new ColorPredicate(chosenColor)); + protectionAbility = new ProtectionAbility(protectionFilter); + } + if (protectionAbility != null) { + permanent.addAbility(protectionAbility, source.getSourceId(), game); + return true; + } + } + return false; + } +} diff --git a/Mage.Sets/src/mage/cards/p/PedanticLearning.java b/Mage.Sets/src/mage/cards/p/PedanticLearning.java new file mode 100644 index 0000000000..89001b48bd --- /dev/null +++ b/Mage.Sets/src/mage/cards/p/PedanticLearning.java @@ -0,0 +1,111 @@ +/* + * Copyright 2010 BetaSteward_at_googlemail.com. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are + * permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this list of + * conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, this list + * of conditions and the following disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY BetaSteward_at_googlemail.com ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BetaSteward_at_googlemail.com OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * The views and conclusions contained in the software and documentation are those of the + * authors and should not be interpreted as representing official policies, either expressed + * or implied, of BetaSteward_at_googlemail.com. + */ +package mage.cards.p; + +import java.util.Set; +import java.util.UUID; +import mage.abilities.TriggeredAbilityImpl; +import mage.abilities.costs.mana.ManaCostsImpl; +import mage.abilities.effects.common.DoIfCostPaid; +import mage.abilities.effects.common.DrawCardSourceControllerEffect; +import mage.cards.Card; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.Zone; +import mage.game.Game; +import mage.game.events.GameEvent; +import mage.game.events.ZoneChangeEvent; + +/** + * + * @author LevelX2 & L_J + */ +public class PedanticLearning extends CardImpl { + + public PedanticLearning(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.ENCHANTMENT}, "{U}{U}"); + + // Whenever a land card is put into your graveyard from your library, you may pay {1}. If you do, draw a card. + this.addAbility(new PedanticLearningTriggeredAbility()); + } + + public PedanticLearning(final PedanticLearning card) { + super(card); + } + + @Override + public PedanticLearning copy() { + return new PedanticLearning(this); + } +} + +class PedanticLearningTriggeredAbility extends TriggeredAbilityImpl { + + public PedanticLearningTriggeredAbility() { + super(Zone.BATTLEFIELD, new DoIfCostPaid(new DrawCardSourceControllerEffect(1), new ManaCostsImpl("{1}")), false); + } + + public PedanticLearningTriggeredAbility(final PedanticLearningTriggeredAbility ability) { + super(ability); + } + + @Override + public boolean checkEventType(GameEvent event, Game game) { + return event.getType() == GameEvent.EventType.ZONE_CHANGE; + } + + @Override + public boolean checkTrigger(GameEvent event, Game game) { + ZoneChangeEvent zEvent = (ZoneChangeEvent) event; + if (zEvent != null && zEvent.getFromZone() == Zone.LIBRARY && zEvent.getToZone() == Zone.GRAVEYARD) { + Card card = game.getCard(event.getTargetId()); + if (card != null) { + UUID cardOwnerId = card.getOwnerId(); + Set cardType = card.getCardType(); + if (cardOwnerId != null + && card.getOwnerId().equals(getControllerId()) + && cardType != null + && card.isLand()) { + return true; + } + } + } + return false; + } + + @Override + public PedanticLearningTriggeredAbility copy() { + return new PedanticLearningTriggeredAbility(this); + } + + @Override + public String getRule() { + return "Whenever a land card is put into your graveyard from your library, you may pay {1}. If you do, draw a card."; + } +} diff --git a/Mage.Sets/src/mage/cards/p/PetraSphinx.java b/Mage.Sets/src/mage/cards/p/PetraSphinx.java new file mode 100644 index 0000000000..a1292fd7d0 --- /dev/null +++ b/Mage.Sets/src/mage/cards/p/PetraSphinx.java @@ -0,0 +1,130 @@ +/* + * Copyright 2010 BetaSteward_at_googlemail.com. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are + * permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this list of + * conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, this list + * of conditions and the following disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY BetaSteward_at_googlemail.com ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BetaSteward_at_googlemail.com OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * The views and conclusions contained in the software and documentation are those of the + * authors and should not be interpreted as representing official policies, either expressed + * or implied, of BetaSteward_at_googlemail.com. + */ +package mage.cards.p; + +import java.util.UUID; +import mage.MageInt; +import mage.MageObject; +import mage.abilities.Ability; +import mage.abilities.common.SimpleActivatedAbility; +import mage.abilities.costs.common.TapSourceCost; +import mage.abilities.effects.OneShotEffect; +import mage.cards.*; +import mage.cards.repository.CardRepository; +import mage.choices.Choice; +import mage.choices.ChoiceImpl; +import mage.constants.CardType; +import mage.constants.Outcome; +import mage.constants.SubType; +import mage.constants.Zone; +import mage.game.Game; +import mage.players.Player; +import mage.target.TargetPlayer; + +/** + * + * @author BetaSteward_at_googlemail.com & L_J + */ +public class PetraSphinx extends CardImpl { + + public PetraSphinx(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{2}{W}{W}{W}"); + this.subtype.add(SubType.SPHINX); + + this.power = new MageInt(3); + this.toughness = new MageInt(4); + + // {tap}: Target player chooses a card name, then reveals the top card of his or her library. If that card has the chosen name, that player puts it into his or her hand. If it doesn't, the player puts it into his or her graveyard. + Ability ability = new SimpleActivatedAbility(Zone.BATTLEFIELD, new PetraSphinxEffect(), new TapSourceCost()); + ability.addTarget(new TargetPlayer()); + this.addAbility(ability); + } + + public PetraSphinx(final PetraSphinx card) { + super(card); + } + + @Override + public PetraSphinx copy() { + return new PetraSphinx(this); + } + +} + +class PetraSphinxEffect extends OneShotEffect { + + public PetraSphinxEffect() { + super(Outcome.DrawCard); + staticText = "Target player chooses a card name, then reveals the top card of his or her library. If that card has the chosen name, that player puts it into his or her hand. If it doesn't, the player puts it into his or her graveyard"; + } + + public PetraSphinxEffect(final PetraSphinxEffect effect) { + super(effect); + } + + @Override + public boolean apply(Game game, Ability source) { + MageObject sourceObject = source.getSourceObject(game); + Player controller = game.getPlayer(source.getControllerId()); + Player player = game.getPlayer(targetPointer.getFirst(game, source)); + if (controller != null && sourceObject != null && player != null) { + + + if (player.getLibrary().hasCards()) { + Choice cardChoice = new ChoiceImpl(); + cardChoice.setChoices(CardRepository.instance.getNames()); + cardChoice.setMessage("Name a card"); + while (!player.choose(Outcome.DrawCard, cardChoice, game)) { + if (!player.canRespond()) { + return false; + } + } + String cardName = cardChoice.getChoice(); + game.informPlayers(sourceObject.getLogName() + ", player: " + player.getLogName() + ", named: [" + cardName + ']'); + Card card = player.getLibrary().removeFromTop(game); + if (card != null) { + Cards cards = new CardsImpl(card); + player.revealCards(sourceObject.getIdName(), cards, game); + if (card.getName().equals(cardName)) { + player.moveCards(cards, Zone.HAND, source, game); + } else { + player.moveCards(cards, Zone.GRAVEYARD, source, game); + } + } + } + return true; + } + return false; + } + + @Override + public PetraSphinxEffect copy() { + return new PetraSphinxEffect(this); + } + +} diff --git a/Mage.Sets/src/mage/cards/p/PhantomWhelp.java b/Mage.Sets/src/mage/cards/p/PhantomWhelp.java new file mode 100644 index 0000000000..ace645b93e --- /dev/null +++ b/Mage.Sets/src/mage/cards/p/PhantomWhelp.java @@ -0,0 +1,70 @@ +/* + * Copyright 2010 BetaSteward_at_googlemail.com. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are + * permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this list of + * conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, this list + * of conditions and the following disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY BetaSteward_at_googlemail.com ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BetaSteward_at_googlemail.com OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * The views and conclusions contained in the software and documentation are those of the + * authors and should not be interpreted as representing official policies, either expressed + * or implied, of BetaSteward_at_googlemail.com. + */ +package mage.cards.p; + +import java.util.UUID; +import mage.MageInt; +import mage.abilities.common.AttacksOrBlocksTriggeredAbility; +import mage.abilities.common.delayed.AtTheEndOfCombatDelayedTriggeredAbility; +import mage.abilities.effects.Effect; +import mage.abilities.effects.common.CreateDelayedTriggeredAbilityEffect; +import mage.abilities.effects.common.ReturnToHandSourceEffect; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.SubType; + +/** + * + * @author fireshoes & L_J + */ +public class PhantomWhelp extends CardImpl { + + public PhantomWhelp(UUID ownerId, CardSetInfo setInfo) { + super(ownerId,setInfo,new CardType[]{CardType.CREATURE},"{1}{U}"); + this.subtype.add(SubType.ILLUSION); + this.subtype.add(SubType.HOUND); + this.power = new MageInt(2); + this.toughness = new MageInt(2); + + // When Phantom Whelp attacks or blocks, return it to its owner's hand at end of combat. (Return it only if it's on the battlefield.) + Effect effect = new CreateDelayedTriggeredAbilityEffect( + new AtTheEndOfCombatDelayedTriggeredAbility(new ReturnToHandSourceEffect(true))); + effect.setText("return it to its owner's hand at end of combat"); + this.addAbility(new AttacksOrBlocksTriggeredAbility(effect, false)); + } + + public PhantomWhelp(final PhantomWhelp card) { + super(card); + } + + @Override + public PhantomWhelp copy() { + return new PhantomWhelp(this); + } +} diff --git a/Mage.Sets/src/mage/cards/p/PrismaticWard.java b/Mage.Sets/src/mage/cards/p/PrismaticWard.java new file mode 100644 index 0000000000..3d5c31ec3b --- /dev/null +++ b/Mage.Sets/src/mage/cards/p/PrismaticWard.java @@ -0,0 +1,129 @@ +/* + * Copyright 2010 BetaSteward_at_googlemail.com. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are + * permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this list of + * conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, this list + * of conditions and the following disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY BetaSteward_at_googlemail.com ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BetaSteward_at_googlemail.com OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * The views and conclusions contained in the software and documentation are those of the + * authors and should not be interpreted as representing official policies, either expressed + * or implied, of BetaSteward_at_googlemail.com. + */ +package mage.cards.p; + +import java.util.UUID; +import mage.MageObject; +import mage.ObjectColor; +import mage.constants.SubType; +import mage.target.common.TargetCreaturePermanent; +import mage.abilities.Ability; +import mage.abilities.common.AsEntersBattlefieldAbility; +import mage.abilities.common.SimpleStaticAbility; +import mage.abilities.effects.PreventionEffectImpl; +import mage.abilities.effects.common.AttachEffect; +import mage.abilities.effects.common.ChooseColorEffect; +import mage.constants.Outcome; +import mage.target.TargetPermanent; +import mage.abilities.keyword.EnchantAbility; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.Duration; +import mage.constants.Zone; +import mage.game.Game; +import mage.game.events.GameEvent; +import mage.game.permanent.Permanent; + +/** + * + * @author TheElk801 + */ +public class PrismaticWard extends CardImpl { + + public PrismaticWard(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.ENCHANTMENT}, "{1}{W}"); + + this.subtype.add(SubType.AURA); + + // Enchant creature + TargetPermanent auraTarget = new TargetCreaturePermanent(); + this.getSpellAbility().addTarget(auraTarget); + this.getSpellAbility().addEffect(new AttachEffect(Outcome.BoostCreature)); + Ability ability = new EnchantAbility(auraTarget.getTargetName()); + this.addAbility(ability); + + // As Prismatic Ward enters the battlefield, choose a color. + this.addAbility(new AsEntersBattlefieldAbility(new ChooseColorEffect(Outcome.Benefit))); + + // Prevent all damage that would be dealt to enchanted creature by sources of the chosen color. + this.addAbility(new SimpleStaticAbility(Zone.BATTLEFIELD, new PrismaticWardPreventDamageEffect())); + } + + public PrismaticWard(final PrismaticWard card) { + super(card); + } + + @Override + public PrismaticWard copy() { + return new PrismaticWard(this); + } +} + +class PrismaticWardPreventDamageEffect extends PreventionEffectImpl { + + public PrismaticWardPreventDamageEffect() { + super(Duration.WhileOnBattlefield, Integer.MAX_VALUE, false); + staticText = "Prevent all damage that would be dealt to enchanted creature by sources of the chosen color."; + } + + public PrismaticWardPreventDamageEffect(final PrismaticWardPreventDamageEffect effect) { + super(effect); + } + + @Override + public PrismaticWardPreventDamageEffect copy() { + return new PrismaticWardPreventDamageEffect(this); + } + + @Override + public boolean applies(GameEvent event, Ability source, Game game) { + if (!super.applies(event, source, game)) { + return false; + } + Permanent permanent = game.getPermanent(source.getSourceId()); + if (permanent == null) { + return false; + } + ObjectColor color = (ObjectColor) game.getState().getValue(permanent.getId() + "_color"); + if (color == null) { + return false; + } + MageObject sourceObject = game.getObject(event.getSourceId()); + if (sourceObject == null || !sourceObject.getColor(game).shares(color)) { + return false; + } + Permanent attachment = game.getPermanent(source.getSourceId()); + if (attachment != null + && attachment.getAttachedTo() != null + && event.getTargetId().equals(attachment.getAttachedTo())) { + return true; + } + return false; + } +} diff --git a/Mage.Sets/src/mage/cards/p/PulseOfTheDross.java b/Mage.Sets/src/mage/cards/p/PulseOfTheDross.java new file mode 100644 index 0000000000..f0be2b5f5b --- /dev/null +++ b/Mage.Sets/src/mage/cards/p/PulseOfTheDross.java @@ -0,0 +1,101 @@ +/* + * Copyright 2010 BetaSteward_at_googlemail.com. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are + * permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this list of + * conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, this list + * of conditions and the following disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY BetaSteward_at_googlemail.com ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BetaSteward_at_googlemail.com OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * The views and conclusions contained in the software and documentation are those of the + * authors and should not be interpreted as representing official policies, either expressed + * or implied, of BetaSteward_at_googlemail.com. + */ +package mage.cards.p; + +import java.util.UUID; +import mage.abilities.Ability; +import mage.abilities.effects.OneShotEffect; +import mage.abilities.effects.common.discard.DiscardCardYouChooseTargetEffect; +import mage.cards.Card; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.Outcome; +import mage.constants.TargetController; +import mage.constants.Zone; +import mage.game.Game; +import mage.players.Player; +import mage.target.TargetPlayer; + +/** + * + * @author emerald000 & L_J + */ +public class PulseOfTheDross extends CardImpl { + + public PulseOfTheDross(UUID ownerId, CardSetInfo setInfo) { + super(ownerId,setInfo,new CardType[]{CardType.SORCERY},"{1}{B}{B}"); + + // Target player reveals three cards from his or her hand and you choose one of them. That player discards that card. + this.getSpellAbility().addEffect(new DiscardCardYouChooseTargetEffect(TargetController.ANY, 3)); + this.getSpellAbility().addEffect(new PulseOfTheDrossReturnToHandEffect()); + this.getSpellAbility().addTarget(new TargetPlayer()); + } + + public PulseOfTheDross(final PulseOfTheDross card) { + super(card); + } + + @Override + public PulseOfTheDross copy() { + return new PulseOfTheDross(this); + } +} + +class PulseOfTheDrossReturnToHandEffect extends OneShotEffect { + + PulseOfTheDrossReturnToHandEffect() { + super(Outcome.Benefit); + this.staticText = "Then if that player has more cards in hand than you, return {this} to its owner's hand"; + } + + PulseOfTheDrossReturnToHandEffect(final PulseOfTheDrossReturnToHandEffect effect) { + super(effect); + } + + @Override + public PulseOfTheDrossReturnToHandEffect copy() { + return new PulseOfTheDrossReturnToHandEffect(this); + } + + @Override + public boolean apply(Game game, Ability source) { + Player controller = game.getPlayer(source.getControllerId()); + if (controller != null) { + Player player = game.getPlayer(source.getFirstTarget()); + if (player != null) { + if (player.getHand().size() > controller.getHand().size()) { + Card card = game.getCard(source.getSourceId()); + controller.moveCards(card, Zone.HAND, source, game); + } + return true; + } + } + return false; + } +} diff --git a/Mage.Sets/src/mage/cards/p/PulseOfTheGrid.java b/Mage.Sets/src/mage/cards/p/PulseOfTheGrid.java index 704e3d3570..485af3b3c5 100644 --- a/Mage.Sets/src/mage/cards/p/PulseOfTheGrid.java +++ b/Mage.Sets/src/mage/cards/p/PulseOfTheGrid.java @@ -68,7 +68,7 @@ class PulseOfTheGridReturnToHandEffect extends OneShotEffect { PulseOfTheGridReturnToHandEffect() { super(Outcome.Benefit); - this.staticText = "Draw two cards, then discard a card. Then if an opponent has more cards in hand than you, return {this} to its owner's hand"; + this.staticText = "Then if an opponent has more cards in hand than you, return {this} to its owner's hand"; } PulseOfTheGridReturnToHandEffect(final PulseOfTheGridReturnToHandEffect effect) { diff --git a/Mage.Sets/src/mage/cards/r/RallyTheTroops.java b/Mage.Sets/src/mage/cards/r/RallyTheTroops.java new file mode 100644 index 0000000000..4974b7b806 --- /dev/null +++ b/Mage.Sets/src/mage/cards/r/RallyTheTroops.java @@ -0,0 +1,72 @@ +/* + * Copyright 2010 BetaSteward_at_googlemail.com. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are + * permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this list of + * conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, this list + * of conditions and the following disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY BetaSteward_at_googlemail.com ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BetaSteward_at_googlemail.com OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * The views and conclusions contained in the software and documentation are those of the + * authors and should not be interpreted as representing official policies, either expressed + * or implied, of BetaSteward_at_googlemail.com. + */ +package mage.cards.r; + +import java.util.UUID; +import mage.abilities.Ability; +import mage.abilities.common.CastOnlyDuringPhaseStepSourceAbility; +import mage.abilities.condition.common.AttackedThisStepCondition; +import mage.abilities.effects.common.UntapAllControllerEffect; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.PhaseStep; +import mage.constants.TurnPhase; +import mage.filter.StaticFilters; +import mage.watchers.common.PlayerAttackedStepWatcher; + +/** + * + * @author TheElk801 + */ +public class RallyTheTroops extends CardImpl { + + public RallyTheTroops(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.INSTANT}, "{W}"); + + // Cast Rally the Troops only during the declare attackers step and only if you've been attacked this step. + Ability ability = new CastOnlyDuringPhaseStepSourceAbility( + TurnPhase.COMBAT, PhaseStep.DECLARE_ATTACKERS, AttackedThisStepCondition.instance, + "Cast {this} only during the declare attackers step and only if you've been attacked this step." + ); + ability.addWatcher(new PlayerAttackedStepWatcher()); + this.addAbility(ability); + + // Untap all creatures you control. + this.getSpellAbility().addEffect(new UntapAllControllerEffect(StaticFilters.FILTER_PERMANENT_CREATURES)); + } + + public RallyTheTroops(final RallyTheTroops card) { + super(card); + } + + @Override + public RallyTheTroops copy() { + return new RallyTheTroops(this); + } +} diff --git a/Mage.Sets/src/mage/cards/r/Reap.java b/Mage.Sets/src/mage/cards/r/Reap.java new file mode 100644 index 0000000000..242acfd7f4 --- /dev/null +++ b/Mage.Sets/src/mage/cards/r/Reap.java @@ -0,0 +1,95 @@ +/* + * Copyright 2010 BetaSteward_at_googlemail.com. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are + * permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this list of + * conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, this list + * of conditions and the following disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY BetaSteward_at_googlemail.com ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BetaSteward_at_googlemail.com OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * The views and conclusions contained in the software and documentation are those of the + * authors and should not be interpreted as representing official policies, either expressed + * or implied, of BetaSteward_at_googlemail.com. + */ +package mage.cards.r; + +import java.util.UUID; +import mage.ObjectColor; +import mage.abilities.Ability; +import mage.abilities.SpellAbility; +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.filter.FilterCard; +import mage.filter.FilterPermanent; +import mage.filter.predicate.mageobject.ColorPredicate; +import mage.players.Player; +import mage.target.Target; +import mage.target.common.TargetCardInYourGraveyard; +import mage.target.common.TargetOpponent; + +/** + * + * @author L_J + */ +public class Reap extends CardImpl { + + private static final FilterPermanent filter = new FilterPermanent("black permanents"); + + static { + filter.add(new ColorPredicate(ObjectColor.BLACK)); + } + + public Reap(UUID ownerId, CardSetInfo setInfo) { + super(ownerId,setInfo,new CardType[]{CardType.INSTANT},"{1}{G}"); + + // Return up to X target cards from your graveyard to your hand, where X is the number of black permanents target opponent controls as you cast Reap. + this.getSpellAbility().addEffect(new ReturnToHandTargetEffect().setText("Return up to X target cards from your graveyard to your hand, where X is the number of black permanents target opponent controls as you cast Reap.")); + this.getSpellAbility().addTarget(new TargetOpponent()); + this.getSpellAbility().addTarget(new TargetCardInYourGraveyard(0, 0, new FilterCard("cards from your graveyard"))); + } + + @Override + public void adjustTargets(Ability ability, Game game) { + if (ability instanceof SpellAbility) { + Player controller = game.getPlayer(ability.getControllerId()); + if (controller != null) { + ability.getTargets().clear(); + UUID opponentId = null; + Target target = new TargetOpponent(); + if (controller.chooseTarget(Outcome.ReturnToHand, target, ability, game)) { + opponentId = target.getFirstTarget(); + } + int numbTargets = game.getBattlefield().getAllActivePermanents(filter, opponentId, game).size(); + ability.addTarget(new TargetCardInYourGraveyard(0, numbTargets, new FilterCard("cards from your graveyard"))); + } + } + } + + + public Reap(final Reap card) { + super(card); + } + + @Override + public Reap copy() { + return new Reap(this); + } +} diff --git a/Mage.Sets/src/mage/cards/r/Remove.java b/Mage.Sets/src/mage/cards/r/Remove.java new file mode 100644 index 0000000000..fa859c91a1 --- /dev/null +++ b/Mage.Sets/src/mage/cards/r/Remove.java @@ -0,0 +1,73 @@ +/* + * Copyright 2010 BetaSteward_at_googlemail.com. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are + * permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this list of + * conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, this list + * of conditions and the following disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY BetaSteward_at_googlemail.com ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BetaSteward_at_googlemail.com OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * The views and conclusions contained in the software and documentation are those of the + * authors and should not be interpreted as representing official policies, either expressed + * or implied, of BetaSteward_at_googlemail.com. + */ +package mage.cards.r; + +import java.util.UUID; +import mage.abilities.Ability; +import mage.abilities.common.CastOnlyDuringPhaseStepSourceAbility; +import mage.abilities.condition.common.AttackedThisStepCondition; +import mage.abilities.effects.common.ReturnToHandTargetEffect; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.PhaseStep; +import mage.constants.TurnPhase; +import mage.target.common.TargetAttackingCreature; +import mage.watchers.common.PlayerAttackedStepWatcher; + +/** + * + * @author TheElk801 + */ +public class Remove extends CardImpl { + + public Remove(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.INSTANT}, "{U}"); + + // Cast Remove only during the declare attackers step and only if you've been attacked this step. + Ability ability = new CastOnlyDuringPhaseStepSourceAbility( + TurnPhase.COMBAT, PhaseStep.DECLARE_ATTACKERS, AttackedThisStepCondition.instance, + "Cast {this} only during the declare attackers step and only if you've been attacked this step." + ); + ability.addWatcher(new PlayerAttackedStepWatcher()); + this.addAbility(ability); + + // Return target attacking creature to its owner's hand. + this.getSpellAbility().addEffect(new ReturnToHandTargetEffect()); + this.getSpellAbility().addTarget(new TargetAttackingCreature()); + } + + public Remove(final Remove card) { + super(card); + } + + @Override + public Remove copy() { + return new Remove(this); + } +} diff --git a/Mage.Sets/src/mage/cards/r/RhysticCave.java b/Mage.Sets/src/mage/cards/r/RhysticCave.java new file mode 100644 index 0000000000..6ce08e5651 --- /dev/null +++ b/Mage.Sets/src/mage/cards/r/RhysticCave.java @@ -0,0 +1,172 @@ +/* + * Copyright 2010 BetaSteward_at_googlemail.com. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are + * permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this list of + * conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, this list + * of conditions and the following disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY BetaSteward_at_googlemail.com ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BetaSteward_at_googlemail.com OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * The views and conclusions contained in the software and documentation are those of the + * authors and should not be interpreted as representing official policies, either expressed + * or implied, of BetaSteward_at_googlemail.com. + */ +package mage.cards.r; + +import java.util.UUID; +import mage.MageObject; +import mage.Mana; +import mage.abilities.Ability; +import mage.abilities.costs.Cost; +import mage.abilities.costs.common.TapSourceCost; +import mage.abilities.costs.mana.GenericManaCost; +import mage.abilities.effects.Effect; +import mage.abilities.effects.common.BasicManaEffect; +import mage.abilities.effects.common.DoUnlessAnyPlayerPaysManaEffect; +import mage.abilities.effects.common.ManaEffect; +import mage.abilities.mana.ActivatedManaAbilityImpl; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.choices.ChoiceColor; +import mage.constants.CardType; +import mage.constants.Zone; +import mage.game.Game; +import mage.players.Player; + +/** + * + * @author jerekwilson + */ +public class RhysticCave extends CardImpl { + + public RhysticCave(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.LAND}, ""); + + // {T}: Choose a color. Add one mana of that color to your mana pool unless any player pays {1}. Activate this ability only any time you could cast an instant. + this.addAbility(new RhysticCaveManaAbility()); + } + + public RhysticCave(final RhysticCave card) { + super(card); + } + + @Override + public RhysticCave copy() { + return new RhysticCave(this); + } +} + +class RhysticCaveManaAbility extends ActivatedManaAbilityImpl { + + public RhysticCaveManaAbility() { + super(Zone.BATTLEFIELD, new DoUnlessAnyPlayerPaysManaEffect(new RhysticCaveManaEffect(), new GenericManaCost(1), "Pay {1} to prevent mana adding from {this}."), new TapSourceCost()); + this.netMana.add(new Mana(0, 0, 0, 0, 0, 0, 1, 0)); + this.setUndoPossible(false); + } + + public RhysticCaveManaAbility(Zone zone, Mana mana, Cost cost) { + super(zone, new BasicManaEffect(mana), cost); + + } + + public RhysticCaveManaAbility(final RhysticCaveManaAbility ability) { + super(ability); + } + + @Override + public boolean canActivate(UUID playerId, Game game) { + Player player = game.getPlayer(playerId); + if (player != null && !player.isInPayManaMode()) { + return super.canActivate(playerId, game); + } + return false; + } + + @Override + public RhysticCaveManaAbility copy() { + return new RhysticCaveManaAbility(this); + } + + @Override + public String getRule() { + return super.getRule() + " Activate this ability only any time you could cast an instant."; + } +} + +class RhysticCaveManaEffect extends ManaEffect { + + private final Mana chosenMana; + + public RhysticCaveManaEffect() { + super(); + chosenMana = new Mana(); + this.staticText = "Choose a color. Add one mana of that color to your mana pool "; + } + + public RhysticCaveManaEffect(final RhysticCaveManaEffect effect) { + super(effect); + this.chosenMana = effect.chosenMana.copy(); + } + + @Override + public Mana getMana(Game game, Ability source) { + return null; + } + + @Override + public boolean apply(Game game, Ability source) { + Player controller = game.getPlayer(source.getControllerId()); + MageObject mageObject = game.getPermanentOrLKIBattlefield(source.getSourceId()); //get obj reference to Rhystic Cave + if (controller != null) { + if (mageObject != null) { + ChoiceColor choice = new ChoiceColor(true); + controller.choose(outcome, choice, game); + if (choice.getColor() != null) { + String color = choice.getColor().toString(); + switch (color) { + case "R": + chosenMana.setRed(1); + break; + case "U": + chosenMana.setBlue(1); + break; + case "W": + chosenMana.setWhite(1); + break; + case "B": + chosenMana.setBlack(1); + break; + case "G": + chosenMana.setGreen(1); + break; + } + } + checkToFirePossibleEvents(chosenMana, game, source); + controller.getManaPool().addMana(chosenMana, game, source); + return true; + } + + } + + return false; + } + + @Override + public Effect copy() { + return new RhysticCaveManaEffect(this); + } +} diff --git a/Mage.Sets/src/mage/cards/r/RighteousWar.java b/Mage.Sets/src/mage/cards/r/RighteousWar.java new file mode 100644 index 0000000000..b64fd49875 --- /dev/null +++ b/Mage.Sets/src/mage/cards/r/RighteousWar.java @@ -0,0 +1,89 @@ +/* + * Copyright 2010 BetaSteward_at_googlemail.com. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are + * permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this list of + * conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, this list + * of conditions and the following disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY BetaSteward_at_googlemail.com ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BetaSteward_at_googlemail.com OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * The views and conclusions contained in the software and documentation are those of the + * authors and should not be interpreted as representing official policies, either expressed + * or implied, of BetaSteward_at_googlemail.com. + */ +package mage.cards.r; + +import java.util.UUID; +import mage.ObjectColor; +import mage.abilities.common.SimpleStaticAbility; +import mage.abilities.effects.common.continuous.GainAbilityControlledEffect; +import mage.abilities.keyword.ProtectionAbility; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.Duration; +import mage.constants.Zone; +import mage.filter.common.FilterCreaturePermanent; +import mage.filter.predicate.mageobject.ColorPredicate; + +/** + * + * @author TheElk801 + */ +public class RighteousWar extends CardImpl { + + private static final FilterCreaturePermanent whiteFilter = new FilterCreaturePermanent("white creatures you control"); + private static final FilterCreaturePermanent blackFilter = new FilterCreaturePermanent("black creatures you control"); + + static { + whiteFilter.add(new ColorPredicate(ObjectColor.WHITE)); + blackFilter.add(new ColorPredicate(ObjectColor.BLACK)); + } + + public RighteousWar(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.ENCHANTMENT}, "{1}{W}{B}"); + + // White creatures you control have protection from black. + this.addAbility(new SimpleStaticAbility( + Zone.BATTLEFIELD, + new GainAbilityControlledEffect( + ProtectionAbility.from(ObjectColor.BLACK), + Duration.WhileOnBattlefield, + whiteFilter + ) + )); + + // Black creatures you control have protection from white. + this.addAbility(new SimpleStaticAbility( + Zone.BATTLEFIELD, + new GainAbilityControlledEffect( + ProtectionAbility.from(ObjectColor.WHITE), + Duration.WhileOnBattlefield, + blackFilter + ) + )); + } + + public RighteousWar(final RighteousWar card) { + super(card); + } + + @Override + public RighteousWar copy() { + return new RighteousWar(this); + } +} diff --git a/Mage.Sets/src/mage/cards/r/RiskyMove.java b/Mage.Sets/src/mage/cards/r/RiskyMove.java new file mode 100644 index 0000000000..322719a585 --- /dev/null +++ b/Mage.Sets/src/mage/cards/r/RiskyMove.java @@ -0,0 +1,240 @@ +/* + * Copyright 2010 BetaSteward_at_googlemail.com. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are + * permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this list of + * conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, this list + * of conditions and the following disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY BetaSteward_at_googlemail.com ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BetaSteward_at_googlemail.com OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * The views and conclusions contained in the software and documentation are those of the + * authors and should not be interpreted as representing official policies, either expressed + * or implied, of BetaSteward_at_googlemail.com. + */ +package mage.cards.r; + +import java.util.UUID; +import mage.MageObject; +import mage.abilities.Ability; +import mage.abilities.Mode; +import mage.abilities.TriggeredAbilityImpl; +import mage.abilities.common.BeginningOfUpkeepTriggeredAbility; +import mage.abilities.effects.ContinuousEffect; +import mage.abilities.effects.ContinuousEffectImpl; +import mage.abilities.effects.OneShotEffect; +import mage.abilities.effects.common.continuous.GainControlTargetEffect; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.*; +import mage.filter.common.FilterControlledCreaturePermanent; +import mage.game.Game; +import mage.game.events.GameEvent; +import mage.game.permanent.Permanent; +import mage.players.Player; +import mage.target.Target; +import mage.target.common.TargetControlledCreaturePermanent; +import mage.target.common.TargetOpponent; +import mage.target.targetpointer.FixedTarget; + +/** + * + * @author L_J + */ +public class RiskyMove extends CardImpl { + + public RiskyMove(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.ENCHANTMENT}, "{3}{R}{R}{R}"); + + // At the beginning of each player's upkeep, that player gains control of Risky Move. + this.addAbility(new BeginningOfUpkeepTriggeredAbility(Zone.BATTLEFIELD, new RiskyMoveGetControlEffect(), TargetController.ANY, false, true)); + + // When you gain control of Risky Move from another player, choose a creature you control and an opponent. Flip a coin. If you lose the flip, that opponent gains control of that creature. + this.addAbility(new RiskyMoveTriggeredAbility()); + } + + public RiskyMove(final RiskyMove card) { + super(card); + } + + @Override + public RiskyMove copy() { + return new RiskyMove(this); + } +} + +class RiskyMoveGetControlEffect extends OneShotEffect { + + public RiskyMoveGetControlEffect() { + super(Outcome.GainControl); + this.staticText = "that player gains control of {this}"; + } + + public RiskyMoveGetControlEffect(final RiskyMoveGetControlEffect effect) { + super(effect); + } + + @Override + public RiskyMoveGetControlEffect copy() { + return new RiskyMoveGetControlEffect(this); + } + + @Override + public boolean apply(Game game, Ability source) { + Player controller = game.getPlayer(source.getControllerId()); + MageObject sourceObject = source.getSourceObject(game); + Permanent sourcePermanent = game.getPermanent(source.getSourceId()); + Player newController = game.getPlayer(getTargetPointer().getFirst(game, source)); + if (newController != null && controller != null && sourceObject != null && sourceObject.equals(sourcePermanent)) { + // remove old control effects of the same player + for (ContinuousEffect effect : game.getState().getContinuousEffects().getLayeredEffects(game)) { + if (effect instanceof GainControlTargetEffect) { + UUID checkId = (UUID) ((GainControlTargetEffect) effect).getValue("RiskyMoveSourceId"); + UUID controllerId = (UUID) ((GainControlTargetEffect) effect).getValue("RiskyMoveControllerId"); + if (source.getSourceId().equals(checkId) && newController.getId().equals(controllerId)) { + effect.discard(); + } + } + } + ContinuousEffect effect = new GainControlTargetEffect(Duration.Custom, true, newController.getId()); + effect.setValue("RiskyMoveSourceId", source.getSourceId()); + effect.setValue("RiskyMoveControllerId", newController.getId()); + effect.setTargetPointer(new FixedTarget(sourcePermanent.getId())); + effect.setText("and gains control of it"); + game.addEffect(effect, source); + return true; + } + return false; + } +} + +class RiskyMoveTriggeredAbility extends TriggeredAbilityImpl { + + public RiskyMoveTriggeredAbility() { + super(Zone.BATTLEFIELD, new RiskyMoveFlipCoinEffect(), false); + } + + public RiskyMoveTriggeredAbility(final RiskyMoveTriggeredAbility ability) { + super(ability); + } + + @Override + public RiskyMoveTriggeredAbility copy() { + return new RiskyMoveTriggeredAbility(this); + } + + @Override + public boolean checkEventType(GameEvent event, Game game) { + return event.getType() == GameEvent.EventType.GAINED_CONTROL; + } + + @Override + public boolean checkTrigger(GameEvent event, Game game) { + return event.getTargetId().equals(sourceId); + } + + @Override + public String getRule() { + return "When you gain control of {this} from another player, " + super.getRule(); + } +} + + +class RiskyMoveFlipCoinEffect extends OneShotEffect { + + public RiskyMoveFlipCoinEffect() { + super(Outcome.Detriment); + this.staticText = "choose a creature you control and an opponent. Flip a coin. If you lose the flip, that opponent gains control of that creature"; + } + + public RiskyMoveFlipCoinEffect(final RiskyMoveFlipCoinEffect effect) { + super(effect); + } + + @Override + public RiskyMoveFlipCoinEffect copy() { + return new RiskyMoveFlipCoinEffect(this); + } + + @Override + public boolean apply(Game game, Ability source) { + Player controller = game.getPlayer(source.getControllerId()); + if (controller != null) { + Target target1 = new TargetControlledCreaturePermanent(1, 1, new FilterControlledCreaturePermanent(), true); + Target target2 = new TargetOpponent(true); + + if (target1.canChoose(source.getSourceId(), controller.getId(), game)) { + while (!target1.isChosen() && target1.canChoose(controller.getId(), game) && controller.canRespond()) { + controller.chooseTarget(outcome, target1, source, game); + } + } + if (target2.canChoose(source.getSourceId(), controller.getId(), game)) { + while (!target2.isChosen() && target2.canChoose(controller.getId(), game) && controller.canRespond()) { + controller.chooseTarget(outcome, target2, source, game); + } + } + Permanent permanent = game.getPermanent(target1.getFirstTarget()); + Player chosenOpponent = game.getPlayer(target2.getFirstTarget()); + if (!controller.flipCoin(game)) { + if (permanent != null && chosenOpponent != null) { + ContinuousEffect effect = new RiskyMoveCreatureGainControlEffect(Duration.Custom, chosenOpponent.getId()); + effect.setTargetPointer(new FixedTarget(permanent.getId())); + game.addEffect(effect, source); + game.informPlayers(chosenOpponent.getLogName() + " has gained control of " + permanent.getLogName()); + return true; + } + } + } + return false; + } +} + +class RiskyMoveCreatureGainControlEffect extends ContinuousEffectImpl { + + private UUID controller; + + public RiskyMoveCreatureGainControlEffect(Duration duration, UUID controller) { + super(duration, Layer.ControlChangingEffects_2, SubLayer.NA, Outcome.GainControl); + this.controller = controller; + } + + public RiskyMoveCreatureGainControlEffect(final RiskyMoveCreatureGainControlEffect effect) { + super(effect); + this.controller = effect.controller; + } + + @Override + public RiskyMoveCreatureGainControlEffect copy() { + return new RiskyMoveCreatureGainControlEffect(this); + } + + @Override + public boolean apply(Game game, Ability source) { + Permanent permanent = game.getPermanent(source.getFirstTarget()); + if (targetPointer != null) { + permanent = game.getPermanent(targetPointer.getFirst(game, source)); + } + if (permanent != null) { + return permanent.changeControllerId(controller, game); + } + return false; + } + + @Override + public String getText(Mode mode) { + return "If you lose the flip, that opponent gains control of that creature"; + } +} diff --git a/Mage.Sets/src/mage/cards/s/Sailmonger.java b/Mage.Sets/src/mage/cards/s/Sailmonger.java new file mode 100644 index 0000000000..a5a1846d09 --- /dev/null +++ b/Mage.Sets/src/mage/cards/s/Sailmonger.java @@ -0,0 +1,76 @@ +/* + * Copyright 2010 BetaSteward_at_googlemail.com. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are + * permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this list of + * conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, this list + * of conditions and the following disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY BetaSteward_at_googlemail.com ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BetaSteward_at_googlemail.com OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * The views and conclusions contained in the software and documentation are those of the + * authors and should not be interpreted as representing official policies, either expressed + * or implied, of BetaSteward_at_googlemail.com. + */ +package mage.cards.s; + +import java.util.UUID; +import mage.MageInt; +import mage.abilities.Ability; +import mage.abilities.common.SimpleActivatedAbility; +import mage.abilities.costs.mana.ManaCostsImpl; +import mage.abilities.effects.common.InfoEffect; +import mage.abilities.effects.common.continuous.GainAbilityTargetEffect; +import mage.abilities.keyword.FlyingAbility; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.Duration; +import mage.constants.SubType; +import mage.constants.TargetController; +import mage.constants.Zone; +import mage.target.common.TargetCreaturePermanent; + +/** + * + * @author L_J + */ +public class Sailmonger extends CardImpl { + + public Sailmonger(UUID ownerId, CardSetInfo setInfo) { + super(ownerId,setInfo,new CardType[]{CardType.CREATURE},"{3}{U}"); + this.subtype.add(SubType.HUMAN); + this.subtype.add(SubType.MONGER); + this.power = new MageInt(3); + this.toughness = new MageInt(3); + + // {2}: Target creature gains flying until end of turn. Any player may activate this ability. + SimpleActivatedAbility ability = new SimpleActivatedAbility(Zone.BATTLEFIELD, new GainAbilityTargetEffect(FlyingAbility.getInstance(), Duration.EndOfTurn), new ManaCostsImpl("{2}")); + ability.addTarget(new TargetCreaturePermanent()); + ability.setMayActivate(TargetController.ANY); + ability.addEffect(new InfoEffect("Any player may activate this ability")); + this.addAbility(ability); + } + + public Sailmonger(final Sailmonger card) { + super(card); + } + + @Override + public Sailmonger copy() { + return new Sailmonger(this); + } +} diff --git a/Mage.Sets/src/mage/cards/s/ScorchingWinds.java b/Mage.Sets/src/mage/cards/s/ScorchingWinds.java new file mode 100644 index 0000000000..3c5bd2a76c --- /dev/null +++ b/Mage.Sets/src/mage/cards/s/ScorchingWinds.java @@ -0,0 +1,72 @@ +/* + * Copyright 2010 BetaSteward_at_googlemail.com. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are + * permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this list of + * conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, this list + * of conditions and the following disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY BetaSteward_at_googlemail.com ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BetaSteward_at_googlemail.com OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * The views and conclusions contained in the software and documentation are those of the + * authors and should not be interpreted as representing official policies, either expressed + * or implied, of BetaSteward_at_googlemail.com. + */ +package mage.cards.s; + +import java.util.UUID; +import mage.abilities.Ability; +import mage.abilities.common.CastOnlyDuringPhaseStepSourceAbility; +import mage.abilities.condition.common.AttackedThisStepCondition; +import mage.abilities.effects.common.DamageAllEffect; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.PhaseStep; +import mage.constants.TurnPhase; +import mage.filter.common.FilterAttackingCreature; +import mage.watchers.common.PlayerAttackedStepWatcher; + +/** + * + * @author TheElk801 + */ +public class ScorchingWinds extends CardImpl { + + public ScorchingWinds(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.INSTANT}, "{R}"); + + // Cast Scorching Winds only during the declare attackers step and only if you've been attacked this step. + Ability ability = new CastOnlyDuringPhaseStepSourceAbility( + TurnPhase.COMBAT, PhaseStep.DECLARE_ATTACKERS, AttackedThisStepCondition.instance, + "Cast {this} only during the declare attackers step and only if you've been attacked this step." + ); + ability.addWatcher(new PlayerAttackedStepWatcher()); + this.addAbility(ability); + + // Scorching Winds deals 1 damage to each attacking creature. + this.getSpellAbility().addEffect(new DamageAllEffect(1, new FilterAttackingCreature())); + } + + public ScorchingWinds(final ScorchingWinds card) { + super(card); + } + + @Override + public ScorchingWinds copy() { + return new ScorchingWinds(this); + } +} diff --git a/Mage.Sets/src/mage/cards/s/Scrounge.java b/Mage.Sets/src/mage/cards/s/Scrounge.java new file mode 100644 index 0000000000..b4fa332d95 --- /dev/null +++ b/Mage.Sets/src/mage/cards/s/Scrounge.java @@ -0,0 +1,107 @@ +/* + * Copyright 2010 BetaSteward_at_googlemail.com. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are + * permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this list of + * conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, this list + * of conditions and the following disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY BetaSteward_at_googlemail.com ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BetaSteward_at_googlemail.com OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * The views and conclusions contained in the software and documentation are those of the + * authors and should not be interpreted as representing official policies, either expressed + * or implied, of BetaSteward_at_googlemail.com. + */ +package mage.cards.s; + +import java.util.UUID; +import mage.abilities.Ability; +import mage.abilities.effects.OneShotEffect; +import mage.cards.*; +import mage.constants.CardType; +import mage.constants.Outcome; +import mage.constants.Zone; +import mage.filter.common.FilterArtifactCard; +import mage.filter.predicate.other.OwnerIdPredicate; +import mage.game.Game; +import mage.players.Player; +import mage.target.common.TargetCardInGraveyard; +import mage.target.common.TargetOpponent; + +/** + * + * @author LoneFox & L_J + */ +public class Scrounge extends CardImpl { + + public Scrounge(UUID ownerId, CardSetInfo setInfo) { + super(ownerId,setInfo,new CardType[]{CardType.SORCERY},"{2}{B}"); + + // Target opponent chooses an artifact card in his or her graveyard. Put that card onto the battlefield under your control. + this.getSpellAbility().addEffect(new ScroungeEffect()); + this.getSpellAbility().addTarget(new TargetOpponent()); + } + + public Scrounge(final Scrounge card) { + super(card); + } + + @Override + public Scrounge copy() { + return new Scrounge(this); + } +} + +class ScroungeEffect extends OneShotEffect { + + public ScroungeEffect() { + super(Outcome.Benefit); + staticText = "Target opponent chooses an artifact card in his or her graveyard. Put that card onto the battlefield under your control"; + } + + public ScroungeEffect(final ScroungeEffect effect) { + super(effect); + } + + @Override + public ScroungeEffect copy() { + return new ScroungeEffect(this); + } + + @Override + public boolean apply(Game game, Ability source) { + Player controller = game.getPlayer(source.getControllerId()); + Player opponent = game.getPlayer(targetPointer.getFirst(game, source)); + if (controller != null && opponent != null) { + FilterArtifactCard filter = new FilterArtifactCard(); + filter.add(new OwnerIdPredicate(opponent.getId())); + TargetCardInGraveyard chosenCard = new TargetCardInGraveyard(filter); + chosenCard.setNotTarget(true); + if (chosenCard.canChoose(opponent.getId(), game)) { + opponent.chooseTarget(Outcome.ReturnToHand, chosenCard, source, game); + Card card = game.getCard(chosenCard.getFirstTarget()); + if (card != null) { + game.informPlayers ("Scrounge: " + opponent.getLogName() + " has chosen " + card.getLogName()); + Cards cardsToMove = new CardsImpl(); + cardsToMove.add(card); + controller.moveCards(cardsToMove, Zone.BATTLEFIELD, source, game); + } + } + return true; + } + return false; + } +} diff --git a/Mage.Sets/src/mage/cards/s/SeasonOfTheWitch.java b/Mage.Sets/src/mage/cards/s/SeasonOfTheWitch.java new file mode 100644 index 0000000000..e2bc1e7c4f --- /dev/null +++ b/Mage.Sets/src/mage/cards/s/SeasonOfTheWitch.java @@ -0,0 +1,187 @@ +/* + * Copyright 2010 BetaSteward_at_googlemail.com. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are + * permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this list of + * conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, this list + * of conditions and the following disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY BetaSteward_at_googlemail.com ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BetaSteward_at_googlemail.com OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * The views and conclusions contained in the software and documentation are those of the + * authors and should not be interpreted as representing official policies, either expressed + * or implied, of BetaSteward_at_googlemail.com. + */ +package mage.cards.s; + +import java.util.HashSet; +import java.util.Set; +import java.util.UUID; +import mage.MageObjectReference; +import mage.abilities.Ability; +import mage.abilities.common.BeginningOfEndStepTriggeredAbility; +import mage.abilities.common.BeginningOfUpkeepTriggeredAbility; +import mage.abilities.costs.Cost; +import mage.abilities.costs.common.PayLifeCost; +import mage.abilities.effects.OneShotEffect; +import mage.abilities.effects.common.SacrificeSourceUnlessPaysEffect; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.Outcome; +import mage.constants.TargetController; +import mage.constants.WatcherScope; +import mage.filter.StaticFilters; +import mage.game.Game; +import mage.game.events.GameEvent; +import mage.game.permanent.Permanent; +import mage.players.Player; +import mage.watchers.Watcher; +import mage.watchers.common.AttackedThisTurnWatcher; + +/** + * + * @author L_J + */ +public class SeasonOfTheWitch extends CardImpl { + + public SeasonOfTheWitch(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.ENCHANTMENT}, "{B}{B}{B}"); + + // At the beginning of your upkeep, sacrifice Season of the Witch unless you pay 2 life. + Cost cost = new PayLifeCost(2); + cost.setText("2 life"); + this.addAbility(new BeginningOfUpkeepTriggeredAbility(new SacrificeSourceUnlessPaysEffect(cost), TargetController.YOU, false)); + + // At the beginning of the end step, destroy all untapped creatures that didn't attack this turn, except for creatures that couldn't attack. + Ability ability = new BeginningOfEndStepTriggeredAbility(new SeasonOfTheWitchEffect(), TargetController.ANY, false); + ability.addWatcher(new AttackedThisTurnWatcher()); + ability.addWatcher(new CouldAttackThisTurnWatcher()); + this.addAbility(ability); + } + + public SeasonOfTheWitch(final SeasonOfTheWitch card) { + super(card); + } + + @Override + public SeasonOfTheWitch copy() { + return new SeasonOfTheWitch(this); + } +} + +class SeasonOfTheWitchEffect extends OneShotEffect { + + SeasonOfTheWitchEffect() { + super(Outcome.DestroyPermanent); + this.staticText = "destroy all untapped creatures that didn't attack this turn, except for creatures that couldn't attack"; + } + + SeasonOfTheWitchEffect(final SeasonOfTheWitchEffect effect) { + super(effect); + } + + @Override + public SeasonOfTheWitchEffect copy() { + return new SeasonOfTheWitchEffect(this); + } + + @Override + public boolean apply(Game game, Ability source) { + Player activePlayer = game.getPlayer(game.getActivePlayerId()); + if (activePlayer != null) { + for (Permanent permanent : game.getBattlefield().getAllActivePermanents(StaticFilters.FILTER_PERMANENT_CREATURE, game)) { + // Noncreature cards are safe. + if (!permanent.isCreature()) { + continue; + } + // Tapped cards are safe. + if (permanent.isTapped()) { + continue; + } + // Creatures that attacked are safe. + AttackedThisTurnWatcher watcher = (AttackedThisTurnWatcher) game.getState().getWatchers().get(AttackedThisTurnWatcher.class.getSimpleName()); + if (watcher != null + && watcher.getAttackedThisTurnCreatures().contains(new MageObjectReference(permanent, game))) { + continue; + } + // Creatures that couldn't attack are safe. + CouldAttackThisTurnWatcher watcher2 = (CouldAttackThisTurnWatcher) game.getState().getWatchers().get(CouldAttackThisTurnWatcher.class.getSimpleName()); + if (watcher2 != null + && !watcher2.getCouldAttackThisTurnCreatures().contains(new MageObjectReference(permanent, game))) { + continue; + } + // Destroy the rest. + permanent.destroy(source.getSourceId(), game, false); + } + return true; + } + return false; + } +} + +class CouldAttackThisTurnWatcher extends Watcher { + + public final Set couldAttackThisTurnCreatures = new HashSet<>(); + + public CouldAttackThisTurnWatcher() { + super(CouldAttackThisTurnWatcher.class.getSimpleName(), WatcherScope.GAME); + } + + public CouldAttackThisTurnWatcher(final CouldAttackThisTurnWatcher watcher) { + super(watcher); + this.couldAttackThisTurnCreatures.addAll(watcher.couldAttackThisTurnCreatures); + } + + @Override + public void watch(GameEvent event, Game game) { + if (event.getType() == GameEvent.EventType.DECLARE_ATTACKERS_STEP_PRE) { + Player activePlayer = game.getPlayer(game.getActivePlayerId()); + for (Permanent permanent : game.getBattlefield().getAllActivePermanents(activePlayer.getId())) { + if (permanent.isCreature()) { + for (UUID defender : game.getCombat().getDefenders()) { + if (defender != activePlayer.getId()) { + if (permanent.canAttack(defender, game)) { + // exclude Propaganda style effects + if (!game.getContinuousEffects().checkIfThereArePayCostToAttackBlockEffects( + GameEvent.getEvent(GameEvent.EventType.DECLARE_ATTACKER, + defender, permanent.getId(), permanent.getControllerId()), game)) { + this.couldAttackThisTurnCreatures.add(new MageObjectReference(permanent.getId(), game)); + break; + } + } + } + } + } + } + } + } + + public Set getCouldAttackThisTurnCreatures() { + return this.couldAttackThisTurnCreatures; + } + + @Override + public CouldAttackThisTurnWatcher copy() { + return new CouldAttackThisTurnWatcher(this); + } + + @Override + public void reset() { + super.reset(); + this.couldAttackThisTurnCreatures.clear(); + } +} diff --git a/Mage.Sets/src/mage/cards/s/ShadesBreath.java b/Mage.Sets/src/mage/cards/s/ShadesBreath.java new file mode 100644 index 0000000000..c3580f87f4 --- /dev/null +++ b/Mage.Sets/src/mage/cards/s/ShadesBreath.java @@ -0,0 +1,143 @@ +/* + * Copyright 2010 BetaSteward_at_googlemail.com. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are + * permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this list of + * conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, this list + * of conditions and the following disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY BetaSteward_at_googlemail.com ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BetaSteward_at_googlemail.com OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * The views and conclusions contained in the software and documentation are those of the + * authors and should not be interpreted as representing official policies, either expressed + * or implied, of BetaSteward_at_googlemail.com. + */ +package mage.cards.s; + +import java.util.List; +import java.util.UUID; +import mage.ObjectColor; +import mage.abilities.Ability; +import mage.abilities.common.SimpleActivatedAbility; +import mage.abilities.costs.mana.ManaCostsImpl; +import mage.abilities.effects.ContinuousEffectImpl; +import mage.abilities.effects.common.continuous.BoostSourceEffect; +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.Layer; +import mage.constants.Outcome; +import mage.constants.SubLayer; +import mage.constants.SubType; +import mage.constants.Zone; +import mage.filter.StaticFilters; +import mage.game.Game; +import mage.game.permanent.Permanent; +import mage.util.SubTypeList; + +/** + * + * @author TheElk801 + */ +public class ShadesBreath extends CardImpl { + + public ShadesBreath(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.INSTANT}, "{1}{B}"); + + // Until end of turn, each creature you control becomes a black Shade and gains "{B}: This creature gets +1/+1 until end of turn." + this.getSpellAbility().addEffect(new ShadesBreathSetColorEffect()); + this.getSpellAbility().addEffect(new ShadesBreathSetSubtypeEffect()); + this.getSpellAbility().addEffect( + new GainAbilityControlledEffect(new SimpleActivatedAbility( + Zone.BATTLEFIELD, + new BoostSourceEffect(1, 1, Duration.EndOfTurn).setText("this creature gets +1/+1 until end of turn"), + new ManaCostsImpl("{B}") + ), Duration.EndOfTurn, StaticFilters.FILTER_CONTROLLED_A_CREATURE) + .setText("and gains \"{B}: This creature gets +1/+1 until end of turn.\"") + ); + } + + public ShadesBreath(final ShadesBreath card) { + super(card); + } + + @Override + public ShadesBreath copy() { + return new ShadesBreath(this); + } +} + +class ShadesBreathSetColorEffect extends ContinuousEffectImpl { + + public ShadesBreathSetColorEffect() { + super(Duration.EndOfTurn, Layer.ColorChangingEffects_5, SubLayer.NA, Outcome.Benefit); + staticText = "Until end of turn, each creature you control becomes a black"; + } + + public ShadesBreathSetColorEffect(final ShadesBreathSetColorEffect effect) { + super(effect); + } + + @Override + public boolean apply(Game game, Ability source) { + List permanents = game.getBattlefield().getAllActivePermanents(StaticFilters.FILTER_PERMANENT_CREATURE, source.getControllerId(), game); + for (Permanent permanent : permanents) { + if (permanent != null) { + permanent.getColor(game).setColor(ObjectColor.BLACK); + } + } + return true; + } + + @Override + public ShadesBreathSetColorEffect copy() { + return new ShadesBreathSetColorEffect(this); + } +} + +class ShadesBreathSetSubtypeEffect extends ContinuousEffectImpl { + + public ShadesBreathSetSubtypeEffect() { + super(Duration.EndOfTurn, Layer.TypeChangingEffects_4, SubLayer.NA, Outcome.Benefit); + staticText = "Shade"; + } + + public ShadesBreathSetSubtypeEffect(final ShadesBreathSetSubtypeEffect effect) { + super(effect); + } + + @Override + public boolean apply(Game game, Ability source) { + List permanents = game.getBattlefield().getAllActivePermanents(StaticFilters.FILTER_PERMANENT_CREATURE, source.getControllerId(), game); + for (Permanent permanent : permanents) { + if (permanent != null) { + SubTypeList subtype = permanent.getSubtype(game); + if (subtype != null && subtype.size() != 1 || !subtype.contains(SubType.SHADE)) { + subtype.removeAll(SubType.getCreatureTypes(false)); + subtype.add(SubType.SHADE); + } + } + } + return true; + } + + @Override + public ShadesBreathSetSubtypeEffect copy() { + return new ShadesBreathSetSubtypeEffect(this); + } +} diff --git a/Mage.Sets/src/mage/cards/s/ShamanEnKor.java b/Mage.Sets/src/mage/cards/s/ShamanEnKor.java index 780c4b58da..13e67fb808 100644 --- a/Mage.Sets/src/mage/cards/s/ShamanEnKor.java +++ b/Mage.Sets/src/mage/cards/s/ShamanEnKor.java @@ -43,9 +43,11 @@ import mage.constants.SubType; import mage.constants.Duration; import mage.constants.Outcome; import mage.constants.Zone; +import mage.filter.common.FilterCreaturePermanent; import mage.game.Game; import mage.game.events.GameEvent; import mage.game.events.GameEvent.EventType; +import mage.game.permanent.Permanent; import mage.players.Player; import mage.target.TargetPermanent; import mage.target.TargetSource; @@ -91,6 +93,7 @@ public class ShamanEnKor extends CardImpl { class ShamanEnKorRedirectFromTargetEffect extends RedirectionEffect { + private static FilterCreaturePermanent filter = new FilterCreaturePermanent(); protected MageObjectReference sourceObject; ShamanEnKorRedirectFromTargetEffect() { @@ -122,10 +125,15 @@ class ShamanEnKorRedirectFromTargetEffect extends RedirectionEffect { @Override public boolean applies(GameEvent event, Ability source, Game game) { - if (sourceObject.equals(new MageObjectReference(event.getSourceId(), game))) { - redirectTarget = new TargetPermanent(); - redirectTarget.add(source.getSourceId(), game); - return event.getTargetId().equals(getTargetPointer().getFirst(game, source)); + Permanent permanent = game.getBattlefield().getPermanent(source.getSourceId()); + if (permanent != null) { + if (filter.match(permanent, permanent.getId(), permanent.getControllerId(), game)) { + if (sourceObject.equals(new MageObjectReference(event.getSourceId(), game))) { + redirectTarget = new TargetPermanent(); + redirectTarget.add(source.getSourceId(), game); + return event.getTargetId().equals(getTargetPointer().getFirst(game, source)); + } + } } return false; } diff --git a/Mage.Sets/src/mage/cards/s/ShieldmageAdvocate.java b/Mage.Sets/src/mage/cards/s/ShieldmageAdvocate.java new file mode 100644 index 0000000000..15022713e9 --- /dev/null +++ b/Mage.Sets/src/mage/cards/s/ShieldmageAdvocate.java @@ -0,0 +1,132 @@ +/* + * Copyright 2010 BetaSteward_at_googlemail.com. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are + * permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this list of + * conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, this list + * of conditions and the following disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY BetaSteward_at_googlemail.com ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BetaSteward_at_googlemail.com OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * The views and conclusions contained in the software and documentation are those of the + * authors and should not be interpreted as representing official policies, either expressed + * or implied, of BetaSteward_at_googlemail.com. + */ +package mage.cards.s; + +import java.util.UUID; +import mage.MageInt; +import mage.abilities.Ability; +import mage.abilities.common.SimpleActivatedAbility; +import mage.abilities.costs.common.TapSourceCost; +import mage.abilities.effects.Effect; +import mage.abilities.effects.PreventionEffectImpl; +import mage.abilities.effects.common.PreventDamageToTargetEffect; +import mage.abilities.effects.common.ReturnFromGraveyardToHandTargetEffect; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.Duration; +import mage.constants.SubType; +import mage.constants.Outcome; +import mage.constants.Zone; +import mage.filter.FilterCard; +import mage.filter.StaticFilters; +import mage.game.Game; +import mage.game.events.GameEvent; +import mage.target.TargetSource; +import mage.target.common.TargetCardInOpponentsGraveyard; +import mage.target.common.TargetCreatureOrPlayer; +import mage.target.targetpointer.SecondTargetPointer; + +/** + * + * @author L_J + */ +public class ShieldmageAdvocate extends CardImpl { + + public ShieldmageAdvocate(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{2}{W}"); + this.subtype.add(SubType.HUMAN); + this.subtype.add(SubType.CLERIC); + this.power = new MageInt(1); + this.toughness = new MageInt(3); + + // {tap}: Return target card from an opponent's graveyard to his or her hand. Prevent all damage that would be dealt to target creature or player this turn by a source of your choice. + Effect effect = new ReturnFromGraveyardToHandTargetEffect(); + effect.setText("Return target card from an opponent's graveyard to his or her hand"); + Ability ability = new SimpleActivatedAbility(Zone.BATTLEFIELD, effect, new TapSourceCost()); + + effect = new ShieldmageAdvocateEffect(); + effect.setTargetPointer(new SecondTargetPointer()); + ability.addEffect(effect); + ability.addTarget(new TargetCardInOpponentsGraveyard(1, 1, new FilterCard(), true)); + ability.addTarget(new TargetCreatureOrPlayer()); + this.addAbility(ability); + } + + public ShieldmageAdvocate(final ShieldmageAdvocate card) { + super(card); + } + + @Override + public ShieldmageAdvocate copy() { + return new ShieldmageAdvocate(this); + } +} + +class ShieldmageAdvocateEffect extends PreventionEffectImpl { + + protected final TargetSource targetSource; + + public ShieldmageAdvocateEffect() { + super(Duration.EndOfTurn, Integer.MAX_VALUE, false); + staticText = "Prevent all damage that would be dealt to target creature or player this turn by a source of your choice"; + this.targetSource = new TargetSource(); + } + + public ShieldmageAdvocateEffect(final ShieldmageAdvocateEffect effect) { + super(effect); + this.targetSource = effect.targetSource.copy(); + } + + @Override + public ShieldmageAdvocateEffect copy() { + return new ShieldmageAdvocateEffect(this); + } + + @Override + public void init(Ability source, Game game) { + this.targetSource.choose(Outcome.PreventDamage, source.getControllerId(), source.getSourceId(), game); + } + + @Override + public boolean replaceEvent(GameEvent event, Ability source, Game game) { + preventDamageAction(event, source, game); + return false; + } + + @Override + public boolean applies(GameEvent event, Ability source, Game game) { + if (super.applies(event, source, game)) { + if (event.getTargetId().equals(targetPointer.getFirst(game, source)) && event.getSourceId().equals(targetSource.getFirstTarget())) { + return true; + } + } + return false; + } + +} diff --git a/Mage.Sets/src/mage/cards/s/ShivanSandMage.java b/Mage.Sets/src/mage/cards/s/ShivanSandMage.java new file mode 100644 index 0000000000..7666241f03 --- /dev/null +++ b/Mage.Sets/src/mage/cards/s/ShivanSandMage.java @@ -0,0 +1,135 @@ +/* + * Copyright 2010 BetaSteward_at_googlemail.com. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are + * permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this list of + * conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, this list + * of conditions and the following disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY BetaSteward_at_googlemail.com ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BetaSteward_at_googlemail.com OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * The views and conclusions contained in the software and documentation are those of the + * authors and should not be interpreted as representing official policies, either expressed + * or implied, of BetaSteward_at_googlemail.com. + */ +package mage.cards.s; + +import java.util.UUID; +import mage.MageInt; +import mage.abilities.Ability; +import mage.abilities.Mode; +import mage.abilities.common.EntersBattlefieldTriggeredAbility; +import mage.abilities.costs.mana.ManaCostsImpl; +import mage.abilities.effects.OneShotEffect; +import mage.abilities.keyword.SuspendAbility; +import mage.cards.Card; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.SubType; +import mage.constants.Outcome; +import mage.counters.CounterType; +import mage.game.Game; +import mage.game.permanent.Permanent; +import mage.target.common.TargetPermanentOrSuspendedCard; + +/** + * + * @author L_J + */ +public class ShivanSandMage extends CardImpl { + + public ShivanSandMage(UUID ownerId, CardSetInfo setInfo) { + super(ownerId,setInfo,new CardType[]{CardType.CREATURE},"{2}{R}{R}"); + this.subtype.add(SubType.VIASHINO); + this.subtype.add(SubType.SHAMAN); + this.power = new MageInt(3); + this.toughness = new MageInt(2); + + // When Shivan Sand-Mage enters the battlefield, choose one — + // Remove two time counters from target permanent or suspended card. + Ability ability = new EntersBattlefieldTriggeredAbility(new ShivanSandMageEffect(false)); + ability.addTarget(new TargetPermanentOrSuspendedCard()); + + // Put two time counters on target permanent with a time counter on it or suspended card. + Mode mode = new Mode(); + mode.getEffects().add(new ShivanSandMageEffect(true)); + mode.getTargets().add(new TargetPermanentOrSuspendedCard()); + ability.addMode(mode); + ability.getModes().addMode(mode); + this.addAbility(ability); + + // Suspend 4-{R} + this.addAbility(new SuspendAbility(4, new ManaCostsImpl("{R}"), this)); + } + + public ShivanSandMage(final ShivanSandMage card) { + super(card); + } + + @Override + public ShivanSandMage copy() { + return new ShivanSandMage(this); + } +} + +class ShivanSandMageEffect extends OneShotEffect { + + private final boolean addCounters; + + public ShivanSandMageEffect(boolean addCounters) { + super(Outcome.Benefit); + this.addCounters = addCounters; + if (addCounters) { + this.staticText = "put two time counters on target permanent or suspended card"; + } else { + this.staticText = "remove two time counters from target permanent or suspended card"; + } + } + + public ShivanSandMageEffect(final ShivanSandMageEffect effect) { + super(effect); + this.addCounters = effect.addCounters; + } + + @Override + public ShivanSandMageEffect copy() { + return new ShivanSandMageEffect(this); + } + + @Override + public boolean apply(Game game, Ability source) { + Permanent permanent = game.getPermanent(this.getTargetPointer().getFirst(game, source)); + if (permanent != null) { + if (addCounters) { + permanent.addCounters(CounterType.TIME.createInstance(2), source, game); + } else { + permanent.removeCounters(CounterType.TIME.getName(), 2, game); + } + return true; + } + Card card = game.getCard(this.getTargetPointer().getFirst(game, source)); + if (card != null) { + if (addCounters) { + card.addCounters(CounterType.TIME.createInstance(2), source, game); + } else { + card.removeCounters(CounterType.TIME.getName(), 2, game); + } + return true; + } + return false; + } +} diff --git a/Mage.Sets/src/mage/cards/s/ShrivelingRot.java b/Mage.Sets/src/mage/cards/s/ShrivelingRot.java new file mode 100644 index 0000000000..55c7374342 --- /dev/null +++ b/Mage.Sets/src/mage/cards/s/ShrivelingRot.java @@ -0,0 +1,190 @@ +/* + * Copyright 2010 BetaSteward_at_googlemail.com. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are + * permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this list of + * conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, this list + * of conditions and the following disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY BetaSteward_at_googlemail.com ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BetaSteward_at_googlemail.com OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * The views and conclusions contained in the software and documentation are those of the + * authors and should not be interpreted as representing official policies, either expressed + * or implied, of BetaSteward_at_googlemail.com. + */ +package mage.cards.s; + +import java.util.UUID; +import mage.abilities.Ability; +import mage.abilities.DelayedTriggeredAbility; +import mage.abilities.Mode; +import mage.abilities.effects.OneShotEffect; +import mage.abilities.effects.Effect; +import mage.abilities.effects.common.CreateDelayedTriggeredAbilityEffect; +import mage.abilities.effects.common.DestroyTargetEffect; +import mage.abilities.keyword.EntwineAbility; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.Duration; +import mage.constants.Outcome; +import mage.constants.Zone; +import mage.game.Game; +import mage.game.events.GameEvent; +import mage.game.permanent.Permanent; +import mage.players.Player; +import mage.target.targetpointer.FixedTarget; +import mage.game.events.ZoneChangeEvent; + +/** + * + * @author L_J + */ +public class ShrivelingRot extends CardImpl { + + public ShrivelingRot(UUID ownerId, CardSetInfo setInfo) { + super(ownerId,setInfo,new CardType[]{CardType.INSTANT},"{2}{B}{B}"); + + // Choose one - + // Until end of turn, whenever a creature is dealt damage, destroy it. + this.getSpellAbility().addEffect(new CreateDelayedTriggeredAbilityEffect(new ShrivelingRotDestroyTriggeredAbility())); + // Until end of turn, whenever a creature dies, that creature's controller loses life equal to its toughness. + Mode mode = new Mode(); + mode.getEffects().add(new CreateDelayedTriggeredAbilityEffect(new ShrivelingRotLoseLifeTriggeredAbility())); + this.getSpellAbility().getModes().addMode(mode); + + // Entwine {2}{B} + this.addAbility(new EntwineAbility("{2}{B}")); + } + + public ShrivelingRot(final ShrivelingRot card) { + super(card); + } + + @Override + public ShrivelingRot copy() { + return new ShrivelingRot(this); + } +} + +class ShrivelingRotDestroyTriggeredAbility extends DelayedTriggeredAbility { + + ShrivelingRotDestroyTriggeredAbility() { + super(new DestroyTargetEffect(), Duration.EndOfTurn, false); + } + + ShrivelingRotDestroyTriggeredAbility(final ShrivelingRotDestroyTriggeredAbility ability) { + super(ability); + } + + @Override + public ShrivelingRotDestroyTriggeredAbility copy() { + return new ShrivelingRotDestroyTriggeredAbility(this); + } + + @Override + public boolean checkEventType(GameEvent event, Game game) { + return event.getType() == GameEvent.EventType.DAMAGED_CREATURE; + } + + @Override + public boolean checkTrigger(GameEvent event, Game game) { + for (Effect effect : this.getEffects()) { + effect.setTargetPointer(new FixedTarget(event.getTargetId())); + } + return true; + } + + @Override + public String getRule() { + return "Until end of turn, whenever a creature is dealt damage, destroy it."; + } +} + +class ShrivelingRotLoseLifeTriggeredAbility extends DelayedTriggeredAbility { + + ShrivelingRotLoseLifeTriggeredAbility() { + super(new ShrivelingRotEffect(), Duration.EndOfTurn, false); + } + + ShrivelingRotLoseLifeTriggeredAbility(final ShrivelingRotLoseLifeTriggeredAbility ability) { + super(ability); + } + + @Override + public ShrivelingRotLoseLifeTriggeredAbility copy() { + return new ShrivelingRotLoseLifeTriggeredAbility(this); + } + + @Override + public boolean checkEventType(GameEvent event, Game game) { + return event.getType() == GameEvent.EventType.ZONE_CHANGE; + } + + @Override + public boolean checkTrigger(GameEvent event, Game game) { + ZoneChangeEvent zEvent = (ZoneChangeEvent) event; + if (zEvent.getFromZone() == Zone.BATTLEFIELD && zEvent.getToZone() == Zone.GRAVEYARD) { + if (zEvent.getTarget().isCreature()) { + Effect effect = this.getEffects().get(0); + effect.setTargetPointer(new FixedTarget(event.getTargetId())); + return true; + } + } + return false; + } + + @Override + public String getRule() { + return "Until end of turn, whenever a creature dies, that creature's controller loses life equal to its toughness."; + } +} + +class ShrivelingRotEffect extends OneShotEffect { + + public ShrivelingRotEffect() { + super(Outcome.LoseLife); + staticText = "that creature's controller loses life equal to its toughness"; + } + + public ShrivelingRotEffect(final ShrivelingRotEffect effect) { + super(effect); + } + + @Override + public ShrivelingRotEffect copy() { + return new ShrivelingRotEffect(this); + } + + @Override + public boolean apply(Game game, Ability source) { + Permanent permanent = game.getPermanentOrLKIBattlefield(getTargetPointer().getFirst(game, source)); + if (permanent != null) { + if (permanent.getZoneChangeCounter(game) + 1 == game.getState().getZoneChangeCounter(permanent.getId()) + && !game.getState().getZone(permanent.getId()).equals(Zone.GRAVEYARD)) { + // A replacement effect has moved the card to another zone as graveyard + return true; + } + Player permanentController = game.getPlayer(permanent.getControllerId()); + if (permanentController != null) { + int amount = permanent.getToughness().getValue(); + permanentController.loseLife(amount, game, false); + return true; + } + } + return false; + } +} diff --git a/Mage.Sets/src/mage/cards/s/Shyft.java b/Mage.Sets/src/mage/cards/s/Shyft.java new file mode 100644 index 0000000000..ea0e075411 --- /dev/null +++ b/Mage.Sets/src/mage/cards/s/Shyft.java @@ -0,0 +1,96 @@ +/* + * Copyright 2010 BetaSteward_at_googlemail.com. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are + * permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this list of + * conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, this list + * of conditions and the following disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY BetaSteward_at_googlemail.com ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BetaSteward_at_googlemail.com OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * The views and conclusions contained in the software and documentation are those of the + * authors and should not be interpreted as representing official policies, either expressed + * or implied, of BetaSteward_at_googlemail.com. + */ +package mage.cards.s; + +import java.util.UUID; +import mage.MageInt; +import mage.abilities.Ability; +import mage.abilities.common.BeginningOfUpkeepTriggeredAbility; +import mage.abilities.effects.Effect; +import mage.abilities.effects.OneShotEffect; +import mage.abilities.effects.common.continuous.BecomesColorOrColorsTargetEffect; +import mage.constants.SubType; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.Duration; +import mage.constants.Outcome; +import mage.constants.TargetController; +import mage.game.Game; +import mage.target.targetpointer.FixedTarget; + +/** + * + * @author TheElk801 + */ +public class Shyft extends CardImpl { + + public Shyft(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{4}{U}"); + + this.subtype.add(SubType.SHAPESHIFTER); + this.power = new MageInt(4); + this.toughness = new MageInt(2); + + // At the beginning of your upkeep, you may have Shyft become the color or colors of your choice. + this.addAbility(new BeginningOfUpkeepTriggeredAbility(new ShyftEffect(), TargetController.YOU, true)); + } + + public Shyft(final Shyft card) { + super(card); + } + + @Override + public Shyft copy() { + return new Shyft(this); + } +} + +class ShyftEffect extends OneShotEffect { + + ShyftEffect() { + super(Outcome.Benefit); + this.staticText = "have {this} become the color or colors of your choice."; + } + + ShyftEffect(final ShyftEffect effect) { + super(effect); + } + + @Override + public ShyftEffect copy() { + return new ShyftEffect(this); + } + + @Override + public boolean apply(Game game, Ability source) { + Effect effect = new BecomesColorOrColorsTargetEffect(Duration.Custom); + effect.setTargetPointer(new FixedTarget(source.getSourceId(), source.getSourceObjectZoneChangeCounter())); + return effect.apply(game, source); + } +} diff --git a/Mage.Sets/src/mage/cards/s/SignalTheClans.java b/Mage.Sets/src/mage/cards/s/SignalTheClans.java index 2b9f3484e6..0fed43aa02 100644 --- a/Mage.Sets/src/mage/cards/s/SignalTheClans.java +++ b/Mage.Sets/src/mage/cards/s/SignalTheClans.java @@ -27,15 +27,10 @@ */ package mage.cards.s; -import java.util.List; -import java.util.UUID; +import mage.MageObject; import mage.abilities.Ability; import mage.abilities.effects.SearchEffect; -import mage.cards.Card; -import mage.cards.CardImpl; -import mage.cards.CardSetInfo; -import mage.cards.Cards; -import mage.cards.CardsImpl; +import mage.cards.*; import mage.constants.CardType; import mage.constants.Outcome; import mage.constants.Zone; @@ -44,6 +39,11 @@ import mage.game.Game; import mage.players.Player; import mage.target.common.TargetCardInLibrary; +import java.util.List; +import java.util.UUID; +import java.util.stream.Collectors; +import java.util.stream.Stream; + /** * * @author Plopman @@ -105,7 +105,7 @@ class SignalTheClansEffect extends SearchEffect { player.revealCards("Reveal", cards, game); Card cardsArray[] = cards.getCards(game).toArray(new Card[0]); //If you reveal three cards with different names - if(cardsArray.length == 3 && !cardsArray[0].getName().equals(cardsArray[1]) && !cardsArray[0].getName().equals(cardsArray[2]) && !cardsArray[1].getName().equals(cardsArray[2])){ + if(Stream.of(cardsArray).map(MageObject::getName).collect(Collectors.toSet()).size() == 3){ //Choose one of them at random and put that card into your hand Card randomCard = cards.getRandom(game); randomCard.moveToZone(Zone.HAND, source.getSourceId(), game, true); diff --git a/Mage.Sets/src/mage/cards/s/Skulduggery.java b/Mage.Sets/src/mage/cards/s/Skulduggery.java index 7690f8944c..b3d4dbf328 100644 --- a/Mage.Sets/src/mage/cards/s/Skulduggery.java +++ b/Mage.Sets/src/mage/cards/s/Skulduggery.java @@ -29,14 +29,14 @@ package mage.cards.s; import java.util.UUID; import mage.abilities.Ability; -import mage.abilities.effects.ContinuousEffectImpl; +import mage.abilities.effects.ContinuousEffect; +import mage.abilities.effects.OneShotEffect; +import mage.abilities.effects.common.continuous.BoostTargetEffect; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; import mage.constants.Duration; -import mage.constants.Layer; import mage.constants.Outcome; -import mage.constants.SubLayer; import mage.constants.TargetController; import mage.filter.common.FilterCreaturePermanent; import mage.filter.predicate.permanent.ControllerPredicate; @@ -44,6 +44,7 @@ import mage.game.Game; import mage.game.permanent.Permanent; import mage.target.common.TargetControlledCreaturePermanent; import mage.target.common.TargetCreaturePermanent; +import mage.target.targetpointer.FixedTarget; /** * @@ -76,10 +77,10 @@ public class Skulduggery extends CardImpl { } } -class SkulduggeryEffect extends ContinuousEffectImpl { +class SkulduggeryEffect extends OneShotEffect { public SkulduggeryEffect() { - super(Duration.EndOfTurn, Layer.PTChangingEffects_7, SubLayer.ModifyPT_7c, Outcome.BoostCreature); + super(Outcome.BoostCreature); this.staticText = "Until end of turn, target creature you control gets +1/+1 and target creature an opponent controls gets -1/-1"; } @@ -96,13 +97,15 @@ class SkulduggeryEffect extends ContinuousEffectImpl { public boolean apply(Game game, Ability source) { Permanent permanent = game.getPermanent(source.getFirstTarget()); if (permanent != null) { - permanent.addPower(1); - permanent.addToughness(1); + ContinuousEffect effect = new BoostTargetEffect(1, 1, Duration.EndOfTurn); + effect.setTargetPointer(new FixedTarget(permanent, game)); + game.addEffect(effect, source); } permanent = game.getPermanent(source.getTargets().get(1).getFirstTarget()); if (permanent != null) { - permanent.addPower(-1); - permanent.addToughness(-1); + ContinuousEffect effect = new BoostTargetEffect(-1, -1, Duration.EndOfTurn); + effect.setTargetPointer(new FixedTarget(permanent, game)); + game.addEffect(effect, source); } return true; } diff --git a/Mage.Sets/src/mage/cards/s/SnowFortress.java b/Mage.Sets/src/mage/cards/s/SnowFortress.java index 7ec925286b..1d58404c88 100644 --- a/Mage.Sets/src/mage/cards/s/SnowFortress.java +++ b/Mage.Sets/src/mage/cards/s/SnowFortress.java @@ -42,12 +42,10 @@ import mage.cards.CardSetInfo; import mage.constants.CardType; import mage.constants.Duration; import mage.constants.Zone; -import mage.filter.common.FilterAttackingCreature; import mage.filter.predicate.Predicates; import mage.filter.predicate.mageobject.AbilityPredicate; -import mage.game.Game; -import mage.game.permanent.Permanent; -import mage.target.common.TargetCreatureOrPlayer; +import mage.target.common.FilterCreatureAttackingYou; +import mage.target.common.TargetCreaturePermanent; /** * @@ -55,7 +53,7 @@ import mage.target.common.TargetCreatureOrPlayer; */ public class SnowFortress extends CardImpl { - private static final SnowFortressFilter filter = new SnowFortressFilter(); + private static final FilterCreatureAttackingYou filter = new FilterCreatureAttackingYou("creature without flying that's attacking you"); static { filter.add(Predicates.not(new AbilityPredicate(FlyingAbility.class))); @@ -79,7 +77,7 @@ public class SnowFortress extends CardImpl { // {3}: Snow Fortress deals 1 damage to target creature without flying that's attacking you. Ability ability = new SimpleActivatedAbility(Zone.BATTLEFIELD, new DamageTargetEffect(1), new GenericManaCost(3)); - ability.addTarget(new TargetCreatureOrPlayer()); + ability.addTarget(new TargetCreaturePermanent(filter)); this.addAbility(ability); } @@ -92,26 +90,3 @@ public class SnowFortress extends CardImpl { return new SnowFortress(this); } } - -class SnowFortressFilter extends FilterAttackingCreature { - - public SnowFortressFilter() { - super("creature without flying that's attacking you"); - } - - public SnowFortressFilter(final SnowFortressFilter filter) { - super(filter); - } - - @Override - public SnowFortressFilter copy() { - return new SnowFortressFilter(this); - } - - @Override - public boolean match(Permanent permanent, UUID sourceId, UUID playerId, Game game) { - return super.match(permanent, sourceId, playerId, game) - && permanent.isAttacking() // to prevent unneccessary combat checking if not attacking - && playerId.equals(game.getCombat().getDefenderId(permanent.getId())); - } -} diff --git a/Mage.Sets/src/mage/cards/s/SoulSnare.java b/Mage.Sets/src/mage/cards/s/SoulSnare.java index e68f31e8fa..984e93f80a 100644 --- a/Mage.Sets/src/mage/cards/s/SoulSnare.java +++ b/Mage.Sets/src/mage/cards/s/SoulSnare.java @@ -37,9 +37,7 @@ import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; import mage.constants.Zone; -import mage.filter.common.FilterAttackingCreature; -import mage.game.Game; -import mage.game.permanent.Permanent; +import mage.target.common.FilterCreatureAttackingYou; import mage.target.common.TargetCreaturePermanent; /** @@ -56,7 +54,7 @@ public class SoulSnare extends CardImpl { Ability ability = new SimpleActivatedAbility(Zone.BATTLEFIELD, new ExileTargetEffect(), new ManaCostsImpl("{W}")); ability.addCost(new SacrificeSourceCost()); - ability.addTarget(new TargetCreaturePermanent(new SoulSnareFilter())); + ability.addTarget(new TargetCreaturePermanent(new FilterCreatureAttackingYou(true))); this.addAbility(ability); } @@ -69,25 +67,3 @@ public class SoulSnare extends CardImpl { return new SoulSnare(this); } } - -class SoulSnareFilter extends FilterAttackingCreature { - - public SoulSnareFilter() { - super("creature that's attacking you or a planeswalker you control"); - } - - public SoulSnareFilter(final SoulSnareFilter filter) { - super(filter); - } - - @Override - public SoulSnareFilter copy() { - return new SoulSnareFilter(this); - } - - @Override - public boolean match(Permanent permanent, UUID sourceId, UUID playerId, Game game) { - return super.match(permanent, sourceId, playerId, game) - && playerId.equals(game.getCombat().getDefendingPlayerId(permanent.getId(), game)); - } -} diff --git a/Mage.Sets/src/mage/cards/s/SporeCloud.java b/Mage.Sets/src/mage/cards/s/SporeCloud.java new file mode 100644 index 0000000000..38dbaaf8c7 --- /dev/null +++ b/Mage.Sets/src/mage/cards/s/SporeCloud.java @@ -0,0 +1,123 @@ +/* + * Copyright 2010 BetaSteward_at_googlemail.com. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are + * permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this list of + * conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, this list + * of conditions and the following disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY BetaSteward_at_googlemail.com ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BetaSteward_at_googlemail.com OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * The views and conclusions contained in the software and documentation are those of the + * authors and should not be interpreted as representing official policies, either expressed + * or implied, of BetaSteward_at_googlemail.com. + */ +package mage.cards.s; + +import java.util.ArrayList; +import java.util.List; +import java.util.UUID; +import mage.abilities.Ability; +import mage.abilities.effects.ContinuousEffect; +import mage.abilities.effects.OneShotEffect; +import mage.abilities.effects.common.DontUntapInControllersNextUntapStepTargetEffect; +import mage.abilities.effects.common.PreventAllDamageByAllPermanentsEffect; +import mage.abilities.effects.common.TapAllEffect; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.Duration; +import mage.constants.Outcome; +import mage.filter.common.FilterCreaturePermanent; +import mage.filter.predicate.Predicates; +import mage.filter.predicate.permanent.AttackingPredicate; +import mage.filter.predicate.permanent.BlockingPredicate; +import mage.game.Game; +import mage.game.permanent.Permanent; +import mage.players.Player; +import mage.target.targetpointer.FixedTargets; + +/** + * + * @author L_J + */ +public class SporeCloud extends CardImpl { + + private static final FilterCreaturePermanent filter = new FilterCreaturePermanent("blocking creatures"); + static { + filter.add(new BlockingPredicate()); + } + + public SporeCloud(UUID ownerId, CardSetInfo setInfo) { + super(ownerId,setInfo,new CardType[]{CardType.INSTANT},"{1}{G}{G}"); + + // Tap all blocking creatures. + this.getSpellAbility().addEffect(new TapAllEffect(filter)); + // Prevent all combat damage that would be dealt this turn. + this.getSpellAbility().addEffect(new PreventAllDamageByAllPermanentsEffect(Duration.EndOfTurn, true)); + // Each attacking creature and each blocking creature doesn't untap during its controller's next untap step. + this.getSpellAbility().addEffect(new SporeCloudEffect()); + } + + public SporeCloud(final SporeCloud card) { + super(card); + } + + @Override + public SporeCloud copy() { + return new SporeCloud(this); + } +} + +class SporeCloudEffect extends OneShotEffect { + + private static final FilterCreaturePermanent filter = new FilterCreaturePermanent("Each attacking creature and each blocking creature"); + static { + filter.add(Predicates.or(new AttackingPredicate(), new BlockingPredicate())); + } + + public SporeCloudEffect() { + super(Outcome.Benefit); + this.staticText = "Each attacking creature and each blocking creature doesn't untap during its controller's next untap step"; + } + + public SporeCloudEffect(final SporeCloudEffect effect) { + super(effect); + } + + @Override + public SporeCloudEffect copy() { + return new SporeCloudEffect(this); + } + + @Override + public boolean apply(Game game, Ability source) { + Player controller = game.getPlayer(source.getControllerId()); + if (controller != null) { + List doNotUntapNextUntapStep = new ArrayList<>(); + for (Permanent permanent : game.getBattlefield().getActivePermanents(filter, source.getControllerId(), source.getSourceId(), game)) { + doNotUntapNextUntapStep.add(permanent); + } + if (!doNotUntapNextUntapStep.isEmpty()) { + ContinuousEffect effect = new DontUntapInControllersNextUntapStepTargetEffect("This creature"); + effect.setTargetPointer(new FixedTargets(doNotUntapNextUntapStep, game)); + game.addEffect(effect, source); + } + return true; + } + return false; + } +} diff --git a/Mage.Sets/src/mage/cards/s/StalkingLeonin.java b/Mage.Sets/src/mage/cards/s/StalkingLeonin.java index c917e94728..a181a42116 100644 --- a/Mage.Sets/src/mage/cards/s/StalkingLeonin.java +++ b/Mage.Sets/src/mage/cards/s/StalkingLeonin.java @@ -44,10 +44,10 @@ import mage.constants.CardType; import mage.constants.Outcome; import mage.constants.SubType; import mage.constants.Zone; -import mage.filter.common.FilterAttackingCreature; import mage.game.Game; import mage.game.permanent.Permanent; import mage.players.Player; +import mage.target.common.FilterCreatureAttackingYou; import mage.target.common.TargetCreaturePermanent; import mage.target.common.TargetOpponent; import mage.util.CardUtil; @@ -72,7 +72,7 @@ public class StalkingLeonin extends CardImpl { this.addAbility(new EntersBattlefieldTriggeredAbility(new StalkingLeoninChooseOpponent(), false)); // Reveal the player you chose: Exile target creature that's attacking you if it's controlled by the chosen player. Activate this ability only once. Ability ability = new SimpleActivatedAbility(Zone.BATTLEFIELD, new StalkingLeoninEffect(), new StalkingLeoninRevealOpponentCost()); - ability.addTarget(new TargetCreaturePermanent(new StalkingLeoninFilter())); + ability.addTarget(new TargetCreaturePermanent(new FilterCreatureAttackingYou())); this.addAbility(ability); } @@ -217,25 +217,3 @@ class StalkingLeoninEffect extends OneShotEffect { return false; } } - -class StalkingLeoninFilter extends FilterAttackingCreature { - - public StalkingLeoninFilter() { - super("creature that's attacking you"); - } - - public StalkingLeoninFilter(final StalkingLeoninFilter filter) { - super(filter); - } - - @Override - public StalkingLeoninFilter copy() { - return new StalkingLeoninFilter(this); - } - - @Override - public boolean match(Permanent permanent, UUID sourceId, UUID playerId, Game game) { - return super.match(permanent, sourceId, playerId, game) - && playerId.equals(game.getCombat().getDefenderId(permanent.getId())); - } -} diff --git a/Mage.Sets/src/mage/cards/s/SteamVines.java b/Mage.Sets/src/mage/cards/s/SteamVines.java new file mode 100644 index 0000000000..514159305a --- /dev/null +++ b/Mage.Sets/src/mage/cards/s/SteamVines.java @@ -0,0 +1,142 @@ +/* + * Copyright 2010 BetaSteward_at_googlemail.com. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are + * permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this list of + * conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, this list + * of conditions and the following disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY BetaSteward_at_googlemail.com ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BetaSteward_at_googlemail.com OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * The views and conclusions contained in the software and documentation are those of the + * authors and should not be interpreted as representing official policies, either expressed + * or implied, of BetaSteward_at_googlemail.com. + */ +package mage.cards.s; + +import java.util.UUID; +import mage.abilities.Ability; +import mage.abilities.common.BecomesTappedAttachedTriggeredAbility; +import mage.abilities.effects.OneShotEffect; +import mage.abilities.effects.common.AttachEffect; +import mage.abilities.keyword.EnchantAbility; +import mage.cards.Card; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.SubType; +import mage.constants.Outcome; +import mage.constants.Zone; +import mage.filter.Filter; +import mage.game.Game; +import mage.game.permanent.Permanent; +import mage.players.Player; +import mage.target.Target; +import mage.target.TargetPermanent; +import mage.target.common.TargetLandPermanent; + +/** + * + * @author jeffwadsworth & L_J + */ +public class SteamVines extends CardImpl { + + public SteamVines(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.ENCHANTMENT}, "{1}{R}{R}"); + this.subtype.add(SubType.AURA); + + // Enchant land + TargetPermanent auraTarget = new TargetLandPermanent(); + this.getSpellAbility().addTarget(auraTarget); + this.getSpellAbility().addEffect(new AttachEffect(Outcome.BoostCreature)); + Ability ability = new EnchantAbility(auraTarget.getTargetName()); + this.addAbility(ability); + + // When enchanted land becomes tapped, destroy it and Steam Vines deals 1 damage to that land's controller. That player attaches Steam Vines to a land of his or her choice. + this.addAbility(new BecomesTappedAttachedTriggeredAbility(new SteamVinesEffect(), "enchanted land")); + + } + + public SteamVines(final SteamVines card) { + super(card); + } + + @Override + public SteamVines copy() { + return new SteamVines(this); + } +} + +class SteamVinesEffect extends OneShotEffect { + + public SteamVinesEffect() { + super(Outcome.Detriment); + staticText = "destroy it and {this} deals 1 damage to that land's controller. That player attaches {this} to a land of his or her choice"; + } + + public SteamVinesEffect(final SteamVinesEffect effect) { + super(effect); + } + + @Override + public SteamVinesEffect copy() { + return new SteamVinesEffect(this); + } + + @Override + public boolean apply(Game game, Ability source) { + Permanent kudzu = game.getPermanentOrLKIBattlefield(source.getSourceId()); + Card kudzuCard = game.getCard(source.getSourceId()); + if (kudzu != null) { + Permanent enchantedLand = game.getPermanentOrLKIBattlefield(kudzu.getAttachedTo()); + Player controller = game.getPlayer(source.getControllerId()); + if (enchantedLand != null + && controller != null) { + Player landsController = game.getPlayer(enchantedLand.getControllerId()); + if (game.getState().getZone(enchantedLand.getId()) == Zone.BATTLEFIELD) { // if 2 or more Steam Vines were on a land + enchantedLand.destroy(source.getId(), game, false); + landsController.damage(1, source.getSourceId(), game, false, true); + } + if (!game.getBattlefield().getAllActivePermanents(CardType.LAND).isEmpty()) { //lands are available on the battlefield + Target target = new TargetLandPermanent(); + target.setNotTarget(true); //not a target, it is chosen + if (kudzuCard != null + && landsController != null) { + if (landsController.choose(Outcome.Detriment, target, source.getId(), game)) { + if (target.getFirstTarget() != null) { + Permanent landChosen = game.getPermanent(target.getFirstTarget()); + if (landChosen != null) { + for (Target targetTest : kudzuCard.getSpellAbility().getTargets()) { + Filter filterTest = targetTest.getFilter(); + if (filterTest.match(landChosen, game)) { + if (game.getBattlefield().containsPermanent(landChosen.getId())) { //verify that it is still on the battlefield + game.getState().setValue("attachTo:" + kudzuCard.getId(), landChosen); + Zone zone = game.getState().getZone(kudzuCard.getId()); + kudzuCard.putOntoBattlefield(game, zone, source.getSourceId(), controller.getId()); + return landChosen.addAttachment(kudzuCard.getId(), game); + } + } + } + } + } + } + } + } + } + } + return false; + } +} diff --git a/Mage.Sets/src/mage/cards/s/SuleimansLegacy.java b/Mage.Sets/src/mage/cards/s/SuleimansLegacy.java new file mode 100644 index 0000000000..5bb92a92e6 --- /dev/null +++ b/Mage.Sets/src/mage/cards/s/SuleimansLegacy.java @@ -0,0 +1,81 @@ +/* + * Copyright 2010 BetaSteward_at_googlemail.com. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are + * permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this list of + * conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, this list + * of conditions and the following disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY BetaSteward_at_googlemail.com ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BetaSteward_at_googlemail.com OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * The views and conclusions contained in the software and documentation are those of the + * authors and should not be interpreted as representing official policies, either expressed + * or implied, of BetaSteward_at_googlemail.com. + */ +package mage.cards.s; + +import java.util.UUID; +import mage.abilities.common.EntersBattlefieldAllTriggeredAbility; +import mage.abilities.common.EntersBattlefieldTriggeredAbility; +import mage.abilities.effects.common.DestroyAllEffect; +import mage.abilities.effects.common.DestroyTargetEffect; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.SetTargetPointer; +import mage.constants.SubType; +import mage.constants.Zone; +import mage.filter.FilterPermanent; +import mage.filter.predicate.Predicates; +import mage.filter.predicate.mageobject.SubtypePredicate; + +/** + * + * @author TheElk801 + */ +public class SuleimansLegacy extends CardImpl { + + private static final FilterPermanent filter = new FilterPermanent("Djinns and Efreets"); + + static { + filter.add(Predicates.or( + new SubtypePredicate(SubType.DJINN), + new SubtypePredicate(SubType.EFREET) + )); + } + + public SuleimansLegacy(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.ENCHANTMENT}, "{R}{W}"); + + // When Suleiman's Legacy enters the battlefield, destroy all Djinns and Efreets. They can't be regenerated. + this.addAbility(new EntersBattlefieldTriggeredAbility(new DestroyAllEffect(filter, true))); + + // Whenever a Djinn or Efreet enters the battlefield, destroy it. It can't be regenerated. + this.addAbility(new EntersBattlefieldAllTriggeredAbility( + Zone.BATTLEFIELD, new DestroyTargetEffect(true), filter, false, SetTargetPointer.PERMANENT, + "Whenever a Djinn or Efreet enters the battlefield, destroy it. It can't be regenerated." + )); + } + + public SuleimansLegacy(final SuleimansLegacy card) { + super(card); + } + + @Override + public SuleimansLegacy copy() { + return new SuleimansLegacy(this); + } +} diff --git a/Mage.Sets/src/mage/cards/s/SurpriseDeployment.java b/Mage.Sets/src/mage/cards/s/SurpriseDeployment.java new file mode 100644 index 0000000000..6eafd6e076 --- /dev/null +++ b/Mage.Sets/src/mage/cards/s/SurpriseDeployment.java @@ -0,0 +1,132 @@ +/* + * Copyright 2010 BetaSteward_at_googlemail.com. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are + * permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this list of + * conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, this list + * of conditions and the following disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY BetaSteward_at_googlemail.com ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BetaSteward_at_googlemail.com OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * The views and conclusions contained in the software and documentation are those of the + * authors and should not be interpreted as representing official policies, either expressed + * or implied, of BetaSteward_at_googlemail.com. + */ +package mage.cards.s; + +import java.util.UUID; +import mage.ObjectColor; +import mage.abilities.Ability; +import mage.abilities.DelayedTriggeredAbility; +import mage.abilities.common.CastOnlyDuringPhaseStepSourceAbility; +import mage.abilities.common.delayed.AtTheBeginOfNextEndStepDelayedTriggeredAbility; +import mage.abilities.effects.OneShotEffect; +import mage.abilities.effects.common.ReturnToHandTargetEffect; +import mage.cards.Card; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.Duration; +import mage.constants.Outcome; +import mage.constants.TurnPhase; +import mage.constants.Zone; +import mage.filter.common.FilterCreatureCard; +import mage.filter.predicate.Predicates; +import mage.filter.predicate.mageobject.ColorPredicate; +import mage.game.Game; +import mage.game.permanent.Permanent; +import mage.players.Player; +import mage.target.common.TargetCardInHand; +import mage.target.targetpointer.FixedTarget; + +/** + * + * @author L_J + */ +public class SurpriseDeployment extends CardImpl { + + public SurpriseDeployment(UUID ownerId, CardSetInfo setInfo) { + super(ownerId,setInfo,new CardType[]{CardType.INSTANT},"{3}{W}"); + + // Cast Surprise Deployment only during combat. + this.addAbility(new CastOnlyDuringPhaseStepSourceAbility(TurnPhase.COMBAT)); + + // You may put a nonwhite creature card from your hand onto the battlefield. At the beginning of the next end step, return that creature to your hand. (Return it only if it's on the battlefield.) + this.getSpellAbility().addEffect(new SurpriseDeploymentEffect()); + } + + public SurpriseDeployment(final SurpriseDeployment card) { + super(card); + } + + @Override + public SurpriseDeployment copy() { + return new SurpriseDeployment(this); + } +} + +class SurpriseDeploymentEffect extends OneShotEffect { + + private static final String choiceText = "Put a nonwhite creature card from your hand onto the battlefield?"; + + private static final FilterCreatureCard filter = new FilterCreatureCard(); + + static { + filter.add(Predicates.not(new ColorPredicate(ObjectColor.WHITE))); + } + + public SurpriseDeploymentEffect() { + super(Outcome.Benefit); + this.staticText = "You may put a nonwhite creature card from your hand onto the battlefield. At the beginning of the next end step, return that creature to your hand"; + } + + public SurpriseDeploymentEffect(final SurpriseDeploymentEffect effect) { + super(effect); + } + + @Override + public SurpriseDeploymentEffect copy() { + return new SurpriseDeploymentEffect(this); + } + + @Override + public boolean apply(Game game, Ability source) { + Player controller = game.getPlayer(source.getControllerId()); + if (controller != null) { + if (controller.chooseUse(Outcome.PutCreatureInPlay, choiceText, source, game)) { + TargetCardInHand target = new TargetCardInHand(filter); + if (controller.choose(Outcome.PutCreatureInPlay, target, source.getSourceId(), game)) { + Card card = game.getCard(target.getFirstTarget()); + if (card != null) { + if (controller.moveCards(card, Zone.BATTLEFIELD, source, game)) { + Permanent permanent = game.getPermanent(card.getId()); + if (permanent != null) { + ReturnToHandTargetEffect effect = new ReturnToHandTargetEffect(); + effect.setTargetPointer(new FixedTarget(permanent, game)); + DelayedTriggeredAbility delayedAbility = new AtTheBeginOfNextEndStepDelayedTriggeredAbility(effect); + game.addDelayedTriggeredAbility(delayedAbility, source); + return true; + } + } + } + return false; + } + } + return true; + } + return false; + } +} diff --git a/Mage.Sets/src/mage/cards/t/TalonOfPain.java b/Mage.Sets/src/mage/cards/t/TalonOfPain.java new file mode 100644 index 0000000000..f9ddad3377 --- /dev/null +++ b/Mage.Sets/src/mage/cards/t/TalonOfPain.java @@ -0,0 +1,199 @@ +/* + * Copyright 2010 BetaSteward_at_googlemail.com. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are + * permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this list of + * conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, this list + * of conditions and the following disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY BetaSteward_at_googlemail.com ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BetaSteward_at_googlemail.com OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * The views and conclusions contained in the software and documentation are those of the + * authors and should not be interpreted as representing official policies, either expressed + * or implied, of BetaSteward_at_googlemail.com. + */ +package mage.cards.t; + +import java.util.UUID; +import mage.abilities.Ability; +import mage.abilities.TriggeredAbilityImpl; +import mage.abilities.common.SimpleActivatedAbility; +import mage.abilities.costs.Cost; +import mage.abilities.costs.VariableCostImpl; +import mage.abilities.costs.common.RemoveCountersSourceCost; +import mage.abilities.costs.common.TapSourceCost; +import mage.abilities.costs.mana.ManaCostsImpl; +import mage.abilities.dynamicvalue.common.ManacostVariableValue; +import mage.abilities.effects.common.DamageTargetEffect; +import mage.abilities.effects.common.counter.AddCountersSourceEffect; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.Zone; +import mage.counters.Counter; +import mage.counters.CounterType; +import mage.game.Game; +import mage.game.events.GameEvent; +import mage.game.permanent.Permanent; +import mage.players.Player; +import mage.target.common.TargetCreatureOrPlayer; + +/** + * + * @author jerekwilson + */ +public class TalonOfPain extends CardImpl { + + public TalonOfPain(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.ARTIFACT}, "{4}"); + + + /* + * Whenever a source you control other than Talon of Pain deals damage to an opponent, + * put a charge counter on Talon of Pain. + */ + this.addAbility(new TalonOfPainTriggeredAbility()); + + // {X}, {T}, Remove X charge counters from Talon of Pain: Talon of Pain deals X damage to target creature or player. + Ability ability = new SimpleActivatedAbility(Zone.BATTLEFIELD, new DamageTargetEffect(new ManacostVariableValue()), new ManaCostsImpl("{X}")); + ability.addCost(new TapSourceCost()); + ability.addCost(new TalonOfPainRemoveVariableCountersSourceCost(CounterType.CHARGE.createInstance())); + ability.addTarget(new TargetCreatureOrPlayer()); + this.addAbility(ability); + + } + + public TalonOfPain(final TalonOfPain card) { + super(card); + } + + @Override + public TalonOfPain copy() { + return new TalonOfPain(this); + } + + private class TalonOfPainTriggeredAbility extends TriggeredAbilityImpl { + + public TalonOfPainTriggeredAbility() { + super(Zone.BATTLEFIELD, new AddCountersSourceEffect(CounterType.CHARGE.createInstance())); + } + + public TalonOfPainTriggeredAbility(final TalonOfPainTriggeredAbility ability) { + super(ability); + } + + @Override + public TalonOfPainTriggeredAbility copy() { + return new TalonOfPainTriggeredAbility(this); + } + + @Override + public boolean checkEventType(GameEvent event, Game game) { + return event.getType() == GameEvent.EventType.DAMAGED_PLAYER; + } + + @Override + public boolean checkTrigger(GameEvent event, Game game) { + // to another player + Player controller = game.getPlayer(this.getControllerId()); + if (controller == null) { + return false; + } + if (controller.hasOpponent(event.getTargetId(), game)) { + // a source you control other than Talon of Pain + UUID sourceControllerId = game.getControllerId(event.getSourceId()); + if (sourceControllerId != null + && sourceControllerId.equals(this.getControllerId()) + && this.getSourceId() != event.getSourceId()) { + // return true so the effect will fire and a charge counter will be added + return true; + } + } + return false; + } + + @Override + public String getRule() { + return "Whenever a source you control other than {this} deals damage to an opponent, " + super.getRule(); + } + } +} + +class TalonOfPainRemoveVariableCountersSourceCost extends VariableCostImpl { + + protected int minimalCountersToPay = 0; + private String counterName; + + public TalonOfPainRemoveVariableCountersSourceCost(Counter counter) { + this(counter, 0); + } + + public TalonOfPainRemoveVariableCountersSourceCost(Counter counter, String text) { + this(counter, 0, text); + } + + public TalonOfPainRemoveVariableCountersSourceCost(Counter counter, int minimalCountersToPay) { + this(counter, minimalCountersToPay, ""); + } + + public TalonOfPainRemoveVariableCountersSourceCost(Counter counter, int minimalCountersToPay, String text) { + super(counter.getName() + " counters to remove"); + this.minimalCountersToPay = minimalCountersToPay; + this.counterName = counter.getName(); + if (text == null || text.isEmpty()) { + this.text = "Remove X " + counterName + " counters from {this}"; + } else { + this.text = text; + } + } + + public TalonOfPainRemoveVariableCountersSourceCost(final TalonOfPainRemoveVariableCountersSourceCost cost) { + super(cost); + this.minimalCountersToPay = cost.minimalCountersToPay; + this.counterName = cost.counterName; + } + + @Override + public TalonOfPainRemoveVariableCountersSourceCost copy() { + return new TalonOfPainRemoveVariableCountersSourceCost(this); + } + + @Override + public Cost getFixedCostsFromAnnouncedValue(int xValue) { + return new RemoveCountersSourceCost(new Counter(counterName, xValue)); + } + + @Override + public int getMinValue(Ability source, Game game) { + return minimalCountersToPay; + } + + @Override + public int getMaxValue(Ability source, Game game) { + int maxValue = 0; + Permanent permanent = game.getPermanent(source.getSourceId()); + if (permanent != null) { + maxValue = permanent.getCounters(game).getCount(counterName); + } + return maxValue; + } + + @Override + public int announceXValue(Ability source, Game game) { + return source.getManaCostsToPay().getX(); + } + +} diff --git a/Mage.Sets/src/mage/cards/t/Taniwha.java b/Mage.Sets/src/mage/cards/t/Taniwha.java index ac9524bd13..6e7897ec3c 100644 --- a/Mage.Sets/src/mage/cards/t/Taniwha.java +++ b/Mage.Sets/src/mage/cards/t/Taniwha.java @@ -27,11 +27,14 @@ */ package mage.cards.t; +import java.util.ArrayList; +import java.util.List; import java.util.UUID; import mage.MageInt; import mage.abilities.Ability; import mage.abilities.common.BeginningOfUpkeepTriggeredAbility; import mage.abilities.effects.OneShotEffect; +import mage.abilities.effects.common.PhaseOutAllEffect; import mage.abilities.keyword.PhasingAbility; import mage.abilities.keyword.TrampleAbility; import mage.cards.CardImpl; @@ -41,6 +44,7 @@ import mage.constants.SubType; import mage.constants.Outcome; import mage.constants.SuperType; import mage.constants.TargetController; +import mage.filter.StaticFilters; import mage.filter.common.FilterControlledLandPermanent; import mage.game.Game; import mage.game.permanent.Permanent; @@ -53,7 +57,7 @@ import mage.players.Player; public class Taniwha extends CardImpl { public Taniwha(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.CREATURE},"{3}{U}{U}"); + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{3}{U}{U}"); addSuperType(SuperType.LEGENDARY); this.subtype.add(SubType.SERPENT); this.power = new MageInt(7); @@ -61,10 +65,10 @@ public class Taniwha extends CardImpl { // Trample this.addAbility(TrampleAbility.getInstance()); - + // Phasing this.addAbility(PhasingAbility.getInstance()); - + // At the beginning of your upkeep, all lands you control phase out. this.addAbility(new BeginningOfUpkeepTriggeredAbility(new TaniwhaEffect(), TargetController.YOU, false)); } @@ -99,10 +103,11 @@ class TaniwhaEffect extends OneShotEffect { public boolean apply(Game game, Ability source) { Player controller = game.getPlayer(source.getControllerId()); if (controller != null) { + List permIds = new ArrayList<>(); for (Permanent permanent : game.getBattlefield().getActivePermanents(new FilterControlledLandPermanent(), controller.getId(), game)) { - permanent.phaseOut(game); + permIds.add(permanent.getId()); } - return true; + return new PhaseOutAllEffect(permIds).apply(game, source); } return false; } diff --git a/Mage.Sets/src/mage/cards/t/TeferisProtection.java b/Mage.Sets/src/mage/cards/t/TeferisProtection.java index a08ad3ba12..98701104c9 100644 --- a/Mage.Sets/src/mage/cards/t/TeferisProtection.java +++ b/Mage.Sets/src/mage/cards/t/TeferisProtection.java @@ -27,11 +27,14 @@ */ package mage.cards.t; +import java.util.ArrayList; +import java.util.List; import java.util.UUID; import mage.MageObject; import mage.abilities.Ability; import mage.abilities.effects.OneShotEffect; import mage.abilities.effects.common.ExileSpellEffect; +import mage.abilities.effects.common.PhaseOutAllEffect; import mage.abilities.effects.common.continuous.GainAbilityControllerEffect; import mage.abilities.effects.common.continuous.LifeTotalCantChangeControllerEffect; import mage.abilities.keyword.ProtectionAbility; @@ -170,10 +173,11 @@ class TeferisProtectionPhaseOutEffect extends OneShotEffect { public boolean apply(Game game, Ability source) { Player controller = game.getPlayer(source.getControllerId()); if (controller != null) { + List permIds = new ArrayList<>(); for (Permanent permanent : game.getBattlefield().getActivePermanents(StaticFilters.FILTER_CONTROLLED_PERMANENT, controller.getId(), game)) { - permanent.phaseOut(game); + permIds.add(permanent.getId()); } - return true; + return new PhaseOutAllEffect(permIds).apply(game, source); } return false; } diff --git a/Mage.Sets/src/mage/cards/t/TeferisRealm.java b/Mage.Sets/src/mage/cards/t/TeferisRealm.java index d74b69fcb1..da7adaa853 100644 --- a/Mage.Sets/src/mage/cards/t/TeferisRealm.java +++ b/Mage.Sets/src/mage/cards/t/TeferisRealm.java @@ -27,6 +27,7 @@ */ package mage.cards.t; +import java.util.ArrayList; import mage.abilities.Ability; import mage.abilities.common.BeginningOfUpkeepTriggeredAbility; import mage.abilities.effects.OneShotEffect; @@ -45,8 +46,11 @@ import mage.game.permanent.Permanent; import mage.players.Player; import java.util.HashSet; +import java.util.List; import java.util.Set; import java.util.UUID; +import mage.abilities.effects.common.PhaseOutAllEffect; +import mage.filter.common.FilterControlledLandPermanent; /** * @@ -55,7 +59,7 @@ import java.util.UUID; public class TeferisRealm extends CardImpl { public TeferisRealm(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.ENCHANTMENT},"{1}{U}{U}"); + super(ownerId, setInfo, new CardType[]{CardType.ENCHANTMENT}, "{1}{U}{U}"); addSuperType(SuperType.WORLD); // At the beginning of each player's upkeep, that player chooses artifact, creature, land, or non-Aura enchantment. All nontoken permanents of that type phase out. @@ -135,10 +139,11 @@ class TeferisRealmEffect extends OneShotEffect { return false; } game.informPlayers(player.getLogName() + " chooses " + choosenType + "s to phase out"); + List permIds = new ArrayList<>(); for (Permanent permanent : game.getBattlefield().getActivePermanents(filter, controller.getId(), game)) { - permanent.phaseOut(game); + permIds.add(permanent.getId()); } - return true; + return new PhaseOutAllEffect(permIds).apply(game, source); } return false; } diff --git a/Mage.Sets/src/mage/cards/t/Teleport.java b/Mage.Sets/src/mage/cards/t/Teleport.java new file mode 100644 index 0000000000..3fea5398ba --- /dev/null +++ b/Mage.Sets/src/mage/cards/t/Teleport.java @@ -0,0 +1,64 @@ +/* + * Copyright 2010 BetaSteward_at_googlemail.com. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are + * permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this list of + * conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, this list + * of conditions and the following disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY BetaSteward_at_googlemail.com ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BetaSteward_at_googlemail.com OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * The views and conclusions contained in the software and documentation are those of the + * authors and should not be interpreted as representing official policies, either expressed + * or implied, of BetaSteward_at_googlemail.com. + */ +package mage.cards.t; + +import java.util.UUID; +import mage.abilities.common.CastOnlyDuringPhaseStepSourceAbility; +import mage.abilities.effects.common.combat.CantBeBlockedTargetEffect; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.PhaseStep; +import mage.target.common.TargetCreaturePermanent; + +/** + * + * @author L_J + */ +public class Teleport extends CardImpl { + + public Teleport(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.INSTANT}, "{U}{U}{U}"); + + // Cast Teleport only during the declare attackers step. + this.addAbility(new CastOnlyDuringPhaseStepSourceAbility(null, PhaseStep.DECLARE_ATTACKERS, null, "Cast Teleport only during the declare attackers step")); + + // Target creature can't be blocked this turn. + this.getSpellAbility().addEffect(new CantBeBlockedTargetEffect()); + this.getSpellAbility().addTarget(new TargetCreaturePermanent()); + } + + public Teleport(final Teleport card) { + super(card); + } + + @Override + public Teleport copy() { + return new Teleport(this); + } +} diff --git a/Mage.Sets/src/mage/cards/t/TimeElemental.java b/Mage.Sets/src/mage/cards/t/TimeElemental.java new file mode 100644 index 0000000000..62dc23201d --- /dev/null +++ b/Mage.Sets/src/mage/cards/t/TimeElemental.java @@ -0,0 +1,92 @@ +/* + * Copyright 2010 BetaSteward_at_googlemail.com. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are + * permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this list of + * conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, this list + * of conditions and the following disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY BetaSteward_at_googlemail.com ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BetaSteward_at_googlemail.com OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * The views and conclusions contained in the software and documentation are those of the + * authors and should not be interpreted as representing official policies, either expressed + * or implied, of BetaSteward_at_googlemail.com. + */ +package mage.cards.t; + +import java.util.UUID; +import mage.MageInt; +import mage.abilities.Ability; +import mage.abilities.DelayedTriggeredAbility; +import mage.abilities.common.AttacksOrBlocksTriggeredAbility; +import mage.abilities.common.SimpleActivatedAbility; +import mage.abilities.common.delayed.AtTheEndOfCombatDelayedTriggeredAbility; +import mage.abilities.costs.common.TapSourceCost; +import mage.abilities.costs.mana.ManaCostsImpl; +import mage.abilities.effects.Effect; +import mage.abilities.effects.common.CreateDelayedTriggeredAbilityEffect; +import mage.abilities.effects.common.DamageControllerEffect; +import mage.abilities.effects.common.ReturnToHandTargetEffect; +import mage.abilities.effects.common.SacrificeSourceEffect; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.SubType; +import mage.constants.Zone; +import mage.filter.FilterPermanent; +import mage.filter.predicate.Predicates; +import mage.filter.predicate.permanent.EnchantedPredicate; +import mage.target.TargetPermanent; + +/** + * + * @author L_J + */ +public class TimeElemental extends CardImpl { + + private static final FilterPermanent filter = new FilterPermanent("permanent that isn't enchanted"); + + static { + filter.add(Predicates.not(new EnchantedPredicate())); + } + + public TimeElemental(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{2}{U}"); + this.subtype.add(SubType.ELEMENTAL); + this.power = new MageInt(0); + this.toughness = new MageInt(2); + + // When Time Elemental attacks or blocks, at end of combat, sacrifice it and it deals 5 damage to you. + DelayedTriggeredAbility ability = new AtTheEndOfCombatDelayedTriggeredAbility(new SacrificeSourceEffect().setText("at end of combat, sacrifice it")); + ability.addEffect(new DamageControllerEffect(5).setText("and it deals 5 damage to you")); + this.addAbility(new AttacksOrBlocksTriggeredAbility(new CreateDelayedTriggeredAbilityEffect(ability, true), false)); + + // {2}{U}{U}, {tap}: Return target permanent that isn't enchanted to its owner's hand. + Ability ability2 = new SimpleActivatedAbility(Zone.BATTLEFIELD, new ReturnToHandTargetEffect(), new ManaCostsImpl("{2}{U}{U}")); + ability2.addCost(new TapSourceCost()); + ability2.addTarget(new TargetPermanent(filter)); + this.addAbility(ability2); + } + + public TimeElemental(final TimeElemental card) { + super(card); + } + + @Override + public TimeElemental copy() { + return new TimeElemental(this); + } +} diff --git a/Mage.Sets/src/mage/cards/t/Timebender.java b/Mage.Sets/src/mage/cards/t/Timebender.java new file mode 100644 index 0000000000..d817dbafc3 --- /dev/null +++ b/Mage.Sets/src/mage/cards/t/Timebender.java @@ -0,0 +1,136 @@ +/* + * Copyright 2010 BetaSteward_at_googlemail.com. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are + * permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this list of + * conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, this list + * of conditions and the following disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY BetaSteward_at_googlemail.com ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BetaSteward_at_googlemail.com OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * The views and conclusions contained in the software and documentation are those of the + * authors and should not be interpreted as representing official policies, either expressed + * or implied, of BetaSteward_at_googlemail.com. + */ +package mage.cards.t; + +import java.util.UUID; +import mage.MageInt; +import mage.abilities.Ability; +import mage.abilities.Mode; +import mage.abilities.common.TurnedFaceUpSourceTriggeredAbility; +import mage.abilities.costs.mana.ManaCostsImpl; +import mage.abilities.effects.OneShotEffect; +import mage.abilities.keyword.MorphAbility; +import mage.cards.Card; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.SubType; +import mage.constants.Outcome; +import mage.counters.CounterType; +import mage.game.Game; +import mage.game.permanent.Permanent; +import mage.target.common.TargetPermanentOrSuspendedCard; + +/** + * + * @author L_J + */ +public class Timebender extends CardImpl { + + public Timebender(UUID ownerId, CardSetInfo setInfo) { + super(ownerId,setInfo,new CardType[]{CardType.CREATURE},"{U}"); + this.subtype.add(SubType.HUMAN); + this.subtype.add(SubType.WIZARD); + this.power = new MageInt(1); + this.toughness = new MageInt(1); + + // Morph {U} + this.addAbility(new MorphAbility(this, new ManaCostsImpl("{U}"))); + + // When Timebender is turned face up, choose one — + // Remove two time counters from target permanent or suspended card. + Ability ability = new TurnedFaceUpSourceTriggeredAbility(new TimebenderEffect(false)); + ability.addTarget(new TargetPermanentOrSuspendedCard()); + + // Put two time counters on target permanent with a time counter on it or suspended card. + Mode mode = new Mode(); + mode.getEffects().add(new TimebenderEffect(true)); + mode.getTargets().add(new TargetPermanentOrSuspendedCard()); + ability.addMode(mode); + ability.getModes().addMode(mode); + this.addAbility(ability); + + } + + public Timebender(final Timebender card) { + super(card); + } + + @Override + public Timebender copy() { + return new Timebender(this); + } +} + +class TimebenderEffect extends OneShotEffect { + + private final boolean addCounters; + + public TimebenderEffect(boolean addCounters) { + super(Outcome.Benefit); + this.addCounters = addCounters; + if (addCounters) { + this.staticText = "put two time counters on target permanent or suspended card"; + } else { + this.staticText = "remove two time counters from target permanent or suspended card"; + } + } + + public TimebenderEffect(final TimebenderEffect effect) { + super(effect); + this.addCounters = effect.addCounters; + } + + @Override + public TimebenderEffect copy() { + return new TimebenderEffect(this); + } + + @Override + public boolean apply(Game game, Ability source) { + Permanent permanent = game.getPermanent(this.getTargetPointer().getFirst(game, source)); + if (permanent != null) { + if (addCounters) { + permanent.addCounters(CounterType.TIME.createInstance(2), source, game); + } else { + permanent.removeCounters(CounterType.TIME.getName(), 2, game); + } + return true; + } + Card card = game.getCard(this.getTargetPointer().getFirst(game, source)); + if (card != null) { + if (addCounters) { + card.addCounters(CounterType.TIME.createInstance(2), source, game); + } else { + card.removeCounters(CounterType.TIME.getName(), 2, game); + } + return true; + } + return false; + } +} diff --git a/Mage.Sets/src/mage/cards/t/TotalWar.java b/Mage.Sets/src/mage/cards/t/TotalWar.java new file mode 100644 index 0000000000..5aca291c7a --- /dev/null +++ b/Mage.Sets/src/mage/cards/t/TotalWar.java @@ -0,0 +1,152 @@ +/* + * Copyright 2010 BetaSteward_at_googlemail.com. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are + * permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this list of + * conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, this list + * of conditions and the following disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY BetaSteward_at_googlemail.com ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BetaSteward_at_googlemail.com OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * The views and conclusions contained in the software and documentation are those of the + * authors and should not be interpreted as representing official policies, either expressed + * or implied, of BetaSteward_at_googlemail.com. + */ +package mage.cards.t; + +import java.util.UUID; +import mage.MageObjectReference; +import mage.abilities.Ability; +import mage.abilities.TriggeredAbilityImpl; +import mage.abilities.effects.OneShotEffect; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.Outcome; +import mage.constants.SubType; +import mage.constants.Zone; +import mage.game.Game; +import mage.game.events.GameEvent; +import mage.game.events.GameEvent.EventType; +import mage.game.permanent.Permanent; +import mage.players.Player; +import mage.watchers.common.AttackedOrBlockedThisCombatWatcher; + +/** + * + * @author jeffwadsworth & emerald000 & L_J + */ +public class TotalWar extends CardImpl { + + public TotalWar(UUID ownerId, CardSetInfo setInfo) { + super(ownerId,setInfo,new CardType[]{CardType.ENCHANTMENT},"{3}{R}"); + + // Whenever a player attacks with one or more creatures, destroy all untapped non-Wall creatures that player controls that didn't attack, except for creatures the player hasn't controlled continuously since the beginning of the turn. + this.addAbility(new TotalWarTriggeredAbility(), new AttackedOrBlockedThisCombatWatcher()); + } + + public TotalWar(final TotalWar card) { + super(card); + } + + @Override + public TotalWar copy() { + return new TotalWar(this); + } +} + +class TotalWarTriggeredAbility extends TriggeredAbilityImpl { + + public TotalWarTriggeredAbility() { + super(Zone.BATTLEFIELD, new TotalWarDestroyEffect()); + } + + public TotalWarTriggeredAbility(final TotalWarTriggeredAbility ability) { + super(ability); + } + + @Override + public TotalWarTriggeredAbility copy() { + return new TotalWarTriggeredAbility(this); + } + + @Override + public boolean checkEventType(GameEvent event, Game game) { + return event.getType() == EventType.DECLARED_ATTACKERS; + } + + @Override + public boolean checkTrigger(GameEvent event, Game game) { + return !game.getCombat().getAttackers().isEmpty(); + } + + @Override + public String getRule() { + return "Whenever a player attacks with one or more creatures, " + super.getRule(); + } +} + +class TotalWarDestroyEffect extends OneShotEffect { + + TotalWarDestroyEffect() { + super(Outcome.DestroyPermanent); + this.staticText = "destroy all untapped non-Wall creatures that player controls that didn't attack, except for creatures the player hasn't controlled continuously since the beginning of the turn"; + } + + TotalWarDestroyEffect(final TotalWarDestroyEffect effect) { + super(effect); + } + + @Override + public TotalWarDestroyEffect copy() { + return new TotalWarDestroyEffect(this); + } + + @Override + public boolean apply(Game game, Ability source) { + Player activePlayer = game.getPlayer(game.getActivePlayerId()); + if (activePlayer != null) { + for (Permanent permanent : game.getBattlefield().getAllActivePermanents(activePlayer.getId())) { + // Noncreature cards are safe. + if (!permanent.isCreature()) { + continue; + } + // Tapped cards are safe. + if (permanent.isTapped()) { + continue; + } + // Walls are safe. + if (permanent.hasSubtype(SubType.WALL, game)) { + continue; + } + // Creatures that attacked are safe. + AttackedOrBlockedThisCombatWatcher watcher = (AttackedOrBlockedThisCombatWatcher) game.getState().getWatchers().get(AttackedOrBlockedThisCombatWatcher.class.getSimpleName()); + if (watcher != null + && watcher.getAttackedThisTurnCreatures().contains(new MageObjectReference(permanent, game))) { + continue; + } + // Creatures that weren't controlled since the beginning of turn are safe. + if (!permanent.wasControlledFromStartOfControllerTurn()) { + continue; + } + // Destroy the rest. + permanent.destroy(source.getSourceId(), game, false); + } + return true; + } + return false; + } +} diff --git a/Mage.Sets/src/mage/cards/t/TourachsGate.java b/Mage.Sets/src/mage/cards/t/TourachsGate.java new file mode 100644 index 0000000000..f298c2a9ff --- /dev/null +++ b/Mage.Sets/src/mage/cards/t/TourachsGate.java @@ -0,0 +1,164 @@ +/* + * Copyright 2010 BetaSteward_at_googlemail.com. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are + * permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this list of + * conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, this list + * of conditions and the following disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY BetaSteward_at_googlemail.com ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BetaSteward_at_googlemail.com OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * The views and conclusions contained in the software and documentation are those of the + * authors and should not be interpreted as representing official policies, either expressed + * or implied, of BetaSteward_at_googlemail.com. + */ +package mage.cards.t; + +import java.util.UUID; +import mage.abilities.Ability; +import mage.abilities.common.ActivateIfConditionActivatedAbility; +import mage.abilities.common.BeginningOfUpkeepTriggeredAbility; +import mage.abilities.common.SimpleActivatedAbility; +import mage.abilities.condition.common.AttachedToMatchesFilterCondition; +import mage.abilities.costs.Cost; +import mage.abilities.costs.common.TapAttachedCost; +import mage.abilities.effects.OneShotEffect; +import mage.abilities.effects.common.AttachEffect; +import mage.abilities.effects.common.continuous.BoostAllEffect; +import mage.abilities.effects.common.counter.AddCountersSourceEffect; +import mage.abilities.costs.common.SacrificeTargetCost; +import mage.abilities.keyword.EnchantAbility; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.SubType; +import mage.constants.Outcome; +import mage.constants.Duration; +import mage.constants.TargetController; +import mage.constants.Zone; +import mage.counters.CounterType; +import mage.filter.FilterPermanent; +import mage.filter.common.FilterControlledPermanent; +import mage.filter.common.FilterControlledCreaturePermanent; +import mage.filter.common.FilterCreaturePermanent; +import mage.filter.predicate.Predicates; +import mage.filter.predicate.mageobject.CardTypePredicate; +import mage.filter.predicate.mageobject.SubtypePredicate; +import mage.filter.predicate.permanent.AttackingPredicate; +import mage.filter.predicate.permanent.ControllerPredicate; +import mage.filter.predicate.permanent.TappedPredicate; +import mage.game.Game; +import mage.game.permanent.Permanent; +import mage.target.TargetPermanent; +import mage.target.common.TargetControlledCreaturePermanent; +import mage.target.common.TargetControlledPermanent; + +/** + * + * @author L_J + */ +public class TourachsGate extends CardImpl { + + private static final FilterControlledPermanent filterLand = new FilterControlledPermanent("land you control"); + static { + filterLand.add(new CardTypePredicate(CardType.LAND)); + } + + private static final FilterPermanent filterUntapped = new FilterPermanent("enchanted land is untapped"); + static { + filterUntapped.add(Predicates.not(new TappedPredicate())); + } + + private static final FilterCreaturePermanent filterAttackingCreatures = new FilterCreaturePermanent("attacking creatures you control"); + static { + filterAttackingCreatures.add(new AttackingPredicate()); + filterAttackingCreatures.add(new ControllerPredicate(TargetController.YOU)); + } + + private static final FilterControlledCreaturePermanent filterThrull = new FilterControlledCreaturePermanent("a Thrull"); + static { + filterThrull.add(new SubtypePredicate(SubType.THRULL)); + } + + public TourachsGate(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.ENCHANTMENT}, "{1}{B}{B}"); + this.subtype.add(SubType.AURA); + + // Enchant land you control + TargetPermanent auraTarget = new TargetControlledPermanent(filterLand); + this.getSpellAbility().addTarget(auraTarget); + this.getSpellAbility().addEffect(new AttachEffect(Outcome.AddAbility)); + Ability ability = new EnchantAbility(auraTarget.getTargetName()); + this.addAbility(ability); + + // Sacrifice a Thrull: Put three time counters on Tourach's Gate. + this.addAbility(new SimpleActivatedAbility(Zone.BATTLEFIELD, new AddCountersSourceEffect(CounterType.TIME.createInstance(3)), + new SacrificeTargetCost(new TargetControlledCreaturePermanent(1,1, filterThrull, true)))); + + // At the beginning of your upkeep, remove a time counter from Tourach's Gate. If there are no time counters on Tourach's Gate, sacrifice it. + this.addAbility(new BeginningOfUpkeepTriggeredAbility(new TourachsGateUpkeepEffect(), TargetController.YOU, false)); + + // Tap enchanted land: Attacking creatures you control get +2/-1 until end of turn. Activate this ability only if enchanted land is untapped. + Cost cost = new TapAttachedCost(); + cost.setText("Tap enchanted land"); + this.addAbility(new ActivateIfConditionActivatedAbility(Zone.BATTLEFIELD, new BoostAllEffect(2, -1, Duration.EndOfTurn, filterAttackingCreatures, false), + cost, new AttachedToMatchesFilterCondition(filterUntapped))); + } + + public TourachsGate(final TourachsGate card) { + super(card); + } + + @Override + public TourachsGate copy() { + return new TourachsGate(this); + } +} + +class TourachsGateUpkeepEffect extends OneShotEffect { + + TourachsGateUpkeepEffect() { + super(Outcome.Sacrifice); + staticText = "remove a time counter from {this}. If there are no time counters on {this}, sacrifice it"; + } + + TourachsGateUpkeepEffect(final TourachsGateUpkeepEffect effect) { + super(effect); + } + + @Override + public boolean apply(Game game, Ability source) { + Permanent permanent = game.getPermanent(source.getSourceId()); + if (permanent != null) { + int amount = permanent.getCounters(game).getCount(CounterType.TIME); + if (amount > 0) { + permanent.removeCounters(CounterType.TIME.createInstance(), game); + } + // is supposed to function similar to Vanishing + amount = permanent.getCounters(game).getCount(CounterType.TIME); + if (amount == 0) { + permanent.sacrifice(source.getSourceId(), game); + } + return true; + } + return false; + } + + @Override + public TourachsGateUpkeepEffect copy() { + return new TourachsGateUpkeepEffect(this); + } +} diff --git a/Mage.Sets/src/mage/cards/t/TreetopDefense.java b/Mage.Sets/src/mage/cards/t/TreetopDefense.java new file mode 100644 index 0000000000..c144df4dd7 --- /dev/null +++ b/Mage.Sets/src/mage/cards/t/TreetopDefense.java @@ -0,0 +1,73 @@ +/* + * Copyright 2010 BetaSteward_at_googlemail.com. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are + * permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this list of + * conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, this list + * of conditions and the following disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY BetaSteward_at_googlemail.com ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BetaSteward_at_googlemail.com OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * The views and conclusions contained in the software and documentation are those of the + * authors and should not be interpreted as representing official policies, either expressed + * or implied, of BetaSteward_at_googlemail.com. + */ +package mage.cards.t; + +import java.util.UUID; +import mage.abilities.Ability; +import mage.abilities.common.CastOnlyDuringPhaseStepSourceAbility; +import mage.abilities.condition.common.AttackedThisStepCondition; +import mage.abilities.effects.common.continuous.GainAbilityControlledEffect; +import mage.abilities.keyword.ReachAbility; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.Duration; +import mage.constants.PhaseStep; +import mage.constants.TurnPhase; +import mage.watchers.common.PlayerAttackedStepWatcher; + +/** + * + * @author TheElk801 + */ +public class TreetopDefense extends CardImpl { + + public TreetopDefense(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.INSTANT}, "{1}{G}"); + + // Cast Treetop Defense only during the declare attackers step and only if you've been attacked this step. + Ability ability = new CastOnlyDuringPhaseStepSourceAbility( + TurnPhase.COMBAT, PhaseStep.DECLARE_ATTACKERS, AttackedThisStepCondition.instance, + "Cast {this} only during the declare attackers step and only if you've been attacked this step." + ); + ability.addWatcher(new PlayerAttackedStepWatcher()); + this.addAbility(ability); + + // Creatures you control gain reach until end of turn. + this.getSpellAbility().addEffect(new GainAbilityControlledEffect(ReachAbility.getInstance(), Duration.EndOfTurn)); + } + + public TreetopDefense(final TreetopDefense card) { + super(card); + } + + @Override + public TreetopDefense copy() { + return new TreetopDefense(this); + } +} diff --git a/Mage.Sets/src/mage/cards/t/TribalGolem.java b/Mage.Sets/src/mage/cards/t/TribalGolem.java new file mode 100644 index 0000000000..f29eb8611b --- /dev/null +++ b/Mage.Sets/src/mage/cards/t/TribalGolem.java @@ -0,0 +1,126 @@ +/* + * Copyright 2010 BetaSteward_at_googlemail.com. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are + * permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this list of + * conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, this list + * of conditions and the following disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY BetaSteward_at_googlemail.com ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BetaSteward_at_googlemail.com OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * The views and conclusions contained in the software and documentation are those of the + * authors and should not be interpreted as representing official policies, either expressed + * or implied, of BetaSteward_at_googlemail.com. + */ +package mage.cards.t; + +import java.util.UUID; +import mage.MageInt; +import mage.abilities.Ability; +import mage.abilities.common.SimpleActivatedAbility; +import mage.abilities.common.SimpleStaticAbility; +import mage.abilities.condition.common.PermanentsOnTheBattlefieldCondition; +import mage.abilities.costs.mana.ManaCostsImpl; +import mage.abilities.decorator.ConditionalContinuousEffect; +import mage.abilities.effects.Effect; +import mage.abilities.effects.common.RegenerateSourceEffect; +import mage.abilities.effects.common.continuous.GainAbilitySourceEffect; +import mage.abilities.keyword.FirstStrikeAbility; +import mage.abilities.keyword.FlyingAbility; +import mage.abilities.keyword.HasteAbility; +import mage.abilities.keyword.TrampleAbility; +import mage.constants.SubType; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.Zone; +import mage.filter.common.FilterControlledPermanent; +import mage.filter.predicate.mageobject.SubtypePredicate; + +/** + * + * @author TheElk801 + */ +public class TribalGolem extends CardImpl { + + private static final FilterControlledPermanent filter1 = new FilterControlledPermanent("a Beast"); + private static final FilterControlledPermanent filter2 = new FilterControlledPermanent("a Goblin"); + private static final FilterControlledPermanent filter3 = new FilterControlledPermanent("a Soldier"); + private static final FilterControlledPermanent filter4 = new FilterControlledPermanent("a Wizard"); + private static final FilterControlledPermanent filter5 = new FilterControlledPermanent("a Zombie"); + + static { + filter1.add(new SubtypePredicate(SubType.BEAST)); + filter2.add(new SubtypePredicate(SubType.GOBLIN)); + filter3.add(new SubtypePredicate(SubType.SOLDIER)); + filter4.add(new SubtypePredicate(SubType.WIZARD)); + filter5.add(new SubtypePredicate(SubType.ZOMBIE)); + } + + public TribalGolem(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.ARTIFACT, CardType.CREATURE}, "{6}"); + + this.subtype.add(SubType.GOLEM); + this.power = new MageInt(4); + this.toughness = new MageInt(4); + + // Tribal Golem has trample as long as you control a Beast, haste as long as you control a Goblin, first strike as long as you control a Soldier, flying as long as you control a Wizard, and "{B}: Regenerate Tribal Golem" as long as you control a Zombie. + Effect effect1 = new ConditionalContinuousEffect( + new GainAbilitySourceEffect(TrampleAbility.getInstance()), + new PermanentsOnTheBattlefieldCondition(filter1), + "{this} has trample as long as you control a Beast," + ); + Effect effect2 = new ConditionalContinuousEffect( + new GainAbilitySourceEffect(HasteAbility.getInstance()), + new PermanentsOnTheBattlefieldCondition(filter2), + "haste as long as you control a Goblin," + ); + Effect effect3 = new ConditionalContinuousEffect( + new GainAbilitySourceEffect(FirstStrikeAbility.getInstance()), + new PermanentsOnTheBattlefieldCondition(filter3), + "first strike as long as you control a Soldier," + ); + Effect effect4 = new ConditionalContinuousEffect( + new GainAbilitySourceEffect(FlyingAbility.getInstance()), + new PermanentsOnTheBattlefieldCondition(filter4), + "flying as long as you control a Wizard," + ); + Effect effect5 = new ConditionalContinuousEffect( + new GainAbilitySourceEffect(new SimpleActivatedAbility( + Zone.BATTLEFIELD, + new RegenerateSourceEffect(), + new ManaCostsImpl("{B}") + )), + new PermanentsOnTheBattlefieldCondition(filter5), + "and \"{B}: Regenerate {this}\" as long as you control a Zombie" + ); + Ability ability = new SimpleStaticAbility(Zone.BATTLEFIELD, effect1); + ability.addEffect(effect2); + ability.addEffect(effect3); + ability.addEffect(effect4); + ability.addEffect(effect5); + this.addAbility(ability); + } + + public TribalGolem(final TribalGolem card) { + super(card); + } + + @Override + public TribalGolem copy() { + return new TribalGolem(this); + } +} diff --git a/Mage.Sets/src/mage/cards/v/VeteransVoice.java b/Mage.Sets/src/mage/cards/v/VeteransVoice.java new file mode 100644 index 0000000000..880bc071ee --- /dev/null +++ b/Mage.Sets/src/mage/cards/v/VeteransVoice.java @@ -0,0 +1,114 @@ +/* + * Copyright 2010 BetaSteward_at_googlemail.com. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are + * permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this list of + * conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, this list + * of conditions and the following disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY BetaSteward_at_googlemail.com ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BetaSteward_at_googlemail.com OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * The views and conclusions contained in the software and documentation are those of the + * authors and should not be interpreted as representing official policies, either expressed + * or implied, of BetaSteward_at_googlemail.com. + */ +package mage.cards.v; + +import java.util.UUID; +import mage.abilities.Ability; +import mage.abilities.common.ActivateIfConditionActivatedAbility; +import mage.abilities.condition.common.AttachedToMatchesFilterCondition; +import mage.abilities.costs.common.TapAttachedCost; +import mage.abilities.effects.common.AttachEffect; +import mage.abilities.effects.common.continuous.BoostTargetEffect; +import mage.abilities.keyword.EnchantAbility; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.SubType; +import mage.constants.Outcome; +import mage.constants.Duration; +import mage.constants.Zone; +import mage.filter.FilterPermanent; +import mage.filter.common.FilterCreaturePermanent; +import mage.filter.predicate.Predicate; +import mage.filter.predicate.Predicates; +import mage.filter.predicate.permanent.TappedPredicate; +import mage.game.Game; +import mage.game.permanent.Permanent; +import mage.target.TargetPermanent; +import mage.target.common.TargetControlledCreaturePermanent; + +/** + * + * @author L_J + */ +public class VeteransVoice extends CardImpl { + + private static final FilterCreaturePermanent filterUntapped = new FilterCreaturePermanent("enchanted creature is untapped"); + + static { + filterUntapped.add(Predicates.not(new TappedPredicate())); + } + + public VeteransVoice(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.ENCHANTMENT}, "{R}"); + this.subtype.add(SubType.AURA); + + // Enchant creature you control + TargetPermanent auraTarget = new TargetControlledCreaturePermanent(); + this.getSpellAbility().addTarget(auraTarget); + this.getSpellAbility().addEffect(new AttachEffect(Outcome.BoostCreature)); + Ability ability = new EnchantAbility(auraTarget.getTargetName()); + this.addAbility(ability); + + // Tap enchanted creature: Target creature other than the creature tapped this way gets +2/+1 until end of turn. Activate this ability only if enchanted creature is untapped. + FilterPermanent filterTarget = new FilterCreaturePermanent("creature other than the creature tapped this way"); + filterTarget.add(Predicates.not(new AttachmentByUUIDPredicate(this.getId()))); + Ability ability2 = new ActivateIfConditionActivatedAbility(Zone.BATTLEFIELD, + new BoostTargetEffect(2, 1, Duration.EndOfTurn), new TapAttachedCost(), new AttachedToMatchesFilterCondition(filterUntapped)); + ability2.addTarget(new TargetPermanent(filterTarget)); + this.addAbility(ability2); + } + + public VeteransVoice(final VeteransVoice card) { + super(card); + } + + @Override + public VeteransVoice copy() { + return new VeteransVoice(this); + } +} + +class AttachmentByUUIDPredicate implements Predicate { + + private final UUID id; + + public AttachmentByUUIDPredicate(UUID id) { + this.id = id; + } + + @Override + public boolean apply(Permanent input, Game game) { + return input.getAttachments().contains(id); + } + + @Override + public String toString() { + return "AttachmentUUID(" + id + ')'; + } +} diff --git a/Mage.Sets/src/mage/cards/v/VexingArcanix.java b/Mage.Sets/src/mage/cards/v/VexingArcanix.java new file mode 100644 index 0000000000..5278c1626b --- /dev/null +++ b/Mage.Sets/src/mage/cards/v/VexingArcanix.java @@ -0,0 +1,127 @@ +/* + * Copyright 2010 BetaSteward_at_googlemail.com. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are + * permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this list of + * conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, this list + * of conditions and the following disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY BetaSteward_at_googlemail.com ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BetaSteward_at_googlemail.com OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * The views and conclusions contained in the software and documentation are those of the + * authors and should not be interpreted as representing official policies, either expressed + * or implied, of BetaSteward_at_googlemail.com. + */ +package mage.cards.v; + +import java.util.UUID; +import mage.MageObject; +import mage.abilities.Ability; +import mage.abilities.common.SimpleActivatedAbility; +import mage.abilities.costs.common.TapSourceCost; +import mage.abilities.costs.mana.GenericManaCost; +import mage.abilities.effects.OneShotEffect; +import mage.cards.*; +import mage.cards.repository.CardRepository; +import mage.choices.Choice; +import mage.choices.ChoiceImpl; +import mage.constants.CardType; +import mage.constants.Outcome; +import mage.constants.Zone; +import mage.game.Game; +import mage.players.Player; +import mage.target.TargetPlayer; + +/** + * + * @author BetaSteward_at_googlemail.com & L_J + */ +public class VexingArcanix extends CardImpl { + + public VexingArcanix(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.ARTIFACT}, "{4}"); + + // {3}, {tap}: Target player chooses a card name, then reveals the top card of his or her library. If that card has the chosen name, the player puts it into his or her hand. Otherwise, the player puts it into his or her graveyard and Vexing Arcanix deals 2 damage to him or her. + Ability ability = new SimpleActivatedAbility(Zone.BATTLEFIELD, new VexingArcanixEffect(), new GenericManaCost(3)); + ability.addCost(new TapSourceCost()); + ability.addTarget(new TargetPlayer()); + this.addAbility(ability); + } + + public VexingArcanix(final VexingArcanix card) { + super(card); + } + + @Override + public VexingArcanix copy() { + return new VexingArcanix(this); + } + +} + +class VexingArcanixEffect extends OneShotEffect { + + public VexingArcanixEffect() { + super(Outcome.DrawCard); + staticText = "Target player chooses a card name, then reveals the top card of his or her library. If that card has the chosen name, the player puts it into his or her hand. Otherwise, the player puts it into his or her graveyard and {this} deals 2 damage to him or her"; + } + + public VexingArcanixEffect(final VexingArcanixEffect effect) { + super(effect); + } + + @Override + public boolean apply(Game game, Ability source) { + MageObject sourceObject = source.getSourceObject(game); + Player controller = game.getPlayer(source.getControllerId()); + Player player = game.getPlayer(targetPointer.getFirst(game, source)); + if (controller != null && sourceObject != null && player != null) { + + + if (player.getLibrary().hasCards()) { + Choice cardChoice = new ChoiceImpl(); + cardChoice.setChoices(CardRepository.instance.getNames()); + cardChoice.setMessage("Name a card"); + while (!player.choose(Outcome.DrawCard, cardChoice, game)) { + if (!player.canRespond()) { + return false; + } + } + String cardName = cardChoice.getChoice(); + game.informPlayers(sourceObject.getLogName() + ", player: " + player.getLogName() + ", named: [" + cardName + ']'); + Card card = player.getLibrary().removeFromTop(game); + if (card != null) { + Cards cards = new CardsImpl(card); + player.revealCards(sourceObject.getIdName(), cards, game); + if (card.getName().equals(cardName)) { + player.moveCards(cards, Zone.HAND, source, game); + } else { + player.moveCards(cards, Zone.GRAVEYARD, source, game); + player.damage(2, source.getSourceId(), game, false, true); + } + } + } + return true; + } + return false; + } + + @Override + public VexingArcanixEffect copy() { + return new VexingArcanixEffect(this); + } + +} diff --git a/Mage.Sets/src/mage/cards/w/WarTax.java b/Mage.Sets/src/mage/cards/w/WarTax.java index 689779066c..a82625fd18 100644 --- a/Mage.Sets/src/mage/cards/w/WarTax.java +++ b/Mage.Sets/src/mage/cards/w/WarTax.java @@ -30,10 +30,11 @@ package mage.cards.w; import java.util.UUID; import mage.abilities.Ability; import mage.abilities.common.SimpleActivatedAbility; +import mage.abilities.costs.mana.ManaCosts; import mage.abilities.costs.mana.ManaCostsImpl; import mage.abilities.dynamicvalue.DynamicValue; import mage.abilities.dynamicvalue.common.ManacostVariableValue; -import mage.abilities.effects.ReplacementEffectImpl; +import mage.abilities.effects.PayCostToAttackBlockEffectImpl; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; @@ -42,12 +43,12 @@ import mage.constants.Outcome; import mage.constants.Zone; import mage.game.Game; import mage.game.events.GameEvent; -import mage.players.Player; +import mage.game.permanent.Permanent; /** * * - * @author HCrescent original code by LevelX2 edited from War Cadence + * @author HCrescent & L_J */ public class WarTax extends CardImpl { @@ -55,7 +56,7 @@ public class WarTax extends CardImpl { super(ownerId, setInfo, new CardType[]{CardType.ENCHANTMENT}, "{2}{U}"); // {X}{U}: This turn, creatures can't attack unless their controller pays {X} for each attacking creature he or she controls. - this.addAbility(new SimpleActivatedAbility(Zone.BATTLEFIELD, new WarTaxReplacementEffect(), new ManaCostsImpl("{X}{U}"))); + this.addAbility(new SimpleActivatedAbility(Zone.BATTLEFIELD, new WarTaxCantAttackUnlessPaysEffect(), new ManaCostsImpl("{X}{U}"))); } public WarTax(final WarTax card) { @@ -68,51 +69,42 @@ public class WarTax extends CardImpl { } } -class WarTaxReplacementEffect extends ReplacementEffectImpl { +class WarTaxCantAttackUnlessPaysEffect extends PayCostToAttackBlockEffectImpl { DynamicValue xCosts = new ManacostVariableValue(); - WarTaxReplacementEffect() { - super(Duration.EndOfTurn, Outcome.Neutral); + WarTaxCantAttackUnlessPaysEffect() { + super(Duration.EndOfTurn, Outcome.Neutral, RestrictType.ATTACK); staticText = "This turn, creatures can't attack unless their controller pays {X} for each attacking creature he or she controls"; } - WarTaxReplacementEffect(WarTaxReplacementEffect effect) { + WarTaxCantAttackUnlessPaysEffect(WarTaxCantAttackUnlessPaysEffect effect) { super(effect); } - @Override - public boolean replaceEvent(GameEvent event, Ability source, Game game) { - Player player = game.getPlayer(event.getPlayerId()); - if (player != null) { - int amount = xCosts.calculate(game, source, this); - if (amount > 0) { - String mana = "{" + amount + '}'; - ManaCostsImpl cost = new ManaCostsImpl(mana); - if (cost.canPay(source, source.getSourceId(), event.getPlayerId(), game) - && player.chooseUse(Outcome.Benefit, "Pay " + mana + " to declare attacker?", source, game)) { - if (cost.payOrRollback(source, game, source.getSourceId(), event.getPlayerId())) { - return false; - } - } - return true; - } - } - return false; - } - - @Override - public boolean checksEventType(GameEvent event, Game game) { - return event.getType() == GameEvent.EventType.DECLARE_ATTACKER; - } - @Override public boolean applies(GameEvent event, Ability source, Game game) { return true; } @Override - public WarTaxReplacementEffect copy() { - return new WarTaxReplacementEffect(this); + public ManaCosts getManaCostToPay(GameEvent event, Ability source, Game game) { + Permanent sourceObject = game.getPermanent(source.getSourceId()); + if (sourceObject != null) { + int amount = xCosts.calculate(game, source, this); + return new ManaCostsImpl<>("{" + amount + '}'); + } + return null; } + + @Override + public boolean isCostless(GameEvent event, Ability source, Game game) { + return false; + } + + @Override + public WarTaxCantAttackUnlessPaysEffect copy() { + return new WarTaxCantAttackUnlessPaysEffect(this); + } + } diff --git a/Mage.Sets/src/mage/cards/w/WatertrapWeaver.java b/Mage.Sets/src/mage/cards/w/WatertrapWeaver.java index 2820a85eee..703eb4ae9a 100644 --- a/Mage.Sets/src/mage/cards/w/WatertrapWeaver.java +++ b/Mage.Sets/src/mage/cards/w/WatertrapWeaver.java @@ -61,7 +61,7 @@ public class WatertrapWeaver extends CardImpl { this.power = new MageInt(2); this.toughness = new MageInt(2); - // When Watertrap Weaver enters the battlefield, tap target creature an opponent controls. That creature doesn't untap during its controller's next untap step. + // When Watertrap Weaver enters the battlefield, tap target creature an opponent controls. That creature doesn't untap during its controller's next untap step. EntersBattlefieldTriggeredAbility ability = new EntersBattlefieldTriggeredAbility(new TapTargetEffect()); ability.addEffect(new DontUntapInControllersNextUntapStepTargetEffect("that creature")); ability.addTarget(new TargetCreaturePermanent(filter)); diff --git a/Mage.Sets/src/mage/cards/w/Waylay.java b/Mage.Sets/src/mage/cards/w/Waylay.java new file mode 100644 index 0000000000..795197e929 --- /dev/null +++ b/Mage.Sets/src/mage/cards/w/Waylay.java @@ -0,0 +1,103 @@ +/* + * Copyright 2010 BetaSteward_at_googlemail.com. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are + * permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this list of + * conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, this list + * of conditions and the following disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY BetaSteward_at_googlemail.com ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BetaSteward_at_googlemail.com OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * The views and conclusions contained in the software and documentation are those of the + * authors and should not be interpreted as representing official policies, either expressed + * or implied, of BetaSteward_at_googlemail.com. + */ +package mage.cards.w; + +import java.util.ArrayList; +import java.util.List; +import java.util.UUID; +import mage.abilities.Ability; +import mage.abilities.common.delayed.AtTheBeginOfNextCleanupDelayedTriggeredAbility; +import mage.abilities.effects.Effect; +import mage.abilities.effects.OneShotEffect; +import mage.abilities.effects.common.ExileTargetEffect; +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.permanent.token.Token; +import mage.game.permanent.token.WaylayToken; +import mage.target.targetpointer.FixedTargets; + +/** + * + * @author TheElk801 + */ +public class Waylay extends CardImpl { + + public Waylay(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.INSTANT}, "{2}{W}"); + + // Create three 2/2 white Knight creature tokens. Exile them at the beginning of the next cleanup step. + this.getSpellAbility().addEffect(new WaylayEffect()); + } + + public Waylay(final Waylay card) { + super(card); + } + + @Override + public Waylay copy() { + return new Waylay(this); + } +} + +class WaylayEffect extends OneShotEffect { + + public WaylayEffect() { + super(Outcome.PutCreatureInPlay); + this.staticText = "Create three 2/2 white Knight creature tokens. Exile them at the beginning of the next cleanup step."; + } + + public WaylayEffect(final WaylayEffect effect) { + super(effect); + } + + @Override + public WaylayEffect copy() { + return new WaylayEffect(this); + } + + @Override + public boolean apply(Game game, Ability source) { + Token token = new WaylayToken(); + token.putOntoBattlefield(3, game, source.getSourceId(), source.getControllerId()); + List toExile = new ArrayList<>(); + for (UUID tokenId : token.getLastAddedTokenIds()) { + Permanent tokenPermanent = game.getPermanent(tokenId); + if (tokenPermanent != null) { + toExile.add(tokenPermanent); + } + } + Effect effect = new ExileTargetEffect(); + effect.setTargetPointer(new FixedTargets(toExile, game)); + game.addDelayedTriggeredAbility(new AtTheBeginOfNextCleanupDelayedTriggeredAbility(effect), source); + return true; + } +} diff --git a/Mage.Sets/src/mage/cards/w/WeiAssassins.java b/Mage.Sets/src/mage/cards/w/WeiAssassins.java new file mode 100644 index 0000000000..282f9b0dc0 --- /dev/null +++ b/Mage.Sets/src/mage/cards/w/WeiAssassins.java @@ -0,0 +1,116 @@ +/* + * Copyright 2010 BetaSteward_at_googlemail.com. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are + * permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this list of + * conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, this list + * of conditions and the following disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY BetaSteward_at_googlemail.com ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BetaSteward_at_googlemail.com OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * The views and conclusions contained in the software and documentation are those of the + * authors and should not be interpreted as representing official policies, either expressed + * or implied, of BetaSteward_at_googlemail.com. + */ +package mage.cards.w; + +import java.util.UUID; +import mage.MageInt; +import mage.abilities.Ability; +import mage.abilities.common.EntersBattlefieldTriggeredAbility; +import mage.abilities.effects.OneShotEffect; +import mage.constants.SubType; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.Outcome; +import mage.filter.common.FilterCreaturePermanent; +import mage.filter.predicate.permanent.ControllerIdPredicate; +import mage.game.Game; +import mage.game.permanent.Permanent; +import mage.players.Player; +import mage.target.Target; +import mage.target.TargetPermanent; +import mage.target.common.TargetOpponent; + +/** + * + * @author TheElk801 + */ +public class WeiAssassins extends CardImpl { + + public WeiAssassins(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{3}{B}{B}"); + + this.subtype.add(SubType.HUMAN); + this.subtype.add(SubType.SOLDIER); + this.subtype.add(SubType.ASSASSIN); + this.power = new MageInt(3); + this.toughness = new MageInt(2); + + // When Wei Assassins enters the battlefield, target opponent chooses a creature he or she controls. Destroy it. + Ability ability = new EntersBattlefieldTriggeredAbility(new WeiAssassinsEffect(), false); + ability.addTarget(new TargetOpponent()); + this.addAbility(ability); + } + + public WeiAssassins(final WeiAssassins card) { + super(card); + } + + @Override + public WeiAssassins copy() { + return new WeiAssassins(this); + } +} + +class WeiAssassinsEffect extends OneShotEffect { + + WeiAssassinsEffect() { + super(Outcome.Benefit); + this.staticText = "target opponent chooses a creature he or she controls. Destroy it."; + } + + WeiAssassinsEffect(final WeiAssassinsEffect effect) { + super(effect); + } + + @Override + public WeiAssassinsEffect copy() { + return new WeiAssassinsEffect(this); + } + + @Override + public boolean apply(Game game, Ability source) { + Player player = game.getPlayer(source.getFirstTarget()); + if (player == null) { + return false; + } + FilterCreaturePermanent filter = new FilterCreaturePermanent("creature you control"); + filter.add(new ControllerIdPredicate(player.getId())); + Target target = new TargetPermanent(1, 1, filter, true); + if (target.canChoose(source.getSourceId(), player.getId(), game)) { + while (!target.isChosen() && target.canChoose(player.getId(), game) && player.canRespond()) { + player.chooseTarget(Outcome.DestroyPermanent, target, source, game); + } + Permanent permanent = game.getPermanent(target.getFirstTarget()); + if (permanent != null) { + permanent.destroy(source.getSourceId(), game, false); + } + } + return true; + } +} diff --git a/Mage.Sets/src/mage/cards/w/Wishmonger.java b/Mage.Sets/src/mage/cards/w/Wishmonger.java new file mode 100644 index 0000000000..46659aab0e --- /dev/null +++ b/Mage.Sets/src/mage/cards/w/Wishmonger.java @@ -0,0 +1,175 @@ +/* + * Copyright 2010 BetaSteward_at_googlemail.com. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are + * permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this list of + * conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, this list + * of conditions and the following disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY BetaSteward_at_googlemail.com ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BetaSteward_at_googlemail.com OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * The views and conclusions contained in the software and documentation are those of the + * authors and should not be interpreted as representing official policies, either expressed + * or implied, of BetaSteward_at_googlemail.com. + */ +package mage.cards.w; + +import java.util.UUID; +import mage.MageInt; +import mage.ObjectColor; +import mage.abilities.Ability; +import mage.abilities.common.SimpleActivatedAbility; +import mage.abilities.costs.mana.ManaCostsImpl; +import mage.abilities.effects.ContinuousEffect; +import mage.abilities.effects.ContinuousEffectImpl; +import mage.abilities.effects.OneShotEffect; +import mage.abilities.effects.common.InfoEffect; +import mage.abilities.keyword.ProtectionAbility; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.choices.ChoiceColor; +import mage.constants.CardType; +import mage.constants.SubType; +import mage.constants.Duration; +import mage.constants.Layer; +import mage.constants.Outcome; +import mage.constants.SubLayer; +import mage.constants.TargetController; +import mage.constants.Zone; +import mage.filter.FilterObject; +import mage.filter.predicate.mageobject.ColorPredicate; +import mage.game.Game; +import mage.game.permanent.Permanent; +import mage.players.Player; +import mage.target.common.TargetCreaturePermanent; +import mage.target.targetpointer.FixedTarget; + +/** + * + * @author jeffwadsworth & L_J + */ +public class Wishmonger extends CardImpl { + + public Wishmonger(UUID ownerId, CardSetInfo setInfo) { + super(ownerId,setInfo,new CardType[]{CardType.CREATURE},"{3}{W}"); + this.subtype.add(SubType.UNICORN); + this.subtype.add(SubType.MONGER); + this.power = new MageInt(3); + this.toughness = new MageInt(3); + + // {2}: Target creature gains protection from the color of its controller's choice until end of turn. Any player may activate this ability. + SimpleActivatedAbility ability = new SimpleActivatedAbility(Zone.BATTLEFIELD, new WishmongerEffect(), new ManaCostsImpl("{2}")); + ability.addTarget(new TargetCreaturePermanent()); + ability.setMayActivate(TargetController.ANY); + ability.addEffect(new InfoEffect("Any player may activate this ability")); + this.addAbility(ability); + } + + public Wishmonger(final Wishmonger card) { + super(card); + } + + @Override + public Wishmonger copy() { + return new Wishmonger(this); + } +} + +class WishmongerEffect extends OneShotEffect { + + public WishmongerEffect() { + super(Outcome.BoostCreature); + staticText = "Target creature gains protection from the color of its controller's choice until end of turn"; + } + + public WishmongerEffect(final WishmongerEffect effect) { + super(effect); + } + + @Override + public boolean apply(Game game, Ability source) { + Permanent targetCreature = game.getPermanent(getTargetPointer().getFirst(game, source)); + if (targetCreature != null) { + Player player = game.getPlayer(targetCreature.getControllerId()); + if (player != null) { + ChoiceColor colorChoice = new ChoiceColor(); + if (player.choose(Outcome.Neutral, colorChoice, game)) { + game.informPlayers(targetCreature.getName() + ": " + player.getLogName() + " has chosen " + colorChoice.getChoice()); + game.getState().setValue(targetCreature.getId() + "_color", colorChoice.getColor()); + + ObjectColor protectColor = (ObjectColor) game.getState().getValue(targetCreature.getId() + "_color"); + if (protectColor != null) { + ContinuousEffect effect = new ProtectionChosenColorTargetEffect(); + effect.setTargetPointer(new FixedTarget(targetCreature, game)); + game.addEffect(effect, source); + } + } + return true; + } + } + return false; + } + + @Override + public WishmongerEffect copy() { + return new WishmongerEffect(this); + } +} + + +class ProtectionChosenColorTargetEffect extends ContinuousEffectImpl { + + protected ObjectColor chosenColor; + protected ProtectionAbility protectionAbility; + + public ProtectionChosenColorTargetEffect() { + super(Duration.EndOfTurn, Layer.AbilityAddingRemovingEffects_6, SubLayer.NA, Outcome.AddAbility); + } + + public ProtectionChosenColorTargetEffect(final ProtectionChosenColorTargetEffect effect) { + super(effect); + if (effect.chosenColor != null) { + this.chosenColor = effect.chosenColor.copy(); + } + if (effect.protectionAbility != null) { + this.protectionAbility = effect.protectionAbility.copy(); + } + } + + @Override + public ProtectionChosenColorTargetEffect copy() { + return new ProtectionChosenColorTargetEffect(this); + } + + @Override + public boolean apply(Game game, Ability source) { + Permanent permanent = game.getPermanent(getTargetPointer().getFirst(game, source)); + if (permanent != null) { + ObjectColor color = (ObjectColor) game.getState().getValue(permanent.getId() + "_color"); + if (color != null && (protectionAbility == null || !color.equals(chosenColor))) { + chosenColor = color; + FilterObject protectionFilter = new FilterObject(chosenColor.getDescription()); + protectionFilter.add(new ColorPredicate(chosenColor)); + protectionAbility = new ProtectionAbility(protectionFilter); + } + if (protectionAbility != null) { + permanent.addAbility(protectionAbility, source.getSourceId(), game); + return true; + } + } + return false; + } +} diff --git a/Mage.Sets/src/mage/cards/w/WitchEngine.java b/Mage.Sets/src/mage/cards/w/WitchEngine.java index 2d5659e4d3..51f61adebe 100644 --- a/Mage.Sets/src/mage/cards/w/WitchEngine.java +++ b/Mage.Sets/src/mage/cards/w/WitchEngine.java @@ -39,11 +39,11 @@ import mage.abilities.keyword.SwampwalkAbility; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; -import mage.constants.SubType; import mage.constants.Duration; import mage.constants.Layer; import mage.constants.Outcome; import mage.constants.SubLayer; +import mage.constants.SubType; import mage.constants.Zone; import mage.game.Game; import mage.game.permanent.Permanent; @@ -56,15 +56,15 @@ import mage.target.common.TargetOpponent; public class WitchEngine extends CardImpl { public WitchEngine(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.CREATURE},"{5}{B}"); + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{5}{B}"); this.subtype.add(SubType.HORROR); this.power = new MageInt(4); this.toughness = new MageInt(4); // Swampwalk this.addAbility(new SwampwalkAbility()); - - // {tap}: Add {B}{B}{B}{B} to your mana pool. Target opponent gains control of Witch Engine. + + // {T}: Add {B}{B}{B}{B} to your mana pool. Target opponent gains control of Witch Engine. (Activate this ability only any time you could cast an instant.) Ability ability = new SimpleActivatedAbility(Zone.BATTLEFIELD, new BasicManaEffect(Mana.BlackMana(4)), new TapSourceCost()); ability.addEffect(new WitchEngineEffect()); ability.addTarget(new TargetOpponent()); diff --git a/Mage.Sets/src/mage/sets/Alliances.java b/Mage.Sets/src/mage/sets/Alliances.java index 6144a6e8bb..e97dda2169 100644 --- a/Mage.Sets/src/mage/sets/Alliances.java +++ b/Mage.Sets/src/mage/sets/Alliances.java @@ -104,6 +104,7 @@ public class Alliances extends ExpansionSet { cards.add(new SetCardInfo("Keeper of Tresserhorn", 14, Rarity.RARE, mage.cards.k.KeeperOfTresserhorn.class)); cards.add(new SetCardInfo("Kjeldoran Home Guard", 135, Rarity.UNCOMMON, mage.cards.k.KjeldoranHomeGuard.class)); cards.add(new SetCardInfo("Kjeldoran Outpost", 184, Rarity.RARE, mage.cards.k.KjeldoranOutpost.class)); + cards.add(new SetCardInfo("Krovikan Horror", 15, Rarity.RARE, mage.cards.k.KrovikanHorror.class)); cards.add(new SetCardInfo("Krovikan Plague", 16, Rarity.UNCOMMON, mage.cards.k.KrovikanPlague.class)); cards.add(new SetCardInfo("Lake of the Dead", 185, Rarity.RARE, mage.cards.l.LakeOfTheDead.class)); cards.add(new SetCardInfo("Library of Lat-Nam", 47, Rarity.RARE, mage.cards.l.LibraryOfLatNam.class)); @@ -112,7 +113,10 @@ public class Alliances extends ExpansionSet { cards.add(new SetCardInfo("Lim-Dul's Paladin", 191, Rarity.UNCOMMON, mage.cards.l.LimDulsPaladin.class)); cards.add(new SetCardInfo("Lim-Dul's Vault", 192, Rarity.UNCOMMON, mage.cards.l.LimDulsVault.class)); cards.add(new SetCardInfo("Lord of Tresserhorn", 193, Rarity.RARE, mage.cards.l.LordOfTresserhorn.class)); + cards.add(new SetCardInfo("Martyrdom", 138, Rarity.COMMON, mage.cards.m.Martyrdom.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Martyrdom", 139, Rarity.COMMON, mage.cards.m.Martyrdom.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Mishra's Groundbreaker", 165, Rarity.UNCOMMON, mage.cards.m.MishrasGroundbreaker.class)); + cards.add(new SetCardInfo("Misinformation", 19, Rarity.UNCOMMON, mage.cards.m.Misinformation.class)); cards.add(new SetCardInfo("Mystic Compass", 166, Rarity.UNCOMMON, mage.cards.m.MysticCompass.class)); cards.add(new SetCardInfo("Nature's Chosen", 81, Rarity.UNCOMMON, mage.cards.n.NaturesChosen.class)); cards.add(new SetCardInfo("Nature's Wrath", 82, Rarity.RARE, mage.cards.n.NaturesWrath.class)); @@ -170,6 +174,8 @@ public class Alliances extends ExpansionSet { cards.add(new SetCardInfo("Varchild's Crusader", 120, Rarity.COMMON, mage.cards.v.VarchildsCrusader.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Varchild's Crusader", 121, Rarity.COMMON, mage.cards.v.VarchildsCrusader.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Varchild's War-Riders", 122, Rarity.RARE, mage.cards.v.VarchildsWarRiders.class)); + cards.add(new SetCardInfo("Veteran's Voice", 123, Rarity.COMMON, mage.cards.v.VeteransVoice.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Veteran's Voice", 124, Rarity.COMMON, mage.cards.v.VeteransVoice.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Viscerid Armor", 60, Rarity.COMMON, mage.cards.v.VisceridArmor.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Viscerid Armor", 61, Rarity.COMMON, mage.cards.v.VisceridArmor.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Viscerid Drone", 62, Rarity.UNCOMMON, mage.cards.v.VisceridDrone.class)); diff --git a/Mage.Sets/src/mage/sets/Chronicles.java b/Mage.Sets/src/mage/sets/Chronicles.java index add6a9345f..fac22fcc4f 100644 --- a/Mage.Sets/src/mage/sets/Chronicles.java +++ b/Mage.Sets/src/mage/sets/Chronicles.java @@ -57,7 +57,7 @@ public class Chronicles extends ExpansionSet { cards.add(new SetCardInfo("Active Volcano", 43, Rarity.COMMON, mage.cards.a.ActiveVolcano.class)); cards.add(new SetCardInfo("Akron Legionnaire", 58, Rarity.RARE, mage.cards.a.AkronLegionnaire.class)); cards.add(new SetCardInfo("Aladdin", 44, Rarity.RARE, mage.cards.a.Aladdin.class)); - cards.add(new SetCardInfo("Angelic Voices", 59, Rarity.RARE, mage.cards.a.AngelicVoices.class)); + cards.add(new SetCardInfo("Angelic Voices", 59, Rarity.RARE, mage.cards.a.AngelicVoices.class)); cards.add(new SetCardInfo("Arcades Sabboth", 106, Rarity.RARE, mage.cards.a.ArcadesSabboth.class)); cards.add(new SetCardInfo("Arena of the Ancients", 71, Rarity.RARE, mage.cards.a.ArenaOfTheAncients.class)); cards.add(new SetCardInfo("Argothian Pixies", 29, Rarity.COMMON, mage.cards.a.ArgothianPixies.class)); @@ -98,9 +98,10 @@ public class Chronicles extends ExpansionSet { cards.add(new SetCardInfo("Hasran Ogress", 6, Rarity.COMMON, mage.cards.h.HasranOgress.class)); cards.add(new SetCardInfo("Hell's Caretaker", 7, Rarity.RARE, mage.cards.h.HellsCaretaker.class)); cards.add(new SetCardInfo("Horn of Deafening", 80, Rarity.RARE, mage.cards.h.HornOfDeafening.class)); - cards.add(new SetCardInfo("Indestructible Aura", 63, Rarity.COMMON, mage.cards.i.IndestructibleAura.class)); + cards.add(new SetCardInfo("Indestructible Aura", 63, Rarity.COMMON, mage.cards.i.IndestructibleAura.class)); cards.add(new SetCardInfo("Ivory Guardians", 64, Rarity.UNCOMMON, mage.cards.i.IvoryGuardians.class)); cards.add(new SetCardInfo("Jalum Tome", 81, Rarity.RARE, mage.cards.j.JalumTome.class)); + cards.add(new SetCardInfo("Johan", 112, Rarity.RARE, mage.cards.j.Johan.class)); cards.add(new SetCardInfo("Juxtapose", 22, Rarity.RARE, mage.cards.j.Juxtapose.class)); cards.add(new SetCardInfo("Keepers of the Faith", 65, Rarity.COMMON, mage.cards.k.KeepersOfTheFaith.class)); cards.add(new SetCardInfo("Kei Takahashi", 113, Rarity.UNCOMMON, mage.cards.k.KeiTakahashi.class)); @@ -112,6 +113,7 @@ public class Chronicles extends ExpansionSet { cards.add(new SetCardInfo("Nicol Bolas", 116, Rarity.RARE, mage.cards.n.NicolBolas.class)); cards.add(new SetCardInfo("Obelisk of Undoing", 84, Rarity.RARE, mage.cards.o.ObeliskOfUndoing.class)); cards.add(new SetCardInfo("Palladia-Mors", 117, Rarity.RARE, mage.cards.p.PalladiaMors.class)); + cards.add(new SetCardInfo("Petra Sphinx", 66, Rarity.RARE, mage.cards.p.PetraSphinx.class)); cards.add(new SetCardInfo("Rabid Wombat", 39, Rarity.UNCOMMON, mage.cards.r.RabidWombat.class)); cards.add(new SetCardInfo("Rakalite", 85, Rarity.RARE, mage.cards.r.Rakalite.class)); cards.add(new SetCardInfo("Recall", 24, Rarity.UNCOMMON, mage.cards.r.Recall.class)); @@ -127,6 +129,7 @@ public class Chronicles extends ExpansionSet { cards.add(new SetCardInfo("Sivitri Scarzam", 119, Rarity.UNCOMMON, mage.cards.s.SivitriScarzam.class)); cards.add(new SetCardInfo("Sol'kanar the Swamp King", 120, Rarity.RARE, mage.cards.s.SolkanarTheSwampKing.class)); cards.add(new SetCardInfo("Storm Seeker", 42, Rarity.UNCOMMON, mage.cards.s.StormSeeker.class)); + cards.add(new SetCardInfo("Teleport", 26, Rarity.RARE, mage.cards.t.Teleport.class)); cards.add(new SetCardInfo("The Wretched", 11, Rarity.RARE, mage.cards.t.TheWretched.class)); cards.add(new SetCardInfo("Tobias Andrion", 122, Rarity.UNCOMMON, mage.cards.t.TobiasAndrion.class)); cards.add(new SetCardInfo("Tormod's Crypt", 89, Rarity.COMMON, mage.cards.t.TormodsCrypt.class)); diff --git a/Mage.Sets/src/mage/sets/Commander.java b/Mage.Sets/src/mage/sets/Commander.java index a87566d11e..3460d42679 100644 --- a/Mage.Sets/src/mage/sets/Commander.java +++ b/Mage.Sets/src/mage/sets/Commander.java @@ -210,6 +210,7 @@ public class Commander extends ExpansionSet { cards.add(new SetCardInfo("Malfegor", 208, Rarity.MYTHIC, mage.cards.m.Malfegor.class)); cards.add(new SetCardInfo("Mana-Charged Dragon", 129, Rarity.RARE, mage.cards.m.ManaChargedDragon.class)); cards.add(new SetCardInfo("Martyr's Bond", 19, Rarity.RARE, mage.cards.m.MartyrsBond.class)); + cards.add(new SetCardInfo("Master Warcraft", 209, Rarity.RARE, mage.cards.m.MasterWarcraft.class)); cards.add(new SetCardInfo("Memory Erosion", 50, Rarity.RARE, mage.cards.m.MemoryErosion.class)); cards.add(new SetCardInfo("Minds Aglow", 51, Rarity.RARE, mage.cards.m.MindsAglow.class)); cards.add(new SetCardInfo("Molten Slagheap", 282, Rarity.UNCOMMON, mage.cards.m.MoltenSlagheap.class)); diff --git a/Mage.Sets/src/mage/sets/CommanderAnthology.java b/Mage.Sets/src/mage/sets/CommanderAnthology.java index fc943136b2..7142cee09a 100644 --- a/Mage.Sets/src/mage/sets/CommanderAnthology.java +++ b/Mage.Sets/src/mage/sets/CommanderAnthology.java @@ -207,6 +207,7 @@ public class CommanderAnthology extends ExpansionSet { cards.add(new SetCardInfo("Malfegor", 184, Rarity.MYTHIC, mage.cards.m.Malfegor.class)); cards.add(new SetCardInfo("Mana-Charged Dragon", 84, Rarity.RARE, mage.cards.m.ManaChargedDragon.class)); cards.add(new SetCardInfo("Masked Admirers", 127, Rarity.UNCOMMON, mage.cards.m.MaskedAdmirers.class)); + cards.add(new SetCardInfo("Master Warcraft", 202, Rarity.RARE, mage.cards.m.MasterWarcraft.class)); cards.add(new SetCardInfo("Mazirek, Kraul Death Priest", 185, Rarity.MYTHIC, mage.cards.m.MazirekKraulDeathPriest.class)); cards.add(new SetCardInfo("Meren of Clan Nel Toth", 186, Rarity.MYTHIC, mage.cards.m.MerenOfClanNelToth.class)); cards.add(new SetCardInfo("Mirror Entity", 16, Rarity.RARE, mage.cards.m.MirrorEntity.class)); diff --git a/Mage.Sets/src/mage/sets/ConspiracyTakeTheCrown.java b/Mage.Sets/src/mage/sets/ConspiracyTakeTheCrown.java index 0cda5865fd..630eca1b6c 100644 --- a/Mage.Sets/src/mage/sets/ConspiracyTakeTheCrown.java +++ b/Mage.Sets/src/mage/sets/ConspiracyTakeTheCrown.java @@ -86,6 +86,7 @@ public class ConspiracyTakeTheCrown extends ExpansionSet { cards.add(new SetCardInfo("Coveted Peacock", 29, Rarity.UNCOMMON, mage.cards.c.CovetedPeacock.class)); cards.add(new SetCardInfo("Crown-Hunter Hireling", 50, Rarity.COMMON, mage.cards.c.CrownHunterHireling.class)); cards.add(new SetCardInfo("Custodi Lich", 41, Rarity.RARE, mage.cards.c.CustodiLich.class)); + cards.add(new SetCardInfo("Custodi Soulcaller", 15, Rarity.UNCOMMON, mage.cards.c.CustodiSoulcaller.class)); cards.add(new SetCardInfo("Daretti, Ingenious Iconoclast", 74, Rarity.MYTHIC, mage.cards.d.DarettiIngeniousIconoclast.class)); cards.add(new SetCardInfo("Deadly Designs", 42, Rarity.UNCOMMON, mage.cards.d.DeadlyDesigns.class)); cards.add(new SetCardInfo("Death Wind", 131, Rarity.COMMON, mage.cards.d.DeathWind.class)); diff --git a/Mage.Sets/src/mage/sets/Darksteel.java b/Mage.Sets/src/mage/sets/Darksteel.java index eae36ce1cd..67b77deb03 100644 --- a/Mage.Sets/src/mage/sets/Darksteel.java +++ b/Mage.Sets/src/mage/sets/Darksteel.java @@ -121,6 +121,7 @@ public class Darksteel extends ExpansionSet { cards.add(new SetCardInfo("Pristine Angel", 9, Rarity.RARE, mage.cards.p.PristineAngel.class)); cards.add(new SetCardInfo("Psychic Overload", 28, Rarity.UNCOMMON, mage.cards.p.PsychicOverload.class)); cards.add(new SetCardInfo("Pteron Ghost", 10, Rarity.COMMON, mage.cards.p.PteronGhost.class)); + cards.add(new SetCardInfo("Pulse of the Dross", 50, Rarity.RARE, mage.cards.p.PulseOfTheDross.class)); cards.add(new SetCardInfo("Pulse of the Fields", 11, Rarity.RARE, mage.cards.p.PulseOfTheFields.class)); cards.add(new SetCardInfo("Pulse of the Forge", 66, Rarity.RARE, mage.cards.p.PulseOfTheForge.class)); cards.add(new SetCardInfo("Pulse of the Grid", 29, Rarity.RARE, mage.cards.p.PulseOfTheGrid.class)); @@ -137,9 +138,11 @@ public class Darksteel extends ExpansionSet { cards.add(new SetCardInfo("Savage Beating", 67, Rarity.RARE, mage.cards.s.SavageBeating.class)); cards.add(new SetCardInfo("Scavenging Scarab", 51, Rarity.COMMON, mage.cards.s.ScavengingScarab.class)); cards.add(new SetCardInfo("Screams from Within", 52, Rarity.UNCOMMON, mage.cards.s.ScreamsFromWithin.class)); + cards.add(new SetCardInfo("Scrounge", 53, Rarity.UNCOMMON, mage.cards.s.Scrounge.class)); cards.add(new SetCardInfo("Second Sight", 33, Rarity.UNCOMMON, mage.cards.s.SecondSight.class)); cards.add(new SetCardInfo("Serum Powder", 138, Rarity.RARE, mage.cards.s.SerumPowder.class)); cards.add(new SetCardInfo("Shield of Kaldra", 139, Rarity.RARE, mage.cards.s.ShieldOfKaldra.class)); + cards.add(new SetCardInfo("Shriveling Rot", 54, Rarity.RARE, mage.cards.s.ShrivelingRot.class)); cards.add(new SetCardInfo("Shunt", 68, Rarity.RARE, mage.cards.s.Shunt.class)); cards.add(new SetCardInfo("Skullclamp", 140, Rarity.UNCOMMON, mage.cards.s.Skullclamp.class)); cards.add(new SetCardInfo("Slobad, Goblin Tinkerer", 69, Rarity.RARE, mage.cards.s.SlobadGoblinTinkerer.class)); @@ -157,6 +160,7 @@ public class Darksteel extends ExpansionSet { cards.add(new SetCardInfo("Sword of Fire and Ice", 148, Rarity.RARE, mage.cards.s.SwordOfFireAndIce.class)); cards.add(new SetCardInfo("Sword of Light and Shadow", 149, Rarity.RARE, mage.cards.s.SwordOfLightAndShadow.class)); cards.add(new SetCardInfo("Synod Artificer", 34, Rarity.RARE, mage.cards.s.SynodArtificer.class)); + cards.add(new SetCardInfo("Talon of Pain", 150, Rarity.UNCOMMON, mage.cards.t.TalonOfPain.class)); cards.add(new SetCardInfo("Tangle Golem", 151, Rarity.COMMON, mage.cards.t.TangleGolem.class)); cards.add(new SetCardInfo("Tangle Spider", 85, Rarity.COMMON, mage.cards.t.TangleSpider.class)); cards.add(new SetCardInfo("Tanglewalker", 86, Rarity.UNCOMMON, mage.cards.t.Tanglewalker.class)); diff --git a/Mage.Sets/src/mage/sets/Dissension.java b/Mage.Sets/src/mage/sets/Dissension.java index 3bc0aaaf64..58724c4ca4 100644 --- a/Mage.Sets/src/mage/sets/Dissension.java +++ b/Mage.Sets/src/mage/sets/Dissension.java @@ -71,7 +71,7 @@ public class Dissension extends ExpansionSet { cards.add(new SetCardInfo("Blood Crypt", 171, Rarity.RARE, mage.cards.b.BloodCrypt.class)); cards.add(new SetCardInfo("Bond of Agony", 38, Rarity.UNCOMMON, mage.cards.b.BondOfAgony.class)); cards.add(new SetCardInfo("Bound // Determined", 149, Rarity.RARE, mage.cards.b.BoundDetermined.class)); - cards.add(new SetCardInfo("Brace for Impact", 5, Rarity.UNCOMMON, mage.cards.b.BraceForImpact.class)); + cards.add(new SetCardInfo("Brace for Impact", 5, Rarity.UNCOMMON, mage.cards.b.BraceForImpact.class)); cards.add(new SetCardInfo("Brain Pry", 39, Rarity.UNCOMMON, mage.cards.b.BrainPry.class)); cards.add(new SetCardInfo("Breeding Pool", 172, Rarity.RARE, mage.cards.b.BreedingPool.class)); cards.add(new SetCardInfo("Bronze Bombshell", 160, Rarity.RARE, mage.cards.b.BronzeBombshell.class)); @@ -118,6 +118,7 @@ public class Dissension extends ExpansionSet { cards.add(new SetCardInfo("Indrik Stomphowler", 86, Rarity.UNCOMMON, mage.cards.i.IndrikStomphowler.class)); cards.add(new SetCardInfo("Infernal Tutor", 46, Rarity.RARE, mage.cards.i.InfernalTutor.class)); cards.add(new SetCardInfo("Isperia the Inscrutable", 114, Rarity.RARE, mage.cards.i.IsperiaTheInscrutable.class)); + cards.add(new SetCardInfo("Jagged Poppet", 115, Rarity.UNCOMMON, mage.cards.j.JaggedPoppet.class)); cards.add(new SetCardInfo("Kill-Suit Cultist", 65, Rarity.COMMON, mage.cards.k.KillSuitCultist.class)); cards.add(new SetCardInfo("Kindle the Carnage", 66, Rarity.UNCOMMON, mage.cards.k.KindleTheCarnage.class)); cards.add(new SetCardInfo("Leafdrake Roost", 116, Rarity.UNCOMMON, mage.cards.l.LeafdrakeRoost.class)); @@ -199,7 +200,7 @@ public class Dissension extends ExpansionSet { cards.add(new SetCardInfo("Trial // Error", 158, Rarity.UNCOMMON, mage.cards.t.TrialError.class)); cards.add(new SetCardInfo("Trygon Predator", 133, Rarity.UNCOMMON, mage.cards.t.TrygonPredator.class)); cards.add(new SetCardInfo("Twinstrike", 134, Rarity.UNCOMMON, mage.cards.t.Twinstrike.class)); - cards.add(new SetCardInfo("Unliving Psychopath", 56, Rarity.RARE, mage.cards.u.UnlivingPsychopath.class)); + cards.add(new SetCardInfo("Unliving Psychopath", 56, Rarity.RARE, mage.cards.u.UnlivingPsychopath.class)); cards.add(new SetCardInfo("Utopia Sprawl", 99, Rarity.COMMON, mage.cards.u.UtopiaSprawl.class)); cards.add(new SetCardInfo("Utvara Scalper", 76, Rarity.COMMON, mage.cards.u.UtvaraScalper.class)); cards.add(new SetCardInfo("Valor Made Real", 20, Rarity.COMMON, mage.cards.v.ValorMadeReal.class)); diff --git a/Mage.Sets/src/mage/sets/EighthEdition.java b/Mage.Sets/src/mage/sets/EighthEdition.java index 1d6c7f307a..e9d4a733f6 100644 --- a/Mage.Sets/src/mage/sets/EighthEdition.java +++ b/Mage.Sets/src/mage/sets/EighthEdition.java @@ -350,6 +350,7 @@ public class EighthEdition extends ExpansionSet { cards.add(new SetCardInfo("Venerable Monk", 55, Rarity.COMMON, mage.cards.v.VenerableMonk.class)); cards.add(new SetCardInfo("Verduran Enchantress", 285, Rarity.RARE, mage.cards.v.VerduranEnchantress.class)); cards.add(new SetCardInfo("Vernal Bloom", 286, Rarity.RARE, mage.cards.v.VernalBloom.class)); + cards.add(new SetCardInfo("Vexing Arcanix", 319, Rarity.RARE, mage.cards.v.VexingArcanix.class)); cards.add(new SetCardInfo("Viashino Sandstalker", 230, Rarity.UNCOMMON, mage.cards.v.ViashinoSandstalker.class)); cards.add(new SetCardInfo("Vicious Hunger", 171, Rarity.COMMON, mage.cards.v.ViciousHunger.class)); cards.add(new SetCardInfo("Vine Trellis", 287, Rarity.COMMON, mage.cards.v.VineTrellis.class)); diff --git a/Mage.Sets/src/mage/sets/Exodus.java b/Mage.Sets/src/mage/sets/Exodus.java index 65d7537e62..59c6cd1644 100644 --- a/Mage.Sets/src/mage/sets/Exodus.java +++ b/Mage.Sets/src/mage/sets/Exodus.java @@ -76,7 +76,7 @@ public class Exodus extends ExpansionSet { cards.add(new SetCardInfo("Dauthi Warlord", 59, Rarity.UNCOMMON, mage.cards.d.DauthiWarlord.class)); cards.add(new SetCardInfo("Death's Duet", 60, Rarity.COMMON, mage.cards.d.DeathsDuet.class)); cards.add(new SetCardInfo("Dominating Licid", 30, Rarity.RARE, mage.cards.d.DominatingLicid.class)); - cards.add(new SetCardInfo("Elven Palisade", 109, Rarity.UNCOMMON, mage.cards.e.ElvenPalisade.class)); + cards.add(new SetCardInfo("Elven Palisade", 109, Rarity.UNCOMMON, mage.cards.e.ElvenPalisade.class)); cards.add(new SetCardInfo("Elvish Berserker", 110, Rarity.COMMON, mage.cards.e.ElvishBerserker.class)); cards.add(new SetCardInfo("Entropic Specter", 61, Rarity.RARE, mage.cards.e.EntropicSpecter.class)); cards.add(new SetCardInfo("Ephemeron", 31, Rarity.RARE, mage.cards.e.Ephemeron.class)); @@ -104,8 +104,9 @@ public class Exodus extends ExpansionSet { cards.add(new SetCardInfo("Merfolk Looter", 39, Rarity.COMMON, mage.cards.m.MerfolkLooter.class)); cards.add(new SetCardInfo("Mindless Automaton", 135, Rarity.RARE, mage.cards.m.MindlessAutomaton.class)); cards.add(new SetCardInfo("Mind Over Matter", 40, Rarity.RARE, mage.cards.m.MindOverMatter.class)); - cards.add(new SetCardInfo("Mirozel", 41, Rarity.UNCOMMON, mage.cards.m.Mirozel.class)); + cards.add(new SetCardInfo("Mirozel", 41, Rarity.UNCOMMON, mage.cards.m.Mirozel.class)); cards.add(new SetCardInfo("Mirri, Cat Warrior", 114, Rarity.RARE, mage.cards.m.MirriCatWarrior.class)); + cards.add(new SetCardInfo("Mogg Assassin", 88, Rarity.UNCOMMON, mage.cards.m.MoggAssassin.class)); cards.add(new SetCardInfo("Nausea", 67, Rarity.COMMON, mage.cards.n.Nausea.class)); cards.add(new SetCardInfo("Necrologia", 68, Rarity.UNCOMMON, mage.cards.n.Necrologia.class)); cards.add(new SetCardInfo("Null Brooch", 136, Rarity.RARE, mage.cards.n.NullBrooch.class)); @@ -123,7 +124,7 @@ public class Exodus extends ExpansionSet { cards.add(new SetCardInfo("Pit Spawn", 70, Rarity.RARE, mage.cards.p.PitSpawn.class)); cards.add(new SetCardInfo("Plaguebearer", 71, Rarity.RARE, mage.cards.p.Plaguebearer.class)); cards.add(new SetCardInfo("Plated Rootwalla", 116, Rarity.COMMON, mage.cards.p.PlatedRootwalla.class)); - cards.add(new SetCardInfo("Predatory Hunger", 117, Rarity.COMMON, mage.cards.p.PredatoryHunger.class)); + cards.add(new SetCardInfo("Predatory Hunger", 117, Rarity.COMMON, mage.cards.p.PredatoryHunger.class)); cards.add(new SetCardInfo("Price of Progress", 95, Rarity.UNCOMMON, mage.cards.p.PriceOfProgress.class)); cards.add(new SetCardInfo("Pygmy Troll", 118, Rarity.COMMON, mage.cards.p.PygmyTroll.class)); cards.add(new SetCardInfo("Rabid Wolverines", 119, Rarity.COMMON, mage.cards.r.RabidWolverines.class)); @@ -134,19 +135,19 @@ public class Exodus extends ExpansionSet { cards.add(new SetCardInfo("Reclaim", 120, Rarity.COMMON, mage.cards.r.Reclaim.class)); cards.add(new SetCardInfo("Reconnaissance", 17, Rarity.UNCOMMON, mage.cards.r.Reconnaissance.class)); cards.add(new SetCardInfo("Recurring Nightmare", 72, Rarity.RARE, mage.cards.r.RecurringNightmare.class)); - cards.add(new SetCardInfo("Resuscitate", 121, Rarity.UNCOMMON, mage.cards.r.Resuscitate.class)); + cards.add(new SetCardInfo("Resuscitate", 121, Rarity.UNCOMMON, mage.cards.r.Resuscitate.class)); cards.add(new SetCardInfo("Robe of Mirrors", 43, Rarity.COMMON, mage.cards.r.RobeOfMirrors.class)); cards.add(new SetCardInfo("Rootwater Alligator", 122, Rarity.COMMON, mage.cards.r.RootwaterAlligator.class)); cards.add(new SetCardInfo("Rootwater Mystic", 44, Rarity.COMMON, mage.cards.r.RootwaterMystic.class)); cards.add(new SetCardInfo("Sabertooth Wyvern", 99, Rarity.UNCOMMON, mage.cards.s.SabertoothWyvern.class)); - cards.add(new SetCardInfo("Scalding Salamander", 100, Rarity.UNCOMMON, mage.cards.s.ScaldingSalamander.class)); + cards.add(new SetCardInfo("Scalding Salamander", 100, Rarity.UNCOMMON, mage.cards.s.ScaldingSalamander.class)); cards.add(new SetCardInfo("Scare Tactics", 73, Rarity.COMMON, mage.cards.s.ScareTactics.class)); cards.add(new SetCardInfo("School of Piranha", 45, Rarity.COMMON, mage.cards.s.SchoolOfPiranha.class)); cards.add(new SetCardInfo("Scrivener", 46, Rarity.UNCOMMON, mage.cards.s.Scrivener.class)); cards.add(new SetCardInfo("Seismic Assault", 101, Rarity.RARE, mage.cards.s.SeismicAssault.class)); cards.add(new SetCardInfo("Shackles", 18, Rarity.COMMON, mage.cards.s.Shackles.class)); cards.add(new SetCardInfo("Shattering Pulse", 102, Rarity.COMMON, mage.cards.s.ShatteringPulse.class)); - cards.add(new SetCardInfo("Shield Mate", 19, Rarity.COMMON, mage.cards.s.ShieldMate.class)); + cards.add(new SetCardInfo("Shield Mate", 19, Rarity.COMMON, mage.cards.s.ShieldMate.class)); cards.add(new SetCardInfo("Skyshaper", 137, Rarity.UNCOMMON, mage.cards.s.Skyshaper.class)); cards.add(new SetCardInfo("Skyshroud Elite", 123, Rarity.UNCOMMON, mage.cards.s.SkyshroudElite.class)); cards.add(new SetCardInfo("Slaughter", 74, Rarity.UNCOMMON, mage.cards.s.Slaughter.class)); @@ -178,6 +179,6 @@ public class Exodus extends ExpansionSet { cards.add(new SetCardInfo("Whiptongue Frog", 52, Rarity.COMMON, mage.cards.w.WhiptongueFrog.class)); cards.add(new SetCardInfo("Wood Elves", 130, Rarity.COMMON, mage.cards.w.WoodElves.class)); cards.add(new SetCardInfo("Workhorse", 142, Rarity.RARE, mage.cards.w.Workhorse.class)); - cards.add(new SetCardInfo("Zealots en-Dal", 26, Rarity.UNCOMMON, mage.cards.z.ZealotsEnDal.class)); + cards.add(new SetCardInfo("Zealots en-Dal", 26, Rarity.UNCOMMON, mage.cards.z.ZealotsEnDal.class)); } } diff --git a/Mage.Sets/src/mage/sets/FallenEmpires.java b/Mage.Sets/src/mage/sets/FallenEmpires.java index aa73229d50..bbfed14790 100644 --- a/Mage.Sets/src/mage/sets/FallenEmpires.java +++ b/Mage.Sets/src/mage/sets/FallenEmpires.java @@ -219,6 +219,9 @@ public class FallenEmpires extends ExpansionSet { cards.add(new SetCardInfo("Seasinger", 52, Rarity.UNCOMMON, mage.cards.s.Seasinger.class)); cards.add(new SetCardInfo("Soul Exchange", 28, Rarity.UNCOMMON, mage.cards.s.SoulExchange.class)); cards.add(new SetCardInfo("Spirit Shield", 175, Rarity.RARE, mage.cards.s.SpiritShield.class)); + cards.add(new SetCardInfo("Spore Cloud", 83, Rarity.COMMON, mage.cards.s.SporeCloud.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Spore Cloud", 84, Rarity.COMMON, mage.cards.s.SporeCloud.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Spore Cloud", 85, Rarity.COMMON, mage.cards.s.SporeCloud.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Spore Flower", 86, Rarity.UNCOMMON, mage.cards.s.SporeFlower.class)); cards.add(new SetCardInfo("Svyelunite Priest", 53, Rarity.UNCOMMON, mage.cards.s.SvyelunitePriest.class)); cards.add(new SetCardInfo("Svyelunite Temple", 187, Rarity.UNCOMMON, mage.cards.s.SvyeluniteTemple.class)); @@ -237,6 +240,7 @@ public class FallenEmpires extends ExpansionSet { cards.add(new SetCardInfo("Thrull Retainer", 30, Rarity.UNCOMMON, mage.cards.t.ThrullRetainer.class)); cards.add(new SetCardInfo("Thrull Wizard", 31, Rarity.UNCOMMON, mage.cards.t.ThrullWizard.class)); cards.add(new SetCardInfo("Tidal Influence", 57, Rarity.UNCOMMON, mage.cards.t.TidalInfluence.class)); + cards.add(new SetCardInfo("Tourach's Gate", 33, Rarity.RARE, mage.cards.t.TourachsGate.class)); cards.add(new SetCardInfo("Vodalian Knights", 58, Rarity.RARE, mage.cards.v.VodalianKnights.class)); cards.add(new SetCardInfo("Vodalian Mage", 59, Rarity.COMMON, VodalianMage.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Vodalian Mage", 60, Rarity.COMMON, VodalianMage.class, NON_FULL_USE_VARIOUS)); diff --git a/Mage.Sets/src/mage/sets/FifthEdition.java b/Mage.Sets/src/mage/sets/FifthEdition.java index c04cc7dae8..0ba5e924b3 100644 --- a/Mage.Sets/src/mage/sets/FifthEdition.java +++ b/Mage.Sets/src/mage/sets/FifthEdition.java @@ -217,6 +217,7 @@ public class FifthEdition extends ExpansionSet { cards.add(new SetCardInfo("Icatian Scout", 313, Rarity.COMMON, IcatianScout.class)); cards.add(new SetCardInfo("Icatian Store", 423, Rarity.RARE, mage.cards.i.IcatianStore.class)); cards.add(new SetCardInfo("Icatian Town", 314, Rarity.RARE, mage.cards.i.IcatianTown.class)); + cards.add(new SetCardInfo("Ice Floe", 424, Rarity.UNCOMMON, mage.cards.i.IceFloe.class)); cards.add(new SetCardInfo("Imposing Visage", 241, Rarity.COMMON, mage.cards.i.ImposingVisage.class)); cards.add(new SetCardInfo("Incinerate", 242, Rarity.COMMON, mage.cards.i.Incinerate.class)); cards.add(new SetCardInfo("Inferno", 243, Rarity.RARE, mage.cards.i.Inferno.class)); @@ -252,7 +253,7 @@ public class FifthEdition extends ExpansionSet { cards.add(new SetCardInfo("Knight of Stromgald", 33, Rarity.UNCOMMON, mage.cards.k.KnightOfStromgald.class)); cards.add(new SetCardInfo("Krovikan Fetish", 34, Rarity.COMMON, mage.cards.k.KrovikanFetish.class)); cards.add(new SetCardInfo("Krovikan Sorcerer", 96, Rarity.COMMON, mage.cards.k.KrovikanSorcerer.class)); - cards.add(new SetCardInfo("Labyrinth Minotaur", 97, Rarity.COMMON, mage.cards.l.LabyrinthMinotaur.class)); + cards.add(new SetCardInfo("Labyrinth Minotaur", 97, Rarity.COMMON, mage.cards.l.LabyrinthMinotaur.class)); cards.add(new SetCardInfo("Leshrac's Rite", 35, Rarity.UNCOMMON, mage.cards.l.LeshracsRite.class)); cards.add(new SetCardInfo("Leviathan", 98, Rarity.RARE, mage.cards.l.Leviathan.class)); cards.add(new SetCardInfo("Ley Druid", 170, Rarity.COMMON, mage.cards.l.LeyDruid.class)); @@ -300,7 +301,7 @@ public class FifthEdition extends ExpansionSet { cards.add(new SetCardInfo("Orcish Artillery", 253, Rarity.UNCOMMON, mage.cards.o.OrcishArtillery.class)); cards.add(new SetCardInfo("Orcish Captain", 254, Rarity.UNCOMMON, mage.cards.o.OrcishCaptain.class)); cards.add(new SetCardInfo("Orcish Oriflamme", 257, Rarity.UNCOMMON, mage.cards.o.OrcishOriflamme.class)); - cards.add(new SetCardInfo("Orcish Squatters", 258, Rarity.RARE, mage.cards.o.OrcishSquatters.class)); + cards.add(new SetCardInfo("Orcish Squatters", 258, Rarity.RARE, mage.cards.o.OrcishSquatters.class)); cards.add(new SetCardInfo("Order of the Sacred Torch", 324, Rarity.RARE, mage.cards.o.OrderOfTheSacredTorch.class)); cards.add(new SetCardInfo("Order of the White Shield", 325, Rarity.UNCOMMON, mage.cards.o.OrderOfTheWhiteShield.class)); cards.add(new SetCardInfo("Orgg", 259, Rarity.RARE, mage.cards.o.Orgg.class)); @@ -327,6 +328,7 @@ public class FifthEdition extends ExpansionSet { cards.add(new SetCardInfo("Pradesh Gypsies", 179, Rarity.COMMON, mage.cards.p.PradeshGypsies.class)); cards.add(new SetCardInfo("Primal Clay", 395, Rarity.RARE, mage.cards.p.PrimalClay.class)); cards.add(new SetCardInfo("Primal Order", 180, Rarity.RARE, mage.cards.p.PrimalOrder.class)); + cards.add(new SetCardInfo("Prismatic Ward", 329, Rarity.COMMON, mage.cards.p.PrismaticWard.class)); cards.add(new SetCardInfo("Prodigal Sorcerer", 112, Rarity.COMMON, mage.cards.p.ProdigalSorcerer.class)); cards.add(new SetCardInfo("Psychic Venom", 113, Rarity.COMMON, mage.cards.p.PsychicVenom.class)); cards.add(new SetCardInfo("Pyroblast", 262, Rarity.UNCOMMON, mage.cards.p.Pyroblast.class)); @@ -400,6 +402,7 @@ public class FifthEdition extends ExpansionSet { cards.add(new SetCardInfo("Throne of Bone", 403, Rarity.UNCOMMON, mage.cards.t.ThroneOfBone.class)); cards.add(new SetCardInfo("Thrull Retainer", 60, Rarity.UNCOMMON, mage.cards.t.ThrullRetainer.class)); cards.add(new SetCardInfo("Time Bomb", 404, Rarity.RARE, mage.cards.t.TimeBomb.class)); + cards.add(new SetCardInfo("Time Elemental", 129, Rarity.RARE, mage.cards.t.TimeElemental.class)); cards.add(new SetCardInfo("Titania's Song", 194, Rarity.RARE, mage.cards.t.TitaniasSong.class)); cards.add(new SetCardInfo("Torture", 61, Rarity.COMMON, Torture.class)); cards.add(new SetCardInfo("Touch of Death", 62, Rarity.COMMON, mage.cards.t.TouchOfDeath.class)); @@ -437,7 +440,7 @@ public class FifthEdition extends ExpansionSet { cards.add(new SetCardInfo("Wild Growth", 204, Rarity.COMMON, mage.cards.w.WildGrowth.class)); cards.add(new SetCardInfo("Winds of Change", 275, Rarity.RARE, mage.cards.w.WindsOfChange.class)); cards.add(new SetCardInfo("Wind Spirit", 136, Rarity.UNCOMMON, mage.cards.w.WindSpirit.class)); - cards.add(new SetCardInfo("Winter Blast", 205, Rarity.UNCOMMON, mage.cards.w.WinterBlast.class)); + cards.add(new SetCardInfo("Winter Blast", 205, Rarity.UNCOMMON, mage.cards.w.WinterBlast.class)); cards.add(new SetCardInfo("Winter Orb", 408, Rarity.RARE, mage.cards.w.WinterOrb.class)); cards.add(new SetCardInfo("Wolverine Pack", 206, Rarity.UNCOMMON, mage.cards.w.WolverinePack.class)); cards.add(new SetCardInfo("Wooden Sphere", 409, Rarity.UNCOMMON, mage.cards.w.WoodenSphere.class)); diff --git a/Mage.Sets/src/mage/sets/FourthEdition.java b/Mage.Sets/src/mage/sets/FourthEdition.java index f44d101070..263ec33b0d 100644 --- a/Mage.Sets/src/mage/sets/FourthEdition.java +++ b/Mage.Sets/src/mage/sets/FourthEdition.java @@ -359,6 +359,7 @@ public class FourthEdition extends ExpansionSet { cards.add(new SetCardInfo("Thicket Basilisk", 158, Rarity.UNCOMMON, mage.cards.t.ThicketBasilisk.class)); cards.add(new SetCardInfo("Thoughtlace", 107, Rarity.RARE, mage.cards.t.Thoughtlace.class)); cards.add(new SetCardInfo("Throne of Bone", 371, Rarity.UNCOMMON, mage.cards.t.ThroneOfBone.class)); + cards.add(new SetCardInfo("Time Elemental", 108, Rarity.RARE, mage.cards.t.TimeElemental.class)); cards.add(new SetCardInfo("Titania's Song", 160, Rarity.RARE, mage.cards.t.TitaniasSong.class)); cards.add(new SetCardInfo("Tranquility", 161, Rarity.COMMON, mage.cards.t.Tranquility.class)); cards.add(new SetCardInfo("Triskelion", 372, Rarity.RARE, mage.cards.t.Triskelion.class)); diff --git a/Mage.Sets/src/mage/sets/FutureSight.java b/Mage.Sets/src/mage/sets/FutureSight.java index 14ab9c9bfc..1fd069f0cc 100644 --- a/Mage.Sets/src/mage/sets/FutureSight.java +++ b/Mage.Sets/src/mage/sets/FutureSight.java @@ -188,6 +188,7 @@ public class FutureSight extends ExpansionSet { cards.add(new SetCardInfo("Seht's Tiger", 31, Rarity.RARE, mage.cards.s.SehtsTiger.class)); cards.add(new SetCardInfo("Shapeshifter's Marrow", 58, Rarity.RARE, mage.cards.s.ShapeshiftersMarrow.class)); cards.add(new SetCardInfo("Shimian Specter", 76, Rarity.RARE, mage.cards.s.ShimianSpecter.class)); + cards.add(new SetCardInfo("Shivan Sand-Mage", 108, Rarity.UNCOMMON, mage.cards.s.ShivanSandMage.class)); cards.add(new SetCardInfo("Skirk Ridge Exhumer", 77, Rarity.UNCOMMON, mage.cards.s.SkirkRidgeExhumer.class)); cards.add(new SetCardInfo("Skizzik Surger", 120, Rarity.UNCOMMON, mage.cards.s.SkizzikSurger.class)); cards.add(new SetCardInfo("Slaughter Pact", 78, Rarity.RARE, mage.cards.s.SlaughterPact.class)); diff --git a/Mage.Sets/src/mage/sets/Guildpact.java b/Mage.Sets/src/mage/sets/Guildpact.java index 5b51825dd8..e1d9e70c17 100644 --- a/Mage.Sets/src/mage/sets/Guildpact.java +++ b/Mage.Sets/src/mage/sets/Guildpact.java @@ -61,7 +61,7 @@ public class Guildpact extends ExpansionSet { cards.add(new SetCardInfo("Beastmaster's Magemark", 80, Rarity.COMMON, mage.cards.b.BeastmastersMagemark.class)); cards.add(new SetCardInfo("Belfry Spirit", 2, Rarity.UNCOMMON, mage.cards.b.BelfrySpirit.class)); cards.add(new SetCardInfo("Benediction of Moons", 3, Rarity.COMMON, mage.cards.b.BenedictionOfMoons.class)); - cards.add(new SetCardInfo("Bioplasm", 81, Rarity.RARE, mage.cards.b.Bioplasm.class)); + cards.add(new SetCardInfo("Bioplasm", 81, Rarity.RARE, mage.cards.b.Bioplasm.class)); cards.add(new SetCardInfo("Blind Hunter", 102, Rarity.COMMON, mage.cards.b.BlindHunter.class)); cards.add(new SetCardInfo("Bloodscale Prowler", 64, Rarity.COMMON, mage.cards.b.BloodscaleProwler.class)); cards.add(new SetCardInfo("Borborygmos", 103, Rarity.RARE, mage.cards.b.Borborygmos.class)); @@ -73,13 +73,14 @@ public class Guildpact extends ExpansionSet { cards.add(new SetCardInfo("Crash Landing", 82, Rarity.UNCOMMON, mage.cards.c.CrashLanding.class)); cards.add(new SetCardInfo("Cremate", 45, Rarity.COMMON, mage.cards.c.Cremate.class)); cards.add(new SetCardInfo("Cry of Contrition", 46, Rarity.COMMON, mage.cards.c.CryOfContrition.class)); + cards.add(new SetCardInfo("Cryptwailing", 47, Rarity.UNCOMMON, mage.cards.c.Cryptwailing.class)); cards.add(new SetCardInfo("Crystal Seer", 23, Rarity.UNCOMMON, mage.cards.c.CrystalSeer.class)); cards.add(new SetCardInfo("Culling Sun", 109, Rarity.RARE, mage.cards.c.CullingSun.class)); cards.add(new SetCardInfo("Daggerclaw Imp", 48, Rarity.UNCOMMON, mage.cards.d.DaggerclawImp.class)); cards.add(new SetCardInfo("Debtors' Knell", 141, Rarity.RARE, mage.cards.d.DebtorsKnell.class)); cards.add(new SetCardInfo("Djinn Illuminatus", 142, Rarity.RARE, mage.cards.d.DjinnIlluminatus.class)); cards.add(new SetCardInfo("Douse in Gloom", 49, Rarity.COMMON, mage.cards.d.DouseInGloom.class)); - cards.add(new SetCardInfo("Droning Bureaucrats", 4, Rarity.UNCOMMON, mage.cards.d.DroningBureaucrats.class)); + cards.add(new SetCardInfo("Droning Bureaucrats", 4, Rarity.UNCOMMON, mage.cards.d.DroningBureaucrats.class)); cards.add(new SetCardInfo("Drowned Rusalka", 24, Rarity.UNCOMMON, mage.cards.d.DrownedRusalka.class)); cards.add(new SetCardInfo("Dryad Sophisticate", 83, Rarity.UNCOMMON, mage.cards.d.DryadSophisticate.class)); cards.add(new SetCardInfo("Dune-Brood Nephilim", 110, Rarity.RARE, mage.cards.d.DuneBroodNephilim.class)); @@ -121,7 +122,7 @@ public class Guildpact extends ExpansionSet { cards.add(new SetCardInfo("Izzet Chronarch", 119, Rarity.COMMON, mage.cards.i.IzzetChronarch.class)); cards.add(new SetCardInfo("Izzet Guildmage", 145, Rarity.UNCOMMON, mage.cards.i.IzzetGuildmage.class)); cards.add(new SetCardInfo("Izzet Signet", 152, Rarity.COMMON, mage.cards.i.IzzetSignet.class)); - cards.add(new SetCardInfo("Killer Instinct", 120, Rarity.RARE, mage.cards.k.KillerInstinct.class)); + cards.add(new SetCardInfo("Killer Instinct", 120, Rarity.RARE, mage.cards.k.KillerInstinct.class)); cards.add(new SetCardInfo("Leap of Flame", 121, Rarity.COMMON, mage.cards.l.LeapOfFlame.class)); cards.add(new SetCardInfo("Leyline of Lifeforce", 90, Rarity.RARE, mage.cards.l.LeylineOfLifeforce.class)); cards.add(new SetCardInfo("Leyline of Lightning", 68, Rarity.RARE, mage.cards.l.LeylineOfLightning.class)); @@ -129,10 +130,11 @@ public class Guildpact extends ExpansionSet { cards.add(new SetCardInfo("Leyline of the Meek", 10, Rarity.RARE, mage.cards.l.LeylineOfTheMeek.class)); cards.add(new SetCardInfo("Leyline of the Void", 52, Rarity.RARE, mage.cards.l.LeylineOfTheVoid.class)); cards.add(new SetCardInfo("Lionheart Maverick", 11, Rarity.COMMON, mage.cards.l.LionheartMaverick.class)); + cards.add(new SetCardInfo("Living Inferno", 69, Rarity.RARE, mage.cards.l.LivingInferno.class)); cards.add(new SetCardInfo("Martyred Rusalka", 12, Rarity.UNCOMMON, mage.cards.m.MartyredRusalka.class)); cards.add(new SetCardInfo("Mimeofacture", 30, Rarity.RARE, mage.cards.m.Mimeofacture.class)); cards.add(new SetCardInfo("Mizzium Transreliquat", 153, Rarity.RARE, mage.cards.m.MizziumTransreliquat.class)); - cards.add(new SetCardInfo("Moratorium Stone", 154, Rarity.RARE, mage.cards.m.MoratoriumStone.class)); + cards.add(new SetCardInfo("Moratorium Stone", 154, Rarity.RARE, mage.cards.m.MoratoriumStone.class)); cards.add(new SetCardInfo("Mortify", 122, Rarity.UNCOMMON, mage.cards.m.Mortify.class)); cards.add(new SetCardInfo("Mourning Thrull", 146, Rarity.COMMON, mage.cards.m.MourningThrull.class)); cards.add(new SetCardInfo("Necromancer's Magemark", 53, Rarity.COMMON, mage.cards.n.NecromancersMagemark.class)); @@ -166,14 +168,14 @@ public class Guildpact extends ExpansionSet { cards.add(new SetCardInfo("Scab-Clan Mauler", 128, Rarity.COMMON, mage.cards.s.ScabClanMauler.class)); cards.add(new SetCardInfo("Schismotivate", 129, Rarity.UNCOMMON, mage.cards.s.Schismotivate.class)); cards.add(new SetCardInfo("Scorched Rusalka", 74, Rarity.UNCOMMON, mage.cards.s.ScorchedRusalka.class)); - cards.add(new SetCardInfo("Seize the Soul", 61, Rarity.RARE, mage.cards.s.SeizeTheSoul.class)); + cards.add(new SetCardInfo("Seize the Soul", 61, Rarity.RARE, mage.cards.s.SeizeTheSoul.class)); cards.add(new SetCardInfo("Shadow Lance", 14, Rarity.UNCOMMON, mage.cards.s.ShadowLance.class)); cards.add(new SetCardInfo("Shattering Spree", 75, Rarity.UNCOMMON, mage.cards.s.ShatteringSpree.class)); cards.add(new SetCardInfo("Shrieking Grotesque", 15, Rarity.COMMON, mage.cards.s.ShriekingGrotesque.class)); cards.add(new SetCardInfo("Siege of Towers", 76, Rarity.RARE, mage.cards.s.SiegeOfTowers.class)); cards.add(new SetCardInfo("Silhana Ledgewalker", 94, Rarity.COMMON, mage.cards.s.SilhanaLedgewalker.class)); cards.add(new SetCardInfo("Silhana Starfletcher", 95, Rarity.COMMON, mage.cards.s.SilhanaStarfletcher.class)); - cards.add(new SetCardInfo("Sinstriker's Will", 16, Rarity.UNCOMMON, mage.cards.s.SinstrikersWill.class)); + cards.add(new SetCardInfo("Sinstriker's Will", 16, Rarity.UNCOMMON, mage.cards.s.SinstrikersWill.class)); cards.add(new SetCardInfo("Skarrgan Firebird", 77, Rarity.RARE, mage.cards.s.SkarrganFirebird.class)); cards.add(new SetCardInfo("Skarrgan Pit-Skulk", 96, Rarity.COMMON, mage.cards.s.SkarrganPitSkulk.class)); cards.add(new SetCardInfo("Skarrgan Skybreaker", 130, Rarity.UNCOMMON, mage.cards.s.SkarrganSkybreaker.class)); diff --git a/Mage.Sets/src/mage/sets/IceAge.java b/Mage.Sets/src/mage/sets/IceAge.java index 2f96059ac1..f7ca4d9134 100644 --- a/Mage.Sets/src/mage/sets/IceAge.java +++ b/Mage.Sets/src/mage/sets/IceAge.java @@ -151,6 +151,7 @@ public class IceAge extends ExpansionSet { cards.add(new SetCardInfo("Glacial Chasm", 331, Rarity.UNCOMMON, mage.cards.g.GlacialChasm.class)); cards.add(new SetCardInfo("Glacial Crevasses", 187, Rarity.RARE, mage.cards.g.GlacialCrevasses.class)); cards.add(new SetCardInfo("Glacial Wall", 71, Rarity.UNCOMMON, mage.cards.g.GlacialWall.class)); + cards.add(new SetCardInfo("Goblin Lyre", 294, Rarity.RARE, mage.cards.g.GoblinLyre.class)); cards.add(new SetCardInfo("Goblin Mutant", 188, Rarity.UNCOMMON, mage.cards.g.GoblinMutant.class)); cards.add(new SetCardInfo("Goblin Snowman", 191, Rarity.UNCOMMON, mage.cards.g.GoblinSnowman.class)); cards.add(new SetCardInfo("Gorilla Pack", 135, Rarity.COMMON, mage.cards.g.GorillaPack.class)); @@ -167,6 +168,7 @@ public class IceAge extends ExpansionSet { cards.add(new SetCardInfo("Hyalopterous Lemure", 21, Rarity.UNCOMMON, mage.cards.h.HyalopterousLemure.class)); cards.add(new SetCardInfo("Hydroblast", 72, Rarity.COMMON, mage.cards.h.Hydroblast.class)); cards.add(new SetCardInfo("Hymn of Rebirth", 373, Rarity.UNCOMMON, mage.cards.h.HymnOfRebirth.class)); + cards.add(new SetCardInfo("Ice Floe", 333, Rarity.UNCOMMON, mage.cards.i.IceFloe.class)); cards.add(new SetCardInfo("Iceberg", 73, Rarity.UNCOMMON, mage.cards.i.Iceberg.class)); cards.add(new SetCardInfo("Icequake", 22, Rarity.UNCOMMON, mage.cards.i.Icequake.class)); cards.add(new SetCardInfo("Icy Manipulator", 297, Rarity.UNCOMMON, mage.cards.i.IcyManipulator.class)); @@ -211,6 +213,8 @@ public class IceAge extends ExpansionSet { cards.add(new SetCardInfo("Magus of the Unseen", 82, Rarity.RARE, mage.cards.m.MagusOfTheUnseen.class)); cards.add(new SetCardInfo("Malachite Talisman", 303, Rarity.UNCOMMON, mage.cards.m.MalachiteTalisman.class)); cards.add(new SetCardInfo("Marton Stromgald", 199, Rarity.RARE, mage.cards.m.MartonStromgald.class)); + cards.add(new SetCardInfo("Melee", 200, Rarity.UNCOMMON, mage.cards.m.Melee.class)); + cards.add(new SetCardInfo("Melting", 201, Rarity.UNCOMMON, mage.cards.m.Melting.class)); cards.add(new SetCardInfo("Merieke Ri Berit", 375, Rarity.RARE, mage.cards.m.MeriekeRiBerit.class)); cards.add(new SetCardInfo("Mesmeric Trance", 83, Rarity.RARE, mage.cards.m.MesmericTrance.class)); cards.add(new SetCardInfo("Meteor Shower", 202, Rarity.COMMON, mage.cards.m.MeteorShower.class)); @@ -231,6 +235,7 @@ public class IceAge extends ExpansionSet { cards.add(new SetCardInfo("Naked Singularity", 305, Rarity.RARE, mage.cards.n.NakedSingularity.class)); cards.add(new SetCardInfo("Nature's Lore", 143, Rarity.UNCOMMON, mage.cards.n.NaturesLore.class)); cards.add(new SetCardInfo("Necropotence", 42, Rarity.RARE, mage.cards.n.Necropotence.class)); + cards.add(new SetCardInfo("Norritt", 43, Rarity.COMMON, mage.cards.n.Norritt.class)); cards.add(new SetCardInfo("Onyx Talisman", 306, Rarity.UNCOMMON, mage.cards.o.OnyxTalisman.class)); cards.add(new SetCardInfo("Orcish Cannoneers", 205, Rarity.UNCOMMON, mage.cards.o.OrcishCannoneers.class)); cards.add(new SetCardInfo("Orcish Healer", 208, Rarity.UNCOMMON, mage.cards.o.OrcishHealer.class)); @@ -251,6 +256,7 @@ public class IceAge extends ExpansionSet { cards.add(new SetCardInfo("Portent", 90, Rarity.COMMON, mage.cards.p.Portent.class)); cards.add(new SetCardInfo("Power Sink", 91, Rarity.COMMON, mage.cards.p.PowerSink.class)); cards.add(new SetCardInfo("Pox", 46, Rarity.RARE, mage.cards.p.Pox.class)); + cards.add(new SetCardInfo("Prismatic Ward", 271, Rarity.COMMON, mage.cards.p.PrismaticWard.class)); cards.add(new SetCardInfo("Pygmy Allosaurus", 145, Rarity.RARE, mage.cards.p.PygmyAllosaurus.class)); cards.add(new SetCardInfo("Pyknite", 146, Rarity.COMMON, mage.cards.p.Pyknite.class)); cards.add(new SetCardInfo("Pyroblast", 213, Rarity.COMMON, mage.cards.p.Pyroblast.class)); @@ -272,6 +278,7 @@ public class IceAge extends ExpansionSet { cards.add(new SetCardInfo("Shambling Strider", 151, Rarity.COMMON, mage.cards.s.ShamblingStrider.class)); cards.add(new SetCardInfo("Shatter", 216, Rarity.COMMON, mage.cards.s.Shatter.class)); cards.add(new SetCardInfo("Shield of the Ages", 310, Rarity.UNCOMMON, mage.cards.s.ShieldOfTheAges.class)); + cards.add(new SetCardInfo("Shyft", 96, Rarity.RARE, mage.cards.s.Shyft.class)); cards.add(new SetCardInfo("Sibilant Spirit", 97, Rarity.RARE, mage.cards.s.SibilantSpirit.class)); cards.add(new SetCardInfo("Silver Erne", 98, Rarity.UNCOMMON, mage.cards.s.SilverErne.class)); cards.add(new SetCardInfo("Skeleton Ship", 379, Rarity.RARE, mage.cards.s.SkeletonShip.class)); @@ -313,6 +320,7 @@ public class IceAge extends ExpansionSet { cards.add(new SetCardInfo("Time Bomb", 317, Rarity.RARE, mage.cards.t.TimeBomb.class)); cards.add(new SetCardInfo("Tinder Wall", 158, Rarity.COMMON, mage.cards.t.TinderWall.class)); cards.add(new SetCardInfo("Tor Giant", 220, Rarity.COMMON, mage.cards.t.TorGiant.class)); + cards.add(new SetCardInfo("Total War", 221, Rarity.RARE, mage.cards.t.TotalWar.class)); cards.add(new SetCardInfo("Touch of Death", 55, Rarity.COMMON, mage.cards.t.TouchOfDeath.class)); cards.add(new SetCardInfo("Trailblazer", 160, Rarity.RARE, mage.cards.t.Trailblazer.class)); cards.add(new SetCardInfo("Underground River", 357, Rarity.RARE, mage.cards.u.UndergroundRiver.class)); @@ -320,6 +328,7 @@ public class IceAge extends ExpansionSet { cards.add(new SetCardInfo("Urza's Bauble", 318, Rarity.UNCOMMON, mage.cards.u.UrzasBauble.class)); cards.add(new SetCardInfo("Veldt", 358, Rarity.RARE, mage.cards.v.Veldt.class)); cards.add(new SetCardInfo("Vertigo", 222, Rarity.UNCOMMON, mage.cards.v.Vertigo.class)); + cards.add(new SetCardInfo("Vexing Arcanix", 319, Rarity.RARE, mage.cards.v.VexingArcanix.class)); cards.add(new SetCardInfo("Vibrating Sphere", 320, Rarity.RARE, mage.cards.v.VibratingSphere.class)); cards.add(new SetCardInfo("Walking Wall", 321, Rarity.UNCOMMON, mage.cards.w.WalkingWall.class)); cards.add(new SetCardInfo("Wall of Lava", 223, Rarity.UNCOMMON, mage.cards.w.WallOfLava.class)); diff --git a/Mage.Sets/src/mage/sets/Invasion.java b/Mage.Sets/src/mage/sets/Invasion.java index 1a287d0fe7..a0d5f71e37 100644 --- a/Mage.Sets/src/mage/sets/Invasion.java +++ b/Mage.Sets/src/mage/sets/Invasion.java @@ -292,7 +292,7 @@ public class Invasion extends ExpansionSet { cards.add(new SetCardInfo("Slimy Kavu", 170, Rarity.COMMON, mage.cards.s.SlimyKavu.class)); cards.add(new SetCardInfo("Slinking Serpent", 274, Rarity.UNCOMMON, mage.cards.s.SlinkingSerpent.class)); cards.add(new SetCardInfo("Smoldering Tar", 275, Rarity.UNCOMMON, mage.cards.s.SmolderingTar.class)); - cards.add(new SetCardInfo("Soul Burn", 351, Rarity.COMMON, mage.cards.s.SoulBurn.class)); + cards.add(new SetCardInfo("Soul Burn", 124, Rarity.COMMON, mage.cards.s.SoulBurn.class)); cards.add(new SetCardInfo("Sparring Golem", 312, Rarity.UNCOMMON, mage.cards.s.SparringGolem.class)); cards.add(new SetCardInfo("Spinal Embrace", 276, Rarity.RARE, mage.cards.s.SpinalEmbrace.class)); cards.add(new SetCardInfo("Spirit of Resistance", 38, Rarity.RARE, mage.cards.s.SpiritOfResistance.class)); @@ -345,7 +345,6 @@ public class Invasion extends ExpansionSet { cards.add(new SetCardInfo("Tsabo's Decree", 129, Rarity.RARE, mage.cards.t.TsabosDecree.class)); cards.add(new SetCardInfo("Tsabo's Web", 317, Rarity.RARE, mage.cards.t.TsabosWeb.class)); cards.add(new SetCardInfo("Tsabo Tavoc", 281, Rarity.RARE, mage.cards.t.TsaboTavoc.class)); - cards.add(new SetCardInfo("Tsabo's Assassin", 128, Rarity.RARE, mage.cards.t.TsabosAssassin.class)); cards.add(new SetCardInfo("Turf Wound", 177, Rarity.COMMON, mage.cards.t.TurfWound.class)); cards.add(new SetCardInfo("Twilight's Call", 130, Rarity.RARE, mage.cards.t.TwilightsCall.class)); cards.add(new SetCardInfo("Undermine", 282, Rarity.RARE, mage.cards.u.Undermine.class)); diff --git a/Mage.Sets/src/mage/sets/Judgment.java b/Mage.Sets/src/mage/sets/Judgment.java index 4f46a7b417..9007e49c9e 100644 --- a/Mage.Sets/src/mage/sets/Judgment.java +++ b/Mage.Sets/src/mage/sets/Judgment.java @@ -100,6 +100,7 @@ public class Judgment extends ExpansionSet { cards.add(new SetCardInfo("Flash of Insight", 40, Rarity.UNCOMMON, mage.cards.f.FlashOfInsight.class)); cards.add(new SetCardInfo("Fledgling Dragon", 90, Rarity.RARE, mage.cards.f.FledglingDragon.class)); cards.add(new SetCardInfo("Folk Medicine", 115, Rarity.COMMON, mage.cards.f.FolkMedicine.class)); + cards.add(new SetCardInfo("Forcemage Advocate", 116, Rarity.UNCOMMON, mage.cards.f.ForcemageAdvocate.class)); cards.add(new SetCardInfo("Funeral Pyre", 10, Rarity.COMMON, mage.cards.f.FuneralPyre.class)); cards.add(new SetCardInfo("Genesis", 117, Rarity.RARE, mage.cards.g.Genesis.class)); cards.add(new SetCardInfo("Giant Warthog", 118, Rarity.COMMON, mage.cards.g.GiantWarthog.class)); @@ -118,7 +119,7 @@ public class Judgment extends ExpansionSet { cards.add(new SetCardInfo("Krosan Reclamation", 122, Rarity.UNCOMMON, mage.cards.k.KrosanReclamation.class)); cards.add(new SetCardInfo("Krosan Verge", 141, Rarity.UNCOMMON, mage.cards.k.KrosanVerge.class)); cards.add(new SetCardInfo("Krosan Wayfarer", 123, Rarity.COMMON, mage.cards.k.KrosanWayfarer.class)); - cards.add(new SetCardInfo("Laquatus's Disdain", 44, Rarity.UNCOMMON, mage.cards.l.LaquatussDisdain.class)); + cards.add(new SetCardInfo("Laquatus's Disdain", 44, Rarity.UNCOMMON, mage.cards.l.LaquatussDisdain.class)); cards.add(new SetCardInfo("Lava Dart", 94, Rarity.COMMON, mage.cards.l.LavaDart.class)); cards.add(new SetCardInfo("Lead Astray", 14, Rarity.COMMON, mage.cards.l.LeadAstray.class)); cards.add(new SetCardInfo("Liberated Dwarf", 95, Rarity.COMMON, mage.cards.l.LiberatedDwarf.class)); @@ -147,6 +148,7 @@ public class Judgment extends ExpansionSet { cards.add(new SetCardInfo("Riftstone Portal", 143, Rarity.UNCOMMON, mage.cards.r.RiftstonePortal.class)); cards.add(new SetCardInfo("Scalpelexis", 50, Rarity.RARE, mage.cards.s.Scalpelexis.class)); cards.add(new SetCardInfo("Seedtime", 130, Rarity.RARE, mage.cards.s.Seedtime.class)); + cards.add(new SetCardInfo("Shieldmage Advocate", 22, Rarity.COMMON, mage.cards.s.ShieldmageAdvocate.class)); cards.add(new SetCardInfo("Silver Seraph", 23, Rarity.RARE, mage.cards.s.SilverSeraph.class)); cards.add(new SetCardInfo("Solitary Confinement", 24, Rarity.RARE, mage.cards.s.SolitaryConfinement.class)); cards.add(new SetCardInfo("Soulcatchers' Aerie", 25, Rarity.UNCOMMON, mage.cards.s.SoulcatchersAerie.class)); @@ -164,8 +166,8 @@ public class Judgment extends ExpansionSet { cards.add(new SetCardInfo("Test of Endurance", 29, Rarity.RARE, mage.cards.t.TestOfEndurance.class)); cards.add(new SetCardInfo("Thriss, Nantuko Primus", 134, Rarity.RARE, mage.cards.t.ThrissNantukoPrimus.class)); cards.add(new SetCardInfo("Toxic Stench", 74, Rarity.COMMON, mage.cards.t.ToxicStench.class)); - cards.add(new SetCardInfo("Treacherous Vampire", 75, Rarity.UNCOMMON, mage.cards.t.TreacherousVampire.class)); - cards.add(new SetCardInfo("Treacherous Werewolf", 76, Rarity.COMMON, mage.cards.t.TreacherousWerewolf.class)); + cards.add(new SetCardInfo("Treacherous Vampire", 75, Rarity.UNCOMMON, mage.cards.t.TreacherousVampire.class)); + cards.add(new SetCardInfo("Treacherous Werewolf", 76, Rarity.COMMON, mage.cards.t.TreacherousWerewolf.class)); cards.add(new SetCardInfo("Tunneler Wurm", 135, Rarity.UNCOMMON, mage.cards.t.TunnelerWurm.class)); cards.add(new SetCardInfo("Unquestioned Authority", 31, Rarity.UNCOMMON, mage.cards.u.UnquestionedAuthority.class)); cards.add(new SetCardInfo("Valor", 32, Rarity.UNCOMMON, mage.cards.v.Valor.class)); diff --git a/Mage.Sets/src/mage/sets/Legends.java b/Mage.Sets/src/mage/sets/Legends.java index 62385b2f40..5b74674e2a 100644 --- a/Mage.Sets/src/mage/sets/Legends.java +++ b/Mage.Sets/src/mage/sets/Legends.java @@ -101,13 +101,13 @@ public class Legends extends ExpansionSet { cards.add(new SetCardInfo("D'Avenant Archer", 176, Rarity.COMMON, mage.cards.d.DAvenantArcher.class)); cards.add(new SetCardInfo("Demonic Torment", 9, Rarity.UNCOMMON, mage.cards.d.DemonicTorment.class)); cards.add(new SetCardInfo("Devouring Deep", 50, Rarity.COMMON, mage.cards.d.DevouringDeep.class)); - cards.add(new SetCardInfo("Disharmony", 140, Rarity.RARE, mage.cards.d.Disharmony.class)); + cards.add(new SetCardInfo("Disharmony", 140, Rarity.RARE, mage.cards.d.Disharmony.class)); cards.add(new SetCardInfo("Divine Intervention", 177, Rarity.RARE, mage.cards.d.DivineIntervention.class)); cards.add(new SetCardInfo("Divine Offering", 178, Rarity.COMMON, mage.cards.d.DivineOffering.class)); cards.add(new SetCardInfo("Divine Transformation", 179, Rarity.RARE, mage.cards.d.DivineTransformation.class)); cards.add(new SetCardInfo("Durkwood Boars", 96, Rarity.COMMON, mage.cards.d.DurkwoodBoars.class)); cards.add(new SetCardInfo("Dwarven Song", 141, Rarity.UNCOMMON, mage.cards.d.DwarvenSong.class)); - cards.add(new SetCardInfo("Elder Land Wurm", 180, Rarity.RARE, mage.cards.e.ElderLandWurm.class)); + cards.add(new SetCardInfo("Elder Land Wurm", 180, Rarity.RARE, mage.cards.e.ElderLandWurm.class)); cards.add(new SetCardInfo("Elven Riders", 97, Rarity.RARE, mage.cards.e.ElvenRiders.class)); cards.add(new SetCardInfo("Emerald Dragonfly", 98, Rarity.COMMON, mage.cards.e.EmeraldDragonfly.class)); cards.add(new SetCardInfo("Energy Tap", 54, Rarity.COMMON, mage.cards.e.EnergyTap.class)); @@ -119,20 +119,20 @@ public class Legends extends ExpansionSet { cards.add(new SetCardInfo("Fire Sprites", 100, Rarity.COMMON, mage.cards.f.FireSprites.class)); cards.add(new SetCardInfo("Flash Counter", 56, Rarity.COMMON, mage.cards.f.FlashCounter.class)); cards.add(new SetCardInfo("Flash Flood", 57, Rarity.COMMON, mage.cards.f.FlashFlood.class)); - cards.add(new SetCardInfo("Floral Spuzzem", 101, Rarity.UNCOMMON, mage.cards.f.FloralSpuzzem.class)); + cards.add(new SetCardInfo("Floral Spuzzem", 101, Rarity.UNCOMMON, mage.cards.f.FloralSpuzzem.class)); cards.add(new SetCardInfo("Force Spike", 58, Rarity.COMMON, mage.cards.f.ForceSpike.class)); cards.add(new SetCardInfo("Frost Giant", 146, Rarity.UNCOMMON, mage.cards.f.FrostGiant.class)); cards.add(new SetCardInfo("Gaseous Form", 59, Rarity.COMMON, mage.cards.g.GaseousForm.class)); cards.add(new SetCardInfo("Ghosts of the Damned", 12, Rarity.COMMON, mage.cards.g.GhostsOfTheDamned.class)); cards.add(new SetCardInfo("Giant Strength", 147, Rarity.COMMON, mage.cards.g.GiantStrength.class)); - cards.add(new SetCardInfo("Giant Turtle", 102, Rarity.COMMON, mage.cards.g.GiantTurtle.class)); + cards.add(new SetCardInfo("Giant Turtle", 102, Rarity.COMMON, mage.cards.g.GiantTurtle.class)); cards.add(new SetCardInfo("Gravity Sphere", 149, Rarity.RARE, mage.cards.g.GravitySphere.class)); cards.add(new SetCardInfo("Great Defender", 185, Rarity.UNCOMMON, mage.cards.g.GreatDefender.class)); cards.add(new SetCardInfo("Greater Realm of Preservation", 187, Rarity.UNCOMMON, mage.cards.g.GreaterRealmOfPreservation.class)); cards.add(new SetCardInfo("Greed", 15, Rarity.RARE, mage.cards.g.Greed.class)); cards.add(new SetCardInfo("Green Mana Battery", 223, Rarity.UNCOMMON, mage.cards.g.GreenManaBattery.class)); cards.add(new SetCardInfo("Gwendlyn Di Corci", 268, Rarity.RARE, mage.cards.g.GwendlynDiCorci.class)); - cards.add(new SetCardInfo("Hammerheim", 247, Rarity.UNCOMMON, mage.cards.h.Hammerheim.class)); + cards.add(new SetCardInfo("Hammerheim", 247, Rarity.UNCOMMON, mage.cards.h.Hammerheim.class)); cards.add(new SetCardInfo("Hazezon Tamar", 270, Rarity.RARE, mage.cards.h.HazezonTamar.class)); cards.add(new SetCardInfo("Headless Horseman", 16, Rarity.COMMON, mage.cards.h.HeadlessHorseman.class)); cards.add(new SetCardInfo("Heaven's Gate", 188, Rarity.UNCOMMON, mage.cards.h.HeavensGate.class)); @@ -147,13 +147,14 @@ public class Legends extends ExpansionSet { cards.add(new SetCardInfo("Hyperion Blacksmith", 150, Rarity.UNCOMMON, mage.cards.h.HyperionBlacksmith.class)); cards.add(new SetCardInfo("Immolation", 151, Rarity.COMMON, mage.cards.i.Immolation.class)); cards.add(new SetCardInfo("In the Eye of Chaos", 61, Rarity.RARE, mage.cards.i.InTheEyeOfChaos.class)); - cards.add(new SetCardInfo("Indestructible Aura", 190, Rarity.COMMON, mage.cards.i.IndestructibleAura.class)); + cards.add(new SetCardInfo("Indestructible Aura", 190, Rarity.COMMON, mage.cards.i.IndestructibleAura.class)); cards.add(new SetCardInfo("Invoke Prejudice", 62, Rarity.RARE, mage.cards.i.InvokePrejudice.class)); cards.add(new SetCardInfo("Ivory Guardians", 192, Rarity.UNCOMMON, mage.cards.i.IvoryGuardians.class)); cards.add(new SetCardInfo("Jacques le Vert", 272, Rarity.RARE, mage.cards.j.JacquesLeVert.class)); cards.add(new SetCardInfo("Jasmine Boreal", 273, Rarity.UNCOMMON, mage.cards.j.JasmineBoreal.class)); cards.add(new SetCardInfo("Jedit Ojanen", 274, Rarity.UNCOMMON, mage.cards.j.JeditOjanen.class)); cards.add(new SetCardInfo("Jerrard of the Closed Fist", 275, Rarity.UNCOMMON, mage.cards.j.JerrardOfTheClosedFist.class)); + cards.add(new SetCardInfo("Johan", 276, Rarity.RARE, mage.cards.j.Johan.class)); cards.add(new SetCardInfo("Juxtapose", 63, Rarity.RARE, mage.cards.j.Juxtapose.class)); cards.add(new SetCardInfo("Karakas", 248, Rarity.UNCOMMON, mage.cards.k.Karakas.class)); cards.add(new SetCardInfo("Kasimir the Lone Wolf", 277, Rarity.UNCOMMON, mage.cards.k.KasimirTheLoneWolf.class)); @@ -186,11 +187,13 @@ public class Legends extends ExpansionSet { cards.add(new SetCardInfo("Mountain Yeti", 156, Rarity.UNCOMMON, mage.cards.m.MountainYeti.class)); cards.add(new SetCardInfo("Nether Void", 27, Rarity.RARE, mage.cards.n.NetherVoid.class)); cards.add(new SetCardInfo("Nicol Bolas", 286, Rarity.RARE, mage.cards.n.NicolBolas.class)); + cards.add(new SetCardInfo("Nova Pentacle", 234, Rarity.RARE, mage.cards.n.NovaPentacle.class)); cards.add(new SetCardInfo("Osai Vultures", 198, Rarity.COMMON, mage.cards.o.OsaiVultures.class)); cards.add(new SetCardInfo("Palladia-Mors", 287, Rarity.RARE, mage.cards.p.PalladiaMors.class)); cards.add(new SetCardInfo("Part Water", 66, Rarity.UNCOMMON, mage.cards.p.PartWater.class)); cards.add(new SetCardInfo("Pavel Maliki", 288, Rarity.UNCOMMON, mage.cards.p.PavelMaliki.class)); cards.add(new SetCardInfo("Pendelhaven", 250, Rarity.UNCOMMON, mage.cards.p.Pendelhaven.class)); + cards.add(new SetCardInfo("Petra Sphinx", 199, Rarity.RARE, mage.cards.p.PetraSphinx.class)); cards.add(new SetCardInfo("Pit Scorpion", 28, Rarity.COMMON, mage.cards.p.PitScorpion.class)); cards.add(new SetCardInfo("Pixie Queen", 110, Rarity.RARE, mage.cards.p.PixieQueen.class)); cards.add(new SetCardInfo("Planar Gate", 235, Rarity.RARE, mage.cards.p.PlanarGate.class)); @@ -216,7 +219,7 @@ public class Legends extends ExpansionSet { cards.add(new SetCardInfo("Righteous Avengers", 203, Rarity.UNCOMMON, mage.cards.r.RighteousAvengers.class)); cards.add(new SetCardInfo("Ring of Immortals", 238, Rarity.RARE, mage.cards.r.RingOfImmortals.class)); cards.add(new SetCardInfo("Riven Turnbull", 294, Rarity.UNCOMMON, mage.cards.r.RivenTurnbull.class)); - cards.add(new SetCardInfo("Rohgahh of Kher Keep", 295, Rarity.RARE, mage.cards.r.RohgahhOfKherKeep.class)); + cards.add(new SetCardInfo("Rohgahh of Kher Keep", 295, Rarity.RARE, mage.cards.r.RohgahhOfKherKeep.class)); cards.add(new SetCardInfo("Rubinia Soulsinger", 296, Rarity.RARE, mage.cards.r.RubiniaSoulsinger.class)); cards.add(new SetCardInfo("Rust", 49, Rarity.COMMON, mage.cards.r.Rust.class)); cards.add(new SetCardInfo("Sea Kings' Blessing", 75, Rarity.UNCOMMON, mage.cards.s.SeaKingsBlessing.class)); @@ -227,7 +230,7 @@ public class Legends extends ExpansionSet { cards.add(new SetCardInfo("Sir Shandlar of Eberyn", 297, Rarity.UNCOMMON, mage.cards.s.SirShandlarOfEberyn.class)); cards.add(new SetCardInfo("Sivitri Scarzam", 298, Rarity.UNCOMMON, mage.cards.s.SivitriScarzam.class)); cards.add(new SetCardInfo("Sol'kanar the Swamp King", 299, Rarity.RARE, mage.cards.s.SolkanarTheSwampKing.class)); - cards.add(new SetCardInfo("Spectral Cloak", 78, Rarity.UNCOMMON, mage.cards.s.SpectralCloak.class)); + cards.add(new SetCardInfo("Spectral Cloak", 78, Rarity.UNCOMMON, mage.cards.s.SpectralCloak.class)); cards.add(new SetCardInfo("Spinal Villain", 161, Rarity.RARE, mage.cards.s.SpinalVillain.class)); cards.add(new SetCardInfo("Spirit Link", 206, Rarity.UNCOMMON, mage.cards.s.SpiritLink.class)); cards.add(new SetCardInfo("Spirit Shackle", 31, Rarity.COMMON, mage.cards.s.SpiritShackle.class)); @@ -237,6 +240,7 @@ public class Legends extends ExpansionSet { cards.add(new SetCardInfo("Sylvan Library", 121, Rarity.UNCOMMON, mage.cards.s.SylvanLibrary.class)); cards.add(new SetCardInfo("Sylvan Paradise", 122, Rarity.UNCOMMON, mage.cards.s.SylvanParadise.class)); cards.add(new SetCardInfo("Syphon Soul", 32, Rarity.COMMON, mage.cards.s.SyphonSoul.class)); + cards.add(new SetCardInfo("Teleport", 80, Rarity.RARE, mage.cards.t.Teleport.class)); cards.add(new SetCardInfo("Tetsuo Umezawa", 302, Rarity.RARE, mage.cards.t.TetsuoUmezawa.class)); cards.add(new SetCardInfo("The Abyss", 34, Rarity.RARE, mage.cards.t.TheAbyss.class)); cards.add(new SetCardInfo("The Brute", 164, Rarity.COMMON, mage.cards.t.TheBrute.class)); @@ -244,6 +248,7 @@ public class Legends extends ExpansionSet { cards.add(new SetCardInfo("The Tabernacle at Pendrell Vale", 252, Rarity.RARE, mage.cards.t.TheTabernacleAtPendrellVale.class)); cards.add(new SetCardInfo("The Wretched", 35, Rarity.RARE, mage.cards.t.TheWretched.class)); cards.add(new SetCardInfo("Thunder Spirit", 208, Rarity.RARE, mage.cards.t.ThunderSpirit.class)); + cards.add(new SetCardInfo("Time Elemental", 81, Rarity.RARE, mage.cards.t.TimeElemental.class)); cards.add(new SetCardInfo("Tobias Andrion", 304, Rarity.UNCOMMON, mage.cards.t.TobiasAndrion.class)); cards.add(new SetCardInfo("Torsten Von Ursus", 306, Rarity.UNCOMMON, mage.cards.t.TorstenVonUrsus.class)); cards.add(new SetCardInfo("Tor Wauki", 305, Rarity.UNCOMMON, mage.cards.t.TorWauki.class)); @@ -268,7 +273,7 @@ public class Legends extends ExpansionSet { cards.add(new SetCardInfo("White Mana Battery", 244, Rarity.UNCOMMON, mage.cards.w.WhiteManaBattery.class)); cards.add(new SetCardInfo("Willow Satyr", 126, Rarity.RARE, mage.cards.w.WillowSatyr.class)); cards.add(new SetCardInfo("Winds of Change", 169, Rarity.UNCOMMON, mage.cards.w.WindsOfChange.class)); - cards.add(new SetCardInfo("Winter Blast", 127, Rarity.RARE, mage.cards.w.WinterBlast.class)); + cards.add(new SetCardInfo("Winter Blast", 127, Rarity.RARE, mage.cards.w.WinterBlast.class)); cards.add(new SetCardInfo("Wolverine Pack", 128, Rarity.COMMON, mage.cards.w.WolverinePack.class)); cards.add(new SetCardInfo("Xira Arien", 310, Rarity.RARE, mage.cards.x.XiraArien.class)); cards.add(new SetCardInfo("Zephyr Falcon", 86, Rarity.COMMON, mage.cards.z.ZephyrFalcon.class)); diff --git a/Mage.Sets/src/mage/sets/MastersEdition.java b/Mage.Sets/src/mage/sets/MastersEdition.java index 5adcbf72ba..a6029ef856 100644 --- a/Mage.Sets/src/mage/sets/MastersEdition.java +++ b/Mage.Sets/src/mage/sets/MastersEdition.java @@ -108,7 +108,7 @@ public class MastersEdition extends ExpansionSet { cards.add(new SetCardInfo("Dwarven Catapult", 91, Rarity.UNCOMMON, mage.cards.d.DwarvenCatapult.class)); cards.add(new SetCardInfo("Dwarven Soldier", 92, Rarity.COMMON, DwarvenSoldier.class)); cards.add(new SetCardInfo("Eater of the Dead", 67, Rarity.UNCOMMON, mage.cards.e.EaterOfTheDead.class)); - cards.add(new SetCardInfo("Elder Land Wurm", 11, Rarity.UNCOMMON, mage.cards.e.ElderLandWurm.class)); + cards.add(new SetCardInfo("Elder Land Wurm", 11, Rarity.UNCOMMON, mage.cards.e.ElderLandWurm.class)); cards.add(new SetCardInfo("Erg Raiders", 68, Rarity.COMMON, mage.cards.e.ErgRaiders.class)); cards.add(new SetCardInfo("Eureka", 117, Rarity.RARE, mage.cards.e.Eureka.class)); cards.add(new SetCardInfo("Exile", 12, Rarity.COMMON, mage.cards.e.Exile.class)); @@ -183,9 +183,10 @@ public class MastersEdition extends ExpansionSet { cards.add(new SetCardInfo("Order of the Ebon Hand", 78, Rarity.COMMON, OrderOfTheEbonHand.class)); cards.add(new SetCardInfo("Oubliette", 79, Rarity.COMMON, Oubliette.class)); cards.add(new SetCardInfo("Paralyze", 80, Rarity.COMMON, mage.cards.p.Paralyze.class)); + cards.add(new SetCardInfo("Petra Sphinx", 23, Rarity.RARE, mage.cards.p.PetraSphinx.class)); cards.add(new SetCardInfo("Phantom Monster", 43, Rarity.COMMON, mage.cards.p.PhantomMonster.class)); cards.add(new SetCardInfo("Phelddagrif", 150, Rarity.RARE, mage.cards.p.Phelddagrif.class)); - cards.add(new SetCardInfo("Phyrexian Boon", 81, Rarity.COMMON, mage.cards.p.PhyrexianBoon.class)); + cards.add(new SetCardInfo("Phyrexian Boon", 81, Rarity.COMMON, mage.cards.p.PhyrexianBoon.class)); cards.add(new SetCardInfo("Phyrexian War Beast", 162, Rarity.UNCOMMON, PhyrexianWarBeast.class)); cards.add(new SetCardInfo("Plains", 181, Rarity.LAND, mage.cards.basiclands.Plains.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Plains", 182, Rarity.LAND, mage.cards.basiclands.Plains.class, NON_FULL_USE_VARIOUS)); @@ -229,6 +230,7 @@ public class MastersEdition extends ExpansionSet { cards.add(new SetCardInfo("Thrull Champion", 83, Rarity.RARE, mage.cards.t.ThrullChampion.class)); cards.add(new SetCardInfo("Thrull Retainer", 84, Rarity.COMMON, mage.cards.t.ThrullRetainer.class)); cards.add(new SetCardInfo("Thunder Spirit", 27, Rarity.UNCOMMON, mage.cards.t.ThunderSpirit.class)); + cards.add(new SetCardInfo("Time Elemental", 53, Rarity.RARE, mage.cards.t.TimeElemental.class)); cards.add(new SetCardInfo("Tivadar's Crusade", 28, Rarity.UNCOMMON, mage.cards.t.TivadarsCrusade.class)); cards.add(new SetCardInfo("Tornado", 136, Rarity.RARE, mage.cards.t.Tornado.class)); cards.add(new SetCardInfo("Urza's Bauble", 170, Rarity.UNCOMMON, mage.cards.u.UrzasBauble.class)); @@ -239,7 +241,7 @@ public class MastersEdition extends ExpansionSet { cards.add(new SetCardInfo("Walking Wall", 172, Rarity.UNCOMMON, mage.cards.w.WalkingWall.class)); cards.add(new SetCardInfo("Wanderlust", 137, Rarity.COMMON, mage.cards.w.Wanderlust.class)); cards.add(new SetCardInfo("Winds of Change", 111, Rarity.UNCOMMON, mage.cards.w.WindsOfChange.class)); - cards.add(new SetCardInfo("Winter Blast", 138, Rarity.UNCOMMON, mage.cards.w.WinterBlast.class)); + cards.add(new SetCardInfo("Winter Blast", 138, Rarity.UNCOMMON, mage.cards.w.WinterBlast.class)); cards.add(new SetCardInfo("Winter Orb", 173, Rarity.RARE, mage.cards.w.WinterOrb.class)); cards.add(new SetCardInfo("Wyluli Wolf", 139, Rarity.COMMON, mage.cards.w.WyluliWolf.class)); cards.add(new SetCardInfo("Yavimaya Ants", 140, Rarity.UNCOMMON, mage.cards.y.YavimayaAnts.class)); diff --git a/Mage.Sets/src/mage/sets/MastersEditionII.java b/Mage.Sets/src/mage/sets/MastersEditionII.java index 2b276c52b3..f7fbf2feaa 100644 --- a/Mage.Sets/src/mage/sets/MastersEditionII.java +++ b/Mage.Sets/src/mage/sets/MastersEditionII.java @@ -148,6 +148,7 @@ public class MastersEditionII extends ExpansionSet { cards.add(new SetCardInfo("Helm of Obedience", 210, Rarity.RARE, mage.cards.h.HelmOfObedience.class)); cards.add(new SetCardInfo("Icatian Javelineers", 15, Rarity.COMMON, IcatianJavelineers.class)); cards.add(new SetCardInfo("Icatian Scout", 17, Rarity.COMMON, IcatianScout.class)); + cards.add(new SetCardInfo("Ice Floe", 232, Rarity.UNCOMMON, mage.cards.i.IceFloe.class)); cards.add(new SetCardInfo("Iceberg", 49, Rarity.UNCOMMON, mage.cards.i.Iceberg.class)); cards.add(new SetCardInfo("Icequake", 94, Rarity.COMMON, mage.cards.i.Icequake.class)); cards.add(new SetCardInfo("Icy Prison", 50, Rarity.COMMON, mage.cards.i.IcyPrison.class)); @@ -169,6 +170,7 @@ public class MastersEditionII extends ExpansionSet { cards.add(new SetCardInfo("Kjeldoran Outpost", 233, Rarity.RARE, mage.cards.k.KjeldoranOutpost.class)); cards.add(new SetCardInfo("Knight of Stromgald", 99, Rarity.UNCOMMON, mage.cards.k.KnightOfStromgald.class)); cards.add(new SetCardInfo("Krovikan Fetish", 100, Rarity.COMMON, mage.cards.k.KrovikanFetish.class)); + cards.add(new SetCardInfo("Krovikan Horror", 101, Rarity.RARE, mage.cards.k.KrovikanHorror.class)); cards.add(new SetCardInfo("Krovikan Sorcerer", 51, Rarity.COMMON, mage.cards.k.KrovikanSorcerer.class)); cards.add(new SetCardInfo("Leaping Lizard", 171, Rarity.COMMON, mage.cards.l.LeapingLizard.class)); cards.add(new SetCardInfo("Lim-Dul's High Guard", 103, Rarity.UNCOMMON, LimDulsHighGuard.class)); @@ -178,6 +180,7 @@ public class MastersEditionII extends ExpansionSet { cards.add(new SetCardInfo("Mesmeric Trance", 55, Rarity.RARE, mage.cards.m.MesmericTrance.class)); cards.add(new SetCardInfo("Meteor Shower", 135, Rarity.COMMON, mage.cards.m.MeteorShower.class)); cards.add(new SetCardInfo("Minion of Leshrac", 104, Rarity.RARE, mage.cards.m.MinionOfLeshrac.class)); + cards.add(new SetCardInfo("Misinformation", 105, Rarity.UNCOMMON, mage.cards.m.Misinformation.class)); cards.add(new SetCardInfo("Mudslide", 136, Rarity.RARE, mage.cards.m.Mudslide.class)); cards.add(new SetCardInfo("Narwhal", 57, Rarity.UNCOMMON, mage.cards.n.Narwhal.class)); cards.add(new SetCardInfo("Nature's Wrath", 172, Rarity.RARE, mage.cards.n.NaturesWrath.class)); @@ -215,6 +218,7 @@ public class MastersEditionII extends ExpansionSet { cards.add(new SetCardInfo("Sea Drake", 64, Rarity.RARE, mage.cards.s.SeaDrake.class)); cards.add(new SetCardInfo("Sea Spirit", 65, Rarity.UNCOMMON, mage.cards.s.SeaSpirit.class)); cards.add(new SetCardInfo("Shrink", 175, Rarity.COMMON, mage.cards.s.Shrink.class)); + cards.add(new SetCardInfo("Shyft", 66, Rarity.COMMON, mage.cards.s.Shyft.class)); cards.add(new SetCardInfo("Sibilant Spirit", 67, Rarity.RARE, mage.cards.s.SibilantSpirit.class)); cards.add(new SetCardInfo("Skeleton Ship", 197, Rarity.RARE, mage.cards.s.SkeletonShip.class)); cards.add(new SetCardInfo("Skull Catapult", 219, Rarity.UNCOMMON, mage.cards.s.SkullCatapult.class)); @@ -230,6 +234,7 @@ public class MastersEditionII extends ExpansionSet { cards.add(new SetCardInfo("Songs of the Damned", 110, Rarity.COMMON, mage.cards.s.SongsOfTheDamned.class)); cards.add(new SetCardInfo("Soul Exchange", 111, Rarity.UNCOMMON, mage.cards.s.SoulExchange.class)); cards.add(new SetCardInfo("Soul Kiss", 112, Rarity.UNCOMMON, mage.cards.s.SoulKiss.class)); + cards.add(new SetCardInfo("Spore Cloud", 176, Rarity.UNCOMMON, mage.cards.s.SporeCloud.class)); cards.add(new SetCardInfo("Spore Flower", 177, Rarity.UNCOMMON, mage.cards.s.SporeFlower.class)); cards.add(new SetCardInfo("Stampede", 178, Rarity.UNCOMMON, mage.cards.s.Stampede.class)); cards.add(new SetCardInfo("Stonehands", 151, Rarity.COMMON, mage.cards.s.Stonehands.class)); diff --git a/Mage.Sets/src/mage/sets/MastersEditionIII.java b/Mage.Sets/src/mage/sets/MastersEditionIII.java index a46ec0ceb0..4289a33168 100644 --- a/Mage.Sets/src/mage/sets/MastersEditionIII.java +++ b/Mage.Sets/src/mage/sets/MastersEditionIII.java @@ -100,9 +100,10 @@ public class MastersEditionIII extends ExpansionSet { cards.add(new SetCardInfo("Desperate Charge", 63, Rarity.COMMON, mage.cards.d.DesperateCharge.class)); cards.add(new SetCardInfo("Didgeridoo", 194, Rarity.UNCOMMON, mage.cards.d.Didgeridoo.class)); cards.add(new SetCardInfo("Disenchant", 7, Rarity.COMMON, mage.cards.d.Disenchant.class)); - cards.add(new SetCardInfo("Disharmony", 95, Rarity.UNCOMMON, mage.cards.d.Disharmony.class)); + cards.add(new SetCardInfo("Disharmony", 95, Rarity.UNCOMMON, mage.cards.d.Disharmony.class)); cards.add(new SetCardInfo("Divine Intervention", 8, Rarity.RARE, mage.cards.d.DivineIntervention.class)); cards.add(new SetCardInfo("Dong Zhou, the Tyrant", 96, Rarity.RARE, mage.cards.d.DongZhouTheTyrant.class)); + cards.add(new SetCardInfo("Eightfold Maze", 9, Rarity.UNCOMMON, mage.cards.e.EightfoldMaze.class)); cards.add(new SetCardInfo("Elves of Deep Shadow", 116, Rarity.COMMON, mage.cards.e.ElvesOfDeepShadow.class)); cards.add(new SetCardInfo("Evil Presence", 64, Rarity.COMMON, mage.cards.e.EvilPresence.class)); cards.add(new SetCardInfo("Exorcist", 10, Rarity.UNCOMMON, mage.cards.e.Exorcist.class)); @@ -129,7 +130,7 @@ public class MastersEditionIII extends ExpansionSet { cards.add(new SetCardInfo("Guan Yu's 1,000-Li March", 13, Rarity.RARE, mage.cards.g.GuanYus1000LiMarch.class)); cards.add(new SetCardInfo("Guan Yu, Sainted Warrior", 12, Rarity.UNCOMMON, mage.cards.g.GuanYuSaintedWarrior.class)); cards.add(new SetCardInfo("Gwendlyn Di Corci", 149, Rarity.RARE, mage.cards.g.GwendlynDiCorci.class)); - cards.add(new SetCardInfo("Hammerheim", 207, Rarity.UNCOMMON, mage.cards.h.Hammerheim.class)); + cards.add(new SetCardInfo("Hammerheim", 207, Rarity.UNCOMMON, mage.cards.h.Hammerheim.class)); cards.add(new SetCardInfo("Hazezon Tamar", 151, Rarity.RARE, mage.cards.h.HazezonTamar.class)); cards.add(new SetCardInfo("Heal", 14, Rarity.COMMON, mage.cards.h.Heal.class)); cards.add(new SetCardInfo("Hellfire", 70, Rarity.RARE, mage.cards.h.Hellfire.class)); @@ -155,7 +156,7 @@ public class MastersEditionIII extends ExpansionSet { cards.add(new SetCardInfo("Kobolds of Kher Keep", 107, Rarity.COMMON, mage.cards.k.KoboldsOfKherKeep.class)); cards.add(new SetCardInfo("Kobold Taskmaster", 106, Rarity.COMMON, mage.cards.k.KoboldTaskmaster.class)); cards.add(new SetCardInfo("Kongming, 'Sleeping Dragon'", 16, Rarity.RARE, mage.cards.k.KongmingSleepingDragon.class)); - cards.add(new SetCardInfo("Labyrinth Minotaur", 39, Rarity.COMMON, mage.cards.l.LabyrinthMinotaur.class)); + cards.add(new SetCardInfo("Labyrinth Minotaur", 39, Rarity.COMMON, mage.cards.l.LabyrinthMinotaur.class)); cards.add(new SetCardInfo("Lady Caleria", 157, Rarity.UNCOMMON, mage.cards.l.LadyCaleria.class)); cards.add(new SetCardInfo("Lady Evangela", 158, Rarity.UNCOMMON, mage.cards.l.LadyEvangela.class)); cards.add(new SetCardInfo("Lady Orca", 159, Rarity.COMMON, mage.cards.l.LadyOrca.class)); @@ -182,6 +183,7 @@ public class MastersEditionIII extends ExpansionSet { cards.add(new SetCardInfo("Mountain", 227, Rarity.LAND, mage.cards.basiclands.Mountain.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Nether Void", 73, Rarity.RARE, mage.cards.n.NetherVoid.class)); cards.add(new SetCardInfo("Nicol Bolas", 163, Rarity.RARE, mage.cards.n.NicolBolas.class)); + cards.add(new SetCardInfo("Nova Pentacle", 200, Rarity.RARE, mage.cards.n.NovaPentacle.class)); cards.add(new SetCardInfo("Old Man of the Sea", 45, Rarity.RARE, mage.cards.o.OldManOfTheSea.class)); cards.add(new SetCardInfo("Palladia-Mors", 164, Rarity.RARE, mage.cards.p.PalladiaMors.class)); cards.add(new SetCardInfo("Pavel Maliki", 165, Rarity.UNCOMMON, mage.cards.p.PavelMaliki.class)); @@ -203,7 +205,7 @@ public class MastersEditionIII extends ExpansionSet { cards.add(new SetCardInfo("Reveka, Wizard Savant", 49, Rarity.UNCOMMON, mage.cards.r.RevekaWizardSavant.class)); cards.add(new SetCardInfo("Riding the Dilu Horse", 131, Rarity.UNCOMMON, mage.cards.r.RidingTheDiluHorse.class)); cards.add(new SetCardInfo("Riven Turnbull", 171, Rarity.UNCOMMON, mage.cards.r.RivenTurnbull.class)); - cards.add(new SetCardInfo("Rohgahh of Kher Keep", 172, Rarity.RARE, mage.cards.r.RohgahhOfKherKeep.class)); + cards.add(new SetCardInfo("Rohgahh of Kher Keep", 172, Rarity.RARE, mage.cards.r.RohgahhOfKherKeep.class)); cards.add(new SetCardInfo("Rolling Earthquake", 110, Rarity.RARE, mage.cards.r.RollingEarthquake.class)); cards.add(new SetCardInfo("Rubinia Soulsinger", 173, Rarity.RARE, mage.cards.r.RubiniaSoulsinger.class)); cards.add(new SetCardInfo("Scrubland", 210, Rarity.RARE, mage.cards.s.Scrubland.class)); diff --git a/Mage.Sets/src/mage/sets/MastersEditionIV.java b/Mage.Sets/src/mage/sets/MastersEditionIV.java index 25979eabb1..56844d6e8e 100644 --- a/Mage.Sets/src/mage/sets/MastersEditionIV.java +++ b/Mage.Sets/src/mage/sets/MastersEditionIV.java @@ -186,6 +186,7 @@ public class MastersEditionIV extends ExpansionSet { cards.add(new SetCardInfo("Mahamoti Djinn", 52, Rarity.RARE, mage.cards.m.MahamotiDjinn.class)); cards.add(new SetCardInfo("Mana Matrix", 213, Rarity.RARE, mage.cards.m.ManaMatrix.class)); cards.add(new SetCardInfo("Mana Vault", 214, Rarity.RARE, mage.cards.m.ManaVault.class)); + cards.add(new SetCardInfo("Martyr's Cry", 19, Rarity.RARE, mage.cards.m.MartyrsCry.class)); cards.add(new SetCardInfo("Martyrs of Korlis", 20, Rarity.UNCOMMON, mage.cards.m.MartyrsOfKorlis.class)); cards.add(new SetCardInfo("Maze of Ith", 246, Rarity.RARE, mage.cards.m.MazeOfIth.class)); cards.add(new SetCardInfo("Mightstone", 215, Rarity.COMMON, mage.cards.m.Mightstone.class)); diff --git a/Mage.Sets/src/mage/sets/MercadianMasques.java b/Mage.Sets/src/mage/sets/MercadianMasques.java index d8ceae0219..d20afbfc27 100644 --- a/Mage.Sets/src/mage/sets/MercadianMasques.java +++ b/Mage.Sets/src/mage/sets/MercadianMasques.java @@ -158,6 +158,7 @@ public class MercadianMasques extends ExpansionSet { cards.add(new SetCardInfo("Fresh Volunteers", 20, Rarity.COMMON, mage.cards.f.FreshVolunteers.class)); cards.add(new SetCardInfo("Furious Assault", 191, Rarity.COMMON, mage.cards.f.FuriousAssault.class)); cards.add(new SetCardInfo("Game Preserve", 248, Rarity.RARE, mage.cards.g.GamePreserve.class)); + cards.add(new SetCardInfo("General's Regalia", 295, Rarity.RARE, mage.cards.g.GeneralsRegalia.class)); cards.add(new SetCardInfo("Gerrard's Irregulars", 192, Rarity.COMMON, mage.cards.g.GerrardsIrregulars.class)); cards.add(new SetCardInfo("Ghoul's Feast", 137, Rarity.UNCOMMON, mage.cards.g.GhoulsFeast.class)); cards.add(new SetCardInfo("Giant Caterpillar", 249, Rarity.COMMON, mage.cards.g.GiantCaterpillar.class)); @@ -274,6 +275,7 @@ public class MercadianMasques extends ExpansionSet { cards.add(new SetCardInfo("Rushwood Legate", 266, Rarity.UNCOMMON, mage.cards.r.RushwoodLegate.class)); cards.add(new SetCardInfo("Saber Ants", 267, Rarity.UNCOMMON, mage.cards.s.SaberAnts.class)); cards.add(new SetCardInfo("Sacred Prey", 268, Rarity.COMMON, mage.cards.s.SacredPrey.class)); + cards.add(new SetCardInfo("Sailmonger", 95, Rarity.UNCOMMON, mage.cards.s.Sailmonger.class)); cards.add(new SetCardInfo("Sand Squid", 96, Rarity.RARE, mage.cards.s.SandSquid.class)); cards.add(new SetCardInfo("Sandstone Needle", 326, Rarity.COMMON, mage.cards.s.SandstoneNeedle.class)); cards.add(new SetCardInfo("Saprazzan Cove", 327, Rarity.UNCOMMON, mage.cards.s.SaprazzanCove.class)); @@ -329,7 +331,7 @@ public class MercadianMasques extends ExpansionSet { cards.add(new SetCardInfo("Tidal Bore", 109, Rarity.COMMON, mage.cards.t.TidalBore.class)); cards.add(new SetCardInfo("Tidal Kraken", 110, Rarity.RARE, mage.cards.t.TidalKraken.class)); cards.add(new SetCardInfo("Tiger Claws", 279, Rarity.COMMON, mage.cards.t.TigerClaws.class)); - cards.add(new SetCardInfo("Timid Drake", 111, Rarity.UNCOMMON, mage.cards.t.TimidDrake.class)); + cards.add(new SetCardInfo("Timid Drake", 111, Rarity.UNCOMMON, mage.cards.t.TimidDrake.class)); cards.add(new SetCardInfo("Tonic Peddler", 54, Rarity.UNCOMMON, mage.cards.t.TonicPeddler.class)); cards.add(new SetCardInfo("Tooth of Ramos", 313, Rarity.RARE, mage.cards.t.ToothOfRamos.class)); cards.add(new SetCardInfo("Tower of the Magistrate", 330, Rarity.RARE, mage.cards.t.TowerOfTheMagistrate.class)); @@ -352,6 +354,7 @@ public class MercadianMasques extends ExpansionSet { cards.add(new SetCardInfo("Waterfront Bouncer", 114, Rarity.COMMON, mage.cards.w.WaterfrontBouncer.class)); cards.add(new SetCardInfo("Wave of Reckoning", 56, Rarity.RARE, mage.cards.w.WaveOfReckoning.class)); cards.add(new SetCardInfo("Wild Jhovall", 227, Rarity.COMMON, mage.cards.w.WildJhovall.class)); + cards.add(new SetCardInfo("Wishmonger", 57, Rarity.UNCOMMON, mage.cards.w.Wishmonger.class)); cards.add(new SetCardInfo("Word of Blasting", 228, Rarity.UNCOMMON, mage.cards.w.WordOfBlasting.class)); cards.add(new SetCardInfo("Worry Beads", 315, Rarity.RARE, mage.cards.w.WorryBeads.class)); } diff --git a/Mage.Sets/src/mage/sets/Mirage.java b/Mage.Sets/src/mage/sets/Mirage.java index 2100e30fab..e16c401dca 100644 --- a/Mage.Sets/src/mage/sets/Mirage.java +++ b/Mage.Sets/src/mage/sets/Mirage.java @@ -105,6 +105,7 @@ public class Mirage extends ExpansionSet { cards.add(new SetCardInfo("Daring Apprentice", 60, Rarity.RARE, mage.cards.d.DaringApprentice.class)); cards.add(new SetCardInfo("Dark Banishing", 13, Rarity.COMMON, mage.cards.d.DarkBanishing.class)); cards.add(new SetCardInfo("Dark Ritual", 14, Rarity.COMMON, mage.cards.d.DarkRitual.class)); + cards.add(new SetCardInfo("Dazzling Beauty", 212, Rarity.COMMON, mage.cards.d.DazzlingBeauty.class)); cards.add(new SetCardInfo("Dirtwater Wraith", 15, Rarity.COMMON, mage.cards.d.DirtwaterWraith.class)); cards.add(new SetCardInfo("Disempower", 213, Rarity.COMMON, mage.cards.d.Disempower.class)); cards.add(new SetCardInfo("Disenchant", 214, Rarity.COMMON, mage.cards.d.Disenchant.class)); diff --git a/Mage.Sets/src/mage/sets/Mirrodin.java b/Mage.Sets/src/mage/sets/Mirrodin.java index 7222f68d8a..51363efc4e 100644 --- a/Mage.Sets/src/mage/sets/Mirrodin.java +++ b/Mage.Sets/src/mage/sets/Mirrodin.java @@ -68,6 +68,7 @@ public class Mirrodin extends ExpansionSet { cards.add(new SetCardInfo("Crystal Shard", 159, Rarity.UNCOMMON, mage.cards.c.CrystalShard.class)); cards.add(new SetCardInfo("Culling Scales", 160, Rarity.RARE, mage.cards.c.CullingScales.class)); cards.add(new SetCardInfo("Damping Matrix", 161, Rarity.RARE, mage.cards.d.DampingMatrix.class)); + cards.add(new SetCardInfo("Dead-Iron Sledge", 162, Rarity.UNCOMMON, mage.cards.d.DeadIronSledge.class)); cards.add(new SetCardInfo("Deconstruct", 118, Rarity.COMMON, mage.cards.d.Deconstruct.class)); cards.add(new SetCardInfo("Detonate", 88, Rarity.UNCOMMON, mage.cards.d.Detonate.class)); cards.add(new SetCardInfo("Disarm", 32, Rarity.COMMON, mage.cards.d.Disarm.class)); @@ -142,6 +143,7 @@ public class Mirrodin extends ExpansionSet { cards.add(new SetCardInfo("Leonin Skyhunter", 11, Rarity.UNCOMMON, mage.cards.l.LeoninSkyhunter.class)); cards.add(new SetCardInfo("Leonin Sun Standard", 194, Rarity.RARE, mage.cards.l.LeoninSunStandard.class)); cards.add(new SetCardInfo("Leveler", 195, Rarity.RARE, mage.cards.l.Leveler.class)); + cards.add(new SetCardInfo("Liar's Pendulum", 196, Rarity.RARE, mage.cards.l.LiarsPendulum.class)); cards.add(new SetCardInfo("Lifespark Spellbomb", 197, Rarity.COMMON, mage.cards.l.LifesparkSpellbomb.class)); cards.add(new SetCardInfo("Lightning Coils", 198, Rarity.RARE, mage.cards.l.LightningCoils.class)); cards.add(new SetCardInfo("Lightning Greaves", 199, Rarity.UNCOMMON, mage.cards.l.LightningGreaves.class)); @@ -149,8 +151,10 @@ public class Mirrodin extends ExpansionSet { cards.add(new SetCardInfo("Lodestone Myr", 200, Rarity.RARE, mage.cards.l.LodestoneMyr.class)); cards.add(new SetCardInfo("Looming Hoverguard", 38, Rarity.UNCOMMON, mage.cards.l.LoomingHoverguard.class)); cards.add(new SetCardInfo("Loxodon Mender", 12, Rarity.COMMON, mage.cards.l.LoxodonMender.class)); + cards.add(new SetCardInfo("Loxodon Peacekeeper", 13, Rarity.RARE, mage.cards.l.LoxodonPeacekeeper.class)); cards.add(new SetCardInfo("Loxodon Punisher", 14, Rarity.RARE, mage.cards.l.LoxodonPunisher.class)); cards.add(new SetCardInfo("Loxodon Warhammer", 201, Rarity.UNCOMMON, mage.cards.l.LoxodonWarhammer.class)); + cards.add(new SetCardInfo("Lumengrid Augur", 39, Rarity.RARE, mage.cards.l.LumengridAugur.class)); cards.add(new SetCardInfo("Lumengrid Sentinel", 40, Rarity.UNCOMMON, mage.cards.l.LumengridSentinel.class)); cards.add(new SetCardInfo("Lumengrid Warden", 41, Rarity.COMMON, mage.cards.l.LumengridWarden.class)); cards.add(new SetCardInfo("Luminous Angel", 15, Rarity.RARE, mage.cards.l.LuminousAngel.class)); @@ -174,6 +178,7 @@ public class Mirrodin extends ExpansionSet { cards.add(new SetCardInfo("Myr Enforcer", 211, Rarity.COMMON, mage.cards.m.MyrEnforcer.class)); cards.add(new SetCardInfo("Myr Incubator", 212, Rarity.RARE, mage.cards.m.MyrIncubator.class)); cards.add(new SetCardInfo("Myr Mindservant", 213, Rarity.UNCOMMON, mage.cards.m.MyrMindservant.class)); + cards.add(new SetCardInfo("Myr Prototype", 214, Rarity.UNCOMMON, mage.cards.m.MyrPrototype.class)); cards.add(new SetCardInfo("Myr Retriever", 215, Rarity.UNCOMMON, mage.cards.m.MyrRetriever.class)); cards.add(new SetCardInfo("Necrogen Mists", 69, Rarity.RARE, mage.cards.n.NecrogenMists.class)); cards.add(new SetCardInfo("Necrogen Spellbomb", 216, Rarity.COMMON, mage.cards.n.NecrogenSpellbomb.class)); diff --git a/Mage.Sets/src/mage/sets/Nemesis.java b/Mage.Sets/src/mage/sets/Nemesis.java index b8225ffd6a..f05a4909d3 100644 --- a/Mage.Sets/src/mage/sets/Nemesis.java +++ b/Mage.Sets/src/mage/sets/Nemesis.java @@ -85,6 +85,7 @@ public class Nemesis extends ExpansionSet { cards.add(new SetCardInfo("Dominate", 31, Rarity.UNCOMMON, mage.cards.d.Dominate.class)); cards.add(new SetCardInfo("Downhill Charge", 79, Rarity.COMMON, mage.cards.d.DownhillCharge.class)); cards.add(new SetCardInfo("Ensnare", 32, Rarity.UNCOMMON, mage.cards.e.Ensnare.class)); + cards.add(new SetCardInfo("Eye of Yawgmoth", 129, Rarity.RARE, mage.cards.e.EyeOfYawgmoth.class)); cards.add(new SetCardInfo("Fanatical Devotion", 8, Rarity.COMMON, mage.cards.f.FanaticalDevotion.class)); cards.add(new SetCardInfo("Flame Rift", 80, Rarity.COMMON, mage.cards.f.FlameRift.class)); cards.add(new SetCardInfo("Flowstone Armor", 131, Rarity.UNCOMMON, mage.cards.f.FlowstoneArmor.class)); @@ -99,6 +100,11 @@ public class Nemesis extends ExpansionSet { cards.add(new SetCardInfo("Jolting Merfolk", 34, Rarity.UNCOMMON, mage.cards.j.JoltingMerfolk.class)); cards.add(new SetCardInfo("Kill Switch", 133, Rarity.RARE, mage.cards.k.KillSwitch.class)); cards.add(new SetCardInfo("Kor Haven", 141, Rarity.RARE, mage.cards.k.KorHaven.class)); + cards.add(new SetCardInfo("Laccolith Grunt", 87, Rarity.COMMON, mage.cards.l.LaccolithGrunt.class)); + cards.add(new SetCardInfo("Laccolith Rig", 88, Rarity.COMMON, mage.cards.l.LaccolithRig.class)); + cards.add(new SetCardInfo("Laccolith Titan", 89, Rarity.RARE, mage.cards.l.LaccolithTitan.class)); + cards.add(new SetCardInfo("Laccolith Warrior", 90, Rarity.UNCOMMON, mage.cards.l.LaccolithWarrior.class)); + cards.add(new SetCardInfo("Laccolith Whelp", 91, Rarity.COMMON, mage.cards.l.LaccolithWhelp.class)); cards.add(new SetCardInfo("Lashknife", 9, Rarity.COMMON, mage.cards.l.Lashknife.class)); cards.add(new SetCardInfo("Lawbringer", 10, Rarity.COMMON, mage.cards.l.Lawbringer.class)); cards.add(new SetCardInfo("Lightbringer", 11, Rarity.COMMON, mage.cards.l.Lightbringer.class)); diff --git a/Mage.Sets/src/mage/sets/Odyssey.java b/Mage.Sets/src/mage/sets/Odyssey.java index 046a90917c..7900768d2b 100644 --- a/Mage.Sets/src/mage/sets/Odyssey.java +++ b/Mage.Sets/src/mage/sets/Odyssey.java @@ -184,8 +184,10 @@ public class Odyssey extends ExpansionSet { cards.add(new SetCardInfo("Halberdier", 196, Rarity.COMMON, mage.cards.h.Halberdier.class)); cards.add(new SetCardInfo("Hallowed Healer", 25, Rarity.COMMON, mage.cards.h.HallowedHealer.class)); cards.add(new SetCardInfo("Haunting Echoes", 142, Rarity.RARE, mage.cards.h.HauntingEchoes.class)); + cards.add(new SetCardInfo("Holistic Wisdom", 243, Rarity.RARE, mage.cards.h.HolisticWisdom.class)); cards.add(new SetCardInfo("Howling Gale", 244, Rarity.UNCOMMON, mage.cards.h.HowlingGale.class)); cards.add(new SetCardInfo("Immobilizing Ink", 87, Rarity.COMMON, mage.cards.i.ImmobilizingInk.class)); + cards.add(new SetCardInfo("Impulsive Maneuvers", 197, Rarity.RARE, mage.cards.i.ImpulsiveManeuvers.class)); cards.add(new SetCardInfo("Infected Vermin", 144, Rarity.UNCOMMON, mage.cards.i.InfectedVermin.class)); cards.add(new SetCardInfo("Innocent Blood", 145, Rarity.COMMON, mage.cards.i.InnocentBlood.class)); cards.add(new SetCardInfo("Iridescent Angel", 288, Rarity.RARE, mage.cards.i.IridescentAngel.class)); @@ -194,7 +196,7 @@ public class Odyssey extends ExpansionSet { cards.add(new SetCardInfo("Island", 337, Rarity.LAND, mage.cards.basiclands.Island.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Island", 338, Rarity.LAND, mage.cards.basiclands.Island.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Ivy Elemental", 245, Rarity.RARE, mage.cards.i.IvyElemental.class)); - cards.add(new SetCardInfo("Junk Golem", 300, Rarity.RARE, mage.cards.j.JunkGolem.class)); + cards.add(new SetCardInfo("Junk Golem", 300, Rarity.RARE, mage.cards.j.JunkGolem.class)); cards.add(new SetCardInfo("Kamahl, Pit Fighter", 198, Rarity.RARE, mage.cards.k.KamahlPitFighter.class)); cards.add(new SetCardInfo("Kamahl's Desire", 199, Rarity.COMMON, mage.cards.k.KamahlsDesire.class)); cards.add(new SetCardInfo("Karmic Justice", 26, Rarity.RARE, mage.cards.k.KarmicJustice.class)); @@ -251,7 +253,7 @@ public class Odyssey extends ExpansionSet { cards.add(new SetCardInfo("Nomad Stadium", 322, Rarity.UNCOMMON, mage.cards.n.NomadStadium.class)); cards.add(new SetCardInfo("Nut Collector", 259, Rarity.RARE, mage.cards.n.NutCollector.class)); cards.add(new SetCardInfo("Obstinate Familiar", 210, Rarity.RARE, mage.cards.o.ObstinateFamiliar.class)); - cards.add(new SetCardInfo("Otarian Juggernaut", 305, Rarity.RARE, mage.cards.o.OtarianJuggernaut.class)); + cards.add(new SetCardInfo("Otarian Juggernaut", 305, Rarity.RARE, mage.cards.o.OtarianJuggernaut.class)); cards.add(new SetCardInfo("Overeager Apprentice", 154, Rarity.COMMON, mage.cards.o.OvereagerApprentice.class)); cards.add(new SetCardInfo("Overrun", 260, Rarity.UNCOMMON, mage.cards.o.Overrun.class)); cards.add(new SetCardInfo("Pardic Firecat", 211, Rarity.COMMON, mage.cards.p.PardicFirecat.class)); @@ -261,6 +263,7 @@ public class Odyssey extends ExpansionSet { cards.add(new SetCardInfo("Patriarch's Desire", 156, Rarity.COMMON, mage.cards.p.PatriarchsDesire.class)); cards.add(new SetCardInfo("Patrol Hound", 38, Rarity.COMMON, mage.cards.p.PatrolHound.class)); cards.add(new SetCardInfo("Patron Wizard", 89, Rarity.RARE, mage.cards.p.PatronWizard.class)); + cards.add(new SetCardInfo("Pedantic Learning", 90, Rarity.RARE, mage.cards.p.PedanticLearning.class)); cards.add(new SetCardInfo("Peek", 91, Rarity.COMMON, mage.cards.p.Peek.class)); cards.add(new SetCardInfo("Persuasion", 92, Rarity.RARE, mage.cards.p.Persuasion.class)); cards.add(new SetCardInfo("Petrified Field", 323, Rarity.RARE, mage.cards.p.PetrifiedField.class)); @@ -273,6 +276,7 @@ public class Odyssey extends ExpansionSet { cards.add(new SetCardInfo("Plains", 332, Rarity.LAND, mage.cards.basiclands.Plains.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Plains", 333, Rarity.LAND, mage.cards.basiclands.Plains.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Plains", 334, Rarity.LAND, mage.cards.basiclands.Plains.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Phantom Whelp", 93, Rarity.COMMON, mage.cards.p.PhantomWhelp.class)); cards.add(new SetCardInfo("Predict", 94, Rarity.UNCOMMON, mage.cards.p.Predict.class)); cards.add(new SetCardInfo("Price of Glory", 214, Rarity.UNCOMMON, mage.cards.p.PriceOfGlory.class)); cards.add(new SetCardInfo("Primal Frenzy", 262, Rarity.COMMON, mage.cards.p.PrimalFrenzy.class)); @@ -321,17 +325,18 @@ public class Odyssey extends ExpansionSet { cards.add(new SetCardInfo("Soulcatcher", 47, Rarity.UNCOMMON, mage.cards.s.Soulcatcher.class)); cards.add(new SetCardInfo("Spark Mage", 222, Rarity.UNCOMMON, mage.cards.s.SparkMage.class)); cards.add(new SetCardInfo("Spellbane Centaur", 271, Rarity.RARE, mage.cards.s.SpellbaneCentaur.class)); - cards.add(new SetCardInfo("Sphere of Duty", 48, Rarity.UNCOMMON, mage.cards.s.SphereOfDuty.class)); - cards.add(new SetCardInfo("Sphere of Grace", 49, Rarity.UNCOMMON, mage.cards.s.SphereOfGrace.class)); - cards.add(new SetCardInfo("Sphere of Law", 50, Rarity.UNCOMMON, mage.cards.s.SphereOfLaw.class)); - cards.add(new SetCardInfo("Sphere of Reason", 51, Rarity.UNCOMMON, mage.cards.s.SphereOfReason.class)); - cards.add(new SetCardInfo("Sphere of Truth", 52, Rarity.UNCOMMON, mage.cards.s.SphereOfTruth.class)); + cards.add(new SetCardInfo("Sphere of Duty", 48, Rarity.UNCOMMON, mage.cards.s.SphereOfDuty.class)); + cards.add(new SetCardInfo("Sphere of Grace", 49, Rarity.UNCOMMON, mage.cards.s.SphereOfGrace.class)); + cards.add(new SetCardInfo("Sphere of Law", 50, Rarity.UNCOMMON, mage.cards.s.SphereOfLaw.class)); + cards.add(new SetCardInfo("Sphere of Reason", 51, Rarity.UNCOMMON, mage.cards.s.SphereOfReason.class)); + cards.add(new SetCardInfo("Sphere of Truth", 52, Rarity.UNCOMMON, mage.cards.s.SphereOfTruth.class)); cards.add(new SetCardInfo("Spiritualize", 53, Rarity.UNCOMMON, mage.cards.s.Spiritualize.class)); cards.add(new SetCardInfo("Springing Tiger", 272, Rarity.COMMON, mage.cards.s.SpringingTiger.class)); cards.add(new SetCardInfo("Squirrel Mob", 273, Rarity.RARE, mage.cards.s.SquirrelMob.class)); cards.add(new SetCardInfo("Squirrel Nest", 274, Rarity.UNCOMMON, mage.cards.s.SquirrelNest.class)); cards.add(new SetCardInfo("Stalking Bloodsucker", 163, Rarity.RARE, mage.cards.s.StalkingBloodsucker.class)); cards.add(new SetCardInfo("Standstill", 102, Rarity.UNCOMMON, mage.cards.s.Standstill.class)); + cards.add(new SetCardInfo("Steam Vines", 223, Rarity.UNCOMMON, mage.cards.s.SteamVines.class)); cards.add(new SetCardInfo("Steamclaw", 310, Rarity.UNCOMMON, mage.cards.s.Steamclaw.class)); cards.add(new SetCardInfo("Still Life", 275, Rarity.UNCOMMON, mage.cards.s.StillLife.class)); cards.add(new SetCardInfo("Stone-Tongue Basilisk", 276, Rarity.RARE, mage.cards.s.StoneTongueBasilisk.class)); @@ -361,7 +366,7 @@ public class Odyssey extends ExpansionSet { cards.add(new SetCardInfo("Traumatize", 110, Rarity.RARE, mage.cards.t.Traumatize.class)); cards.add(new SetCardInfo("Treetop Sentinel", 111, Rarity.UNCOMMON, mage.cards.t.TreetopSentinel.class)); cards.add(new SetCardInfo("Tremble", 225, Rarity.COMMON, mage.cards.t.Tremble.class)); - cards.add(new SetCardInfo("Twigwalker", 279, Rarity.UNCOMMON, mage.cards.t.Twigwalker.class)); + cards.add(new SetCardInfo("Twigwalker", 279, Rarity.UNCOMMON, mage.cards.t.Twigwalker.class)); cards.add(new SetCardInfo("Unifying Theory", 112, Rarity.RARE, mage.cards.u.UnifyingTheory.class)); cards.add(new SetCardInfo("Upheaval", 113, Rarity.RARE, mage.cards.u.Upheaval.class)); cards.add(new SetCardInfo("Vampiric Dragon", 296, Rarity.RARE, mage.cards.v.VampiricDragon.class)); diff --git a/Mage.Sets/src/mage/sets/Onslaught.java b/Mage.Sets/src/mage/sets/Onslaught.java index ae21f921fc..8e76f69828 100644 --- a/Mage.Sets/src/mage/sets/Onslaught.java +++ b/Mage.Sets/src/mage/sets/Onslaught.java @@ -145,6 +145,7 @@ public class Onslaught extends ExpansionSet { cards.add(new SetCardInfo("Glory Seeker", 31, Rarity.COMMON, mage.cards.g.GlorySeeker.class)); cards.add(new SetCardInfo("Gluttonous Zombie", 151, Rarity.UNCOMMON, mage.cards.g.GluttonousZombie.class)); cards.add(new SetCardInfo("Goblin Burrows", 318, Rarity.UNCOMMON, mage.cards.g.GoblinBurrows.class)); + cards.add(new SetCardInfo("Goblin Machinist", 204, Rarity.UNCOMMON, mage.cards.g.GoblinMachinist.class)); cards.add(new SetCardInfo("Goblin Piledriver", 205, Rarity.RARE, mage.cards.g.GoblinPiledriver.class)); cards.add(new SetCardInfo("Goblin Pyromancer", 206, Rarity.RARE, mage.cards.g.GoblinPyromancer.class)); cards.add(new SetCardInfo("Goblin Sharpshooter", 207, Rarity.RARE, mage.cards.g.GoblinSharpshooter.class)); @@ -197,13 +198,13 @@ public class Onslaught extends ExpansionSet { cards.add(new SetCardInfo("Mana Echoes", 218, Rarity.RARE, mage.cards.m.ManaEchoes.class)); cards.add(new SetCardInfo("Menacing Ogre", 219, Rarity.RARE, mage.cards.m.MenacingOgre.class)); cards.add(new SetCardInfo("Misery Charm", 158, Rarity.COMMON, mage.cards.m.MiseryCharm.class)); - cards.add(new SetCardInfo("Mistform Dreamer", 93, Rarity.COMMON, mage.cards.m.MistformDreamer.class)); - cards.add(new SetCardInfo("Mistform Mask", 94, Rarity.COMMON, mage.cards.m.MistformMask.class)); + cards.add(new SetCardInfo("Mistform Dreamer", 93, Rarity.COMMON, mage.cards.m.MistformDreamer.class)); + cards.add(new SetCardInfo("Mistform Mask", 94, Rarity.COMMON, mage.cards.m.MistformMask.class)); cards.add(new SetCardInfo("Mistform Mutant", 95, Rarity.UNCOMMON, mage.cards.m.MistformMutant.class)); - cards.add(new SetCardInfo("Mistform Shrieker", 96, Rarity.UNCOMMON, mage.cards.m.MistformShrieker.class)); - cards.add(new SetCardInfo("Mistform Skyreaver", 97, Rarity.RARE, mage.cards.m.MistformSkyreaver.class)); - cards.add(new SetCardInfo("Mistform Stalker", 98, Rarity.UNCOMMON, mage.cards.m.MistformStalker.class)); - cards.add(new SetCardInfo("Mistform Wall", 99, Rarity.COMMON, mage.cards.m.MistformWall.class)); + cards.add(new SetCardInfo("Mistform Shrieker", 96, Rarity.UNCOMMON, mage.cards.m.MistformShrieker.class)); + cards.add(new SetCardInfo("Mistform Skyreaver", 97, Rarity.RARE, mage.cards.m.MistformSkyreaver.class)); + cards.add(new SetCardInfo("Mistform Stalker", 98, Rarity.UNCOMMON, mage.cards.m.MistformStalker.class)); + cards.add(new SetCardInfo("Mistform Wall", 99, Rarity.COMMON, mage.cards.m.MistformWall.class)); cards.add(new SetCardInfo("Mobilization", 44, Rarity.RARE, mage.cards.m.Mobilization.class)); cards.add(new SetCardInfo("Mountain", 343, Rarity.LAND, mage.cards.basiclands.Mountain.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Mountain", 344, Rarity.LAND, mage.cards.basiclands.Mountain.class, NON_FULL_USE_VARIOUS)); @@ -246,12 +247,13 @@ public class Onslaught extends ExpansionSet { cards.add(new SetCardInfo("Riptide Laboratory", 322, Rarity.RARE, mage.cards.r.RiptideLaboratory.class)); cards.add(new SetCardInfo("Riptide Replicator", 309, Rarity.RARE, mage.cards.r.RiptideReplicator.class)); cards.add(new SetCardInfo("Riptide Shapeshifter", 109, Rarity.UNCOMMON, mage.cards.r.RiptideShapeshifter.class)); + cards.add(new SetCardInfo("Risky Move", 223, Rarity.RARE, mage.cards.r.RiskyMove.class)); cards.add(new SetCardInfo("Rorix Bladewing", 224, Rarity.RARE, mage.cards.r.RorixBladewing.class)); cards.add(new SetCardInfo("Rotlung Reanimator", 164, Rarity.RARE, mage.cards.r.RotlungReanimator.class)); cards.add(new SetCardInfo("Rummaging Wizard", 110, Rarity.UNCOMMON, mage.cards.r.RummagingWizard.class)); cards.add(new SetCardInfo("Run Wild", 279, Rarity.UNCOMMON, mage.cards.r.RunWild.class)); cards.add(new SetCardInfo("Sage Aven", 111, Rarity.COMMON, mage.cards.s.SageAven.class)); - cards.add(new SetCardInfo("Sandskin", 52, Rarity.COMMON, mage.cards.s.Sandskin.class)); + cards.add(new SetCardInfo("Sandskin", 52, Rarity.COMMON, mage.cards.s.Sandskin.class)); cards.add(new SetCardInfo("Screaming Seahawk", 112, Rarity.COMMON, mage.cards.s.ScreamingSeahawk.class)); cards.add(new SetCardInfo("Screeching Buzzard", 165, Rarity.COMMON, mage.cards.s.ScreechingBuzzard.class)); cards.add(new SetCardInfo("Searing Flesh", 225, Rarity.UNCOMMON, mage.cards.s.SearingFlesh.class)); @@ -260,11 +262,12 @@ public class Onslaught extends ExpansionSet { cards.add(new SetCardInfo("Secluded Steppe", 324, Rarity.COMMON, mage.cards.s.SecludedSteppe.class)); cards.add(new SetCardInfo("Serpentine Basilisk", 280, Rarity.UNCOMMON, mage.cards.s.SerpentineBasilisk.class)); cards.add(new SetCardInfo("Severed Legion", 166, Rarity.COMMON, mage.cards.s.SeveredLegion.class)); + cards.add(new SetCardInfo("Shade's Breath", 167, Rarity.UNCOMMON, mage.cards.s.ShadesBreath.class)); cards.add(new SetCardInfo("Shaleskin Bruiser", 226, Rarity.UNCOMMON, mage.cards.s.ShaleskinBruiser.class)); cards.add(new SetCardInfo("Shared Triumph", 53, Rarity.RARE, mage.cards.s.SharedTriumph.class)); cards.add(new SetCardInfo("Shepherd of Rot", 168, Rarity.COMMON, mage.cards.s.ShepherdOfRot.class)); cards.add(new SetCardInfo("Shock", 227, Rarity.COMMON, mage.cards.s.Shock.class)); - cards.add(new SetCardInfo("Sigil of the New Dawn", 55, Rarity.RARE, mage.cards.s.SigilOfTheNewDawn.class)); + cards.add(new SetCardInfo("Sigil of the New Dawn", 55, Rarity.RARE, mage.cards.s.SigilOfTheNewDawn.class)); cards.add(new SetCardInfo("Silent Specter", 169, Rarity.RARE, mage.cards.s.SilentSpecter.class)); cards.add(new SetCardInfo("Silklash Spider", 281, Rarity.RARE, mage.cards.s.SilklashSpider.class)); cards.add(new SetCardInfo("Silvos, Rogue Elemental", 282, Rarity.RARE, mage.cards.s.SilvosRogueElemental.class)); @@ -280,7 +283,7 @@ public class Onslaught extends ExpansionSet { cards.add(new SetCardInfo("Soulless One", 171, Rarity.UNCOMMON, mage.cards.s.SoullessOne.class)); cards.add(new SetCardInfo("Sparksmith", 235, Rarity.COMMON, mage.cards.s.Sparksmith.class)); cards.add(new SetCardInfo("Spined Basher", 172, Rarity.COMMON, mage.cards.s.SpinedBasher.class)); - cards.add(new SetCardInfo("Spitfire Handler", 236, Rarity.UNCOMMON, mage.cards.s.SpitfireHandler.class)); + cards.add(new SetCardInfo("Spitfire Handler", 236, Rarity.UNCOMMON, mage.cards.s.SpitfireHandler.class)); cards.add(new SetCardInfo("Spitting Gourna", 284, Rarity.COMMON, mage.cards.s.SpittingGourna.class)); cards.add(new SetCardInfo("Spurred Wolverine", 237, Rarity.COMMON, mage.cards.s.SpurredWolverine.class)); cards.add(new SetCardInfo("Stag Beetle", 285, Rarity.RARE, mage.cards.s.StagBeetle.class)); @@ -311,12 +314,13 @@ public class Onslaught extends ExpansionSet { cards.add(new SetCardInfo("Trade Secrets", 118, Rarity.RARE, mage.cards.t.TradeSecrets.class)); cards.add(new SetCardInfo("Tranquil Thicket", 326, Rarity.COMMON, mage.cards.t.TranquilThicket.class)); cards.add(new SetCardInfo("Treespring Lorian", 293, Rarity.COMMON, mage.cards.t.TreespringLorian.class)); + cards.add(new SetCardInfo("Tribal Golem", 311, Rarity.RARE, mage.cards.t.TribalGolem.class)); cards.add(new SetCardInfo("Tribal Unity", 294, Rarity.UNCOMMON, mage.cards.t.TribalUnity.class)); cards.add(new SetCardInfo("Trickery Charm", 119, Rarity.COMMON, mage.cards.t.TrickeryCharm.class)); cards.add(new SetCardInfo("True Believer", 57, Rarity.RARE, mage.cards.t.TrueBeliever.class)); cards.add(new SetCardInfo("Undead Gladiator", 178, Rarity.RARE, mage.cards.u.UndeadGladiator.class)); cards.add(new SetCardInfo("Unholy Grotto", 327, Rarity.RARE, mage.cards.u.UnholyGrotto.class)); - cards.add(new SetCardInfo("Unified Strike", 58, Rarity.COMMON, mage.cards.u.UnifiedStrike.class)); + cards.add(new SetCardInfo("Unified Strike", 58, Rarity.COMMON, mage.cards.u.UnifiedStrike.class)); cards.add(new SetCardInfo("Venomspout Brackus", 295, Rarity.UNCOMMON, mage.cards.v.VenomspoutBrackus.class)); cards.add(new SetCardInfo("Visara the Dreadful", 179, Rarity.RARE, mage.cards.v.VisaraTheDreadful.class)); cards.add(new SetCardInfo("Vitality Charm", 296, Rarity.COMMON, mage.cards.v.VitalityCharm.class)); @@ -336,7 +340,7 @@ public class Onslaught extends ExpansionSet { cards.add(new SetCardInfo("Wirewood Lodge", 329, Rarity.RARE, mage.cards.w.WirewoodLodge.class)); cards.add(new SetCardInfo("Wirewood Pride", 303, Rarity.COMMON, mage.cards.w.WirewoodPride.class)); cards.add(new SetCardInfo("Wirewood Savage", 304, Rarity.COMMON, mage.cards.w.WirewoodSavage.class)); - cards.add(new SetCardInfo("Withering Hex", 181, Rarity.UNCOMMON, mage.cards.w.WitheringHex.class)); + cards.add(new SetCardInfo("Withering Hex", 181, Rarity.UNCOMMON, mage.cards.w.WitheringHex.class)); cards.add(new SetCardInfo("Wooded Foothills", 330, Rarity.RARE, mage.cards.w.WoodedFoothills.class, new CardGraphicInfo(new ObjectColor("RG"), null, false))); cards.add(new SetCardInfo("Words of War", 244, Rarity.RARE, mage.cards.w.WordsOfWar.class)); cards.add(new SetCardInfo("Words of Waste", 182, Rarity.RARE, mage.cards.w.WordsOfWaste.class)); diff --git a/Mage.Sets/src/mage/sets/PlanarChaos.java b/Mage.Sets/src/mage/sets/PlanarChaos.java index d68966c157..0e86820575 100644 --- a/Mage.Sets/src/mage/sets/PlanarChaos.java +++ b/Mage.Sets/src/mage/sets/PlanarChaos.java @@ -198,6 +198,7 @@ public class PlanarChaos extends ExpansionSet { cards.add(new SetCardInfo("Teneb, the Harvester", 163, Rarity.RARE, mage.cards.t.TenebTheHarvester.class)); cards.add(new SetCardInfo("Tidewalker", 49, Rarity.UNCOMMON, mage.cards.t.Tidewalker.class)); cards.add(new SetCardInfo("Timbermare", 140, Rarity.RARE, mage.cards.t.Timbermare.class)); + cards.add(new SetCardInfo("Timebender", 50, Rarity.UNCOMMON, mage.cards.t.Timebender.class)); cards.add(new SetCardInfo("Timecrafting", 109, Rarity.UNCOMMON, mage.cards.t.Timecrafting.class)); cards.add(new SetCardInfo("Torchling", 110, Rarity.RARE, mage.cards.t.Torchling.class)); cards.add(new SetCardInfo("Treacherous Urge", 82, Rarity.UNCOMMON, mage.cards.t.TreacherousUrge.class)); diff --git a/Mage.Sets/src/mage/sets/Planeshift.java b/Mage.Sets/src/mage/sets/Planeshift.java index c44e08f37c..bc0f02483c 100644 --- a/Mage.Sets/src/mage/sets/Planeshift.java +++ b/Mage.Sets/src/mage/sets/Planeshift.java @@ -181,6 +181,7 @@ public class Planeshift extends ExpansionSet { cards.add(new SetCardInfo("Sunken Hope", 37, Rarity.RARE, mage.cards.s.SunkenHope.class)); cards.add(new SetCardInfo("Sunscape Battlemage", 16, Rarity.UNCOMMON, mage.cards.s.SunscapeBattlemage.class)); cards.add(new SetCardInfo("Sunscape Familiar", 17, Rarity.COMMON, mage.cards.s.SunscapeFamiliar.class)); + cards.add(new SetCardInfo("Surprise Deployment", 18, Rarity.UNCOMMON, mage.cards.s.SurpriseDeployment.class)); cards.add(new SetCardInfo("Tahngarth, Talruum Hero", "74a", Rarity.RARE, TahngarthTalruumHero.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Tahngarth, Talruum Hero", "74b", Rarity.RARE, TahngarthTalruumHero.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Terminal Moraine", 142, Rarity.UNCOMMON, mage.cards.t.TerminalMoraine.class)); diff --git a/Mage.Sets/src/mage/sets/Portal.java b/Mage.Sets/src/mage/sets/Portal.java index 7551940ca8..8c15c619ed 100644 --- a/Mage.Sets/src/mage/sets/Portal.java +++ b/Mage.Sets/src/mage/sets/Portal.java @@ -71,6 +71,7 @@ public class Portal extends ExpansionSet { cards.add(new SetCardInfo("Armageddon", 167, Rarity.RARE, mage.cards.a.Armageddon.class)); cards.add(new SetCardInfo("Armored Pegasus", 168, Rarity.COMMON, mage.cards.a.ArmoredPegasus.class)); cards.add(new SetCardInfo("Arrogant Vampire", 1, Rarity.UNCOMMON, mage.cards.a.ArrogantVampire.class)); + cards.add(new SetCardInfo("Assassin's Blade", 2, Rarity.UNCOMMON, mage.cards.a.AssassinsBlade.class)); cards.add(new SetCardInfo("Balance of Power", 42, Rarity.RARE, mage.cards.b.BalanceOfPower.class)); cards.add(new SetCardInfo("Baleful Stare", 43, Rarity.UNCOMMON, mage.cards.b.BalefulStare.class)); cards.add(new SetCardInfo("Bee Sting", 83, Rarity.UNCOMMON, mage.cards.b.BeeSting.class)); @@ -94,12 +95,14 @@ public class Portal extends ExpansionSet { cards.add(new SetCardInfo("Cloud Dragon", 46, Rarity.RARE, mage.cards.c.CloudDragon.class)); cards.add(new SetCardInfo("Cloud Pirates", 47, Rarity.COMMON, mage.cards.c.CloudPirates.class)); cards.add(new SetCardInfo("Cloud Spirit", 48, Rarity.UNCOMMON, mage.cards.c.CloudSpirit.class)); + cards.add(new SetCardInfo("Command of Unsummoning", 49, Rarity.UNCOMMON, mage.cards.c.CommandOfUnsummoning.class)); cards.add(new SetCardInfo("Coral Eel", 50, Rarity.COMMON, mage.cards.c.CoralEel.class)); cards.add(new SetCardInfo("Craven Giant", 126, Rarity.COMMON, mage.cards.c.CravenGiant.class)); cards.add(new SetCardInfo("Craven Knight", 7, Rarity.COMMON, mage.cards.c.CravenKnight.class)); cards.add(new SetCardInfo("Cruel Bargain", 8, Rarity.RARE, mage.cards.c.CruelBargain.class)); cards.add(new SetCardInfo("Cruel Tutor", 9, Rarity.RARE, mage.cards.c.CruelTutor.class)); cards.add(new SetCardInfo("Deep-Sea Serpent", 52, Rarity.UNCOMMON, mage.cards.d.DeepSeaSerpent.class)); + cards.add(new SetCardInfo("Defiant Stand", 174, Rarity.UNCOMMON, mage.cards.d.DefiantStand.class)); cards.add(new SetCardInfo("Deja Vu", 53, Rarity.COMMON, mage.cards.d.DejaVu.class)); cards.add(new SetCardInfo("Desert Drake", 127, Rarity.UNCOMMON, mage.cards.d.DesertDrake.class)); cards.add(new SetCardInfo("Devastation", 128, Rarity.RARE, mage.cards.d.Devastation.class)); @@ -214,6 +217,7 @@ public class Portal extends ExpansionSet { cards.add(new SetCardInfo("Sacred Knight", 186, Rarity.COMMON, mage.cards.s.SacredKnight.class)); cards.add(new SetCardInfo("Sacred Nectar", 187, Rarity.COMMON, mage.cards.s.SacredNectar.class)); cards.add(new SetCardInfo("Scorching Spear", 154, Rarity.COMMON, mage.cards.s.ScorchingSpear.class)); + cards.add(new SetCardInfo("Scorching Winds", 155, Rarity.UNCOMMON, mage.cards.s.ScorchingWinds.class)); cards.add(new SetCardInfo("Seasoned Marshal", 188, Rarity.UNCOMMON, mage.cards.s.SeasonedMarshal.class)); cards.add(new SetCardInfo("Serpent Assassin", 31, Rarity.RARE, mage.cards.s.SerpentAssassin.class)); cards.add(new SetCardInfo("Serpent Warrior", 32, Rarity.COMMON, mage.cards.s.SerpentWarrior.class)); @@ -248,6 +252,7 @@ public class Portal extends ExpansionSet { cards.add(new SetCardInfo("Tidal Surge", 75, Rarity.COMMON, mage.cards.t.TidalSurge.class)); cards.add(new SetCardInfo("Time Ebb", 76, Rarity.COMMON, mage.cards.t.TimeEbb.class)); cards.add(new SetCardInfo("Touch of Brilliance", 77, Rarity.COMMON, mage.cards.t.TouchOfBrilliance.class)); + cards.add(new SetCardInfo("Treetop Defense", 116, Rarity.RARE, mage.cards.t.TreetopDefense.class)); cards.add(new SetCardInfo("Undying Beast", 36, Rarity.COMMON, mage.cards.u.UndyingBeast.class)); cards.add(new SetCardInfo("Untamed Wilds", 117, Rarity.UNCOMMON, mage.cards.u.UntamedWilds.class)); cards.add(new SetCardInfo("Valorous Charge", 196, Rarity.UNCOMMON, mage.cards.v.ValorousCharge.class)); diff --git a/Mage.Sets/src/mage/sets/PortalSecondAge.java b/Mage.Sets/src/mage/sets/PortalSecondAge.java index 16e6adfa71..ced4eb2baf 100644 --- a/Mage.Sets/src/mage/sets/PortalSecondAge.java +++ b/Mage.Sets/src/mage/sets/PortalSecondAge.java @@ -165,8 +165,10 @@ public class PortalSecondAge extends ExpansionSet { cards.add(new SetCardInfo("Raiding Nightstalker", 24, Rarity.COMMON, mage.cards.r.RaidingNightstalker.class)); cards.add(new SetCardInfo("Rain of Daggers", 25, Rarity.RARE, mage.cards.r.RainOfDaggers.class)); cards.add(new SetCardInfo("Raise Dead", 26, Rarity.COMMON, mage.cards.r.RaiseDead.class)); + cards.add(new SetCardInfo("Rally the Troops", 139, Rarity.UNCOMMON, mage.cards.r.RallyTheTroops.class)); cards.add(new SetCardInfo("Ravenous Rats", 27, Rarity.COMMON, mage.cards.r.RavenousRats.class)); cards.add(new SetCardInfo("Razorclaw Bear", 82, Rarity.RARE, mage.cards.r.RazorclawBear.class)); + cards.add(new SetCardInfo("Remove", 43, Rarity.UNCOMMON, mage.cards.r.Remove.class)); cards.add(new SetCardInfo("Renewing Touch", 83, Rarity.UNCOMMON, mage.cards.r.RenewingTouch.class)); cards.add(new SetCardInfo("Return of the Nightstalkers", 28, Rarity.RARE, mage.cards.r.ReturnOfTheNightstalkers.class)); cards.add(new SetCardInfo("Righteous Charge", 140, Rarity.COMMON, mage.cards.r.RighteousCharge.class)); diff --git a/Mage.Sets/src/mage/sets/PortalThreeKingdoms.java b/Mage.Sets/src/mage/sets/PortalThreeKingdoms.java index 4970599957..bc64a4afe9 100644 --- a/Mage.Sets/src/mage/sets/PortalThreeKingdoms.java +++ b/Mage.Sets/src/mage/sets/PortalThreeKingdoms.java @@ -68,6 +68,7 @@ public class PortalThreeKingdoms extends ExpansionSet { cards.add(new SetCardInfo("Cao Cao, Lord of Wei", 68, Rarity.RARE, mage.cards.c.CaoCaoLordOfWei.class)); cards.add(new SetCardInfo("Cao Ren, Wei Commander", 69, Rarity.RARE, mage.cards.c.CaoRenWeiCommander.class)); cards.add(new SetCardInfo("Capture of Jingzhou", 38, Rarity.RARE, mage.cards.c.CaptureOfJingzhou.class)); + cards.add(new SetCardInfo("Champion's Victory", 39, Rarity.UNCOMMON, mage.cards.c.ChampionsVictory.class)); cards.add(new SetCardInfo("Coercion", 70, Rarity.UNCOMMON, mage.cards.c.Coercion.class)); cards.add(new SetCardInfo("Control of the Court", 105, Rarity.UNCOMMON, mage.cards.c.ControlOfTheCourt.class)); cards.add(new SetCardInfo("Corrupt Court Official", 71, Rarity.UNCOMMON, mage.cards.c.CorruptCourtOfficial.class)); @@ -80,6 +81,7 @@ public class PortalThreeKingdoms extends ExpansionSet { cards.add(new SetCardInfo("Desperate Charge", 74, Rarity.UNCOMMON, mage.cards.d.DesperateCharge.class)); cards.add(new SetCardInfo("Diaochan, Artful Beauty", 108, Rarity.RARE, mage.cards.d.DiaochanArtfulBeauty.class)); cards.add(new SetCardInfo("Dong Zhou, the Tyrant", 109, Rarity.RARE, mage.cards.d.DongZhouTheTyrant.class)); + cards.add(new SetCardInfo("Eightfold Maze", 2, Rarity.RARE, mage.cards.e.EightfoldMaze.class)); cards.add(new SetCardInfo("Empty City Ruse", 3, Rarity.UNCOMMON, mage.cards.e.EmptyCityRuse.class)); cards.add(new SetCardInfo("Exhaustion", 42, Rarity.RARE, mage.cards.e.Exhaustion.class)); cards.add(new SetCardInfo("Extinguish", 43, Rarity.COMMON, mage.cards.e.Extinguish.class)); @@ -100,6 +102,7 @@ public class PortalThreeKingdoms extends ExpansionSet { cards.add(new SetCardInfo("Huang Zhong, Shu General", 8, Rarity.RARE, mage.cards.h.HuangZhongShuGeneral.class)); cards.add(new SetCardInfo("Hua Tuo, Honored Physician", 137, Rarity.RARE, mage.cards.h.HuaTuoHonoredPhysician.class)); cards.add(new SetCardInfo("Hunting Cheetah", 138, Rarity.UNCOMMON, mage.cards.h.HuntingCheetah.class)); + cards.add(new SetCardInfo("Imperial Edict", 77, Rarity.COMMON, mage.cards.i.ImperialEdict.class)); cards.add(new SetCardInfo("Imperial Recruiter", 113, Rarity.UNCOMMON, mage.cards.i.ImperialRecruiter.class)); cards.add(new SetCardInfo("Imperial Seal", 78, Rarity.RARE, mage.cards.i.ImperialSeal.class)); cards.add(new SetCardInfo("Independent Troops", 114, Rarity.COMMON, mage.cards.i.IndependentTroops.class)); @@ -134,6 +137,7 @@ public class PortalThreeKingdoms extends ExpansionSet { cards.add(new SetCardInfo("Plains", 168, Rarity.LAND, mage.cards.basiclands.Plains.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Poison Arrow", 80, Rarity.UNCOMMON, mage.cards.p.PoisonArrow.class)); cards.add(new SetCardInfo("Preemptive Strike", 50, Rarity.COMMON, mage.cards.p.PreemptiveStrike.class)); + cards.add(new SetCardInfo("Rally the Troops", 16, Rarity.UNCOMMON, mage.cards.r.RallyTheTroops.class)); cards.add(new SetCardInfo("Ravages of War", 17, Rarity.RARE, mage.cards.r.RavagesOfWar.class)); cards.add(new SetCardInfo("Ravaging Horde", 118, Rarity.UNCOMMON, mage.cards.r.RavagingHorde.class)); cards.add(new SetCardInfo("Red Cliffs Armada", 51, Rarity.UNCOMMON, mage.cards.r.RedCliffsArmada.class)); @@ -182,6 +186,7 @@ public class PortalThreeKingdoms extends ExpansionSet { cards.add(new SetCardInfo("Volunteer Militia", 30, Rarity.COMMON, mage.cards.v.VolunteerMilitia.class)); cards.add(new SetCardInfo("Warrior's Oath", 124, Rarity.RARE, mage.cards.w.WarriorsOath.class)); cards.add(new SetCardInfo("Wei Ambush Force", 85, Rarity.COMMON, mage.cards.w.WeiAmbushForce.class)); + cards.add(new SetCardInfo("Wei Assassins", 86, Rarity.UNCOMMON, mage.cards.w.WeiAssassins.class)); cards.add(new SetCardInfo("Wei Elite Companions", 87, Rarity.UNCOMMON, mage.cards.w.WeiEliteCompanions.class)); cards.add(new SetCardInfo("Wei Infantry", 88, Rarity.COMMON, mage.cards.w.WeiInfantry.class)); cards.add(new SetCardInfo("Wei Night Raiders", 89, Rarity.UNCOMMON, mage.cards.w.WeiNightRaiders.class)); diff --git a/Mage.Sets/src/mage/sets/Prophecy.java b/Mage.Sets/src/mage/sets/Prophecy.java index 10b7c6d885..9f3172aa2f 100644 --- a/Mage.Sets/src/mage/sets/Prophecy.java +++ b/Mage.Sets/src/mage/sets/Prophecy.java @@ -83,10 +83,12 @@ public class Prophecy extends ExpansionSet { cards.add(new SetCardInfo("Diving Griffin", 6, Rarity.COMMON, mage.cards.d.DivingGriffin.class)); cards.add(new SetCardInfo("Dual Nature", 112, Rarity.RARE, mage.cards.d.DualNature.class)); cards.add(new SetCardInfo("Elephant Resurgence", 113, Rarity.RARE, mage.cards.e.ElephantResurgence.class)); + cards.add(new SetCardInfo("Endbringer's Revel", 63, Rarity.UNCOMMON, mage.cards.e.EndbringersRevel.class)); cards.add(new SetCardInfo("Entangler", 7, Rarity.UNCOMMON, mage.cards.e.Entangler.class)); cards.add(new SetCardInfo("Excavation", 33, Rarity.UNCOMMON, mage.cards.e.Excavation.class)); cards.add(new SetCardInfo("Fault Riders", 88, Rarity.COMMON, mage.cards.f.FaultRiders.class)); cards.add(new SetCardInfo("Fen Stalker", 64, Rarity.COMMON, mage.cards.f.FenStalker.class)); + cards.add(new SetCardInfo("Fickle Efreet", 89, Rarity.RARE, mage.cards.f.FickleEfreet.class)); cards.add(new SetCardInfo("Flameshot", 90, Rarity.UNCOMMON, mage.cards.f.Flameshot.class)); cards.add(new SetCardInfo("Flowering Field", 9, Rarity.UNCOMMON, mage.cards.f.FloweringField.class)); cards.add(new SetCardInfo("Foil", 34, Rarity.UNCOMMON, mage.cards.f.Foil.class)); @@ -105,6 +107,7 @@ public class Prophecy extends ExpansionSet { cards.add(new SetCardInfo("Keldon Berserker", 93, Rarity.COMMON, mage.cards.k.KeldonBerserker.class)); cards.add(new SetCardInfo("Keldon Firebombers", 94, Rarity.RARE, mage.cards.k.KeldonFirebombers.class)); cards.add(new SetCardInfo("Latulla, Keldon Overseer", 95, Rarity.RARE, mage.cards.l.LatullaKeldonOverseer.class)); + cards.add(new SetCardInfo("Latulla's Orders", 96, Rarity.COMMON, mage.cards.l.LatullasOrders.class)); cards.add(new SetCardInfo("Lesser Gargadon", 97, Rarity.UNCOMMON, mage.cards.l.LesserGargadon.class)); cards.add(new SetCardInfo("Living Terrain", 117, Rarity.UNCOMMON, mage.cards.l.LivingTerrain.class)); cards.add(new SetCardInfo("Mageta's Boon", 14, Rarity.COMMON, mage.cards.m.MagetasBoon.class)); @@ -128,6 +131,7 @@ public class Prophecy extends ExpansionSet { cards.add(new SetCardInfo("Rebel Informer", 75, Rarity.RARE, mage.cards.r.RebelInformer.class)); cards.add(new SetCardInfo("Rethink", 42, Rarity.COMMON, mage.cards.r.Rethink.class)); cards.add(new SetCardInfo("Reveille Squad", 18, Rarity.UNCOMMON, mage.cards.r.ReveilleSquad.class)); + cards.add(new SetCardInfo("Rhystic Cave", 142, Rarity.UNCOMMON, mage.cards.r.RhysticCave.class)); cards.add(new SetCardInfo("Rhystic Circle", 19, Rarity.COMMON, mage.cards.r.RhysticCircle.class)); cards.add(new SetCardInfo("Rhystic Study", 45, Rarity.COMMON, mage.cards.r.RhysticStudy.class)); cards.add(new SetCardInfo("Rhystic Tutor", 77, Rarity.RARE, mage.cards.r.RhysticTutor.class)); diff --git a/Mage.Sets/src/mage/sets/RavnicaCityOfGuilds.java b/Mage.Sets/src/mage/sets/RavnicaCityOfGuilds.java index 8bea79044a..f2884e0aa5 100644 --- a/Mage.Sets/src/mage/sets/RavnicaCityOfGuilds.java +++ b/Mage.Sets/src/mage/sets/RavnicaCityOfGuilds.java @@ -213,6 +213,7 @@ public class RavnicaCityOfGuilds extends ExpansionSet { cards.add(new SetCardInfo("Loxodon Hierarch", 214, Rarity.RARE, mage.cards.l.LoxodonHierarch.class)); cards.add(new SetCardInfo("Lurking Informant", 249, Rarity.COMMON, mage.cards.l.LurkingInformant.class)); cards.add(new SetCardInfo("Mark of Eviction", 58, Rarity.UNCOMMON, mage.cards.m.MarkOfEviction.class)); + cards.add(new SetCardInfo("Master Warcraft", 250, Rarity.RARE, mage.cards.m.MasterWarcraft.class)); cards.add(new SetCardInfo("Mausoleum Turnkey", 94, Rarity.UNCOMMON, mage.cards.m.MausoleumTurnkey.class)); cards.add(new SetCardInfo("Mindleech Mass", 215, Rarity.RARE, mage.cards.m.MindleechMass.class)); cards.add(new SetCardInfo("Mindmoil", 135, Rarity.RARE, mage.cards.m.Mindmoil.class)); diff --git a/Mage.Sets/src/mage/sets/RevisedEdition.java b/Mage.Sets/src/mage/sets/RevisedEdition.java index de67e20007..ae43bcfa15 100644 --- a/Mage.Sets/src/mage/sets/RevisedEdition.java +++ b/Mage.Sets/src/mage/sets/RevisedEdition.java @@ -163,6 +163,7 @@ public class RevisedEdition extends ExpansionSet { cards.add(new SetCardInfo("Keldon Warlord", 159, Rarity.UNCOMMON, mage.cards.k.KeldonWarlord.class)); cards.add(new SetCardInfo("Kird Ape", 160, Rarity.COMMON, mage.cards.k.KirdApe.class)); cards.add(new SetCardInfo("Kormus Bell", 260, Rarity.RARE, mage.cards.k.KormusBell.class)); + cards.add(new SetCardInfo("Kudzu", 112, Rarity.RARE, mage.cards.k.Kudzu.class)); cards.add(new SetCardInfo("Lance", 211, Rarity.UNCOMMON, mage.cards.l.Lance.class)); cards.add(new SetCardInfo("Ley Druid", 113, Rarity.UNCOMMON, mage.cards.l.LeyDruid.class)); cards.add(new SetCardInfo("Library of Leng", 261, Rarity.UNCOMMON, mage.cards.l.LibraryOfLeng.class)); diff --git a/Mage.Sets/src/mage/sets/Scourge.java b/Mage.Sets/src/mage/sets/Scourge.java index d3462236f7..122d20e405 100644 --- a/Mage.Sets/src/mage/sets/Scourge.java +++ b/Mage.Sets/src/mage/sets/Scourge.java @@ -55,7 +55,7 @@ public class Scourge extends ExpansionSet { this.numBoosterRare = 1; this.ratioBoosterMythic = 0; cards.add(new SetCardInfo("Accelerated Mutation", 109, Rarity.COMMON, mage.cards.a.AcceleratedMutation.class)); - cards.add(new SetCardInfo("Ageless Sentinels", 1, Rarity.RARE, mage.cards.a.AgelessSentinels.class)); + cards.add(new SetCardInfo("Ageless Sentinels", 1, Rarity.RARE, mage.cards.a.AgelessSentinels.class)); cards.add(new SetCardInfo("Alpha Status", 110, Rarity.UNCOMMON, mage.cards.a.AlphaStatus.class)); cards.add(new SetCardInfo("Ambush Commander", 111, Rarity.RARE, mage.cards.a.AmbushCommander.class)); cards.add(new SetCardInfo("Ancient Ooze", 112, Rarity.RARE, mage.cards.a.AncientOoze.class)); @@ -66,7 +66,7 @@ public class Scourge extends ExpansionSet { cards.add(new SetCardInfo("Aven Liberator", 4, Rarity.COMMON, mage.cards.a.AvenLiberator.class)); cards.add(new SetCardInfo("Bladewing's Thrall", 55, Rarity.UNCOMMON, mage.cards.b.BladewingsThrall.class)); cards.add(new SetCardInfo("Bladewing the Risen", 136, Rarity.RARE, mage.cards.b.BladewingTheRisen.class)); - cards.add(new SetCardInfo("Bonethorn Valesk", 82, Rarity.COMMON, mage.cards.b.BonethornValesk.class)); + cards.add(new SetCardInfo("Bonethorn Valesk", 82, Rarity.COMMON, mage.cards.b.BonethornValesk.class)); cards.add(new SetCardInfo("Brain Freeze", 29, Rarity.UNCOMMON, mage.cards.b.BrainFreeze.class)); cards.add(new SetCardInfo("Break Asunder", 113, Rarity.COMMON, mage.cards.b.BreakAsunder.class)); cards.add(new SetCardInfo("Cabal Conditioning", 56, Rarity.RARE, mage.cards.c.CabalConditioning.class)); @@ -116,6 +116,7 @@ public class Scourge extends ExpansionSet { cards.add(new SetCardInfo("Frozen Solid", 36, Rarity.COMMON, mage.cards.f.FrozenSolid.class)); cards.add(new SetCardInfo("Gilded Light", 16, Rarity.UNCOMMON, mage.cards.g.GildedLight.class)); cards.add(new SetCardInfo("Goblin Brigand", 94, Rarity.COMMON, mage.cards.g.GoblinBrigand.class)); + cards.add(new SetCardInfo("Goblin Psychopath", 95, Rarity.UNCOMMON, mage.cards.g.GoblinPsychopath.class)); cards.add(new SetCardInfo("Goblin Warchief", 97, Rarity.UNCOMMON, mage.cards.g.GoblinWarchief.class)); cards.add(new SetCardInfo("Goblin War Strike", 96, Rarity.COMMON, mage.cards.g.GoblinWarStrike.class)); cards.add(new SetCardInfo("Grip of Chaos", 98, Rarity.RARE, mage.cards.g.GripOfChaos.class)); @@ -133,7 +134,7 @@ public class Scourge extends ExpansionSet { cards.add(new SetCardInfo("Mind's Desire", 41, Rarity.RARE, mage.cards.m.MindsDesire.class)); cards.add(new SetCardInfo("Mischievous Quanar", 42, Rarity.RARE, mage.cards.m.MischievousQuanar.class)); cards.add(new SetCardInfo("Misguided Rage", 99, Rarity.COMMON, mage.cards.m.MisguidedRage.class)); - cards.add(new SetCardInfo("Mistform Warchief", 43, Rarity.UNCOMMON, mage.cards.m.MistformWarchief.class)); + cards.add(new SetCardInfo("Mistform Warchief", 43, Rarity.UNCOMMON, mage.cards.m.MistformWarchief.class)); cards.add(new SetCardInfo("Nefashu", 70, Rarity.RARE, mage.cards.n.Nefashu.class)); cards.add(new SetCardInfo("Noble Templar", 19, Rarity.COMMON, mage.cards.n.NobleTemplar.class)); cards.add(new SetCardInfo("One with Nature", 125, Rarity.UNCOMMON, mage.cards.o.OneWithNature.class)); @@ -142,7 +143,7 @@ public class Scourge extends ExpansionSet { cards.add(new SetCardInfo("Putrid Raptor", 71, Rarity.UNCOMMON, mage.cards.p.PutridRaptor.class)); cards.add(new SetCardInfo("Pyrostatic Pillar", 100, Rarity.UNCOMMON, mage.cards.p.PyrostaticPillar.class)); cards.add(new SetCardInfo("Rain of Blades", 20, Rarity.UNCOMMON, mage.cards.r.RainOfBlades.class)); - cards.add(new SetCardInfo("Raven Guild Initiate", 46, Rarity.COMMON, mage.cards.r.RavenGuildInitiate.class)); + cards.add(new SetCardInfo("Raven Guild Initiate", 46, Rarity.COMMON, mage.cards.r.RavenGuildInitiate.class)); cards.add(new SetCardInfo("Raven Guild Master", 47, Rarity.RARE, mage.cards.r.RavenGuildMaster.class)); cards.add(new SetCardInfo("Reaping the Graves", 72, Rarity.COMMON, mage.cards.r.ReapingTheGraves.class)); cards.add(new SetCardInfo("Recuperate", 21, Rarity.COMMON, mage.cards.r.Recuperate.class)); diff --git a/Mage.Sets/src/mage/sets/Tempest.java b/Mage.Sets/src/mage/sets/Tempest.java index eb67ac2a83..a42508ca05 100644 --- a/Mage.Sets/src/mage/sets/Tempest.java +++ b/Mage.Sets/src/mage/sets/Tempest.java @@ -182,6 +182,7 @@ public class Tempest extends ExpansionSet { cards.add(new SetCardInfo("Lobotomy", 342, Rarity.UNCOMMON, mage.cards.l.Lobotomy.class)); cards.add(new SetCardInfo("Lotus Petal", 284, Rarity.COMMON, mage.cards.l.LotusPetal.class)); cards.add(new SetCardInfo("Lowland Giant", 187, Rarity.COMMON, mage.cards.l.LowlandGiant.class)); + cards.add(new SetCardInfo("Maddening Imp", 37, Rarity.RARE, mage.cards.m.MaddeningImp.class)); cards.add(new SetCardInfo("Magmasaur", 188, Rarity.RARE, mage.cards.m.Magmasaur.class)); cards.add(new SetCardInfo("Manakin", 286, Rarity.COMMON, mage.cards.m.Manakin.class)); cards.add(new SetCardInfo("Mana Severance", 73, Rarity.RARE, mage.cards.m.ManaSeverance.class)); @@ -244,6 +245,7 @@ public class Tempest extends ExpansionSet { cards.add(new SetCardInfo("Rats of Rath", 44, Rarity.COMMON, mage.cards.r.RatsOfRath.class)); cards.add(new SetCardInfo("Reality Anchor", 140, Rarity.COMMON, mage.cards.r.RealityAnchor.class)); cards.add(new SetCardInfo("Reanimate", 45, Rarity.UNCOMMON, mage.cards.r.Reanimate.class)); + cards.add(new SetCardInfo("Reap", 141, Rarity.UNCOMMON, mage.cards.r.Reap.class)); cards.add(new SetCardInfo("Reckless Spite", 46, Rarity.UNCOMMON, mage.cards.r.RecklessSpite.class)); cards.add(new SetCardInfo("Recycle", 142, Rarity.RARE, mage.cards.r.Recycle.class)); cards.add(new SetCardInfo("Reflecting Pool", 328, Rarity.RARE, mage.cards.r.ReflectingPool.class)); diff --git a/Mage.Sets/src/mage/sets/TheDark.java b/Mage.Sets/src/mage/sets/TheDark.java index bacad0e06f..a3586cc625 100644 --- a/Mage.Sets/src/mage/sets/TheDark.java +++ b/Mage.Sets/src/mage/sets/TheDark.java @@ -105,6 +105,7 @@ public class TheDark extends ExpansionSet { cards.add(new SetCardInfo("Marsh Gas", 10, Rarity.COMMON, mage.cards.m.MarshGas.class)); cards.add(new SetCardInfo("Marsh Goblins", 118, Rarity.COMMON, mage.cards.m.MarshGoblins.class)); cards.add(new SetCardInfo("Marsh Viper", 44, Rarity.COMMON, mage.cards.m.MarshViper.class)); + cards.add(new SetCardInfo("Martyr's Cry", 85, Rarity.RARE, mage.cards.m.MartyrsCry.class)); cards.add(new SetCardInfo("Maze of Ith", 114, Rarity.UNCOMMON, mage.cards.m.MazeOfIth.class)); cards.add(new SetCardInfo("Merfolk Assassin", 31, Rarity.UNCOMMON, mage.cards.m.MerfolkAssassin.class)); cards.add(new SetCardInfo("Mind Bomb", 32, Rarity.RARE, mage.cards.m.MindBomb.class)); @@ -123,6 +124,7 @@ public class TheDark extends ExpansionSet { cards.add(new SetCardInfo("Scarwood Goblins", 119, Rarity.COMMON, mage.cards.s.ScarwoodGoblins.class)); cards.add(new SetCardInfo("Scarwood Hag", 49, Rarity.UNCOMMON, mage.cards.s.ScarwoodHag.class)); cards.add(new SetCardInfo("Scavenger Folk", 50, Rarity.COMMON, mage.cards.s.ScavengerFolk.class)); + cards.add(new SetCardInfo("Season of the Witch", 14, Rarity.RARE, mage.cards.s.SeasonOfTheWitch.class)); cards.add(new SetCardInfo("Sisters of the Flame", 73, Rarity.UNCOMMON, mage.cards.s.SistersOfTheFlame.class)); cards.add(new SetCardInfo("Skull of Orm", 106, Rarity.UNCOMMON, mage.cards.s.SkullOfOrm.class)); cards.add(new SetCardInfo("Squire", 90, Rarity.COMMON, mage.cards.s.Squire.class)); diff --git a/Mage.Sets/src/mage/sets/UnlimitedEdition.java b/Mage.Sets/src/mage/sets/UnlimitedEdition.java index 32df097c5e..cfecaacda2 100644 --- a/Mage.Sets/src/mage/sets/UnlimitedEdition.java +++ b/Mage.Sets/src/mage/sets/UnlimitedEdition.java @@ -154,6 +154,7 @@ public class UnlimitedEdition extends ExpansionSet { cards.add(new SetCardInfo("Karma", 211, Rarity.UNCOMMON, mage.cards.k.Karma.class)); cards.add(new SetCardInfo("Keldon Warlord", 161, Rarity.UNCOMMON, mage.cards.k.KeldonWarlord.class)); cards.add(new SetCardInfo("Kormus Bell", 257, Rarity.RARE, mage.cards.k.KormusBell.class)); + cards.add(new SetCardInfo("Kudzu", 113, Rarity.RARE, mage.cards.k.Kudzu.class)); cards.add(new SetCardInfo("Lance", 212, Rarity.UNCOMMON, mage.cards.l.Lance.class)); cards.add(new SetCardInfo("Ley Druid", 114, Rarity.UNCOMMON, mage.cards.l.LeyDruid.class)); cards.add(new SetCardInfo("Library of Leng", 258, Rarity.UNCOMMON, mage.cards.l.LibraryOfLeng.class)); diff --git a/Mage.Sets/src/mage/sets/UrzasDestiny.java b/Mage.Sets/src/mage/sets/UrzasDestiny.java index 6a243198e5..acec22dff2 100644 --- a/Mage.Sets/src/mage/sets/UrzasDestiny.java +++ b/Mage.Sets/src/mage/sets/UrzasDestiny.java @@ -120,6 +120,7 @@ public class UrzasDestiny extends ExpansionSet { cards.add(new SetCardInfo("Mental Discipline", 37, Rarity.COMMON, mage.cards.m.MentalDiscipline.class)); cards.add(new SetCardInfo("Metalworker", 135, Rarity.RARE, mage.cards.m.Metalworker.class)); cards.add(new SetCardInfo("Metathran Soldier", 39, Rarity.COMMON, mage.cards.m.MetathranSoldier.class)); + cards.add(new SetCardInfo("Momentum", 113, Rarity.UNCOMMON, mage.cards.m.Momentum.class)); cards.add(new SetCardInfo("Multani's Decree", 114, Rarity.COMMON, mage.cards.m.MultanisDecree.class)); cards.add(new SetCardInfo("Opalescence", 13, Rarity.RARE, mage.cards.o.Opalescence.class)); cards.add(new SetCardInfo("Opposition", 40, Rarity.RARE, mage.cards.o.Opposition.class)); diff --git a/Mage.Sets/src/mage/sets/UrzasSaga.java b/Mage.Sets/src/mage/sets/UrzasSaga.java index 3968d93c04..e6c428107e 100644 --- a/Mage.Sets/src/mage/sets/UrzasSaga.java +++ b/Mage.Sets/src/mage/sets/UrzasSaga.java @@ -362,6 +362,7 @@ public class UrzasSaga extends ExpansionSet { cards.add(new SetCardInfo("Vug Lizard", 227, Rarity.UNCOMMON, mage.cards.v.VugLizard.class)); cards.add(new SetCardInfo("War Dance", 282, Rarity.UNCOMMON, mage.cards.w.WarDance.class)); cards.add(new SetCardInfo("Wall of Junk", 315, Rarity.UNCOMMON, mage.cards.w.WallOfJunk.class)); + cards.add(new SetCardInfo("Waylay", 56, Rarity.UNCOMMON, mage.cards.w.Waylay.class)); cards.add(new SetCardInfo("Western Paladin", 168, Rarity.RARE, mage.cards.w.WesternPaladin.class)); cards.add(new SetCardInfo("Whetstone", 316, Rarity.RARE, mage.cards.w.Whetstone.class)); cards.add(new SetCardInfo("Whirlwind", 283, Rarity.RARE, mage.cards.w.Whirlwind.class)); diff --git a/Mage.Sets/src/mage/sets/Visions.java b/Mage.Sets/src/mage/sets/Visions.java index 06465ba0d5..4f8f5d0e79 100644 --- a/Mage.Sets/src/mage/sets/Visions.java +++ b/Mage.Sets/src/mage/sets/Visions.java @@ -78,8 +78,10 @@ public class Visions extends ExpansionSet { cards.add(new SetCardInfo("Diamond Kaleidoscope", 143, Rarity.RARE, mage.cards.d.DiamondKaleidoscope.class)); cards.add(new SetCardInfo("Dormant Volcano", 161, Rarity.UNCOMMON, mage.cards.d.DormantVolcano.class)); cards.add(new SetCardInfo("Dragon Mask", 144, Rarity.UNCOMMON, mage.cards.d.DragonMask.class)); + cards.add(new SetCardInfo("Dream Tides", 31, Rarity.UNCOMMON, mage.cards.d.DreamTides.class)); cards.add(new SetCardInfo("Dwarven Vigilantes", 77, Rarity.COMMON, mage.cards.d.DwarvenVigilantes.class)); cards.add(new SetCardInfo("Elephant Grass", 54, Rarity.UNCOMMON, mage.cards.e.ElephantGrass.class)); + cards.add(new SetCardInfo("Elkin Lair", 78, Rarity.RARE, mage.cards.e.ElkinLair.class)); cards.add(new SetCardInfo("Elven Cache", 55, Rarity.COMMON, mage.cards.e.ElvenCache.class)); cards.add(new SetCardInfo("Emerald Charm", 56, Rarity.COMMON, mage.cards.e.EmeraldCharm.class)); cards.add(new SetCardInfo("Equipoise", 103, Rarity.RARE, mage.cards.e.Equipoise.class)); @@ -115,7 +117,7 @@ public class Visions extends ExpansionSet { cards.add(new SetCardInfo("King Cheetah", 60, Rarity.COMMON, mage.cards.k.KingCheetah.class)); cards.add(new SetCardInfo("Knight of Valor", 111, Rarity.COMMON, mage.cards.k.KnightOfValor.class)); cards.add(new SetCardInfo("Knight of the Mists", 36, Rarity.COMMON, mage.cards.k.KnightOfTheMists.class)); - cards.add(new SetCardInfo("Kookus", 85, Rarity.RARE, mage.cards.k.Kookus.class)); + cards.add(new SetCardInfo("Kookus", 86, Rarity.RARE, mage.cards.k.Kookus.class)); cards.add(new SetCardInfo("Lead-Belly Chimera", 148, Rarity.UNCOMMON, mage.cards.l.LeadBellyChimera.class)); cards.add(new SetCardInfo("Lichenthrope", 62, Rarity.RARE, mage.cards.l.Lichenthrope.class)); cards.add(new SetCardInfo("Lightning Cloud", 87, Rarity.RARE, mage.cards.l.LightningCloud.class)); @@ -147,6 +149,7 @@ public class Visions extends ExpansionSet { cards.add(new SetCardInfo("Resistance Fighter", 118, Rarity.COMMON, mage.cards.r.ResistanceFighter.class)); cards.add(new SetCardInfo("Retribution of the Meek", 119, Rarity.RARE, mage.cards.r.RetributionOfTheMeek.class)); cards.add(new SetCardInfo("Righteous Aura", 120, Rarity.COMMON, mage.cards.r.RighteousAura.class)); + cards.add(new SetCardInfo("Righteous War", 134, Rarity.RARE, mage.cards.r.RighteousWar.class)); cards.add(new SetCardInfo("River Boa", 68, Rarity.COMMON, mage.cards.r.RiverBoa.class)); cards.add(new SetCardInfo("Rock Slide", 92, Rarity.COMMON, mage.cards.r.RockSlide.class)); cards.add(new SetCardInfo("Rowen", 69, Rarity.RARE, mage.cards.r.Rowen.class)); @@ -161,6 +164,7 @@ public class Visions extends ExpansionSet { cards.add(new SetCardInfo("Spitting Drake", 95, Rarity.UNCOMMON, mage.cards.s.SpittingDrake.class)); cards.add(new SetCardInfo("Squandered Resources", 137, Rarity.RARE, mage.cards.s.SquanderedResources.class)); cards.add(new SetCardInfo("Stampeding Wildebeests", 71, Rarity.UNCOMMON, mage.cards.s.StampedingWildebeests.class)); + cards.add(new SetCardInfo("Suleiman's Legacy", 138, Rarity.RARE, mage.cards.s.SuleimansLegacy.class)); cards.add(new SetCardInfo("Summer Bloom", 72, Rarity.UNCOMMON, mage.cards.s.SummerBloom.class)); cards.add(new SetCardInfo("Sun Clasp", 121, Rarity.COMMON, mage.cards.s.SunClasp.class)); cards.add(new SetCardInfo("Suq'Ata Assassin", 19, Rarity.UNCOMMON, mage.cards.s.SuqAtaAssassin.class)); diff --git a/Mage.Sets/src/mage/sets/Weatherlight.java b/Mage.Sets/src/mage/sets/Weatherlight.java index 6d2f6558d7..c3832ecdd9 100644 --- a/Mage.Sets/src/mage/sets/Weatherlight.java +++ b/Mage.Sets/src/mage/sets/Weatherlight.java @@ -90,6 +90,7 @@ public class Weatherlight extends ExpansionSet { cards.add(new SetCardInfo("Cone of Flame", 95, Rarity.UNCOMMON, mage.cards.c.ConeOfFlame.class)); cards.add(new SetCardInfo("Debt of Loyalty", 127, Rarity.RARE, mage.cards.d.DebtOfLoyalty.class)); cards.add(new SetCardInfo("Dense Foliage", 66, Rarity.RARE, mage.cards.d.DenseFoliage.class)); + cards.add(new SetCardInfo("Desperate Gambit", 96, Rarity.UNCOMMON, mage.cards.d.DesperateGambit.class)); cards.add(new SetCardInfo("Dingus Staff", 149, Rarity.UNCOMMON, mage.cards.d.DingusStaff.class)); cards.add(new SetCardInfo("Disrupt", 37, Rarity.COMMON, mage.cards.d.Disrupt.class)); cards.add(new SetCardInfo("Doomsday", 8, Rarity.RARE, mage.cards.d.Doomsday.class)); diff --git a/Mage.Tests/src/test/java/org/mage/test/cards/planeswalker/AjaniTest.java b/Mage.Tests/src/test/java/org/mage/test/cards/planeswalker/AjaniTest.java index 7e0b24aa51..6a341d7b9b 100644 --- a/Mage.Tests/src/test/java/org/mage/test/cards/planeswalker/AjaniTest.java +++ b/Mage.Tests/src/test/java/org/mage/test/cards/planeswalker/AjaniTest.java @@ -81,7 +81,7 @@ public class AjaniTest extends CardTestPlayerBase { assertPermanentCount(playerA, "Kor Ally", 2); assertPermanentCount(playerA, "Oath of Gideon", 1); assertPermanentCount(playerA, "Ajani Goldmane", 1); - assertCounterCount("Ajani Goldmane", CounterType.LOYALTY, 6); // 5 + 1 = 5 + assertCounterCount("Ajani Goldmane", CounterType.LOYALTY, 6); // 4 + 1 + 1 = 6 assertLife(playerA, 22); assertLife(playerB, 20); diff --git a/Mage.Tests/src/test/java/org/mage/test/cards/triggers/delayed/NettlingImplTest.java b/Mage.Tests/src/test/java/org/mage/test/cards/triggers/delayed/NettlingImplTest.java new file mode 100644 index 0000000000..c2192aadd1 --- /dev/null +++ b/Mage.Tests/src/test/java/org/mage/test/cards/triggers/delayed/NettlingImplTest.java @@ -0,0 +1,63 @@ +/* + * To change this license header, choose License Headers in Project Properties. + * To change this template file, choose Tools | Templates + * and open the template in the editor. + */ +package org.mage.test.cards.triggers.delayed; + +import mage.constants.PhaseStep; +import mage.constants.Zone; +import org.junit.Test; +import org.mage.test.serverside.base.CardTestPlayerBase; + +/** + * + * @author LevelX2 + */ +public class NettlingImplTest extends CardTestPlayerBase { + + @Test + public void testForcedDidAttack() { + addCard(Zone.BATTLEFIELD, playerB, "Silvercoat Lion", 1); + + // {T}: Choose target non-Wall creature the active player has controlled continuously since the beginning of the turn. That creature attacks this turn if able. If it doesn't, destroy it at the beginning of the next end step. Activate this ability only during an opponent's turn, before attackers are declared. + addCard(Zone.BATTLEFIELD, playerA, "Nettling Imp", 1); + + activateAbility(2, PhaseStep.PRECOMBAT_MAIN, playerA, "{T}: Choose", "Silvercoat Lion"); + + setStopAt(5, PhaseStep.PRECOMBAT_MAIN); + execute(); + + assertPermanentCount(playerA, "Nettling Imp", 1); + assertPermanentCount(playerB, "Silvercoat Lion", 1); + + assertLife(playerA, 18); + assertLife(playerB, 20); + } + + @Test + public void testForcedDidNotAttack() { + addCard(Zone.BATTLEFIELD, playerB, "Silvercoat Lion", 1); + + addCard(Zone.BATTLEFIELD, playerA, "Plains", 2); + // {T}: Choose target non-Wall creature the active player has controlled continuously since the beginning of the turn. That creature attacks this turn if able. If it doesn't, destroy it at the beginning of the next end step. Activate this ability only during an opponent's turn, before attackers are declared. + addCard(Zone.BATTLEFIELD, playerA, "Nettling Imp", 1); + // Tap target creature. + // Draw a card. + addCard(Zone.HAND, playerA, "Pressure Point", 1); // Instant {1}{W} + + activateAbility(2, PhaseStep.PRECOMBAT_MAIN, playerA, "{T}: Choose", "Silvercoat Lion"); + castSpell(2, PhaseStep.BEGIN_COMBAT, playerA, "Pressure Point", "Silvercoat Lion"); + setStopAt(3, PhaseStep.PRECOMBAT_MAIN); + execute(); + + assertPermanentCount(playerA, "Nettling Imp", 1); + assertGraveyardCount(playerA, "Pressure Point", 1); + assertPermanentCount(playerB, "Silvercoat Lion", 0); + + assertHandCount(playerA, 2); + assertLife(playerA, 20); + assertLife(playerB, 20); + } + +} diff --git a/Mage.Tests/src/test/java/org/mage/test/multiplayer/PlayerLeftGameRange1Test.java b/Mage.Tests/src/test/java/org/mage/test/multiplayer/PlayerLeftGameRange1Test.java index 69424f1425..1ac18334e5 100644 --- a/Mage.Tests/src/test/java/org/mage/test/multiplayer/PlayerLeftGameRange1Test.java +++ b/Mage.Tests/src/test/java/org/mage/test/multiplayer/PlayerLeftGameRange1Test.java @@ -1,373 +1,373 @@ -/* - * Copyright 2010 BetaSteward_at_googlemail.com. All rights reserved. - * - * Redistribution and use in source and binary forms, with or without modification, are - * permitted provided that the following conditions are met: - * - * 1. Redistributions of source code must retain the above copyright notice, this list of - * conditions and the following disclaimer. - * - * 2. Redistributions in binary form must reproduce the above copyright notice, this list - * of conditions and the following disclaimer in the documentation and/or other materials - * provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY BetaSteward_at_googlemail.com ``AS IS'' AND ANY EXPRESS OR IMPLIED - * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND - * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BetaSteward_at_googlemail.com OR - * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR - * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR - * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON - * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING - * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF - * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - * - * The views and conclusions contained in the software and documentation are those of the - * authors and should not be interpreted as representing official policies, either expressed - * or implied, of BetaSteward_at_googlemail.com. - */ -package org.mage.test.multiplayer; - -import java.io.FileNotFoundException; -import mage.constants.MultiplayerAttackOption; -import mage.constants.PhaseStep; -import mage.constants.RangeOfInfluence; -import mage.constants.Zone; -import mage.counters.CounterType; -import mage.game.FreeForAll; -import mage.game.Game; -import mage.game.GameException; -import mage.game.permanent.Permanent; -import org.junit.Assert; -import org.junit.Test; -import org.mage.test.serverside.base.CardTestMultiPlayerBase; - -/** - * - * @author LevelX2 - */ -public class PlayerLeftGameRange1Test extends CardTestMultiPlayerBase { - - @Override - protected Game createNewGameAndPlayers() throws GameException, FileNotFoundException { - // Start Life = 2 - Game game = new FreeForAll(MultiplayerAttackOption.MULTIPLE, RangeOfInfluence.ONE, 0, 2); - // Player order: A -> D -> C -> B - playerA = createPlayer(game, playerA, "PlayerA"); - playerB = createPlayer(game, playerB, "PlayerB"); - playerC = createPlayer(game, playerC, "PlayerC"); - playerD = createPlayer(game, playerD, "PlayerD"); - return game; - } - - /** - * Tests Enchantment to control other permanent - */ - @Test - public void TestControlledByEnchantment() { - addCard(Zone.BATTLEFIELD, playerB, "Rootwater Commando"); - - addCard(Zone.BATTLEFIELD, playerA, "Island", 4); - // Enchant creature - // You control enchanted creature. - addCard(Zone.HAND, playerA, "Control Magic"); - - addCard(Zone.BATTLEFIELD, playerC, "Silvercoat Lion"); - - castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Control Magic", "Rootwater Commando"); - - attack(3, playerC, "Silvercoat Lion", playerB); - - setStopAt(3, PhaseStep.POSTCOMBAT_MAIN); - execute(); - - assertLife(playerB, 0); - assertPermanentCount(playerB, 0); - assertPermanentCount(playerA, "Rootwater Commando", 0); - assertGraveyardCount(playerA, "Control Magic", 1); - - } - - /** - * Tests Sorcery to control other players permanent - */ - @Test - public void TestControlledBySorcery() { - addCard(Zone.BATTLEFIELD, playerB, "Rootwater Commando"); - - addCard(Zone.BATTLEFIELD, playerA, "Island", 4); - // Exchange control of target artifact or creature and another target permanent that shares one of those types with it. - // (This effect lasts indefinitely.) - addCard(Zone.HAND, playerA, "Legerdemain"); // Sorcery - addCard(Zone.BATTLEFIELD, playerA, "Wall of Air"); - - addCard(Zone.BATTLEFIELD, playerC, "Silvercoat Lion"); - - castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Legerdemain", "Rootwater Commando^Wall of Air"); - - attack(3, playerC, "Silvercoat Lion", playerB); - - setStopAt(3, PhaseStep.POSTCOMBAT_MAIN); - execute(); - - assertLife(playerB, 0); - assertGraveyardCount(playerA, "Legerdemain", 1); - assertPermanentCount(playerB, 0); - assertPermanentCount(playerA, "Rootwater Commando", 0); // removed from game because player B left - assertPermanentCount(playerB, "Wall of Air", 0); - assertGraveyardCount(playerA, "Wall of Air", 0); - assertPermanentCount(playerA, "Wall of Air", 1); // Returned back to player A - - } - - /** - * Tests Instant to control other permanent - */ - @Test - public void TestOtherPlayerControllsCreature() { - addCard(Zone.BATTLEFIELD, playerB, "Rootwater Commando"); - - addCard(Zone.BATTLEFIELD, playerA, "Mountain", 4); - // Untap target nonlegendary creature and gain control of it until end of turn. That creature gains haste until end of turn. - addCard(Zone.HAND, playerA, "Blind with Anger"); // Instant - - addCard(Zone.BATTLEFIELD, playerC, "Silvercoat Lion"); - - castSpell(2, PhaseStep.PRECOMBAT_MAIN, playerA, "Blind with Anger", "Rootwater Commando"); - - attack(3, playerC, "Silvercoat Lion", playerB); - - setStopAt(3, PhaseStep.POSTCOMBAT_MAIN); - execute(); - - assertLife(playerB, 0); - assertGraveyardCount(playerA, "Blind with Anger", 1); - assertPermanentCount(playerB, 0); - assertPermanentCount(playerA, "Rootwater Commando", 0); // Removed from game because player C left - assertPermanentCount(playerA, "Rootwater Commando", 0); // Returned back to player A - } - - /** - * Xmage throws an error involving an emblem unable to find the initial - * source if it has a proc. To reproduce, a Planeswalker was taken from an - * original player's control, such as using Scrambleverse to shuffle Jace, - * Unraveler of Secrets, to a second player and then the second player uses - * Jace's ability to create an emblem ("Whenever an opponent casts his or - * her first spell each turn, counter that spell."). Then the original - * player concedes the game and removes the Planeswalker. Once it becomes an - * opponent of the original player's turn and that opponent plays a spell, - * Xmage throws an error and rollsback the turn. - * - * I don't have the actual error report on my due to negligence, but what I - * can recollect is that the error message was along the lines of "The - * emblem cannot find the original source. This turn will be rolled back". - * This error message will always appear when an opponent tries to play a - * spell. Player order: A -> D -> C -> B - */ - @Test - public void TestOtherPlayerPlaneswalkerCreatedEmblem() { - // +1: Scry 1, then draw a card. - // -2: Return target creature to its owner's hand. - // -8: You get an emblem with "Whenever an opponent casts his or her first spell each turn, counter that spell." - addCard(Zone.BATTLEFIELD, playerB, "Jace, Unraveler of Secrets"); - addCounters(1, PhaseStep.DRAW, playerB, "Jace, Unraveler of Secrets", CounterType.LOYALTY, 8); - - addCard(Zone.BATTLEFIELD, playerA, "Island", 6); - // Enchant permanent (Target a permanent as you cast this. This card enters the battlefield attached to that permanent.) - // You control enchanted permanent. - addCard(Zone.HAND, playerA, "Confiscate"); // Enchantment Aura - - addCard(Zone.BATTLEFIELD, playerC, "Plains", 2); - addCard(Zone.HAND, playerC, "Silvercoat Lion"); - - addCard(Zone.BATTLEFIELD, playerD, "Plains", 2); - addCard(Zone.HAND, playerD, "Silvercoat Lion"); - - addCard(Zone.BATTLEFIELD, playerC, "Silvercoat Lion"); - - castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Confiscate", "Jace, Unraveler of Secrets"); - activateAbility(1, PhaseStep.POSTCOMBAT_MAIN, playerA, "-8: You get an emblem with"); - - castSpell(2, PhaseStep.PRECOMBAT_MAIN, playerA, "Blind with Anger", "Rootwater Commando"); - - attack(3, playerC, "Silvercoat Lion", playerB); - castSpell(3, PhaseStep.POSTCOMBAT_MAIN, playerC, "Silvercoat Lion"); - - castSpell(5, PhaseStep.PRECOMBAT_MAIN, playerD, "Silvercoat Lion"); - - setStopAt(5, PhaseStep.END_TURN); - execute(); - - assertLife(playerB, 0); - assertPermanentCount(playerB, 0); - assertGraveyardCount(playerA, "Confiscate", 1); - assertPermanentCount(playerA, "Jace, Unraveler of Secrets", 0); // Removed from game because player C left the game - assertEmblemCount(playerA, 1); - assertPermanentCount(playerC, "Silvercoat Lion", 2); // Emblem does not work yet on player C, because range 1 - assertGraveyardCount(playerD, "Silvercoat Lion", 1); // Emblem should counter the spell - } - - /** - * Situation: I attacked an opponent with some creatures with True - * Conviction in play. There were multiple "deals combat damage to a - * player"-triggers (Edric, Spymaster of Trest, Daxos of Meletis et al), - * then the opponent lost the game during the first strike combat - * damage-step . In the second combat damage step the triggers went on the - * stack again, although there was no player being dealt damage (multiplayer - * game, so the game wasn't over yet). I don't think these abilities should - * trigger again here. - */ - @Test - public void TestPlayerDiesDuringFirstStrikeDamageStep() { - // Creatures you control have double strike and lifelink. - addCard(Zone.BATTLEFIELD, playerD, "True Conviction"); - // Whenever a creature deals combat damage to one of your opponents, its controller may draw a card. - addCard(Zone.BATTLEFIELD, playerD, "Edric, Spymaster of Trest"); - addCard(Zone.BATTLEFIELD, playerD, "Dross Crocodile", 8); // Creature 5/1 - - attack(2, playerD, "Dross Crocodile", playerC); - - setStopAt(3, PhaseStep.END_TURN); - execute(); - - assertLife(playerC, -3); - assertLife(playerD, 7); - - assertHandCount(playerD, 2); // 1 (normal draw) + 1 from True Convition - assertPermanentCount(playerC, 0); - - } - - /** - * I've encountered a case today where someone conceded on their turn. The - * remaining phases were went through as normal, but my Luminarch Ascension - * did not trigger during the end step. - */ - // Player order: A -> D -> C -> B - @Test - public void TestTurnEndTrigger() { - addCard(Zone.BATTLEFIELD, playerA, "Plains", 2); - // At the beginning of each opponent's end step, if you didn't lose life this turn, you may put a quest counter on Luminarch Ascension. - // {1}{W}: Create a 4/4 white Angel creature token with flying. Activate this ability only if Luminarch Ascension has four or more quest counters on it.. - addCard(Zone.HAND, playerA, "Luminarch Ascension"); // Enchantment {1}{W} - - addCard(Zone.HAND, playerC, "Lightning Bolt"); - addCard(Zone.BATTLEFIELD, playerC, "Mountain", 1); - - addCard(Zone.HAND, playerD, "Silvercoat Lion"); - addCard(Zone.BATTLEFIELD, playerD, "Plains", 2); - - castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Luminarch Ascension"); - - castSpell(2, PhaseStep.PRECOMBAT_MAIN, playerD, "Silvercoat Lion"); - castSpell(2, PhaseStep.BEGIN_COMBAT, playerC, "Lightning Bolt", playerD); - - setStopAt(3, PhaseStep.PRECOMBAT_MAIN); - execute(); - - assertPermanentCount(playerA, "Luminarch Ascension", 1); - assertGraveyardCount(playerC, "Lightning Bolt", 1); - - assertLife(playerD, -1); - Assert.assertFalse("Player D is no longer in the game", playerD.isInGame()); - - assertCounterCount(playerA, "Luminarch Ascension", CounterType.QUEST, 1); // 1 from turn 2 - } - - @Test - public void TestTurnEndTriggerAfterConcede() { - addCard(Zone.BATTLEFIELD, playerA, "Plains", 2); - // At the beginning of each opponent's end step, if you didn't lose life this turn, you may put a quest counter on Luminarch Ascension. - // {1}{W}: Create a 4/4 white Angel creature token with flying. Activate this ability only if Luminarch Ascension has four or more quest counters on it.. - addCard(Zone.HAND, playerA, "Luminarch Ascension"); // Enchantment {1}{W} - - addCard(Zone.HAND, playerD, "Silvercoat Lion"); - addCard(Zone.BATTLEFIELD, playerD, "Plains", 2); - - castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Luminarch Ascension"); - - castSpell(2, PhaseStep.PRECOMBAT_MAIN, playerD, "Silvercoat Lion"); - - concede(2, PhaseStep.BEGIN_COMBAT, playerD); - - setStopAt(3, PhaseStep.PRECOMBAT_MAIN); - execute(); - - assertPermanentCount(playerA, "Luminarch Ascension", 1); - - assertLife(playerD, 2); - Assert.assertFalse("Player D is no longer in the game", playerD.isInGame()); - - assertCounterCount(playerA, "Luminarch Ascension", CounterType.QUEST, 1); // 1 from turn 2 - } - - /** - * Pithing Needle keeps the named card's abilities disabled even after the - * player controlling the Needle loses the game. - * - * I saw it happen during a Commander game. A player cast Pithing Needle - * targeting my Proteus Staff. After I killed him, I still couldn't activate - * the Staff. - */ - @Test - public void TestPithingNeedle() { - addCard(Zone.BATTLEFIELD, playerA, "Plains", 1); - // As Pithing Needle enters the battlefield, name a card. - // Activated abilities of sources with the chosen name can't be activated unless they're mana abilities. - addCard(Zone.HAND, playerA, "Pithing Needle"); // Artifact {1} - addCard(Zone.BATTLEFIELD, playerA, "Silvercoat Lion", 1); - addCard(Zone.LIBRARY, playerA, "Pillarfield Ox", 1); - - addCard(Zone.BATTLEFIELD, playerD, "Island", 3); - // {2}{U}, {T}: Put target creature on the bottom of its owner's library. That creature's controller reveals cards from the - // top of his or her library until he or she reveals a creature card. The player puts that card onto the battlefield and the - // rest on the bottom of his or her library in any order. Activate this ability only any time you could cast a sorcery. - addCard(Zone.BATTLEFIELD, playerD, "Proteus Staff", 1); - - addCard(Zone.BATTLEFIELD, playerD, "Eager Cadet", 1); - addCard(Zone.LIBRARY, playerD, "Storm Crow", 2); - - addCard(Zone.BATTLEFIELD, playerC, "Island", 3); - addCard(Zone.BATTLEFIELD, playerC, "Proteus Staff", 1); - addCard(Zone.BATTLEFIELD, playerC, "Wall of Air", 1); - addCard(Zone.LIBRARY, playerC, "Wind Drake", 2); - - addCard(Zone.BATTLEFIELD, playerB, "Island", 3); - addCard(Zone.BATTLEFIELD, playerB, "Proteus Staff", 1); - - skipInitShuffling(); - - castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Pithing Needle"); - setChoice(playerA, "Proteus Staff"); - - activateAbility(2, PhaseStep.PRECOMBAT_MAIN, playerD, "{2}{U}", "Silvercoat Lion"); // not allowed - - activateAbility(3, PhaseStep.PRECOMBAT_MAIN, playerC, "{2}{U}", "Eager Cadet"); // allowed because Needle out of range - concede(3, PhaseStep.POSTCOMBAT_MAIN, playerA); - - activateAbility(4, PhaseStep.PRECOMBAT_MAIN, playerB, "{2}{U}", "Wall of Air"); // allowed because Needle lost game - - setStopAt(4, PhaseStep.POSTCOMBAT_MAIN); - execute(); - - assertPermanentCount(playerA, 0); - - assertLife(playerA, 2); - Assert.assertFalse("Player A is no longer in the game", playerA.isInGame()); - - Permanent staffPlayerD = getPermanent("Proteus Staff", playerD); - Assert.assertFalse("Staff of player D could not be used", staffPlayerD.isTapped()); - - assertPermanentCount(playerD, "Eager Cadet", 0); - assertPermanentCount(playerD, "Storm Crow", 1); - - Permanent staffPlayerC = getPermanent("Proteus Staff", playerC); - Assert.assertTrue("Staff of player C could be used", staffPlayerC.isTapped()); - - assertPermanentCount(playerC, "Wall of Air", 0); - assertPermanentCount(playerC, "Wind Drake", 1); - - Permanent staffPlayerB = getPermanent("Proteus Staff", playerB); - Assert.assertTrue("Staff of player B could be used", staffPlayerB.isTapped()); - - } -} +/* + * Copyright 2010 BetaSteward_at_googlemail.com. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are + * permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this list of + * conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, this list + * of conditions and the following disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY BetaSteward_at_googlemail.com ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BetaSteward_at_googlemail.com OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * The views and conclusions contained in the software and documentation are those of the + * authors and should not be interpreted as representing official policies, either expressed + * or implied, of BetaSteward_at_googlemail.com. + */ +package org.mage.test.multiplayer; + +import java.io.FileNotFoundException; +import mage.constants.MultiplayerAttackOption; +import mage.constants.PhaseStep; +import mage.constants.RangeOfInfluence; +import mage.constants.Zone; +import mage.counters.CounterType; +import mage.game.FreeForAll; +import mage.game.Game; +import mage.game.GameException; +import mage.game.permanent.Permanent; +import org.junit.Assert; +import org.junit.Test; +import org.mage.test.serverside.base.CardTestMultiPlayerBase; + +/** + * + * @author LevelX2 + */ +public class PlayerLeftGameRange1Test extends CardTestMultiPlayerBase { + + @Override + protected Game createNewGameAndPlayers() throws GameException, FileNotFoundException { + // Start Life = 2 + Game game = new FreeForAll(MultiplayerAttackOption.MULTIPLE, RangeOfInfluence.ONE, 0, 2); + // Player order: A -> D -> C -> B + playerA = createPlayer(game, playerA, "PlayerA"); + playerB = createPlayer(game, playerB, "PlayerB"); + playerC = createPlayer(game, playerC, "PlayerC"); + playerD = createPlayer(game, playerD, "PlayerD"); + return game; + } + + /** + * Tests Enchantment to control other permanent + */ + @Test + public void TestControlledByEnchantment() { + addCard(Zone.BATTLEFIELD, playerB, "Rootwater Commando"); + + addCard(Zone.BATTLEFIELD, playerA, "Island", 4); + // Enchant creature + // You control enchanted creature. + addCard(Zone.HAND, playerA, "Control Magic"); + + addCard(Zone.BATTLEFIELD, playerC, "Silvercoat Lion"); + + castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Control Magic", "Rootwater Commando"); + + attack(3, playerC, "Silvercoat Lion", playerB); + + setStopAt(3, PhaseStep.POSTCOMBAT_MAIN); + execute(); + + assertLife(playerB, 0); + assertPermanentCount(playerB, 0); + assertPermanentCount(playerA, "Rootwater Commando", 0); + assertGraveyardCount(playerA, "Control Magic", 1); + + } + + /** + * Tests Sorcery to control other players permanent + */ + @Test + public void TestControlledBySorcery() { + addCard(Zone.BATTLEFIELD, playerB, "Rootwater Commando"); + + addCard(Zone.BATTLEFIELD, playerA, "Island", 4); + // Exchange control of target artifact or creature and another target permanent that shares one of those types with it. + // (This effect lasts indefinitely.) + addCard(Zone.HAND, playerA, "Legerdemain"); // Sorcery + addCard(Zone.BATTLEFIELD, playerA, "Wall of Air"); + + addCard(Zone.BATTLEFIELD, playerC, "Silvercoat Lion"); + + castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Legerdemain", "Rootwater Commando^Wall of Air"); + + attack(3, playerC, "Silvercoat Lion", playerB); + + setStopAt(3, PhaseStep.POSTCOMBAT_MAIN); + execute(); + + assertLife(playerB, 0); + assertGraveyardCount(playerA, "Legerdemain", 1); + assertPermanentCount(playerB, 0); + assertPermanentCount(playerA, "Rootwater Commando", 0); // removed from game because player B left + assertPermanentCount(playerB, "Wall of Air", 0); + assertGraveyardCount(playerA, "Wall of Air", 0); + assertPermanentCount(playerA, "Wall of Air", 1); // Returned back to player A + + } + + /** + * Tests Instant to control other permanent + */ + @Test + public void TestOtherPlayerControllsCreature() { + addCard(Zone.BATTLEFIELD, playerB, "Rootwater Commando"); + + addCard(Zone.BATTLEFIELD, playerA, "Mountain", 4); + // Untap target nonlegendary creature and gain control of it until end of turn. That creature gains haste until end of turn. + addCard(Zone.HAND, playerA, "Blind with Anger"); // Instant + + addCard(Zone.BATTLEFIELD, playerC, "Silvercoat Lion"); + + castSpell(2, PhaseStep.PRECOMBAT_MAIN, playerA, "Blind with Anger", "Rootwater Commando"); + + attack(3, playerC, "Silvercoat Lion", playerB); + + setStopAt(3, PhaseStep.POSTCOMBAT_MAIN); + execute(); + + assertLife(playerB, 0); + assertGraveyardCount(playerA, "Blind with Anger", 1); + assertPermanentCount(playerB, 0); + assertPermanentCount(playerA, "Rootwater Commando", 0); // Removed from game because player C left + assertPermanentCount(playerA, "Rootwater Commando", 0); // Returned back to player A + } + + /** + * Xmage throws an error involving an emblem unable to find the initial + * source if it has a proc. To reproduce, a Planeswalker was taken from an + * original player's control, such as using Scrambleverse to shuffle Jace, + * Unraveler of Secrets, to a second player and then the second player uses + * Jace's ability to create an emblem ("Whenever an opponent casts his or + * her first spell each turn, counter that spell."). Then the original + * player concedes the game and removes the Planeswalker. Once it becomes an + * opponent of the original player's turn and that opponent plays a spell, + * Xmage throws an error and rollsback the turn. + * + * I don't have the actual error report on my due to negligence, but what I + * can recollect is that the error message was along the lines of "The + * emblem cannot find the original source. This turn will be rolled back". + * This error message will always appear when an opponent tries to play a + * spell. Player order: A -> D -> C -> B + */ + @Test + public void TestOtherPlayerPlaneswalkerCreatedEmblem() { + // +1: Scry 1, then draw a card. + // -2: Return target creature to its owner's hand. + // -8: You get an emblem with "Whenever an opponent casts his or her first spell each turn, counter that spell." + addCard(Zone.BATTLEFIELD, playerB, "Jace, Unraveler of Secrets"); + addCounters(1, PhaseStep.DRAW, playerB, "Jace, Unraveler of Secrets", CounterType.LOYALTY, 8); + + addCard(Zone.BATTLEFIELD, playerA, "Island", 6); + // Enchant permanent (Target a permanent as you cast this. This card enters the battlefield attached to that permanent.) + // You control enchanted permanent. + addCard(Zone.HAND, playerA, "Confiscate"); // Enchantment Aura + + addCard(Zone.BATTLEFIELD, playerC, "Plains", 2); + addCard(Zone.HAND, playerC, "Silvercoat Lion"); + + addCard(Zone.BATTLEFIELD, playerD, "Plains", 2); + addCard(Zone.HAND, playerD, "Silvercoat Lion"); + + addCard(Zone.BATTLEFIELD, playerC, "Silvercoat Lion"); + + castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Confiscate", "Jace, Unraveler of Secrets"); + activateAbility(1, PhaseStep.POSTCOMBAT_MAIN, playerA, "-8: You get an emblem with"); + + castSpell(2, PhaseStep.PRECOMBAT_MAIN, playerA, "Blind with Anger", "Rootwater Commando"); + + attack(3, playerC, "Silvercoat Lion", playerB); + castSpell(3, PhaseStep.POSTCOMBAT_MAIN, playerC, "Silvercoat Lion"); + + castSpell(5, PhaseStep.PRECOMBAT_MAIN, playerD, "Silvercoat Lion"); + + setStopAt(5, PhaseStep.END_TURN); + execute(); + + assertLife(playerB, 0); + assertPermanentCount(playerB, 0); + assertGraveyardCount(playerA, "Confiscate", 1); + assertPermanentCount(playerA, "Jace, Unraveler of Secrets", 0); // Removed from game because player C left the game + assertEmblemCount(playerA, 1); + assertPermanentCount(playerC, "Silvercoat Lion", 2); // Emblem does not work yet on player C, because range 1 + assertGraveyardCount(playerD, "Silvercoat Lion", 1); // Emblem should counter the spell + } + + /** + * Situation: I attacked an opponent with some creatures with True + * Conviction in play. There were multiple "deals combat damage to a + * player"-triggers (Edric, Spymaster of Trest, Daxos of Meletis et al), + * then the opponent lost the game during the first strike combat + * damage-step . In the second combat damage step the triggers went on the + * stack again, although there was no player being dealt damage (multiplayer + * game, so the game wasn't over yet). I don't think these abilities should + * trigger again here. + */ + @Test + public void TestPlayerDiesDuringFirstStrikeDamageStep() { + // Creatures you control have double strike and lifelink. + addCard(Zone.BATTLEFIELD, playerD, "True Conviction"); + // Whenever a creature deals combat damage to one of your opponents, its controller may draw a card. + addCard(Zone.BATTLEFIELD, playerD, "Edric, Spymaster of Trest"); + addCard(Zone.BATTLEFIELD, playerD, "Dross Crocodile", 8); // Creature 5/1 + + attack(2, playerD, "Dross Crocodile", playerC); + + setStopAt(3, PhaseStep.END_TURN); + execute(); + + assertLife(playerC, -3); + assertLife(playerD, 7); + + assertHandCount(playerD, 2); // 1 (normal draw) + 1 from True Convition + assertPermanentCount(playerC, 0); + + } + + /** + * I've encountered a case today where someone conceded on their turn. The + * remaining phases were went through as normal, but my Luminarch Ascension + * did not trigger during the end step. + */ + // Player order: A -> D -> C -> B + @Test + public void TestTurnEndTrigger() { + addCard(Zone.BATTLEFIELD, playerA, "Plains", 2); + // At the beginning of each opponent's end step, if you didn't lose life this turn, you may put a quest counter on Luminarch Ascension. + // {1}{W}: Create a 4/4 white Angel creature token with flying. Activate this ability only if Luminarch Ascension has four or more quest counters on it.. + addCard(Zone.HAND, playerA, "Luminarch Ascension"); // Enchantment {1}{W} + + addCard(Zone.HAND, playerC, "Lightning Bolt"); + addCard(Zone.BATTLEFIELD, playerC, "Mountain", 1); + + addCard(Zone.HAND, playerD, "Silvercoat Lion"); + addCard(Zone.BATTLEFIELD, playerD, "Plains", 2); + + castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Luminarch Ascension"); + + castSpell(2, PhaseStep.PRECOMBAT_MAIN, playerD, "Silvercoat Lion"); + castSpell(2, PhaseStep.BEGIN_COMBAT, playerC, "Lightning Bolt", playerD); + + setStopAt(3, PhaseStep.PRECOMBAT_MAIN); + execute(); + + assertPermanentCount(playerA, "Luminarch Ascension", 1); + assertGraveyardCount(playerC, "Lightning Bolt", 1); + + assertLife(playerD, -1); + Assert.assertFalse("Player D is no longer in the game", playerD.isInGame()); + + assertCounterCount(playerA, "Luminarch Ascension", CounterType.QUEST, 1); // 1 from turn 2 + } + + @Test + public void TestTurnEndTriggerAfterConcede() { + addCard(Zone.BATTLEFIELD, playerA, "Plains", 2); + // At the beginning of each opponent's end step, if you didn't lose life this turn, you may put a quest counter on Luminarch Ascension. + // {1}{W}: Create a 4/4 white Angel creature token with flying. Activate this ability only if Luminarch Ascension has four or more quest counters on it.. + addCard(Zone.HAND, playerA, "Luminarch Ascension"); // Enchantment {1}{W} + + addCard(Zone.HAND, playerD, "Silvercoat Lion"); + addCard(Zone.BATTLEFIELD, playerD, "Plains", 2); + + castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Luminarch Ascension"); + + castSpell(2, PhaseStep.PRECOMBAT_MAIN, playerD, "Silvercoat Lion"); + + concede(2, PhaseStep.BEGIN_COMBAT, playerD); + + setStopAt(3, PhaseStep.PRECOMBAT_MAIN); + execute(); + + assertPermanentCount(playerA, "Luminarch Ascension", 1); + + assertLife(playerD, 2); + Assert.assertFalse("Player D is no longer in the game", playerD.isInGame()); + + assertCounterCount(playerA, "Luminarch Ascension", CounterType.QUEST, 1); // 1 from turn 2 + } + + /** + * Pithing Needle keeps the named card's abilities disabled even after the + * player controlling the Needle loses the game. + * + * I saw it happen during a Commander game. A player cast Pithing Needle + * targeting my Proteus Staff. After I killed him, I still couldn't activate + * the Staff. + */ + @Test + public void TestPithingNeedle() { + addCard(Zone.BATTLEFIELD, playerA, "Plains", 1); + // As Pithing Needle enters the battlefield, name a card. + // Activated abilities of sources with the chosen name can't be activated unless they're mana abilities. + addCard(Zone.HAND, playerA, "Pithing Needle"); // Artifact {1} + addCard(Zone.BATTLEFIELD, playerA, "Silvercoat Lion", 1); + addCard(Zone.LIBRARY, playerA, "Pillarfield Ox", 1); + + addCard(Zone.BATTLEFIELD, playerD, "Island", 3); + // {2}{U}, {T}: Put target creature on the bottom of its owner's library. That creature's controller reveals cards from the + // top of his or her library until he or she reveals a creature card. The player puts that card onto the battlefield and the + // rest on the bottom of his or her library in any order. Activate this ability only any time you could cast a sorcery. + addCard(Zone.BATTLEFIELD, playerD, "Proteus Staff", 1); + + addCard(Zone.BATTLEFIELD, playerD, "Eager Cadet", 1); + addCard(Zone.LIBRARY, playerD, "Storm Crow", 2); + + addCard(Zone.BATTLEFIELD, playerC, "Island", 3); + addCard(Zone.BATTLEFIELD, playerC, "Proteus Staff", 1); + addCard(Zone.BATTLEFIELD, playerC, "Wall of Air", 1); + addCard(Zone.LIBRARY, playerC, "Wind Drake", 2); + + addCard(Zone.BATTLEFIELD, playerB, "Island", 3); + addCard(Zone.BATTLEFIELD, playerB, "Proteus Staff", 1); + + skipInitShuffling(); + + castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Pithing Needle"); + setChoice(playerA, "Proteus Staff"); + + activateAbility(2, PhaseStep.PRECOMBAT_MAIN, playerD, "{2}{U}", "Silvercoat Lion"); // not allowed + + activateAbility(3, PhaseStep.PRECOMBAT_MAIN, playerC, "{2}{U}", "Eager Cadet"); // allowed because Needle out of range + concede(3, PhaseStep.POSTCOMBAT_MAIN, playerA); + + activateAbility(4, PhaseStep.PRECOMBAT_MAIN, playerB, "{2}{U}", "Wall of Air"); // allowed because Needle lost game + + setStopAt(4, PhaseStep.POSTCOMBAT_MAIN); + execute(); + + assertLife(playerA, 2); + Assert.assertFalse("Player A is no longer in the game", playerA.isInGame()); + + assertPermanentCount(playerA, 0); + + Permanent staffPlayerD = getPermanent("Proteus Staff", playerD); + Assert.assertFalse("Staff of player D could not be used", staffPlayerD.isTapped()); + + assertPermanentCount(playerD, "Eager Cadet", 0); + assertPermanentCount(playerD, "Storm Crow", 1); + + Permanent staffPlayerC = getPermanent("Proteus Staff", playerC); + Assert.assertTrue("Staff of player C could be used", staffPlayerC.isTapped()); + + assertPermanentCount(playerC, "Wall of Air", 0); + assertPermanentCount(playerC, "Wind Drake", 1); + + Permanent staffPlayerB = getPermanent("Proteus Staff", playerB); + Assert.assertTrue("Staff of player B could be used", staffPlayerB.isTapped()); + + } +} 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 74a9d87399..595a54d6e6 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 @@ -57,6 +57,7 @@ import mage.filter.predicate.Predicates; import mage.filter.predicate.mageobject.NamePredicate; import mage.filter.predicate.permanent.SummoningSicknessPredicate; import mage.game.Game; +import mage.game.GameImpl; import mage.game.Graveyard; import mage.game.Table; import mage.game.combat.CombatGroup; @@ -519,6 +520,7 @@ public class TestPlayer implements Player { } if (groups[0].equals("Concede")) { game.concede(getId()); + ((GameImpl) game).checkConcede(); actions.remove(action); } } @@ -1182,6 +1184,11 @@ public class TestPlayer implements Player { computerPlayer.abort(); } + @Override + public void signalPlayerConcede() { + computerPlayer.signalPlayerConcede(); + } + @Override public void abortReset() { computerPlayer.abortReset(); 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 54fdb7ac45..e082f0a0b9 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 @@ -27,6 +27,8 @@ */ package org.mage.test.stub; +import java.io.Serializable; +import java.util.*; import mage.MageObject; import mage.abilities.*; import mage.abilities.costs.AlternativeSourceCosts; @@ -62,9 +64,6 @@ import mage.target.TargetAmount; import mage.target.TargetCard; import mage.target.common.TargetCardInLibrary; -import java.io.Serializable; -import java.util.*; - /** * * @author Quercitron @@ -702,6 +701,11 @@ public class PlayerStub implements Player { } + @Override + public void signalPlayerConcede() { + + } + @Override public void abortReset() { diff --git a/Mage/src/main/java/mage/abilities/common/delayed/AtTheBeginOfNextEndStepDelayedTriggeredAbility.java b/Mage/src/main/java/mage/abilities/common/delayed/AtTheBeginOfNextEndStepDelayedTriggeredAbility.java index 4f16e72e8d..3b533fa098 100644 --- a/Mage/src/main/java/mage/abilities/common/delayed/AtTheBeginOfNextEndStepDelayedTriggeredAbility.java +++ b/Mage/src/main/java/mage/abilities/common/delayed/AtTheBeginOfNextEndStepDelayedTriggeredAbility.java @@ -28,7 +28,9 @@ package mage.abilities.common.delayed; import mage.abilities.DelayedTriggeredAbility; +import mage.abilities.condition.Condition; import mage.abilities.effects.Effect; +import mage.constants.Duration; import mage.constants.TargetController; import mage.constants.Zone; import mage.game.Game; @@ -42,6 +44,7 @@ import mage.game.permanent.Permanent; public class AtTheBeginOfNextEndStepDelayedTriggeredAbility extends DelayedTriggeredAbility { private TargetController targetController; + private Condition condition; public AtTheBeginOfNextEndStepDelayedTriggeredAbility(Effect effect) { this(effect, TargetController.ANY); @@ -52,14 +55,20 @@ public class AtTheBeginOfNextEndStepDelayedTriggeredAbility extends DelayedTrigg } public AtTheBeginOfNextEndStepDelayedTriggeredAbility(Zone zone, Effect effect, TargetController targetController) { - super(effect); + this(zone, effect, targetController, null); + } + + public AtTheBeginOfNextEndStepDelayedTriggeredAbility(Zone zone, Effect effect, TargetController targetController, Condition condition) { + super(effect, Duration.EndOfTurn); this.zone = zone; this.targetController = targetController; + this.condition = condition; } public AtTheBeginOfNextEndStepDelayedTriggeredAbility(final AtTheBeginOfNextEndStepDelayedTriggeredAbility ability) { super(ability); this.targetController = ability.targetController; + this.condition = ability.condition; } @Override @@ -69,27 +78,34 @@ public class AtTheBeginOfNextEndStepDelayedTriggeredAbility extends DelayedTrigg @Override public boolean checkTrigger(GameEvent event, Game game) { + boolean correctEndPhase = false; switch (targetController) { case ANY: - return true; + correctEndPhase = true; + break; case YOU: - return event.getPlayerId().equals(this.controllerId); - + correctEndPhase = event.getPlayerId().equals(this.controllerId); + break; case OPPONENT: if (game.getPlayer(this.getControllerId()).hasOpponent(event.getPlayerId(), game)) { - return true; + correctEndPhase = true; } break; - case CONTROLLER_ATTACHED_TO: Permanent attachment = game.getPermanent(sourceId); if (attachment != null && attachment.getAttachedTo() != null) { Permanent attachedTo = game.getPermanent(attachment.getAttachedTo()); if (attachedTo != null && attachedTo.getControllerId().equals(event.getPlayerId())) { - return true; + correctEndPhase = true; } } } + if (correctEndPhase) { + if (condition != null && !condition.apply(game, this)) { + return false; + } + return true; + } return false; } diff --git a/Mage/src/main/java/mage/abilities/condition/common/AttackedThisStepCondition.java b/Mage/src/main/java/mage/abilities/condition/common/AttackedThisStepCondition.java new file mode 100644 index 0000000000..7ecc8fb53c --- /dev/null +++ b/Mage/src/main/java/mage/abilities/condition/common/AttackedThisStepCondition.java @@ -0,0 +1,52 @@ +/* + * Copyright 2010 BetaSteward_at_googlemail.com. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are + * permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this list of + * conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, this list + * of conditions and the following disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY BetaSteward_at_googlemail.com ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BetaSteward_at_googlemail.com OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * The views and conclusions contained in the software and documentation are those of the + * authors and should not be interpreted as representing official policies, either expressed + * or implied, of BetaSteward_at_googlemail.com. + */ +package mage.abilities.condition.common; + +import mage.abilities.Ability; +import mage.abilities.condition.Condition; +import mage.game.Game; +import mage.watchers.common.PlayerAttackedStepWatcher; + +/** + * @author LevelX2 + */ +public enum AttackedThisStepCondition implements Condition { + + instance; + + @Override + public boolean apply(Game game, Ability source) { + PlayerAttackedStepWatcher watcher = (PlayerAttackedStepWatcher) game.getState().getWatchers().get(PlayerAttackedStepWatcher.class.getSimpleName()); + return watcher != null + && watcher.getNumberAttackingCurrentStep(source.getControllerId()) > 0; + } + + public String toString() { + return "during the declare attackers step and only if you've been attacked this step."; + } +} diff --git a/Mage/src/main/java/mage/abilities/condition/common/YouGainedLifeCondition.java b/Mage/src/main/java/mage/abilities/condition/common/YouGainedLifeCondition.java index f19ff14b8e..a33a4d9bd0 100644 --- a/Mage/src/main/java/mage/abilities/condition/common/YouGainedLifeCondition.java +++ b/Mage/src/main/java/mage/abilities/condition/common/YouGainedLifeCondition.java @@ -27,7 +27,6 @@ public class YouGainedLifeCondition extends IntCompareCondition { @Override public String toString() { - return String.format("if you gained %s or more life this turn ", value); + return String.format("if you gained %s or more life this turn ", value + 1); } } - diff --git a/Mage/src/main/java/mage/abilities/effects/common/DoUnlessAnyPlayerPaysManaEffect.java b/Mage/src/main/java/mage/abilities/effects/common/DoUnlessAnyPlayerPaysManaEffect.java new file mode 100644 index 0000000000..2917742425 --- /dev/null +++ b/Mage/src/main/java/mage/abilities/effects/common/DoUnlessAnyPlayerPaysManaEffect.java @@ -0,0 +1,94 @@ +/* + * To change this license header, choose License Headers in Project Properties. + * To change this template file, choose Tools | Templates + * and open the template in the editor. + */ +package mage.abilities.effects.common; + +import java.util.UUID; +import mage.MageObject; +import mage.Mana; +import mage.abilities.Ability; +import mage.abilities.Mode; +import mage.abilities.costs.Cost; +import mage.constants.Outcome; +import mage.game.Game; +import mage.players.Player; +import mage.util.CardUtil; + +/** + * + * @author LevelX2 + */ +public class DoUnlessAnyPlayerPaysManaEffect extends ManaEffect { + + private final ManaEffect manaEffect; + private final Cost cost; + private final String chooseUseText; + + public DoUnlessAnyPlayerPaysManaEffect(ManaEffect effect, Cost cost, String chooseUseText) { + this.manaEffect = effect; + this.cost = cost; + this.chooseUseText = chooseUseText; + } + + public DoUnlessAnyPlayerPaysManaEffect(final DoUnlessAnyPlayerPaysManaEffect effect) { + super(effect); + this.manaEffect = (ManaEffect) effect.manaEffect.copy(); + this.cost = effect.cost.copy(); + this.chooseUseText = effect.chooseUseText; + } + + @Override + public boolean apply(Game game, Ability source) { + Player controller = game.getPlayer(source.getControllerId()); + MageObject sourceObject = game.getObject(source.getSourceId()); + if (controller != null && sourceObject != null) { + String message = CardUtil.replaceSourceName(chooseUseText, sourceObject.getName()); + boolean result = true; + boolean doEffect = true; + // check if any player is willing to pay + for (UUID playerId : game.getState().getPlayersInRange(controller.getId(), game)) { + Player player = game.getPlayer(playerId); + if (player != null && cost.canPay(source, source.getSourceId(), player.getId(), game) && player.chooseUse(Outcome.Detriment, message, source, game)) { + cost.clearPaid(); + if (cost.pay(source, game, source.getSourceId(), player.getId(), false, null)) { + if (!game.isSimulation()) { + game.informPlayers(player.getLogName() + " pays the cost to prevent the effect"); + } + doEffect = false; + } + } + } + // do the effects if nobody paid + if (doEffect) { + return manaEffect.apply(game, source); + } + return result; + } + return false; + } + + protected Player getPayingPlayer(Game game, Ability source) { + return game.getPlayer(source.getControllerId()); + } + + @Override + public String getText(Mode mode) { + if (!staticText.isEmpty()) { + return staticText; + } + return manaEffect.getText(mode) + " unless any player pays " + cost.getText(); + } + + @Override + public Mana getMana(Game game, Ability source) { + return manaEffect.getMana(game, source); + } + + @Override + public ManaEffect copy() { + return new DoUnlessAnyPlayerPaysManaEffect(this); + } + +} diff --git a/Mage/src/main/java/mage/abilities/effects/common/LookLibraryAndPickControllerEffect.java b/Mage/src/main/java/mage/abilities/effects/common/LookLibraryAndPickControllerEffect.java index 5a93cbae46..99958198d3 100644 --- a/Mage/src/main/java/mage/abilities/effects/common/LookLibraryAndPickControllerEffect.java +++ b/Mage/src/main/java/mage/abilities/effects/common/LookLibraryAndPickControllerEffect.java @@ -270,7 +270,7 @@ public class LookLibraryAndPickControllerEffect extends LookLibraryControllerEff } else { sb.append('P'); } - sb.append("put ").append(filter.getMessage()).append(" from among them onto the "); + sb.append("ut ").append(filter.getMessage()).append(" from among them onto the "); } else { sb.append(". Put "); if (numberToPick.calculate(null, null, this) > 1) { diff --git a/Mage/src/main/java/mage/abilities/effects/common/PhaseOutAllEffect.java b/Mage/src/main/java/mage/abilities/effects/common/PhaseOutAllEffect.java new file mode 100644 index 0000000000..0ac346eda2 --- /dev/null +++ b/Mage/src/main/java/mage/abilities/effects/common/PhaseOutAllEffect.java @@ -0,0 +1,85 @@ +/* + * Copyright 2010 BetaSteward_at_googlemail.com. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are + * permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this list of + * conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, this list + * of conditions and the following disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY BetaSteward_at_googlemail.com ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BetaSteward_at_googlemail.com OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * The views and conclusions contained in the software and documentation are those of the + * authors and should not be interpreted as representing official policies, either expressed + * or implied, of BetaSteward_at_googlemail.com. + */ +package mage.abilities.effects.common; + +import java.util.List; +import java.util.UUID; +import mage.abilities.Ability; +import mage.abilities.effects.OneShotEffect; +import mage.constants.Outcome; +import mage.game.Game; +import mage.game.permanent.Permanent; + +/** + * This class should only be used within the application of another effect + * + * @author TheElk801 + */ +public class PhaseOutAllEffect extends OneShotEffect { + + private final List idList; + + public PhaseOutAllEffect(List idList) { + super(Outcome.Neutral); + this.idList = idList; + } + + public PhaseOutAllEffect(final PhaseOutAllEffect effect) { + super(effect); + this.idList = effect.idList; + } + + @Override + public PhaseOutAllEffect copy() { + return new PhaseOutAllEffect(this); + } + + @Override + public boolean apply(Game game, Ability source) { + // First we phase out everything that isn't attached to anything + // Anything attached to these permanents will phase out indirectly + for (UUID permanentId : idList) { + Permanent permanent = game.getPermanent(permanentId); + if (permanent != null) { + Permanent attachedTo = game.getPermanent(permanent.getAttachedTo()); + if (attachedTo == null) { + permanent.phaseOut(game); + } + } + } + // Once this is done, we'll have permanents which are attached to something but haven't phased out + // These will be phased out directly + for (UUID permanentId : idList) { + Permanent permanent = game.getPermanent(permanentId); + if (permanent != null && permanent.isPhasedIn()) { + permanent.phaseOut(game); + } + } + return true; + } +} diff --git a/Mage/src/main/java/mage/abilities/effects/common/RedirectDamageFromSourceToTargetEffect.java b/Mage/src/main/java/mage/abilities/effects/common/RedirectDamageFromSourceToTargetEffect.java index 9a1e32f7e0..bff0d3ccee 100644 --- a/Mage/src/main/java/mage/abilities/effects/common/RedirectDamageFromSourceToTargetEffect.java +++ b/Mage/src/main/java/mage/abilities/effects/common/RedirectDamageFromSourceToTargetEffect.java @@ -10,6 +10,7 @@ import mage.abilities.effects.RedirectionEffect; import mage.constants.Duration; import mage.game.Game; import mage.game.events.GameEvent; +import mage.game.permanent.Permanent; /** * @@ -33,9 +34,14 @@ public class RedirectDamageFromSourceToTargetEffect extends RedirectionEffect { @Override public boolean applies(GameEvent event, Ability source, Game game) { - if (event.getTargetId().equals(source.getSourceId())) { - this.redirectTarget = source.getTargets().get(0); - return true; + Permanent permanent = game.getBattlefield().getPermanent(source.getSourceId()); + if (permanent != null) { + if (event.getTargetId().equals(source.getSourceId())) { + if (getTargetPointer().getFirst(game, source) != null) { + this.redirectTarget = source.getTargets().get(0); + return true; + } + } } return false; } diff --git a/Mage/src/main/java/mage/abilities/effects/common/combat/CantAttackSourceEffect.java b/Mage/src/main/java/mage/abilities/effects/common/combat/CantAttackSourceEffect.java new file mode 100644 index 0000000000..c84508d18a --- /dev/null +++ b/Mage/src/main/java/mage/abilities/effects/common/combat/CantAttackSourceEffect.java @@ -0,0 +1,70 @@ +/* + * Copyright 2010 BetaSteward_at_googlemail.com. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are + * permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this list of + * conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, this list + * of conditions and the following disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY BetaSteward_at_googlemail.com ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BetaSteward_at_googlemail.com OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * The views and conclusions contained in the software and documentation are those of the + * authors and should not be interpreted as representing official policies, either expressed + * or implied, of BetaSteward_at_googlemail.com. + */ + +package mage.abilities.effects.common.combat; + +import mage.constants.Duration; +import mage.abilities.Ability; +import mage.abilities.effects.RestrictionEffect; +import mage.game.Game; +import mage.game.permanent.Permanent; + +/** + * + * @author BetaSteward_at_googlemail.com & L_J + */ +public class CantAttackSourceEffect extends RestrictionEffect { + + public CantAttackSourceEffect(Duration duration) { + super(duration); + this.staticText = "{this} can't attack"; + } + + public CantAttackSourceEffect(final CantAttackSourceEffect effect) { + super(effect); + } + + @Override + public boolean applies(Permanent permanent, Ability source, Game game) { + if (permanent.getId().equals(source.getSourceId())) { + return true; + } + return false; + } + + @Override + public boolean canAttack(Game game) { + return false; + } + + @Override + public CantAttackSourceEffect copy() { + return new CantAttackSourceEffect(this); + } + +} diff --git a/Mage/src/main/java/mage/abilities/effects/common/combat/GoadTargetEffect.java b/Mage/src/main/java/mage/abilities/effects/common/combat/GoadTargetEffect.java index 5b5a7b55dd..093693bb29 100644 --- a/Mage/src/main/java/mage/abilities/effects/common/combat/GoadTargetEffect.java +++ b/Mage/src/main/java/mage/abilities/effects/common/combat/GoadTargetEffect.java @@ -74,7 +74,7 @@ public class GoadTargetEffect extends OneShotEffect { effect = new CantAttackYouEffect(Duration.UntilYourNextTurn); effect.setTargetPointer(new FixedTarget(getTargetPointer().getFirst(game, source))); game.addEffect(effect, source); - game.informPlayers(controller.getLogName() + " is goating " + targetCreature.getLogName()); + game.informPlayers(controller.getLogName() + " is goading " + targetCreature.getLogName()); } return true; } diff --git a/Mage/src/main/java/mage/abilities/keyword/MeleeAbility.java b/Mage/src/main/java/mage/abilities/keyword/MeleeAbility.java index 04d14eff93..6fc22f8803 100644 --- a/Mage/src/main/java/mage/abilities/keyword/MeleeAbility.java +++ b/Mage/src/main/java/mage/abilities/keyword/MeleeAbility.java @@ -47,7 +47,7 @@ import mage.watchers.Watcher; * * @author emerald000 */ -public class MeleeAbility extends AttacksTriggeredAbility { +public class MeleeAbility extends AttacksTriggeredAbility { public MeleeAbility() { super(new BoostSourceEffect(new MeleeDynamicValue(), new MeleeDynamicValue(), Duration.EndOfTurn), false); @@ -71,7 +71,7 @@ public class MeleeAbility extends AttacksTriggeredAbility { class MeleeWatcher extends Watcher { - private final HashMap> playersAttacked = new HashMap<>(0); + private HashMap> playersAttacked = new HashMap<>(0); MeleeWatcher() { super("MeleeWatcher", WatcherScope.GAME); @@ -95,7 +95,10 @@ class MeleeWatcher extends Watcher { } public int getNumberOfAttackedPlayers(UUID attackerId) { - return this.playersAttacked.get(attackerId).size(); + if (this.playersAttacked.get(attackerId) != null) { + return this.playersAttacked.get(attackerId).size(); + } + return 0; } @Override @@ -106,11 +109,18 @@ class MeleeWatcher extends Watcher { class MeleeDynamicValue implements DynamicValue { + private boolean valueChecked = false; + private int lockedInValue; + @Override public int calculate(Game game, Ability sourceAbility, Effect effect) { MeleeWatcher watcher = (MeleeWatcher) game.getState().getWatchers().get(MeleeWatcher.class.getSimpleName()); if (watcher != null) { - return watcher.getNumberOfAttackedPlayers(sourceAbility.getControllerId()); + if (!valueChecked) { + this.lockedInValue = watcher.getNumberOfAttackedPlayers(sourceAbility.getControllerId()); + valueChecked = true; + } + return this.lockedInValue; } return 0; } diff --git a/Mage/src/main/java/mage/abilities/keyword/special/JohanVigilanceAbility.java b/Mage/src/main/java/mage/abilities/keyword/special/JohanVigilanceAbility.java new file mode 100644 index 0000000000..2232b4739e --- /dev/null +++ b/Mage/src/main/java/mage/abilities/keyword/special/JohanVigilanceAbility.java @@ -0,0 +1,67 @@ +/* + * Copyright 2010 BetaSteward_at_googlemail.com. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are + * permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this list of + * conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, this list + * of conditions and the following disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY BetaSteward_at_googlemail.com ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BetaSteward_at_googlemail.com OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * The views and conclusions contained in the software and documentation are those of the + * authors and should not be interpreted as representing official policies, either expressed + * or implied, of BetaSteward_at_googlemail.com. + */ + +package mage.abilities.keyword.special; + +import mage.constants.Zone; +import mage.abilities.MageSingleton; +import mage.abilities.StaticAbility; + +import java.io.ObjectStreamException; + +/** + * + * @author BetaSteward_at_googlemail.com & L_J + */ +public class JohanVigilanceAbility extends StaticAbility implements MageSingleton { // special instance of "attacking doesn't cause this to tap" granted by Johan's ability + + private static final JohanVigilanceAbility instance = new JohanVigilanceAbility(); + + private Object readResolve() throws ObjectStreamException { + return instance; + } + + public static JohanVigilanceAbility getInstance() { + return instance; + } + + private JohanVigilanceAbility() { + super(Zone.BATTLEFIELD, null); + } + + @Override + public String getRule() { + return ""; + } + + @Override + public JohanVigilanceAbility copy() { + return instance; + } + +} diff --git a/Mage/src/main/java/mage/cards/repository/CardRepository.java b/Mage/src/main/java/mage/cards/repository/CardRepository.java index 91530a64df..59517a91ff 100644 --- a/Mage/src/main/java/mage/cards/repository/CardRepository.java +++ b/Mage/src/main/java/mage/cards/repository/CardRepository.java @@ -58,7 +58,7 @@ public enum CardRepository { // raise this if db structure was changed private static final long CARD_DB_VERSION = 51; // raise this if new cards were added to the server - private static final long CARD_CONTENT_VERSION = 94; + private static final long CARD_CONTENT_VERSION = 95; private Dao cardDao; private Set classNames; diff --git a/Mage/src/main/java/mage/counters/CounterType.java b/Mage/src/main/java/mage/counters/CounterType.java index d4b4464157..1b7862d19e 100644 --- a/Mage/src/main/java/mage/counters/CounterType.java +++ b/Mage/src/main/java/mage/counters/CounterType.java @@ -68,6 +68,7 @@ public enum CounterType { FURY("fury"), FUSE("fuse"), GOLD("gold"), + GROWTH("growth"), HATCHLING("hatchling"), HEALING("healing"), HOOFPRINT("hoofprint"), diff --git a/Mage/src/main/java/mage/filter/common/FilterCreatureAttackingYou.java b/Mage/src/main/java/mage/filter/common/FilterCreatureAttackingYou.java new file mode 100644 index 0000000000..308089f38a --- /dev/null +++ b/Mage/src/main/java/mage/filter/common/FilterCreatureAttackingYou.java @@ -0,0 +1,82 @@ +/* +* Copyright 2010 BetaSteward_at_googlemail.com. All rights reserved. +* +* Redistribution and use in source and binary forms, with or without modification, are +* permitted provided that the following conditions are met: +* +* 1. Redistributions of source code must retain the above copyright notice, this list of +* conditions and the following disclaimer. +* +* 2. Redistributions in binary form must reproduce the above copyright notice, this list +* of conditions and the following disclaimer in the documentation and/or other materials +* provided with the distribution. +* +* THIS SOFTWARE IS PROVIDED BY BetaSteward_at_googlemail.com ``AS IS'' AND ANY EXPRESS OR IMPLIED +* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND +* FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BetaSteward_at_googlemail.com OR +* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR +* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON +* ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING +* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF +* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +* +* The views and conclusions contained in the software and documentation are those of the +* authors and should not be interpreted as representing official policies, either expressed +* or implied, of BetaSteward_at_googlemail.com. + */ +package mage.target.common; + +import java.util.UUID; +import mage.filter.common.FilterAttackingCreature; +import mage.game.Game; +import mage.game.permanent.Permanent; + +/** + * + * @author TheElk801 + */ +public class FilterCreatureAttackingYou extends FilterAttackingCreature { + + private final boolean orWalker; + + public FilterCreatureAttackingYou() { + this(false); + } + + public FilterCreatureAttackingYou(boolean orWalker) { + this("creature that's attacking you" + (orWalker ? "or a planeswalker you control" : ""), orWalker); + } + + public FilterCreatureAttackingYou(String name) { + this(name, false); + } + + public FilterCreatureAttackingYou(String name, boolean orWalker) { + super(name); + this.orWalker = orWalker; + } + + public FilterCreatureAttackingYou(final FilterCreatureAttackingYou filter) { + super(filter); + this.orWalker = filter.orWalker; + } + + @Override + public FilterCreatureAttackingYou copy() { + return new FilterCreatureAttackingYou(this); + } + + @Override + public boolean match(Permanent permanent, UUID sourceId, UUID playerId, Game game) { + if (orWalker) { + return super.match(permanent, sourceId, playerId, game) + && permanent.isAttacking() // to prevent unneccessary combat checking if not attacking + && playerId.equals(game.getCombat().getDefendingPlayerId(permanent.getId(), game)); + } else { + return super.match(permanent, sourceId, playerId, game) + && permanent.isAttacking() // to prevent unneccessary combat checking if not attacking + && playerId.equals(game.getCombat().getDefenderId(permanent.getId())); + } + } +} diff --git a/Mage/src/main/java/mage/game/Game.java b/Mage/src/main/java/mage/game/Game.java index 044e6a3ae7..3956dd24b7 100644 --- a/Mage/src/main/java/mage/game/Game.java +++ b/Mage/src/main/java/mage/game/Game.java @@ -173,7 +173,7 @@ public interface Game extends MageItem, Serializable { UUID getPriorityPlayerId(); - boolean gameOver(UUID playerId); + boolean checkIfGameIsOver(); boolean hasEnded(); @@ -347,6 +347,8 @@ public interface Game extends MageItem, Serializable { void concede(UUID playerId); + void setConcedingPlayer(UUID playerId); + void setManaPaymentMode(UUID playerId, boolean autoPayment); void setManaPaymentModeRestricted(UUID playerId, boolean autoPaymentRestricted); diff --git a/Mage/src/main/java/mage/game/GameImpl.java b/Mage/src/main/java/mage/game/GameImpl.java index 768703d804..9e07a84e34 100644 --- a/Mage/src/main/java/mage/game/GameImpl.java +++ b/Mage/src/main/java/mage/game/GameImpl.java @@ -161,6 +161,8 @@ public abstract class GameImpl implements Game, Serializable { private final LinkedList stackObjectsCheck = new LinkedList<>(); // used to check if different sources used the stack // used to set the counters a permanent adds the battlefield (if no replacement effect is used e.g. Persist) protected Map enterWithCounters = new HashMap<>(); + // used to proceed player conceding requests + private final LinkedList concedingPlayers = new LinkedList<>(); // used to handle asynchronous request of a player to leave the game public GameImpl(MultiplayerAttackOption attackOption, RangeOfInfluence range, int freeMulligans, int startLife) { this.id = UUID.randomUUID(); @@ -535,26 +537,64 @@ public abstract class GameImpl implements Game, Serializable { } } - /** - * Starts check if game is over or if playerId is given let the player - * concede. - * - * @param playerId - * @return - */ +// /** +// * Starts check if game is over or if playerId is given let the player +// * concede. +// * +// * @param playerId +// * @return +// */ +// @Override +// public synchronized boolean gameOver(UUID playerId) { +// if (playerId == null) { +// boolean result = checkIfGameIsOver(); +// return result; +// } else { +// logger.debug("Game over for player Id: " + playerId + " gameId " + getId()); +// concedingPlayers.add(playerId); +// Player player = getPlayer(state.getPriorityPlayerId()); +// if (player != null && player.isHuman()) { +// player.signalPlayerConcede(); +// } else { +// checkConcede(); +// } +// return true; +// } +// } @Override - public synchronized boolean gameOver(UUID playerId) { - if (playerId == null) { - boolean result = checkIfGameIsOver(); - return result; + public void setConcedingPlayer(UUID playerId) { + Player player = null; + if (state.getChoosingPlayerId() != null) { + player = getPlayer(state.getChoosingPlayerId()); + } else if (state.getPriorityPlayerId() != null) { + player = getPlayer(state.getPriorityPlayerId()); + } + if (player != null) { + if (!player.hasLeft() && player.isHuman()) { + if (!concedingPlayers.contains(playerId)) { + logger.debug("Game over for player Id: " + playerId + " gameId " + getId()); + concedingPlayers.add(playerId); + player.signalPlayerConcede(); + } + } else { + // no asynchronous action so check directly + concedingPlayers.add(playerId); + checkConcede(); + } } else { - logger.debug("Game over for player Id: " + playerId + " gameId " + getId()); - leave(playerId); - return true; + checkConcede(); + checkIfGameIsOver(); } } - private boolean checkIfGameIsOver() { + public void checkConcede() { + while (!concedingPlayers.isEmpty()) { + leave(concedingPlayers.removeFirst()); + } + } + + @Override + public boolean checkIfGameIsOver() { if (state.isGameOver()) { return true; } @@ -578,7 +618,7 @@ public abstract class GameImpl implements Game, Serializable { } for (Player player : state.getPlayers().values()) { if (!player.hasLeft() && !player.hasLost()) { - logger.debug(new StringBuilder("Player ").append(player.getName()).append(" has won gameId: ").append(this.getId())); + logger.debug("Player " + player.getName() + " has won gameId: " + this.getId()); player.won(this); } } @@ -696,13 +736,13 @@ public abstract class GameImpl implements Game, Serializable { Player player = getPlayer(playerList.get()); boolean wasPaused = state.isPaused(); state.resume(); - if (!gameOver(null)) { + if (!checkIfGameIsOver()) { fireInformEvent("Turn " + state.getTurnNum()); if (checkStopOnTurnOption()) { return; } state.getTurn().resumePlay(this, wasPaused); - if (!isPaused() && !gameOver(null)) { + if (!isPaused() && !checkIfGameIsOver()) { endOfTurn(); player = playerList.getNext(this); state.setTurnNum(state.getTurnNum() + 1); @@ -712,11 +752,11 @@ public abstract class GameImpl implements Game, Serializable { } protected void play(UUID nextPlayerId) { - if (!isPaused() && !gameOver(null)) { + if (!isPaused() && !checkIfGameIsOver()) { playerList = state.getPlayerList(nextPlayerId); Player playerByOrder = getPlayer(playerList.get()); state.setPlayerByOrderId(playerByOrder.getId()); - while (!isPaused() && !gameOver(null)) { + while (!isPaused() && !checkIfGameIsOver()) { if (!playExtraTurns()) { break; } @@ -733,7 +773,7 @@ public abstract class GameImpl implements Game, Serializable { state.setPlayerByOrderId(playerByOrder.getId()); } } - if (gameOver(null) && !isSimulation()) { + if (checkIfGameIsOver() && !isSimulation()) { winnerId = findWinnersAndLosers(); StringBuilder sb = new StringBuilder("GAME END gameId: ").append(this.getId()).append(' '); int count = 0; @@ -816,7 +856,7 @@ public abstract class GameImpl implements Game, Serializable { skipTurn = state.getTurn().play(this, player); } while (executingRollback); - if (isPaused() || gameOver(null)) { + if (isPaused() || checkIfGameIsOver()) { return false; } if (!skipTurn) { @@ -854,7 +894,7 @@ public abstract class GameImpl implements Game, Serializable { saveState(false); - if (gameOver(null)) { + if (checkIfGameIsOver()) { return; } @@ -1245,7 +1285,7 @@ public abstract class GameImpl implements Game, Serializable { clearAllBookmarks(); try { applyEffects(); - while (!isPaused() && !gameOver(null) && !this.getTurn().isEndTurnRequested()) { + while (!isPaused() && !checkIfGameIsOver() && !this.getTurn().isEndTurnRequested()) { if (!resuming) { state.getPlayers().resetPassed(); state.getPlayerList().setCurrent(activePlayerId); @@ -1254,14 +1294,14 @@ public abstract class GameImpl implements Game, Serializable { } fireUpdatePlayersEvent(); Player player; - while (!isPaused() && !gameOver(null)) { + while (!isPaused() && !checkIfGameIsOver()) { try { if (bookmark == 0) { bookmark = bookmarkState(); } player = getPlayer(state.getPlayerList().get()); state.setPriorityPlayerId(player.getId()); - while (!player.isPassed() && player.canRespond() && !isPaused() && !gameOver(null)) { + while (!player.isPassed() && player.canRespond() && !isPaused() && !checkIfGameIsOver()) { if (!resuming) { // 603.3. Once an ability has triggered, its controller puts it on the stack as an object that's not a card the next time a player would receive priority checkStateAndTriggered(); @@ -1270,7 +1310,7 @@ public abstract class GameImpl implements Game, Serializable { resetLKI(); } saveState(false); - if (isPaused() || gameOver(null)) { + if (isPaused() || checkIfGameIsOver()) { return; } // resetPassed should be called if player performs any action @@ -1289,13 +1329,14 @@ public abstract class GameImpl implements Game, Serializable { } resetShortLivingLKI(); resuming = false; - if (isPaused() || gameOver(null)) { + if (isPaused() || checkIfGameIsOver()) { return; } if (allPassed()) { if (!state.getStack().isEmpty()) { //20091005 - 115.4 resolve(); + checkConcede(); applyEffects(); state.getPlayers().resetPassed(); fireUpdatePlayersEvent(); @@ -1609,11 +1650,11 @@ public abstract class GameImpl implements Game, Serializable { public boolean checkStateAndTriggered() { boolean somethingHappened = false; //20091005 - 115.5 - while (!isPaused() && !gameOver(null)) { + while (!isPaused() && !checkIfGameIsOver()) { if (!checkStateBasedActions()) { // nothing happened so check triggers state.handleSimultaneousEvent(this); - if (isPaused() || gameOver(null) || getTurn().isEndTurnRequested() || !checkTriggered()) { + if (isPaused() || checkIfGameIsOver() || getTurn().isEndTurnRequested() || !checkTriggered()) { break; } } @@ -1621,6 +1662,7 @@ public abstract class GameImpl implements Game, Serializable { applyEffects(); // needed e.g if boost effects end and cause creatures to die somethingHappened = true; } + checkConcede(); return somethingHappened; } @@ -1734,7 +1776,6 @@ public abstract class GameImpl implements Game, Serializable { } } - List planeswalkers = new ArrayList<>(); List legendary = new ArrayList<>(); List worldEnchantment = new ArrayList<>(); for (Permanent perm : getBattlefield().getAllActivePermanents()) { @@ -1781,7 +1822,6 @@ public abstract class GameImpl implements Game, Serializable { continue; } } - planeswalkers.add(perm); } if (perm.isWorld()) { worldEnchantment.add(perm); @@ -2288,7 +2328,6 @@ public abstract class GameImpl implements Game, Serializable { * @param playerId */ protected void leave(UUID playerId) { // needs to be executed from the game thread, not from the concede thread of conceding player! - Player player = getPlayer(playerId); if (player == null || player.hasLeft()) { logger.debug("Player already left " + (player != null ? player.getName() : playerId)); diff --git a/Mage/src/main/java/mage/game/combat/Combat.java b/Mage/src/main/java/mage/game/combat/Combat.java index 1ad1948a1b..df50deaf89 100644 --- a/Mage/src/main/java/mage/game/combat/Combat.java +++ b/Mage/src/main/java/mage/game/combat/Combat.java @@ -34,6 +34,7 @@ import mage.abilities.Ability; import mage.abilities.effects.RequirementEffect; import mage.abilities.effects.RestrictionEffect; import mage.abilities.keyword.VigilanceAbility; +import mage.abilities.keyword.special.JohanVigilanceAbility; import mage.constants.Outcome; import mage.constants.Zone; import mage.filter.StaticFilters; @@ -264,7 +265,7 @@ public class Combat implements Serializable, Copyable { player.selectAttackers(game, attackingPlayerId); } firstTime = false; - if (game.isPaused() || game.gameOver(null) || game.executingRollback()) { + if (game.isPaused() || game.checkIfGameIsOver() || game.executingRollback()) { return; } // because of possible undo during declare attackers it's neccassary to call here the methods with "game.getCombat()." to get the current combat object!!! @@ -461,7 +462,7 @@ public class Combat implements Serializable, Copyable { } while (choose) { controller.selectBlockers(game, defenderId); - if (game.isPaused() || game.gameOver(null) || game.executingRollback()) { + if (game.isPaused() || game.checkIfGameIsOver() || game.executingRollback()) { return; } if (!game.getCombat().checkBlockRestrictions(defender, game)) { @@ -1091,7 +1092,7 @@ public class Combat implements Serializable, Copyable { @SuppressWarnings("deprecation") public boolean declareAttacker(UUID creatureId, UUID defenderId, UUID playerId, Game game) { Permanent attacker = game.getPermanent(creatureId); - if (!attacker.getAbilities().containsKey(VigilanceAbility.getInstance().getId())) { + if (!attacker.getAbilities().containsKey(VigilanceAbility.getInstance().getId()) && !attacker.getAbilities().containsKey(JohanVigilanceAbility.getInstance().getId())) { if (!attacker.isTapped()) { attacker.setTapped(true); attackersTappedByAttack.add(attacker.getId()); diff --git a/Mage/src/main/java/mage/game/permanent/Permanent.java b/Mage/src/main/java/mage/game/permanent/Permanent.java index fedf9aad48..45e8226439 100644 --- a/Mage/src/main/java/mage/game/permanent/Permanent.java +++ b/Mage/src/main/java/mage/game/permanent/Permanent.java @@ -78,10 +78,16 @@ public interface Permanent extends Card, Controllable { boolean isPhasedIn(); + boolean isPhasedOutIndirectly(); + boolean phaseIn(Game game); + boolean phaseIn(Game game, boolean onlyDirect); + boolean phaseOut(Game game); + boolean phaseOut(Game game, boolean indirectPhase); + boolean isMonstrous(); void setMonstrous(boolean value); diff --git a/Mage/src/main/java/mage/game/permanent/PermanentImpl.java b/Mage/src/main/java/mage/game/permanent/PermanentImpl.java index f4bd39bb1a..c30051d825 100644 --- a/Mage/src/main/java/mage/game/permanent/PermanentImpl.java +++ b/Mage/src/main/java/mage/game/permanent/PermanentImpl.java @@ -89,6 +89,7 @@ public abstract class PermanentImpl extends CardImpl implements Permanent { protected boolean controlledFromStartOfControllerTurn; protected int turnsOnBattlefield; protected boolean phasedIn = true; + protected boolean indirectPhase = false; protected boolean faceDown; protected boolean attacking; protected int blocking; @@ -138,6 +139,7 @@ public abstract class PermanentImpl extends CardImpl implements Permanent { this.controlledFromStartOfControllerTurn = permanent.controlledFromStartOfControllerTurn; this.turnsOnBattlefield = permanent.turnsOnBattlefield; this.phasedIn = permanent.phasedIn; + this.indirectPhase = permanent.indirectPhase; this.faceDown = permanent.faceDown; this.attacking = permanent.attacking; this.blocking = permanent.blocking; @@ -461,14 +463,32 @@ public abstract class PermanentImpl extends CardImpl implements Permanent { return phasedIn; } + @Override + public boolean isPhasedOutIndirectly() { + return !phasedIn && indirectPhase; + } + @Override public boolean phaseIn(Game game) { + return phaseIn(game, true); + } + + @Override + public boolean phaseIn(Game game, boolean onlyDirect) { if (!phasedIn) { - if (!replaceEvent(EventType.PHASE_IN, game)) { + if (!replaceEvent(EventType.PHASE_IN, game) + && ((onlyDirect && !indirectPhase) || (!onlyDirect))) { this.phasedIn = true; + this.indirectPhase = false; if (!game.isSimulation()) { game.informPlayers(getLogName() + " phased in"); } + for (UUID attachedId : this.getAttachments()) { + Permanent attachedPerm = game.getPermanent(attachedId); + if (attachedPerm != null) { + attachedPerm.phaseIn(game, false); + } + } fireEvent(EventType.PHASED_IN, game); return true; } @@ -478,9 +498,21 @@ public abstract class PermanentImpl extends CardImpl implements Permanent { @Override public boolean phaseOut(Game game) { + return phaseOut(game, false); + } + + @Override + public boolean phaseOut(Game game, boolean indirectPhase) { if (phasedIn) { if (!replaceEvent(EventType.PHASE_OUT, game)) { + for (UUID attachedId : this.getAttachments()) { + Permanent attachedPerm = game.getPermanent(attachedId); + if (attachedPerm != null) { + attachedPerm.phaseOut(game, true); + } + } this.phasedIn = false; + this.indirectPhase = indirectPhase; if (!game.isSimulation()) { game.informPlayers(getLogName() + " phased out"); } diff --git a/Mage/src/main/java/mage/game/permanent/token/WaylayToken.java b/Mage/src/main/java/mage/game/permanent/token/WaylayToken.java new file mode 100644 index 0000000000..47942f2c6a --- /dev/null +++ b/Mage/src/main/java/mage/game/permanent/token/WaylayToken.java @@ -0,0 +1,48 @@ +/* +* Copyright 2010 BetaSteward_at_googlemail.com. All rights reserved. +* +* Redistribution and use in source and binary forms, with or without modification, are +* permitted provided that the following conditions are met: +* +* 1. Redistributions of source code must retain the above copyright notice, this list of +* conditions and the following disclaimer. +* +* 2. Redistributions in binary form must reproduce the above copyright notice, this list +* of conditions and the following disclaimer in the documentation and/or other materials +* provided with the distribution. +* +* THIS SOFTWARE IS PROVIDED BY BetaSteward_at_googlemail.com AS IS AND ANY EXPRESS OR IMPLIED +* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND +* FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BetaSteward_at_googlemail.com OR +* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR +* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON +* ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING +* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF +* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +* +* The views and conclusions contained in the software and documentation are those of the +* authors and should not be interpreted as representing official policies, either expressed +* or implied, of BetaSteward_at_googlemail.com. + */ +package mage.game.permanent.token; + +import mage.constants.CardType; +import mage.constants.SubType; +import mage.MageInt; + +/** + * + * @author spjspj + */ +public class WaylayToken extends Token { + + public WaylayToken() { + super("Knight", "2/2 white Knight creature token"); + cardType.add(CardType.CREATURE); + color.setWhite(true); + subtype.add(SubType.KNIGHT); + power = new MageInt(2); + toughness = new MageInt(2); + } +} diff --git a/Mage/src/main/java/mage/game/turn/Phase.java b/Mage/src/main/java/mage/game/turn/Phase.java index e4b276336e..500709b399 100644 --- a/Mage/src/main/java/mage/game/turn/Phase.java +++ b/Mage/src/main/java/mage/game/turn/Phase.java @@ -95,7 +95,7 @@ public abstract class Phase implements Serializable { } public boolean play(Game game, UUID activePlayerId) { - if (game.isPaused() || game.gameOver(null)) { + if (game.isPaused() || game.checkIfGameIsOver()) { return false; } @@ -104,7 +104,7 @@ public abstract class Phase implements Serializable { if (beginPhase(game, activePlayerId)) { for (Step step : steps) { - if (game.isPaused() || game.gameOver(null)) { + if (game.isPaused() || game.checkIfGameIsOver()) { return false; } if (game.getTurn().isEndTurnRequested() && step.getType()!=PhaseStep.CLEANUP) { @@ -122,7 +122,7 @@ public abstract class Phase implements Serializable { } } - if (game.isPaused() || game.gameOver(null)) { + if (game.isPaused() || game.checkIfGameIsOver()) { return false; } count++; @@ -143,7 +143,7 @@ public abstract class Phase implements Serializable { } public boolean resumePlay(Game game, PhaseStep stepType, boolean wasPaused) { - if (game.isPaused() || game.gameOver(null)) { + if (game.isPaused() || game.checkIfGameIsOver()) { return false; } @@ -157,7 +157,7 @@ public abstract class Phase implements Serializable { resumeStep(game, wasPaused); while (it.hasNext()) { step = it.next(); - if (game.isPaused() || game.gameOver(null)) { + if (game.isPaused() || game.checkIfGameIsOver()) { return false; } currentStep = step; @@ -169,7 +169,7 @@ public abstract class Phase implements Serializable { } } - if (game.isPaused() || game.gameOver(null)) { + if (game.isPaused() || game.checkIfGameIsOver()) { return false; } count++; @@ -206,13 +206,13 @@ public abstract class Phase implements Serializable { if (!currentStep.skipStep(game, activePlayerId)) { game.getState().increaseStepNum(); prePriority(game, activePlayerId); - if (!game.isPaused() && !game.gameOver(null) && !game.executingRollback()) { + if (!game.isPaused() && !game.checkIfGameIsOver() && !game.executingRollback()) { currentStep.priority(game, activePlayerId, false); if (game.executingRollback()) { return; } } - if (!game.isPaused() && !game.gameOver(null) && !game.executingRollback()) { + if (!game.isPaused() && !game.checkIfGameIsOver() && !game.executingRollback()) { postPriority(game, activePlayerId); } } @@ -233,11 +233,11 @@ public abstract class Phase implements Serializable { prePriority(game, activePlayerId); } case PRIORITY: - if (!game.isPaused() && !game.gameOver(null)) { + if (!game.isPaused() && !game.checkIfGameIsOver()) { currentStep.priority(game, activePlayerId, resuming); } case POST: - if (!game.isPaused() && !game.gameOver(null)) { + if (!game.isPaused() && !game.checkIfGameIsOver()) { postPriority(game, activePlayerId); } } diff --git a/Mage/src/main/java/mage/game/turn/Turn.java b/Mage/src/main/java/mage/game/turn/Turn.java index 4ae01ed55e..6b910ad1e6 100644 --- a/Mage/src/main/java/mage/game/turn/Turn.java +++ b/Mage/src/main/java/mage/game/turn/Turn.java @@ -127,7 +127,7 @@ public class Turn implements Serializable { public boolean play(Game game, Player activePlayer) { activePlayer.becomesActivePlayer(); this.setDeclareAttackersStepStarted(false); - if (game.isPaused() || game.gameOver(null)) { + if (game.isPaused() || game.checkIfGameIsOver()) { return false; } @@ -143,7 +143,7 @@ public class Turn implements Serializable { resetCounts(); game.getPlayer(activePlayer.getId()).beginTurn(game); for (Phase phase : phases) { - if (game.isPaused() || game.gameOver(null)) { + if (game.isPaused() || game.checkIfGameIsOver()) { return false; } if (!isEndTurnRequested() || phase.getType() == TurnPhase.END) { @@ -189,7 +189,7 @@ public class Turn implements Serializable { } while (it.hasNext()) { phase = it.next(); - if (game.isPaused() || game.gameOver(null)) { + if (game.isPaused() || game.checkIfGameIsOver()) { return; } currentPhase = phase; diff --git a/Mage/src/main/java/mage/players/ManaPool.java b/Mage/src/main/java/mage/players/ManaPool.java index e55444bf3d..62ddedf6d6 100644 --- a/Mage/src/main/java/mage/players/ManaPool.java +++ b/Mage/src/main/java/mage/players/ManaPool.java @@ -125,7 +125,7 @@ public class ManaPool implements Serializable { } if (getConditional(manaType, ability, filter, game, costToPay) > 0) { - removeConditional(manaType, ability, game, costToPay); + removeConditional(manaType, ability, game, costToPay, usedManaToPay); lockManaType(); // pay only one mana if mana payment is set to manually return true; } @@ -437,10 +437,11 @@ public class ManaPool implements Serializable { return new ManaPool(this); } - private void removeConditional(ManaType manaType, Ability ability, Game game, Cost costToPay) { + private void removeConditional(ManaType manaType, Ability ability, Game game, Cost costToPay, Mana usedManaToPay) { for (ConditionalMana mana : getConditionalMana()) { if (mana.get(manaType) > 0 && mana.apply(ability, game, mana.getManaProducerId(), costToPay)) { mana.set(manaType, mana.get(manaType) - 1); + usedManaToPay.increase(manaType); GameEvent event = new GameEvent(GameEvent.EventType.MANA_PAID, ability.getId(), mana.getManaProducerId(), ability.getControllerId(), 0, mana.getFlag()); event.setData(mana.getManaProducerOriginalId().toString()); game.fireEvent(event); diff --git a/Mage/src/main/java/mage/players/Player.java b/Mage/src/main/java/mage/players/Player.java index 261a24c22f..71478eb2f9 100644 --- a/Mage/src/main/java/mage/players/Player.java +++ b/Mage/src/main/java/mage/players/Player.java @@ -444,6 +444,8 @@ public interface Player extends MageItem, Copyable { void abortReset(); + void signalPlayerConcede(); + void skip(); // priority, undo, ... diff --git a/Mage/src/main/java/mage/players/PlayerImpl.java b/Mage/src/main/java/mage/players/PlayerImpl.java index dac2bddf9a..7168fcbcd6 100644 --- a/Mage/src/main/java/mage/players/PlayerImpl.java +++ b/Mage/src/main/java/mage/players/PlayerImpl.java @@ -1484,16 +1484,15 @@ public abstract class PlayerImpl implements Player, Serializable { // phasing out is known as phasing out "indirectly." An enchantment or Equipment // that phased out indirectly won't phase in by itself, but instead phases in // along with the card it's attached to. - for (UUID attachmentId : permanent.getAttachments()) { - Permanent attachment = game.getPermanent(attachmentId); - if (attachment != null) { - attachment.phaseOut(game); - } + Permanent attachedTo = game.getPermanent(permanent.getAttachedTo()); + if (!(attachedTo != null && attachedTo.getControllerId().equals(this.getId()))) { + permanent.phaseOut(game, false); } - permanent.phaseOut(game); } for (Permanent permanent : phasedOut) { - permanent.phaseIn(game); + if (!permanent.isPhasedOutIndirectly()) { + permanent.phaseIn(game); + } } } @@ -1752,7 +1751,9 @@ public abstract class PlayerImpl implements Player, Serializable { if (!game.isSimulation()) { game.informPlayers(this.getLogName() + " loses " + event.getAmount() + " life"); } - game.fireEvent(new GameEvent(GameEvent.EventType.LOST_LIFE, playerId, playerId, playerId, amount, atCombat)); + if (amount > 0) { + game.fireEvent(new GameEvent(GameEvent.EventType.LOST_LIFE, playerId, playerId, playerId, amount, atCombat)); + } return amount; } return 0; @@ -2039,9 +2040,9 @@ public abstract class PlayerImpl implements Player, Serializable { @Override public void concede(Game game) { - game.gameOver(playerId); + game.setConcedingPlayer(playerId); lost(game); - this.left = true; +// this.left = true; } @Override @@ -2136,7 +2137,7 @@ public abstract class PlayerImpl implements Player, Serializable { // for draw - first all players that have lost have to be set to lost if (!hasLeft()) { logger.debug("Game over playerId: " + playerId); - game.gameOver(playerId); + game.setConcedingPlayer(playerId); } } @@ -2197,7 +2198,7 @@ public abstract class PlayerImpl implements Player, Serializable { this.draws = true; game.fireEvent(GameEvent.getEvent(GameEvent.EventType.DRAW_PLAYER, null, null, playerId)); game.informPlayers("For " + this.getLogName() + " the game is a draw."); - game.gameOver(playerId); + game.setConcedingPlayer(playerId); } } @@ -3579,6 +3580,11 @@ public abstract class PlayerImpl implements Player, Serializable { abort = false; } + @Override + public void signalPlayerConcede() { + + } + @Override public boolean scry(int value, Ability source, Game game diff --git a/Mage/src/main/java/mage/target/TargetImpl.java b/Mage/src/main/java/mage/target/TargetImpl.java index 3dbe7568cc..fb4aa7f6b8 100644 --- a/Mage/src/main/java/mage/target/TargetImpl.java +++ b/Mage/src/main/java/mage/target/TargetImpl.java @@ -128,11 +128,11 @@ public abstract class TargetImpl implements Target { @Override public String getMessage() { String suffix = ""; - if (targetController != null) { - // Hint for the selecting player that the targets must be valid from the point of the ability controller - // e.g. select opponent text may be misleading otherwise - suffix = " (target controlling!)"; - } +// if (targetController != null) { +// // Hint for the selecting player that the targets must be valid from the point of the ability controller +// // e.g. select opponent text may be misleading otherwise +// suffix = " (target controlling!)"; +// } if (getMaxNumberOfTargets() != 1) { StringBuilder sb = new StringBuilder(); sb.append("Select ").append(targetName); diff --git a/Mage/src/main/java/mage/watchers/common/ChooseBlockersRedundancyWatcher.java b/Mage/src/main/java/mage/watchers/common/ChooseBlockersRedundancyWatcher.java new file mode 100644 index 0000000000..f39cbb2c00 --- /dev/null +++ b/Mage/src/main/java/mage/watchers/common/ChooseBlockersRedundancyWatcher.java @@ -0,0 +1,80 @@ +/* + * Copyright 2010 BetaSteward_at_googlemail.com. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are + * permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this list of + * conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, this list + * of conditions and the following disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY BetaSteward_at_googlemail.com ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BetaSteward_at_googlemail.com OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * The views and conclusions contained in the software and documentation are those of the + * authors and should not be interpreted as representing official policies, either expressed + * or implied, of BetaSteward_at_googlemail.com. + */ +package mage.watchers.common; + +import mage.constants.WatcherScope; +import mage.game.Game; +import mage.game.events.GameEvent; +import mage.watchers.Watcher; + +/** + * + * @author L_J + */ + +public class ChooseBlockersRedundancyWatcher extends Watcher { // workaround for solving timestamp issues regarding "you choose which creatures block and how those creatures block" effects + + public int copyCount = 0; + public int copyCountApply = 0; + + public ChooseBlockersRedundancyWatcher() { + super(ChooseBlockersRedundancyWatcher.class.getSimpleName(), WatcherScope.GAME); + } + + public ChooseBlockersRedundancyWatcher(final ChooseBlockersRedundancyWatcher watcher) { + super(watcher); + this.copyCount = watcher.copyCount; + this.copyCountApply = watcher.copyCountApply; + } + + @Override + public void reset() { + copyCount = 0; + copyCountApply = 0; + } + + @Override + public ChooseBlockersRedundancyWatcher copy() { + return new ChooseBlockersRedundancyWatcher(this); + } + + @Override + public void watch(GameEvent event, Game game) { + } + + public void increment() { + copyCount++; + copyCountApply = copyCount; + } + + public void decrement() { + if (copyCountApply > 0) { + copyCountApply--; + } + } +} diff --git a/Mage/src/main/java/mage/watchers/common/PlayerAttackedStepWatcher.java b/Mage/src/main/java/mage/watchers/common/PlayerAttackedStepWatcher.java new file mode 100644 index 0000000000..03f56c9beb --- /dev/null +++ b/Mage/src/main/java/mage/watchers/common/PlayerAttackedStepWatcher.java @@ -0,0 +1,82 @@ +/* + * Copyright 2010 BetaSteward_at_googlemail.com. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are + * permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this list of + * conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, this list + * of conditions and the following disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY BetaSteward_at_googlemail.com ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BetaSteward_at_googlemail.com OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * The views and conclusions contained in the software and documentation are those of the + * authors and should not be interpreted as representing official policies, either expressed + * or implied, of BetaSteward_at_googlemail.com. + */ +package mage.watchers.common; + +import java.util.HashMap; +import java.util.Map; +import java.util.UUID; +import mage.constants.WatcherScope; +import mage.game.Game; +import mage.game.events.GameEvent; +import mage.watchers.Watcher; + +/** + * @author LevelX2 + */ +public class PlayerAttackedStepWatcher extends Watcher { + + // With how many creatures attacked this player this turn + private final Map playerAttacked = new HashMap<>(); + + public PlayerAttackedStepWatcher() { + super(PlayerAttackedWatcher.class.getSimpleName(), WatcherScope.GAME); + } + + public PlayerAttackedStepWatcher(final PlayerAttackedStepWatcher watcher) { + super(watcher); + for (Map.Entry entry : watcher.playerAttacked.entrySet()) { + this.playerAttacked.put(entry.getKey(), entry.getValue()); + } + } + + @Override + public PlayerAttackedStepWatcher copy() { + return new PlayerAttackedStepWatcher(this); + } + + @Override + public void watch(GameEvent event, Game game) { + if (event.getType() == GameEvent.EventType.DECLARE_ATTACKERS_STEP_POST) { + playerAttacked.clear(); + } + if (event.getType() == GameEvent.EventType.ATTACKER_DECLARED) { + playerAttacked.putIfAbsent(event.getTargetId(), 0); + playerAttacked.compute(event.getTargetId(), (p, amount) -> amount + 1); + } + } + + @Override + public void reset() { + super.reset(); + playerAttacked.clear(); + } + + public int getNumberAttackingCurrentStep(UUID playerId) { + return playerAttacked.getOrDefault(playerId, 0); + } +}