From d28de9e357011310f8914ee4fda58d0311ade01f Mon Sep 17 00:00:00 2001 From: Evan Kranzler Date: Fri, 1 Sep 2017 16:38:40 -0400 Subject: [PATCH 1/6] Implemented Shifty Doppelganger --- .../src/mage/cards/s/ShiftyDoppelganger.java | 174 ++++++++++++++++++ Mage.Sets/src/mage/sets/Odyssey.java | 1 + .../costs/common/ExileSourceCost.java | 5 +- 3 files changed, 178 insertions(+), 2 deletions(-) create mode 100644 Mage.Sets/src/mage/cards/s/ShiftyDoppelganger.java diff --git a/Mage.Sets/src/mage/cards/s/ShiftyDoppelganger.java b/Mage.Sets/src/mage/cards/s/ShiftyDoppelganger.java new file mode 100644 index 0000000000..546790b9da --- /dev/null +++ b/Mage.Sets/src/mage/cards/s/ShiftyDoppelganger.java @@ -0,0 +1,174 @@ +/* + * 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.MageObject; +import mage.abilities.Ability; +import mage.abilities.DelayedTriggeredAbility; +import mage.abilities.common.SimpleActivatedAbility; +import mage.abilities.common.delayed.AtTheBeginOfNextEndStepDelayedTriggeredAbility; +import mage.abilities.costs.common.ExileSourceCost; +import mage.abilities.costs.mana.ManaCostsImpl; +import mage.abilities.effects.ContinuousEffect; +import mage.abilities.effects.OneShotEffect; +import mage.abilities.effects.common.continuous.GainAbilityTargetEffect; +import mage.abilities.keyword.HasteAbility; +import mage.cards.Card; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.Duration; +import mage.constants.Outcome; +import mage.constants.Zone; +import mage.filter.common.FilterCreatureCard; +import mage.game.Game; +import mage.game.permanent.Permanent; +import mage.players.Player; +import mage.target.common.TargetCardInHand; +import mage.target.targetpointer.FixedTarget; + +/** + * + * @author TheElk801 + */ +public class ShiftyDoppelganger extends CardImpl { + + public ShiftyDoppelganger(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{2}{U}"); + + this.subtype.add("Shapeshifter"); + this.power = new MageInt(1); + this.toughness = new MageInt(1); + + // {3}{U}, Exile Shifty Doppelganger: You may put a creature card from your hand onto the battlefield. If you do, that creature gains haste until end of turn. At the beginning of the next end step, sacrifice that creature. If you do, return Shifty Doppelganger to the battlefield. + Ability ability = new SimpleActivatedAbility(Zone.BATTLEFIELD, new ShiftyDoppelgangerExileEffect(), new ManaCostsImpl("{3}{U}")); + ability.addCost(new ExileSourceCost(true)); + this.addAbility(ability); + + } + + public ShiftyDoppelganger(final ShiftyDoppelganger card) { + super(card); + } + + @Override + public ShiftyDoppelganger copy() { + return new ShiftyDoppelganger(this); + } +} + +class ShiftyDoppelgangerExileEffect extends OneShotEffect { + + public ShiftyDoppelgangerExileEffect() { + super(Outcome.PutCreatureInPlay); + this.staticText = "You may put a creature card from your hand onto the battlefield. If you do, that creature gains haste until end of turn. At the beginning of the next end step, sacrifice that creature. If you do, return {this} to the battlefield"; + } + + public ShiftyDoppelgangerExileEffect(final ShiftyDoppelgangerExileEffect effect) { + super(effect); + } + + @Override + public ShiftyDoppelgangerExileEffect copy() { + return new ShiftyDoppelgangerExileEffect(this); + } + + @Override + public boolean apply(Game game, Ability source) { + FilterCreatureCard filter = new FilterCreatureCard("a creature card"); + boolean putCreature = false; + UUID creatureId = UUID.randomUUID(); + Player player = game.getPlayer(source.getControllerId()); + if (player.chooseUse(Outcome.PutCardInPlay, "Put " + filter.getMessage() + " from your hand onto the battlefield?", source, game)) { + TargetCardInHand target = new TargetCardInHand(filter); + if (player.choose(Outcome.PutCreatureInPlay, target, source.getSourceId(), game)) { + Card card = game.getCard(target.getFirstTarget()); + if (card != null) { + putCreature = player.moveCards(card, Zone.BATTLEFIELD, source, game); + if (putCreature) { + creatureId = card.getId(); + } + } + } + } + if (putCreature) { + Permanent creature = game.getPermanent(creatureId); + if (creature != null) { + ContinuousEffect hasteEffect = new GainAbilityTargetEffect(HasteAbility.getInstance(), Duration.EndOfTurn); + hasteEffect.setTargetPointer(new FixedTarget(creature, game)); + game.addEffect(hasteEffect, source); + DelayedTriggeredAbility delayedAbility = new AtTheBeginOfNextEndStepDelayedTriggeredAbility( + new ShiftyDoppelgangerReturnEffect(creature.getId(), creature.getZoneChangeCounter(game), (int) game.getState().getValue(source.getSourceId().toString()))); + game.addDelayedTriggeredAbility(delayedAbility, source); + } + } + return true; + } +} + +class ShiftyDoppelgangerReturnEffect extends OneShotEffect { + + private final UUID creatureId; + private final int creatureZoneCount; + private final int sourceZoneCount; + + ShiftyDoppelgangerReturnEffect(UUID creatureId, int creatureZoneCount, int sourceZoneCount) { + super(Outcome.Benefit); + this.staticText = "sacrifice that creature. If you do, return {this} to the battlefield"; + this.creatureId = creatureId; + this.creatureZoneCount = creatureZoneCount; + this.sourceZoneCount = sourceZoneCount; + } + + ShiftyDoppelgangerReturnEffect(final ShiftyDoppelgangerReturnEffect effect) { + super(effect); + this.creatureId = effect.creatureId; + this.creatureZoneCount = effect.creatureZoneCount; + this.sourceZoneCount = effect.sourceZoneCount; + } + + @Override + public ShiftyDoppelgangerReturnEffect copy() { + return new ShiftyDoppelgangerReturnEffect(this); + } + + @Override + public boolean apply(Game game, Ability source) { + Permanent creature = game.getPermanent(creatureId); + Player player = game.getPlayer(source.getControllerId()); + MageObject sourceObject = source.getSourceObject(game); + if (creature != null && creature.getZoneChangeCounter(game) == this.creatureZoneCount && creature.sacrifice(source.getSourceId(), game)) { + if (player != null && sourceObject != null && sourceObject.getZoneChangeCounter(game) == this.sourceZoneCount) { + player.moveCards(game.getCard(source.getSourceId()), Zone.BATTLEFIELD, source, game); + } + } + return false; + } +} diff --git a/Mage.Sets/src/mage/sets/Odyssey.java b/Mage.Sets/src/mage/sets/Odyssey.java index 95185534b3..e5a0611070 100644 --- a/Mage.Sets/src/mage/sets/Odyssey.java +++ b/Mage.Sets/src/mage/sets/Odyssey.java @@ -302,6 +302,7 @@ public class Odyssey extends ExpansionSet { cards.add(new SetCardInfo("Shadowblood Ridge", 326, Rarity.RARE, mage.cards.s.ShadowbloodRidge.class)); cards.add(new SetCardInfo("Shadowmage Infiltrator", 294, Rarity.RARE, mage.cards.s.ShadowmageInfiltrator.class)); cards.add(new SetCardInfo("Shelter", 46, Rarity.COMMON, mage.cards.s.Shelter.class)); + cards.add(new SetCardInfo("Shifty Doppelganger", 101, Rarity.RARE, mage.cards.s.ShiftyDoppelganger.class)); cards.add(new SetCardInfo("Shower of Coals", 221, Rarity.UNCOMMON, mage.cards.s.ShowerOfCoals.class)); cards.add(new SetCardInfo("Simplify", 269, Rarity.COMMON, mage.cards.s.Simplify.class)); cards.add(new SetCardInfo("Skeletal Scrying", 161, Rarity.UNCOMMON, mage.cards.s.SkeletalScrying.class)); diff --git a/Mage/src/main/java/mage/abilities/costs/common/ExileSourceCost.java b/Mage/src/main/java/mage/abilities/costs/common/ExileSourceCost.java index 9afd2fbd7b..8678db2a98 100644 --- a/Mage/src/main/java/mage/abilities/costs/common/ExileSourceCost.java +++ b/Mage/src/main/java/mage/abilities/costs/common/ExileSourceCost.java @@ -47,7 +47,7 @@ public class ExileSourceCost extends CostImpl { private boolean toUniqueExileZone; public ExileSourceCost() { - this.text = "Exile {this}"; + this.text = "exile {this}"; } /** @@ -57,7 +57,7 @@ public class ExileSourceCost extends CostImpl { * Deadeye Navigator) can identify the card */ public ExileSourceCost(boolean toUniqueExileZone) { - this.text = "Exile {this}"; + this.text = "exile {this}"; this.toUniqueExileZone = toUniqueExileZone; } @@ -76,6 +76,7 @@ public class ExileSourceCost extends CostImpl { if (toUniqueExileZone) { exileZoneId = CardUtil.getExileZoneId(game, ability.getSourceId(), ability.getSourceObjectZoneChangeCounter()); exileZoneName = sourceObject.getName(); + game.getState().setValue(sourceObject.getId().toString(), ability.getSourceObjectZoneChangeCounter()); } controller.moveCardToExileWithInfo((Card) sourceObject, exileZoneId, exileZoneName, sourceId, game, game.getState().getZone(sourceObject.getId()), true); // 117.11. The actions performed when paying a cost may be modified by effects. From 1ad83253774823f3670a08f60c127c807eea7352 Mon Sep 17 00:00:00 2001 From: Evan Kranzler Date: Fri, 1 Sep 2017 17:59:58 -0400 Subject: [PATCH 2/6] Implemented Angrath's Marauders --- .../src/mage/cards/a/AngrathsMarauders.java | 110 ++++++++++++++++++ Mage.Sets/src/mage/sets/Ixalan.java | 1 + 2 files changed, 111 insertions(+) create mode 100644 Mage.Sets/src/mage/cards/a/AngrathsMarauders.java diff --git a/Mage.Sets/src/mage/cards/a/AngrathsMarauders.java b/Mage.Sets/src/mage/cards/a/AngrathsMarauders.java new file mode 100644 index 0000000000..74e35b6fc4 --- /dev/null +++ b/Mage.Sets/src/mage/cards/a/AngrathsMarauders.java @@ -0,0 +1,110 @@ +/* + * 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.MageInt; +import mage.abilities.Ability; +import mage.abilities.common.SimpleStaticAbility; +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.constants.Zone; +import mage.game.Game; +import mage.game.events.GameEvent; + +/** + * + * @author TheElk801 + */ +public class AngrathsMarauders extends CardImpl { + + public AngrathsMarauders(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{5}{R}{R}"); + + this.subtype.add("Human"); + this.subtype.add("Pirate"); + this.power = new MageInt(4); + this.toughness = new MageInt(4); + + // If a source you control would deal damage to a permanent or player, it deals double that damage to that permanent or player instead. + this.addAbility(new SimpleStaticAbility(Zone.BATTLEFIELD, new AngrathsMaraudersEffect())); + } + + public AngrathsMarauders(final AngrathsMarauders card) { + super(card); + } + + @Override + public AngrathsMarauders copy() { + return new AngrathsMarauders(this); + } +} +class AngrathsMaraudersEffect extends ReplacementEffectImpl { + + public AngrathsMaraudersEffect() { + super(Duration.WhileOnBattlefield, Outcome.Damage); + staticText = "If a source you control would deal damage to a permanent or player, it deals double that damage to that permanent or player instead"; + } + + public AngrathsMaraudersEffect(final AngrathsMaraudersEffect effect) { + super(effect); + } + + @Override + public AngrathsMaraudersEffect copy() { + return new AngrathsMaraudersEffect(this); + } + + @Override + public boolean checksEventType(GameEvent event, Game game) { + switch (event.getType()) { + case DAMAGE_PLAYER: + return true; + case DAMAGE_CREATURE: + return true; + case DAMAGE_PLANESWALKER: + return true; + } + return false; + } + + @Override + public boolean applies(GameEvent event, Ability source, Game game) { + return event.getSourceId().equals(source.getControllerId()); + } + + @Override + public boolean replaceEvent(GameEvent event, Ability source, Game game) { + event.setAmount(2 * event.getAmount()); + return false; + } +} diff --git a/Mage.Sets/src/mage/sets/Ixalan.java b/Mage.Sets/src/mage/sets/Ixalan.java index 32681a83a7..d38ef2db08 100644 --- a/Mage.Sets/src/mage/sets/Ixalan.java +++ b/Mage.Sets/src/mage/sets/Ixalan.java @@ -31,6 +31,7 @@ public class Ixalan extends ExpansionSet { this.numBoosterUncommon = 3; this.numBoosterRare = 1; this.ratioBoosterMythic = 8; + cards.add(new SetCardInfo("Angrath's Marauders", 132, Rarity.RARE, mage.cards.a.AngrathsMarauders.class)); cards.add(new SetCardInfo("Bloodcrazed Paladin", 93, Rarity.RARE, mage.cards.b.BloodcrazedPaladin.class)); cards.add(new SetCardInfo("Burning Sun's Avatar", 135, Rarity.RARE, mage.cards.b.BurningSunsAvatar.class)); cards.add(new SetCardInfo("Captain Lannery Storm", 136, Rarity.RARE, mage.cards.c.CaptainLanneryStorm.class)); From 7c64e487abe36c6afd558368ad37e392ad298a62 Mon Sep 17 00:00:00 2001 From: Evan Kranzler Date: Fri, 1 Sep 2017 18:11:36 -0400 Subject: [PATCH 3/6] Implemented Daring Saboteur --- .../src/mage/cards/d/DaringSaboteur.java | 75 +++++++++++++++++++ Mage.Sets/src/mage/sets/Ixalan.java | 1 + 2 files changed, 76 insertions(+) create mode 100644 Mage.Sets/src/mage/cards/d/DaringSaboteur.java diff --git a/Mage.Sets/src/mage/cards/d/DaringSaboteur.java b/Mage.Sets/src/mage/cards/d/DaringSaboteur.java new file mode 100644 index 0000000000..729b34dfbe --- /dev/null +++ b/Mage.Sets/src/mage/cards/d/DaringSaboteur.java @@ -0,0 +1,75 @@ +/* + * 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.DealsCombatDamageToAPlayerTriggeredAbility; +import mage.abilities.common.SimpleActivatedAbility; +import mage.abilities.costs.mana.ManaCostsImpl; +import mage.abilities.effects.Effect; +import mage.abilities.effects.common.DrawDiscardControllerEffect; +import mage.abilities.effects.common.combat.CantBeBlockedSourceEffect; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.Duration; +import mage.constants.Zone; + +/** + * + * @author TheElk801 + */ +public class DaringSaboteur extends CardImpl { + + public DaringSaboteur(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{1}{U}"); + + this.subtype.add("Human"); + this.subtype.add("Pirate"); + this.power = new MageInt(2); + this.toughness = new MageInt(1); + + // {2}{U}: Daring Saboteur can't be blocked this turn. + this.addAbility(new SimpleActivatedAbility(Zone.BATTLEFIELD, new CantBeBlockedSourceEffect(Duration.EndOfTurn), new ManaCostsImpl("{2}{U}"))); + + // Whenever Daring Saboteur deals combat damage to a player, you may draw a card. If you do, discard a card. + Effect effect = new DrawDiscardControllerEffect(1, 1); + effect.setText("you may draw a card. If you do, discard a card"); + this.addAbility(new DealsCombatDamageToAPlayerTriggeredAbility(effect, true)); + } + + public DaringSaboteur(final DaringSaboteur card) { + super(card); + } + + @Override + public DaringSaboteur copy() { + return new DaringSaboteur(this); + } +} diff --git a/Mage.Sets/src/mage/sets/Ixalan.java b/Mage.Sets/src/mage/sets/Ixalan.java index d38ef2db08..125e3fc524 100644 --- a/Mage.Sets/src/mage/sets/Ixalan.java +++ b/Mage.Sets/src/mage/sets/Ixalan.java @@ -36,6 +36,7 @@ public class Ixalan extends ExpansionSet { cards.add(new SetCardInfo("Burning Sun's Avatar", 135, Rarity.RARE, mage.cards.b.BurningSunsAvatar.class)); cards.add(new SetCardInfo("Captain Lannery Storm", 136, Rarity.RARE, mage.cards.c.CaptainLanneryStorm.class)); cards.add(new SetCardInfo("Carnage Tyrant", 179, Rarity.MYTHIC, mage.cards.c.CarnageTyrant.class)); + cards.add(new SetCardInfo("Daring Saboteur", 49, Rarity.RARE, mage.cards.d.DaringSaboteur.class)); cards.add(new SetCardInfo("Deadeye Tormentor", 98, Rarity.COMMON, mage.cards.d.DeadeyeTormentor.class)); cards.add(new SetCardInfo("Deadeye Tracker", 99, Rarity.RARE, mage.cards.d.DeadeyeTracker.class)); cards.add(new SetCardInfo("Deeproot Champion", 185, Rarity.RARE, mage.cards.d.DeeprootChampion.class)); From 9d6fdbb600f58c23cff14a333afece8930922218 Mon Sep 17 00:00:00 2001 From: Evan Kranzler Date: Fri, 1 Sep 2017 18:20:11 -0400 Subject: [PATCH 4/6] Implemented River's Rebuke, fixed Hurkyl's Recall --- Mage.Sets/src/mage/cards/h/HurkylsRecall.java | 7 +- Mage.Sets/src/mage/cards/r/RiversRebuke.java | 96 +++++++++++++++++++ Mage.Sets/src/mage/sets/Ixalan.java | 1 + 3 files changed, 100 insertions(+), 4 deletions(-) create mode 100644 Mage.Sets/src/mage/cards/r/RiversRebuke.java diff --git a/Mage.Sets/src/mage/cards/h/HurkylsRecall.java b/Mage.Sets/src/mage/cards/h/HurkylsRecall.java index baeab7390e..76785338f7 100644 --- a/Mage.Sets/src/mage/cards/h/HurkylsRecall.java +++ b/Mage.Sets/src/mage/cards/h/HurkylsRecall.java @@ -36,7 +36,7 @@ import mage.constants.CardType; import mage.constants.Outcome; import mage.constants.Zone; import mage.filter.common.FilterArtifactPermanent; -import mage.filter.predicate.permanent.ControllerIdPredicate; +import mage.filter.predicate.other.OwnerIdPredicate; import mage.game.Game; import mage.game.permanent.Permanent; import mage.target.TargetPlayer; @@ -48,8 +48,7 @@ import mage.target.TargetPlayer; public class HurkylsRecall extends CardImpl { public HurkylsRecall(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.INSTANT},"{1}{U}"); - + super(ownerId, setInfo, new CardType[]{CardType.INSTANT}, "{1}{U}"); // Return all artifacts target player owns to his or her hand. this.getSpellAbility().addEffect(new HurkylsRecallReturnToHandEffect()); @@ -81,7 +80,7 @@ class HurkylsRecallReturnToHandEffect extends OneShotEffect { public boolean apply(Game game, Ability source) { if (targetPointer.getFirst(game, source) != null) { FilterArtifactPermanent filter = new FilterArtifactPermanent(); - filter.add(new ControllerIdPredicate(targetPointer.getFirst(game, source))); + filter.add(new OwnerIdPredicate(targetPointer.getFirst(game, source))); for (Permanent permanent : game.getBattlefield().getActivePermanents(filter, source.getControllerId(), source.getSourceId(), game)) { permanent.moveToZone(Zone.HAND, source.getSourceId(), game, true); } diff --git a/Mage.Sets/src/mage/cards/r/RiversRebuke.java b/Mage.Sets/src/mage/cards/r/RiversRebuke.java new file mode 100644 index 0000000000..5ce62f4a54 --- /dev/null +++ b/Mage.Sets/src/mage/cards/r/RiversRebuke.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.r; + +import java.util.UUID; +import mage.abilities.Ability; +import mage.abilities.effects.OneShotEffect; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.Outcome; +import mage.constants.Zone; +import mage.filter.common.FilterNonlandPermanent; +import mage.filter.predicate.permanent.ControllerIdPredicate; +import mage.game.Game; +import mage.game.permanent.Permanent; +import mage.target.TargetPlayer; + +/** + * + * @author TheElk801 + */ +public class RiversRebuke extends CardImpl { + + public RiversRebuke(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.SORCERY}, "{4}{U}{U}"); + + // Return all nonland permanents target player controls to their owner's hand. + this.getSpellAbility().addEffect(new RiversRebukeReturnToHandEffect()); + this.getSpellAbility().addTarget(new TargetPlayer()); + } + + public RiversRebuke(final RiversRebuke card) { + super(card); + } + + @Override + public RiversRebuke copy() { + return new RiversRebuke(this); + } +} + +class RiversRebukeReturnToHandEffect extends OneShotEffect { + + public RiversRebukeReturnToHandEffect() { + super(Outcome.ReturnToHand); + staticText = "Return all nonland permanents target player controls to their owner's hand"; + } + + public RiversRebukeReturnToHandEffect(final RiversRebukeReturnToHandEffect effect) { + super(effect); + } + + @Override + public boolean apply(Game game, Ability source) { + if (targetPointer.getFirst(game, source) != null) { + FilterNonlandPermanent filter = new FilterNonlandPermanent(); + filter.add(new ControllerIdPredicate(targetPointer.getFirst(game, source))); + for (Permanent permanent : game.getBattlefield().getActivePermanents(filter, source.getControllerId(), source.getSourceId(), game)) { + permanent.moveToZone(Zone.HAND, source.getSourceId(), game, true); + } + return true; + } + return false; + } + + @Override + public RiversRebukeReturnToHandEffect copy() { + return new RiversRebukeReturnToHandEffect(this); + } +} diff --git a/Mage.Sets/src/mage/sets/Ixalan.java b/Mage.Sets/src/mage/sets/Ixalan.java index 125e3fc524..9a2b0b71cb 100644 --- a/Mage.Sets/src/mage/sets/Ixalan.java +++ b/Mage.Sets/src/mage/sets/Ixalan.java @@ -53,6 +53,7 @@ public class Ixalan extends ExpansionSet { cards.add(new SetCardInfo("Queen's Bay Soldier", 115, Rarity.COMMON, mage.cards.q.QueensBaySoldier.class)); cards.add(new SetCardInfo("Revel in Riches", 117, Rarity.RARE, mage.cards.r.RevelInRiches.class)); cards.add(new SetCardInfo("Ripjaw Raptor", 203, Rarity.RARE, mage.cards.r.RipjawRaptor.class)); + cards.add(new SetCardInfo("River's Rebuke", 71, Rarity.RARE, mage.cards.r.RiversRebuke.class)); cards.add(new SetCardInfo("Rootbound Crag", 256, Rarity.RARE, mage.cards.r.RootboundCrag.class)); cards.add(new SetCardInfo("Rowdy Crew", 159, Rarity.MYTHIC, mage.cards.r.RowdyCrew.class)); cards.add(new SetCardInfo("Ruin Raider", 118, Rarity.RARE, mage.cards.r.RuinRaider.class)); From 9e11b533c220ed8f65cc3f1bff574aacf499fc86 Mon Sep 17 00:00:00 2001 From: Evan Kranzler Date: Fri, 1 Sep 2017 19:03:10 -0400 Subject: [PATCH 5/6] updated Amonkhet full-art basics (#3452) --- Mage.Sets/src/mage/sets/Amonkhet.java | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/Mage.Sets/src/mage/sets/Amonkhet.java b/Mage.Sets/src/mage/sets/Amonkhet.java index b8ae0a7253..006da239d6 100644 --- a/Mage.Sets/src/mage/sets/Amonkhet.java +++ b/Mage.Sets/src/mage/sets/Amonkhet.java @@ -152,7 +152,7 @@ public class Amonkhet extends ExpansionSet { cards.add(new SetCardInfo("Flameblade Adept", 131, Rarity.UNCOMMON, mage.cards.f.FlamebladeAdept.class)); cards.add(new SetCardInfo("Fling", 132, Rarity.COMMON, mage.cards.f.Fling.class)); cards.add(new SetCardInfo("Floodwaters", 53, Rarity.COMMON, mage.cards.f.Floodwaters.class)); - cards.add(new SetCardInfo("Forest", 254, Rarity.LAND, mage.cards.basiclands.Forest.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Forest", 254, Rarity.LAND, mage.cards.basiclands.Forest.class, FULL_ART_BFZ_VARIOUS)); cards.add(new SetCardInfo("Forest", 267, Rarity.LAND, mage.cards.basiclands.Forest.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Forest", 268, Rarity.LAND, mage.cards.basiclands.Forest.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Forest", 269, Rarity.LAND, mage.cards.basiclands.Forest.class, NON_FULL_USE_VARIOUS)); @@ -202,7 +202,7 @@ public class Amonkhet extends ExpansionSet { cards.add(new SetCardInfo("Initiate's Companion", 174, Rarity.COMMON, mage.cards.i.InitiatesCompanion.class)); cards.add(new SetCardInfo("Insult // Injury", 213, Rarity.RARE, mage.cards.i.InsultInjury.class)); cards.add(new SetCardInfo("Irrigated Farmland", 245, Rarity.RARE, mage.cards.i.IrrigatedFarmland.class)); - cards.add(new SetCardInfo("Island", 251, Rarity.LAND, mage.cards.basiclands.Island.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Island", 251, Rarity.LAND, mage.cards.basiclands.Island.class, FULL_ART_BFZ_VARIOUS)); cards.add(new SetCardInfo("Island", 258, Rarity.LAND, mage.cards.basiclands.Island.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Island", 259, Rarity.LAND, mage.cards.basiclands.Island.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Island", 260, Rarity.LAND, mage.cards.basiclands.Island.class, NON_FULL_USE_VARIOUS)); @@ -227,7 +227,7 @@ public class Amonkhet extends ExpansionSet { cards.add(new SetCardInfo("Miasmic Mummy", 100, Rarity.COMMON, mage.cards.m.MiasmicMummy.class)); cards.add(new SetCardInfo("Mighty Leap", 20, Rarity.COMMON, mage.cards.m.MightyLeap.class)); cards.add(new SetCardInfo("Minotaur Sureshot", 143, Rarity.COMMON, mage.cards.m.MinotaurSureshot.class)); - cards.add(new SetCardInfo("Mountain", 253, Rarity.LAND, mage.cards.basiclands.Mountain.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Mountain", 253, Rarity.LAND, mage.cards.basiclands.Mountain.class, FULL_ART_BFZ_VARIOUS)); cards.add(new SetCardInfo("Mountain", 264, Rarity.LAND, mage.cards.basiclands.Mountain.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Mountain", 265, Rarity.LAND, mage.cards.basiclands.Mountain.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Mountain", 266, Rarity.LAND, mage.cards.basiclands.Mountain.class, NON_FULL_USE_VARIOUS)); @@ -255,7 +255,7 @@ public class Amonkhet extends ExpansionSet { cards.add(new SetCardInfo("Pitiless Vizier", 103, Rarity.COMMON, mage.cards.p.PitilessVizier.class)); cards.add(new SetCardInfo("Plague Belcher", 104, Rarity.RARE, mage.cards.p.PlagueBelcher.class)); cards.add(new SetCardInfo("Pyramid of the Pantheon", 235, Rarity.RARE, mage.cards.p.PyramidOfThePantheon.class)); - cards.add(new SetCardInfo("Plains", 250, Rarity.LAND, mage.cards.basiclands.Plains.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Plains", 250, Rarity.LAND, mage.cards.basiclands.Plains.class, FULL_ART_BFZ_VARIOUS)); cards.add(new SetCardInfo("Plains", 255, Rarity.LAND, mage.cards.basiclands.Plains.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Plains", 256, Rarity.LAND, mage.cards.basiclands.Plains.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Plains", 257, Rarity.LAND, mage.cards.basiclands.Plains.class, NON_FULL_USE_VARIOUS)); @@ -307,7 +307,7 @@ public class Amonkhet extends ExpansionSet { cards.add(new SetCardInfo("Sunscorched Desert", 249, Rarity.COMMON, mage.cards.s.SunscorchedDesert.class)); cards.add(new SetCardInfo("Supernatural Stamina", 111, Rarity.COMMON, mage.cards.s.SupernaturalStamina.class)); cards.add(new SetCardInfo("Supply Caravan", 30, Rarity.COMMON, mage.cards.s.SupplyCaravan.class)); - cards.add(new SetCardInfo("Swamp", 252, Rarity.LAND, mage.cards.basiclands.Swamp.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Swamp", 252, Rarity.LAND, mage.cards.basiclands.Swamp.class, FULL_ART_BFZ_VARIOUS)); cards.add(new SetCardInfo("Swamp", 261, Rarity.LAND, mage.cards.basiclands.Swamp.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Swamp", 262, Rarity.LAND, mage.cards.basiclands.Swamp.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Swamp", 263, Rarity.LAND, mage.cards.basiclands.Swamp.class, NON_FULL_USE_VARIOUS)); From 1f382a7ce79729d3a49406bd3919e58140d1023f Mon Sep 17 00:00:00 2001 From: Evan Kranzler Date: Fri, 1 Sep 2017 21:20:05 -0400 Subject: [PATCH 6/6] Implemented Jace, Cunning Castaway (ultimate won't work correctly until planeswalker rule is removed) various other small changes as well --- .../src/mage/cards/j/JaceCunningCastaway.java | 186 ++++++++++++++++++ .../src/mage/cards/l/LabyrinthGuardian.java | 4 +- Mage.Sets/src/mage/sets/Ixalan.java | 1 + ...tTokenOntoBattlefieldCopySourceEffect.java | 2 +- ...tTokenOntoBattlefieldCopyTargetEffect.java | 10 + .../game/permanent/token/IllusionToken.java | 1 - .../JaceCunningCastawayIllusionToken.java | 95 +++++++++ 7 files changed, 295 insertions(+), 4 deletions(-) create mode 100644 Mage.Sets/src/mage/cards/j/JaceCunningCastaway.java create mode 100644 Mage/src/main/java/mage/game/permanent/token/JaceCunningCastawayIllusionToken.java diff --git a/Mage.Sets/src/mage/cards/j/JaceCunningCastaway.java b/Mage.Sets/src/mage/cards/j/JaceCunningCastaway.java new file mode 100644 index 0000000000..c41c432980 --- /dev/null +++ b/Mage.Sets/src/mage/cards/j/JaceCunningCastaway.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.j; + +import java.util.ArrayList; +import java.util.List; +import java.util.UUID; +import mage.abilities.Ability; +import mage.abilities.DelayedTriggeredAbility; +import mage.abilities.LoyaltyAbility; +import mage.abilities.common.PlanswalkerEntersWithLoyalityCountersAbility; +import mage.abilities.effects.OneShotEffect; +import mage.abilities.effects.common.CreateTokenEffect; +import mage.abilities.effects.common.DrawDiscardControllerEffect; +import mage.abilities.effects.common.PutTokenOntoBattlefieldCopyTargetEffect; +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.game.Game; +import mage.game.events.DamagedPlayerEvent; +import mage.game.events.GameEvent; +import mage.game.permanent.Permanent; +import mage.game.permanent.token.JaceCunningCastawayIllusionToken; +import mage.target.targetpointer.FixedTarget; + +/** + * + * @author TheElk801 + */ +public class JaceCunningCastaway extends CardImpl { + + public JaceCunningCastaway(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.PLANESWALKER}, "{1}{U}{U}"); + + addSuperType(SuperType.LEGENDARY); + this.subtype.add("Jace"); + + this.addAbility(new PlanswalkerEntersWithLoyalityCountersAbility(3)); + + // +1: Whenever one or more creatures you control deal combat damage to a player this turn, draw a card, then discard a card. + this.addAbility(new LoyaltyAbility(new JaceArchitectOfThouStartEffect1(), 1)); + + // -2: Create a 2/2 blue Illusion creature token with "When this creature becomes the target of a spell, sacrifice it." + this.addAbility(new LoyaltyAbility(new CreateTokenEffect(new JaceCunningCastawayIllusionToken()), -2)); + + // -5: Create two tokens that are copies of Jace, Cunning Castaway, except they're not legendary. + this.addAbility(new LoyaltyAbility(new JaceCunningCastawayCopyEffect(), -5)); + } + + public JaceCunningCastaway(final JaceCunningCastaway card) { + super(card); + } + + @Override + public JaceCunningCastaway copy() { + return new JaceCunningCastaway(this); + } +} + +class JaceArchitectOfThouStartEffect1 extends OneShotEffect { + + public JaceArchitectOfThouStartEffect1() { + super(Outcome.DrawCard); + this.staticText = "Whenever one or more creatures you control deal combat damage to a player this turn, draw a card, then discard a card"; + } + + public JaceArchitectOfThouStartEffect1(final JaceArchitectOfThouStartEffect1 effect) { + super(effect); + } + + @Override + public JaceArchitectOfThouStartEffect1 copy() { + return new JaceArchitectOfThouStartEffect1(this); + } + + @Override + public boolean apply(Game game, Ability source) { + DelayedTriggeredAbility delayedAbility = new ThopterSpyNetwoDamageTriggeredAbility(); + game.addDelayedTriggeredAbility(delayedAbility, source); + return true; + } +} + +class ThopterSpyNetwoDamageTriggeredAbility extends DelayedTriggeredAbility { + + List damagedPlayerIds = new ArrayList<>(); + + public ThopterSpyNetwoDamageTriggeredAbility() { + super(new DrawDiscardControllerEffect(1, 1), Duration.EndOfTurn, false); + } + + public ThopterSpyNetwoDamageTriggeredAbility(final ThopterSpyNetwoDamageTriggeredAbility ability) { + super(ability); + } + + @Override + public ThopterSpyNetwoDamageTriggeredAbility copy() { + return new ThopterSpyNetwoDamageTriggeredAbility(this); + } + + @Override + public boolean checkEventType(GameEvent event, Game game) { + return event.getType() == GameEvent.EventType.DAMAGED_PLAYER + || event.getType() == GameEvent.EventType.END_COMBAT_STEP_POST; + } + + @Override + public boolean checkTrigger(GameEvent event, Game game) { + if (event.getType() == GameEvent.EventType.DAMAGED_PLAYER) { + if (((DamagedPlayerEvent) event).isCombatDamage()) { + Permanent creature = game.getPermanent(event.getSourceId()); + if (creature != null && creature.getControllerId().equals(controllerId) + && !damagedPlayerIds.contains(event.getTargetId())) { + damagedPlayerIds.add(event.getTargetId()); + return true; + } + } + } + if (event.getType() == GameEvent.EventType.END_COMBAT_STEP_POST) { + damagedPlayerIds.clear(); + } + return false; + } + + @Override + public String getRule() { + return "Whenever one or more creatures you control deal combat damage to a player this turn, draw a card, then discard a card"; + } +} + +class JaceCunningCastawayCopyEffect extends OneShotEffect { + + JaceCunningCastawayCopyEffect() { + super(Outcome.Benefit); + this.staticText = "Create two tokens that are copies of {this}, except they're not legendary"; + } + + JaceCunningCastawayCopyEffect(final JaceCunningCastawayCopyEffect effect) { + super(effect); + } + + @Override + public JaceCunningCastawayCopyEffect copy() { + return new JaceCunningCastawayCopyEffect(this); + } + + @Override + public boolean apply(Game game, Ability source) { + Permanent permanent = game.getPermanentOrLKIBattlefield(source.getSourceId()); + if (permanent != null) { + PutTokenOntoBattlefieldCopyTargetEffect effect = new PutTokenOntoBattlefieldCopyTargetEffect(source.getControllerId(), null, false, 2); + effect.setTargetPointer(new FixedTarget(source.getSourceId())); + effect.setIsntLegendary(true); + return effect.apply(game, source); + } + return false; + } +} diff --git a/Mage.Sets/src/mage/cards/l/LabyrinthGuardian.java b/Mage.Sets/src/mage/cards/l/LabyrinthGuardian.java index 09a13cb50f..54c6e27df6 100644 --- a/Mage.Sets/src/mage/cards/l/LabyrinthGuardian.java +++ b/Mage.Sets/src/mage/cards/l/LabyrinthGuardian.java @@ -99,7 +99,7 @@ class LabyrinthGuardianTriggeredAbility extends TriggeredAbilityImpl { @Override public boolean checkTrigger(GameEvent event, Game game) { MageObject eventSourceObject = game.getObject(event.getSourceId()); - if (eventSourceObject != null && event.getTargetId().equals(this.getSourceId())&& eventSourceObject instanceof Spell ) { + if (eventSourceObject != null && event.getTargetId().equals(this.getSourceId()) && eventSourceObject instanceof Spell) { getEffects().get(0).setTargetPointer(new FixedTarget(event.getPlayerId())); return true; } @@ -108,7 +108,7 @@ class LabyrinthGuardianTriggeredAbility extends TriggeredAbilityImpl { @Override public String getRule() { - return "Whenever {this} becomes the target of a spell, sacrifice it."; + return "When {this} becomes the target of a spell, sacrifice it."; } } diff --git a/Mage.Sets/src/mage/sets/Ixalan.java b/Mage.Sets/src/mage/sets/Ixalan.java index 9a2b0b71cb..b375fd392f 100644 --- a/Mage.Sets/src/mage/sets/Ixalan.java +++ b/Mage.Sets/src/mage/sets/Ixalan.java @@ -48,6 +48,7 @@ public class Ixalan extends ExpansionSet { cards.add(new SetCardInfo("Gishath, Sun's Avatar", 222, Rarity.MYTHIC, mage.cards.g.GishathSunsAvatar.class)); cards.add(new SetCardInfo("Glacial Fortress", 255, Rarity.RARE, mage.cards.g.GlacialFortress.class)); cards.add(new SetCardInfo("Herald of Secret Streams", 59, Rarity.RARE, mage.cards.h.HeraldOfSecretStreams.class)); + cards.add(new SetCardInfo("Jace, Cunning Castaway", 60, Rarity.MYTHIC, mage.cards.j.JaceCunningCastaway.class)); cards.add(new SetCardInfo("Old-Growth Dryads", 199, Rarity.RARE, mage.cards.o.OldGrowthDryads.class)); cards.add(new SetCardInfo("Prosperous Pirates", 69, Rarity.COMMON, mage.cards.p.ProsperousPirates.class)); cards.add(new SetCardInfo("Queen's Bay Soldier", 115, Rarity.COMMON, mage.cards.q.QueensBaySoldier.class)); diff --git a/Mage/src/main/java/mage/abilities/effects/PutTokenOntoBattlefieldCopySourceEffect.java b/Mage/src/main/java/mage/abilities/effects/PutTokenOntoBattlefieldCopySourceEffect.java index ac09d74151..5fdba542a4 100644 --- a/Mage/src/main/java/mage/abilities/effects/PutTokenOntoBattlefieldCopySourceEffect.java +++ b/Mage/src/main/java/mage/abilities/effects/PutTokenOntoBattlefieldCopySourceEffect.java @@ -21,7 +21,7 @@ public class PutTokenOntoBattlefieldCopySourceEffect extends OneShotEffect { public PutTokenOntoBattlefieldCopySourceEffect(int copies) { super(Outcome.PutCreatureInPlay); this.number = copies; - staticText = "put a token onto the battlefield that's a copy of {this}"; + staticText = "create a token that's a copy of {this}"; } public PutTokenOntoBattlefieldCopySourceEffect(final PutTokenOntoBattlefieldCopySourceEffect effect) { diff --git a/Mage/src/main/java/mage/abilities/effects/common/PutTokenOntoBattlefieldCopyTargetEffect.java b/Mage/src/main/java/mage/abilities/effects/common/PutTokenOntoBattlefieldCopyTargetEffect.java index 337f8c05d4..9c3e4da898 100644 --- a/Mage/src/main/java/mage/abilities/effects/common/PutTokenOntoBattlefieldCopyTargetEffect.java +++ b/Mage/src/main/java/mage/abilities/effects/common/PutTokenOntoBattlefieldCopyTargetEffect.java @@ -41,6 +41,7 @@ import mage.abilities.keyword.HasteAbility; import mage.cards.Card; import mage.constants.CardType; import mage.constants.Outcome; +import mage.constants.SuperType; import mage.game.Game; import mage.game.permanent.Permanent; import mage.game.permanent.token.EmptyToken; @@ -71,6 +72,7 @@ public class PutTokenOntoBattlefieldCopyTargetEffect extends OneShotEffect { private boolean becomesArtifact; private ObjectColor color; private boolean useLKI = false; + private boolean isntLegendary = false; public PutTokenOntoBattlefieldCopyTargetEffect(boolean useLKI) { this(); @@ -156,12 +158,17 @@ public class PutTokenOntoBattlefieldCopyTargetEffect extends OneShotEffect { this.becomesArtifact = effect.becomesArtifact; this.color = effect.color; this.useLKI = effect.useLKI; + this.isntLegendary = effect.isntLegendary; } public void setBecomesArtifact(boolean becomesArtifact) { this.becomesArtifact = becomesArtifact; } + public void setIsntLegendary(boolean isntLegendary) { + this.isntLegendary = isntLegendary; + } + @Override public boolean apply(Game game, Ability source) { UUID targetId; @@ -211,6 +218,9 @@ public class PutTokenOntoBattlefieldCopyTargetEffect extends OneShotEffect { if (becomesArtifact) { token.addCardType(CardType.ARTIFACT); } + if (isntLegendary) { + token.getSuperType().remove(SuperType.LEGENDARY); + } if (additionalCardType != null && !token.getCardType().contains(additionalCardType)) { token.addCardType(additionalCardType); } diff --git a/Mage/src/main/java/mage/game/permanent/token/IllusionToken.java b/Mage/src/main/java/mage/game/permanent/token/IllusionToken.java index f1dce2ff38..280639a1ef 100644 --- a/Mage/src/main/java/mage/game/permanent/token/IllusionToken.java +++ b/Mage/src/main/java/mage/game/permanent/token/IllusionToken.java @@ -25,7 +25,6 @@ * authors and should not be interpreted as representing official policies, either expressed * or implied, of BetaSteward_at_googlemail.com. */ - package mage.game.permanent.token; import mage.constants.CardType; import mage.MageInt; diff --git a/Mage/src/main/java/mage/game/permanent/token/JaceCunningCastawayIllusionToken.java b/Mage/src/main/java/mage/game/permanent/token/JaceCunningCastawayIllusionToken.java new file mode 100644 index 0000000000..fee62abba1 --- /dev/null +++ b/Mage/src/main/java/mage/game/permanent/token/JaceCunningCastawayIllusionToken.java @@ -0,0 +1,95 @@ +/* +* Copyright 2010 BetaSteward_at_googlemail.com. All rights reserved. +* +* Redistribution and use in source and binary forms, with or without modification, are +* permitted provided that the following conditions are met: +* +* 1. Redistributions of source code must retain the above copyright notice, this list of +* conditions and the following disclaimer. +* +* 2. Redistributions in binary form must reproduce the above copyright notice, this list +* of conditions and the following disclaimer in the documentation and/or other materials +* provided with the distribution. +* +* THIS SOFTWARE IS PROVIDED BY BetaSteward_at_googlemail.com AS IS AND ANY EXPRESS OR IMPLIED +* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND +* FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BetaSteward_at_googlemail.com OR +* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR +* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON +* ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING +* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF +* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +* +* The views and conclusions contained in the software and documentation are those of the +* authors and should not be interpreted as representing official policies, either expressed +* or implied, of BetaSteward_at_googlemail.com. + */ +package mage.game.permanent.token; + +import mage.constants.CardType; +import mage.MageInt; +import mage.MageObject; +import mage.abilities.TriggeredAbilityImpl; +import mage.abilities.effects.common.SacrificeSourceEffect; +import mage.constants.Zone; +import mage.game.Game; +import mage.game.events.GameEvent; +import mage.game.stack.Spell; +import mage.target.targetpointer.FixedTarget; + +/** + * + * @author TheElk801 + */ +public class JaceCunningCastawayIllusionToken extends Token { + + public JaceCunningCastawayIllusionToken() { + super("Illusion", "2/2 blue Illusion creature token with \"When this creature becomes the target of a spell, sacrifice it.\""); + cardType.add(CardType.CREATURE); + color.setBlue(true); + + subtype.add("Illusion"); + power = new MageInt(2); + toughness = new MageInt(2); + + this.addAbility(new IllusionTokenTriggeredAbility()); + } +} + +class IllusionTokenTriggeredAbility extends TriggeredAbilityImpl { + + public IllusionTokenTriggeredAbility() { + super(Zone.BATTLEFIELD, new SacrificeSourceEffect(), false); + } + + public IllusionTokenTriggeredAbility(final IllusionTokenTriggeredAbility ability) { + super(ability); + } + + @Override + public IllusionTokenTriggeredAbility copy() { + return new IllusionTokenTriggeredAbility(this); + } + + @Override + public boolean checkEventType(GameEvent event, Game game) { + return event.getType() == GameEvent.EventType.TARGETED; + } + + @Override + public boolean checkTrigger(GameEvent event, Game game) { + MageObject eventSourceObject = game.getObject(event.getSourceId()); + if (eventSourceObject != null && event.getTargetId().equals(this.getSourceId()) && eventSourceObject instanceof Spell) { + getEffects().get(0).setTargetPointer(new FixedTarget(event.getPlayerId())); + return true; + } + return false; + } + + @Override + public String getRule() { + return "When this creature becomes the target of a spell, sacrifice it."; + } + +}