diff --git a/Mage.Client/src/main/java/mage/client/MageFrame.java b/Mage.Client/src/main/java/mage/client/MageFrame.java index dfa734f1afc..7df4a984ff0 100644 --- a/Mage.Client/src/main/java/mage/client/MageFrame.java +++ b/Mage.Client/src/main/java/mage/client/MageFrame.java @@ -429,17 +429,41 @@ public class MageFrame extends javax.swing.JFrame implements MageClient { } } + private boolean isChrismasTime(){ + // from december 15 to january 15 + Calendar cal = Calendar.getInstance(); + int currentYear = cal.get(Calendar.YEAR); + Date currentTime = cal.getTime(); + + Date chrisFrom = new GregorianCalendar(currentYear, Calendar.DECEMBER, 15).getTime(); + Date chrisTo = new GregorianCalendar(currentYear + 1, Calendar.JANUARY, 15 + 1).getTime(); + + return currentTime.after(chrisFrom) && currentTime.before(chrisTo); + } + private void addMageLabel() { if (liteMode || grayMode) { return; } - String filename = "/label-xmage.png"; + + String filename; + float ratio; + if (isChrismasTime()){ + // chrismass logo + LOGGER.info("Yo Ho Ho, Merry Christmas and a Happy New Year"); + filename = "/label-xmage-christmas.png"; + ratio = 539.0f / 318.0f; + }else{ + // standard logo + filename = "/label-xmage.png"; + ratio = 509.0f / 288.0f; + } + try { InputStream is = this.getClass().getResourceAsStream(filename); - - float ratio = 1179.0f / 678.0f; - titleRectangle = new Rectangle(540, (int) (640 / ratio)); if (is != null) { + titleRectangle = new Rectangle(540, (int) (640 / ratio)); + BufferedImage image = ImageIO.read(is); //ImageIcon resized = new ImageIcon(image.getScaledInstance(titleRectangle.width, titleRectangle.height, java.awt.Image.SCALE_SMOOTH)); title = new JLabel(); diff --git a/Mage.Client/src/main/resources/label-xmage-christmas.png b/Mage.Client/src/main/resources/label-xmage-christmas.png new file mode 100644 index 00000000000..92edd1ee6c0 Binary files /dev/null and b/Mage.Client/src/main/resources/label-xmage-christmas.png differ 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 f281d360e21..b4055ba53f8 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 @@ -489,7 +489,9 @@ public class ComputerPlayer6 extends ComputerPlayer /*implements Player*/ { maxSeconds = 3600; } logger.debug("maxThink: " + maxSeconds + " seconds "); - return task.get(maxSeconds, TimeUnit.SECONDS); + if (task.get(maxSeconds, TimeUnit.SECONDS) != null) { + return task.get(maxSeconds, TimeUnit.SECONDS); + } } catch (TimeoutException e) { logger.info("simulating - timed out"); task.cancel(true); diff --git a/Mage.Sets/src/mage/cards/a/AngrathMinotaurPirate.java b/Mage.Sets/src/mage/cards/a/AngrathMinotaurPirate.java index 6cf617b6e4b..e685f257608 100644 --- a/Mage.Sets/src/mage/cards/a/AngrathMinotaurPirate.java +++ b/Mage.Sets/src/mage/cards/a/AngrathMinotaurPirate.java @@ -69,7 +69,7 @@ public class AngrathMinotaurPirate extends CardImpl { // +2: Angrath, Minotaur Pirate deals 1 damage to target opponent and each creature that player controls. Effects effects1 = new Effects(); effects1.add(new DamageTargetEffect(1)); - effects1.add(new DamageAllControlledTargetEffect(1, new FilterCreaturePermanent())); + effects1.add(new DamageAllControlledTargetEffect(1, new FilterCreaturePermanent()).setText("and each creature that player controls")); LoyaltyAbility ability1 = new LoyaltyAbility(effects1, +2); ability1.addTarget(new TargetOpponent()); this.addAbility(ability1); @@ -77,7 +77,8 @@ public class AngrathMinotaurPirate extends CardImpl { // -3: Return target Pirate card from your graveyard to the battlefield. FilterCard filterPirateCard = new FilterCreatureCard("pirate card from your graveyard"); filterPirateCard.add(new SubtypePredicate(SubType.PIRATE)); - Ability ability2 = new LoyaltyAbility(new ReturnFromGraveyardToBattlefieldTargetEffect(), -3); + Ability ability2 = new LoyaltyAbility(new ReturnFromGraveyardToBattlefieldTargetEffect() + .setText("Return target Pirate card from your graveyard to the battlefield"), -3); ability2.addTarget(new TargetCardInYourGraveyard(filterPirateCard)); this.addAbility(ability2); diff --git a/Mage.Sets/src/mage/cards/a/AngrathsFury.java b/Mage.Sets/src/mage/cards/a/AngrathsFury.java new file mode 100644 index 00000000000..3141cb58d4b --- /dev/null +++ b/Mage.Sets/src/mage/cards/a/AngrathsFury.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.a; + +import java.util.UUID; +import mage.abilities.effects.common.DamageTargetEffect; +import mage.abilities.effects.common.DestroyTargetEffect; +import mage.abilities.effects.common.search.SearchLibraryGraveyardPutInHandEffect; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.filter.FilterCard; +import mage.filter.predicate.mageobject.NamePredicate; +import mage.target.TargetPlayer; +import mage.target.common.TargetCreaturePermanent; +import mage.target.targetpointer.SecondTargetPointer; + +/** + * + * @author LevelX2 + */ +public class AngrathsFury extends CardImpl { + + private final static FilterCard filter = new FilterCard("Angrath, Minotaur Pirate"); + + static { + filter.add(new NamePredicate(filter.getMessage())); + } + + public AngrathsFury(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.SORCERY}, "{3}{B}{R}"); + + // Destroy target creature. + this.getSpellAbility().addEffect(new DestroyTargetEffect()); + this.getSpellAbility().addTarget(new TargetCreaturePermanent()); + + // Angrath's Fury deals 3 damage to target player. + this.getSpellAbility().addEffect(new DamageTargetEffect(3).setTargetPointer(new SecondTargetPointer()) + .setText("{this} deals 3 damage to target player")); + this.getSpellAbility().addTarget(new TargetPlayer()); + + // You may search your library and/or graveyard for a card named Angrath, Minotaur Pirate, reveal it, and put it into your hand. If you search your library this way, shuffle it. + this.getSpellAbility().addEffect(new SearchLibraryGraveyardPutInHandEffect(filter) + .setText("You may search your library and/or graveyard for a card named Angrath, Minotaur Pirate, reveal it, and put it into your hand. If you search your library this way, shuffle it")); + + } + + public AngrathsFury(final AngrathsFury card) { + super(card); + } + + @Override + public AngrathsFury copy() { + return new AngrathsFury(this); + } +} diff --git a/Mage.Sets/src/mage/cards/a/AngrathsMarauders.java b/Mage.Sets/src/mage/cards/a/AngrathsMarauders.java index e6e12b2eec5..5c1a49af5e5 100644 --- a/Mage.Sets/src/mage/cards/a/AngrathsMarauders.java +++ b/Mage.Sets/src/mage/cards/a/AngrathsMarauders.java @@ -41,6 +41,7 @@ import mage.constants.Outcome; import mage.constants.Zone; import mage.game.Game; import mage.game.events.GameEvent; +import mage.util.CardUtil; /** * @@ -106,7 +107,7 @@ class AngrathsMaraudersEffect extends ReplacementEffectImpl { @Override public boolean replaceEvent(GameEvent event, Ability source, Game game) { - event.setAmount(2 * event.getAmount()); + event.setAmount(CardUtil.addWithOverflowCheck(event.getAmount(), event.getAmount())); return false; } } diff --git a/Mage.Sets/src/mage/cards/a/AnthemOfRakdos.java b/Mage.Sets/src/mage/cards/a/AnthemOfRakdos.java index 068b806cfb4..c3ec17a4179 100644 --- a/Mage.Sets/src/mage/cards/a/AnthemOfRakdos.java +++ b/Mage.Sets/src/mage/cards/a/AnthemOfRakdos.java @@ -44,6 +44,7 @@ import mage.constants.Outcome; import mage.constants.Zone; import mage.game.Game; import mage.game.events.GameEvent; +import mage.util.CardUtil; /** * @author JotaPeRL @@ -110,7 +111,7 @@ class AnthemOfRakdosHellbentEffect extends ReplacementEffectImpl { @Override public boolean replaceEvent(GameEvent event, Ability source, Game game) { - event.setAmount(event.getAmount() * 2); + event.setAmount(CardUtil.addWithOverflowCheck(event.getAmount(), event.getAmount())); return false; } } diff --git a/Mage.Sets/src/mage/cards/a/ArlinnEmbracedByTheMoon.java b/Mage.Sets/src/mage/cards/a/ArlinnEmbracedByTheMoon.java index 2904b7e803b..793ed6ffbd3 100644 --- a/Mage.Sets/src/mage/cards/a/ArlinnEmbracedByTheMoon.java +++ b/Mage.Sets/src/mage/cards/a/ArlinnEmbracedByTheMoon.java @@ -43,7 +43,7 @@ import mage.constants.CardType; import mage.constants.Duration; import mage.constants.SubType; import mage.constants.SuperType; -import mage.filter.common.FilterCreaturePermanent; +import mage.filter.StaticFilters; import mage.game.command.emblems.ArlinnEmbracedByTheMoonEmblem; import mage.target.common.TargetCreatureOrPlayer; @@ -53,8 +53,6 @@ import mage.target.common.TargetCreatureOrPlayer; */ public class ArlinnEmbracedByTheMoon extends CardImpl { - private static final FilterCreaturePermanent filter = new FilterCreaturePermanent("Creatures you control"); - public ArlinnEmbracedByTheMoon(UUID ownerId, CardSetInfo setInfo) { super(ownerId, setInfo, new CardType[]{CardType.PLANESWALKER}, ""); this.addSuperType(SuperType.LEGENDARY); @@ -66,10 +64,10 @@ public class ArlinnEmbracedByTheMoon extends CardImpl { this.transformable = true; // +1: Creatures you control get +1/+1 and gain trample until end of turn. - Effect effect = new BoostControlledEffect(1, 1, Duration.EndOfTurn, filter); + Effect effect = new BoostControlledEffect(1, 1, Duration.EndOfTurn, StaticFilters.FILTER_PERMANENT_CREATURE); effect.setText("Creatures you control get +1/+1"); LoyaltyAbility ability = new LoyaltyAbility(effect, 1); - effect = new GainAbilityControlledEffect(TrampleAbility.getInstance(), Duration.EndOfTurn, filter); + effect = new GainAbilityControlledEffect(TrampleAbility.getInstance(), Duration.EndOfTurn, StaticFilters.FILTER_PERMANENT_CREATURE); effect.setText("and gain trample until end of turn"); ability.addEffect(effect); this.addAbility(ability); diff --git a/Mage.Sets/src/mage/cards/a/AshnodsCylix.java b/Mage.Sets/src/mage/cards/a/AshnodsCylix.java new file mode 100644 index 00000000000..fd11615bf38 --- /dev/null +++ b/Mage.Sets/src/mage/cards/a/AshnodsCylix.java @@ -0,0 +1,125 @@ +/* + * 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.abilities.Ability; +import mage.abilities.common.SimpleActivatedAbility; +import mage.abilities.costs.Cost; +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.game.Game; +import mage.game.permanent.Permanent; +import mage.players.Player; +import mage.target.Target; +import mage.target.TargetCard; +import mage.target.TargetPlayer; + +/** + * + * @author L_J + */ +public class AshnodsCylix extends CardImpl { + + public AshnodsCylix(UUID ownerId, CardSetInfo setInfo) { + super(ownerId,setInfo,new CardType[]{CardType.ARTIFACT},"{2}"); + + // {3}, {T}: Target player looks at the top three cards of his or her library, puts one of them back on top of his or her library, then exiles the rest. + SimpleActivatedAbility ability = new SimpleActivatedAbility(Zone.BATTLEFIELD, new AshnodsCylixEffect(), new GenericManaCost(3)); + ability.addCost(new TapSourceCost()); + ability.addTarget(new TargetPlayer()); + this.addAbility(ability); + } + + public AshnodsCylix(final AshnodsCylix card) { + super(card); + } + + @Override + public AshnodsCylix copy() { + return new AshnodsCylix(this); + } +} + +class AshnodsCylixEffect extends OneShotEffect { + + AshnodsCylixEffect() { + super(Outcome.Benefit); + this.staticText = "Target player looks at the top three cards of his or her library, puts one of them back on top of his or her library, then exiles the rest"; + } + + AshnodsCylixEffect(final AshnodsCylixEffect effect) { + super(effect); + } + + @Override + public AshnodsCylixEffect copy() { + return new AshnodsCylixEffect(this); + } + + @Override + public boolean apply(Game game, Ability source) { + Player player = game.getPlayer(source.getFirstTarget()); + if (player == null) { + return false; + } + Cards cards = new CardsImpl(); + int count = Math.min(player.getLibrary().size(), 3); + for (int i = 0; i < count; i++) { + Card card = player.getLibrary().removeFromTop(game); + if (card != null) { + cards.add(card); + } + } + //~ player.revealCards(source.getSourceObject(game).getIdName(), cards, game); + TargetCard target = new TargetCard(Zone.LIBRARY, new FilterCard("card to put on top of your library")); + if (player.choose(Outcome.DrawCard, cards, target, game)) { + Card card = cards.get(target.getFirstTarget(), game); + if (card != null) { + cards.remove(card); + player.getLibrary().putOnTop(card, game); + game.informPlayers(source.getSourceObject(game).getIdName() + ": " + player.getLogName() + " puts a card on top of his or her library"); + } + } + 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/a/AugurOfBolas.java b/Mage.Sets/src/mage/cards/a/AugurOfBolas.java index e0e3b2b31dd..5d626a7210f 100644 --- a/Mage.Sets/src/mage/cards/a/AugurOfBolas.java +++ b/Mage.Sets/src/mage/cards/a/AugurOfBolas.java @@ -44,7 +44,6 @@ import mage.filter.predicate.Predicates; import mage.filter.predicate.mageobject.CardTypePredicate; import mage.game.Game; import mage.players.Player; -import mage.target.Target; import mage.target.TargetCard; /** @@ -113,8 +112,8 @@ class AugurOfBolasEffect extends OneShotEffect { if (number == 1) { card = topCards.getCards(new FilterInstantOrSorceryCard(), source.getSourceId(), source.getControllerId(), game).iterator().next(); } else { - Target target = new TargetCard(Zone.LIBRARY, new FilterInstantOrSorceryCard()); - controller.chooseTarget(outcome, target, source, game); + TargetCard target = new TargetCard(Zone.LIBRARY, new FilterInstantOrSorceryCard()); + controller.chooseTarget(outcome, topCards, target, source, game); card = topCards.get(target.getFirstTarget(), game); } if (card != null) { diff --git a/Mage.Sets/src/mage/cards/b/BitterFeud.java b/Mage.Sets/src/mage/cards/b/BitterFeud.java index 5297a739da0..e7d64955514 100644 --- a/Mage.Sets/src/mage/cards/b/BitterFeud.java +++ b/Mage.Sets/src/mage/cards/b/BitterFeud.java @@ -47,6 +47,7 @@ import mage.game.permanent.Permanent; import mage.game.stack.StackObject; import mage.players.Player; import mage.target.TargetPlayer; +import mage.util.CardUtil; /** * @@ -194,7 +195,7 @@ class BitterFeudEffect extends ReplacementEffectImpl { @Override public boolean replaceEvent(GameEvent event, Ability source, Game game) { - event.setAmount(event.getAmount() * 2); + event.setAmount(CardUtil.addWithOverflowCheck(event.getAmount(), event.getAmount())); return false; } } diff --git a/Mage.Sets/src/mage/cards/b/BlatantThievery.java b/Mage.Sets/src/mage/cards/b/BlatantThievery.java index bd64506d75c..85c0c6b8645 100644 --- a/Mage.Sets/src/mage/cards/b/BlatantThievery.java +++ b/Mage.Sets/src/mage/cards/b/BlatantThievery.java @@ -28,7 +28,6 @@ package mage.cards.b; import java.util.*; -import mage.MageObject; import mage.abilities.Ability; import mage.abilities.SpellAbility; import mage.abilities.effects.ContinuousEffect; @@ -40,8 +39,10 @@ import mage.constants.CardType; import mage.constants.Duration; import mage.constants.Outcome; import mage.filter.FilterPermanent; +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.targetpointer.FixedTarget; @@ -52,7 +53,7 @@ import mage.target.targetpointer.FixedTarget; public class BlatantThievery extends CardImpl { public BlatantThievery(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.SORCERY},"{4}{U}{U}{U}"); + super(ownerId, setInfo, new CardType[]{CardType.SORCERY}, "{4}{U}{U}{U}"); // For each opponent, gain control of target permanent that player controls. this.getSpellAbility().addEffect(new BlatantThieveryEffect()); @@ -66,7 +67,15 @@ public class BlatantThievery extends CardImpl { public void adjustTargets(Ability ability, Game game) { if (ability instanceof SpellAbility) { ability.getTargets().clear(); - ability.addTarget(new BlatantThieveryTarget(game.getOpponents(ability.getControllerId()).size())); + for (UUID opponentId : game.getOpponents(ability.getControllerId())) { + Player opponent = game.getPlayer(opponentId); + if (opponent != null) { + FilterPermanent filter = new FilterPermanent("Permanent of player " + opponent.getName()); + filter.add(new ControllerIdPredicate(opponentId)); + TargetPermanent targetPermanent = new TargetPermanent(filter); + ability.addTarget(targetPermanent); + } + } } } @@ -94,117 +103,13 @@ class BlatantThieveryEffect extends OneShotEffect { @Override public boolean apply(Game game, Ability source) { - for (UUID targetId : getTargetPointer().getTargets(game, source)) { - ContinuousEffect effect = new GainControlTargetEffect(Duration.EndOfGame); - effect.setTargetPointer(new FixedTarget(targetId)); - game.addEffect(effect, source); - } - return true; - } -} - -class BlatantThieveryTarget extends TargetPermanent { - - Map targetOpponent = new HashMap<>(); - - public BlatantThieveryTarget(int opponents) { - super(opponents, opponents, new FilterPermanent("a permanent for each opponent"), false); - } - - public BlatantThieveryTarget(final BlatantThieveryTarget target) { - super(target); - this.targetOpponent.putAll(target.targetOpponent); - } - - @Override - public boolean canTarget(UUID controllerId, UUID objectId, Ability source, Game game) { - Permanent targetObject = game.getPermanent(objectId); - if (targetObject == null || !game.getOpponents(source.getControllerId()).contains(targetObject.getControllerId())) { - return false; - } - // If a permanent changes controller after being targeted but before this spell resolves, you won't gain control of that permanent. - if (targetOpponent.containsKey(objectId)) { - if (!targetOpponent.get(objectId).equals(targetObject.getControllerId())) { - return false; - } - } else { - // if already a target from this opponent exists, another can't be target - if (targetOpponent.values().contains(targetObject.getControllerId())) { - return false; - } - } - return super.canTarget(controllerId, objectId, source, game); - } - - @Override - public Set possibleTargets(UUID sourceId, UUID sourceControllerId, Game game) { - Set opponents = new HashSet<>(); - for (UUID targetId : getTargets()) { - Permanent oldTargets = game.getPermanent(targetId); - if (oldTargets != null) { - opponents.add(oldTargets.getControllerId()); - } - } - Set possibleTargets = new HashSet<>(); - MageObject mageObject = game.getObject(sourceId); - if (mageObject == null) { - return possibleTargets; - } - for (UUID opponentId : game.getOpponents(sourceControllerId)) { - if (opponents.contains(opponentId)) { - // Target for this opponent already selected - continue; - } - for (Permanent permanent : game.getBattlefield().getAllActivePermanents(opponentId)) { - if (permanent.canBeTargetedBy(mageObject, sourceControllerId, game)) { - possibleTargets.add(permanent.getId()); - } - } - } - return possibleTargets; - } - - @Override - public boolean canChoose(UUID sourceId, UUID sourceControllerId, Game game) { - for (UUID opponentId : game.getOpponents(sourceControllerId)) { - boolean targetAvailable = false; - for (Permanent permanent : game.getBattlefield().getAllActivePermanents(opponentId)) { - if (!targets.containsKey(permanent.getId())) { - MageObject mageObject = game.getObject(sourceId); - if (mageObject != null && permanent.canBeTargetedBy(mageObject, sourceControllerId, game)) { - targetAvailable = true; - break; - } - - } else { - targetAvailable = true; - break; - } - } - if (!targetAvailable) { - return false; + for (Target target : source.getTargets()) { + if (target.getFirstTarget() != null) { + ContinuousEffect effect = new GainControlTargetEffect(Duration.EndOfGame); + effect.setTargetPointer(new FixedTarget(target.getFirstTarget())); + game.addEffect(effect, source); } } return true; } - - @Override - public void addTarget(UUID objectId, int amount, Ability source, Game game, boolean skipEvent) { - Permanent targetObject = game.getPermanent(objectId); - if (targetObject != null) { - targetOpponent.put(objectId, targetObject.getControllerId()); - } - super.addTarget(objectId, amount, source, game, skipEvent); - } - - @Override - public void remove(UUID id) { - super.remove(id); - targetOpponent.remove(id); - } - - @Override - public BlatantThieveryTarget copy() { - return new BlatantThieveryTarget(this); - } } diff --git a/Mage.Sets/src/mage/cards/b/BrandedBrawlers.java b/Mage.Sets/src/mage/cards/b/BrandedBrawlers.java new file mode 100644 index 00000000000..83553cefb51 --- /dev/null +++ b/Mage.Sets/src/mage/cards/b/BrandedBrawlers.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.b; + +import java.util.UUID; +import mage.MageInt; +import mage.abilities.Ability; +import mage.abilities.common.SimpleStaticAbility; +import mage.abilities.effects.RestrictionEffect; +import mage.abilities.effects.common.combat.CantAttackIfDefenderControlsPermanent; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.SubType; +import mage.constants.Duration; +import mage.constants.Zone; +import mage.filter.FilterPermanent; +import mage.filter.common.FilterLandPermanent; +import mage.filter.predicate.Predicates; +import mage.filter.predicate.permanent.TappedPredicate; +import mage.game.Game; +import mage.game.permanent.Permanent; +import mage.players.Player; + +/** + * @author L_J + */ +public class BrandedBrawlers extends CardImpl { + + static final private FilterLandPermanent filter = new FilterLandPermanent("an untapped land"); + static { + filter.add(Predicates.not(new TappedPredicate())); + } + + final static private String rule = "{this} can't block if you control an untapped land"; + + public BrandedBrawlers(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{R}"); + this.subtype.add(SubType.HUMAN); + this.subtype.add(SubType.SOLDIER); + this.power = new MageInt(2); + this.toughness = new MageInt(2); + + // Branded Brawlers can't attack if defending player controls an untapped land. + this.addAbility(new SimpleStaticAbility(Zone.BATTLEFIELD, new CantAttackIfDefenderControlsPermanent(filter))); + + // Branded Brawlers can't block if you control an untapped land. + this.addAbility(new SimpleStaticAbility(Zone.BATTLEFIELD, new BrandedBrawlersCantBlockEffect(filter))); + } + + public BrandedBrawlers(final BrandedBrawlers card) { + super(card); + } + + @Override + public BrandedBrawlers copy() { + return new BrandedBrawlers(this); + } +} + +class BrandedBrawlersCantBlockEffect extends RestrictionEffect { + + private final FilterPermanent filter; + + public BrandedBrawlersCantBlockEffect(FilterPermanent filter) { + super(Duration.WhileOnBattlefield); + this.filter = filter; + staticText = new StringBuilder("{this} can't attack if you control ").append(filter.getMessage()).toString(); + } + + public BrandedBrawlersCantBlockEffect(final BrandedBrawlersCantBlockEffect effect) { + super(effect); + this.filter = effect.filter; + } + + @Override + public boolean applies(Permanent permanent, Ability source, Game game) { + return permanent.getId().equals(source.getSourceId()); + } + + @Override + public boolean canBlock(Permanent attacker, Permanent blocker, Ability source, Game game) { + Player player = game.getPlayer(blocker.getControllerId()); + if (player != null) { + if (game.getBattlefield().countAll(filter, player.getId(), game) > 0) { + return false; + } + } + return true; + } + + @Override + public BrandedBrawlersCantBlockEffect copy() { + return new BrandedBrawlersCantBlockEffect(this); + } + +} diff --git a/Mage.Sets/src/mage/cards/b/ButcherOrgg.java b/Mage.Sets/src/mage/cards/b/ButcherOrgg.java new file mode 100644 index 00000000000..f12cd58780a --- /dev/null +++ b/Mage.Sets/src/mage/cards/b/ButcherOrgg.java @@ -0,0 +1,63 @@ +/* + * 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.b; + +import java.util.UUID; +import mage.MageInt; +import mage.abilities.common.ControllerDivideCombatDamageAbility; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.SubType; + +/** + * + * @author L_J + */ +public class ButcherOrgg extends CardImpl { + + public ButcherOrgg(UUID ownerId, CardSetInfo setInfo) { + super(ownerId,setInfo,new CardType[]{CardType.CREATURE},"{4}{R}{R}{R}"); + this.subtype.add(SubType.ORGG); + + this.power = new MageInt(6); + this.toughness = new MageInt(6); + + // You may assign Butcher Orgg's combat damage divided as you choose among defending player and/or any number of creatures he or she controls. + this.addAbility(ControllerDivideCombatDamageAbility.getInstance()); + } + + public ButcherOrgg(final ButcherOrgg card) { + super(card); + } + + @Override + public ButcherOrgg copy() { + return new ButcherOrgg(this); + } +} diff --git a/Mage.Sets/src/mage/cards/c/CallousOppressor.java b/Mage.Sets/src/mage/cards/c/CallousOppressor.java new file mode 100644 index 00000000000..63acbd3c2e1 --- /dev/null +++ b/Mage.Sets/src/mage/cards/c/CallousOppressor.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.c; + +import java.util.LinkedHashSet; +import java.util.UUID; +import java.util.stream.Collectors; +import mage.MageInt; +import mage.MageObject; +import mage.abilities.Ability; +import mage.abilities.common.AsEntersBattlefieldAbility; +import mage.abilities.common.SimpleActivatedAbility; +import mage.abilities.common.SkipUntapOptionalAbility; +import mage.abilities.condition.common.SourceTappedCondition; +import mage.abilities.costs.common.TapSourceCost; +import mage.abilities.decorator.ConditionalContinuousEffect; +import mage.abilities.effects.OneShotEffect; +import mage.abilities.effects.common.continuous.GainControlTargetEffect; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.choices.Choice; +import mage.choices.ChoiceImpl; +import mage.constants.CardType; +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.permanent.Permanent; +import mage.players.Player; +import mage.target.common.TargetCreaturePermanent; +import mage.target.common.TargetOpponent; +import mage.util.CardUtil; + +/** + * + * @author L_J + */ +public class CallousOppressor extends CardImpl { + + public CallousOppressor(UUID ownerId, CardSetInfo setInfo) { + super(ownerId,setInfo,new CardType[]{CardType.CREATURE},"{1}{U}{U}"); + this.subtype.add(SubType.CEPHALID); + this.power = new MageInt(1); + this.toughness = new MageInt(2); + + // You may choose not to untap Callous Oppressor during your untap step. + this.addAbility(new SkipUntapOptionalAbility()); + + // As Callous Oppressor enters the battlefield, an opponent chooses a creature type. + this.addAbility(new AsEntersBattlefieldAbility(new CallousOppressorChooseCreatureTypeEffect())); + + // {T}: Gain control of target creature that isn't of the chosen type for as long as Callous Oppressor remains tapped. + ConditionalContinuousEffect effect = new ConditionalContinuousEffect( + new GainControlTargetEffect(Duration.OneUse), + SourceTappedCondition.instance, + "Gain control of target creature for as long as {this} remains tapped"); + Ability ability = new SimpleActivatedAbility(Zone.BATTLEFIELD, effect, new TapSourceCost()); + ability.addTarget(new TargetCreaturePermanent(new CallousOppressorFilter())); + this.addAbility(ability); + } + + public CallousOppressor(final CallousOppressor card) { + super(card); + } + + @Override + public CallousOppressor copy() { + return new CallousOppressor(this); + } +} + +class CallousOppressorFilter extends FilterCreaturePermanent { + + public CallousOppressorFilter() { + super("creature that isn't of the chosen type"); + } + + public CallousOppressorFilter(final CallousOppressorFilter filter) { + super(filter); + } + + @Override + public CallousOppressorFilter copy() { + return new CallousOppressorFilter(this); + } + + @Override + public boolean match(Permanent permanent, UUID sourceId, UUID playerId, Game game) { + if (super.match(permanent, sourceId, playerId, game)) { + SubType subtype = (SubType) game.getState().getValue(sourceId + "_type"); + if (subtype != null && permanent.hasSubtype(subtype, game)) { + return false; + } + return true; + } + return false; + } + +} + +class CallousOppressorChooseCreatureTypeEffect extends OneShotEffect { + + public CallousOppressorChooseCreatureTypeEffect() { + super(Outcome.Benefit); + staticText = "an opponent chooses a creature type"; + } + + public CallousOppressorChooseCreatureTypeEffect(final CallousOppressorChooseCreatureTypeEffect effect) { + super(effect); + } + + @Override + public boolean apply(Game game, Ability source) { + Player controller = game.getPlayer(source.getControllerId()); + MageObject mageObject = game.getPermanentEntering(source.getSourceId()); + if (mageObject == null) { + mageObject = game.getObject(source.getSourceId()); + } + if (controller != null) { + TargetOpponent 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); + } + } else { + return false; + } + Player opponent = game.getPlayer(target.getFirstTarget()); + if (opponent != null && mageObject != null) { + Choice typeChoice = new ChoiceImpl(true); + typeChoice.setMessage("Choose creature type"); + typeChoice.setChoices(SubType.getCreatureTypes(false).stream().map(SubType::toString).collect(Collectors.toCollection(LinkedHashSet::new))); + while (!opponent.choose(outcome, typeChoice, game)) { + if (!opponent.canRespond()) { + return false; + } + } + if (typeChoice.getChoice() == null) { + return false; + } + if (!game.isSimulation()) { + game.informPlayers(mageObject.getName() + ": " + opponent.getLogName() + " has chosen " + typeChoice.getChoice()); + } + game.getState().setValue(mageObject.getId() + "_type", SubType.byDescription(typeChoice.getChoice())); + if (mageObject instanceof Permanent) { + ((Permanent) mageObject).addInfo("chosen type", CardUtil.addToolTipMarkTags("Chosen type: " + typeChoice.getChoice()), game); + } + return true; + } + } + return false; + } + + @Override + public CallousOppressorChooseCreatureTypeEffect copy() { + return new CallousOppressorChooseCreatureTypeEffect(this); + } + +} diff --git a/Mage.Sets/src/mage/cards/c/CaptainsHook.java b/Mage.Sets/src/mage/cards/c/CaptainsHook.java new file mode 100644 index 00000000000..20df6b3c6cf --- /dev/null +++ b/Mage.Sets/src/mage/cards/c/CaptainsHook.java @@ -0,0 +1,90 @@ +/* + * 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.SimpleStaticAbility; +import mage.abilities.common.UnattachedTriggeredAbility; +import mage.abilities.costs.mana.GenericManaCost; +import mage.abilities.effects.Effect; +import mage.abilities.effects.common.DestroyEquippedEffect; +import mage.abilities.effects.common.continuous.AddCardSubtypeAttachedEffect; +import mage.abilities.effects.common.continuous.BoostEquippedEffect; +import mage.abilities.effects.common.continuous.GainAbilityAttachedEffect; +import mage.abilities.keyword.EquipAbility; +import mage.abilities.keyword.MenaceAbility; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.AttachmentType; +import mage.constants.CardType; +import mage.constants.Duration; +import mage.constants.Outcome; +import mage.constants.SubType; +import mage.constants.Zone; + +/** + * + * @author LevelX2 + */ +public class CaptainsHook extends CardImpl { + + public CaptainsHook(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.ARTIFACT}, "{3}"); + + this.subtype.add(SubType.EQUIPMENT); + + // Equipped creature gets +2/+0 + Effect effect = new BoostEquippedEffect(2, 0); + effect.setText("Equipped creature gets +2/+0"); + Ability ability = new SimpleStaticAbility(Zone.BATTLEFIELD, effect); + // has menace, + effect = new GainAbilityAttachedEffect(new MenaceAbility(), AttachmentType.EQUIPMENT); + effect.setText(", has menace"); + ability.addEffect(effect); + //, and is a Pirate in addition to its other creature types + effect = new AddCardSubtypeAttachedEffect(SubType.PIRATE, Duration.WhileOnBattlefield, AttachmentType.EQUIPMENT); + effect.setText(", and is a Pirate in addition to its other creature types"); + ability.addEffect(effect); + this.addAbility(ability); + // Whenever Captain's Hook becomes unattached from a permanent, destroy that permanent. + this.addAbility(new UnattachedTriggeredAbility(new DestroyEquippedEffect(), false)); + + // Equip {1} + this.addAbility(new EquipAbility(Outcome.BoostCreature, new GenericManaCost(1))); + } + + public CaptainsHook(final CaptainsHook card) { + super(card); + } + + @Override + public CaptainsHook copy() { + return new CaptainsHook(this); + } +} diff --git a/Mage.Sets/src/mage/cards/c/ChannelHarm.java b/Mage.Sets/src/mage/cards/c/ChannelHarm.java index df072718ee6..9123edb2340 100644 --- a/Mage.Sets/src/mage/cards/c/ChannelHarm.java +++ b/Mage.Sets/src/mage/cards/c/ChannelHarm.java @@ -41,6 +41,7 @@ import mage.game.Controllable; import mage.game.Game; import mage.game.events.GameEvent; import mage.game.permanent.Permanent; +import mage.players.Player; import mage.target.common.TargetCreaturePermanent; /** @@ -90,11 +91,14 @@ class ChannelHarmEffect extends PreventionEffectImpl { @Override public boolean replaceEvent(GameEvent event, Ability source, Game game) { + Player sourceController = game.getPlayer(source.getControllerId()); PreventionEffectData preventionData = preventDamageAction(event, source, game); if (preventionData.getPreventedDamage() > 0) { Permanent targetCreature = game.getPermanent(source.getFirstTarget()); if (targetCreature != null) { - targetCreature.damage(preventionData.getPreventedDamage(), source.getSourceId(), game, false, true); + if (sourceController != null && sourceController.chooseUse(outcome, "Would you like to have " + preventionData.getPreventedDamage() + " damage dealt to " + targetCreature.getLogName() + "?", source, game)) { + targetCreature.damage(preventionData.getPreventedDamage(), source.getSourceId(), game, false, true); + } } } return true; diff --git a/Mage.Sets/src/mage/cards/c/CurseOfBloodletting.java b/Mage.Sets/src/mage/cards/c/CurseOfBloodletting.java index 941df4792e3..14a92b7d164 100644 --- a/Mage.Sets/src/mage/cards/c/CurseOfBloodletting.java +++ b/Mage.Sets/src/mage/cards/c/CurseOfBloodletting.java @@ -27,6 +27,7 @@ */ package mage.cards.c; +import java.util.UUID; import mage.abilities.Ability; import mage.abilities.common.SimpleStaticAbility; import mage.abilities.effects.ReplacementEffectImpl; @@ -39,8 +40,7 @@ import mage.game.Game; import mage.game.events.GameEvent; import mage.game.permanent.Permanent; import mage.target.TargetPlayer; - -import java.util.UUID; +import mage.util.CardUtil; /** * @@ -112,8 +112,8 @@ class CurseOfBloodlettingEffect extends ReplacementEffectImpl { @Override public boolean replaceEvent(GameEvent event, Ability source, Game game) { - event.setAmount(event.getAmount() * 2); + event.setAmount(CardUtil.addWithOverflowCheck(event.getAmount(), event.getAmount())); return false; } -} \ No newline at end of file +} diff --git a/Mage.Sets/src/mage/cards/d/DeathCharmer.java b/Mage.Sets/src/mage/cards/d/DeathCharmer.java new file mode 100644 index 00000000000..d8873abbae4 --- /dev/null +++ b/Mage.Sets/src/mage/cards/d/DeathCharmer.java @@ -0,0 +1,66 @@ +/* + * 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.MageInt; +import mage.abilities.common.DealsCombatDamageToACreatureTriggeredAbility; +import mage.abilities.costs.mana.ManaCostsImpl; +import mage.abilities.effects.common.DoUnlessTargetPlayerOrTargetsControllerPaysEffect; +import mage.abilities.effects.common.LoseLifeTargetControllerEffect; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.SubType; + +/** + * + * @author L_J + */ +public class DeathCharmer extends CardImpl { + + public DeathCharmer(UUID ownerId, CardSetInfo setInfo) { + super(ownerId,setInfo,new CardType[]{CardType.CREATURE},"{2}{B}"); + this.subtype.add(SubType.WORM); + this.subtype.add(SubType.MERCENARY); + this.power = new MageInt(2); + this.toughness = new MageInt(2); + + // Whenever Death Charmer deals combat damage to a creature, that creature's controller loses 2 life unless he or she pays {2}. + this.addAbility(new DealsCombatDamageToACreatureTriggeredAbility(new DoUnlessTargetPlayerOrTargetsControllerPaysEffect(new LoseLifeTargetControllerEffect(2), new ManaCostsImpl("{2}")), false, true)); + } + + public DeathCharmer(final DeathCharmer card) { + super(card); + } + + @Override + public DeathCharmer copy() { + return new DeathCharmer(this); + } +} diff --git a/Mage.Sets/src/mage/cards/d/DesperateGambit.java b/Mage.Sets/src/mage/cards/d/DesperateGambit.java index 1272b4c7291..3dde02e293d 100644 --- a/Mage.Sets/src/mage/cards/d/DesperateGambit.java +++ b/Mage.Sets/src/mage/cards/d/DesperateGambit.java @@ -49,6 +49,7 @@ import mage.filter.FilterObject; import mage.filter.predicate.permanent.ControllerPredicate; import mage.players.Player; import mage.target.TargetSource; +import mage.util.CardUtil; /** * @@ -129,7 +130,7 @@ class DesperateGambitEffect extends PreventionEffectImpl { if (controller != null && object != null) { if (super.applies(event, source, game) && event instanceof DamageEvent && event.getAmount() > 0) { if (wonFlip) { - event.setAmount(event.getAmount() * 2); + event.setAmount(CardUtil.addWithOverflowCheck(event.getAmount(), event.getAmount())); this.discard(); } else { preventDamageAction(event, source, game); diff --git a/Mage.Sets/src/mage/cards/d/DictateOfTheTwinGods.java b/Mage.Sets/src/mage/cards/d/DictateOfTheTwinGods.java index 8e4814dbcd9..8b57e8b53a2 100644 --- a/Mage.Sets/src/mage/cards/d/DictateOfTheTwinGods.java +++ b/Mage.Sets/src/mage/cards/d/DictateOfTheTwinGods.java @@ -44,6 +44,7 @@ import mage.game.events.GameEvent; import mage.game.events.GameEvent.EventType; import mage.game.permanent.Permanent; import mage.players.Player; +import mage.util.CardUtil; /** * @@ -115,13 +116,13 @@ class DictateOfTheTwinGodsEffect extends ReplacementEffectImpl { if (damageEvent.getType() == EventType.DAMAGE_PLAYER) { Player targetPlayer = game.getPlayer(event.getTargetId()); if (targetPlayer != null) { - targetPlayer.damage(damageEvent.getAmount() * 2, damageEvent.getSourceId(), game, damageEvent.isCombatDamage(), damageEvent.isPreventable(), event.getAppliedEffects()); + targetPlayer.damage(CardUtil.addWithOverflowCheck(damageEvent.getAmount(), damageEvent.getAmount()), damageEvent.getSourceId(), game, damageEvent.isCombatDamage(), damageEvent.isPreventable(), event.getAppliedEffects()); return true; } } else { Permanent targetPermanent = game.getPermanent(event.getTargetId()); if (targetPermanent != null) { - targetPermanent.damage(damageEvent.getAmount() * 2, damageEvent.getSourceId(), game, damageEvent.isCombatDamage(), damageEvent.isPreventable(), event.getAppliedEffects()); + targetPermanent.damage(CardUtil.addWithOverflowCheck(damageEvent.getAmount(), damageEvent.getAmount()), damageEvent.getSourceId(), game, damageEvent.isCombatDamage(), damageEvent.isPreventable(), event.getAppliedEffects()); return true; } } diff --git a/Mage.Sets/src/mage/cards/d/DoomCannon.java b/Mage.Sets/src/mage/cards/d/DoomCannon.java new file mode 100644 index 00000000000..383bf31b35b --- /dev/null +++ b/Mage.Sets/src/mage/cards/d/DoomCannon.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.d; + +import java.util.UUID; +import mage.abilities.Ability; +import mage.abilities.common.AsEntersBattlefieldAbility; +import mage.abilities.common.SimpleActivatedAbility; +import mage.abilities.costs.common.SacrificeTargetCost; +import mage.abilities.costs.common.TapSourceCost; +import mage.abilities.costs.mana.GenericManaCost; +import mage.abilities.effects.common.ChooseCreatureTypeEffect; +import mage.abilities.effects.common.DamageTargetEffect; +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.common.FilterControlledCreaturePermanent; +import mage.game.Game; +import mage.game.permanent.Permanent; +import mage.target.common.TargetControlledCreaturePermanent; +import mage.target.common.TargetCreatureOrPlayer; + +/** + * + * @author L_J + */ +public class DoomCannon extends CardImpl { + + public DoomCannon(UUID ownerId, CardSetInfo setInfo) { + super(ownerId,setInfo,new CardType[]{CardType.ARTIFACT},"{6}"); + + // As Doom Cannon enters the battlefield, choose a creature type. + this.addAbility(new AsEntersBattlefieldAbility(new ChooseCreatureTypeEffect(Outcome.Sacrifice))); + + // {3}, {T}, Sacrifice a creature of the chosen type: Doom Cannon deals 3 damage to target creature or player. + Ability ability = new SimpleActivatedAbility(Zone.BATTLEFIELD, new DamageTargetEffect(3), new GenericManaCost(3)); + ability.addCost(new TapSourceCost()); + ability.addCost(new SacrificeTargetCost(new TargetControlledCreaturePermanent(new DoomCannonFilter()))); + ability.addTarget(new TargetCreatureOrPlayer()); + this.addAbility(ability); + } + + public DoomCannon(final DoomCannon card) { + super(card); + } + + @Override + public DoomCannon copy() { + return new DoomCannon(this); + } +} + +class DoomCannonFilter extends FilterControlledCreaturePermanent { + + public DoomCannonFilter() { + super("a creature of the chosen type"); + } + + public DoomCannonFilter(final DoomCannonFilter filter) { + super(filter); + } + + @Override + public DoomCannonFilter copy() { + return new DoomCannonFilter(this); + } + + @Override + public boolean match(Permanent permanent, UUID sourceId, UUID playerId, Game game) { + if (super.match(permanent, sourceId, playerId, game)) { + SubType subtype = (SubType) game.getState().getValue(sourceId + "_type"); + if (subtype != null && permanent.hasSubtype(subtype, game)) { + return true; + } + } + return false; + } + +} diff --git a/Mage.Sets/src/mage/cards/d/Dracoplasm.java b/Mage.Sets/src/mage/cards/d/Dracoplasm.java index e378fc79986..1ccf4cfbe01 100644 --- a/Mage.Sets/src/mage/cards/d/Dracoplasm.java +++ b/Mage.Sets/src/mage/cards/d/Dracoplasm.java @@ -50,6 +50,7 @@ import mage.game.permanent.Permanent; import mage.players.Player; import mage.target.Target; import mage.target.common.TargetControlledPermanent; +import mage.util.CardUtil; /** * @@ -131,8 +132,8 @@ class DracoplasmEffect extends ReplacementEffectImpl { for (UUID targetId : target.getTargets()) { Permanent targetCreature = game.getPermanent(targetId); if (targetCreature != null && targetCreature.sacrifice(source.getSourceId(), game)) { - power += targetCreature.getPower().getValue(); - toughness += targetCreature.getToughness().getValue(); + power = CardUtil.addWithOverflowCheck(power, targetCreature.getPower().getValue()); + toughness = CardUtil.addWithOverflowCheck(toughness, targetCreature.getToughness().getValue()); } } ContinuousEffect effect = new SetPowerToughnessSourceEffect(power, toughness, Duration.Custom, SubLayer.SetPT_7b); @@ -141,4 +142,4 @@ class DracoplasmEffect extends ReplacementEffectImpl { } return false; } -} \ No newline at end of file +} diff --git a/Mage.Sets/src/mage/cards/e/EmbermawHellion.java b/Mage.Sets/src/mage/cards/e/EmbermawHellion.java index 641091b6fc6..9a7957cf5f3 100644 --- a/Mage.Sets/src/mage/cards/e/EmbermawHellion.java +++ b/Mage.Sets/src/mage/cards/e/EmbermawHellion.java @@ -44,6 +44,7 @@ import mage.constants.Zone; import mage.game.Game; import mage.game.events.GameEvent; import mage.game.permanent.Permanent; +import mage.util.CardUtil; /** * @@ -120,7 +121,7 @@ class EmbermawHellionEffect extends ReplacementEffectImpl { @Override public boolean replaceEvent(GameEvent event, Ability source, Game game) { - event.setAmount(event.getAmount() + 1); + event.setAmount(CardUtil.addWithOverflowCheck(event.getAmount(), 1)); return false; } diff --git a/Mage.Sets/src/mage/cards/e/EntrailsFeaster.java b/Mage.Sets/src/mage/cards/e/EntrailsFeaster.java new file mode 100644 index 00000000000..a446dd82ad2 --- /dev/null +++ b/Mage.Sets/src/mage/cards/e/EntrailsFeaster.java @@ -0,0 +1,124 @@ +/* + * 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.MageInt; +import mage.abilities.Ability; +import mage.abilities.common.BeginningOfUpkeepTriggeredAbility; +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.TargetController; +import mage.constants.Zone; +import mage.counters.CounterType; +import mage.filter.common.FilterCreatureCard; +import mage.game.Game; +import mage.game.permanent.Permanent; +import mage.players.Player; +import mage.target.common.TargetCardInGraveyard; + +/** + * + * @author L_J + */ +public class EntrailsFeaster extends CardImpl { + + public EntrailsFeaster(UUID ownerId, CardSetInfo setInfo) { + super(ownerId,setInfo,new CardType[]{CardType.CREATURE},"{B}"); + this.subtype.add(SubType.ZOMBIE); + this.subtype.add(SubType.CAT); + this.power = new MageInt(1); + this.toughness = new MageInt(1); + + // At the beginning of your upkeep, you may exile a creature card from a graveyard. If you do, put a +1/+1 counter on Entrails Feaster. If you don't, tap Entrails Feaster. + Ability ability = new BeginningOfUpkeepTriggeredAbility(Zone.BATTLEFIELD, new EntrailsFeasterEffect(), TargetController.YOU, false); + this.addAbility(ability); + + } + + public EntrailsFeaster(final EntrailsFeaster card) { + super(card); + } + + @Override + public EntrailsFeaster copy() { + return new EntrailsFeaster(this); + } +} + +class EntrailsFeasterEffect extends OneShotEffect { + + private static final FilterCreatureCard filter = new FilterCreatureCard("creature card from a graveyard"); + + public EntrailsFeasterEffect() { + super(Outcome.Detriment); + this.staticText = "you may exile a creature card from a graveyard. If you do, put a +1/+1 counter on {this}. If you don't, tap {this}"; + } + + public EntrailsFeasterEffect(final EntrailsFeasterEffect effect) { + super(effect); + } + + @Override + public EntrailsFeasterEffect copy() { + return new EntrailsFeasterEffect(this); + } + + @Override + public boolean apply(Game game, Ability source) { + Player controller = game.getPlayer(source.getControllerId()); + if (controller != null && source.getSourceId() != null) { + Permanent sourceObject = (Permanent) source.getSourceObjectIfItStillExists(game); + TargetCardInGraveyard target = new TargetCardInGraveyard(filter); + target.setNotTarget(true); + if (target.canChoose(source.getSourceId(), controller.getId(), game) && controller.chooseUse(outcome, "Exile a creature card from a graveyard?", source, game)) { + if (controller.choose(Outcome.Exile, target, source.getId(), game)) { + Card cardChosen = game.getCard(target.getFirstTarget()); + if (cardChosen != null) { + controller.moveCardsToExile(cardChosen, source, game, true, null, ""); + if (sourceObject != null) { + sourceObject.getCounters(game).addCounter(CounterType.P1P1.createInstance()); + game.informPlayers(controller.getLogName() + " puts a +1/+1 counter on " + sourceObject.getLogName()); + } + } + } else if (sourceObject != null) { + sourceObject.tap(game); + } + } else if (sourceObject != null) { + sourceObject.tap(game); + } + return true; + } + return false; + } +} diff --git a/Mage.Sets/src/mage/cards/e/Excise.java b/Mage.Sets/src/mage/cards/e/Excise.java new file mode 100644 index 00000000000..e9220d5bb67 --- /dev/null +++ b/Mage.Sets/src/mage/cards/e/Excise.java @@ -0,0 +1,68 @@ +/* + * 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.dynamicvalue.common.ManacostVariableValue; +import mage.abilities.effects.common.DoUnlessTargetPlayerOrTargetsControllerPaysEffect; +import mage.abilities.effects.common.ExileTargetEffect; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.filter.common.FilterCreaturePermanent; +import mage.filter.predicate.permanent.AttackingPredicate; +import mage.target.common.TargetCreaturePermanent; + +/** + * + * @author L_J + */ +public class Excise extends CardImpl { + + private static final FilterCreaturePermanent filter = new FilterCreaturePermanent("attacking creature"); + static { + filter.add(new AttackingPredicate()); + } + + public Excise(UUID ownerId, CardSetInfo setInfo) { + super(ownerId,setInfo,new CardType[]{CardType.INSTANT},"{X}{W}"); + + // Excise target nonwhite attacking creature unless its controller pays {X}. + this.getSpellAbility().addTarget(new TargetCreaturePermanent(filter)); + this.getSpellAbility().addEffect(new DoUnlessTargetPlayerOrTargetsControllerPaysEffect(new ExileTargetEffect(), new ManacostVariableValue())); + } + + public Excise(final Excise card) { + super(card); + } + + @Override + public Excise copy() { + return new Excise(this); + } +} diff --git a/Mage.Sets/src/mage/cards/f/FarrelsMantle.java b/Mage.Sets/src/mage/cards/f/FarrelsMantle.java index 380f184ab96..e24f2981817 100644 --- a/Mage.Sets/src/mage/cards/f/FarrelsMantle.java +++ b/Mage.Sets/src/mage/cards/f/FarrelsMantle.java @@ -48,6 +48,7 @@ import mage.game.Game; import mage.game.permanent.Permanent; import mage.target.TargetPermanent; import mage.target.common.TargetCreaturePermanent; +import mage.util.CardUtil; /** * @@ -126,7 +127,8 @@ class FarrelsMantleEffect extends OneShotEffect{ @Override public boolean apply(Game game, Ability source) { Permanent perm = game.getPermanent(source.getSourceId()); - DamageTargetEffect dmgEffect = new DamageTargetEffect(2+perm.getPower().getValue()); + int damage = CardUtil.addWithOverflowCheck(perm.getPower().getValue(), 2); + DamageTargetEffect dmgEffect = new DamageTargetEffect(damage); return dmgEffect.apply(game, source); } } diff --git a/Mage.Sets/src/mage/cards/f/FireServant.java b/Mage.Sets/src/mage/cards/f/FireServant.java index e0eadfc9574..2349f1b97b0 100644 --- a/Mage.Sets/src/mage/cards/f/FireServant.java +++ b/Mage.Sets/src/mage/cards/f/FireServant.java @@ -43,6 +43,7 @@ import mage.constants.Zone; import mage.game.Game; import mage.game.events.GameEvent; import mage.game.stack.StackObject; +import mage.util.CardUtil; /** * @@ -111,7 +112,7 @@ class FireServantEffect extends ReplacementEffectImpl { @Override public boolean replaceEvent(GameEvent event, Ability source, Game game) { - event.setAmount(event.getAmount() * 2); + event.setAmount(CardUtil.addWithOverflowCheck(event.getAmount(), event.getAmount())); return false; } diff --git a/Mage.Sets/src/mage/cards/f/Flay.java b/Mage.Sets/src/mage/cards/f/Flay.java new file mode 100644 index 00000000000..e9cc5561a0a --- /dev/null +++ b/Mage.Sets/src/mage/cards/f/Flay.java @@ -0,0 +1,65 @@ +/* + * 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.abilities.costs.mana.ManaCostsImpl; +import mage.abilities.effects.Effect; +import mage.abilities.effects.common.DoUnlessTargetPlayerOrTargetsControllerPaysEffect; +import mage.abilities.effects.common.discard.DiscardTargetEffect; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.target.TargetPlayer; + +/** + * + * @author L_J + */ +public class Flay extends CardImpl { + + public Flay(UUID ownerId, CardSetInfo setInfo) { + super(ownerId,setInfo,new CardType[]{CardType.SORCERY},"{3}{B}"); + + // Target player discards a card at random. Then that player discards another card at random unless he or she pays {1}. + this.getSpellAbility().addEffect(new DiscardTargetEffect(1, true)); + Effect effect = new DoUnlessTargetPlayerOrTargetsControllerPaysEffect(new DiscardTargetEffect(1, true), new ManaCostsImpl("{1}")); + effect.setText("Then that player discards another card at random unless he or she pays {1}"); + this.getSpellAbility().addEffect(effect); + this.getSpellAbility().addTarget(new TargetPlayer()); + } + + public Flay(final Flay card) { + super(card); + } + + @Override + public Flay copy() { + return new Flay(this); + } +} diff --git a/Mage.Sets/src/mage/cards/f/FlintGolem.java b/Mage.Sets/src/mage/cards/f/FlintGolem.java new file mode 100644 index 00000000000..ed99556a940 --- /dev/null +++ b/Mage.Sets/src/mage/cards/f/FlintGolem.java @@ -0,0 +1,99 @@ +/* + * 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.BecomesBlockedByCreatureTriggeredAbility; +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.permanent.Permanent; +import mage.players.Player; + +/** + * + * @author fireshoes & L_J + */ +public class FlintGolem extends CardImpl { + + public FlintGolem(UUID ownerId, CardSetInfo setInfo) { + super(ownerId,setInfo,new CardType[]{CardType.ARTIFACT,CardType.CREATURE},"{4}"); + this.subtype.add(SubType.GOLEM); + this.power = new MageInt(2); + this.toughness = new MageInt(3); + + // Whenever Flint Golem becomes blocked, defending player puts the top three cards of his or her library into his or her graveyard. + this.addAbility(new BecomesBlockedByCreatureTriggeredAbility(new FlintGolemEffect(), false)); + } + + public FlintGolem(final FlintGolem card) { + super(card); + } + + @Override + public FlintGolem copy() { + return new FlintGolem(this); + } +} + +class FlintGolemEffect extends OneShotEffect { + + public FlintGolemEffect() { + super(Outcome.Detriment); + this.staticText = "defending player puts the top three cards of his or her library into his or her graveyard"; + } + + public FlintGolemEffect(final FlintGolemEffect effect) { + super(effect); + } + + @Override + public FlintGolemEffect copy() { + return new FlintGolemEffect(this); + } + + @Override + public boolean apply(Game game, Ability source) { + Permanent blockingCreature = game.getPermanent(getTargetPointer().getFirst(game, source)); + if (blockingCreature != null) { + Player opponent = game.getPlayer(blockingCreature.getControllerId()); + if (opponent != null) { + opponent.moveCards(opponent.getLibrary().getTopCards(game, 3), Zone.GRAVEYARD, source, game); + return true; + } + } + return false; + } +} diff --git a/Mage.Sets/src/mage/cards/f/FogPatch.java b/Mage.Sets/src/mage/cards/f/FogPatch.java new file mode 100644 index 00000000000..9baada1501f --- /dev/null +++ b/Mage.Sets/src/mage/cards/f/FogPatch.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.f; + +import java.util.UUID; +import mage.abilities.Ability; +import mage.abilities.common.CastOnlyDuringPhaseStepSourceAbility; +import mage.abilities.effects.OneShotEffect; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.Outcome; +import mage.constants.PhaseStep; +import mage.game.Game; +import mage.game.combat.CombatGroup; +import mage.game.permanent.Permanent; +import mage.players.Player; + +/** + * + * @author L_J + */ +public class FogPatch extends CardImpl { + + public FogPatch(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.INSTANT}, "{1}{G}"); + + // Cast Fog Patch only during the declare blockers step. + this.addAbility(new CastOnlyDuringPhaseStepSourceAbility(null, PhaseStep.DECLARE_BLOCKERS, null, "Cast {this} only during the declare blockers step")); + + // Attacking creatures become blocked. + this.getSpellAbility().addEffect(new FogPatchEffect()); + } + + public FogPatch(final FogPatch card) { + super(card); + } + + @Override + public FogPatch copy() { + return new FogPatch(this); + } +} + +class FogPatchEffect extends OneShotEffect { + + public FogPatchEffect() { + super(Outcome.Benefit); + this.staticText = "Attacking creatures become blocked"; + } + + public FogPatchEffect(final FogPatchEffect effect) { + super(effect); + } + + @Override + public FogPatchEffect copy() { + return new FogPatchEffect(this); + } + + @Override + public boolean apply(Game game, Ability source) { + Player controller = game.getPlayer(source.getControllerId()); + if (controller != null) { + for (UUID attackers : game.getCombat().getAttackers()) { + Permanent attacker = game.getPermanent(attackers); + if (attacker != null) { + CombatGroup combatGroup = game.getCombat().findGroup(attacker.getId()); + if (combatGroup != null) { + combatGroup.setBlocked(true); + } + } + } + return true; + } + return false; + } +} diff --git a/Mage.Sets/src/mage/cards/f/FurnaceOfRath.java b/Mage.Sets/src/mage/cards/f/FurnaceOfRath.java index 5bc4655be51..9b8d485b31b 100644 --- a/Mage.Sets/src/mage/cards/f/FurnaceOfRath.java +++ b/Mage.Sets/src/mage/cards/f/FurnaceOfRath.java @@ -39,6 +39,7 @@ import mage.constants.Outcome; import mage.constants.Zone; import mage.game.Game; import mage.game.events.GameEvent; +import mage.util.CardUtil; /** * @@ -99,7 +100,7 @@ class FurnaceOfRathEffect extends ReplacementEffectImpl { @Override public boolean replaceEvent(GameEvent event, Ability source, Game game) { - event.setAmount(2 * event.getAmount()); + event.setAmount(CardUtil.addWithOverflowCheck(event.getAmount(), event.getAmount())); return false; } } diff --git a/Mage.Sets/src/mage/cards/g/GiselaBladeOfGoldnight.java b/Mage.Sets/src/mage/cards/g/GiselaBladeOfGoldnight.java index 7556ea36dea..812edd6216d 100644 --- a/Mage.Sets/src/mage/cards/g/GiselaBladeOfGoldnight.java +++ b/Mage.Sets/src/mage/cards/g/GiselaBladeOfGoldnight.java @@ -41,6 +41,7 @@ import mage.game.Game; import mage.game.events.GameEvent; import mage.game.events.GameEvent.EventType; import mage.game.permanent.Permanent; +import mage.util.CardUtil; /** * @author noxx @@ -124,7 +125,7 @@ class GiselaBladeOfGoldnightDoubleDamageEffect extends ReplacementEffectImpl { if (event.getTargetId().equals(source.getControllerId())) { preventDamage(event, source, source.getControllerId(), game); } else if (game.getOpponents(source.getControllerId()).contains(event.getTargetId())) { - event.setAmount(event.getAmount() * 2); + event.setAmount(CardUtil.addWithOverflowCheck(event.getAmount(), event.getAmount())); } break; case DAMAGE_CREATURE: @@ -134,7 +135,7 @@ class GiselaBladeOfGoldnightDoubleDamageEffect extends ReplacementEffectImpl { if (permanent.getControllerId().equals(source.getControllerId())) { preventDamage(event, source, permanent.getId(), game); } else if (game.getOpponents(source.getControllerId()).contains(permanent.getControllerId())) { - event.setAmount(event.getAmount() * 2); + event.setAmount(CardUtil.addWithOverflowCheck(event.getAmount(), event.getAmount())); } } } diff --git a/Mage.Sets/src/mage/cards/g/GlitteringLion.java b/Mage.Sets/src/mage/cards/g/GlitteringLion.java new file mode 100644 index 00000000000..4ecf4f220e7 --- /dev/null +++ b/Mage.Sets/src/mage/cards/g/GlitteringLion.java @@ -0,0 +1,102 @@ +/* + * 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.io.ObjectStreamException; +import java.util.UUID; +import mage.MageInt; +import mage.abilities.Ability; +import mage.abilities.MageSingleton; +import mage.abilities.StaticAbility; +import mage.abilities.common.SimpleActivatedAbility; +import mage.abilities.costs.mana.ManaCostsImpl; +import mage.abilities.effects.common.InfoEffect; +import mage.abilities.effects.common.PreventAllDamageToSourceEffect; +import mage.abilities.effects.common.continuous.LoseAbilitySourceEffect; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.SubType; +import mage.constants.Duration; +import mage.constants.TargetController; +import mage.constants.Zone; + +/** + * + * @author L_J + */ +public class GlitteringLion extends CardImpl { + + public GlitteringLion(UUID ownerId, CardSetInfo setInfo) { + super(ownerId,setInfo,new CardType[]{CardType.CREATURE},"{2}{W}"); + this.subtype.add(SubType.CAT); + this.power = new MageInt(2); + this.toughness = new MageInt(2); + + // Prevent all damage that would be dealt to Glittering Lion. + this.addAbility(GlitteringLionAbility.getInstance()); + // {3}: Until end of turn, Glittering Lion loses "Prevent all damage that would be dealt to Glittering Lion." Any player may activate this ability. + SimpleActivatedAbility ability2 = new SimpleActivatedAbility(Zone.BATTLEFIELD, new LoseAbilitySourceEffect(GlitteringLionAbility.getInstance(), Duration.EndOfTurn).setText("Until end of turn, {this} loses \"Prevent all damage that would be dealt to {this}.\""), new ManaCostsImpl("{3}")); + ability2.setMayActivate(TargetController.ANY); + ability2.addEffect(new InfoEffect("Any player may activate this ability")); + this.addAbility(ability2); + } + + public GlitteringLion(final GlitteringLion card) { + super(card); + } + + @Override + public GlitteringLion copy() { + return new GlitteringLion(this); + } + +} + +class GlitteringLionAbility extends StaticAbility { + + private static final GlitteringLionAbility instance = new GlitteringLionAbility(); + + private Object readResolve() throws ObjectStreamException { + return instance; + } + + public static GlitteringLionAbility getInstance() { + return instance; + } + + public GlitteringLionAbility() { + super(Zone.BATTLEFIELD, new PreventAllDamageToSourceEffect(Duration.WhileOnBattlefield)); + } + + @Override + public GlitteringLionAbility copy() { + return instance; + } + +} diff --git a/Mage.Sets/src/mage/cards/g/GlitteringLynx.java b/Mage.Sets/src/mage/cards/g/GlitteringLynx.java new file mode 100644 index 00000000000..3c2269fb482 --- /dev/null +++ b/Mage.Sets/src/mage/cards/g/GlitteringLynx.java @@ -0,0 +1,102 @@ +/* + * 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.io.ObjectStreamException; +import java.util.UUID; +import mage.MageInt; +import mage.abilities.Ability; +import mage.abilities.MageSingleton; +import mage.abilities.StaticAbility; +import mage.abilities.common.SimpleActivatedAbility; +import mage.abilities.costs.mana.ManaCostsImpl; +import mage.abilities.effects.common.InfoEffect; +import mage.abilities.effects.common.PreventAllDamageToSourceEffect; +import mage.abilities.effects.common.continuous.LoseAbilitySourceEffect; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.SubType; +import mage.constants.Duration; +import mage.constants.TargetController; +import mage.constants.Zone; + +/** + * + * @author L_J + */ +public class GlitteringLynx extends CardImpl { + + public GlitteringLynx(UUID ownerId, CardSetInfo setInfo) { + super(ownerId,setInfo,new CardType[]{CardType.CREATURE},"{W}"); + this.subtype.add(SubType.CAT); + this.power = new MageInt(1); + this.toughness = new MageInt(1); + + // Prevent all damage that would be dealt to Glittering Lynx. + this.addAbility(GlitteringLynxAbility.getInstance()); + // {2}: Until end of turn, Glittering Lynx loses "Prevent all damage that would be dealt to Glittering Lynx." Any player may activate this ability. + SimpleActivatedAbility ability2 = new SimpleActivatedAbility(Zone.BATTLEFIELD, new LoseAbilitySourceEffect(GlitteringLynxAbility.getInstance(), Duration.EndOfTurn).setText("Until end of turn, {this} loses \"Prevent all damage that would be dealt to {this}.\""), new ManaCostsImpl("{2}")); + ability2.setMayActivate(TargetController.ANY); + ability2.addEffect(new InfoEffect("Any player may activate this ability")); + this.addAbility(ability2); + } + + public GlitteringLynx(final GlitteringLynx card) { + super(card); + } + + @Override + public GlitteringLynx copy() { + return new GlitteringLynx(this); + } + +} + +class GlitteringLynxAbility extends StaticAbility { + + private static final GlitteringLynxAbility instance = new GlitteringLynxAbility(); + + private Object readResolve() throws ObjectStreamException { + return instance; + } + + public static GlitteringLynxAbility getInstance() { + return instance; + } + + public GlitteringLynxAbility() { + super(Zone.BATTLEFIELD, new PreventAllDamageToSourceEffect(Duration.WhileOnBattlefield)); + } + + @Override + public GlitteringLynxAbility copy() { + return instance; + } + +} diff --git a/Mage.Sets/src/mage/cards/g/GlyphOfLife.java b/Mage.Sets/src/mage/cards/g/GlyphOfLife.java new file mode 100644 index 00000000000..69abf3dc790 --- /dev/null +++ b/Mage.Sets/src/mage/cards/g/GlyphOfLife.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.g; + +import java.util.UUID; +import mage.abilities.Ability; +import mage.abilities.DelayedTriggeredAbility; +import mage.abilities.effects.OneShotEffect; +import mage.abilities.effects.common.CreateDelayedTriggeredAbilityEffect; +import mage.abilities.effects.common.InfoEffect; +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.filter.common.FilterCreaturePermanent; +import mage.filter.predicate.mageobject.SubtypePredicate; +import mage.game.Game; +import mage.game.events.GameEvent; +import mage.game.events.DamagedCreatureEvent; +import mage.game.events.GameEvent.EventType; +import mage.game.permanent.Permanent; +import mage.players.Player; +import mage.target.common.TargetCreaturePermanent; + +/** + * + * @author fireshoes & L_J + */ +public class GlyphOfLife extends CardImpl { + + private static final FilterCreaturePermanent filter = new FilterCreaturePermanent("Wall creature"); + + static { + filter.add(new SubtypePredicate(SubType.WALL)); + } + + public GlyphOfLife(UUID ownerId, CardSetInfo setInfo) { + super(ownerId,setInfo,new CardType[]{CardType.INSTANT},"{W}"); + + // Choose target Wall creature. Whenever that creature is dealt damage by an attacking creature this turn, you gain that much life. + this.getSpellAbility().addTarget(new TargetCreaturePermanent(filter)); + this.getSpellAbility().addEffect(new InfoEffect("Choose target Wall creature")); + this.getSpellAbility().addEffect(new CreateDelayedTriggeredAbilityEffect(new GlyphOfLifeTriggeredAbility())); + } + + public GlyphOfLife(final GlyphOfLife card) { + super(card); + } + + @Override + public GlyphOfLife copy() { + return new GlyphOfLife(this); + } +} + +class GlyphOfLifeTriggeredAbility extends DelayedTriggeredAbility { + + public GlyphOfLifeTriggeredAbility() { + super(new GlyphOfLifeGainLifeEffect(), Duration.EndOfTurn, false); + } + + public GlyphOfLifeTriggeredAbility(final GlyphOfLifeTriggeredAbility effect) { + super(effect); + } + + @Override + public GlyphOfLifeTriggeredAbility copy() { + return new GlyphOfLifeTriggeredAbility(this); + } + + @Override + public boolean checkEventType(GameEvent event, Game game) { + return event.getType() == EventType.DAMAGED_CREATURE; + } + + @Override + public boolean checkTrigger(GameEvent event, Game game) { + if (event.getTargetId().equals(this.getFirstTarget())) { + DamagedCreatureEvent damageEvent = (DamagedCreatureEvent) event; + Permanent attackingCreature = game.getPermanentOrLKIBattlefield(damageEvent.getSourceId()); + if (attackingCreature != null && attackingCreature.isCreature() && attackingCreature.isAttacking()) { + this.getEffects().get(0).setValue("damageAmount", event.getAmount()); + return true; + } + } + return false; + } + + @Override + public String getRule() { + return "Whenever that creature is dealt damage by an attacking creature this turn, " + super.getRule(); + } +} + +class GlyphOfLifeGainLifeEffect extends OneShotEffect { + + public GlyphOfLifeGainLifeEffect() { + super(Outcome.GainLife); + staticText = "you gain that much life"; + } + + public GlyphOfLifeGainLifeEffect(final GlyphOfLifeGainLifeEffect effect) { + super(effect); + } + + @Override + public GlyphOfLifeGainLifeEffect copy() { + return new GlyphOfLifeGainLifeEffect(this); + } + + @Override + public boolean apply(Game game, Ability source) { + Player player = game.getPlayer(source.getControllerId()); + if (player != null) { + player.gainLife((Integer) this.getValue("damageAmount"), game); + } + return true; + } + +} diff --git a/Mage.Sets/src/mage/cards/g/GoldnightCastigator.java b/Mage.Sets/src/mage/cards/g/GoldnightCastigator.java index 9411b61bbfd..5f173392257 100644 --- a/Mage.Sets/src/mage/cards/g/GoldnightCastigator.java +++ b/Mage.Sets/src/mage/cards/g/GoldnightCastigator.java @@ -45,6 +45,7 @@ import mage.game.Game; import mage.game.events.GameEvent; import mage.game.events.GameEvent.EventType; import mage.game.permanent.Permanent; +import mage.util.CardUtil; /** * @@ -118,14 +119,14 @@ class GoldnightCastigatorDoubleDamageEffect extends ReplacementEffectImpl { switch (event.getType()) { case DAMAGE_PLAYER: if (event.getTargetId().equals(source.getControllerId())) { - event.setAmount(event.getAmount() * 2); + event.setAmount(CardUtil.addWithOverflowCheck(event.getAmount(), event.getAmount())); } break; case DAMAGE_CREATURE: Permanent permanent = game.getPermanent(event.getTargetId()); if (permanent != null) { if (permanent.getId().equals(source.getSourceId())) { - event.setAmount(event.getAmount() * 2); + event.setAmount(CardUtil.addWithOverflowCheck(event.getAmount(), event.getAmount())); } } } diff --git a/Mage.Sets/src/mage/cards/g/GratuitousViolence.java b/Mage.Sets/src/mage/cards/g/GratuitousViolence.java index 2465d48dde0..dea9322ecda 100644 --- a/Mage.Sets/src/mage/cards/g/GratuitousViolence.java +++ b/Mage.Sets/src/mage/cards/g/GratuitousViolence.java @@ -40,6 +40,7 @@ import mage.constants.Zone; import mage.game.Game; import mage.game.events.GameEvent; import mage.game.permanent.Permanent; +import mage.util.CardUtil; /** * @@ -106,7 +107,7 @@ class GratuitousViolenceReplacementEffect extends ReplacementEffectImpl { @Override public boolean replaceEvent(GameEvent event, Ability source, Game game) { - event.setAmount(2 * event.getAmount()); + event.setAmount(CardUtil.addWithOverflowCheck(event.getAmount(), event.getAmount())); return false; } } diff --git a/Mage.Sets/src/mage/cards/h/HarvestMage.java b/Mage.Sets/src/mage/cards/h/HarvestMage.java new file mode 100644 index 00000000000..8c0aee8aaf6 --- /dev/null +++ b/Mage.Sets/src/mage/cards/h/HarvestMage.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.h; + +import java.util.UUID; +import mage.MageInt; +import mage.MageObject; +import mage.Mana; +import mage.abilities.Ability; +import mage.abilities.common.SimpleActivatedAbility; +import mage.abilities.costs.common.DiscardTargetCost; +import mage.abilities.costs.common.TapSourceCost; +import mage.abilities.costs.mana.ManaCostsImpl; +import mage.abilities.effects.ReplacementEffectImpl; +import mage.abilities.effects.common.AddManaOfAnyColorEffect; +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.filter.common.FilterControlledPermanent; +import mage.game.Game; +import mage.game.events.GameEvent; +import mage.game.events.GameEvent.EventType; +import mage.game.events.ManaEvent; +import mage.game.permanent.Permanent; +import mage.target.common.TargetCardInHand; + +/** + * + * @author L_J + */ +public class HarvestMage extends CardImpl { + + public HarvestMage(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{G}"); + this.subtype.add(SubType.HUMAN); + this.subtype.add(SubType.SPELLSHAPER); + this.power = new MageInt(1); + this.toughness = new MageInt(1); + + // {G}, {T}, Discard a card: Until end of turn, if you tap a land for mana, it produces one mana of a color of your choice instead of any other type and amount. + SimpleActivatedAbility ability = new SimpleActivatedAbility(Zone.BATTLEFIELD, new HarvestMageReplacementEffect(), new ManaCostsImpl("{G}")); + ability.addCost(new TapSourceCost()); + ability.addCost(new DiscardTargetCost(new TargetCardInHand())); + this.addAbility(ability); + } + + public HarvestMage(final HarvestMage card) { + super(card); + } + + @Override + public HarvestMage copy() { + return new HarvestMage(this); + } +} + +class HarvestMageReplacementEffect extends ReplacementEffectImpl { + + private static final FilterControlledPermanent filter = new FilterControlledPermanent(); + + HarvestMageReplacementEffect() { + super(Duration.EndOfTurn, Outcome.Neutral); + staticText = "Until end of turn, if you tap a land for mana, it produces one mana of a color of your choice instead of any other type and amount"; + } + + HarvestMageReplacementEffect(final HarvestMageReplacementEffect effect) { + super(effect); + } + + @Override + public HarvestMageReplacementEffect copy() { + return new HarvestMageReplacementEffect(this); + } + + @Override + public boolean apply(Game game, Ability source) { + return true; + } + + @Override + public boolean replaceEvent(GameEvent event, Ability source, Game game) { + ManaEvent manaEvent = (ManaEvent) event; + Mana mana = manaEvent.getMana(); + new AddManaOfAnyColorEffect().apply(game,source); + mana.setToMana(new Mana(0,0,0,0,0,0,0,0)); + return true; + } + + @Override + public boolean checksEventType(GameEvent event, Game game) { + return event.getType() == EventType.TAPPED_FOR_MANA; + } + + @Override + public boolean applies(GameEvent event, Ability source, Game game) { + MageObject mageObject = game.getObject(event.getSourceId()); + if (mageObject != null && mageObject.isLand()) { + Permanent land = game.getPermanent(event.getSourceId()); + return land != null && filter.match(land, game); + } + return false; + } +} diff --git a/Mage.Sets/src/mage/cards/h/HollowWarrior.java b/Mage.Sets/src/mage/cards/h/HollowWarrior.java new file mode 100644 index 00000000000..fc39cb4e1be --- /dev/null +++ b/Mage.Sets/src/mage/cards/h/HollowWarrior.java @@ -0,0 +1,109 @@ +/* + * 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.UUID; +import mage.MageInt; +import mage.abilities.Ability; +import mage.abilities.common.SimpleStaticAbility; +import mage.abilities.costs.common.TapTargetCost; +import mage.abilities.effects.PayCostToAttackBlockEffectImpl; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.Duration; +import mage.constants.Outcome; +import mage.constants.SubType; +import mage.constants.Zone; +import mage.filter.common.FilterControlledCreaturePermanent; +import mage.filter.predicate.Predicates; +import mage.filter.predicate.permanent.AttackingPredicate; +import mage.filter.predicate.permanent.BlockingPredicate; +import mage.filter.predicate.permanent.TappedPredicate; +import mage.game.Game; +import mage.game.events.GameEvent; +import mage.target.common.TargetControlledPermanent; + +/** + * + * @author L_J + */ +public class HollowWarrior extends CardImpl { + + public HollowWarrior(UUID ownerId, CardSetInfo setInfo) { + super(ownerId,setInfo,new CardType[]{CardType.ARTIFACT,CardType.CREATURE},"{4}"); + this.subtype.add(SubType.GOLEM); + this.subtype.add(SubType.WARRIOR); + this.power = new MageInt(4); + this.toughness = new MageInt(4); + + // Hollow Warrior can't attack or block unless you tap an untapped creature you control not declared as an attacking or blocking creature this combat. (This cost is paid as attackers are declared.) + this.addAbility(new SimpleStaticAbility(Zone.BATTLEFIELD, new HollowWarriorCostToAttackBlockEffect())); + + } + + public HollowWarrior(final HollowWarrior card) { + super(card); + } + + @Override + public HollowWarrior copy() { + return new HollowWarrior(this); + } +} + +class HollowWarriorCostToAttackBlockEffect extends PayCostToAttackBlockEffectImpl { + + private static final FilterControlledCreaturePermanent filter = new FilterControlledCreaturePermanent("an untapped creature you control not declared as an attacking or blocking creature"); + static { + filter.add(Predicates.not(new AttackingPredicate())); + filter.add(Predicates.not(new BlockingPredicate())); + filter.add(Predicates.not(new TappedPredicate())); + } + + HollowWarriorCostToAttackBlockEffect() { + super(Duration.WhileOnBattlefield, Outcome.Detriment, RestrictType.ATTACK_AND_BLOCK, + new TapTargetCost(new TargetControlledPermanent(filter))); + staticText = "{this} can't attack or block unless you tap an untapped creature you control not declared as an attacking or blocking creature this combat (This cost is paid as attackers are declared.)"; + } + + HollowWarriorCostToAttackBlockEffect(HollowWarriorCostToAttackBlockEffect effect) { + super(effect); + } + + @Override + public boolean applies(GameEvent event, Ability source, Game game) { + return source.getSourceId().equals(event.getSourceId()); + } + + @Override + public HollowWarriorCostToAttackBlockEffect copy() { + return new HollowWarriorCostToAttackBlockEffect(this); + } + +} diff --git a/Mage.Sets/src/mage/cards/i/ImpulsiveManeuvers.java b/Mage.Sets/src/mage/cards/i/ImpulsiveManeuvers.java index dd8af49bc75..d94fce17a22 100644 --- a/Mage.Sets/src/mage/cards/i/ImpulsiveManeuvers.java +++ b/Mage.Sets/src/mage/cards/i/ImpulsiveManeuvers.java @@ -46,6 +46,7 @@ import mage.game.permanent.Permanent; import mage.filter.StaticFilters; import mage.filter.predicate.permanent.ControllerPredicate; import mage.players.Player; +import mage.util.CardUtil; /** * @@ -121,7 +122,7 @@ class ImpulsiveManeuversEffect extends PreventionEffectImpl { DamageEvent damageEvent = (DamageEvent) event; if (damageEvent.isCombatDamage()) { if (wonFlip) { - event.setAmount(event.getAmount() * 2); + event.setAmount(CardUtil.addWithOverflowCheck(event.getAmount(), event.getAmount())); this.discard(); } else { preventDamageAction(event, source, game); diff --git a/Mage.Sets/src/mage/cards/i/InquisitorsFlail.java b/Mage.Sets/src/mage/cards/i/InquisitorsFlail.java index fe38f01aba4..9b9d3189d19 100644 --- a/Mage.Sets/src/mage/cards/i/InquisitorsFlail.java +++ b/Mage.Sets/src/mage/cards/i/InquisitorsFlail.java @@ -45,6 +45,7 @@ import mage.game.events.DamageCreatureEvent; import mage.game.events.DamageEvent; import mage.game.events.GameEvent; import mage.game.permanent.Permanent; +import mage.util.CardUtil; /** * @author nantuko @@ -126,7 +127,7 @@ class InquisitorsFlailEffect extends ReplacementEffectImpl { @Override public boolean replaceEvent(GameEvent event, Ability source, Game game) { - event.setAmount(event.getAmount() * 2); + event.setAmount(CardUtil.addWithOverflowCheck(event.getAmount(), event.getAmount())); return false; } diff --git a/Mage.Sets/src/mage/cards/i/InsultInjury.java b/Mage.Sets/src/mage/cards/i/InsultInjury.java index b4c272be79c..7ecd9561c18 100644 --- a/Mage.Sets/src/mage/cards/i/InsultInjury.java +++ b/Mage.Sets/src/mage/cards/i/InsultInjury.java @@ -19,6 +19,7 @@ import mage.game.permanent.Permanent; import mage.players.Player; import mage.target.TargetPlayer; import mage.target.common.TargetCreaturePermanent; +import mage.util.CardUtil; /** * @author Stravant @@ -88,7 +89,7 @@ class InsultDoubleDamageEffect extends ReplacementEffectImpl { @Override public boolean replaceEvent(GameEvent event, Ability source, Game game) { - event.setAmount(event.getAmount() * 2); + event.setAmount(CardUtil.addWithOverflowCheck(event.getAmount(), event.getAmount())); return false; } } diff --git a/Mage.Sets/src/mage/cards/k/KamahlsSummons.java b/Mage.Sets/src/mage/cards/k/KamahlsSummons.java new file mode 100644 index 00000000000..a259d5289a3 --- /dev/null +++ b/Mage.Sets/src/mage/cards/k/KamahlsSummons.java @@ -0,0 +1,121 @@ +/* + * 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.HashMap; +import java.util.Map; +import java.util.UUID; +import mage.MageObject; +import mage.abilities.Ability; +import mage.abilities.effects.OneShotEffect; +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.filter.FilterCard; +import mage.filter.common.FilterCreatureCard; +import mage.game.Game; +import mage.game.permanent.token.BearToken; +import mage.game.permanent.token.Token; +import mage.players.Player; +import mage.target.common.TargetCardInHand; + +/** + * + * @author L_J + */ +public class KamahlsSummons extends CardImpl { + + public KamahlsSummons(UUID ownerId, CardSetInfo setInfo) { + super(ownerId,setInfo,new CardType[]{CardType.SORCERY},"{3}{G}"); + + // Each player may reveal any number of creature cards from his or her hand. Then each player creates a 2/2 green Bear creature token for each card he or she revealed this way. + getSpellAbility().addEffect(new KamahlsSummonsEffect()); + } + + public KamahlsSummons(final KamahlsSummons card) { + super(card); + } + + @Override + public KamahlsSummons copy() { + return new KamahlsSummons(this); + } +} + +class KamahlsSummonsEffect extends OneShotEffect { + + private static final FilterCard filter = new FilterCreatureCard(); + + public KamahlsSummonsEffect() { + super(Outcome.Benefit); + this.staticText = "Each player may reveal any number of creature cards from his or her hand. Then each player creates a 2/2 green Bear creature token for each card he or she revealed this way"; + } + + public KamahlsSummonsEffect(final KamahlsSummonsEffect effect) { + super(effect); + } + + @Override + public KamahlsSummonsEffect copy() { + return new KamahlsSummonsEffect(this); + } + + @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) { + Map revealedCards = new HashMap<>(); + for (UUID playerId : game.getState().getPlayersInRange(controller.getId(), game)) { + Player player = game.getPlayer(playerId); + if (player != null) { + if (player.getHand().count(filter, game) > 0) { + TargetCardInHand target = new TargetCardInHand(0, Integer.MAX_VALUE, filter); + if (player.choose(outcome, target, source.getSourceId(), game)) { + Cards cards = new CardsImpl(target.getTargets()); + controller.revealCards(sourceObject.getIdName(), cards, game); + revealedCards.put(playerId, target.getTargets().size()); + } + } + } + } + Token token = new BearToken(); + for (UUID playerId : revealedCards.keySet()) { + int value = revealedCards.get(playerId); + if (value > 0) { + token.putOntoBattlefield(value, game, source.getSourceId(), playerId); + } + } + return true; + } + return false; + } +} diff --git a/Mage.Sets/src/mage/cards/k/KeldonBattlewagon.java b/Mage.Sets/src/mage/cards/k/KeldonBattlewagon.java new file mode 100644 index 00000000000..e65943b01fc --- /dev/null +++ b/Mage.Sets/src/mage/cards/k/KeldonBattlewagon.java @@ -0,0 +1,169 @@ + /* + * 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.List; +import java.util.UUID; +import mage.MageInt; +import mage.abilities.Ability; +import mage.abilities.common.AttacksTriggeredAbility; +import mage.abilities.common.CantBlockAbility; +import mage.abilities.common.SimpleActivatedAbility; +import mage.abilities.common.delayed.AtTheEndOfCombatDelayedTriggeredAbility; +import mage.abilities.costs.Cost; +import mage.abilities.costs.CostImpl; +import mage.abilities.effects.Effect; +import mage.abilities.effects.OneShotEffect; +import mage.abilities.effects.common.CreateDelayedTriggeredAbilityEffect; +import mage.abilities.effects.common.SacrificeSourceEffect; +import mage.abilities.effects.common.continuous.BoostSourceEffect; +import mage.abilities.keyword.TrampleAbility; +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.filter.common.FilterControlledCreaturePermanent; +import mage.filter.predicate.Predicates; +import mage.filter.predicate.permanent.TappedPredicate; +import mage.game.Game; +import mage.game.permanent.Permanent; +import mage.target.common.TargetControlledPermanent; +import mage.target.targetpointer.FixedTarget; + +/** + * + * @author jeffwadsworth & L_J + */ +public class KeldonBattlewagon extends CardImpl { + + private static final FilterControlledCreaturePermanent filter = new FilterControlledCreaturePermanent("an untapped creature you control"); + static { + filter.add(Predicates.not(new TappedPredicate())); + } + + public KeldonBattlewagon(UUID ownerId, CardSetInfo setInfo) { + super(ownerId,setInfo,new CardType[]{CardType.ARTIFACT,CardType.CREATURE},"{5}"); + this.subtype.add(SubType.JUGGERNAUT); + this.power = new MageInt(0); + this.toughness = new MageInt(3); + + // Trample + this.addAbility(TrampleAbility.getInstance()); + + // Keldon Battlewagon can't block. + this.addAbility(new CantBlockAbility()); + + // When Keldon Battlewagon attacks, sacrifice it at end of combat. + this.addAbility(new AttacksTriggeredAbility(new CreateDelayedTriggeredAbilityEffect(new AtTheEndOfCombatDelayedTriggeredAbility(new SacrificeSourceEffect())), false)); + + // Tap an untapped creature you control: Keldon Battlewagon gets +X/+0 until end of turn, where X is the power of the creature tapped this way. + this.addAbility(new SimpleActivatedAbility(Zone.BATTLEFIELD, new KeldonBattlewagonBoostEffect(), new KeldonBattlewagonCost(new TargetControlledPermanent(filter)))); + + } + + public KeldonBattlewagon(final KeldonBattlewagon card) { + super(card); + } + + @Override + public KeldonBattlewagon copy() { + return new KeldonBattlewagon(this); + } +} + +class KeldonBattlewagonCost extends CostImpl { + + TargetControlledPermanent target; + + public KeldonBattlewagonCost(TargetControlledPermanent target) { + this.target = target; + this.text = "Tap an untapped creature you control"; + } + + public KeldonBattlewagonCost(final KeldonBattlewagonCost cost) { + super(cost); + this.target = cost.target.copy(); + } + + @Override + public boolean pay(Ability ability, Game game, UUID sourceId, UUID controllerId, boolean noMana, Cost costToPay) { + if (target.choose(Outcome.Tap, controllerId, sourceId, game)) { + for (UUID targetId: (List)target.getTargets()) { + Permanent permanent = game.getPermanent(targetId); + if (permanent == null) + return false; + paid |= permanent.tap(game); + for (Effect effect : ability.getEffects()) { + effect.setTargetPointer(new FixedTarget(permanent.getId())); + } + } + } + return paid; + } + + @Override + public boolean canPay(Ability ability, UUID sourceId, UUID controllerId, Game game) { + return target.canChoose(controllerId, game); + } + + @Override + public KeldonBattlewagonCost copy() { + return new KeldonBattlewagonCost(this); + } +} + +class KeldonBattlewagonBoostEffect extends OneShotEffect { + + public KeldonBattlewagonBoostEffect() { + super(Outcome.BoostCreature); + staticText = "{this} gets +X/+0 until end of turn, where X is the power of the creature tapped this way"; + } + + public KeldonBattlewagonBoostEffect(KeldonBattlewagonBoostEffect effect) { + super(effect); + } + + @Override + public boolean apply(Game game, Ability source) { + Permanent KeldonBattlewagon = game.getPermanent(source.getSourceId()); + Permanent tappedCreature = game.getPermanentOrLKIBattlefield(this.targetPointer.getFirst(game, source)); + if (tappedCreature != null && KeldonBattlewagon != null) { + int amount = tappedCreature.getPower().getValue(); + game.addEffect(new BoostSourceEffect(amount, 0, Duration.EndOfTurn), source); + } + return true; + } + + @Override + public KeldonBattlewagonBoostEffect copy() { + return new KeldonBattlewagonBoostEffect(this); + } +} diff --git a/Mage.Sets/src/mage/cards/l/LastRites.java b/Mage.Sets/src/mage/cards/l/LastRites.java new file mode 100644 index 00000000000..151775f5e1a --- /dev/null +++ b/Mage.Sets/src/mage/cards/l/LastRites.java @@ -0,0 +1,125 @@ +/* + * 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.dynamicvalue.common.StaticValue; +import mage.abilities.effects.Effect; +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.cards.Cards; +import mage.constants.CardType; +import mage.constants.Outcome; +import mage.constants.TargetController; +import mage.filter.FilterCard; +import mage.filter.predicate.Predicates; +import mage.filter.predicate.mageobject.CardTypePredicate; +import mage.game.Game; +import mage.players.Player; +import mage.target.TargetCard; +import mage.target.TargetPlayer; +import mage.target.common.TargetCardInHand; +import mage.target.targetpointer.FixedTarget; + +/** + * + * @author L_J + */ +public class LastRites extends CardImpl { + + public LastRites(UUID ownerId, CardSetInfo setInfo) { + super(ownerId,setInfo,new CardType[]{CardType.SORCERY},"{2}{B}"); + + // Discard any number of cards. Target player reveals his or her hand, then you choose a nonland card from it for each card discarded this way. That player discards those cards. + this.getSpellAbility().addEffect(new LastRitesEffect()); + this.getSpellAbility().addTarget(new TargetPlayer()); + + } + + public LastRites(final LastRites card) { + super(card); + } + + @Override + public LastRites copy() { + return new LastRites(this); + } +} + +class LastRitesEffect extends OneShotEffect { + + LastRitesEffect() { + super(Outcome.Discard); + this.staticText = "Discard any number of cards. Target player reveals his or her hand, then you choose a nonland card from it for each card discarded this way. That player discards those cards"; + } + + LastRitesEffect(final LastRitesEffect effect) { + super(effect); + } + + @Override + public LastRitesEffect copy() { + return new LastRitesEffect(this); + } + + @Override + public boolean apply(Game game, Ability source) { + Player controller = game.getPlayer(source.getControllerId()); + Player targetPlayer = game.getPlayer(this.getTargetPointer().getFirst(game, source)); + if (controller != null && targetPlayer != null) { + Cards cardsInHand = controller.getHand().copy(); + TargetCard target = new TargetCardInHand(0, cardsInHand.size(), new FilterCard("cards to discard")); + controller.chooseTarget(outcome, cardsInHand, target, source, game); + int discardCount = target.getTargets().size(); + if (discardCount > 0) { + for (UUID cardId : target.getTargets()) { + Card card = game.getCard(cardId); + if (card != null) { + controller.discard(card, source, game); + } + } + if (targetPlayer != null) { + FilterCard filter = new FilterCard((discardCount > 1 ? "" : "a") + " nonland card" + (discardCount > 1 ? "s" : "")); + filter.add(Predicates.not(new CardTypePredicate(CardType.LAND))); + StaticValue discardValue = new StaticValue(discardCount); + Effect effect = new DiscardCardYouChooseTargetEffect(discardValue, filter, TargetController.ANY); + effect.setTargetPointer(new FixedTarget(targetPlayer.getId())); + effect.apply(game, source); + } else { + return false; + } + } + return true; + } + return false; + } +} diff --git a/Mage.Sets/src/mage/cards/m/ManaCache.java b/Mage.Sets/src/mage/cards/m/ManaCache.java new file mode 100644 index 00000000000..e5976b259bf --- /dev/null +++ b/Mage.Sets/src/mage/cards/m/ManaCache.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.Mana; +import mage.abilities.Ability; +import mage.abilities.TriggeredAbility; +import mage.abilities.common.OnEventTriggeredAbility; +import mage.abilities.costs.common.RemoveCountersSourceCost; +import mage.abilities.effects.Effect; +import mage.abilities.effects.OneShotEffect; +import mage.abilities.effects.common.BasicManaEffect; +import mage.abilities.mana.ActivatedManaAbilityImpl; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.Outcome; +import mage.constants.PhaseStep; +import mage.constants.Zone; +import mage.counters.CounterType; +import mage.filter.FilterPermanent; +import mage.filter.common.FilterControlledLandPermanent; +import mage.filter.predicate.Predicates; +import mage.filter.predicate.permanent.TappedPredicate; +import mage.game.Game; +import mage.game.events.GameEvent; +import mage.game.permanent.Permanent; +import mage.players.Player; + +/** + * + * @author L_J + */ +public class ManaCache extends CardImpl { + + public ManaCache(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.ENCHANTMENT}, "{1}{R}{R}"); + + // At the beginning of each player's end step, put a charge counter on Mana Cache for each untapped land that player controls. + TriggeredAbility ability = new OnEventTriggeredAbility(GameEvent.EventType.END_TURN_STEP_PRE, "beginning of each player's end step", true, new ManaCacheEffect()); + this.addAbility(ability); + + // Remove a charge counter from Mana Cache: Add {C} to your mana pool. Any player may activate this ability but only during his or her turn before the end step. + this.addAbility(new ManaCacheManaAbility()); + } + + public ManaCache(final ManaCache card) { + super(card); + } + + @Override + public ManaCache copy() { + return new ManaCache(this); + } +} + +class ManaCacheEffect extends OneShotEffect { + + private static final FilterPermanent filter = new FilterControlledLandPermanent(); + static { + filter.add(Predicates.not(new TappedPredicate())); + } + + public ManaCacheEffect() { + super(Outcome.Damage); + this.staticText = "put a charge counter on {this} for each untapped land that player controls"; + } + + @Override + public Effect copy() { + return new ManaCacheEffect(); + } + + @Override + public boolean apply(Game game, Ability source) { + Player player = game.getPlayer(game.getActivePlayerId()); + Permanent sourcePermanent = game.getPermanent(source.getSourceId()); + if (player != null && sourcePermanent != null) { + int controlledUntappedLands = game.getBattlefield().countAll(filter, game.getActivePlayerId(), game); + sourcePermanent.addCounters(CounterType.CHARGE.createInstance(controlledUntappedLands), source, game); + return true; + } + return false; + } +} + +class ManaCacheManaAbility extends ActivatedManaAbilityImpl { + + public ManaCacheManaAbility() { + super(Zone.BATTLEFIELD, new BasicManaEffect(Mana.ColorlessMana(1)), new RemoveCountersSourceCost(CounterType.CHARGE.createInstance(1))); + this.netMana.add(new Mana(0,0,0,0,0,0,0,1)); + } + + public ManaCacheManaAbility(final ManaCacheManaAbility ability) { + super(ability); + } + + @Override + public boolean canActivate(UUID playerId, Game game) { + if (!super.hasMoreActivationsThisTurn(game) || !(condition == null || condition.apply(game, this))) { + return false; + } + Player player = game.getPlayer(playerId); + if (player != null && playerId == game.getActivePlayerId() && game.getStep().getType().isBefore(PhaseStep.END_TURN)) { + if (costs.canPay(this, sourceId, playerId, game)) { + this.setControllerId(playerId); + return true; + } + } + return false; + } + + @Override + public ManaCacheManaAbility copy() { + return new ManaCacheManaAbility(this); + } + + @Override + public String getRule() { + return super.getRule() + " Any player may activate this ability but only during his or her turn before the end step."; + } +} diff --git a/Mage.Sets/src/mage/cards/m/MirrorStrike.java b/Mage.Sets/src/mage/cards/m/MirrorStrike.java new file mode 100644 index 00000000000..5d9e5191041 --- /dev/null +++ b/Mage.Sets/src/mage/cards/m/MirrorStrike.java @@ -0,0 +1,131 @@ +/* + * 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.effects.ReplacementEffectImpl; +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.players.Player; +import mage.filter.common.FilterCreaturePermanent; +import mage.filter.predicate.Predicates; +import mage.filter.predicate.permanent.UnblockedPredicate; +import mage.target.common.TargetCreaturePermanent; + +/** + * + * @author L_J + */ +public class MirrorStrike extends CardImpl { + + private static final FilterCreaturePermanent filter = new FilterCreaturePermanent("unblocked creature"); + + static { + filter.add(new UnblockedPredicate()); + } + + public MirrorStrike(UUID ownerId, CardSetInfo setInfo) { + super(ownerId,setInfo,new CardType[]{CardType.INSTANT},"{3}{W}"); + + // All combat damage that would be dealt to you this turn by target unblocked creature is dealt to its controller instead. + this.getSpellAbility().addEffect(new MirrorStrikeEffect()); + this.getSpellAbility().addTarget(new TargetCreaturePermanent(filter)); + } + + public MirrorStrike(final MirrorStrike card) { + super(card); + } + + @Override + public MirrorStrike copy() { + return new MirrorStrike(this); + } +} + +class MirrorStrikeEffect extends ReplacementEffectImpl { + + public MirrorStrikeEffect() { + super(Duration.EndOfTurn, Outcome.RedirectDamage); + staticText = "All combat damage that would be dealt to you this turn by target unblocked creature is dealt to its controller instead"; + } + + public MirrorStrikeEffect(final MirrorStrikeEffect effect) { + super(effect); + } + + @Override + public MirrorStrikeEffect copy() { + return new MirrorStrikeEffect(this); + } + + @Override + public boolean checksEventType(GameEvent event, Game game) { + return event.getType() == GameEvent.EventType.DAMAGE_PLAYER; + } + + @Override + public boolean apply(Game game, Ability source) { + return true; + } + + @Override + public boolean replaceEvent(GameEvent event, Ability source, Game game) { + Player controller = game.getPlayer(source.getControllerId()); + DamageEvent damageEvent = (DamageEvent) event; + if (controller != null) { + Permanent targetPermanent = game.getPermanent(source.getFirstTarget()); + if (targetPermanent != null) { + Player targetsController = game.getPlayer(targetPermanent.getControllerId()); + if (targetsController != null) { + targetsController.damage(damageEvent.getAmount(), damageEvent.getSourceId(), game, damageEvent.isCombatDamage(), damageEvent.isPreventable(), damageEvent.getAppliedEffects()); + return true; + } + } + } + return false; + } + + @Override + public boolean applies(GameEvent event, Ability source, Game game) { + Player controller = game.getPlayer(source.getControllerId()); + DamageEvent damageEvent = (DamageEvent) event; + Permanent targetPermanent = game.getPermanent(source.getFirstTarget()); + if (controller != null && targetPermanent != null) { + return (damageEvent.isCombatDamage() && controller.getId() == damageEvent.getTargetId() && targetPermanent.getId() == damageEvent.getSourceId()); + } + return false; + } +} diff --git a/Mage.Sets/src/mage/cards/m/MoggToady.java b/Mage.Sets/src/mage/cards/m/MoggToady.java new file mode 100644 index 00000000000..be59454a951 --- /dev/null +++ b/Mage.Sets/src/mage/cards/m/MoggToady.java @@ -0,0 +1,150 @@ +/* + * 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.SimpleStaticAbility; +import mage.abilities.effects.RestrictionEffect; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.SubType; +import mage.constants.Duration; +import mage.constants.Zone; +import mage.filter.common.FilterControlledCreaturePermanent; +import mage.game.Game; +import mage.game.permanent.Permanent; +import mage.players.Player; + +/** + * + * @author emerald000 & L_J + */ +public class MoggToady extends CardImpl { + + public MoggToady(UUID ownerId, CardSetInfo setInfo) { + super(ownerId,setInfo,new CardType[]{CardType.CREATURE},"{1}{R}"); + this.subtype.add(SubType.GOBLIN); + this.power = new MageInt(2); + this.toughness = new MageInt(2); + + // Mogg Toady can't attack unless you control more creatures than defending player. + this.addAbility(new SimpleStaticAbility(Zone.BATTLEFIELD, new MoggToadyCantAttackEffect())); + + // Mogg Toady can't block unless you control more creatures than attacking player. + this.addAbility(new SimpleStaticAbility(Zone.BATTLEFIELD, new MoggToadyCantBlockEffect())); + } + + public MoggToady(final MoggToady card) { + super(card); + } + + @Override + public MoggToady copy() { + return new MoggToady(this); + } +} + +class MoggToadyCantAttackEffect extends RestrictionEffect { + + MoggToadyCantAttackEffect() { + super(Duration.WhileOnBattlefield); + staticText = "{this} can't attack unless you control more creatures than defending player"; + } + + MoggToadyCantAttackEffect(final MoggToadyCantAttackEffect effect) { + super(effect); + } + + @Override + public boolean applies(Permanent permanent, Ability source, Game game) { + return permanent.getId().equals(source.getSourceId()); + } + + @Override + public boolean canAttack(Permanent attacker, UUID defenderId, Ability source, Game game) { + UUID defendingPlayerId; + Player defender = game.getPlayer(defenderId); + if (defender == null) { + Permanent permanent = game.getPermanent(defenderId); + if (permanent != null) { + defendingPlayerId = permanent.getControllerId(); + } + else { + return false; + } + } + else { + defendingPlayerId = defenderId; + } + if (defendingPlayerId != null) { + return game.getBattlefield().countAll(new FilterControlledCreaturePermanent(), source.getControllerId(), game) > game.getBattlefield().countAll(new FilterControlledCreaturePermanent(), defendingPlayerId, game); + } + else { + return true; + } + } + + @Override + public MoggToadyCantAttackEffect copy() { + return new MoggToadyCantAttackEffect(this); + } +} + +class MoggToadyCantBlockEffect extends RestrictionEffect { + + MoggToadyCantBlockEffect() { + super(Duration.WhileOnBattlefield); + staticText = "{this} can't block unless you control more creatures than attacking player"; + } + + MoggToadyCantBlockEffect(final MoggToadyCantBlockEffect effect) { + super(effect); + } + + @Override + public MoggToadyCantBlockEffect copy() { + return new MoggToadyCantBlockEffect(this); + } + + @Override + public boolean canBlock(Permanent attacker, Permanent blocker, Ability source, Game game) { + UUID attackingPlayerId = attacker.getControllerId(); + if (attackingPlayerId != null) { + return game.getBattlefield().countAll(new FilterControlledCreaturePermanent(), source.getControllerId(), game) > game.getBattlefield().countAll(new FilterControlledCreaturePermanent(), attackingPlayerId, game); + } + return true; + } + + @Override + public boolean applies(Permanent permanent, Ability source, Game game) { + return permanent.getId().equals(source.getSourceId()); + } +} diff --git a/Mage.Sets/src/mage/cards/m/Mossdog.java b/Mage.Sets/src/mage/cards/m/Mossdog.java new file mode 100644 index 00000000000..728b242230e --- /dev/null +++ b/Mage.Sets/src/mage/cards/m/Mossdog.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.m; + +import java.util.UUID; +import mage.MageInt; +import mage.abilities.TriggeredAbilityImpl; +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.Zone; +import mage.counters.CounterType; +import mage.game.Game; +import mage.game.events.GameEvent; +import mage.game.events.GameEvent.EventType; + +/** + * + * @author fireshoes & L_J + */ +public class Mossdog extends CardImpl { + + public Mossdog(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{G}"); + this.subtype.add(SubType.PLANT); + this.subtype.add(SubType.HOUND); + this.power = new MageInt(1); + this.toughness = new MageInt(1); + + // Whenever Mossdog becomes the target of a spell or ability an opponent controls, put a +1/+1 counter on Mossdog. + this.addAbility(new MossdogAbility()); + } + + public Mossdog(final Mossdog card) { + super(card); + } + + @Override + public Mossdog copy() { + return new Mossdog(this); + } +} + +class MossdogAbility extends TriggeredAbilityImpl { + + public MossdogAbility() { + super(Zone.BATTLEFIELD, new AddCountersSourceEffect(CounterType.P1P1.createInstance()), false); + } + + public MossdogAbility(final MossdogAbility ability) { + super(ability); + } + + @Override + public MossdogAbility copy() { + return new MossdogAbility(this); + } + + @Override + public boolean checkEventType(GameEvent event, Game game) { + return event.getType() == EventType.TARGETED; + } + + @Override + public boolean checkTrigger(GameEvent event, Game game) { + if (event.getTargetId().equals(this.getSourceId()) && game.getOpponents(this.controllerId).contains(event.getPlayerId())) { + return true; + } + return false; + } + + @Override + public String getRule() { + return "Whenever {this} becomes the target of a spell or ability an opponent controls, put a +1/+1 counter on {this}."; + } +} diff --git a/Mage.Sets/src/mage/cards/m/MoxDiamond.java b/Mage.Sets/src/mage/cards/m/MoxDiamond.java index 8049ee94235..adc3c8950ce 100644 --- a/Mage.Sets/src/mage/cards/m/MoxDiamond.java +++ b/Mage.Sets/src/mage/cards/m/MoxDiamond.java @@ -34,7 +34,6 @@ import mage.abilities.costs.Cost; import mage.abilities.costs.common.DiscardTargetCost; import mage.abilities.effects.ReplacementEffectImpl; import mage.abilities.mana.AnyColorManaAbility; -import mage.cards.Card; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; @@ -44,7 +43,7 @@ import mage.constants.Zone; import mage.filter.common.FilterLandCard; import mage.game.Game; import mage.game.events.GameEvent; -import mage.game.events.ZoneChangeEvent; +import mage.game.permanent.Permanent; import mage.players.Player; import mage.target.common.TargetCardInHand; @@ -55,7 +54,7 @@ import mage.target.common.TargetCardInHand; public class MoxDiamond extends CardImpl { public MoxDiamond(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.ARTIFACT},"{0}"); + super(ownerId, setInfo, new CardType[]{CardType.ARTIFACT}, "{0}"); // If Mox Diamond would enter the battlefield, you may discard a land card instead. If you do, put Mox Diamond onto the battlefield. If you don't, put it into its owner's graveyard. this.addAbility(new SimpleStaticAbility(Zone.ALL, new MoxDiamondReplacementEffect())); @@ -95,43 +94,36 @@ class MoxDiamondReplacementEffect extends ReplacementEffectImpl { } @Override - public boolean replaceEvent(GameEvent event, Ability source, Game game) { - Player player = game.getPlayer(source.getControllerId()); - if (player != null){ + public boolean replaceEvent(GameEvent event, Ability source, Game game) { + Player player = game.getPlayer(source.getControllerId()); + if (player != null) { TargetCardInHand target = new TargetCardInHand(new FilterLandCard()); Cost cost = new DiscardTargetCost(target); - if (cost.canPay(source, source.getSourceId(), source.getControllerId(), game) && - player.chooseUse(outcome, "Discard land? (Otherwise Mox Diamond goes to graveyard)", source, game) && - player.chooseTarget(Outcome.Discard, target, source, game)){ + if (cost.canPay(source, source.getSourceId(), source.getControllerId(), game) + && player.chooseUse(outcome, "Discard land? (Otherwise Mox Diamond goes to graveyard)", source, game) + && player.chooseTarget(Outcome.Discard, target, source, game)) { player.discard(game.getCard(target.getFirstTarget()), source, game); return false; - } - else{ - Card card = game.getCard(event.getTargetId()); - if (card != null) { - player.moveCards(card, Zone.GRAVEYARD, source, game); + } else { + Permanent permanent = game.getPermanent(event.getTargetId()); + if (permanent != null) { + player.moveCards(permanent, Zone.GRAVEYARD, source, game); } return true; } - + } return false; } @Override public boolean checksEventType(GameEvent event, Game game) { - return event.getType() == GameEvent.EventType.ZONE_CHANGE; + return event.getType() == GameEvent.EventType.ENTERS_THE_BATTLEFIELD; } @Override public boolean applies(GameEvent event, Ability source, Game game) { - if (source.getSourceId().equals(event.getTargetId())) { - ZoneChangeEvent zEvent = (ZoneChangeEvent) event; - if(zEvent.getToZone() == Zone.BATTLEFIELD){ - return true; - } - } - return false; + return source.getSourceId().equals(event.getTargetId()); } } diff --git a/Mage.Sets/src/mage/cards/o/Overblaze.java b/Mage.Sets/src/mage/cards/o/Overblaze.java index c1092570c8d..db7811c296c 100644 --- a/Mage.Sets/src/mage/cards/o/Overblaze.java +++ b/Mage.Sets/src/mage/cards/o/Overblaze.java @@ -27,6 +27,7 @@ */ package mage.cards.o; +import java.util.UUID; import mage.abilities.Ability; import mage.abilities.effects.ReplacementEffectImpl; import mage.abilities.keyword.SpliceOntoArcaneAbility; @@ -39,8 +40,7 @@ import mage.constants.SubType; import mage.game.Game; import mage.game.events.GameEvent; import mage.target.TargetPermanent; - -import java.util.UUID; +import mage.util.CardUtil; /** * @@ -104,8 +104,8 @@ class FireServantEffect extends ReplacementEffectImpl { @Override public boolean replaceEvent(GameEvent event, Ability source, Game game) { - event.setAmount(event.getAmount() * 2); + event.setAmount(CardUtil.addWithOverflowCheck(event.getAmount(), event.getAmount())); return false; } -} \ No newline at end of file +} diff --git a/Mage.Sets/src/mage/cards/p/PersonalIncarnation.java b/Mage.Sets/src/mage/cards/p/PersonalIncarnation.java index 63ff9fa5de2..a9cdf4be71a 100644 --- a/Mage.Sets/src/mage/cards/p/PersonalIncarnation.java +++ b/Mage.Sets/src/mage/cards/p/PersonalIncarnation.java @@ -128,7 +128,7 @@ class PersonalIncarnationLoseHalfLifeEffect extends OneShotEffect { public boolean apply(Game game, Ability source) { Player player = game.getPlayer(game.getOwnerId(source.getSourceId())); if (player != null) { - int amount = (player.getLife() + 1) / 2; + Integer amount = (int) Math.ceil(player.getLife() / 2f); if (amount > 0) { player.loseLife(amount, game, false); return true; diff --git a/Mage.Sets/src/mage/cards/p/Phthisis.java b/Mage.Sets/src/mage/cards/p/Phthisis.java index 06f54043326..c60f351223d 100644 --- a/Mage.Sets/src/mage/cards/p/Phthisis.java +++ b/Mage.Sets/src/mage/cards/p/Phthisis.java @@ -40,6 +40,7 @@ import mage.game.Game; import mage.game.permanent.Permanent; import mage.players.Player; import mage.target.common.TargetCreaturePermanent; +import mage.util.CardUtil; /** * @@ -91,7 +92,7 @@ class PhthisisEffect extends OneShotEffect { if (creature != null) { Player controller = game.getPlayer(creature.getControllerId()); if (controller != null) { - int lifeLoss = creature.getPower().getValue() + creature.getToughness().getValue(); + int lifeLoss = CardUtil.addWithOverflowCheck(creature.getPower().getValue(), creature.getToughness().getValue()); creature.destroy(source.getSourceId(), game, false); // the life loss happens also if the creature is indestructible or regenerated (legal targets) controller.loseLife(lifeLoss, game, false); diff --git a/Mage.Sets/src/mage/cards/p/PredatorsRapport.java b/Mage.Sets/src/mage/cards/p/PredatorsRapport.java index b2f8c3f5754..4374bbf5347 100644 --- a/Mage.Sets/src/mage/cards/p/PredatorsRapport.java +++ b/Mage.Sets/src/mage/cards/p/PredatorsRapport.java @@ -38,6 +38,7 @@ import mage.constants.CardType; import mage.game.Game; import mage.game.permanent.Permanent; import mage.target.common.TargetControlledCreaturePermanent; +import mage.util.CardUtil; /** * @@ -72,7 +73,7 @@ class TargetPermanentPowerPlusToughnessCount implements DynamicValue { public int calculate(Game game, Ability sourceAbility, Effect effect) { Permanent sourcePermanent = game.getPermanent(sourceAbility.getFirstTarget()); if (sourcePermanent != null) { - return sourcePermanent.getPower().getValue() + sourcePermanent.getToughness().getValue(); + return CardUtil.addWithOverflowCheck(sourcePermanent.getPower().getValue(), sourcePermanent.getToughness().getValue()); } return 0; } diff --git a/Mage.Sets/src/mage/cards/p/PyromancersGauntlet.java b/Mage.Sets/src/mage/cards/p/PyromancersGauntlet.java index 1a2c6717ff2..1282b111719 100644 --- a/Mage.Sets/src/mage/cards/p/PyromancersGauntlet.java +++ b/Mage.Sets/src/mage/cards/p/PyromancersGauntlet.java @@ -42,6 +42,7 @@ import mage.game.Game; import mage.game.events.GameEvent; import mage.game.permanent.Permanent; import mage.game.stack.Spell; +import mage.util.CardUtil; /** * @@ -103,7 +104,7 @@ class PyromancersGauntletReplacementEffect extends ReplacementEffectImpl { @Override public boolean replaceEvent(GameEvent event, Ability source, Game game) { - event.setAmount(event.getAmount() + 2); + event.setAmount(CardUtil.addWithOverflowCheck(event.getAmount(), 2)); return false; } diff --git a/Mage.Sets/src/mage/cards/p/PyromancersSwath.java b/Mage.Sets/src/mage/cards/p/PyromancersSwath.java index 84c83333cb7..933c587e750 100644 --- a/Mage.Sets/src/mage/cards/p/PyromancersSwath.java +++ b/Mage.Sets/src/mage/cards/p/PyromancersSwath.java @@ -39,6 +39,7 @@ import mage.cards.CardSetInfo; import mage.constants.*; import mage.game.Game; import mage.game.events.GameEvent; +import mage.util.CardUtil; /** * @@ -105,7 +106,7 @@ class PyromancersSwathReplacementEffect extends ReplacementEffectImpl { @Override public boolean replaceEvent(GameEvent event, Ability source, Game game) { - event.setAmount(event.getAmount() + 2); + event.setAmount(CardUtil.addWithOverflowCheck(event.getAmount(), 2)); return false; } diff --git a/Mage.Sets/src/mage/cards/q/QuestForPureFlame.java b/Mage.Sets/src/mage/cards/q/QuestForPureFlame.java index 4ac5e7ce402..de563d27acc 100644 --- a/Mage.Sets/src/mage/cards/q/QuestForPureFlame.java +++ b/Mage.Sets/src/mage/cards/q/QuestForPureFlame.java @@ -45,6 +45,7 @@ import mage.counters.CounterType; import mage.game.Game; import mage.game.events.GameEvent; import mage.game.events.GameEvent.EventType; +import mage.util.CardUtil; /** * @@ -137,7 +138,7 @@ class QuestForPureFlameEffect extends ReplacementEffectImpl { @Override public boolean replaceEvent(GameEvent event, Ability source, Game game) { - event.setAmount(event.getAmount() * 2); + event.setAmount(CardUtil.addWithOverflowCheck(event.getAmount(), event.getAmount())); return false; } } diff --git a/Mage.Sets/src/mage/cards/r/RhysticDeluge.java b/Mage.Sets/src/mage/cards/r/RhysticDeluge.java new file mode 100644 index 00000000000..4434da3ec3b --- /dev/null +++ b/Mage.Sets/src/mage/cards/r/RhysticDeluge.java @@ -0,0 +1,66 @@ +/* + * 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.SimpleActivatedAbility; +import mage.abilities.costs.mana.ManaCostsImpl; +import mage.abilities.effects.common.DoUnlessTargetPlayerOrTargetsControllerPaysEffect; +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.target.common.TargetCreaturePermanent; + +/** + * + * @author L_J + */ +public class RhysticDeluge extends CardImpl { + + public RhysticDeluge(UUID ownerId, CardSetInfo setInfo) { + super(ownerId,setInfo,new CardType[]{CardType.ENCHANTMENT},"{2}{U}"); + + // {U}: Tap target creature unless its controller pays {1}. + Ability ability = new SimpleActivatedAbility(Zone.BATTLEFIELD, new DoUnlessTargetPlayerOrTargetsControllerPaysEffect(new TapTargetEffect(), new ManaCostsImpl("{1}")), new ManaCostsImpl("{U}")); + ability.addTarget(new TargetCreaturePermanent()); + this.addAbility(ability); + } + + public RhysticDeluge(final RhysticDeluge card) { + super(card); + } + + @Override + public RhysticDeluge copy() { + return new RhysticDeluge(this); + } +} diff --git a/Mage.Sets/src/mage/cards/r/RhysticLightning.java b/Mage.Sets/src/mage/cards/r/RhysticLightning.java new file mode 100644 index 00000000000..83d3f35dae1 --- /dev/null +++ b/Mage.Sets/src/mage/cards/r/RhysticLightning.java @@ -0,0 +1,65 @@ +/* + * 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.costs.mana.ManaCostsImpl; +import mage.abilities.effects.Effect; +import mage.abilities.effects.common.DamageTargetEffect; +import mage.abilities.effects.common.DoUnlessTargetPlayerOrTargetsControllerPaysEffect; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.target.common.TargetCreatureOrPlayer; + +/** + * + * @author L_J + */ +public class RhysticLightning extends CardImpl { + + public RhysticLightning(UUID ownerId, CardSetInfo setInfo) { + super(ownerId,setInfo,new CardType[]{CardType.INSTANT},"{2}{R}"); + + // Rhystic Lightning deals 4 damage to target creature or player unless that creature's controller or that player pays {2}. If he or she does, Rhystic Lightning deals 2 damage to the creature or player. + Effect effect = new DoUnlessTargetPlayerOrTargetsControllerPaysEffect(new DamageTargetEffect(4), new DamageTargetEffect(2), new ManaCostsImpl("{2}"), + "Pay {2} to have {this} deal 2 damage instead of 4 damage?"); + effect.setText("{this} deals 4 damage to target creature or player unless that creature's controller or that player pays {2}. If he or she does, {this} deals 2 damage to the creature or player"); + this.getSpellAbility().addEffect(effect); + this.getSpellAbility().addTarget(new TargetCreatureOrPlayer()); + } + + public RhysticLightning(final RhysticLightning card) { + super(card); + } + + @Override + public RhysticLightning copy() { + return new RhysticLightning(this); + } +} diff --git a/Mage.Sets/src/mage/cards/r/RhysticScrying.java b/Mage.Sets/src/mage/cards/r/RhysticScrying.java new file mode 100644 index 00000000000..f558aa0e119 --- /dev/null +++ b/Mage.Sets/src/mage/cards/r/RhysticScrying.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.r; + +import java.util.UUID; +import mage.MageObject; +import mage.abilities.Ability; +import mage.abilities.costs.Cost; +import mage.abilities.costs.mana.GenericManaCost; +import mage.abilities.effects.OneShotEffect; +import mage.abilities.effects.common.DrawCardSourceControllerEffect; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.Outcome; +import mage.game.Game; +import mage.players.Player; + +/** + * + * @author L_J + */ +public class RhysticScrying extends CardImpl { + + public RhysticScrying(UUID ownerId, CardSetInfo setInfo) { + super(ownerId,setInfo,new CardType[]{CardType.SORCERY},"{2}{U}{U}"); + + // Draw three cards. Then, if any player pays {2}, discard three cards. + this.getSpellAbility().addEffect(new DrawCardSourceControllerEffect(3)); + this.getSpellAbility().addEffect(new RhysticScryingEffect()); + } + + public RhysticScrying(final RhysticScrying card) { + super(card); + } + + @Override + public RhysticScrying copy() { + return new RhysticScrying(this); + } +} + +class RhysticScryingEffect extends OneShotEffect { + + public RhysticScryingEffect() { + super(Outcome.Benefit); + this.staticText = "Then, if any player pays {2}, discard three cards"; + } + + public RhysticScryingEffect(final RhysticScryingEffect effect) { + super(effect); + } + + @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) { + boolean result = true; + boolean doEffect = false; + Cost cost = new GenericManaCost(2); + // 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, "Pay " + cost.getText() + " for " + sourceObject.getLogName() + "?", 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 for " + sourceObject.getLogName()); + } + doEffect = true; + } + } + } + // do the effects if anybody paid + if (doEffect) { + controller.discard(3, false, source, game); + } + return result; + } + return false; + } + + @Override + public RhysticScryingEffect copy() { + return new RhysticScryingEffect(this); + } +} diff --git a/Mage.Sets/src/mage/cards/r/RhysticShield.java b/Mage.Sets/src/mage/cards/r/RhysticShield.java new file mode 100644 index 00000000000..ad8e47187f9 --- /dev/null +++ b/Mage.Sets/src/mage/cards/r/RhysticShield.java @@ -0,0 +1,65 @@ +/* + * 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.costs.mana.ManaCostsImpl; +import mage.abilities.effects.Effect; +import mage.abilities.effects.common.DoUnlessAnyPlayerPaysEffect; +import mage.abilities.effects.common.continuous.BoostControlledEffect; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.Duration; +import mage.filter.StaticFilters; + +/** + * + * @author L_J + */ +public class RhysticShield extends CardImpl { + + public RhysticShield(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.INSTANT}, "{1}{W}"); + + // Creatures you control get +0/+1 until end of turn. They get an additional +0/+2 until end of turn unless any player pays {2}. + this.getSpellAbility().addEffect(new BoostControlledEffect(0, 1, Duration.EndOfTurn, StaticFilters.FILTER_PERMANENT_CREATURE, false)); + Effect effect = new DoUnlessAnyPlayerPaysEffect(new BoostControlledEffect(0, 2, Duration.EndOfTurn, StaticFilters.FILTER_PERMANENT_CREATURE, false), new ManaCostsImpl("{2}")); + effect.setText("They get an additional +0/+2 until end of turn unless any player pays {2}"); + this.getSpellAbility().addEffect(effect); + } + + public RhysticShield(final RhysticShield card) { + super(card); + } + + @Override + public RhysticShield copy() { + return new RhysticShield(this); + } +} diff --git a/Mage.Sets/src/mage/cards/r/RhysticSyphon.java b/Mage.Sets/src/mage/cards/r/RhysticSyphon.java new file mode 100644 index 00000000000..9435deb09fb --- /dev/null +++ b/Mage.Sets/src/mage/cards/r/RhysticSyphon.java @@ -0,0 +1,66 @@ +/* + * 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.costs.mana.ManaCostsImpl; +import mage.abilities.effects.Effect; +import mage.abilities.effects.common.DoUnlessTargetPlayerOrTargetsControllerPaysEffect; +import mage.abilities.effects.common.GainLifeEffect; +import mage.abilities.effects.common.LoseLifeTargetEffect; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.target.TargetPlayer; + +/** + * + * @author L_J + */ +public class RhysticSyphon extends CardImpl { + + public RhysticSyphon(UUID ownerId, CardSetInfo setInfo) { + super(ownerId,setInfo,new CardType[]{CardType.SORCERY},"{3}{B}{B}"); + + // Unless target player pays {3}, he or she loses 5 life and you gain 5 life. + DoUnlessTargetPlayerOrTargetsControllerPaysEffect effect = new DoUnlessTargetPlayerOrTargetsControllerPaysEffect(new LoseLifeTargetEffect(5), new ManaCostsImpl("{3}")); + effect.addEffect(new GainLifeEffect(5)); + effect.setText("Unless target player pays {3}, he or she loses 5 life and you gain 5 life"); + this.getSpellAbility().addEffect(effect); + this.getSpellAbility().addTarget(new TargetPlayer()); + } + + public RhysticSyphon(final RhysticSyphon card) { + super(card); + } + + @Override + public RhysticSyphon copy() { + return new RhysticSyphon(this); + } +} diff --git a/Mage.Sets/src/mage/cards/r/Rupture.java b/Mage.Sets/src/mage/cards/r/Rupture.java new file mode 100644 index 00000000000..d504b53365e --- /dev/null +++ b/Mage.Sets/src/mage/cards/r/Rupture.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.r; + +import java.util.UUID; +import mage.abilities.Ability; +import mage.abilities.effects.OneShotEffect; +import mage.abilities.effects.common.DamageEverythingEffect; +import mage.abilities.keyword.FlyingAbility; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.Outcome; +import mage.filter.common.FilterControlledCreaturePermanent; +import mage.filter.common.FilterCreaturePermanent; +import mage.filter.predicate.Predicates; +import mage.filter.predicate.mageobject.AbilityPredicate; +import mage.game.Game; +import mage.game.permanent.Permanent; +import mage.players.Player; +import mage.target.common.TargetControlledCreaturePermanent; + +/** + * + * @author L_J + */ +public class Rupture extends CardImpl { + + public Rupture(UUID ownerId, CardSetInfo setInfo) { + super(ownerId,setInfo,new CardType[]{CardType.SORCERY},"{2}{R}"); + + // Sacrifice a creature. Rupture deals damage equal to that creature's power to each creature without flying and each player. + this.getSpellAbility().addEffect(new RuptureEffect()); + } + + public Rupture(final Rupture card) { + super(card); + } + + @Override + public Rupture copy() { + return new Rupture(this); + } +} + +class RuptureEffect extends OneShotEffect { + + private static final FilterCreaturePermanent filter = new FilterCreaturePermanent("creature without flying"); + + static { + filter.add(Predicates.not(new AbilityPredicate(FlyingAbility.class))); + } + + public RuptureEffect() { + super(Outcome.Damage); + staticText = "Sacrifice a creature. Rupture deals damage equal to that creature's power to each creature without flying and each player"; + } + + public RuptureEffect(final RuptureEffect effect) { + super(effect); + } + + @Override + public boolean apply(Game game, Ability source) { + Player player = game.getPlayer(source.getControllerId()); + if (player != null) { + int power = 0; + TargetControlledCreaturePermanent target = new TargetControlledCreaturePermanent(1, 1, new FilterControlledCreaturePermanent("creature to sacrifice"), true); + if (target.canChoose(source.getSourceId(), player.getId(), game)) { + while (!target.isChosen() && target.canChoose(player.getId(), game) && player.canRespond()) { + player.chooseTarget(Outcome.Sacrifice, target, source, game); + } + Permanent permanent = game.getPermanent(target.getFirstTarget()); + if (permanent != null) { + power = permanent.getPower().getValue(); + permanent.sacrifice(source.getSourceId(), game); + } + } + if (power > 0) { + new DamageEverythingEffect(power, filter).apply(game, source); + } + return true; + } + return false; + } + + @Override + public RuptureEffect copy() { + return new RuptureEffect(this); + } +} diff --git a/Mage.Sets/src/mage/cards/s/Seeker.java b/Mage.Sets/src/mage/cards/s/Seeker.java new file mode 100644 index 00000000000..012a0ea0153 --- /dev/null +++ b/Mage.Sets/src/mage/cards/s/Seeker.java @@ -0,0 +1,91 @@ +/* + * 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.common.SimpleEvasionAbility; +import mage.abilities.effects.common.AttachEffect; +import mage.abilities.effects.common.combat.CantBeBlockedByCreaturesAttachedEffect; +import mage.abilities.keyword.EnchantAbility; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.SubType; +import mage.constants.AttachmentType; +import mage.constants.Duration; +import mage.constants.Outcome; +import mage.filter.common.FilterCreaturePermanent; +import mage.filter.predicate.Predicates; +import mage.filter.predicate.mageobject.CardTypePredicate; +import mage.filter.predicate.mageobject.ColorPredicate; +import mage.target.TargetPermanent; +import mage.target.common.TargetCreaturePermanent; + +/** + * + * @author LevelX2 & L_J + */ +public class Seeker extends CardImpl { + + private static final FilterCreaturePermanent filter = new FilterCreaturePermanent("except by artifact creatures and/or white creatures"); + + static { + filter.add(Predicates.not( + Predicates.or( + Predicates.and(new CardTypePredicate(CardType.ARTIFACT), new CardTypePredicate(CardType.CREATURE)), + Predicates.and(new CardTypePredicate(CardType.CREATURE), new ColorPredicate(ObjectColor.WHITE) + )))); + } + + public Seeker(UUID ownerId, CardSetInfo setInfo) { + super(ownerId,setInfo,new CardType[]{CardType.ENCHANTMENT},"{2}{W}{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); + + // Enchanted creature can't be blocked except by artifact creatures and/or white creatures. + this.addAbility(new SimpleEvasionAbility(new CantBeBlockedByCreaturesAttachedEffect(Duration.WhileOnBattlefield, filter, AttachmentType.AURA))); + + } + + public Seeker(final Seeker card) { + super(card); + } + + @Override + public Seeker copy() { + return new Seeker(this); + } +} diff --git a/Mage.Sets/src/mage/cards/s/Sentinel.java b/Mage.Sets/src/mage/cards/s/Sentinel.java index 1c67461fe41..c3c630145d5 100644 --- a/Mage.Sets/src/mage/cards/s/Sentinel.java +++ b/Mage.Sets/src/mage/cards/s/Sentinel.java @@ -51,6 +51,7 @@ import mage.game.Game; import mage.game.permanent.Permanent; import mage.players.Player; import mage.target.common.TargetCreaturePermanent; +import mage.util.CardUtil; /** * @@ -105,7 +106,7 @@ class SentinelEffect extends OneShotEffect { Player controller = game.getPlayer(source.getControllerId()); Permanent targetPermanent = game.getPermanentOrLKIBattlefield(targetPointer.getFirst(game, source)); if (controller != null && targetPermanent != null) { - int newToughness = targetPermanent.getPower().getValue() + 1; + int newToughness = CardUtil.addWithOverflowCheck(targetPermanent.getPower().getValue(), 1); game.addEffect(new SetToughnessSourceEffect(new StaticValue(newToughness), Duration.Custom, SubLayer.SetPT_7b), source); return true; } diff --git a/Mage.Sets/src/mage/cards/s/ShieldmageElder.java b/Mage.Sets/src/mage/cards/s/ShieldmageElder.java new file mode 100644 index 00000000000..63c56953458 --- /dev/null +++ b/Mage.Sets/src/mage/cards/s/ShieldmageElder.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.SimpleActivatedAbility; +import mage.abilities.costs.common.TapTargetCost; +import mage.abilities.effects.common.PreventDamageByTargetEffect; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.SubType; +import mage.constants.Duration; +import mage.constants.Zone; +import mage.filter.common.FilterControlledPermanent; +import mage.filter.predicate.Predicates; +import mage.filter.predicate.mageobject.SubtypePredicate; +import mage.filter.predicate.permanent.TappedPredicate; +import mage.target.TargetSpell; +import mage.target.common.TargetControlledPermanent; +import mage.target.common.TargetCreaturePermanent; + +/** + * + * @author L_J + */ +public class ShieldmageElder extends CardImpl { + + private static final FilterControlledPermanent filter1 = new FilterControlledPermanent("untapped Clerics you control"); + + static { + filter1.add(Predicates.not(new TappedPredicate())); + filter1.add(new SubtypePredicate(SubType.CLERIC)); + } + private static final FilterControlledPermanent filter2 = new FilterControlledPermanent("untapped Wizards you control"); + + static { + filter2.add(Predicates.not(new TappedPredicate())); + filter2.add(new SubtypePredicate(SubType.WIZARD)); + } + + public ShieldmageElder(UUID ownerId, CardSetInfo setInfo) { + super(ownerId,setInfo,new CardType[]{CardType.CREATURE},"{5}{W}"); + this.subtype.add(SubType.HUMAN); + this.subtype.add(SubType.CLERIC); + this.subtype.add(SubType.WIZARD); + this.power = new MageInt(2); + this.toughness = new MageInt(3); + + // Tap two untapped Clerics you control: Prevent all damage target creature would deal this turn. + Ability ability = new SimpleActivatedAbility(Zone.BATTLEFIELD, new PreventDamageByTargetEffect(Duration.EndOfTurn), new TapTargetCost(new TargetControlledPermanent(2, 2, filter1, false))); + ability.addTarget(new TargetCreaturePermanent()); + this.addAbility(ability); + + // Tap two untapped Wizards you control: Prevent all damage target spell would deal this turn. + Ability ability2 = new SimpleActivatedAbility(Zone.BATTLEFIELD, new PreventDamageByTargetEffect(Duration.EndOfTurn), new TapTargetCost(new TargetControlledPermanent(2, 2, filter2, false))); + ability2.addTarget(new TargetSpell()); + this.addAbility(ability2); + } + + public ShieldmageElder(final ShieldmageElder card) { + super(card); + } + + @Override + public ShieldmageElder copy() { + return new ShieldmageElder(this); + } +} diff --git a/Mage.Sets/src/mage/cards/s/ShroudedSerpent.java b/Mage.Sets/src/mage/cards/s/ShroudedSerpent.java new file mode 100644 index 00000000000..7730f739d74 --- /dev/null +++ b/Mage.Sets/src/mage/cards/s/ShroudedSerpent.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.MageInt; +import mage.abilities.common.AttacksTriggeredAbility; +import mage.abilities.costs.mana.ManaCostsImpl; +import mage.abilities.effects.common.DoUnlessTargetPlayerOrTargetsControllerPaysEffect; +import mage.abilities.effects.common.combat.CantBeBlockedByAllSourceEffect; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.SubType; +import mage.constants.SetTargetPointer; +import mage.constants.Duration; +import mage.filter.common.FilterCreaturePermanent; + +/** + * + * @author L_J + */ +public class ShroudedSerpent extends CardImpl { + + public ShroudedSerpent(UUID ownerId, CardSetInfo setInfo) { + super(ownerId,setInfo,new CardType[]{CardType.CREATURE},"{4}{U}{U}{U}"); + this.subtype.add(SubType.SERPENT); + this.power = new MageInt(4); + this.toughness = new MageInt(4); + + // Whenever Shrouded Serpent attacks, defending player may pay {4}. If he or she doesn't, Shrouded Serpent can't be blocked this turn. + this.addAbility(new AttacksTriggeredAbility( + new DoUnlessTargetPlayerOrTargetsControllerPaysEffect(new CantBeBlockedByAllSourceEffect(new FilterCreaturePermanent(), Duration.EndOfCombat), new ManaCostsImpl("{4}")), + false, + "Whenever {this} attacks, defending player may pay {4}. If he or she doesn't, {this} can't be blocked this turn.", + SetTargetPointer.PLAYER)); + } + + public ShroudedSerpent(final ShroudedSerpent card) { + super(card); + } + + @Override + public ShroudedSerpent copy() { + return new ShroudedSerpent(this); + } +} diff --git a/Mage.Sets/src/mage/cards/s/SivvisValor.java b/Mage.Sets/src/mage/cards/s/SivvisValor.java new file mode 100644 index 00000000000..c63a2b21f14 --- /dev/null +++ b/Mage.Sets/src/mage/cards/s/SivvisValor.java @@ -0,0 +1,140 @@ +/* + * 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.condition.common.PermanentsOnTheBattlefieldCondition; +import mage.abilities.costs.AlternativeCostSourceAbility; +import mage.abilities.costs.Cost; +import mage.abilities.costs.common.TapTargetCost; +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.game.permanent.Permanent; +import mage.players.Player; +import mage.filter.FilterPermanent; +import mage.filter.common.FilterControlledCreaturePermanent; +import mage.filter.predicate.Predicates; +import mage.filter.predicate.mageobject.SubtypePredicate; +import mage.filter.predicate.permanent.TappedPredicate; +import mage.target.common.TargetControlledPermanent; +import mage.target.common.TargetCreaturePermanent; + +/** + * + * @author L_J + */ +public class SivvisValor extends CardImpl { + + private static final FilterPermanent filter = new FilterPermanent("If you control a Plains"); + private static final FilterControlledCreaturePermanent filterCreature = new FilterControlledCreaturePermanent("untapped creature you control"); + + static { + filter.add(new SubtypePredicate(SubType.PLAINS)); + filterCreature.add(Predicates.not(new TappedPredicate())); + } + + public SivvisValor(UUID ownerId, CardSetInfo setInfo) { + super(ownerId,setInfo,new CardType[]{CardType.INSTANT},"{2}{W}"); + + // If you control a Plains, you may tap an untapped creature you control rather than pay Sivvi's Valor's mana cost. + Cost cost = new TapTargetCost(new TargetControlledPermanent(1,1,filterCreature,false)); + cost.setText(" tap an untapped creature you control"); + this.addAbility(new AlternativeCostSourceAbility(cost, new PermanentsOnTheBattlefieldCondition(filter))); + + // All damage that would be dealt to target creature this turn is dealt to you instead. + this.getSpellAbility().addEffect(new SivvisValorEffect()); + this.getSpellAbility().addTarget(new TargetCreaturePermanent()); + } + + public SivvisValor(final SivvisValor card) { + super(card); + } + + @Override + public SivvisValor copy() { + return new SivvisValor(this); + } +} + +class SivvisValorEffect extends ReplacementEffectImpl { + + public SivvisValorEffect() { + super(Duration.EndOfTurn, Outcome.RedirectDamage); + staticText = "All damage that would be dealt to target creature this turn is dealt to you instead"; + } + + public SivvisValorEffect(final SivvisValorEffect effect) { + super(effect); + } + + @Override + public SivvisValorEffect copy() { + return new SivvisValorEffect(this); + } + + @Override + public boolean checksEventType(GameEvent event, Game game) { + return event.getType() == GameEvent.EventType.DAMAGE_CREATURE; + } + + @Override + public boolean apply(Game game, Ability source) { + return true; + } + + @Override + public boolean replaceEvent(GameEvent event, Ability source, Game game) { + Player controller = game.getPlayer(source.getControllerId()); + DamageEvent damageEvent = (DamageEvent) event; + if (controller != null) { + controller.damage(damageEvent.getAmount(), damageEvent.getSourceId(), game, damageEvent.isCombatDamage(), damageEvent.isPreventable(), damageEvent.getAppliedEffects()); + return true; + } + return false; + } + + @Override + public boolean applies(GameEvent event, Ability source, Game game) { + Player controller = game.getPlayer(source.getControllerId()); + DamageEvent damageEvent = (DamageEvent) event; + Permanent targetPermanent = game.getPermanent(source.getFirstTarget()); + if (controller != null && targetPermanent != null) { + return targetPermanent.getId() == damageEvent.getTargetId(); + } + return false; + } +} diff --git a/Mage.Sets/src/mage/cards/s/SoldeviSteamBeast.java b/Mage.Sets/src/mage/cards/s/SoldeviSteamBeast.java new file mode 100644 index 00000000000..41c9a6c84ed --- /dev/null +++ b/Mage.Sets/src/mage/cards/s/SoldeviSteamBeast.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.s; + +import java.util.UUID; +import mage.MageInt; +import mage.abilities.Ability; +import mage.abilities.common.BecomesTappedSourceTriggeredAbility; +import mage.abilities.common.SimpleActivatedAbility; +import mage.abilities.costs.mana.GenericManaCost; +import mage.abilities.effects.common.GainLifeTargetEffect; +import mage.abilities.effects.common.RegenerateSourceEffect; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.SubType; +import mage.constants.Zone; +import mage.target.common.TargetOpponent; + +/** + * + * @author L_J + */ +public class SoldeviSteamBeast extends CardImpl { + + public SoldeviSteamBeast(UUID ownerId, CardSetInfo setInfo) { + super(ownerId,setInfo,new CardType[]{CardType.ARTIFACT,CardType.CREATURE},"{5}"); + this.subtype.add(SubType.BEAST); + this.power = new MageInt(4); + this.toughness = new MageInt(2); + + // Whenever Soldevi Steam Beast becomes tapped, target opponent gains 2 life. + Ability ability = new BecomesTappedSourceTriggeredAbility(new GainLifeTargetEffect(2)); + ability.addTarget(new TargetOpponent()); + this.addAbility(ability); + + // {2}: Regenerate Soldevi Steam Beast. + this.addAbility(new SimpleActivatedAbility(Zone.BATTLEFIELD, new RegenerateSourceEffect(), new GenericManaCost(3))); + } + + public SoldeviSteamBeast(final SoldeviSteamBeast card) { + super(card); + } + + @Override + public SoldeviSteamBeast copy() { + return new SoldeviSteamBeast(this); + } +} diff --git a/Mage.Sets/src/mage/cards/s/SoulCharmer.java b/Mage.Sets/src/mage/cards/s/SoulCharmer.java new file mode 100644 index 00000000000..9602b4ffc6a --- /dev/null +++ b/Mage.Sets/src/mage/cards/s/SoulCharmer.java @@ -0,0 +1,66 @@ +/* + * 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.common.DealsCombatDamageToACreatureTriggeredAbility; +import mage.abilities.costs.mana.ManaCostsImpl; +import mage.abilities.effects.common.DoUnlessTargetPlayerOrTargetsControllerPaysEffect; +import mage.abilities.effects.common.GainLifeEffect; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.SubType; + +/** + * + * @author L_J + */ +public class SoulCharmer extends CardImpl { + + public SoulCharmer(UUID ownerId, CardSetInfo setInfo) { + super(ownerId,setInfo,new CardType[]{CardType.CREATURE},"{2}{W}"); + this.subtype.add(SubType.HUMAN); + this.subtype.add(SubType.REBEL); + this.power = new MageInt(2); + this.toughness = new MageInt(2); + + // Whenever Soul Charmer deals combat damage to a creature, you gain 2 life unless he or she pays {2}. + this.addAbility(new DealsCombatDamageToACreatureTriggeredAbility(new DoUnlessTargetPlayerOrTargetsControllerPaysEffect(new GainLifeEffect(2), new ManaCostsImpl("{2}")), false, true)); + } + + public SoulCharmer(final SoulCharmer card) { + super(card); + } + + @Override + public SoulCharmer copy() { + return new SoulCharmer(this); + } +} diff --git a/Mage.Sets/src/mage/cards/s/SpiritualFocus.java b/Mage.Sets/src/mage/cards/s/SpiritualFocus.java new file mode 100644 index 00000000000..5e14d68ba20 --- /dev/null +++ b/Mage.Sets/src/mage/cards/s/SpiritualFocus.java @@ -0,0 +1,140 @@ +/* + * 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.TriggeredAbilityImpl; +import mage.abilities.effects.OneShotEffect; +import mage.abilities.effects.common.GainLifeEffect; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +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.game.stack.StackObject; +import mage.players.Player; + +/** + * + * @author L_J + */ +public class SpiritualFocus extends CardImpl { + + public SpiritualFocus(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.ENCHANTMENT}, "{1}{W}"); + + // Whenever a spell or ability an opponent controls causes you to discard a card, you gain 2 life and you may draw a card. + this.addAbility(new SpiritualFocusTriggeredAbility()); + } + + public SpiritualFocus(final SpiritualFocus card) { + super(card); + } + + @Override + public SpiritualFocus copy() { + return new SpiritualFocus(this); + } +} + +class SpiritualFocusTriggeredAbility extends TriggeredAbilityImpl { + + public SpiritualFocusTriggeredAbility() { + super(Zone.BATTLEFIELD, new GainLifeEffect(2), false); + this.addEffect(new SpiritualFocusDrawCardEffect()); + } + + public SpiritualFocusTriggeredAbility(final SpiritualFocusTriggeredAbility ability) { + super(ability); + } + + @Override + public SpiritualFocusTriggeredAbility copy() { + return new SpiritualFocusTriggeredAbility(this); + } + + @Override + public boolean checkEventType(GameEvent event, Game game) { + return event.getType() == EventType.DISCARDED_CARD; + } + + @Override + public boolean checkTrigger(GameEvent event, Game game) { + StackObject stackObject = game.getStack().getStackObject(event.getSourceId()); + if (stackObject != null) { + if (game.getOpponents(this.getControllerId()).contains(stackObject.getControllerId())) { + Permanent permanent = game.getPermanent(getSourceId()); + if (permanent != null) { + if (permanent.getControllerId() == event.getPlayerId()) { + return true; + } + } + } + } + return false; + } + + @Override + public String getRule() { + return "Whenever a spell or ability an opponent controls causes you to discard a card, you gain 2 life and you may draw a card."; + } +} + +class SpiritualFocusDrawCardEffect extends OneShotEffect { + + public SpiritualFocusDrawCardEffect() { + super(Outcome.DrawCard); + } + + public SpiritualFocusDrawCardEffect(final SpiritualFocusDrawCardEffect effect) { + super(effect); + } + + @Override + public SpiritualFocusDrawCardEffect copy() { + return new SpiritualFocusDrawCardEffect(this); + } + + @Override + public boolean apply(Game game, Ability source) { + Permanent permanent = game.getPermanent(source.getSourceId()); + Player player = game.getPlayer(source.getControllerId()); + if (player != null && permanent != null) { + if (player.chooseUse(outcome, "Draw a card (" + permanent.getLogName() + ')', source, game)) { + player.drawCards(1, game); + } + return true; + } + return false; + } +} diff --git a/Mage.Sets/src/mage/cards/s/StromgaldSpy.java b/Mage.Sets/src/mage/cards/s/StromgaldSpy.java new file mode 100644 index 00000000000..082fe025195 --- /dev/null +++ b/Mage.Sets/src/mage/cards/s/StromgaldSpy.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.s; + +import java.util.UUID; +import mage.MageInt; +import mage.abilities.Ability; +import mage.abilities.common.AttacksAndIsNotBlockedTriggeredAbility; +import mage.abilities.effects.ContinuousEffectImpl; +import mage.abilities.effects.common.continuous.AssignNoCombatDamageSourceEffect; +import mage.constants.SubType; +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.game.Game; +import mage.game.permanent.Permanent; +import mage.players.Player; + +/** + * + * @author L_J + */ +public class StromgaldSpy extends CardImpl { + + public StromgaldSpy(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{3}{B}"); + this.subtype.add(SubType.HUMAN); + this.subtype.add(SubType.ROGUE); + this.power = new MageInt(2); + this.toughness = new MageInt(4); + + // Whenever Stromgald Spy attacks and isn't blocked, you may have defending player play with his or her hand revealed for as long as Stromgald Spy remains on the battlefield. If you do, Stromgald Spy assigns no combat damage this turn. + Ability ability = new AttacksAndIsNotBlockedTriggeredAbility(new StromgaldSpyEffect(), true, true); + ability.addEffect(new AssignNoCombatDamageSourceEffect(Duration.EndOfTurn, true)); + this.addAbility(ability); + } + + public StromgaldSpy(final StromgaldSpy card) { + super(card); + } + + @Override + public StromgaldSpy copy() { + return new StromgaldSpy(this); + } +} + +class StromgaldSpyEffect extends ContinuousEffectImpl { + + public StromgaldSpyEffect() { + super(Duration.WhileOnBattlefield, Layer.PlayerEffects, SubLayer.NA, Outcome.Detriment); + this.staticText = "you may have defending player play with his or her hand revealed for as long as Stromgald Spy remains on the battlefield"; + } + + public StromgaldSpyEffect(final StromgaldSpyEffect effect) { + super(effect); + } + + @Override + public boolean apply(Game game, Ability source) { + Permanent sourcePermanent = game.getPermanent(source.getSourceId()); + Player controller = game.getPlayer(source.getControllerId()); + if (controller != null && sourcePermanent != null) { + Player defender = game.getPlayer(this.getTargetPointer().getFirst(game, source)); + if (defender != null) { + defender.revealCards(defender.getName() + "'s hand cards", defender.getHand(), game, false); + } + return true; + } + return false; + } + + @Override + public StromgaldSpyEffect copy() { + return new StromgaldSpyEffect(this); + } +} diff --git a/Mage.Sets/src/mage/cards/s/SwabGoblin.java b/Mage.Sets/src/mage/cards/s/SwabGoblin.java new file mode 100644 index 00000000000..69705ad8f5f --- /dev/null +++ b/Mage.Sets/src/mage/cards/s/SwabGoblin.java @@ -0,0 +1,60 @@ +/* + * 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.constants.SubType; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; + +/** + * + * @author LevelX2 + */ +public class SwabGoblin extends CardImpl { + + public SwabGoblin(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{1}{R}"); + + this.subtype.add(SubType.GOBLIN); + this.subtype.add(SubType.PIRATE); + this.power = new MageInt(2); + this.toughness = new MageInt(2); + } + + public SwabGoblin(final SwabGoblin card) { + super(card); + } + + @Override + public SwabGoblin copy() { + return new SwabGoblin(this); + } +} diff --git a/Mage.Sets/src/mage/cards/t/TetzimocPrimalDeath.java b/Mage.Sets/src/mage/cards/t/TetzimocPrimalDeath.java new file mode 100644 index 00000000000..751f6f6b3aa --- /dev/null +++ b/Mage.Sets/src/mage/cards/t/TetzimocPrimalDeath.java @@ -0,0 +1,99 @@ +/* + * 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.ActivateIfConditionActivatedAbility; +import mage.abilities.common.EntersBattlefieldTriggeredAbility; +import mage.abilities.condition.common.MyTurnCondition; +import mage.abilities.costs.common.RevealSourceFromYourHandCost; +import mage.abilities.costs.mana.ManaCostsImpl; +import mage.abilities.effects.common.DestroyAllEffect; +import mage.abilities.effects.common.counter.AddCountersTargetEffect; +import mage.abilities.keyword.DeathtouchAbility; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.SubType; +import mage.constants.SuperType; +import mage.constants.TargetController; +import mage.constants.Zone; +import mage.counters.CounterType; +import mage.filter.common.FilterCreaturePermanent; +import mage.filter.predicate.permanent.ControllerPredicate; +import mage.filter.predicate.permanent.CounterPredicate; +import mage.target.common.TargetCreaturePermanent; + +/** + * + * @author LevelX2 + */ +public class TetzimocPrimalDeath extends CardImpl { + + private static final FilterCreaturePermanent filter = new FilterCreaturePermanent("creature your opponents control with a prey counter on it"); + + static { + filter.add(new ControllerPredicate(TargetController.OPPONENT)); + filter.add(new CounterPredicate(CounterType.PREY)); + } + + public TetzimocPrimalDeath(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{4}{B}{B}"); + + this.addSuperType(SuperType.LEGENDARY); + this.subtype.add(SubType.ELDER); + this.subtype.add(SubType.DINOSAUR); + this.power = new MageInt(6); + this.toughness = new MageInt(6); + + // Deathtouch + this.addAbility(DeathtouchAbility.getInstance()); + + // {B}, Reveal Tetzimoc, Primal Death from your hand: Put a prey counter on target creature. Activate this ability only during your turn. + Ability ability = new ActivateIfConditionActivatedAbility(Zone.HAND, new AddCountersTargetEffect(CounterType.PREY.createInstance()), new ManaCostsImpl("{B}"), MyTurnCondition.instance); + ability.addTarget(new TargetCreaturePermanent()); + ability.addCost(new RevealSourceFromYourHandCost()); + this.addAbility(ability); + + // When Tetzimoc, Primal Death enters the battlefield, destroy each creature your opponents control with a prey counter on it. + this.addAbility(new EntersBattlefieldTriggeredAbility( + new DestroyAllEffect(filter).setText("destroy each creature your opponents control with a prey counter on it"), false)); + + } + + public TetzimocPrimalDeath(final TetzimocPrimalDeath card) { + super(card); + } + + @Override + public TetzimocPrimalDeath copy() { + return new TetzimocPrimalDeath(this); + } +} diff --git a/Mage.Sets/src/mage/cards/t/TheImmortalSun.java b/Mage.Sets/src/mage/cards/t/TheImmortalSun.java new file mode 100644 index 00000000000..96d723723e8 --- /dev/null +++ b/Mage.Sets/src/mage/cards/t/TheImmortalSun.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.t; + +import java.util.Optional; +import java.util.UUID; +import mage.MageObject; +import mage.abilities.Ability; +import mage.abilities.LoyaltyAbility; +import mage.abilities.common.BeginningOfDrawTriggeredAbility; +import mage.abilities.common.SimpleStaticAbility; +import mage.abilities.effects.ContinuousRuleModifyingEffectImpl; +import mage.abilities.effects.common.DrawCardSourceControllerEffect; +import mage.abilities.effects.common.continuous.BoostControlledEffect; +import mage.abilities.effects.common.cost.SpellsCostReductionControllerEffect; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +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.filter.FilterCard; +import mage.game.Game; +import mage.game.events.GameEvent; +import mage.game.permanent.Permanent; + +/** + * + * @author LevelX2 + */ +public class TheImmortalSun extends CardImpl { + + public TheImmortalSun(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.ARTIFACT}, "{6}"); + + this.addSuperType(SuperType.LEGENDARY); + + // Players can't activate loyalty abilities of planeswalkers. + this.addAbility(new SimpleStaticAbility(Zone.BATTLEFIELD, new TheImmortalSunCantActivateEffect())); + // At the beginning of your draw step, draw an additional card. + this.addAbility(new BeginningOfDrawTriggeredAbility(new DrawCardSourceControllerEffect(1), TargetController.YOU, false)); + // Spells you cast cost {1} less to cast. + this.addAbility(new SimpleStaticAbility(Zone.BATTLEFIELD, new SpellsCostReductionControllerEffect(new FilterCard("Spells you cast"), 1))); + // Creatures you control get +1/+1. + this.addAbility(new SimpleStaticAbility(Zone.BATTLEFIELD, new BoostControlledEffect(1, 1, Duration.WhileOnBattlefield))); + } + + public TheImmortalSun(final TheImmortalSun card) { + super(card); + } + + @Override + public TheImmortalSun copy() { + return new TheImmortalSun(this); + } +} + +class TheImmortalSunCantActivateEffect extends ContinuousRuleModifyingEffectImpl { + + public TheImmortalSunCantActivateEffect() { + super(Duration.WhileOnBattlefield, Outcome.Detriment); + staticText = "Players can't activate loyalty abilities of planeswalkers"; + } + + public TheImmortalSunCantActivateEffect(final TheImmortalSunCantActivateEffect effect) { + super(effect); + } + + @Override + public TheImmortalSunCantActivateEffect copy() { + return new TheImmortalSunCantActivateEffect(this); + } + + @Override + public boolean apply(Game game, Ability source) { + return true; + } + + @Override + public String getInfoMessage(Ability source, GameEvent event, Game game) { + MageObject mageObject = game.getObject(source.getSourceId()); + if (mageObject != null) { + return "You can't activate loyalty abilities of planeswalkers (" + mageObject.getIdName() + ")."; + } + return null; + } + + @Override + public boolean applies(GameEvent event, Ability source, Game game) { + if (event.getType() == GameEvent.EventType.ACTIVATE_ABILITY) { + Permanent permanent = game.getPermanentOrLKIBattlefield(event.getSourceId()); + if (permanent == null) { + return false; + } + if (permanent.isPlaneswalker()) { + Optional ability = game.getAbility(event.getTargetId(), event.getSourceId()); + return ability.isPresent() && (ability.get() instanceof LoyaltyAbility); + } + } + return false; + } +} diff --git a/Mage.Sets/src/mage/cards/t/ThresherBeast.java b/Mage.Sets/src/mage/cards/t/ThresherBeast.java new file mode 100644 index 00000000000..032bebd53a1 --- /dev/null +++ b/Mage.Sets/src/mage/cards/t/ThresherBeast.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.t; + +import java.util.UUID; +import mage.MageInt; +import mage.abilities.Ability; +import mage.abilities.common.BecomesBlockedByCreatureTriggeredAbility; +import mage.abilities.effects.Effect; +import mage.abilities.effects.OneShotEffect; +import mage.abilities.effects.common.SacrificeEffect; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.Outcome; +import mage.constants.SubType; +import mage.filter.StaticFilters; +import mage.game.Game; +import mage.game.permanent.Permanent; +import mage.players.Player; +import mage.target.targetpointer.FixedTarget; + +/** + * + * @author L_J + */ +public class ThresherBeast extends CardImpl { + + public ThresherBeast(UUID ownerId, CardSetInfo setInfo) { + super(ownerId,setInfo,new CardType[]{CardType.CREATURE},"{3}{G}{G}"); + this.subtype.add(SubType.BEAST); + this.power = new MageInt(4); + this.toughness = new MageInt(4); + + // Whenever Thresher Beast becomes blocked, defending player sacrifices a land. + this.addAbility(new BecomesBlockedByCreatureTriggeredAbility(new ThresherBeastEffect(), false)); + } + + public ThresherBeast(final ThresherBeast card) { + super(card); + } + + @Override + public ThresherBeast copy() { + return new ThresherBeast(this); + } +} + +class ThresherBeastEffect extends OneShotEffect { + + public ThresherBeastEffect() { + super(Outcome.Discard); + this.staticText = "defending player sacrifices a land"; + } + + public ThresherBeastEffect(final ThresherBeastEffect effect) { + super(effect); + } + + @Override + public ThresherBeastEffect copy() { + return new ThresherBeastEffect(this); + } + + @Override + public boolean apply(Game game, Ability source) { + Permanent blockingCreature = game.getPermanent(getTargetPointer().getFirst(game, source)); + if (blockingCreature != null) { + Player opponent = game.getPlayer(blockingCreature.getControllerId()); + if (opponent != null) { + Effect effect = new SacrificeEffect(StaticFilters.FILTER_LAND, 1, ""); + effect.setTargetPointer(new FixedTarget(opponent.getId())); + return effect.apply(game, source); + } + } + return false; + } +} diff --git a/Mage.Sets/src/mage/cards/t/Topple.java b/Mage.Sets/src/mage/cards/t/Topple.java new file mode 100644 index 00000000000..6b1a3ab0f53 --- /dev/null +++ b/Mage.Sets/src/mage/cards/t/Topple.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.t; + +import java.util.List; +import java.util.HashSet; +import java.util.Set; +import java.util.UUID; +import mage.MageObject; +import mage.abilities.Ability; +import mage.abilities.effects.common.ExileTargetEffect; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.filter.predicate.mageobject.CardTypePredicate; +import mage.game.Game; +import mage.game.permanent.Permanent; +import mage.target.TargetPermanent; + +/** + * + * @author L_J + */ +public class Topple extends CardImpl { + + public Topple (UUID ownerId, CardSetInfo setInfo) { + super(ownerId,setInfo,new CardType[]{CardType.SORCERY},"{2}{W}"); + + // Exile target creature with the greatest power among creatures on the battlefield. + this.getSpellAbility().addEffect(new ExileTargetEffect()); + this.getSpellAbility().addTarget(new ToppleTargetCreature()); + } + + public Topple (final Topple card) { + super(card); + } + + @Override + public Topple copy() { + return new Topple(this); + } +} + +class ToppleTargetCreature extends TargetPermanent { + + public ToppleTargetCreature() { + super(); + filter.add(new CardTypePredicate(CardType.CREATURE)); + setTargetName("creature with the greatest power among creatures on the battlefield"); + } + + public ToppleTargetCreature(final ToppleTargetCreature target) { + super(target); + } + + @Override + public boolean canTarget(UUID controllerId, UUID id, Ability source, Game game) { + if (super.canTarget(controllerId, id, source, game)) { + int maxPower = 0; + for (Permanent permanent : game.getBattlefield().getActivePermanents(filter, source.getControllerId(), source.getId(), game)) { + if (permanent.getPower().getValue() > maxPower) { + maxPower = permanent.getPower().getValue(); + } + } + Permanent targetPermanent = game.getPermanent(id); + if (targetPermanent != null) { + return targetPermanent.getPower().getValue() == maxPower; + } + } + return false; + } + + @Override + public Set possibleTargets(UUID sourceId, UUID sourceControllerId, Game game) { + int maxPower = 0; + List activePermanents = game.getBattlefield().getActivePermanents(filter, sourceControllerId, sourceId, game); + Set possibleTargets = new HashSet<>(); + MageObject targetSource = game.getObject(sourceId); + for (Permanent permanent : activePermanents) { + if (permanent.getPower().getValue() > maxPower) { + maxPower = permanent.getPower().getValue(); + } + } + for (Permanent permanent : activePermanents) { + if (!targets.containsKey(permanent.getId()) && permanent.canBeTargetedBy(targetSource, sourceControllerId, game)) { + if (permanent.getPower().getValue() == maxPower) { + possibleTargets.add(permanent.getId()); + } + } + } + return possibleTargets; + } + + @Override + public boolean canChoose(UUID sourceId, UUID sourceControllerId, Game game) { + return !possibleTargets(sourceId, sourceControllerId, game).isEmpty(); + } + + @Override + public ToppleTargetCreature copy() { + return new ToppleTargetCreature(this); + } +} diff --git a/Mage.Sets/src/mage/cards/t/TreacherousLink.java b/Mage.Sets/src/mage/cards/t/TreacherousLink.java new file mode 100644 index 00000000000..f5b7ed121f4 --- /dev/null +++ b/Mage.Sets/src/mage/cards/t/TreacherousLink.java @@ -0,0 +1,133 @@ +/* + * 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.SimpleStaticAbility; +import mage.abilities.effects.ReplacementEffectImpl; +import mage.abilities.effects.common.AttachEffect; +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.DamageEvent; +import mage.game.events.GameEvent; +import mage.game.permanent.Permanent; +import mage.players.Player; +import mage.target.TargetPermanent; +import mage.target.common.TargetCreaturePermanent; + +/** + * + * @author L_J + */ +public class TreacherousLink extends CardImpl { + + public TreacherousLink(UUID ownerId, CardSetInfo setInfo) { + super(ownerId,setInfo,new CardType[]{CardType.ENCHANTMENT},"{1}{B}"); + 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); + + // All damage that would be dealt to enchanted creature is dealt to its controller instead. + this.addAbility(new SimpleStaticAbility(Zone.BATTLEFIELD, new TreacherousLinkEffect())); + } + + public TreacherousLink(final TreacherousLink card) { + super(card); + } + + @Override + public TreacherousLink copy() { + return new TreacherousLink(this); + } +} + +class TreacherousLinkEffect extends ReplacementEffectImpl { + + public TreacherousLinkEffect() { + super(Duration.WhileOnBattlefield, Outcome.RedirectDamage); + staticText = "All damage that would be dealt to enchanted creature is dealt to its controller instead"; + } + + public TreacherousLinkEffect(final TreacherousLinkEffect effect) { + super(effect); + } + + @Override + public TreacherousLinkEffect copy() { + return new TreacherousLinkEffect(this); + } + + @Override + public boolean checksEventType(GameEvent event, Game game) { + return event.getType() == GameEvent.EventType.DAMAGE_CREATURE; + } + + @Override + public boolean apply(Game game, Ability source) { + return true; + } + + @Override + public boolean replaceEvent(GameEvent event, Ability source, Game game) { + DamageEvent damageEvent = (DamageEvent) event; + Permanent enchantedCreature = game.getPermanentOrLKIBattlefield(damageEvent.getTargetId()); + Player controller = game.getPlayer(enchantedCreature.getControllerId()); + if (enchantedCreature != null && controller != null) { + controller.damage(damageEvent.getAmount(), damageEvent.getSourceId(), game, damageEvent.isCombatDamage(), damageEvent.isPreventable(), damageEvent.getAppliedEffects()); + return true; + } + return false; + } + + @Override + public boolean applies(GameEvent event, Ability source, Game game) { + Permanent enchantment = game.getPermanentOrLKIBattlefield(source.getSourceId()); + Player controller = game.getPlayer(source.getControllerId()); + DamageEvent damageEvent = (DamageEvent) event; + if (controller != null && enchantment != null) { + Permanent enchantedCreature = game.getPermanentOrLKIBattlefield(enchantment.getAttachedTo()); + if (enchantedCreature != null) { + return enchantedCreature.getId() == damageEvent.getTargetId(); + } + } + return false; + } +} diff --git a/Mage.Sets/src/mage/cards/v/VampireChampion.java b/Mage.Sets/src/mage/cards/v/VampireChampion.java new file mode 100644 index 00000000000..95bb4358c93 --- /dev/null +++ b/Mage.Sets/src/mage/cards/v/VampireChampion.java @@ -0,0 +1,65 @@ +/* + * 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.MageInt; +import mage.constants.SubType; +import mage.abilities.keyword.DeathtouchAbility; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; + +/** + * + * @author LevelX2 + */ +public class VampireChampion extends CardImpl { + + public VampireChampion(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{3}{B}"); + + this.subtype.add(SubType.VAMPIRE); + this.subtype.add(SubType.SOLDIER); + this.power = new MageInt(3); + this.toughness = new MageInt(3); + + // Deathtouch + this.addAbility(DeathtouchAbility.getInstance()); + + } + + public VampireChampion(final VampireChampion card) { + super(card); + } + + @Override + public VampireChampion copy() { + return new VampireChampion(this); + } +} diff --git a/Mage.Sets/src/mage/cards/v/VeteranBrawlers.java b/Mage.Sets/src/mage/cards/v/VeteranBrawlers.java new file mode 100644 index 00000000000..1ab3d12c248 --- /dev/null +++ b/Mage.Sets/src/mage/cards/v/VeteranBrawlers.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.v; + +import java.util.UUID; +import mage.MageInt; +import mage.abilities.Ability; +import mage.abilities.common.SimpleStaticAbility; +import mage.abilities.effects.RestrictionEffect; +import mage.abilities.effects.common.combat.CantAttackIfDefenderControlsPermanent; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.SubType; +import mage.constants.Duration; +import mage.constants.Zone; +import mage.filter.FilterPermanent; +import mage.filter.common.FilterLandPermanent; +import mage.filter.predicate.Predicates; +import mage.filter.predicate.permanent.TappedPredicate; +import mage.game.Game; +import mage.game.permanent.Permanent; +import mage.players.Player; + +/** + * @author L_J + */ +public class VeteranBrawlers extends CardImpl { + + static final private FilterLandPermanent filter = new FilterLandPermanent("an untapped land"); + static { + filter.add(Predicates.not(new TappedPredicate())); + } + + final static private String rule = "{this} can't block if you control an untapped land"; + + public VeteranBrawlers(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{1}{R}"); + this.subtype.add(SubType.HUMAN); + this.subtype.add(SubType.SOLDIER); + this.power = new MageInt(4); + this.toughness = new MageInt(4); + + // Veteran Brawlers can't attack if defending player controls an untapped land. + this.addAbility(new SimpleStaticAbility(Zone.BATTLEFIELD, new CantAttackIfDefenderControlsPermanent(filter))); + + // Veteran Brawlers can't block if you control an untapped land. + this.addAbility(new SimpleStaticAbility(Zone.BATTLEFIELD, new VeteranBrawlersCantBlockEffect(filter))); + } + + public VeteranBrawlers(final VeteranBrawlers card) { + super(card); + } + + @Override + public VeteranBrawlers copy() { + return new VeteranBrawlers(this); + } +} + +class VeteranBrawlersCantBlockEffect extends RestrictionEffect { + + private final FilterPermanent filter; + + public VeteranBrawlersCantBlockEffect(FilterPermanent filter) { + super(Duration.WhileOnBattlefield); + this.filter = filter; + staticText = new StringBuilder("{this} can't attack if you control ").append(filter.getMessage()).toString(); + } + + public VeteranBrawlersCantBlockEffect(final VeteranBrawlersCantBlockEffect effect) { + super(effect); + this.filter = effect.filter; + } + + @Override + public boolean applies(Permanent permanent, Ability source, Game game) { + return permanent.getId().equals(source.getSourceId()); + } + + @Override + public boolean canBlock(Permanent attacker, Permanent blocker, Ability source, Game game) { + Player player = game.getPlayer(blocker.getControllerId()); + if (player != null) { + if (game.getBattlefield().countAll(filter, player.getId(), game) > 0) { + return false; + } + } + return true; + } + + @Override + public VeteranBrawlersCantBlockEffect copy() { + return new VeteranBrawlersCantBlockEffect(this); + } + +} diff --git a/Mage.Sets/src/mage/cards/v/VraskaSchemingGorgon.java b/Mage.Sets/src/mage/cards/v/VraskaSchemingGorgon.java new file mode 100644 index 00000000000..fc7abafc50d --- /dev/null +++ b/Mage.Sets/src/mage/cards/v/VraskaSchemingGorgon.java @@ -0,0 +1,90 @@ +/* + * 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.LoyaltyAbility; +import mage.abilities.TriggeredAbility; +import mage.abilities.common.DealsCombatDamageToAPlayerTriggeredAbility; +import mage.abilities.common.PlanswalkerEntersWithLoyalityCountersAbility; +import mage.abilities.effects.Effect; +import mage.abilities.effects.common.DestroyTargetEffect; +import mage.abilities.effects.common.LoseGameTargetPlayerEffect; +import mage.abilities.effects.common.continuous.BoostControlledEffect; +import mage.abilities.effects.common.continuous.GainAbilityControlledEffect; +import mage.abilities.keyword.DeathtouchAbility; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.Duration; +import mage.constants.SubType; +import mage.constants.SuperType; +import mage.filter.StaticFilters; +import mage.target.common.TargetCreaturePermanent; + +/** + * + * @author LevelX2 + */ +public class VraskaSchemingGorgon extends CardImpl { + + public VraskaSchemingGorgon(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.PLANESWALKER}, "{4}{B}{B}"); + + this.addSuperType(SuperType.LEGENDARY); + this.subtype.add(SubType.VRASKA); + this.addAbility(new PlanswalkerEntersWithLoyalityCountersAbility(5)); + + // +2: Creatures you control get +1/+0 until end of turn. + Effect effect = new BoostControlledEffect(1, 0, Duration.EndOfTurn, StaticFilters.FILTER_PERMANENT_CREATURE); + effect.setText("Creatures you control get +1/+0"); + this.addAbility(new LoyaltyAbility(effect, 2)); + + // -3: Destroy target creature. + LoyaltyAbility loyaltyAbility = new LoyaltyAbility(new DestroyTargetEffect(), -3); + loyaltyAbility.addTarget(new TargetCreaturePermanent()); + this.addAbility(loyaltyAbility); + + // -10: Until end of turn, creatures you control gain deathtouch and "Whenever this creature deals damage to an opponent, that player loses the game." + loyaltyAbility = new LoyaltyAbility(new GainAbilityControlledEffect(DeathtouchAbility.getInstance(), Duration.EndOfTurn) + .setText("Until end of turn, creatures you control gain deathtouch"), -10); + TriggeredAbility triggeredAbility = new DealsCombatDamageToAPlayerTriggeredAbility(new LoseGameTargetPlayerEffect(), false, true, true); + loyaltyAbility.addEffect(new GainAbilityControlledEffect(triggeredAbility, Duration.EndOfTurn) + .setText("and \"Whenever this creature deals damage to an opponent, that player loses the game.\"")); + this.addAbility(loyaltyAbility); + } + + public VraskaSchemingGorgon(final VraskaSchemingGorgon card) { + super(card); + } + + @Override + public VraskaSchemingGorgon copy() { + return new VraskaSchemingGorgon(this); + } +} diff --git a/Mage.Sets/src/mage/cards/v/VraskasConquistador.java b/Mage.Sets/src/mage/cards/v/VraskasConquistador.java new file mode 100644 index 00000000000..95c9dbc2c12 --- /dev/null +++ b/Mage.Sets/src/mage/cards/v/VraskasConquistador.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.v; + +import java.util.UUID; +import mage.MageInt; +import mage.abilities.TriggeredAbility; +import mage.abilities.common.AttacksOrBlocksTriggeredAbility; +import mage.abilities.condition.common.PermanentsOnTheBattlefieldCondition; +import mage.abilities.decorator.ConditionalTriggeredAbility; +import mage.abilities.effects.common.GainLifeEffect; +import mage.abilities.effects.common.LoseLifeTargetEffect; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.SubType; +import mage.filter.common.FilterControlledPermanent; +import mage.filter.predicate.mageobject.CardTypePredicate; +import mage.filter.predicate.mageobject.SubtypePredicate; +import mage.target.common.TargetOpponent; + +/** + * + * @author LevelX2 + */ +public class VraskasConquistador extends CardImpl { + + private static final FilterControlledPermanent filter = new FilterControlledPermanent(); + + static { + filter.add(new CardTypePredicate(CardType.PLANESWALKER)); + filter.add(new SubtypePredicate(SubType.VRASKA)); + } + + public VraskasConquistador(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{1}{B}"); + + this.subtype.add(SubType.VAMPIRE); + this.subtype.add(SubType.SOLDIER); + this.power = new MageInt(2); + this.toughness = new MageInt(1); + + // Whenever Vraska's Conquistador attacks or blocks, if you control a Vraska planeswalker, target opponent loses 2 life and you gain 2 life. + TriggeredAbility ability = new AttacksOrBlocksTriggeredAbility(new LoseLifeTargetEffect(2), false); + ability.addEffect(new GainLifeEffect(2).setText("and you gain 2 life")); + ability.addTarget(new TargetOpponent()); + this.addAbility(new ConditionalTriggeredAbility( + ability, new PermanentsOnTheBattlefieldCondition(filter), + "Whenever {this} attacks or blocks, if you control a Vraska planeswalker, target opponent loses 2 life and you gain 2 life.")); + } + + public VraskasConquistador(final VraskasConquistador card) { + super(card); + } + + @Override + public VraskasConquistador copy() { + return new VraskasConquistador(this); + } +} diff --git a/Mage.Sets/src/mage/cards/v/VraskasScorn.java b/Mage.Sets/src/mage/cards/v/VraskasScorn.java new file mode 100644 index 00000000000..b99ce79d7fe --- /dev/null +++ b/Mage.Sets/src/mage/cards/v/VraskasScorn.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.v; + +import java.util.UUID; +import mage.abilities.effects.common.LoseLifeTargetEffect; +import mage.abilities.effects.common.search.SearchLibraryGraveyardPutInHandEffect; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.filter.FilterCard; +import mage.filter.predicate.mageobject.NamePredicate; +import mage.target.common.TargetOpponent; + +/** + * + * @author LevelX2 + */ +public class VraskasScorn extends CardImpl { + + private final static FilterCard filter = new FilterCard("Vraska, Scheming Gorgon"); + + static { + filter.add(new NamePredicate(filter.getMessage())); + } + + public VraskasScorn(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.SORCERY}, "{2}{B}{B}"); + + // Target opponent loses 4 life. + this.getSpellAbility().addEffect(new LoseLifeTargetEffect(4)); + this.getSpellAbility().addTarget(new TargetOpponent()); + + // You may search your library and/or graveyard for a card named Vraska, Scheming Gorgon, reveal it, and put it into your hand. If you search your library this way, shuffle it. + this.getSpellAbility().addEffect(new SearchLibraryGraveyardPutInHandEffect(filter) + .setText("You may search your library and/or graveyard for a card named Vraska, Scheming Gorgon, reveal it, and put it into your hand. If you search your library this way, shuffle it")); + } + + public VraskasScorn(final VraskasScorn card) { + super(card); + } + + @Override + public VraskasScorn copy() { + return new VraskasScorn(this); + } +} diff --git a/Mage.Sets/src/mage/cards/w/WalkingSponge.java b/Mage.Sets/src/mage/cards/w/WalkingSponge.java new file mode 100644 index 00000000000..0bc3b9fbbad --- /dev/null +++ b/Mage.Sets/src/mage/cards/w/WalkingSponge.java @@ -0,0 +1,134 @@ +/* + * 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.LinkedHashSet; +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.ContinuousEffect; +import mage.abilities.effects.OneShotEffect; +import mage.abilities.effects.common.continuous.LoseAbilityTargetEffect; +import mage.abilities.keyword.FirstStrikeAbility; +import mage.abilities.keyword.FlyingAbility; +import mage.abilities.keyword.TrampleAbility; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.choices.ChoiceImpl; +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 WalkingSponge extends CardImpl { + + public WalkingSponge(UUID ownerId, CardSetInfo setInfo) { + super(ownerId,setInfo,new CardType[]{CardType.CREATURE},"{1}{U}"); + this.subtype.add(SubType.SPONGE); + this.power = new MageInt(1); + this.toughness = new MageInt(1); + + // {T}: Target creature loses your choice of flying, first strike, or trample until end of turn. + Ability ability = new SimpleActivatedAbility(Zone.BATTLEFIELD, new WalkingSpongeEffect(), new TapSourceCost()); + ability.addTarget(new TargetCreaturePermanent()); + this.addAbility(ability); + } + + public WalkingSponge(final WalkingSponge card) { + super(card); + } + + @Override + public WalkingSponge copy() { + return new WalkingSponge(this); + } +} + +class WalkingSpongeEffect extends OneShotEffect { + + WalkingSpongeEffect() { + super(Outcome.Benefit); + this.staticText = "Target creature loses your choice of flying, first strike, or trample until end of turn"; + } + + WalkingSpongeEffect(final WalkingSpongeEffect effect) { + super(effect); + } + + @Override + public WalkingSpongeEffect copy() { + return new WalkingSpongeEffect(this); + } + + @Override + public boolean apply(Game game, Ability source) { + Player player = game.getPlayer(source.getControllerId()); + Permanent permanent = game.getPermanent(source.getSourceId()); + if (player != null || permanent != null) { + ChoiceImpl chooseAbility = new ChoiceImpl(); + chooseAbility.setMessage("What ability do you wish to remove? (default is Flying)"); + Set choice = new LinkedHashSet<>(); + choice.add("Flying"); + choice.add("First strike"); + choice.add("Trample"); + chooseAbility.setChoices(choice); + // since the player can't pick "no ability", let's default to the first option + Ability ability = FlyingAbility.getInstance(); + + if (player.choose(Outcome.UnboostCreature, chooseAbility, game)) { + String chosenAbility = chooseAbility.getChoice(); + // if (chosenAbility.equals("Flying")) { + // ability = FlyingAbility.getInstance(); + // } + if (chosenAbility.equals("First strike")) { + ability = FirstStrikeAbility.getInstance(); + } + else if (chosenAbility.equals("Trample")) { + ability = TrampleAbility.getInstance(); + } + } + game.informPlayers(player.getLogName() + " has chosen " + ability.getRule()); + ContinuousEffect effect = new LoseAbilityTargetEffect(ability, Duration.EndOfTurn); + game.addEffect(effect, source); + return true; + } + return false; + } +} diff --git a/Mage.Sets/src/mage/cards/w/WallOfVipers.java b/Mage.Sets/src/mage/cards/w/WallOfVipers.java new file mode 100644 index 00000000000..00dbc28da6c --- /dev/null +++ b/Mage.Sets/src/mage/cards/w/WallOfVipers.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.w; + +import java.util.UUID; +import mage.MageInt; +import mage.abilities.common.SimpleActivatedAbility; +import mage.abilities.costs.mana.ManaCostsImpl; +import mage.abilities.effects.common.DestroySourceEffect; +import mage.abilities.effects.common.DestroyTargetEffect; +import mage.abilities.effects.common.InfoEffect; +import mage.abilities.keyword.DefenderAbility; +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.filter.common.FilterCreaturePermanent; +import mage.game.Game; +import mage.game.combat.CombatGroup; +import mage.game.permanent.Permanent; +import mage.target.common.TargetCreaturePermanent; + +/** + * + * @author L_J + */ +public class WallOfVipers extends CardImpl { + + public WallOfVipers(UUID ownerId, CardSetInfo setInfo) { + super(ownerId,setInfo,new CardType[]{CardType.CREATURE},"{2}{B}"); + this.subtype.add(SubType.SNAKE); + this.subtype.add(SubType.WALL); + this.power = new MageInt(2); + this.toughness = new MageInt(4); + + // Defender + this.addAbility(DefenderAbility.getInstance()); + + // {3}: Destroy Wall of Vipers and target creature it's blocking. Any player may activate this ability. + SimpleActivatedAbility ability = new SimpleActivatedAbility(Zone.BATTLEFIELD, new DestroySourceEffect(), new ManaCostsImpl("{3}")); + ability.addEffect(new DestroyTargetEffect(" and target creature it's blocking")); + ability.addTarget(new TargetCreaturePermanent(new WallOfVipersFilter())); + ability.setMayActivate(TargetController.ANY); + ability.addEffect(new InfoEffect("Any player may activate this ability")); + this.addAbility(ability); + } + + public WallOfVipers(final WallOfVipers card) { + super(card); + } + + @Override + public WallOfVipers copy() { + return new WallOfVipers(this); + } +} + +class WallOfVipersFilter extends FilterCreaturePermanent { + + public WallOfVipersFilter() { + super("creature {this} is blocking"); + } + + public WallOfVipersFilter(final WallOfVipersFilter filter) { + super(filter); + } + + @Override + public WallOfVipersFilter copy() { + return new WallOfVipersFilter(this); + } + + @Override + public boolean match(Permanent permanent, UUID sourceId, UUID playerId, Game game) { + if (super.match(permanent, sourceId, playerId, game)) { + SubType subtype = (SubType) game.getState().getValue(sourceId + "_type"); + for (CombatGroup combatGroup : game.getCombat().getGroups()) { + if (combatGroup.getBlockers().contains(sourceId) && combatGroup.getAttackers().contains(permanent.getId())) { + return true; + } + } + } + return false; + } + +} diff --git a/Mage.Sets/src/mage/cards/w/WildMammoth.java b/Mage.Sets/src/mage/cards/w/WildMammoth.java new file mode 100644 index 00000000000..3deee0822d3 --- /dev/null +++ b/Mage.Sets/src/mage/cards/w/WildMammoth.java @@ -0,0 +1,140 @@ +/* + * 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.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.FilterPermanent; +import mage.filter.predicate.mageobject.CardTypePredicate; +import mage.game.Game; +import mage.game.permanent.Permanent; +import mage.players.Player; +import mage.target.targetpointer.FixedTarget; + +/** + * + * @author L_J + */ +public class WildMammoth extends CardImpl { + + public WildMammoth(UUID ownerId, CardSetInfo setInfo) { + super(ownerId,setInfo,new CardType[]{CardType.CREATURE},"{2}{G}"); + this.subtype.add(SubType.ELEPHANT); + this.power = new MageInt(3); + this.toughness = new MageInt(4); + + // At the beginning of your upkeep, if a player controls more creatures than each other player, the player who controls the most creatures gains control of Wild Mammoth. + this.addAbility(new BeginningOfUpkeepTriggeredAbility(new WildMammothEffect(), TargetController.YOU, false)); + } + + public WildMammoth(final WildMammoth card) { + super(card); + } + + @Override + public WildMammoth copy() { + return new WildMammoth(this); + } +} + +class WildMammothEffect extends OneShotEffect { + + public WildMammothEffect() { + super(Outcome.GainControl); + this.staticText = "if a player controls more creatures than each other player, the player who controls the most creatures gains control of {this}"; + } + + public WildMammothEffect(final WildMammothEffect effect) { + super(effect); + } + + @Override + public WildMammothEffect copy() { + return new WildMammothEffect(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) { + Player newController = null; + int maxCreatures = 0; + boolean tie = false; + FilterPermanent filter = new FilterPermanent(); + filter.add(new CardTypePredicate(CardType.CREATURE)); + + for (UUID playerId : game.getState().getPlayersInRange(source.getControllerId(), game)) { + Player player = game.getPlayer(playerId); + if (player != null) { + int value = game.getBattlefield().countAll(filter, playerId, game); + if (value > maxCreatures) { + maxCreatures = value; + } + } + } + for (UUID playerId : game.getState().getPlayersInRange(source.getControllerId(), game)) { + Player player = game.getPlayer(playerId); + if (player != null) { + int value = game.getBattlefield().countAll(filter, playerId, game); + if (value == maxCreatures) { + if (newController == null) { + newController = player; + } else { + tie = true; + break; + } + } + } + } + + if (!controller.equals(newController) && !tie && newController != null) { + ContinuousEffect effect = new GainControlTargetEffect(Duration.Custom, newController.getId()); + effect.setTargetPointer(new FixedTarget(sourcePermanent, game)); + game.addEffect(effect, source); + } + } + return true; + } + return false; + + } +} diff --git a/Mage.Sets/src/mage/cards/w/WingStorm.java b/Mage.Sets/src/mage/cards/w/WingStorm.java new file mode 100644 index 00000000000..425fc90473a --- /dev/null +++ b/Mage.Sets/src/mage/cards/w/WingStorm.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.cards.w; + +import java.util.UUID; +import mage.abilities.Ability; +import mage.abilities.effects.OneShotEffect; +import mage.abilities.keyword.FlyingAbility; +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.mageobject.AbilityPredicate; +import mage.game.Game; +import mage.players.Player; + +/** + * + * @author LevelX2 & L_J + */ +public class WingStorm extends CardImpl { + + public WingStorm(UUID ownerId, CardSetInfo setInfo) { + super(ownerId,setInfo,new CardType[]{CardType.SORCERY},"{2}{G}"); + + // Wing Storm deals damage to each player equal to twice the number of creatures with flying that player controls. + this.getSpellAbility().addEffect(new WingStormEffect()); + } + + public WingStorm(final WingStorm card) { + super(card); + } + + @Override + public WingStorm copy() { + return new WingStorm(this); + } +} + +class WingStormEffect extends OneShotEffect { + + private static final FilterCreaturePermanent filter = new FilterCreaturePermanent(); + + static { + filter.add(new AbilityPredicate(FlyingAbility.class)); + } + + public WingStormEffect() { + super(Outcome.Benefit); + this.staticText = "{this} deals damage to each player equal to twice the number of creatures with flying that player controls"; + } + + public WingStormEffect(final WingStormEffect effect) { + super(effect); + } + + @Override + public WingStormEffect copy() { + return new WingStormEffect(this); + } + + @Override + public boolean apply(Game game, Ability source) { + Player controller = game.getPlayer(source.getControllerId()); + if (controller != null) { + for (UUID playerId : game.getState().getPlayersInRange(controller.getId(), game)) { + int amount = game.getBattlefield().countAll(filter, playerId, game); + if (amount > 0) { + Player player = game.getPlayer(playerId); + if (player != null) { + player.damage(amount * 2, source.getSourceId(), game, false, true); + } + } + } + return true; + } + return false; + } +} diff --git a/Mage.Sets/src/mage/sets/Alliances.java b/Mage.Sets/src/mage/sets/Alliances.java index e97dda21691..a2f06f874ed 100644 --- a/Mage.Sets/src/mage/sets/Alliances.java +++ b/Mage.Sets/src/mage/sets/Alliances.java @@ -46,6 +46,7 @@ public class Alliances extends ExpansionSet { cards.add(new SetCardInfo("Agent of Stromgald", 95, Rarity.COMMON, AgentOfStromgald.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Arcane Denial", 32, Rarity.COMMON, mage.cards.a.ArcaneDenial.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Arcane Denial", 33, Rarity.COMMON, mage.cards.a.ArcaneDenial.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Ashnod's Cylix", 158, Rarity.RARE, mage.cards.a.AshnodsCylix.class)); cards.add(new SetCardInfo("Astrolabe", 159, Rarity.COMMON, mage.cards.a.Astrolabe.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Astrolabe", 160, Rarity.COMMON, mage.cards.a.Astrolabe.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Balduvian Dead", 1, Rarity.UNCOMMON, mage.cards.b.BalduvianDead.class)); @@ -153,6 +154,8 @@ public class Alliances extends ExpansionSet { cards.add(new SetCardInfo("Soldevi Heretic", 50, Rarity.COMMON, mage.cards.s.SoldeviHeretic.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Soldevi Sage", 51, Rarity.COMMON, SoldeviSage.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Soldevi Sage", 52, Rarity.COMMON, SoldeviSage.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Soldevi Steam Beast", 177, Rarity.COMMON, mage.cards.s.SoldeviSteamBeast.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Soldevi Steam Beast", 178, Rarity.COMMON, mage.cards.s.SoldeviSteamBeast.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Soldier of Fortune", 117, Rarity.UNCOMMON, mage.cards.s.SoldierOfFortune.class)); cards.add(new SetCardInfo("Sol Grail", 173, Rarity.UNCOMMON, mage.cards.s.SolGrail.class)); cards.add(new SetCardInfo("Stench of Decay", 27, Rarity.COMMON, mage.cards.s.StenchOfDecay.class, NON_FULL_USE_VARIOUS)); @@ -162,6 +165,7 @@ public class Alliances extends ExpansionSet { cards.add(new SetCardInfo("Storm Crow", 55, Rarity.COMMON, mage.cards.s.StormCrow.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Storm Shaman", 118, Rarity.COMMON, StormShaman.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Storm Shaman", 119, Rarity.UNCOMMON, StormShaman.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Stromgald Spy", 29, Rarity.UNCOMMON, mage.cards.s.StromgaldSpy.class)); cards.add(new SetCardInfo("Surge of Strength", 197, Rarity.UNCOMMON, mage.cards.s.SurgeOfStrength.class)); cards.add(new SetCardInfo("Sustaining Spirit", 151, Rarity.RARE, mage.cards.s.SustainingSpirit.class)); cards.add(new SetCardInfo("Swamp Mosquito", 30, Rarity.COMMON, SwampMosquito.class, NON_FULL_USE_VARIOUS)); diff --git a/Mage.Sets/src/mage/sets/FourthEdition.java b/Mage.Sets/src/mage/sets/FourthEdition.java index 77e093fdcdc..d4dfa9e5d7b 100644 --- a/Mage.Sets/src/mage/sets/FourthEdition.java +++ b/Mage.Sets/src/mage/sets/FourthEdition.java @@ -335,6 +335,7 @@ public class FourthEdition extends ExpansionSet { cards.add(new SetCardInfo("Righteousness", 46, Rarity.RARE, mage.cards.r.Righteousness.class)); cards.add(new SetCardInfo("Samite Healer", 47, Rarity.COMMON, mage.cards.s.SamiteHealer.class)); cards.add(new SetCardInfo("Savannah Lions", 48, Rarity.RARE, mage.cards.s.SavannahLions.class)); + cards.add(new SetCardInfo("Seeker", 49, Rarity.COMMON, mage.cards.s.Seeker.class)); cards.add(new SetCardInfo("Serra Angel", 50, Rarity.UNCOMMON, mage.cards.s.SerraAngel.class)); cards.add(new SetCardInfo("Spirit Link", 51, Rarity.UNCOMMON, mage.cards.s.SpiritLink.class)); cards.add(new SetCardInfo("Swords to Plowshares", 52, Rarity.UNCOMMON, mage.cards.s.SwordsToPlowshares.class)); diff --git a/Mage.Sets/src/mage/sets/Legends.java b/Mage.Sets/src/mage/sets/Legends.java index cba8669115e..e2c6548a2ec 100644 --- a/Mage.Sets/src/mage/sets/Legends.java +++ b/Mage.Sets/src/mage/sets/Legends.java @@ -130,6 +130,7 @@ public class Legends extends ExpansionSet { 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("Glyph of Destruction", 148, Rarity.COMMON, mage.cards.g.GlyphOfDestruction.class)); + cards.add(new SetCardInfo("Glyph of Life", 184, Rarity.COMMON, mage.cards.g.GlyphOfLife.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)); @@ -233,6 +234,7 @@ public class Legends extends ExpansionSet { 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)); + cards.add(new SetCardInfo("Seeker", 204, Rarity.UNCOMMON, mage.cards.s.Seeker.class)); cards.add(new SetCardInfo("Segovian Leviathan", 76, Rarity.UNCOMMON, mage.cards.s.SegovianLeviathan.class)); cards.add(new SetCardInfo("Sentinel", 239, Rarity.RARE, mage.cards.s.Sentinel.class)); cards.add(new SetCardInfo("Serpent Generator", 240, Rarity.RARE, mage.cards.s.SerpentGenerator.class)); diff --git a/Mage.Sets/src/mage/sets/MastersEditionII.java b/Mage.Sets/src/mage/sets/MastersEditionII.java index cafbc870abb..ec1bba35f8f 100644 --- a/Mage.Sets/src/mage/sets/MastersEditionII.java +++ b/Mage.Sets/src/mage/sets/MastersEditionII.java @@ -77,6 +77,7 @@ public class MastersEditionII extends ExpansionSet { cards.add(new SetCardInfo("Armor of Faith", 4, Rarity.COMMON, mage.cards.a.ArmorOfFaith.class)); cards.add(new SetCardInfo("Armor Thrull", 77, Rarity.COMMON, ArmorThrull.class)); cards.add(new SetCardInfo("Ashen Ghoul", 78, Rarity.UNCOMMON, mage.cards.a.AshenGhoul.class)); + cards.add(new SetCardInfo("Ashnod's Cylix", 203, Rarity.RARE, mage.cards.a.AshnodsCylix.class)); cards.add(new SetCardInfo("Aurochs", 153, Rarity.COMMON, mage.cards.a.Aurochs.class)); cards.add(new SetCardInfo("Aysen Bureaucrats", 6, Rarity.COMMON, mage.cards.a.AysenBureaucrats.class)); cards.add(new SetCardInfo("Aysen Crusader", 7, Rarity.UNCOMMON, mage.cards.a.AysenCrusader.class)); diff --git a/Mage.Sets/src/mage/sets/MercadianMasques.java b/Mage.Sets/src/mage/sets/MercadianMasques.java index 92bb4bc0ab8..df71e3b1794 100644 --- a/Mage.Sets/src/mage/sets/MercadianMasques.java +++ b/Mage.Sets/src/mage/sets/MercadianMasques.java @@ -311,6 +311,7 @@ public class MercadianMasques extends ExpansionSet { cards.add(new SetCardInfo("Soul Channeling", 163, Rarity.COMMON, mage.cards.s.SoulChanneling.class)); cards.add(new SetCardInfo("Specter's Wail", 164, Rarity.COMMON, mage.cards.s.SpectersWail.class)); cards.add(new SetCardInfo("Spidersilk Armor", 273, Rarity.COMMON, mage.cards.s.SpidersilkArmor.class)); + cards.add(new SetCardInfo("Spiritual Focus", 49, Rarity.RARE, mage.cards.s.SpiritualFocus.class)); cards.add(new SetCardInfo("Spontaneous Generation", 274, Rarity.RARE, mage.cards.s.SpontaneousGeneration.class)); cards.add(new SetCardInfo("Squall", 275, Rarity.COMMON, mage.cards.s.Squall.class)); cards.add(new SetCardInfo("Squallmonger", 276, Rarity.UNCOMMON, mage.cards.s.Squallmonger.class)); diff --git a/Mage.Sets/src/mage/sets/Nemesis.java b/Mage.Sets/src/mage/sets/Nemesis.java index f05a4909d36..a1fb5595e93 100644 --- a/Mage.Sets/src/mage/sets/Nemesis.java +++ b/Mage.Sets/src/mage/sets/Nemesis.java @@ -88,6 +88,7 @@ public class Nemesis extends ExpansionSet { 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("Flint Golem", 130, Rarity.UNCOMMON, mage.cards.f.FlintGolem.class)); cards.add(new SetCardInfo("Flowstone Armor", 131, Rarity.UNCOMMON, mage.cards.f.FlowstoneArmor.class)); cards.add(new SetCardInfo("Flowstone Crusher", 81, Rarity.COMMON, mage.cards.f.FlowstoneCrusher.class)); cards.add(new SetCardInfo("Flowstone Overseer", 82, Rarity.RARE, mage.cards.f.FlowstoneOverseer.class)); @@ -96,6 +97,8 @@ public class Nemesis extends ExpansionSet { cards.add(new SetCardInfo("Flowstone Surge", 85, Rarity.UNCOMMON, mage.cards.f.FlowstoneSurge.class)); cards.add(new SetCardInfo("Flowstone Thopter", 132, Rarity.UNCOMMON, mage.cards.f.FlowstoneThopter.class)); cards.add(new SetCardInfo("Flowstone Wall", 86, Rarity.COMMON, mage.cards.f.FlowstoneWall.class)); + cards.add(new SetCardInfo("Fog Patch", 104, Rarity.COMMON, mage.cards.f.FogPatch.class)); + cards.add(new SetCardInfo("Harvest Mage", 105, Rarity.COMMON, mage.cards.h.HarvestMage.class)); cards.add(new SetCardInfo("Infiltrate", 33, Rarity.COMMON, mage.cards.i.Infiltrate.class)); 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)); @@ -109,12 +112,15 @@ public class Nemesis extends ExpansionSet { 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)); cards.add(new SetCardInfo("Lin Sivvi, Defiant Hero", 12, Rarity.RARE, mage.cards.l.LinSivviDefiantHero.class)); + cards.add(new SetCardInfo("Mana Cache", 92, Rarity.RARE, mage.cards.m.ManaCache.class)); cards.add(new SetCardInfo("Massacre", 58, Rarity.UNCOMMON, mage.cards.m.Massacre.class)); cards.add(new SetCardInfo("Mind Slash", 59, Rarity.UNCOMMON, mage.cards.m.MindSlash.class)); cards.add(new SetCardInfo("Mind Swords", 60, Rarity.COMMON, mage.cards.m.MindSwords.class)); cards.add(new SetCardInfo("Mogg Alarm", 93, Rarity.UNCOMMON, mage.cards.m.MoggAlarm.class)); - cards.add(new SetCardInfo("Moggcatcher", 96, Rarity.RARE, mage.cards.m.Moggcatcher.class)); cards.add(new SetCardInfo("Mogg Salvage", 94, Rarity.UNCOMMON, mage.cards.m.MoggSalvage.class)); + cards.add(new SetCardInfo("Mogg Toady", 95, Rarity.COMMON, mage.cards.m.MoggToady.class)); + cards.add(new SetCardInfo("Moggcatcher", 96, Rarity.RARE, mage.cards.m.Moggcatcher.class)); + cards.add(new SetCardInfo("Mossdog", 106, Rarity.COMMON, mage.cards.m.Mossdog.class)); cards.add(new SetCardInfo("Murderous Betrayal", 61, Rarity.RARE, mage.cards.m.MurderousBetrayal.class)); cards.add(new SetCardInfo("Nesting Wurm", 107, Rarity.UNCOMMON, mage.cards.n.NestingWurm.class)); cards.add(new SetCardInfo("Netter en-Dal", 13, Rarity.COMMON, mage.cards.n.NetterEnDal.class)); @@ -146,6 +152,7 @@ public class Nemesis extends ExpansionSet { cards.add(new SetCardInfo("Rising Waters", 38, Rarity.RARE, mage.cards.r.RisingWaters.class)); cards.add(new SetCardInfo("Rootwater Commando", 39, Rarity.COMMON, mage.cards.r.RootwaterCommando.class)); cards.add(new SetCardInfo("Rootwater Thief", 40, Rarity.RARE, mage.cards.r.RootwaterThief.class)); + cards.add(new SetCardInfo("Rupture", 97, Rarity.UNCOMMON, mage.cards.r.Rupture.class)); cards.add(new SetCardInfo("Rusting Golem", 138, Rarity.UNCOMMON, mage.cards.r.RustingGolem.class)); cards.add(new SetCardInfo("Saproling Burst", 113, Rarity.RARE, mage.cards.s.SaprolingBurst.class)); cards.add(new SetCardInfo("Saproling Cluster", 114, Rarity.RARE, mage.cards.s.SaprolingCluster.class)); @@ -159,6 +166,7 @@ public class Nemesis extends ExpansionSet { cards.add(new SetCardInfo("Silkenfist Fighter", 19, Rarity.COMMON, mage.cards.s.SilkenfistFighter.class)); cards.add(new SetCardInfo("Silkenfist Order", 20, Rarity.UNCOMMON, mage.cards.s.SilkenfistOrder.class)); cards.add(new SetCardInfo("Sivvi's Ruse", 21, Rarity.UNCOMMON, mage.cards.s.SivvisRuse.class)); + cards.add(new SetCardInfo("Sivvi's Valor", 22, Rarity.RARE, mage.cards.s.SivvisValor.class)); cards.add(new SetCardInfo("Skyshroud Behemoth", 116, Rarity.RARE, mage.cards.s.SkyshroudBehemoth.class)); cards.add(new SetCardInfo("Skyshroud Claim", 117, Rarity.COMMON, mage.cards.s.SkyshroudClaim.class)); cards.add(new SetCardInfo("Skyshroud Cutter", 118, Rarity.COMMON, mage.cards.s.SkyshroudCutter.class)); @@ -179,6 +187,7 @@ public class Nemesis extends ExpansionSet { cards.add(new SetCardInfo("Submerge", 48, Rarity.UNCOMMON, mage.cards.s.Submerge.class)); cards.add(new SetCardInfo("Tangle Wire", 139, Rarity.RARE, mage.cards.t.TangleWire.class)); cards.add(new SetCardInfo("Terrain Generator", 143, Rarity.UNCOMMON, mage.cards.t.TerrainGenerator.class)); + cards.add(new SetCardInfo("Topple", 24, Rarity.COMMON, mage.cards.t.Topple.class)); cards.add(new SetCardInfo("Treetop Bracers", 123, Rarity.COMMON, mage.cards.t.TreetopBracers.class)); cards.add(new SetCardInfo("Trickster Mage", 49, Rarity.COMMON, mage.cards.t.TricksterMage.class)); cards.add(new SetCardInfo("Vicious Hunger", 74, Rarity.COMMON, mage.cards.v.ViciousHunger.class)); @@ -186,6 +195,7 @@ public class Nemesis extends ExpansionSet { cards.add(new SetCardInfo("Voice of Truth", 25, Rarity.UNCOMMON, mage.cards.v.VoiceOfTruth.class)); cards.add(new SetCardInfo("Volrath the Fallen", 75, Rarity.RARE, mage.cards.v.VolrathTheFallen.class)); cards.add(new SetCardInfo("Wandering Eye", 50, Rarity.COMMON, mage.cards.w.WanderingEye.class)); + cards.add(new SetCardInfo("Wild Mammoth", 124, Rarity.UNCOMMON, mage.cards.w.WildMammoth.class)); cards.add(new SetCardInfo("Woodripper", 125, Rarity.UNCOMMON, mage.cards.w.Woodripper.class)); } } diff --git a/Mage.Sets/src/mage/sets/Odyssey.java b/Mage.Sets/src/mage/sets/Odyssey.java index 7900768d2b5..5644b9dbd01 100644 --- a/Mage.Sets/src/mage/sets/Odyssey.java +++ b/Mage.Sets/src/mage/sets/Odyssey.java @@ -206,6 +206,7 @@ public class Odyssey extends ExpansionSet { cards.add(new SetCardInfo("Krosan Avenger", 247, Rarity.COMMON, mage.cards.k.KrosanAvenger.class)); cards.add(new SetCardInfo("Krosan Beast", 248, Rarity.RARE, mage.cards.k.KrosanBeast.class)); cards.add(new SetCardInfo("Laquatus's Creativity", 88, Rarity.UNCOMMON, mage.cards.l.LaquatussCreativity.class)); + cards.add(new SetCardInfo("Last Rites", 146, Rarity.COMMON, mage.cards.l.LastRites.class)); cards.add(new SetCardInfo("Lava Blister", 200, Rarity.UNCOMMON, mage.cards.l.LavaBlister.class)); cards.add(new SetCardInfo("Leaf Dancer", 249, Rarity.COMMON, mage.cards.l.LeafDancer.class)); cards.add(new SetCardInfo("Lieutenant Kirtar", 29, Rarity.RARE, mage.cards.l.LieutenantKirtar.class)); diff --git a/Mage.Sets/src/mage/sets/Onslaught.java b/Mage.Sets/src/mage/sets/Onslaught.java index 8e76f69828b..daf0abe761b 100644 --- a/Mage.Sets/src/mage/sets/Onslaught.java +++ b/Mage.Sets/src/mage/sets/Onslaught.java @@ -62,9 +62,11 @@ public class Onslaught extends ExpansionSet { cards.add(new SetCardInfo("Break Open", 190, Rarity.COMMON, mage.cards.b.BreakOpen.class)); cards.add(new SetCardInfo("Brightstone Ritual", 191, Rarity.COMMON, mage.cards.b.BrightstoneRitual.class)); cards.add(new SetCardInfo("Broodhatch Nantuko", 250, Rarity.UNCOMMON, mage.cards.b.BroodhatchNantuko.class)); + cards.add(new SetCardInfo("Butcher Orgg", 192, Rarity.RARE, mage.cards.b.ButcherOrgg.class)); cards.add(new SetCardInfo("Cabal Archon", 129, Rarity.UNCOMMON, mage.cards.c.CabalArchon.class)); cards.add(new SetCardInfo("Cabal Executioner", 130, Rarity.UNCOMMON, mage.cards.c.CabalExecutioner.class)); cards.add(new SetCardInfo("Cabal Slaver", 131, Rarity.UNCOMMON, mage.cards.c.CabalSlaver.class)); + cards.add(new SetCardInfo("Callous Oppressor", 72, Rarity.RARE, mage.cards.c.CallousOppressor.class)); cards.add(new SetCardInfo("Catapult Master", 10, Rarity.RARE, mage.cards.c.CatapultMaster.class)); cards.add(new SetCardInfo("Catapult Squad", 11, Rarity.UNCOMMON, mage.cards.c.CatapultSquad.class)); cards.add(new SetCardInfo("Centaur Glade", 251, Rarity.UNCOMMON, mage.cards.c.CentaurGlade.class)); @@ -102,6 +104,7 @@ public class Onslaught extends ExpansionSet { cards.add(new SetCardInfo("Dispersing Orb", 80, Rarity.UNCOMMON, mage.cards.d.DispersingOrb.class)); cards.add(new SetCardInfo("Disruptive Pitmage", 81, Rarity.COMMON, mage.cards.d.DisruptivePitmage.class)); cards.add(new SetCardInfo("Dive Bomber", 26, Rarity.COMMON, mage.cards.d.DiveBomber.class)); + cards.add(new SetCardInfo("Doom Cannon", 307, Rarity.RARE, mage.cards.d.DoomCannon.class)); cards.add(new SetCardInfo("Doomed Necromancer", 140, Rarity.RARE, mage.cards.d.DoomedNecromancer.class)); cards.add(new SetCardInfo("Doubtless One", 27, Rarity.UNCOMMON, mage.cards.d.DoubtlessOne.class)); cards.add(new SetCardInfo("Dragon Roost", 198, Rarity.RARE, mage.cards.d.DragonRoost.class)); @@ -117,6 +120,7 @@ public class Onslaught extends ExpansionSet { cards.add(new SetCardInfo("Elvish Warrior", 260, Rarity.COMMON, mage.cards.e.ElvishWarrior.class)); cards.add(new SetCardInfo("Embermage Goblin", 200, Rarity.UNCOMMON, mage.cards.e.EmbermageGoblin.class)); cards.add(new SetCardInfo("Enchantress's Presence", 261, Rarity.RARE, mage.cards.e.EnchantresssPresence.class)); + cards.add(new SetCardInfo("Entrails Feaster", 143, Rarity.RARE, mage.cards.e.EntrailsFeaster.class)); cards.add(new SetCardInfo("Erratic Explosion", 201, Rarity.COMMON, mage.cards.e.ErraticExplosion.class)); cards.add(new SetCardInfo("Essence Fracture", 82, Rarity.UNCOMMON, mage.cards.e.EssenceFracture.class)); cards.add(new SetCardInfo("Everglove Courier", 262, Rarity.UNCOMMON, mage.cards.e.EvergloveCourier.class)); @@ -186,6 +190,7 @@ public class Onslaught extends ExpansionSet { cards.add(new SetCardInfo("Ixidor, Reality Sculptor", 89, Rarity.RARE, mage.cards.i.IxidorRealitySculptor.class)); cards.add(new SetCardInfo("Jareth, Leonine Titan", 43, Rarity.RARE, mage.cards.j.JarethLeonineTitan.class)); cards.add(new SetCardInfo("Kamahl, Fist of Krosa", 268, Rarity.RARE, mage.cards.k.KamahlFistOfKrosa.class)); + cards.add(new SetCardInfo("Kamahl's Summons", 269, Rarity.UNCOMMON, mage.cards.k.KamahlsSummons.class)); cards.add(new SetCardInfo("Krosan Colossus", 270, Rarity.RARE, mage.cards.k.KrosanColossus.class)); cards.add(new SetCardInfo("Krosan Groundshaker", 271, Rarity.UNCOMMON, mage.cards.k.KrosanGroundshaker.class)); cards.add(new SetCardInfo("Krosan Tusker", 272, Rarity.COMMON, mage.cards.k.KrosanTusker.class)); @@ -266,6 +271,7 @@ public class Onslaught extends ExpansionSet { 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("Shieldmage Elder", 54, Rarity.UNCOMMON, mage.cards.s.ShieldmageElder.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("Silent Specter", 169, Rarity.RARE, mage.cards.s.SilentSpecter.class)); diff --git a/Mage.Sets/src/mage/sets/PDSGraveborn.java b/Mage.Sets/src/mage/sets/PDSGraveborn.java index 91192951d84..77e28025420 100644 --- a/Mage.Sets/src/mage/sets/PDSGraveborn.java +++ b/Mage.Sets/src/mage/sets/PDSGraveborn.java @@ -62,6 +62,7 @@ public class PDSGraveborn extends ExpansionSet { cards.add(new SetCardInfo("Faceless Butcher", 3, Rarity.COMMON, mage.cards.f.FacelessButcher.class)); cards.add(new SetCardInfo("Hidden Horror", 2, Rarity.UNCOMMON, mage.cards.h.HiddenHorror.class)); cards.add(new SetCardInfo("Inkwell Leviathan", 10, Rarity.RARE, mage.cards.i.InkwellLeviathan.class)); + cards.add(new SetCardInfo("Last Rites", 21, Rarity.COMMON, mage.cards.l.LastRites.class)); cards.add(new SetCardInfo("Polluted Mire", 26, Rarity.COMMON, mage.cards.p.PollutedMire.class)); cards.add(new SetCardInfo("Putrid Imp", 1, Rarity.COMMON, mage.cards.p.PutridImp.class)); cards.add(new SetCardInfo("Reanimate", 15, Rarity.UNCOMMON, mage.cards.r.Reanimate.class)); diff --git a/Mage.Sets/src/mage/sets/Prophecy.java b/Mage.Sets/src/mage/sets/Prophecy.java index 9f3172aa2f7..25bd32e66ce 100644 --- a/Mage.Sets/src/mage/sets/Prophecy.java +++ b/Mage.Sets/src/mage/sets/Prophecy.java @@ -68,6 +68,7 @@ public class Prophecy extends ExpansionSet { cards.add(new SetCardInfo("Blessed Wind", 4, Rarity.RARE, mage.cards.b.BlessedWind.class)); cards.add(new SetCardInfo("Bog Elemental", 57, Rarity.RARE, mage.cards.b.BogElemental.class)); cards.add(new SetCardInfo("Bog Glider", 58, Rarity.COMMON, mage.cards.b.BogGlider.class)); + cards.add(new SetCardInfo("Branded Brawlers", 84, Rarity.COMMON, mage.cards.b.BrandedBrawlers.class)); cards.add(new SetCardInfo("Calming Verse", 110, Rarity.COMMON, mage.cards.c.CalmingVerse.class)); cards.add(new SetCardInfo("Celestial Convergence", 5, Rarity.RARE, mage.cards.c.CelestialConvergence.class)); cards.add(new SetCardInfo("Chilling Apparition", 59, Rarity.UNCOMMON, mage.cards.c.ChillingApparition.class)); @@ -77,6 +78,7 @@ public class Prophecy extends ExpansionSet { cards.add(new SetCardInfo("Coffin Puppets", 60, Rarity.RARE, mage.cards.c.CoffinPuppets.class)); cards.add(new SetCardInfo("Copper-Leaf Angel", 137, Rarity.RARE, mage.cards.c.CopperLeafAngel.class)); cards.add(new SetCardInfo("Darba", 111, Rarity.UNCOMMON, mage.cards.d.Darba.class)); + cards.add(new SetCardInfo("Death Charmer", 61, Rarity.COMMON, mage.cards.d.DeathCharmer.class)); cards.add(new SetCardInfo("Denying Wind", 32, Rarity.RARE, mage.cards.d.DenyingWind.class)); cards.add(new SetCardInfo("Despoil", 62, Rarity.COMMON, mage.cards.d.Despoil.class)); cards.add(new SetCardInfo("Devastate", 87, Rarity.COMMON, mage.cards.d.Devastate.class)); @@ -86,24 +88,30 @@ public class Prophecy extends ExpansionSet { 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("Excise", 8, Rarity.COMMON, mage.cards.e.Excise.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("Flay", 65, Rarity.COMMON, mage.cards.f.Flay.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)); cards.add(new SetCardInfo("Forgotten Harvest", 114, Rarity.RARE, mage.cards.f.ForgottenHarvest.class)); + cards.add(new SetCardInfo("Glittering Lion", 10, Rarity.UNCOMMON, mage.cards.g.GlitteringLion.class)); + cards.add(new SetCardInfo("Glittering Lynx", 11, Rarity.COMMON, mage.cards.g.GlitteringLynx.class)); cards.add(new SetCardInfo("Greel's Caress", 67, Rarity.COMMON, mage.cards.g.GreelsCaress.class)); cards.add(new SetCardInfo("Greel, Mind Raker", 66, Rarity.RARE, mage.cards.g.GreelMindRaker.class)); cards.add(new SetCardInfo("Gulf Squid", 35, Rarity.COMMON, mage.cards.g.GulfSquid.class)); cards.add(new SetCardInfo("Hazy Homunculus", 36, Rarity.COMMON, mage.cards.h.HazyHomunculus.class)); cards.add(new SetCardInfo("Heightened Awareness", 37, Rarity.RARE, mage.cards.h.HeightenedAwareness.class)); + cards.add(new SetCardInfo("Hollow Warrior", 138, Rarity.UNCOMMON, mage.cards.h.HollowWarrior.class)); cards.add(new SetCardInfo("Infernal Genesis", 68, Rarity.RARE, mage.cards.i.InfernalGenesis.class)); cards.add(new SetCardInfo("Inflame", 91, Rarity.COMMON, mage.cards.i.Inflame.class)); cards.add(new SetCardInfo("Jeweled Spirit", 12, Rarity.RARE, mage.cards.j.JeweledSpirit.class)); cards.add(new SetCardInfo("Jolrael, Empress of Beasts", 115, Rarity.RARE, mage.cards.j.JolraelEmpressOfBeasts.class)); cards.add(new SetCardInfo("Jolrael's Favor", 116, Rarity.COMMON, mage.cards.j.JolraelsFavor.class)); cards.add(new SetCardInfo("Keldon Arsonist", 92, Rarity.UNCOMMON, mage.cards.k.KeldonArsonist.class)); + cards.add(new SetCardInfo("Keldon Battlewagon", 139, Rarity.RARE, mage.cards.k.KeldonBattlewagon.class)); 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)); @@ -116,6 +124,7 @@ public class Prophecy extends ExpansionSet { cards.add(new SetCardInfo("Marsh Boa", 118, Rarity.COMMON, mage.cards.m.MarshBoa.class)); cards.add(new SetCardInfo("Mercenary Informer", 15, Rarity.RARE, mage.cards.m.MercenaryInformer.class)); cards.add(new SetCardInfo("Mine Bearer", 16, Rarity.COMMON, mage.cards.m.MineBearer.class)); + cards.add(new SetCardInfo("Mirror Strike", 17, Rarity.UNCOMMON, mage.cards.m.MirrorStrike.class)); cards.add(new SetCardInfo("Mungha Wurm", 119, Rarity.RARE, mage.cards.m.MunghaWurm.class)); cards.add(new SetCardInfo("Nakaya Shade", 69, Rarity.UNCOMMON, mage.cards.n.NakayaShade.class)); cards.add(new SetCardInfo("Noxious Field", 70, Rarity.UNCOMMON, mage.cards.n.NoxiousField.class)); @@ -133,7 +142,12 @@ public class Prophecy extends ExpansionSet { 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 Deluge", 43, Rarity.COMMON, mage.cards.r.RhysticDeluge.class)); + cards.add(new SetCardInfo("Rhystic Lightning", 99, Rarity.COMMON, mage.cards.r.RhysticLightning.class)); + cards.add(new SetCardInfo("Rhystic Scrying", 44, Rarity.UNCOMMON, mage.cards.r.RhysticScrying.class)); + cards.add(new SetCardInfo("Rhystic Shield", 20, Rarity.COMMON, mage.cards.r.RhysticShield.class)); cards.add(new SetCardInfo("Rhystic Study", 45, Rarity.COMMON, mage.cards.r.RhysticStudy.class)); + cards.add(new SetCardInfo("Rhystic Syphon", 76, Rarity.UNCOMMON, mage.cards.r.RhysticSyphon.class)); cards.add(new SetCardInfo("Rhystic Tutor", 77, Rarity.RARE, mage.cards.r.RhysticTutor.class)); cards.add(new SetCardInfo("Ribbon Snake", 46, Rarity.COMMON, mage.cards.r.RibbonSnake.class)); cards.add(new SetCardInfo("Rib Cage Spider", 121, Rarity.COMMON, mage.cards.r.RibCageSpider.class)); @@ -143,8 +157,10 @@ public class Prophecy extends ExpansionSet { cards.add(new SetCardInfo("Scoria Cat", 101, Rarity.UNCOMMON, mage.cards.s.ScoriaCat.class)); cards.add(new SetCardInfo("Searing Wind", 103, Rarity.RARE, mage.cards.s.SearingWind.class)); cards.add(new SetCardInfo("Shield Dancer", 23, Rarity.UNCOMMON, mage.cards.s.ShieldDancer.class)); + cards.add(new SetCardInfo("Shrouded Serpent", 47, Rarity.RARE, mage.cards.s.ShroudedSerpent.class)); cards.add(new SetCardInfo("Silt Crawler", 123, Rarity.COMMON, mage.cards.s.SiltCrawler.class)); cards.add(new SetCardInfo("Snag", 124, Rarity.UNCOMMON, mage.cards.s.Snag.class)); + cards.add(new SetCardInfo("Soul Charmer", 24, Rarity.COMMON, mage.cards.s.SoulCharmer.class)); cards.add(new SetCardInfo("Spiketail Drake", 48, Rarity.UNCOMMON, mage.cards.s.SpiketailDrake.class)); cards.add(new SetCardInfo("Spiketail Hatchling", 49, Rarity.COMMON, mage.cards.s.SpiketailHatchling.class)); cards.add(new SetCardInfo("Spitting Spider", 125, Rarity.UNCOMMON, mage.cards.s.SpittingSpider.class)); @@ -156,20 +172,24 @@ public class Prophecy extends ExpansionSet { cards.add(new SetCardInfo("Sunken Field", 51, Rarity.UNCOMMON, mage.cards.s.SunkenField.class)); cards.add(new SetCardInfo("Sword Dancer", 25, Rarity.UNCOMMON, mage.cards.s.SwordDancer.class)); cards.add(new SetCardInfo("Task Mage Assembly", 105, Rarity.RARE, mage.cards.t.TaskMageAssembly.class)); + cards.add(new SetCardInfo("Thresher Beast", 128, Rarity.COMMON, mage.cards.t.ThresherBeast.class)); cards.add(new SetCardInfo("Thrive", 129, Rarity.COMMON, mage.cards.t.Thrive.class)); cards.add(new SetCardInfo("Trenching Steed", 26, Rarity.COMMON, mage.cards.t.TrenchingSteed.class)); cards.add(new SetCardInfo("Troubled Healer", 27, Rarity.COMMON, mage.cards.t.TroubledHealer.class)); cards.add(new SetCardInfo("Troublesome Spirit", 52, Rarity.RARE, mage.cards.t.TroublesomeSpirit.class)); cards.add(new SetCardInfo("Verdant Field", 130, Rarity.UNCOMMON, mage.cards.v.VerdantField.class)); + cards.add(new SetCardInfo("Veteran Brawlers", 106, Rarity.RARE, mage.cards.v.VeteranBrawlers.class)); cards.add(new SetCardInfo("Vintara Elephant", 131, Rarity.COMMON, mage.cards.v.VintaraElephant.class)); cards.add(new SetCardInfo("Vintara Snapper", 132, Rarity.UNCOMMON, mage.cards.v.VintaraSnapper.class)); cards.add(new SetCardInfo("Vitalizing Wind", 133, Rarity.RARE, mage.cards.v.VitalizingWind.class)); + cards.add(new SetCardInfo("Wall of Vipers", 80, Rarity.UNCOMMON, mage.cards.w.WallOfVipers.class)); cards.add(new SetCardInfo("Well of Discovery", 140, Rarity.RARE, mage.cards.w.WellOfDiscovery.class)); cards.add(new SetCardInfo("Well of Life", 141, Rarity.UNCOMMON, mage.cards.w.WellOfLife.class)); cards.add(new SetCardInfo("Whip Sergeant", 107, Rarity.UNCOMMON, mage.cards.w.WhipSergeant.class)); cards.add(new SetCardInfo("Whipstitched Zombie", 81, Rarity.COMMON, mage.cards.w.WhipstitchedZombie.class)); cards.add(new SetCardInfo("Wild Might", 134, Rarity.COMMON, mage.cards.w.WildMight.class)); cards.add(new SetCardInfo("Windscouter", 53, Rarity.UNCOMMON, mage.cards.w.Windscouter.class)); + cards.add(new SetCardInfo("Wing Storm", 135, Rarity.UNCOMMON, mage.cards.w.WingStorm.class)); cards.add(new SetCardInfo("Wintermoon Mesa", 143, Rarity.RARE, mage.cards.w.WintermoonMesa.class)); cards.add(new SetCardInfo("Withdraw", 54, Rarity.COMMON, mage.cards.w.Withdraw.class)); cards.add(new SetCardInfo("Zerapa Minotaur", 108, Rarity.COMMON, mage.cards.z.ZerapaMinotaur.class)); diff --git a/Mage.Sets/src/mage/sets/RivalsOfIxalan.java b/Mage.Sets/src/mage/sets/RivalsOfIxalan.java index 2274507ae97..710c3994e78 100644 --- a/Mage.Sets/src/mage/sets/RivalsOfIxalan.java +++ b/Mage.Sets/src/mage/sets/RivalsOfIxalan.java @@ -56,14 +56,23 @@ public class RivalsOfIxalan extends ExpansionSet { this.ratioBoosterMythic = 8; cards.add(new SetCardInfo("Angrath's Ambusher", 202, Rarity.UNCOMMON, mage.cards.a.AngrathsAmbusher.class)); + cards.add(new SetCardInfo("Angrath's Fury", 204, Rarity.RARE, mage.cards.a.AngrathsFury.class)); cards.add(new SetCardInfo("Angrath, Minotaur Pirate", 201, Rarity.MYTHIC, mage.cards.a.AngrathMinotaurPirate.class)); cards.add(new SetCardInfo("Brass's Bounty", 94, Rarity.RARE, mage.cards.b.BrasssBounty.class)); + cards.add(new SetCardInfo("Captain's Hook", 177, Rarity.RARE, mage.cards.c.CaptainsHook.class)); cards.add(new SetCardInfo("Cinder Barrens", 205, Rarity.RARE, mage.cards.c.CinderBarrens.class)); cards.add(new SetCardInfo("Evolving Wilds", 186, Rarity.RARE, mage.cards.e.EvolvingWilds.class)); cards.add(new SetCardInfo("Ghalta, Primal Hunger", 130, Rarity.RARE, mage.cards.g.GhaltaPrimalHunger.class)); cards.add(new SetCardInfo("Silvergill Adept", 53, Rarity.UNCOMMON, mage.cards.s.SilvergillAdept.class)); cards.add(new SetCardInfo("Storm the Vault", 173, Rarity.RARE, mage.cards.s.StormTheVault.class)); + cards.add(new SetCardInfo("Swab Goblin", 203, Rarity.COMMON, mage.cards.s.SwabGoblin.class)); + cards.add(new SetCardInfo("Tetzimoc, Primal Death", 86, Rarity.RARE, mage.cards.t.TetzimocPrimalDeath.class)); + cards.add(new SetCardInfo("The Immortal Sun", 180, Rarity.MYTHIC, mage.cards.t.TheImmortalSun.class)); + cards.add(new SetCardInfo("Vampire Champion", 198, Rarity.COMMON, mage.cards.v.VampireChampion.class)); cards.add(new SetCardInfo("Vault of Catlacan", 173, Rarity.RARE, mage.cards.v.VaultOfCatlacan.class)); cards.add(new SetCardInfo("Vona's Hunger", 90, Rarity.RARE, mage.cards.v.VonasHunger.class)); + cards.add(new SetCardInfo("Vraska's Conquistador", 199, Rarity.UNCOMMON, mage.cards.v.VraskasConquistador.class)); + cards.add(new SetCardInfo("Vraska's Scorn", 200, Rarity.RARE, mage.cards.v.VraskasScorn.class)); + cards.add(new SetCardInfo("Vraska, Scheming Gorgon", 197, Rarity.MYTHIC, mage.cards.v.VraskaSchemingGorgon.class)); } } diff --git a/Mage.Sets/src/mage/sets/UrzasLegacy.java b/Mage.Sets/src/mage/sets/UrzasLegacy.java index cadbddbd38a..38b8dff7ede 100644 --- a/Mage.Sets/src/mage/sets/UrzasLegacy.java +++ b/Mage.Sets/src/mage/sets/UrzasLegacy.java @@ -175,6 +175,7 @@ public class UrzasLegacy extends ExpansionSet { cards.add(new SetCardInfo("Ticking Gnomes", 136, Rarity.UNCOMMON, mage.cards.t.TickingGnomes.class)); cards.add(new SetCardInfo("Tinker", 45, Rarity.UNCOMMON, mage.cards.t.Tinker.class)); cards.add(new SetCardInfo("Tragic Poet", 24, Rarity.COMMON, mage.cards.t.TragicPoet.class)); + cards.add(new SetCardInfo("Treacherous Link", 71, Rarity.UNCOMMON, mage.cards.t.TreacherousLink.class)); cards.add(new SetCardInfo("Treefolk Mystic", 114, Rarity.COMMON, mage.cards.t.TreefolkMystic.class)); cards.add(new SetCardInfo("Treetop Village", 143, Rarity.UNCOMMON, mage.cards.t.TreetopVillage.class)); cards.add(new SetCardInfo("Unearth", 72, Rarity.COMMON, mage.cards.u.Unearth.class)); @@ -183,6 +184,7 @@ public class UrzasLegacy extends ExpansionSet { cards.add(new SetCardInfo("Viashino Heretic", 95, Rarity.UNCOMMON, mage.cards.v.ViashinoHeretic.class)); cards.add(new SetCardInfo("Viashino Sandscout", 96, Rarity.COMMON, mage.cards.v.ViashinoSandscout.class)); cards.add(new SetCardInfo("Vigilant Drake", 46, Rarity.COMMON, mage.cards.v.VigilantDrake.class)); + cards.add(new SetCardInfo("Walking Sponge", 47, Rarity.UNCOMMON, mage.cards.w.WalkingSponge.class)); cards.add(new SetCardInfo("Weatherseed Elf", 115, Rarity.COMMON, mage.cards.w.WeatherseedElf.class)); cards.add(new SetCardInfo("Weatherseed Faeries", 48, Rarity.COMMON, mage.cards.w.WeatherseedFaeries.class)); cards.add(new SetCardInfo("Weatherseed Treefolk", 116, Rarity.RARE, mage.cards.w.WeatherseedTreefolk.class)); diff --git a/Mage.Tests/src/test/java/org/mage/test/cards/abilities/enters/AugurOfBolasTest.java b/Mage.Tests/src/test/java/org/mage/test/cards/abilities/enters/AugurOfBolasTest.java new file mode 100644 index 00000000000..f8530873451 --- /dev/null +++ b/Mage.Tests/src/test/java/org/mage/test/cards/abilities/enters/AugurOfBolasTest.java @@ -0,0 +1,39 @@ +package org.mage.test.cards.abilities.enters; + +import mage.constants.PhaseStep; +import mage.constants.Zone; +import org.junit.Test; +import org.mage.test.serverside.base.CardTestPlayerBase; + +/** + * + * @author LevelX2 + */ +public class AugurOfBolasTest extends CardTestPlayerBase { + + /* + Aether Figment {1}{U} + Creature - Illusion + 1/1 + Kicker {3} (You may pay an additional as you cast this spell.) + Aether Figment can't be blocked. + If Aether Figment was kicked, it enters the battlefield with two +1/+1 counters on it. + */ + @Test + public void testEnteringWithCounters() { + addCard(Zone.LIBRARY, playerA, "Lightning Bolt", 3); + skipInitShuffling(); + addCard(Zone.BATTLEFIELD, playerA, "Island", 2); + // When Augur of Bolas enters the battlefield, look at the top three cards of your library. + // You may reveal an instant or sorcery card from among them and put it into your hand. Put the rest on the bottom of your library in any order. + addCard(Zone.HAND, playerA, "Augur of Bolas"); // Creature {1}{U} + + castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Augur of Bolas"); + + setStopAt(1, PhaseStep.BEGIN_COMBAT); + execute(); + + assertPermanentCount(playerA, "Augur of Bolas", 1); + assertHandCount(playerA, "Lightning Bolt", 1); + } +} diff --git a/Mage.Tests/src/test/java/org/mage/test/cards/abilities/keywords/MorphTest.java b/Mage.Tests/src/test/java/org/mage/test/cards/abilities/keywords/MorphTest.java index b4a15d9b529..8c8733d57dc 100644 --- a/Mage.Tests/src/test/java/org/mage/test/cards/abilities/keywords/MorphTest.java +++ b/Mage.Tests/src/test/java/org/mage/test/cards/abilities/keywords/MorphTest.java @@ -816,4 +816,41 @@ public class MorphTest extends CardTestPlayerBase { assertPermanentCount(playerA, "", 0); } + + /** + * The Ur-Dragon reduces cost of face down morph Dragons Simple to reproduce + * - Dragons with Morph/Megamorph such as Quicksilver Dragon cost {2} to + * play face-down instead of the normal {3}. Other non-Dragon morph costs + * are unchanged. + */ + @Test + public void testNoCostReductionOfFaceDownCastCreature() { + /* + Quicksilver Dragon {4}{U}{U} + Creature - Dragon + 5/5 + Flying + {U}: If target spell has only one target and that target is Quicksilver Dragon, change that spell's target to another creature. + Morph {4}{U} + */ + addCard(Zone.HAND, playerA, "Quicksilver Dragon"); + addCard(Zone.BATTLEFIELD, playerA, "Island", 3); + + // Eminence - As long as The Ur-Dragon is in the command zone or on the battlefield, other Dragon spells you cast cost {1} less to cast. + // Flying + // Whenever one or more Dragons you control attack, draw that many cards, then you may put a permanent card from your hand onto the battlefield + addCard(Zone.BATTLEFIELD, playerA, "The Ur-Dragon", 1); + + castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Quicksilver Dragon"); + setChoice(playerA, "Yes"); // cast it face down as 2/2 creature + + setStopAt(1, PhaseStep.BEGIN_COMBAT); + execute(); + + assertPermanentCount(playerA, "", 1); + assertHandCount(playerA, 0); + + assertTappedCount("Island", true, 3); + + } } diff --git a/Mage.Tests/src/test/java/org/mage/test/cards/copy/MirrorworksTest.java b/Mage.Tests/src/test/java/org/mage/test/cards/copy/MirrorworksTest.java new file mode 100644 index 00000000000..792a371bc99 --- /dev/null +++ b/Mage.Tests/src/test/java/org/mage/test/cards/copy/MirrorworksTest.java @@ -0,0 +1,94 @@ +/* + * 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.cards.copy; + +import mage.constants.PhaseStep; +import mage.constants.Zone; +import org.junit.Test; +import org.mage.test.serverside.base.CardTestPlayerBase; + +/** + * + * @author LevelX2 + */ +public class MirrorworksTest extends CardTestPlayerBase { + + /** + * If you play Mox Diamond, with Mirrorworks in play, and create a token + * copy, and you have no lands in hand, the Mox will enter the battlefield + * as usual instead of the graveyard. + */ + @Test + public void TestCopyWithoutLand() { + addCard(Zone.HAND, playerA, "Mountain", 1); + addCard(Zone.BATTLEFIELD, playerA, "Island", 2); + + // If Mox Diamond would enter the battlefield, you may discard a land card instead. If you do, put Mox Diamond onto the battlefield. If you don't, put it into its owner's graveyard. + // {T}: Add one mana of any color to your mana pool. + addCard(Zone.HAND, playerA, "Mox Diamond", 1); // Artifact {0} + + // Whenever another nontoken artifact enters the battlefield under your control, you may pay {2}. + // If you do, create a token that's a copy of that artifact. + addCard(Zone.BATTLEFIELD, playerA, "Mirrorworks", 1); // Artifact {5} + + castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Mox Diamond"); + setChoice(playerA, "Yes"); + + setStopAt(1, PhaseStep.BEGIN_COMBAT); + execute(); + + assertPermanentCount(playerA, "Mox Diamond", 1); + assertTappedCount("Island", true, 2); + assertGraveyardCount(playerA, "Mountain", 1); + + } + + @Test + public void TestCorrectCopy() { + addCard(Zone.HAND, playerA, "Mountain", 2); + addCard(Zone.BATTLEFIELD, playerA, "Island", 2); + + // If Mox Diamond would enter the battlefield, you may discard a land card instead. If you do, put Mox Diamond onto the battlefield. If you don't, put it into its owner's graveyard. + // {T}: Add one mana of any color to your mana pool. + addCard(Zone.HAND, playerA, "Mox Diamond", 1); // Artifact {0} + + // Whenever another nontoken artifact enters the battlefield under your control, you may pay {2}. + // If you do, create a token that's a copy of that artifact. + addCard(Zone.BATTLEFIELD, playerA, "Mirrorworks", 1); // Artifact {5} + + castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Mox Diamond"); + setChoice(playerA, "Yes"); + + setStopAt(1, PhaseStep.BEGIN_COMBAT); + execute(); + + assertPermanentCount(playerA, "Mox Diamond", 2); + assertGraveyardCount(playerA, "Mountain", 2); + + } +} diff --git a/Mage.Tests/src/test/java/org/mage/test/multiplayer/BlatantThieveryTest.java b/Mage.Tests/src/test/java/org/mage/test/multiplayer/BlatantThieveryTest.java new file mode 100644 index 00000000000..a5447b94b15 --- /dev/null +++ b/Mage.Tests/src/test/java/org/mage/test/multiplayer/BlatantThieveryTest.java @@ -0,0 +1,93 @@ +/* + * 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.multiplayer; + +import java.io.FileNotFoundException; +import mage.constants.MultiplayerAttackOption; +import mage.constants.PhaseStep; +import mage.constants.RangeOfInfluence; +import mage.constants.Zone; +import mage.game.FreeForAll; +import mage.game.Game; +import mage.game.GameException; +import org.junit.Test; +import org.mage.test.serverside.base.CardTestMultiPlayerBase; + +/** + * + * @author LevelX2 + */ +public class BlatantThieveryTest extends CardTestMultiPlayerBase { + + @Override + protected Game createNewGameAndPlayers() throws GameException, FileNotFoundException { + Game game = new FreeForAll(MultiplayerAttackOption.MULTIPLE, RangeOfInfluence.ALL, 0, 20); + // 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; + } + + @Test + public void NormalTest() { + // For each opponent, gain control of target permanent that player controls. + addCard(Zone.HAND, playerA, "Blatant Thievery"); // Sorcery {4}{U}{U}{U} + addCard(Zone.BATTLEFIELD, playerA, "Island", 7); + + // Player order: A -> D -> C -> B + addCard(Zone.BATTLEFIELD, playerB, "Silvercoat Lion", 2); + addCard(Zone.BATTLEFIELD, playerC, "Walking Corpse", 2); + addCard(Zone.BATTLEFIELD, playerD, "Pillarfield Ox", 2); + + castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Blatant Thievery"); + addTarget(playerA, "Silvercoat Lion"); + addTarget(playerA, "Walking Corpse"); + addTarget(playerA, "Pillarfield Ox"); + + setStopAt(1, PhaseStep.BEGIN_COMBAT); + execute(); + + assertPermanentCount(playerA, "Silvercoat Lion", 1); + assertPermanentCount(playerA, "Walking Corpse", 1); + assertPermanentCount(playerA, "Pillarfield Ox", 1); + assertPermanentCount(playerB, "Silvercoat Lion", 1); + assertPermanentCount(playerC, "Walking Corpse", 1); + assertPermanentCount(playerD, "Pillarfield Ox", 1); + } + + @Test + public void ControlChangeTest() { + // For each opponent, gain control of target permanent that player controls. + addCard(Zone.HAND, playerA, "Blatant Thievery"); // Sorcery {4}{U}{U}{U} + addCard(Zone.BATTLEFIELD, playerA, "Island", 7); + + addCard(Zone.HAND, playerB, "Act of Aggression"); // Instant {3}{M}{M} + addCard(Zone.BATTLEFIELD, playerB, "Mountain", 5); + + // Player order: A -> D -> C -> B + addCard(Zone.BATTLEFIELD, playerB, "Silvercoat Lion", 1); + addCard(Zone.BATTLEFIELD, playerC, "Walking Corpse", 1); + addCard(Zone.BATTLEFIELD, playerD, "Pillarfield Ox", 1); + + castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Blatant Thievery"); + addTarget(playerA, "Silvercoat Lion"); + addTarget(playerA, "Walking Corpse"); + addTarget(playerA, "Pillarfield Ox"); + castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerB, "Act of Aggression", "Pillarfield Ox", "Blatant Thievery"); + + setStopAt(1, PhaseStep.BEGIN_COMBAT); + execute(); + + assertGraveyardCount(playerA, "Blatant Thievery", 1); + assertGraveyardCount(playerB, "Act of Aggression", 1); + + assertPermanentCount(playerA, "Silvercoat Lion", 1); + assertPermanentCount(playerA, "Walking Corpse", 1); + assertPermanentCount(playerB, "Pillarfield Ox", 1); + } +} diff --git a/Mage.Verify/src/test/java/mage/verify/VerifyCardDataTest.java b/Mage.Verify/src/test/java/mage/verify/VerifyCardDataTest.java index 006f999ae22..5835ef9b067 100644 --- a/Mage.Verify/src/test/java/mage/verify/VerifyCardDataTest.java +++ b/Mage.Verify/src/test/java/mage/verify/VerifyCardDataTest.java @@ -33,6 +33,7 @@ public class VerifyCardDataTest { // power-toughness skipListCreate("PT"); skipListAddName("PT", "Garbage Elemental"); // UST + skipListAddName("PT", "Infinity Elemental"); // UST // color skipListCreate("COLOR"); diff --git a/Mage/src/main/java/mage/abilities/common/ControllerDivideCombatDamageAbility.java b/Mage/src/main/java/mage/abilities/common/ControllerDivideCombatDamageAbility.java new file mode 100644 index 00000000000..aceae25cf31 --- /dev/null +++ b/Mage/src/main/java/mage/abilities/common/ControllerDivideCombatDamageAbility.java @@ -0,0 +1,67 @@ +/* + * Copyright 2011 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.common; + +import mage.abilities.MageSingleton; +import mage.abilities.StaticAbility; + +import java.io.ObjectStreamException; + +import mage.constants.AbilityType; +import mage.constants.Zone; + +/** + * @author L_J + */ +public class ControllerDivideCombatDamageAbility extends StaticAbility implements MageSingleton { + + private static final ControllerDivideCombatDamageAbility instance = new ControllerDivideCombatDamageAbility(); + + private Object readResolve() throws ObjectStreamException { + return instance; + } + + public static ControllerDivideCombatDamageAbility getInstance() { + return instance; + } + + private ControllerDivideCombatDamageAbility() { + super(AbilityType.STATIC, Zone.BATTLEFIELD); + } + + @Override + public String getRule() { + return "You may assign {this}'s combat damage divided as you choose among defending player and/or any number of creatures he or she controls."; + } + + @Override + public ControllerDivideCombatDamageAbility copy() { + return instance; + } + +} diff --git a/Mage/src/main/java/mage/abilities/common/DealsCombatDamageToAPlayerTriggeredAbility.java b/Mage/src/main/java/mage/abilities/common/DealsCombatDamageToAPlayerTriggeredAbility.java index c13f59afbbd..392df68ec1f 100644 --- a/Mage/src/main/java/mage/abilities/common/DealsCombatDamageToAPlayerTriggeredAbility.java +++ b/Mage/src/main/java/mage/abilities/common/DealsCombatDamageToAPlayerTriggeredAbility.java @@ -33,6 +33,7 @@ import mage.constants.Zone; import mage.game.Game; import mage.game.events.DamagedPlayerEvent; import mage.game.events.GameEvent; +import mage.players.Player; import mage.target.targetpointer.FixedTarget; /** @@ -43,14 +44,20 @@ public class DealsCombatDamageToAPlayerTriggeredAbility extends TriggeredAbility protected boolean setTargetPointer; protected String text; + protected boolean onlyOpponents; public DealsCombatDamageToAPlayerTriggeredAbility(Effect effect, boolean optional) { this(effect, optional, false); } public DealsCombatDamageToAPlayerTriggeredAbility(Effect effect, boolean optional, boolean setTargetPointer) { + this(effect, optional, setTargetPointer, false); + } + + public DealsCombatDamageToAPlayerTriggeredAbility(Effect effect, boolean optional, boolean setTargetPointer, boolean onlyOpponents) { super(Zone.BATTLEFIELD, effect, optional); this.setTargetPointer = setTargetPointer; + this.onlyOpponents = onlyOpponents; } public DealsCombatDamageToAPlayerTriggeredAbility(Effect effect, boolean optional, String text, boolean setTargetPointer) { @@ -63,6 +70,7 @@ public class DealsCombatDamageToAPlayerTriggeredAbility extends TriggeredAbility super(ability); this.text = ability.text; this.setTargetPointer = ability.setTargetPointer; + this.onlyOpponents = ability.onlyOpponents; } @Override @@ -79,6 +87,12 @@ public class DealsCombatDamageToAPlayerTriggeredAbility extends TriggeredAbility public boolean checkTrigger(GameEvent event, Game game) { if (event.getSourceId().equals(getSourceId()) && ((DamagedPlayerEvent) event).isCombatDamage()) { + if (onlyOpponents) { + Player controller = game.getPlayer(getControllerId()); + if (controller == null || !controller.hasOpponent(event.getPlayerId(), game)) { + return false; + } + } if (setTargetPointer) { for (Effect effect : this.getAllEffects()) { effect.setTargetPointer(new FixedTarget(event.getPlayerId())); @@ -93,7 +107,7 @@ public class DealsCombatDamageToAPlayerTriggeredAbility extends TriggeredAbility @Override public String getRule() { if (text == null || text.isEmpty()) { - return "Whenever {this} deals combat damage to a player, " + super.getRule(); + return "Whenever {this} deals combat damage to " + (onlyOpponents ? "an opponent, " : "a player, ") + super.getRule(); } return text; } diff --git a/Mage/src/main/java/mage/abilities/effects/Effect.java b/Mage/src/main/java/mage/abilities/effects/Effect.java index 17234c7f9dc..fc98f40a947 100644 --- a/Mage/src/main/java/mage/abilities/effects/Effect.java +++ b/Mage/src/main/java/mage/abilities/effects/Effect.java @@ -24,16 +24,15 @@ * 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; import java.io.Serializable; import java.util.UUID; -import mage.constants.EffectType; -import mage.constants.Outcome; import mage.abilities.Ability; import mage.abilities.Mode; +import mage.constants.EffectType; +import mage.constants.Outcome; import mage.game.Game; import mage.target.targetpointer.TargetPointer; @@ -44,18 +43,31 @@ import mage.target.targetpointer.TargetPointer; public interface Effect extends Serializable { UUID getId(); + void newId(); + String getText(Mode mode); + Effect setText(String staticText); + boolean apply(Game game, Ability source); + Outcome getOutcome(); + void setOutcome(Outcome outcome); + EffectType getEffectType(); - void setTargetPointer(TargetPointer targetPointer); + + Effect setTargetPointer(TargetPointer targetPointer); + TargetPointer getTargetPointer(); + void setValue(String key, Object value); + Object getValue(String key); + void setApplyEffectsAfter(); + boolean applyEffectsAfter(); Effect copy(); diff --git a/Mage/src/main/java/mage/abilities/effects/EffectImpl.java b/Mage/src/main/java/mage/abilities/effects/EffectImpl.java index 91f82ddaa98..ccc7f08f3d8 100644 --- a/Mage/src/main/java/mage/abilities/effects/EffectImpl.java +++ b/Mage/src/main/java/mage/abilities/effects/EffectImpl.java @@ -24,20 +24,18 @@ * 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; -import mage.constants.EffectType; -import mage.constants.Outcome; -import mage.abilities.MageSingleton; -import mage.abilities.Mode; -import mage.target.targetpointer.FirstTargetPointer; -import mage.target.targetpointer.TargetPointer; - import java.util.HashMap; import java.util.Map; import java.util.UUID; +import mage.abilities.MageSingleton; +import mage.abilities.Mode; +import mage.constants.EffectType; +import mage.constants.Outcome; +import mage.target.targetpointer.FirstTargetPointer; +import mage.target.targetpointer.TargetPointer; /** * @@ -106,8 +104,9 @@ public abstract class EffectImpl implements Effect { } @Override - public void setTargetPointer(TargetPointer targetPointer) { + public Effect setTargetPointer(TargetPointer targetPointer) { this.targetPointer = targetPointer; + return this; } @Override @@ -141,8 +140,8 @@ public abstract class EffectImpl implements Effect { } /** - * If set, the game.applyEffects() method will be called to apply the effects before the - * next effect (of the same ability) will resolve. + * If set, the game.applyEffects() method will be called to apply the + * effects before the next effect (of the same ability) will resolve. */ @Override public void setApplyEffectsAfter() { diff --git a/Mage/src/main/java/mage/abilities/effects/common/DestroyEquippedEffect.java b/Mage/src/main/java/mage/abilities/effects/common/DestroyEquippedEffect.java new file mode 100644 index 00000000000..6d833155850 --- /dev/null +++ b/Mage/src/main/java/mage/abilities/effects/common/DestroyEquippedEffect.java @@ -0,0 +1,51 @@ +/* + * 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.abilities.Ability; +import mage.abilities.effects.OneShotEffect; +import mage.constants.Outcome; +import mage.game.Game; +import mage.game.permanent.Permanent; + +/** + * + * @author LevelX2 + */ +public class DestroyEquippedEffect extends OneShotEffect { + + public DestroyEquippedEffect() { + super(Outcome.DestroyPermanent); + staticText = "destroy that permanent"; + } + + public DestroyEquippedEffect(final DestroyEquippedEffect effect) { + super(effect); + } + + @Override + public DestroyEquippedEffect copy() { + return new DestroyEquippedEffect(this); + } + + @Override + public boolean apply(Game game, Ability source) { + Permanent equipment = game.getPermanent(source.getSourceId()); + if (equipment != null && equipment.getAttachedTo() != null) { + UUID uuid = getTargetPointer().getFirst(game, source); + Permanent permanent = game.getPermanent(uuid); + if (permanent == null) { + permanent = game.getPermanent(equipment.getAttachedTo()); + } + if (permanent != null) { + return permanent.destroy(source.getSourceId(), game, false); + } + } + return false; + } + +} diff --git a/Mage/src/main/java/mage/abilities/effects/common/DoUnlessTargetPlayerOrTargetsControllerPaysEffect.java b/Mage/src/main/java/mage/abilities/effects/common/DoUnlessTargetPlayerOrTargetsControllerPaysEffect.java new file mode 100644 index 00000000000..47f064ea6fb --- /dev/null +++ b/Mage/src/main/java/mage/abilities/effects/common/DoUnlessTargetPlayerOrTargetsControllerPaysEffect.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.abilities.effects.common; + +import mage.MageObject; +import mage.abilities.Ability; +import mage.abilities.Mode; +import mage.abilities.costs.Cost; +import mage.abilities.costs.mana.GenericManaCost; +import mage.abilities.dynamicvalue.DynamicValue; +import mage.abilities.effects.ContinuousEffect; +import mage.abilities.effects.Effect; +import mage.abilities.effects.Effects; +import mage.abilities.effects.OneShotEffect; +import mage.constants.Outcome; +import mage.game.Game; +import mage.game.permanent.Permanent; +import mage.players.Player; +import mage.util.CardUtil; + +/** + * + * @author MarcoMarin & L_J + */ +public class DoUnlessTargetPlayerOrTargetsControllerPaysEffect extends OneShotEffect { + + protected Effects executingEffects = new Effects(); + private Effect otherwiseEffect; + private Cost cost; + private DynamicValue genericMana; + private String chooseUseText; + + public DoUnlessTargetPlayerOrTargetsControllerPaysEffect(Effect effect, Cost cost) { + this(effect, cost, null); + } + + public DoUnlessTargetPlayerOrTargetsControllerPaysEffect(Effect effect, Cost cost, String chooseUseText) { + this(effect, null, cost, chooseUseText); + } + + public DoUnlessTargetPlayerOrTargetsControllerPaysEffect(Effect effect, Effect otherwiseEffect, Cost cost, String chooseUseText) { + super(Outcome.Detriment); + this.executingEffects.add(effect); + this.otherwiseEffect = otherwiseEffect; + this.cost = cost; + this.chooseUseText = chooseUseText; + } + + public DoUnlessTargetPlayerOrTargetsControllerPaysEffect(Effect effect, DynamicValue genericMana) { + super(Outcome.Detriment); + this.executingEffects.add(effect); + this.genericMana = genericMana; + } + + public DoUnlessTargetPlayerOrTargetsControllerPaysEffect(final DoUnlessTargetPlayerOrTargetsControllerPaysEffect effect) { + super(effect); + this.executingEffects = effect.executingEffects.copy(); + this.otherwiseEffect = effect.otherwiseEffect; + if (effect.cost != null) { + this.cost = effect.cost.copy(); + } + if (effect.genericMana != null) { + this.genericMana = effect.genericMana.copy(); + } + this.chooseUseText = effect.chooseUseText; + } + + public void addEffect(Effect effect) { + executingEffects.add(effect); + } + + @Override + public boolean apply(Game game, Ability source) { + Player targetController = game.getPlayer(this.getTargetPointer().getFirst(game, source)); + Permanent targetPermanent = game.getPermanentOrLKIBattlefield(this.getTargetPointer().getFirst(game, source)); + if (targetPermanent != null) { + targetController = game.getPlayer(targetPermanent.getControllerId()); + } + if (targetController != null) { + MageObject sourceObject = game.getObject(source.getSourceId()); + if (targetController != null && sourceObject != null) { + Cost costToPay; + if (cost != null) { + costToPay = cost.copy(); + } else { + costToPay = new GenericManaCost(genericMana.calculate(game, source, this)); + } + String message; + if (chooseUseText == null) { + String effectText = executingEffects.getText(source.getModes().getMode()); + message = "Pay " + costToPay.getText() + " to prevent (" + effectText.substring(0, effectText.length() - 1) + ")?"; + } else { + message = chooseUseText; + } + message = CardUtil.replaceSourceName(message, sourceObject.getName()); + boolean result = true; + boolean doEffect = true; + + // check if targetController is willing to pay + if (costToPay.canPay(source, source.getSourceId(), targetController.getId(), game) && targetController.chooseUse(Outcome.Detriment, message, source, game)) { + costToPay.clearPaid(); + if (costToPay.pay(source, game, source.getSourceId(), targetController.getId(), false, null)) { + if (!game.isSimulation()) { + game.informPlayers(targetController.getLogName() + " pays the cost to prevent the effect"); + } + doEffect = false; + } + } + + // do the effects if not paid + if (doEffect) { + for (Effect effect : executingEffects) { + effect.setTargetPointer(this.targetPointer); + if (effect instanceof OneShotEffect) { + result &= effect.apply(game, source); + } else { + game.addEffect((ContinuousEffect) effect, source); + } + } + } else if (otherwiseEffect != null) { + otherwiseEffect.setTargetPointer(this.targetPointer); + if (otherwiseEffect instanceof OneShotEffect) { + result &= otherwiseEffect.apply(game, source); + } else { + game.addEffect((ContinuousEffect) otherwiseEffect, source); + } + } + return result; + } + } + return false; + } + + @Override + public String getText(Mode mode) { + if (!staticText.isEmpty()) { + return staticText; + } + String effectsText = executingEffects.getText(mode); + return effectsText.substring(0, effectsText.length() - 1) + " unless its controller pays " + (cost != null ? cost.getText() : "{X}"); + } + + @Override + public DoUnlessTargetPlayerOrTargetsControllerPaysEffect copy() { + return new DoUnlessTargetPlayerOrTargetsControllerPaysEffect(this); + } +} diff --git a/Mage/src/main/java/mage/abilities/keyword/MorphAbility.java b/Mage/src/main/java/mage/abilities/keyword/MorphAbility.java index dfe545198cd..46714d92439 100644 --- a/Mage/src/main/java/mage/abilities/keyword/MorphAbility.java +++ b/Mage/src/main/java/mage/abilities/keyword/MorphAbility.java @@ -230,6 +230,7 @@ public class MorphAbility extends StaticAbility implements AlternativeSourceCost spellColor.setGreen(false); spellColor.setWhite(false); spellColor.setBlue(false); + spell.getSubtype(game).clear(); } else { spell.setFaceDown(false, game); } diff --git a/Mage/src/main/java/mage/counters/CounterType.java b/Mage/src/main/java/mage/counters/CounterType.java index 82c783d3a75..769412a3849 100644 --- a/Mage/src/main/java/mage/counters/CounterType.java +++ b/Mage/src/main/java/mage/counters/CounterType.java @@ -107,6 +107,7 @@ public enum CounterType { POLYP("polyp"), POISON("poison"), PRESSURE("pressure"), + PREY("prey"), REPAIR("repair"), QUEST("quest"), SCREAM("scream"), diff --git a/Mage/src/main/java/mage/game/GameImpl.java b/Mage/src/main/java/mage/game/GameImpl.java index ca02d9e7bbf..7b5e10477b5 100644 --- a/Mage/src/main/java/mage/game/GameImpl.java +++ b/Mage/src/main/java/mage/game/GameImpl.java @@ -3000,5 +3000,4 @@ public abstract class GameImpl implements Game, Serializable { fireEvent(new GameEvent(GameEvent.EventType.BECOMES_MONARCH, monarchId, source == null ? null : source.getSourceId(), monarchId)); } } - } diff --git a/Mage/src/main/java/mage/game/combat/CombatGroup.java b/Mage/src/main/java/mage/game/combat/CombatGroup.java index 44a4e52f383..7ad9391ceac 100644 --- a/Mage/src/main/java/mage/game/combat/CombatGroup.java +++ b/Mage/src/main/java/mage/game/combat/CombatGroup.java @@ -34,6 +34,7 @@ import java.util.List; import java.util.Map; import java.util.UUID; import mage.abilities.common.ControllerAssignCombatDamageToBlockersAbility; +import mage.abilities.common.ControllerDivideCombatDamageAbility; import mage.abilities.common.DamageAsThoughNotBlockedAbility; import mage.abilities.keyword.CantBlockAloneAbility; import mage.abilities.keyword.DeathtouchAbility; @@ -41,6 +42,7 @@ import mage.abilities.keyword.DoubleStrikeAbility; import mage.abilities.keyword.FirstStrikeAbility; import mage.abilities.keyword.TrampleAbility; import mage.constants.Outcome; +import mage.filter.StaticFilters; import mage.game.Game; import mage.game.events.GameEvent; import mage.game.permanent.Permanent; @@ -140,21 +142,24 @@ public class CombatGroup implements Serializable, Copyable { public void assignDamageToBlockers(boolean first, Game game) { if (!attackers.isEmpty() && (!first || hasFirstOrDoubleStrike(game))) { - if (blockers.isEmpty()) { - unblockedDamage(first, game); - } else { - Permanent attacker = game.getPermanent(attackers.get(0)); - if (attacker.getAbilities().containsKey(DamageAsThoughNotBlockedAbility.getInstance().getId())) { - Player player = game.getPlayer(attacker.getControllerId()); - if (player.chooseUse(Outcome.Damage, "Do you wish to assign damage for " + attacker.getLogName() + " as though it weren't blocked?", null, game)) { - blocked = false; - unblockedDamage(first, game); - } - } - if (blockers.size() == 1) { - singleBlockerDamage(first, game); + Permanent attacker = game.getPermanent(attackers.get(0)); + if (!assignsDefendingPlayerAndOrDefendingCreaturesDividedDamage(attacker, attacker.getControllerId(), first, game, true)) { + if (blockers.isEmpty()) { + unblockedDamage(first, game); + return; } else { - multiBlockerDamage(first, game); + Player player = game.getPlayer(defenderControlsDefensiveFormation(game) ? defendingPlayerId : attacker.getControllerId()); + if (attacker.getAbilities().containsKey(DamageAsThoughNotBlockedAbility.getInstance().getId())) { // for handling creatures like Thorn Elemental + if (player.chooseUse(Outcome.Damage, "Do you wish to assign damage for " + attacker.getLogName() + " as though it weren't blocked?", null, game)) { + blocked = false; + unblockedDamage(first, game); + } + } + if (blockers.size() == 1) { + singleBlockerDamage(player, first, game); + } else { + multiBlockerDamage(player, first, game); + } } } } @@ -162,6 +167,18 @@ public class CombatGroup implements Serializable, Copyable { public void assignDamageToAttackers(boolean first, Game game) { if (!blockers.isEmpty() && (!first || hasFirstOrDoubleStrike(game))) { + // this should only come up if Butcher Orgg is granted the ability to block multiple blockers + boolean altDamageMethod = false; + for (UUID blockerId : blockers) { + Permanent blocker = game.getPermanent(blockerId); + if (assignsDefendingPlayerAndOrDefendingCreaturesDividedDamage(blocker, blocker.getControllerId(), first, game, false)) { + altDamageMethod = true; + } + } + if (altDamageMethod) { + // this could be necessary to remake in the future (banding with Butcher Orgg?) + return; + } if (attackers.size() == 1) { singleAttackerDamage(first, game); } else { @@ -226,7 +243,7 @@ public class CombatGroup implements Serializable, Copyable { } } - private void singleBlockerDamage(boolean first, Game game) { + private void singleBlockerDamage(Player player, boolean first, Game game) { //TODO: handle banding Permanent blocker = game.getPermanent(blockers.get(0)); Permanent attacker = game.getPermanent(attackers.get(0)); @@ -244,13 +261,6 @@ public class CombatGroup implements Serializable, Copyable { if (lethalDamage >= damage) { blocker.markDamage(damage, attacker.getId(), game, true, true); } else { - Player player = game.getPlayer(attacker.getControllerId()); - for (Permanent defensiveFormation : game.getBattlefield().getAllActivePermanents(defendingPlayerId)) { // for handling Defensive Formation - if (defensiveFormation.getAbilities().containsKey(ControllerAssignCombatDamageToBlockersAbility.getInstance().getId())) { - player = game.getPlayer(defendingPlayerId); - break; - } - } int damageAssigned = player.getAmount(lethalDamage, damage, "Assign damage to " + blocker.getName(), game); blocker.markDamage(damageAssigned, attacker.getId(), game, true, true); damage -= damageAssigned; @@ -264,27 +274,21 @@ public class CombatGroup implements Serializable, Copyable { } if (canDamage(blocker, first)) { if (blocker.getBlocking() == 1) { // blocking several creatures handled separately - attacker.markDamage(blockerDamage, blocker.getId(), game, true, true); + if (!assignsDefendingPlayerAndOrDefendingCreaturesDividedDamage(blocker, blocker.getControllerId(), first, game, false)) { + attacker.markDamage(blockerDamage, blocker.getId(), game, true, true); + } } } } } - private void multiBlockerDamage(boolean first, Game game) { + private void multiBlockerDamage(Player player, boolean first, Game game) { //TODO: handle banding Permanent attacker = game.getPermanent(attackers.get(0)); if (attacker == null) { return; } - boolean oldRuleDamage = false; - Player player = game.getPlayer(attacker.getControllerId()); - for (Permanent defensiveFormation : game.getBattlefield().getAllActivePermanents(defendingPlayerId)) { // for handling Defensive Formation - if (defensiveFormation.getAbilities().containsKey(ControllerAssignCombatDamageToBlockersAbility.getInstance().getId())) { - player = game.getPlayer(defendingPlayerId); - oldRuleDamage = true; - break; - } - } + boolean oldRuleDamage = (player.getId() == defendingPlayerId); int damage = getDamageValueFromPermanent(attacker, game); if (canDamage(attacker, first)) { // must be set before attacker damage marking because of effects like Test of Faith @@ -310,9 +314,13 @@ public class CombatGroup implements Serializable, Copyable { lethalDamage = blocker.getToughness().getValue() - blocker.getDamage(); } if (lethalDamage >= damage) { - assigned.put(blockerId, damage); - damage = 0; - break; + if (!oldRuleDamage) { + assigned.put(blockerId, damage); + damage = 0; + break; + } else if (damage == 0) { + break; + } } int damageAssigned = 0; if (!oldRuleDamage) { @@ -337,7 +345,11 @@ public class CombatGroup implements Serializable, Copyable { for (UUID blockerId : blockerOrder) { Integer power = blockerPower.get(blockerId); if (power != null) { - attacker.markDamage(power, blockerId, game, true, true); + // might be missing canDamage condition? + Permanent blocker = game.getPermanent(blockerId); + if (!assignsDefendingPlayerAndOrDefendingCreaturesDividedDamage(blocker, blocker.getControllerId(), first, game, false)) { + attacker.markDamage(power, blockerId, game, true, true); + } } } for (Map.Entry entry : assigned.entrySet()) { @@ -348,7 +360,76 @@ public class CombatGroup implements Serializable, Copyable { for (UUID blockerId : blockerOrder) { Permanent blocker = game.getPermanent(blockerId); if (canDamage(blocker, first)) { - attacker.markDamage(getDamageValueFromPermanent(blocker, game), blocker.getId(), game, true, true); + if (!assignsDefendingPlayerAndOrDefendingCreaturesDividedDamage(blocker, blocker.getControllerId(), first, game, false)) { + attacker.markDamage(getDamageValueFromPermanent(blocker, game), blocker.getId(), game, true, true); + } + } + } + } + } + + private void defendingPlayerAndOrDefendingCreaturesDividedDamage(Permanent attacker, Player player, boolean first, Game game, boolean isAttacking) { + // for handling Butcher Orgg + if (!((blocked && blockers.isEmpty() && isAttacking) || (attackers.isEmpty() && !isAttacking))) { + if (attacker == null) { + return; + } + int damage = getDamageValueFromPermanent(attacker, game); + if (canDamage(attacker, first)) { + // must be set before attacker damage marking because of effects like Test of Faith + Map blockerPower = new HashMap<>(); + for (UUID blockerId : blockerOrder) { + Permanent blocker = game.getPermanent(blockerId); + if (canDamage(blocker, first)) { + if (blocker.getBlocking() == 1) { // blocking several creatures handled separately + blockerPower.put(blockerId, getDamageValueFromPermanent(blocker, game)); + } + } + } + Map assigned = new HashMap<>(); + for (Permanent defendingCreature : game.getBattlefield().getAllActivePermanents(StaticFilters.FILTER_PERMANENT_CREATURE, defendingPlayerId, game)) { + if (defendingCreature != null) { + if (!(damage > 0)) { + break; + } + int damageAssigned = 0; + damageAssigned = player.getAmount(0, damage, "Assign damage to " + defendingCreature.getName(), game); + assigned.put(defendingCreature.getId(), damageAssigned); + damage -= damageAssigned; + } + } + if (damage > 0) { + Player defendingPlayer = game.getPlayer(defendingPlayerId); + if (defendingPlayer.isInGame()) { + defendingPlayer.damage(damage, attacker.getId(), game, true, true); + } + } + if (isAttacking) { + for (UUID blockerId : blockerOrder) { + Integer power = blockerPower.get(blockerId); + if (power != null) { + // might be missing canDamage condition? + Permanent blocker = game.getPermanent(blockerId); + if (!assignsDefendingPlayerAndOrDefendingCreaturesDividedDamage(blocker, blocker.getControllerId(), first, game, false)) { + attacker.markDamage(power, blockerId, game, true, true); + } + } + } + } + for (Map.Entry entry : assigned.entrySet()) { + Permanent defendingCreature = game.getPermanent(entry.getKey()); + defendingCreature.markDamage(entry.getValue(), attacker.getId(), game, true, true); + } + } else { + if (isAttacking) { + for (UUID blockerId : blockerOrder) { + Permanent blocker = game.getPermanent(blockerId); + if (canDamage(blocker, first)) { + if (!assignsDefendingPlayerAndOrDefendingCreaturesDividedDamage(blocker, blocker.getControllerId(), first, game, false)) { + attacker.markDamage(getDamageValueFromPermanent(blocker, game), blocker.getId(), game, true, true); + } + } + } } } } @@ -491,13 +572,7 @@ public class CombatGroup implements Serializable, Copyable { if (blockers.isEmpty()) { return; } - Player player = game.getPlayer(playerId); - for (Permanent defensiveFormation : game.getBattlefield().getAllActivePermanents(defendingPlayerId)) { // for handling Defensive Formation - if (defensiveFormation.getAbilities().containsKey(ControllerAssignCombatDamageToBlockersAbility.getInstance().getId())) { - player = game.getPlayer(defendingPlayerId); - break; - } - } + Player player = game.getPlayer(defenderControlsDefensiveFormation(game) ? defendingPlayerId : playerId); List blockerList = new ArrayList<>(blockers); blockerOrder.clear(); while (player.canRespond()) { @@ -720,4 +795,30 @@ public class CombatGroup implements Serializable, Copyable { } return false; } + + public boolean defenderControlsDefensiveFormation(Game game) { + // for handling Defensive Formation + for (Permanent defensiveFormation : game.getBattlefield().getAllActivePermanents(defendingPlayerId)) { + if (defensiveFormation.getAbilities().containsKey(ControllerAssignCombatDamageToBlockersAbility.getInstance().getId())) { + return true; + } + } + return false; + } + + public boolean assignsDefendingPlayerAndOrDefendingCreaturesDividedDamage(Permanent creature, UUID playerId, boolean first, Game game, boolean isAttacking) { + // for handling Butcher Orgg + if (creature.getAbilities().containsKey(ControllerDivideCombatDamageAbility.getInstance().getId())) { + Player player = game.getPlayer(defenderControlsDefensiveFormation(game) ? defendingPlayerId : playerId); + // 10/4/2004 If it is blocked but then all of its blockers are removed before combat damage is assigned, then it won’t be able to deal combat damage and you won’t be able to use its ability. + // (same principle should apply if it's blocking and its blocked attacker is removed from combat) + if (!((blocked && blockers.isEmpty() && isAttacking) || (attackers.isEmpty() && !isAttacking)) && canDamage(creature, first)) { + if (player.chooseUse(Outcome.Damage, "Do you wish to assign " + creature.getLogName() + "'s combat damage divided among defending player and/or any number of defending creatures?", null, game)) { + defendingPlayerAndOrDefendingCreaturesDividedDamage(creature, player, first, game, isAttacking); + return true; + } + } + } + return false; + } } diff --git a/Mage/src/main/java/mage/game/permanent/PermanentImpl.java b/Mage/src/main/java/mage/game/permanent/PermanentImpl.java index a5e5b9d59c1..95c27b3c634 100644 --- a/Mage/src/main/java/mage/game/permanent/PermanentImpl.java +++ b/Mage/src/main/java/mage/game/permanent/PermanentImpl.java @@ -56,6 +56,7 @@ import mage.game.permanent.token.SquirrelToken; import mage.game.stack.Spell; import mage.game.stack.StackObject; import mage.players.Player; +import mage.util.CardUtil; import mage.util.GameLog; import mage.util.ThreadLocalStringBuilder; @@ -887,7 +888,8 @@ public abstract class PermanentImpl extends CardImpl implements Permanent { addCounters(CounterType.M1M1.createInstance(actualDamage), damageSourceAbility, game); } } else { - this.damage += actualDamage; + // this.damage += actualDamage; + this.damage = CardUtil.addWithOverflowCheck(this.damage, actualDamage); } game.fireEvent(new DamagedCreatureEvent(objectId, sourceId, controllerId, actualDamage, combat)); return actualDamage; diff --git a/Mage/src/main/java/mage/players/PlayerImpl.java b/Mage/src/main/java/mage/players/PlayerImpl.java index de7e06268aa..64c9fde58e0 100644 --- a/Mage/src/main/java/mage/players/PlayerImpl.java +++ b/Mage/src/main/java/mage/players/PlayerImpl.java @@ -1759,7 +1759,8 @@ public abstract class PlayerImpl implements Player, Serializable { } GameEvent event = new GameEvent(GameEvent.EventType.LOSE_LIFE, playerId, playerId, playerId, amount, atCombat); if (!game.replaceEvent(event)) { - this.life -= event.getAmount(); + // this.life -= event.getAmount(); + this.life = CardUtil.subtractWithOverflowCheck(this.life, event.getAmount()); if (!game.isSimulation()) { game.informPlayers(this.getLogName() + " loses " + event.getAmount() + " life"); } @@ -1788,7 +1789,10 @@ public abstract class PlayerImpl implements Player, Serializable { } GameEvent event = new GameEvent(GameEvent.EventType.GAIN_LIFE, playerId, playerId, playerId, amount, false); if (!game.replaceEvent(event)) { - this.life += event.getAmount(); + // TODO: lock life at Integer.MAX_VALUE if reached, until it's set to a different amount + // (https://magic.wizards.com/en/articles/archive/news/unstable-faqawaslfaqpaftidawabiajtbt-2017-12-06 - "infinite" life total stays infinite no matter how much is gained or lost) + // this.life += event.getAmount(); + this.life = CardUtil.addWithOverflowCheck(this.life, event.getAmount()); if (!game.isSimulation()) { game.informPlayers(this.getLogName() + " gains " + event.getAmount() + " life"); } diff --git a/Mage/src/main/java/mage/util/CardUtil.java b/Mage/src/main/java/mage/util/CardUtil.java index 301a26e83f2..bdc5e2a1b52 100644 --- a/Mage/src/main/java/mage/util/CardUtil.java +++ b/Mage/src/main/java/mage/util/CardUtil.java @@ -509,4 +509,24 @@ public final class CardUtil { } } + public static int addWithOverflowCheck(int base, int increment) { + long result = ((long) base) + increment; + if (result > Integer.MAX_VALUE) { + return Integer.MAX_VALUE; + } else if (result < Integer.MIN_VALUE) { + return Integer.MIN_VALUE; + } + return base + increment; + } + + public static int subtractWithOverflowCheck(int base, int decrement) { + long result = ((long) base) - decrement; + if (result > Integer.MAX_VALUE) { + return Integer.MAX_VALUE; + } else if (result < Integer.MIN_VALUE) { + return Integer.MIN_VALUE; + } + return base - decrement; + } + }