diff --git a/Mage.Sets/src/mage/cards/g/GallowsAtWillowHill.java b/Mage.Sets/src/mage/cards/g/GallowsAtWillowHill.java index 9c8858f8160..cba413e08ec 100644 --- a/Mage.Sets/src/mage/cards/g/GallowsAtWillowHill.java +++ b/Mage.Sets/src/mage/cards/g/GallowsAtWillowHill.java @@ -34,7 +34,7 @@ import mage.abilities.costs.common.TapSourceCost; import mage.abilities.costs.common.TapTargetCost; import mage.abilities.costs.mana.GenericManaCost; import mage.abilities.effects.OneShotEffect; -import mage.abilities.effects.common.CreateTokenEffect; +import mage.abilities.effects.common.CreateTokenTargetEffect; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; @@ -51,6 +51,7 @@ import mage.game.permanent.token.SpiritWhiteToken; import mage.players.Player; import mage.target.common.TargetControlledPermanent; import mage.target.common.TargetCreaturePermanent; +import mage.target.targetpointer.FixedTarget; /** * @author noxx @@ -103,20 +104,17 @@ class GallowsAtWillowHillEffect extends OneShotEffect { @Override public boolean apply(Game game, Ability source) { - int affectedTargets = 0; - if (!targetPointer.getTargets(game, source).isEmpty()) { - for (UUID permanentId : targetPointer.getTargets(game, source)) { - Permanent permanent = game.getPermanent(permanentId); - if (permanent != null) { - Player controller = game.getPlayer(permanent.getControllerId()); - permanent.destroy(source.getSourceId(), game, false); - if (controller != null) { - new CreateTokenEffect(new SpiritWhiteToken()).apply(game, source); - } - affectedTargets++; - } + Permanent permanent = game.getPermanent(this.getTargetPointer().getFirst(game, source)); + if (permanent != null) { + Player controller = game.getPlayer(permanent.getControllerId()); + permanent.destroy(source.getSourceId(), game, false); + if (controller != null) { + CreateTokenTargetEffect effect = new CreateTokenTargetEffect(new SpiritWhiteToken()); + effect.setTargetPointer(new FixedTarget(controller.getId())); + effect.apply(game, source); } + return true; } - return affectedTargets > 0; + return false; } } diff --git a/Mage.Sets/src/mage/cards/g/GarnaTheBloodflame.java b/Mage.Sets/src/mage/cards/g/GarnaTheBloodflame.java new file mode 100644 index 00000000000..6730c09f04a --- /dev/null +++ b/Mage.Sets/src/mage/cards/g/GarnaTheBloodflame.java @@ -0,0 +1,172 @@ +/* + * Copyright 2010 BetaSteward_at_googlemail.com. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are + * permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this list of + * conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, this list + * of conditions and the following disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY BetaSteward_at_googlemail.com ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BetaSteward_at_googlemail.com OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * The views and conclusions contained in the software and documentation are those of the + * authors and should not be interpreted as representing official policies, either expressed + * or implied, of BetaSteward_at_googlemail.com. + */ +package mage.cards.g; + +import java.util.HashSet; +import java.util.Set; +import java.util.UUID; +import mage.MageInt; +import mage.abilities.Ability; +import mage.abilities.common.EntersBattlefieldTriggeredAbility; +import mage.abilities.common.SimpleStaticAbility; +import mage.abilities.effects.OneShotEffect; +import mage.abilities.effects.common.continuous.GainAbilityControlledEffect; +import mage.abilities.keyword.FlashAbility; +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.SubType; +import mage.constants.SuperType; +import mage.constants.WatcherScope; +import mage.constants.Zone; +import mage.filter.StaticFilters; +import mage.game.Game; +import mage.game.events.GameEvent; +import mage.game.events.ZoneChangeEvent; +import mage.players.Player; +import mage.watchers.Watcher; + +/** + * + * @author LevelX2 + */ +public class GarnaTheBloodflame extends CardImpl { + + public GarnaTheBloodflame(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{3}{B}{R}"); + + this.addSuperType(SuperType.LEGENDARY); + this.subtype.add(SubType.HUMAN); + this.subtype.add(SubType.WARRIOR); + this.power = new MageInt(3); + this.toughness = new MageInt(3); + + // Flash + this.addAbility(FlashAbility.getInstance()); + + // When Garna, the Bloodflame enters the battlefield, return to your hand all creature cards in your graveyard that were put there from anywhere this turn. + this.addAbility(new EntersBattlefieldTriggeredAbility(new GarnaTheBloodflameEffect(), false), new GarnaTheBloodflameWatcher()); + this.getSpellAbility().addEffect(new GarnaTheBloodflameEffect()); + this.getSpellAbility().addWatcher(new GarnaTheBloodflameWatcher()); + + // Other creatures you control have haste. + this.addAbility(new SimpleStaticAbility(Zone.BATTLEFIELD, + new GainAbilityControlledEffect(HasteAbility.getInstance(), Duration.WhileOnBattlefield, StaticFilters.FILTER_PERMANENT_CREATURE, true))); + } + + public GarnaTheBloodflame(final GarnaTheBloodflame card) { + super(card); + } + + @Override + public GarnaTheBloodflame copy() { + return new GarnaTheBloodflame(this); + } +} + +class GarnaTheBloodflameEffect extends OneShotEffect { + + GarnaTheBloodflameEffect() { + super(Outcome.Benefit); + staticText = "return to your hand all creature cards in your graveyard that were put there from anywhere this turn"; + } + + GarnaTheBloodflameEffect(final GarnaTheBloodflameEffect effect) { + super(effect); + } + + @Override + public boolean apply(Game game, Ability source) { + Player controller = game.getPlayer(source.getControllerId()); + if (controller != null) { + GarnaTheBloodflameWatcher watcher = (GarnaTheBloodflameWatcher) game.getState().getWatchers().get(GarnaTheBloodflameWatcher.class.getSimpleName()); + if (watcher != null) { + Set toHand = new HashSet<>(); + for (UUID cardId : watcher.getCardsPutToGraveyardThisTurn()) { + Card card = game.getCard(cardId); + if (card != null && card.getOwnerId().equals(source.getControllerId()) && game.getState().getZone(cardId) == Zone.GRAVEYARD) { + toHand.add(card); + } + } + if (!toHand.isEmpty()) { + controller.moveCards(toHand, Zone.HAND, source, game); + } + return true; + } + } + return false; + } + + @Override + public GarnaTheBloodflameEffect copy() { + return new GarnaTheBloodflameEffect(this); + } +} + +class GarnaTheBloodflameWatcher extends Watcher { + + private final Set cards = new HashSet<>(); + + public GarnaTheBloodflameWatcher() { + super(GarnaTheBloodflameWatcher.class.getSimpleName(), WatcherScope.GAME); + } + + public GarnaTheBloodflameWatcher(final GarnaTheBloodflameWatcher watcher) { + super(watcher); + this.cards.addAll(watcher.cards); + } + + @Override + public void watch(GameEvent event, Game game) { + if (event.getType() == GameEvent.EventType.ZONE_CHANGE && ((ZoneChangeEvent) event).getToZone().equals(Zone.GRAVEYARD)) { + Card card = game.getCard(event.getTargetId()); + if (card != null && card.isCreature()) { + cards.add(event.getTargetId()); + } + } + } + + @Override + public GarnaTheBloodflameWatcher copy() { + return new GarnaTheBloodflameWatcher(this); + } + + public Set getCardsPutToGraveyardThisTurn() { + return cards; + } + + @Override + public void reset() { + super.reset(); + cards.clear(); + } +} diff --git a/Mage.Sets/src/mage/cards/g/GoblinBarrage.java b/Mage.Sets/src/mage/cards/g/GoblinBarrage.java new file mode 100644 index 00000000000..5f52d742092 --- /dev/null +++ b/Mage.Sets/src/mage/cards/g/GoblinBarrage.java @@ -0,0 +1,93 @@ +/* + * 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.condition.common.KickedCondition; +import mage.abilities.costs.common.SacrificeTargetCost; +import mage.abilities.decorator.ConditionalOneShotEffect; +import mage.abilities.effects.OneShotEffect; +import mage.abilities.effects.common.DamageTargetEffect; +import mage.abilities.keyword.KickerAbility; +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.Predicates; +import mage.filter.predicate.mageobject.CardTypePredicate; +import mage.filter.predicate.mageobject.SubtypePredicate; +import mage.game.Game; +import mage.target.common.TargetControlledPermanent; +import mage.target.common.TargetCreaturePermanent; +import mage.target.common.TargetPlayerOrPlaneswalker; +import mage.target.targetpointer.SecondTargetPointer; + +/** + * + * @author LevelX2 + */ +public class GoblinBarrage extends CardImpl { + + public GoblinBarrage(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.SORCERY}, "{3}{R}"); + + // Kicker—Sacrifice an artifact or Goblin. + FilterControlledPermanent filter = new FilterControlledPermanent("an artifact or Goblin"); + filter.add(Predicates.or(new CardTypePredicate(CardType.ARTIFACT), new SubtypePredicate(SubType.GOBLIN))); + this.addAbility(new KickerAbility(new SacrificeTargetCost(new TargetControlledPermanent(filter)))); + + // Goblin Barrage deals 4 damage to target creature. If this spell was kicked, it also deals 4 damage to target player or planeswalker. + this.getSpellAbility().addEffect(new DamageTargetEffect(4).setUseOnlyTargetPointer(true)); + this.getSpellAbility().addTarget(new TargetCreaturePermanent()); + + ConditionalOneShotEffect effect = new ConditionalOneShotEffect( + (OneShotEffect) new DamageTargetEffect(4).setUseOnlyTargetPointer(true), KickedCondition.instance, + "If this spell was kicked, it also deals 4 damage to target player or planeswalker."); + effect.setTargetPointer(new SecondTargetPointer()); + this.getSpellAbility().addEffect(effect); + + } + + @Override + public void adjustTargets(Ability ability, Game game) { + if (KickedCondition.instance.apply(game, ability)) { + ability.addTarget(new TargetPlayerOrPlaneswalker()); + } + } + + public GoblinBarrage(final GoblinBarrage card) { + super(card); + } + + @Override + public GoblinBarrage copy() { + return new GoblinBarrage(this); + } +} diff --git a/Mage.Sets/src/mage/cards/n/NavigatorsCompass.java b/Mage.Sets/src/mage/cards/n/NavigatorsCompass.java new file mode 100644 index 00000000000..e4c12cd094c --- /dev/null +++ b/Mage.Sets/src/mage/cards/n/NavigatorsCompass.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.n; + +import mage.MageInt; +import mage.abilities.Ability; +import mage.abilities.common.EntersBattlefieldTriggeredAbility; +import mage.abilities.common.SimpleActivatedAbility; +import mage.abilities.costs.common.TapSourceCost; +import mage.abilities.effects.common.GainLifeEffect; +import mage.abilities.effects.common.continuous.BecomesBasicLandTargetEffect; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.Duration; +import mage.constants.Zone; +import mage.filter.common.FilterControlledLandPermanent; +import mage.target.common.TargetControlledPermanent; +import mage.target.common.TargetLandPermanent; + +import java.util.UUID; + +/** + * + * @author fireshoes + */ +public class NavigatorsCompass extends CardImpl { + + public NavigatorsCompass(UUID ownerId, CardSetInfo setInfo) { + super(ownerId,setInfo,new CardType[]{CardType.ARTIFACT},"{1}"); + + // When Navigator’s Compass enters the battlefield, you gain 3 life. + Ability etbAbility = new EntersBattlefieldTriggeredAbility(new GainLifeEffect(3)); + this.addAbility(etbAbility); + // {tap}: Until end of turn, target land you control becomes the basic land type of your choice in addition to its other types. + Ability ability = new SimpleActivatedAbility(Zone.BATTLEFIELD, new BecomesBasicLandTargetEffect(Duration.EndOfTurn, true, false), new TapSourceCost()); + ability.addTarget(new TargetControlledPermanent(new FilterControlledLandPermanent())); + this.addAbility(ability); + } + + public NavigatorsCompass(final NavigatorsCompass card) { + super(card); + } + + @Override + public NavigatorsCompass copy() { + return new NavigatorsCompass(this); + } +} diff --git a/Mage.Sets/src/mage/cards/p/PhyrexianScriptures.java b/Mage.Sets/src/mage/cards/p/PhyrexianScriptures.java new file mode 100644 index 00000000000..815d5ec30b4 --- /dev/null +++ b/Mage.Sets/src/mage/cards/p/PhyrexianScriptures.java @@ -0,0 +1,98 @@ +/* + * Copyright 2010 BetaSteward_at_googlemail.com. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are + * permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this list of + * conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, this list + * of conditions and the following disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY BetaSteward_at_googlemail.com ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BetaSteward_at_googlemail.com OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * The views and conclusions contained in the software and documentation are those of the + * authors and should not be interpreted as representing official policies, either expressed + * or implied, of BetaSteward_at_googlemail.com. + */ +package mage.cards.p; + +import java.util.UUID; +import mage.abilities.Ability; +import mage.abilities.common.SagaAbility; +import mage.abilities.effects.Effect; +import mage.abilities.effects.common.DestroyAllEffect; +import mage.abilities.effects.common.ExileGraveyardAllPlayersEffect; +import mage.abilities.effects.common.continuous.AddCardTypeTargetEffect; +import mage.abilities.effects.common.counter.AddCountersTargetEffect; +import mage.constants.SubType; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.Duration; +import mage.constants.SagaChapter; +import mage.constants.TargetController; +import mage.counters.CounterType; +import mage.filter.FilterCard; +import mage.filter.common.FilterCreaturePermanent; +import mage.filter.predicate.Predicates; +import mage.filter.predicate.mageobject.CardTypePredicate; +import mage.filter.predicate.other.OwnerPredicate; +import mage.target.common.TargetCreaturePermanent; + +/** + * + * @author TheElk801 + */ +public class PhyrexianScriptures extends CardImpl { + + private static final FilterCreaturePermanent filter = new FilterCreaturePermanent("nonartifact creatures"); + private static final FilterCard filter2 = new FilterCard("opponents' cards"); + + static { + filter.add(Predicates.not(new CardTypePredicate(CardType.ARTIFACT))); + filter2.add(new OwnerPredicate(TargetController.OPPONENT)); + } + + public PhyrexianScriptures(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.ENCHANTMENT}, "{2}{B}{B}"); + + this.subtype.add(SubType.SAGA); + + // (As this Saga enters and after your draw step, add a lore counter. Sacrifice after III.) + SagaAbility sagaAbility = new SagaAbility(this, SagaChapter.CHAPTER_III); + + // I — Put a +1/+1 counter on up to one target creature. That creature becomes an artifact in addition to its other types. + Ability ability = sagaAbility.addChapterEffect(this, SagaChapter.CHAPTER_I, new AddCountersTargetEffect(CounterType.P1P1.createInstance())); + ability.addTarget(new TargetCreaturePermanent(0, 1)); + Effect effect = new AddCardTypeTargetEffect(Duration.WhileOnBattlefield, CardType.ARTIFACT); + effect.setText("That creature becomes an artifact in addition to its other types"); + ability.addEffect(effect); + + // II — Destroy all nonartifact creatures. + sagaAbility.addChapterEffect(this, SagaChapter.CHAPTER_II, new DestroyAllEffect(filter)); + + // III — Exile all cards from all opponents' graveyards. + sagaAbility.addChapterEffect(this, SagaChapter.CHAPTER_III, new ExileGraveyardAllPlayersEffect().setText("exile all cards from all opponents' graveyards")); + this.addAbility(sagaAbility); + } + + public PhyrexianScriptures(final PhyrexianScriptures card) { + super(card); + } + + @Override + public PhyrexianScriptures copy() { + return new PhyrexianScriptures(this); + } +} diff --git a/Mage.Sets/src/mage/cards/r/RadiatingLightning.java b/Mage.Sets/src/mage/cards/r/RadiatingLightning.java new file mode 100644 index 00000000000..0c3a055c577 --- /dev/null +++ b/Mage.Sets/src/mage/cards/r/RadiatingLightning.java @@ -0,0 +1,64 @@ +/* + * Copyright 2010 BetaSteward_at_googlemail.com. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are + * permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this list of + * conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, this list + * of conditions and the following disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY BetaSteward_at_googlemail.com ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BetaSteward_at_googlemail.com OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * The views and conclusions contained in the software and documentation are those of the + * authors and should not be interpreted as representing official policies, either expressed + * or implied, of BetaSteward_at_googlemail.com. + */ +package mage.cards.r; + +import mage.abilities.effects.common.DamageAllControlledTargetEffect; +import mage.abilities.effects.common.DamageTargetEffect; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.filter.common.FilterCreaturePermanent; +import mage.target.TargetPlayer; + +import java.util.UUID; + +/** + * + * @author rscoates + */ +public class RadiatingLightning extends CardImpl { + + public RadiatingLightning(UUID ownerId, CardSetInfo setInfo) { + super(ownerId,setInfo,new CardType[]{CardType.INSTANT},"{3}{R}"); + + + // Radiating Lightning deals 3 damage to target player and 1 damage to each creature that player controls. + this.getSpellAbility().addEffect(new DamageTargetEffect(3)); + this.getSpellAbility().addEffect(new DamageAllControlledTargetEffect(1, new FilterCreaturePermanent()).setText("and 1 damage to each creature that player controls")); + this.getSpellAbility().addTarget(new TargetPlayer()); + } + + public RadiatingLightning(final RadiatingLightning card) { + super(card); + } + + @Override + public RadiatingLightning copy() { + return new RadiatingLightning(this); + } +} diff --git a/Mage.Sets/src/mage/cards/r/RampagingCyclops.java b/Mage.Sets/src/mage/cards/r/RampagingCyclops.java new file mode 100644 index 00000000000..530a076eac7 --- /dev/null +++ b/Mage.Sets/src/mage/cards/r/RampagingCyclops.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.r; + +import java.util.UUID; +import mage.MageInt; +import mage.abilities.Ability; +import mage.abilities.common.SimpleStaticAbility; +import mage.abilities.condition.Condition; +import mage.abilities.decorator.ConditionalContinuousEffect; +import mage.abilities.effects.common.continuous.BoostSourceEffect; +import mage.constants.SubType; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.Duration; +import mage.constants.Zone; +import mage.game.Game; +import mage.game.combat.CombatGroup; +import mage.game.permanent.Permanent; + +/** + * + * @author TheElk801 + */ +public class RampagingCyclops extends CardImpl { + + public RampagingCyclops(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{3}{R}"); + + this.subtype.add(SubType.CYCLOPS); + this.power = new MageInt(4); + this.toughness = new MageInt(4); + + // Rampaging Cyclops gets -2/-0 as long as two or more creatures are blocking it. + this.addAbility(new SimpleStaticAbility(Zone.BATTLEFIELD, + new ConditionalContinuousEffect( + new BoostSourceEffect(-2, 0, Duration.WhileOnBattlefield), + RampagingCyclopsCondition.instance, + "{this} gets -2/-0 as long as two or more creatures are blocking it" + ) + )); + } + + public RampagingCyclops(final RampagingCyclops card) { + super(card); + } + + @Override + public RampagingCyclops copy() { + return new RampagingCyclops(this); + } +} + +enum RampagingCyclopsCondition implements Condition { + instance; + + @Override + public boolean apply(Game game, Ability source) { + Permanent permanent = game.getBattlefield().getPermanent(source.getSourceId()); + if (permanent == null) { + return false; + } + for (CombatGroup group : game.getCombat().getBlockingGroups()) { + if (group.getAttackers().contains(permanent.getId())) { + int blockerCount = 0; + for (UUID blockerId : group.getBlockers()) { + Permanent blocker = game.getPermanent(blockerId); + if (blocker != null) { + blockerCount++; + } + if (blockerCount > 1) { + return true; + } + } + } + } + return false; + } + + @Override + public String toString() { + return "two or more creatures are blocking {this}"; + } +} diff --git a/Mage.Sets/src/mage/cards/r/RelicRunner.java b/Mage.Sets/src/mage/cards/r/RelicRunner.java new file mode 100644 index 00000000000..604ba13edaa --- /dev/null +++ b/Mage.Sets/src/mage/cards/r/RelicRunner.java @@ -0,0 +1,100 @@ +/* + * Copyright 2010 BetaSteward_at_googlemail.com. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are + * permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this list of + * conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, this list + * of conditions and the following disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY BetaSteward_at_googlemail.com ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BetaSteward_at_googlemail.com OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * The views and conclusions contained in the software and documentation are those of the + * authors and should not be interpreted as representing official policies, either expressed + * or implied, of BetaSteward_at_googlemail.com. + */ +package mage.cards.r; + +import java.util.List; +import java.util.UUID; +import mage.MageInt; +import mage.abilities.Ability; +import mage.abilities.common.SimpleStaticAbility; +import mage.abilities.condition.Condition; +import mage.abilities.decorator.ConditionalContinuousEffect; +import mage.abilities.effects.common.continuous.GainAbilitySourceEffect; +import mage.abilities.keyword.LifelinkAbility; +import mage.constants.SubType; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.Duration; +import mage.constants.Zone; +import mage.game.Game; +import mage.game.stack.Spell; +import mage.watchers.common.SpellsCastWatcher; + +/** + * + * @author TheElk801 + */ +public class RelicRunner extends CardImpl { + + public RelicRunner(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{1}{U}"); + + this.subtype.add(SubType.HUMAN); + this.subtype.add(SubType.ROGUE); + this.power = new MageInt(2); + this.toughness = new MageInt(1); + + // Relic Runner can't be blocked if you've cast an historic spell this turn. + this.addAbility(new SimpleStaticAbility(Zone.BATTLEFIELD, + new ConditionalContinuousEffect( + new GainAbilitySourceEffect(LifelinkAbility.getInstance(), Duration.WhileOnBattlefield), + new CastHistoricSpellThisTurnCondition(), + "{this} can't be blocked if you've cast an historic spell this turn" + ) + ), new SpellsCastWatcher()); + } + + public RelicRunner(final RelicRunner card) { + super(card); + } + + @Override + public RelicRunner copy() { + return new RelicRunner(this); + } +} + +class CastHistoricSpellThisTurnCondition implements Condition { + + @Override + public boolean apply(Game game, Ability source) { + SpellsCastWatcher watcher = (SpellsCastWatcher) game.getState().getWatchers().get(SpellsCastWatcher.class.getSimpleName()); + if (watcher != null) { + List spells = watcher.getSpellsCastThisTurn(source.getControllerId()); + if (spells != null) { + for (Spell spell : spells) { + if (!spell.getSourceId().equals(source.getSourceId()) && spell.isHistoric()) { + return true; + } + } + } + } + return false; + } +} diff --git a/Mage.Sets/src/mage/cards/s/SentinelOfThePearlTrident.java b/Mage.Sets/src/mage/cards/s/SentinelOfThePearlTrident.java new file mode 100644 index 00000000000..b86e8438b81 --- /dev/null +++ b/Mage.Sets/src/mage/cards/s/SentinelOfThePearlTrident.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.s; + +import java.util.UUID; +import mage.MageInt; +import mage.abilities.Ability; +import mage.abilities.common.EntersBattlefieldTriggeredAbility; +import mage.abilities.common.delayed.AtTheBeginOfNextEndStepDelayedTriggeredAbility; +import mage.abilities.effects.Effect; +import mage.abilities.effects.OneShotEffect; +import mage.abilities.effects.common.ReturnToBattlefieldUnderOwnerControlTargetEffect; +import mage.constants.SubType; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.Outcome; +import mage.constants.Zone; +import mage.filter.common.FilterControlledPermanent; +import mage.filter.predicate.mageobject.HistoricPredicate; +import mage.game.Game; +import mage.game.permanent.Permanent; +import mage.players.Player; +import mage.target.TargetPermanent; +import mage.target.targetpointer.FixedTarget; + +/** + * + * @author TheElk801 + */ +public class SentinelOfThePearlTrident extends CardImpl { + + private final static FilterControlledPermanent filter = new FilterControlledPermanent("historic permanent you control"); + + static { + filter.add(new HistoricPredicate()); + } + + public SentinelOfThePearlTrident(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{4}{U}"); + + this.subtype.add(SubType.MERFOLK); + this.subtype.add(SubType.SOLDIER); + this.power = new MageInt(3); + this.toughness = new MageInt(3); + + // When Sentinel of the Pearl Trident enters the battlefield, you may exile target historic permanent you control. If you do, return that card to the battlefield under its owner's control at the beginning of the next end step. + Ability etbAbility = new EntersBattlefieldTriggeredAbility(new SentinelOfThePearlTridentEffect(), true); + etbAbility.addTarget(new TargetPermanent(filter)); + this.addAbility(etbAbility); + } + + public SentinelOfThePearlTrident(final SentinelOfThePearlTrident card) { + super(card); + } + + @Override + public SentinelOfThePearlTrident copy() { + return new SentinelOfThePearlTrident(this); + } +} + +class SentinelOfThePearlTridentEffect extends OneShotEffect { + + private static final String effectText = "exile target historic permanent you control. If you do, return that card to the battlefield under its owner's control at the beginning of the next end step"; + + SentinelOfThePearlTridentEffect() { + super(Outcome.Detriment); + staticText = effectText; + } + + SentinelOfThePearlTridentEffect(SentinelOfThePearlTridentEffect effect) { + super(effect); + } + + @Override + public boolean apply(Game game, Ability source) { + Player controller = game.getPlayer(source.getControllerId()); + if (controller != null) { + Permanent permanent = game.getPermanent(source.getFirstTarget()); + if (permanent != null) { + int zcc = permanent.getZoneChangeCounter(game); + controller.moveCards(permanent, Zone.EXILED, source, game); + //create delayed triggered ability + Effect effect = new ReturnToBattlefieldUnderOwnerControlTargetEffect(); + effect.setTargetPointer(new FixedTarget(permanent.getId(), zcc + 1)); + AtTheBeginOfNextEndStepDelayedTriggeredAbility delayedAbility = new AtTheBeginOfNextEndStepDelayedTriggeredAbility(effect); + game.addDelayedTriggeredAbility(delayedAbility, source); + } + return true; + } + return false; + } + + @Override + public SentinelOfThePearlTridentEffect copy() { + return new SentinelOfThePearlTridentEffect(this); + } + +} diff --git a/Mage.Sets/src/mage/cards/s/SettleTheScore.java b/Mage.Sets/src/mage/cards/s/SettleTheScore.java new file mode 100644 index 00000000000..f5c383bf851 --- /dev/null +++ b/Mage.Sets/src/mage/cards/s/SettleTheScore.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.s; + +import java.util.UUID; +import mage.abilities.Ability; +import mage.abilities.effects.OneShotEffect; +import mage.abilities.effects.common.ExileTargetEffect; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.Outcome; +import mage.counters.CounterType; +import mage.filter.common.FilterControlledPermanent; +import mage.filter.predicate.mageobject.CardTypePredicate; +import mage.game.Game; +import mage.game.permanent.Permanent; +import mage.players.Player; +import mage.target.TargetPermanent; +import mage.target.common.TargetCreaturePermanent; + +/** + * + * @author TheElk801 + */ +public class SettleTheScore extends CardImpl { + + public SettleTheScore(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.SORCERY}, "{2}{B}{B}"); + + // Exile target creature. Put two loyalty counters on a planeswalker you control. + this.getSpellAbility().addEffect(new ExileTargetEffect()); + this.getSpellAbility().addTarget(new TargetCreaturePermanent()); + this.getSpellAbility().addEffect(new SettleTheScoreEffect()); + } + + public SettleTheScore(final SettleTheScore card) { + super(card); + } + + @Override + public SettleTheScore copy() { + return new SettleTheScore(this); + } +} + +class SettleTheScoreEffect extends OneShotEffect { + + private static final FilterControlledPermanent filter = new FilterControlledPermanent("planeswalker you control"); + + static { + filter.add(new CardTypePredicate(CardType.PLANESWALKER)); + } + + public SettleTheScoreEffect() { + super(Outcome.Benefit); + this.staticText = "Put two loyalty counters on a planeswalker you control"; + } + + public SettleTheScoreEffect(final SettleTheScoreEffect effect) { + super(effect); + } + + @Override + public SettleTheScoreEffect copy() { + return new SettleTheScoreEffect(this); + } + + @Override + public boolean apply(Game game, Ability source) { + Player player = game.getPlayer(source.getControllerId()); + if (player == null) { + return false; + } + TargetPermanent target = new TargetPermanent(filter); + if (target.choose(Outcome.Benefit, player.getId(), source.getSourceId(), game)) { + Permanent permanent = game.getPermanent(target.getFirstTarget()); + if (permanent != null) { + permanent.addCounters(CounterType.LOYALTY.createInstance(2), source, game); + } + } + return true; + } +} diff --git a/Mage.Sets/src/mage/cards/s/SlinnVodaTheRisingDeep.java b/Mage.Sets/src/mage/cards/s/SlinnVodaTheRisingDeep.java new file mode 100644 index 00000000000..8511d1173bb --- /dev/null +++ b/Mage.Sets/src/mage/cards/s/SlinnVodaTheRisingDeep.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 mage.cards.s; + +import java.util.UUID; +import mage.MageInt; +import mage.abilities.common.EntersBattlefieldTriggeredAbility; +import mage.abilities.condition.common.KickedCondition; +import mage.abilities.decorator.ConditionalTriggeredAbility; +import mage.abilities.effects.common.ReturnToHandFromBattlefieldAllEffect; +import mage.abilities.keyword.KickerAbility; +import mage.constants.SubType; +import mage.constants.SuperType; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.filter.common.FilterCreaturePermanent; +import mage.filter.predicate.Predicates; +import mage.filter.predicate.mageobject.SubtypePredicate; + +/** + * + * @author TheElk801 + */ +public class SlinnVodaTheRisingDeep extends CardImpl { + + private static final FilterCreaturePermanent filter = new FilterCreaturePermanent(); + + static { + filter.add(Predicates.not( + Predicates.or( + new SubtypePredicate(SubType.KRAKEN), + new SubtypePredicate(SubType.LEVIATHAN), + new SubtypePredicate(SubType.OCTOPUS), + new SubtypePredicate(SubType.MERFOLK), + new SubtypePredicate(SubType.SERPENT)) + )); + } + + public SlinnVodaTheRisingDeep(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{6}{U}{U}"); + + this.addSuperType(SuperType.LEGENDARY); + this.subtype.add(SubType.LEVIATHAN); + this.power = new MageInt(8); + this.toughness = new MageInt(8); + + // Kicker {1}{U} + this.addAbility(new KickerAbility("{1}{U}")); + + // When Slinn Voda, the Rising Deep enters the battlefield, if it was kicked, return all creatures to their owners' hands except for Merfolk, Krakens, Leviathans, Octopuses, and Serpents. + this.addAbility(new ConditionalTriggeredAbility( + new EntersBattlefieldTriggeredAbility(new ReturnToHandFromBattlefieldAllEffect(filter)), + KickedCondition.instance, + "when {this} enters the battlefield, if it was kicked, " + + "return all creatures to their owners' hands except for " + + "Merfolk, Krakens, Leviathans, Octopuses, and Serpents" + )); + } + + public SlinnVodaTheRisingDeep(final SlinnVodaTheRisingDeep card) { + super(card); + } + + @Override + public SlinnVodaTheRisingDeep copy() { + return new SlinnVodaTheRisingDeep(this); + } +} diff --git a/Mage.Sets/src/mage/cards/s/SongOfFreyalise.java b/Mage.Sets/src/mage/cards/s/SongOfFreyalise.java new file mode 100644 index 00000000000..fc2e9024c4a --- /dev/null +++ b/Mage.Sets/src/mage/cards/s/SongOfFreyalise.java @@ -0,0 +1,88 @@ +/* + * Copyright 2010 BetaSteward_at_googlemail.com. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are + * permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this list of + * conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, this list + * of conditions and the following disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY BetaSteward_at_googlemail.com ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BetaSteward_at_googlemail.com OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * The views and conclusions contained in the software and documentation are those of the + * authors and should not be interpreted as representing official policies, either expressed + * or implied, of BetaSteward_at_googlemail.com. + */ +package mage.cards.s; + +import java.util.UUID; +import mage.abilities.Ability; +import mage.abilities.common.SagaAbility; +import mage.abilities.effects.common.continuous.GainAbilityControlledEffect; +import mage.abilities.effects.common.counter.AddCountersAllEffect; +import mage.abilities.keyword.IndestructibleAbility; +import mage.abilities.keyword.TrampleAbility; +import mage.abilities.keyword.VigilanceAbility; +import mage.abilities.mana.AnyColorManaAbility; +import mage.constants.SubType; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.Duration; +import mage.constants.SagaChapter; +import mage.counters.CounterType; +import mage.filter.common.FilterControlledCreaturePermanent; + +/** + * + * @author TheElk801 + */ +public class SongOfFreyalise extends CardImpl { + + private static final FilterControlledCreaturePermanent filter = new FilterControlledCreaturePermanent("creatures you control"); + + public SongOfFreyalise(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.ENCHANTMENT}, "{1}{G}"); + + this.subtype.add(SubType.SAGA); + + // (As this Saga enters and after your draw step, add a lore counter. Sacrifice after III.) + SagaAbility sagaAbility = new SagaAbility(this, SagaChapter.CHAPTER_III); + + // I, II — Until your next turn, creatures you control gain "T: Add one mana of any color." + sagaAbility.addChapterEffect(this, SagaChapter.CHAPTER_I, SagaChapter.CHAPTER_II, + new GainAbilityControlledEffect(new AnyColorManaAbility(), Duration.UntilYourNextTurn, filter) + ); + + // III — Put a +1/+1 counter on each creature you control. Those creatures gain vigilance, trample, and indestructible until end of turn. + Ability ability = sagaAbility.addChapterEffect(this, SagaChapter.CHAPTER_III, new AddCountersAllEffect(CounterType.P1P1.createInstance(), filter)); + ability.addEffect(new GainAbilityControlledEffect(VigilanceAbility.getInstance(), Duration.EndOfTurn, filter) + .setText("Those creatures gain vigilance,")); + ability.addEffect(new GainAbilityControlledEffect(TrampleAbility.getInstance(), Duration.EndOfTurn, filter) + .setText("trample,")); + ability.addEffect(new GainAbilityControlledEffect(IndestructibleAbility.getInstance(), Duration.EndOfTurn, filter) + .setText("and indestructible until end of turn")); + this.addAbility(sagaAbility); + } + + public SongOfFreyalise(final SongOfFreyalise card) { + super(card); + } + + @Override + public SongOfFreyalise copy() { + return new SongOfFreyalise(this); + } +} diff --git a/Mage.Sets/src/mage/cards/s/SylvanAwakening.java b/Mage.Sets/src/mage/cards/s/SylvanAwakening.java new file mode 100644 index 00000000000..fdd30fdd2d4 --- /dev/null +++ b/Mage.Sets/src/mage/cards/s/SylvanAwakening.java @@ -0,0 +1,93 @@ +/* + * 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.effects.common.continuous.BecomesCreatureAllEffect; +import mage.abilities.keyword.HasteAbility; +import mage.abilities.keyword.IndestructibleAbility; +import mage.abilities.keyword.ReachAbility; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.Duration; +import mage.constants.SubType; +import mage.filter.common.FilterControlledLandPermanent; +import mage.game.permanent.token.TokenImpl; + +/** + * + * @author TheElk801 + */ +public class SylvanAwakening extends CardImpl { + + public SylvanAwakening(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.SORCERY}, "{2}{G}"); + + // Until your next turn, all lands you control become 2/2 Elemental creatures with reach, indestructible, and haste. They're still lands. + this.getSpellAbility().addEffect(new BecomesCreatureAllEffect( + new SylvanAwakeningToken(), + "lands", + new FilterControlledLandPermanent("all lands you control"), + Duration.UntilYourNextTurn) + ); + } + + public SylvanAwakening(final SylvanAwakening card) { + super(card); + } + + @Override + public SylvanAwakening copy() { + return new SylvanAwakening(this); + } +} + +class SylvanAwakeningToken extends TokenImpl { + + public SylvanAwakeningToken() { + super("", "2/2 Elemental creatures with reach, indestructible, and haste"); + cardType.add(CardType.CREATURE); + this.subtype.add(SubType.ELEMENTAL); + power = new MageInt(2); + toughness = new MageInt(2); + this.addAbility(ReachAbility.getInstance()); + this.addAbility(IndestructibleAbility.getInstance()); + this.addAbility(HasteAbility.getInstance()); + } + + public SylvanAwakeningToken(final SylvanAwakeningToken token) { + super(token); + } + + public SylvanAwakeningToken copy() { + return new SylvanAwakeningToken(this); + } + +} diff --git a/Mage.Sets/src/mage/cards/t/TheMendingOfDominaria.java b/Mage.Sets/src/mage/cards/t/TheMendingOfDominaria.java new file mode 100644 index 00000000000..cd0f5faade7 --- /dev/null +++ b/Mage.Sets/src/mage/cards/t/TheMendingOfDominaria.java @@ -0,0 +1,149 @@ +/* + * 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.SagaAbility; +import mage.abilities.effects.OneShotEffect; +import mage.abilities.effects.common.PutTopCardOfLibraryIntoGraveControllerEffect; +import mage.cards.Card; +import mage.constants.SubType; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.Outcome; +import mage.constants.SagaChapter; +import mage.constants.Zone; +import mage.filter.StaticFilters; +import mage.filter.common.FilterLandCard; +import mage.game.Game; +import mage.players.Player; +import mage.target.common.TargetCardInYourGraveyard; + +/** + * + * @author TheElk801 + */ +public class TheMendingOfDominaria extends CardImpl { + + public TheMendingOfDominaria(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.ENCHANTMENT}, "{3}{G}{G}"); + + this.subtype.add(SubType.SAGA); + + // (As this Saga enters and after your draw step, add a lore counter. Sacrifice after III.) + SagaAbility sagaAbility = new SagaAbility(this, SagaChapter.CHAPTER_III); + + // I, II — Put the top two cards of your library into your graveyard, then you may return a creature card from your graveyard to your hand. + sagaAbility.addChapterEffect(this, SagaChapter.CHAPTER_I, SagaChapter.CHAPTER_II, new TheMendingOfDominariaFirstEffect()); + + // III — Return all land cards from your graveyard to the battlefield, then shuffle your graveyard into your library. + sagaAbility.addChapterEffect(this, SagaChapter.CHAPTER_III, new TheMendingOfDominariaSecondEffect()); + this.addAbility(sagaAbility); + } + + public TheMendingOfDominaria(final TheMendingOfDominaria card) { + super(card); + } + + @Override + public TheMendingOfDominaria copy() { + return new TheMendingOfDominaria(this); + } +} + +class TheMendingOfDominariaFirstEffect extends OneShotEffect { + + public TheMendingOfDominariaFirstEffect() { + super(Outcome.ReturnToHand); + this.staticText = "Put the top two cards of your library into your graveyard, then you may return a creature card from your graveyard to your hand"; + } + + public TheMendingOfDominariaFirstEffect(final TheMendingOfDominariaFirstEffect effect) { + super(effect); + } + + @Override + public TheMendingOfDominariaFirstEffect copy() { + return new TheMendingOfDominariaFirstEffect(this); + } + + @Override + public boolean apply(Game game, Ability source) { + Player controller = game.getPlayer(source.getControllerId()); + if (controller == null) { + return false; + } + new PutTopCardOfLibraryIntoGraveControllerEffect(2).apply(game, source); + TargetCardInYourGraveyard target = new TargetCardInYourGraveyard(StaticFilters.FILTER_CARD_CREATURE_YOUR_GRAVEYARD); + target.setNotTarget(true); + if (target.canChoose(source.getSourceId(), source.getControllerId(), game) + && controller.chooseUse(outcome, "Return a creature card from your graveyard to hand?", source, game) + && controller.choose(Outcome.ReturnToHand, target, source.getSourceId(), game)) { + Card card = game.getCard(target.getFirstTarget()); + if (card != null) { + controller.moveCards(card, Zone.HAND, source, game); + } + } + return true; + } +} + +class TheMendingOfDominariaSecondEffect extends OneShotEffect { + + TheMendingOfDominariaSecondEffect() { + super(Outcome.PutCardInPlay); + this.staticText = "Return all land cards from your graveyard to the battlefield, then shuffle your graveyard into your library"; + } + + TheMendingOfDominariaSecondEffect(final TheMendingOfDominariaSecondEffect effect) { + super(effect); + } + + @Override + public TheMendingOfDominariaSecondEffect copy() { + return new TheMendingOfDominariaSecondEffect(this); + } + + @Override + public boolean apply(Game game, Ability source) { + Player controller = game.getPlayer(source.getControllerId()); + if (controller != null) { + controller.moveCards( + controller.getGraveyard().getCards(new FilterLandCard(), source.getSourceId(), source.getControllerId(), game), + Zone.BATTLEFIELD, source, game, false, false, false, null + ); + for (Card card : controller.getGraveyard().getCards(game)) { + controller.moveCardToLibraryWithInfo(card, source.getSourceId(), game, Zone.GRAVEYARD, true, true); + } + controller.shuffleLibrary(source, game); + } + return false; + } +} diff --git a/Mage.Sets/src/mage/cards/t/TimeOfIce.java b/Mage.Sets/src/mage/cards/t/TimeOfIce.java new file mode 100644 index 00000000000..6b0fffbe053 --- /dev/null +++ b/Mage.Sets/src/mage/cards/t/TimeOfIce.java @@ -0,0 +1,198 @@ +/* + * 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.MageObject; +import mage.abilities.Ability; +import mage.abilities.common.SagaAbility; +import mage.abilities.effects.ContinuousRuleModifyingEffectImpl; +import mage.abilities.effects.common.ReturnToHandFromBattlefieldAllEffect; +import mage.abilities.effects.common.TapTargetEffect; +import mage.constants.SubType; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.Duration; +import mage.constants.Outcome; +import mage.constants.PhaseStep; +import mage.constants.SagaChapter; +import mage.constants.WatcherScope; +import mage.constants.Zone; +import static mage.filter.StaticFilters.FILTER_OPPONENTS_PERMANENT_CREATURE; +import mage.filter.common.FilterCreaturePermanent; +import mage.filter.predicate.permanent.TappedPredicate; +import mage.game.Game; +import mage.game.events.GameEvent; +import mage.game.events.ZoneChangeEvent; +import mage.game.permanent.Permanent; +import mage.target.common.TargetCreaturePermanent; +import mage.watchers.Watcher; + +/** + * + * @author TheElk801 + */ +public class TimeOfIce extends CardImpl { + + private static final FilterCreaturePermanent filter = new FilterCreaturePermanent("tapped creatures"); + + static { + filter.add(new TappedPredicate()); + } + + public TimeOfIce(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.ENCHANTMENT}, "{3}{U}"); + + this.subtype.add(SubType.SAGA); + + // (As this Saga enters and after your draw step, add a lore counter. Sacrifice after III.) + SagaAbility sagaAbility = new SagaAbility(this, SagaChapter.CHAPTER_III); + + // I, II — Tap target creature an opponent controls. It doesn't untap during its controller's untap step for as long as you control Time of Ice. + Ability ability = sagaAbility.addChapterEffect(this, SagaChapter.CHAPTER_I, SagaChapter.CHAPTER_II, new TapTargetEffect()); + ability.addEffect(new TimeOfIceEffect()); + ability.addTarget(new TargetCreaturePermanent(FILTER_OPPONENTS_PERMANENT_CREATURE)); + + // III — Return all tapped creatures to their owners' hands. + sagaAbility.addChapterEffect(this, SagaChapter.CHAPTER_III, new ReturnToHandFromBattlefieldAllEffect(filter)); + this.addAbility(sagaAbility, new TimeOfIceWatcher()); + } + + public TimeOfIce(final TimeOfIce card) { + super(card); + } + + @Override + public TimeOfIce copy() { + return new TimeOfIce(this); + } +} + +class TimeOfIceEffect extends ContinuousRuleModifyingEffectImpl { + + public TimeOfIceEffect() { + super(Duration.Custom, Outcome.Detriment, false, false); + this.staticText = "That creature doesn't untap during its controller's untap step for as long as you control {this}"; + } + + public TimeOfIceEffect(final TimeOfIceEffect effect) { + super(effect); + } + + @Override + public TimeOfIceEffect copy() { + return new TimeOfIceEffect(this); + } + + @Override + public boolean checksEventType(GameEvent event, Game game) { + return event.getType() == GameEvent.EventType.UNTAP || event.getType() == GameEvent.EventType.ZONE_CHANGE || event.getType() == GameEvent.EventType.LOST_CONTROL; + } + + @Override + public boolean applies(GameEvent event, Ability source, Game game) { + // Source must be on the battlefield (it's neccessary to check here because if as response to the enter + // the battlefield triggered ability the source dies (or will be exiled), then the ZONE_CHANGE or LOST_CONTROL + // event will happen before this effect is applied ever) + MageObject sourceObject = source.getSourceObjectIfItStillExists(game); + if (!(sourceObject instanceof Permanent) || !((Permanent) sourceObject).getControllerId().equals(source.getControllerId())) { + discard(); + return false; + } + switch (event.getType()) { + case ZONE_CHANGE: + // end effect if source does a zone move + if (event.getTargetId().equals(source.getSourceId())) { + ZoneChangeEvent zEvent = (ZoneChangeEvent) event; + if (zEvent.getFromZone() == Zone.BATTLEFIELD) { + discard(); + return false; + } + } + break; + case UNTAP: + // prevent to untap the target creature + if (game.getTurn().getStepType() == PhaseStep.UNTAP && event.getTargetId().equals(targetPointer.getFirst(game, source))) { + Permanent targetCreature = game.getPermanent(targetPointer.getFirst(game, source)); + if (targetCreature != null) { + return targetCreature.getControllerId().equals(game.getActivePlayerId()); + } else { + discard(); + return false; + } + } + break; + case LOST_CONTROL: + // end effect if source control is changed + if (event.getTargetId().equals(source.getSourceId())) { + discard(); + return false; + } + break; + } + return false; + } +} + +class TimeOfIceWatcher extends Watcher { + + TimeOfIceWatcher() { + super("ControlLost", WatcherScope.CARD); + } + + TimeOfIceWatcher(TimeOfIceWatcher watcher) { + super(watcher); + } + + @Override + public void watch(GameEvent event, Game game) { + if (event.getType() == GameEvent.EventType.LOST_CONTROL && event.getPlayerId().equals(controllerId) && event.getTargetId().equals(sourceId)) { + condition = true; + game.replaceEvent(event); + return; + } + if (event.getType() == GameEvent.EventType.ZONE_CHANGE && event.getTargetId().equals(sourceId)) { + ZoneChangeEvent zEvent = (ZoneChangeEvent) event; + if (zEvent.getFromZone() == Zone.BATTLEFIELD) { + condition = true; + game.replaceEvent(event); + } + } + } + + @Override + public void reset() { + //don't reset condition each turn - only when this leaves the battlefield + } + + @Override + public TimeOfIceWatcher copy() { + return new TimeOfIceWatcher(this); + } +} diff --git a/Mage.Sets/src/mage/cards/v/ValdukKeeperOfTheFlame.java b/Mage.Sets/src/mage/cards/v/ValdukKeeperOfTheFlame.java new file mode 100644 index 00000000000..bf7d338fe6a --- /dev/null +++ b/Mage.Sets/src/mage/cards/v/ValdukKeeperOfTheFlame.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.v; + +import java.util.UUID; +import mage.MageInt; +import mage.abilities.Ability; +import mage.abilities.common.BeginningOfCombatTriggeredAbility; +import mage.abilities.dynamicvalue.common.AuraAttachedCount; +import mage.abilities.dynamicvalue.common.EquipmentAttachedCount; +import mage.abilities.effects.OneShotEffect; +import mage.abilities.effects.common.CreateTokenEffect; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.Outcome; +import mage.constants.SubType; +import mage.constants.SuperType; +import mage.constants.TargetController; +import mage.game.Game; +import mage.game.permanent.Permanent; +import mage.game.permanent.token.ValdukElementalToken; + +/** + * + * @author spjspj + */ +public class ValdukKeeperOfTheFlame extends CardImpl { + + public ValdukKeeperOfTheFlame(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{2}{R}"); + + addSuperType(SuperType.LEGENDARY); + this.subtype.add(SubType.HUMAN); + this.subtype.add(SubType.SHAMAN); + this.power = new MageInt(3); + this.toughness = new MageInt(2); + + // At the beginning of combat on your turn, for each Aura and Equipment attached to Valduk, Keeper of the Flame, create a 3/1 red Elemental creature token with trample and haste. Exile those tokens at the beginning of the next end step. + this.addAbility(new BeginningOfCombatTriggeredAbility(new ValdukKeeperOfTheFlameEffect(), TargetController.YOU, false)); + } + + public ValdukKeeperOfTheFlame(final ValdukKeeperOfTheFlame card) { + super(card); + } + + @Override + public ValdukKeeperOfTheFlame copy() { + return new ValdukKeeperOfTheFlame(this); + } +} + +class ValdukKeeperOfTheFlameEffect extends OneShotEffect { + + public ValdukKeeperOfTheFlameEffect() { + super(Outcome.PutCreatureInPlay); + this.staticText = "for each Aura and Equipment attached to {this}, create a 3/1 red Elemental creature token with trample and haste. Exile those tokens at the beginning of the next end step"; + } + + public ValdukKeeperOfTheFlameEffect(final ValdukKeeperOfTheFlameEffect effect) { + super(effect); + } + + @Override + public ValdukKeeperOfTheFlameEffect copy() { + return new ValdukKeeperOfTheFlameEffect(this); + } + + @Override + public boolean apply(Game game, Ability source) { + Permanent sourcePermanent = game.getPermanent(source.getSourceId()); + if (sourcePermanent != null) { + EquipmentAttachedCount eamount = new EquipmentAttachedCount(); + int value = eamount.calculate(game, source, this); + AuraAttachedCount aamount = new AuraAttachedCount(); + value += aamount.calculate(game, source, this); + CreateTokenEffect effect = new CreateTokenEffect(new ValdukElementalToken(), value); + if (effect.apply(game, source)) { + effect.exileTokensCreatedAtNextEndStep(game, source); + return true; + } + } + return false; + } +} diff --git a/Mage.Sets/src/mage/cards/w/WeightOfMemory.java b/Mage.Sets/src/mage/cards/w/WeightOfMemory.java new file mode 100644 index 00000000000..6a4b409f652 --- /dev/null +++ b/Mage.Sets/src/mage/cards/w/WeightOfMemory.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.w; + +import mage.abilities.effects.common.DrawCardSourceControllerEffect; +import mage.abilities.effects.common.PutLibraryIntoGraveTargetEffect; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.target.TargetPlayer; + +import java.util.UUID; + +/** + * + * @author rscoates + */ +public class WeightOfMemory extends CardImpl { + + public WeightOfMemory(UUID ownerId, CardSetInfo setInfo) { + super(ownerId,setInfo,new CardType[]{CardType.SORCERY},"{3}{U}{U}"); + + // Draw three cards. + this.getSpellAbility().addEffect(new DrawCardSourceControllerEffect(3)); + // Target player puts the top three cards of their library into their graveyard. + this.getSpellAbility().addTarget(new TargetPlayer()); + this.getSpellAbility().addEffect(new PutLibraryIntoGraveTargetEffect(3)); + } + + public WeightOfMemory(final WeightOfMemory card) { + super(card); + } + + @Override + public WeightOfMemory copy() { + return new WeightOfMemory(this); + } +} diff --git a/Mage.Sets/src/mage/sets/Dominaria.java b/Mage.Sets/src/mage/sets/Dominaria.java index afc14a2f501..c1853e0a939 100644 --- a/Mage.Sets/src/mage/sets/Dominaria.java +++ b/Mage.Sets/src/mage/sets/Dominaria.java @@ -124,12 +124,14 @@ public class Dominaria extends ExpansionSet { cards.add(new SetCardInfo("Fungal Plots", 160, Rarity.UNCOMMON, mage.cards.f.FungalPlots.class)); cards.add(new SetCardInfo("Gaea's Blessing", 161, Rarity.UNCOMMON, mage.cards.g.GaeasBlessing.class)); cards.add(new SetCardInfo("Gaea's Protector", 162, Rarity.COMMON, mage.cards.g.GaeasProtector.class)); + cards.add(new SetCardInfo("Garna, the Bloodflame", 194, Rarity.UNCOMMON, mage.cards.g.GarnaTheBloodflame.class)); cards.add(new SetCardInfo("Ghitu Chronicler", 125, Rarity.COMMON, mage.cards.g.GhituChronicler.class)); cards.add(new SetCardInfo("Ghitu Journeymage", 126, Rarity.COMMON, mage.cards.g.GhituJourneymage.class)); cards.add(new SetCardInfo("Ghitu Lavarunner", 127, Rarity.COMMON, mage.cards.g.GhituLavarunner.class)); cards.add(new SetCardInfo("Gideon's Reproach", 19, Rarity.COMMON, mage.cards.g.GideonsReproach.class)); cards.add(new SetCardInfo("Gift of Growth", 163, Rarity.COMMON, mage.cards.g.GiftofGrowth.class)); cards.add(new SetCardInfo("Gilded Lotus", 215, Rarity.RARE, mage.cards.g.GildedLotus.class)); + cards.add(new SetCardInfo("Goblin Barrage", 128, Rarity.UNCOMMON, mage.cards.g.GoblinBarrage.class)); cards.add(new SetCardInfo("Goblin Chainwhirler", 129, Rarity.RARE, mage.cards.g.GoblinChainwhirler.class)); cards.add(new SetCardInfo("Goblin Warchief", 130, Rarity.UNCOMMON, mage.cards.g.GoblinWarchief.class)); cards.add(new SetCardInfo("Grow from the Ashes", 164, Rarity.COMMON, mage.cards.g.GrowFromTheAshes.class)); @@ -193,12 +195,14 @@ public class Dominaria extends ExpansionSet { cards.add(new SetCardInfo("Naban, Dean of Iteration", 58, Rarity.RARE, mage.cards.n.NabanDeanOfIteration.class)); cards.add(new SetCardInfo("Naru Meha, Master Wizard", 59, Rarity.MYTHIC, mage.cards.n.NaruMehaMasterWizard.class)); cards.add(new SetCardInfo("Nature's Spiral", 175, Rarity.UNCOMMON, mage.cards.n.NaturesSpiral.class)); + cards.add(new SetCardInfo("Navigator's Compass", 175, Rarity.COMMON, mage.cards.n.NavigatorsCompass.class)); cards.add(new SetCardInfo("Niambi, Faithful Healer", 272, Rarity.RARE, mage.cards.n.NiambiFaithfulHealer.class)); cards.add(new SetCardInfo("On Serra's Wings", 28, Rarity.UNCOMMON, mage.cards.o.OnSerrasWings.class)); cards.add(new SetCardInfo("Opt", 60, Rarity.COMMON, mage.cards.o.Opt.class)); cards.add(new SetCardInfo("Orcish Vandal", 137, Rarity.COMMON, mage.cards.o.OrcishVandal.class)); cards.add(new SetCardInfo("Pardic Wanderer", 226, Rarity.COMMON, mage.cards.p.PardicWanderer.class)); cards.add(new SetCardInfo("Pegasus Courser", 29, Rarity.COMMON, mage.cards.p.PegasusCourser.class)); + cards.add(new SetCardInfo("Phyrexian Scriptures", 100, Rarity.MYTHIC, mage.cards.p.PhyrexianScriptures.class)); cards.add(new SetCardInfo("Pierce the Sky", 176, Rarity.COMMON, mage.cards.p.PierceTheSky.class)); cards.add(new SetCardInfo("Plains", 250, Rarity.LAND, mage.cards.basiclands.Plains.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Plains", 251, Rarity.LAND, mage.cards.basiclands.Plains.class, NON_FULL_USE_VARIOUS)); @@ -208,7 +212,10 @@ public class Dominaria extends ExpansionSet { cards.add(new SetCardInfo("Primevals' Glorious Rebirth", 201, Rarity.RARE, mage.cards.p.PrimevalsGloriousRebirth.class)); cards.add(new SetCardInfo("Primordial Wurm", 177, Rarity.COMMON, mage.cards.p.PrimordialWurm.class)); cards.add(new SetCardInfo("Pyromantic Pilgrim", 278, Rarity.COMMON, mage.cards.p.PyromanticPilgrim.class)); + cards.add(new SetCardInfo("Radiating Lightning", 138, Rarity.COMMON, mage.cards.r.RadiatingLightning.class)); cards.add(new SetCardInfo("Raff Capashen, Ship's Mage", 202, Rarity.UNCOMMON, mage.cards.r.RaffCapashenShipsMage.class)); + cards.add(new SetCardInfo("Rampaging Cyclops", 139, Rarity.COMMON, mage.cards.r.RampagingCyclops.class)); + cards.add(new SetCardInfo("Relic Runner", 62, Rarity.COMMON, mage.cards.r.RelicRunner.class)); cards.add(new SetCardInfo("Rescue", 63, Rarity.COMMON, mage.cards.r.Rescue.class)); cards.add(new SetCardInfo("Rite of Belzenlok", 102, Rarity.RARE, mage.cards.r.RiteOfBelzenlok.class)); cards.add(new SetCardInfo("Run Amok", 140, Rarity.COMMON, mage.cards.r.RunAmok.class)); @@ -216,9 +223,11 @@ public class Dominaria extends ExpansionSet { cards.add(new SetCardInfo("Sanctum Spirit", 30, Rarity.UNCOMMON, mage.cards.s.SanctumSpirit.class)); cards.add(new SetCardInfo("Saproling Migration", 178, Rarity.COMMON, mage.cards.s.SaprolingMigration.class)); cards.add(new SetCardInfo("Seal Away", 31, Rarity.UNCOMMON, mage.cards.s.SealAway.class)); + cards.add(new SetCardInfo("Sentinel of the Pearl Trident", 65, Rarity.UNCOMMON, mage.cards.s.SentinelOfThePearlTrident.class)); cards.add(new SetCardInfo("Sergeant-at-Arms", 32, Rarity.COMMON, mage.cards.s.SergeantAtArms.class)); cards.add(new SetCardInfo("Serra Angel", 33, Rarity.UNCOMMON, mage.cards.s.SerraAngel.class)); cards.add(new SetCardInfo("Serra Disciple", 34, Rarity.COMMON, mage.cards.s.SerraDisciple.class)); + cards.add(new SetCardInfo("Settle the Score", 103, Rarity.UNCOMMON, mage.cards.s.SettleTheScore.class)); cards.add(new SetCardInfo("Shalai, Voice of Plenty", 35, Rarity.RARE, mage.cards.s.ShalaiVoiceOfPlenty.class)); cards.add(new SetCardInfo("Shivan Fire", 142, Rarity.COMMON, mage.cards.s.ShivanFire.class)); cards.add(new SetCardInfo("Short Sword", 229, Rarity.COMMON, mage.cards.s.ShortSword.class)); @@ -226,6 +235,8 @@ public class Dominaria extends ExpansionSet { cards.add(new SetCardInfo("Skirk Prospector", 144, Rarity.COMMON, mage.cards.s.SkirkProspector.class)); cards.add(new SetCardInfo("Skittering Surveyor", 230, Rarity.COMMON, mage.cards.s.SkitteringSurveyor.class)); cards.add(new SetCardInfo("Skizzik", 145, Rarity.UNCOMMON, mage.cards.s.Skizzik.class)); + cards.add(new SetCardInfo("Slinn Voda, the Rising Deep", 66, Rarity.UNCOMMON, mage.cards.s.SlinnVodaTheRisingDeep.class)); + cards.add(new SetCardInfo("Song of Freyalise", 179, Rarity.UNCOMMON, mage.cards.s.SongOfFreyalise.class)); cards.add(new SetCardInfo("Soul Salvage", 104, Rarity.COMMON, mage.cards.s.SoulSalvage.class)); cards.add(new SetCardInfo("Sparring Construct", 232, Rarity.COMMON, mage.cards.s.SparringConstruct.class)); cards.add(new SetCardInfo("Spore Swarm", 180, Rarity.UNCOMMON, mage.cards.s.SporeSwarm.class)); @@ -238,6 +249,7 @@ public class Dominaria extends ExpansionSet { cards.add(new SetCardInfo("Swamp", 259, Rarity.LAND, mage.cards.basiclands.Swamp.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Swamp", 260, Rarity.LAND, mage.cards.basiclands.Swamp.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Swamp", 261, Rarity.LAND, mage.cards.basiclands.Swamp.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Sylvan Awakening", 183, Rarity.RARE, mage.cards.s.SylvanAwakening.class)); cards.add(new SetCardInfo("Syncopate", 67, Rarity.UNCOMMON, mage.cards.s.Syncopate.class)); cards.add(new SetCardInfo("Tatyova, Benthic Druid", 206, Rarity.UNCOMMON, mage.cards.t.TatyovaBenthicDruid.class)); cards.add(new SetCardInfo("Teferi's Sentinel", 273, Rarity.UNCOMMON, mage.cards.t.TeferisSentinel.class)); @@ -253,10 +265,12 @@ public class Dominaria extends ExpansionSet { cards.add(new SetCardInfo("The Antiquities War", 42, Rarity.RARE, mage.cards.t.TheAntiquitiesWar.class)); cards.add(new SetCardInfo("The Eldest Reborn", 90, Rarity.UNCOMMON, mage.cards.t.TheEldestReborn.class)); cards.add(new SetCardInfo("The Flame of Keld", 123, Rarity.UNCOMMON, mage.cards.t.TheFlameOfKeld.class)); + cards.add(new SetCardInfo("The Mending of Dominaria", 173, Rarity.RARE, mage.cards.t.TheMendingOfDominaria.class)); cards.add(new SetCardInfo("The Mirari Conjecture", 57, Rarity.RARE, mage.cards.t.TheMirariConjecture.class)); cards.add(new SetCardInfo("Thorn Elemental", 185, Rarity.UNCOMMON, mage.cards.t.ThornElemental.class)); cards.add(new SetCardInfo("Thran Temporal Gateway", 233, Rarity.RARE, mage.cards.t.ThranTemporalGateway.class)); cards.add(new SetCardInfo("Timber Gorge", 279, Rarity.COMMON, mage.cards.t.TimberGorge.class)); + cards.add(new SetCardInfo("Time of Ice", 70, Rarity.UNCOMMON, mage.cards.t.TimeOfIce.class)); cards.add(new SetCardInfo("Tolarian Scholar", 71, Rarity.COMMON, mage.cards.t.TolarianScholar.class)); cards.add(new SetCardInfo("Tragic Poet", 37, Rarity.COMMON, mage.cards.t.TragicPoet.class)); cards.add(new SetCardInfo("Traxos, Scourge of Kroog", 234, Rarity.RARE, mage.cards.t.TraxosScourgeOfKroog.class)); @@ -266,6 +280,7 @@ public class Dominaria extends ExpansionSet { cards.add(new SetCardInfo("Unwind", 72, Rarity.COMMON, mage.cards.u.Unwind.class)); cards.add(new SetCardInfo("Urza's Ruinous Blast", 39, Rarity.RARE, mage.cards.u.UrzasRuinousBlast.class)); cards.add(new SetCardInfo("Urza's Tome", 235, Rarity.UNCOMMON, mage.cards.u.UrzasTome.class)); + cards.add(new SetCardInfo("Valduk, Keeper of the Flame", 148, Rarity.UNCOMMON, mage.cards.v.ValdukKeeperOfTheFlame.class)); cards.add(new SetCardInfo("Verdant Force", 187, Rarity.RARE, mage.cards.v.VerdantForce.class)); cards.add(new SetCardInfo("Verix Bladewing", 149, Rarity.MYTHIC, mage.cards.v.VerixBladewing.class)); cards.add(new SetCardInfo("Vicious Offering", 110, Rarity.COMMON, mage.cards.v.ViciousOffering.class)); @@ -273,6 +288,7 @@ public class Dominaria extends ExpansionSet { cards.add(new SetCardInfo("Voltaic Servant", 236, Rarity.COMMON, mage.cards.v.VoltaicServant.class)); cards.add(new SetCardInfo("Warlord's Fury", 151, Rarity.COMMON, mage.cards.w.WarlordsFury.class)); cards.add(new SetCardInfo("Weatherlight", 237, Rarity.MYTHIC, mage.cards.w.Weatherlight.class)); + cards.add(new SetCardInfo("Weight of Memory", 74, Rarity.UNCOMMON, mage.cards.w.WeightOfMemory.class)); cards.add(new SetCardInfo("Whisper, Blood Liturgist", 111, Rarity.UNCOMMON, mage.cards.w.WhisperBloodLiturgist.class)); cards.add(new SetCardInfo("Wild Onslaught", 188, Rarity.UNCOMMON, mage.cards.w.WildOnslaught.class)); cards.add(new SetCardInfo("Windgrace Acolyte", 112, Rarity.COMMON, mage.cards.w.WindgraceAcolyte.class)); diff --git a/Mage/src/main/java/mage/cards/ExpansionSet.java b/Mage/src/main/java/mage/cards/ExpansionSet.java index c14340386ed..69ede8fab7d 100644 --- a/Mage/src/main/java/mage/cards/ExpansionSet.java +++ b/Mage/src/main/java/mage/cards/ExpansionSet.java @@ -83,7 +83,7 @@ public abstract class ExpansionSet implements Serializable { return this.cardNumber; } - public int getCardNumberAsInt(){ + public int getCardNumberAsInt() { return CardUtil.parseCardNumberAsInt(this.cardNumber); } @@ -121,6 +121,7 @@ public abstract class ExpansionSet implements Serializable { protected int numBoosterRare; protected int numBoosterDoubleFaced; // -1 = include normally 0 = exclude 1-n = include explicit protected int ratioBoosterMythic; + protected boolean needsLegends = false; protected int maxCardNumberInBooster; // used to omit cards with collector numbers beyond the regular cards in a set for boosters @@ -210,6 +211,20 @@ public abstract class ExpansionSet implements Serializable { } public List createBooster() { + if (needsLegends) { + for (int i = 0; i < 100000; i++) {//don't want to somehow loop forever + List booster = tryBooster(); + for (Card card : booster) { + if (card.isLegendary() && card.isCreature()) {// Dominaria packs must contain at least one legendary creature. + return booster; + } + } + } + } + return tryBooster(); + } + + public List tryBooster() { List booster = new ArrayList<>(); if (!hasBoosters) { return booster; @@ -436,6 +451,8 @@ public abstract class ExpansionSet implements Serializable { savedCards.clear(); } - public int getMaxCardNumberInBooster() { return maxCardNumberInBooster; } + public int getMaxCardNumberInBooster() { + return maxCardNumberInBooster; + } } diff --git a/Mage/src/main/java/mage/filter/common/FilterPlayerOrPlaneswalker.java b/Mage/src/main/java/mage/filter/common/FilterPlayerOrPlaneswalker.java new file mode 100644 index 00000000000..63848adb214 --- /dev/null +++ b/Mage/src/main/java/mage/filter/common/FilterPlayerOrPlaneswalker.java @@ -0,0 +1,84 @@ +/* + * 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.filter.common; + +import java.util.UUID; +import mage.MageItem; +import mage.filter.FilterImpl; +import mage.filter.FilterInPlay; +import mage.filter.FilterPlayer; +import mage.game.Game; +import mage.game.permanent.Permanent; +import mage.players.Player; + +/** + * + * @author LevelX2 + */ +public class FilterPlayerOrPlaneswalker extends FilterImpl implements FilterInPlay { + + protected FilterPlaneswalkerPermanent planeswalkerFilter; + protected final FilterPlayer playerFilter; + + public FilterPlayerOrPlaneswalker() { + this("player or planeswalker"); + } + + public FilterPlayerOrPlaneswalker(String name) { + super(name); + planeswalkerFilter = new FilterPlaneswalkerPermanent(); + playerFilter = new FilterPlayer(); + } + + public FilterPlayerOrPlaneswalker(final FilterPlayerOrPlaneswalker filter) { + super(filter); + this.planeswalkerFilter = filter.planeswalkerFilter.copy(); + this.playerFilter = filter.playerFilter.copy(); + } + + @Override + public boolean checkObjectClass(Object object) { + return true; + } + + @Override + public boolean match(MageItem o, Game game) { + if (o instanceof Player) { + return playerFilter.match((Player) o, game); + } else if (o instanceof Permanent) { + return planeswalkerFilter.match((Permanent) o, game); + } + return false; + } + + @Override + public boolean match(MageItem o, UUID sourceId, UUID playerId, Game game) { + if (o instanceof Player) { + return playerFilter.match((Player) o, sourceId, playerId, game); + } else if (o instanceof Permanent) { + return planeswalkerFilter.match((Permanent) o, sourceId, playerId, game); + } + return false; + } + + public FilterPlaneswalkerPermanent getPlaneswalkerFilter() { + return this.planeswalkerFilter; + } + + public FilterPlayer getPlayerFilter() { + return this.playerFilter; + } + + public void setPlaneswalkerFilter(FilterPlaneswalkerPermanent planeswalkerFilter) { + this.planeswalkerFilter = planeswalkerFilter; + } + + @Override + public FilterPlayerOrPlaneswalker copy() { + return new FilterPlayerOrPlaneswalker(this); + } + +} diff --git a/Mage/src/main/java/mage/game/permanent/token/ValdukElementalToken.java b/Mage/src/main/java/mage/game/permanent/token/ValdukElementalToken.java new file mode 100644 index 00000000000..193c8a999af --- /dev/null +++ b/Mage/src/main/java/mage/game/permanent/token/ValdukElementalToken.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.game.permanent.token; + +import mage.constants.CardType; +import mage.constants.SubType; +import mage.MageInt; +import mage.abilities.keyword.HasteAbility; +import mage.abilities.keyword.TrampleAbility; + +/** + * + * @author spjspj + */ +public class ValdukElementalToken extends TokenImpl { + + public ValdukElementalToken() { + this("DOM"); + } + + public ValdukElementalToken(String setCode) { + super("Elemental", "3/1 red Elemental creature token with trample and haste"); + cardType.add(CardType.CREATURE); + color.setRed(true); + subtype.add(SubType.ELEMENTAL); + power = new MageInt(3); + toughness = new MageInt(1); + this.addAbility(TrampleAbility.getInstance()); + this.addAbility(HasteAbility.getInstance()); + this.setOriginalExpansionSetCode("DOM"); + this.setTokenType(1); + } + + public ValdukElementalToken(final ValdukElementalToken token) { + super(token); + } + + public ValdukElementalToken copy() { + return new ValdukElementalToken(this); + } +} diff --git a/Mage/src/main/java/mage/target/common/TargetPlayerOrPlaneswalker.java b/Mage/src/main/java/mage/target/common/TargetPlayerOrPlaneswalker.java new file mode 100644 index 00000000000..5de959572c9 --- /dev/null +++ b/Mage/src/main/java/mage/target/common/TargetPlayerOrPlaneswalker.java @@ -0,0 +1,221 @@ +/* + * 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.target.common; + +import java.util.HashSet; +import java.util.Set; +import java.util.UUID; +import mage.MageObject; +import mage.abilities.Ability; +import mage.constants.Zone; +import mage.filter.Filter; +import mage.filter.common.FilterPlayerOrPlaneswalker; +import mage.game.Game; +import mage.game.permanent.Permanent; +import mage.players.Player; +import mage.target.TargetImpl; + +/** + * + * @author LevelX2 + */ +public class TargetPlayerOrPlaneswalker extends TargetImpl { + + protected FilterPlayerOrPlaneswalker filter; + + public TargetPlayerOrPlaneswalker() { + this(1, 1, new FilterPlayerOrPlaneswalker()); + } + + public TargetPlayerOrPlaneswalker(int numTargets) { + this(numTargets, numTargets, new FilterPlayerOrPlaneswalker()); + } + + public TargetPlayerOrPlaneswalker(FilterPlayerOrPlaneswalker filter) { + this(1, 1, filter); + } + + public TargetPlayerOrPlaneswalker(int minNumTargets, int maxNumTargets, FilterPlayerOrPlaneswalker filter) { + this.minNumberOfTargets = minNumTargets; + this.maxNumberOfTargets = maxNumTargets; + this.zone = Zone.ALL; + this.filter = filter; + this.targetName = filter.getMessage(); + } + + public TargetPlayerOrPlaneswalker(final TargetPlayerOrPlaneswalker target) { + super(target); + this.filter = target.filter.copy(); + } + + @Override + public Filter getFilter() { + return this.filter; + } + + @Override + public boolean canTarget(UUID id, Game game) { + Permanent permanent = game.getPermanent(id); + if (permanent != null) { + return filter.match(permanent, game); + } + Player player = game.getPlayer(id); + return player != null && filter.match(player, game); + } + + @Override + public boolean canTarget(UUID id, Ability source, Game game) { + return canTarget(source.getControllerId(), id, source, game); + } + + @Override + public boolean canTarget(UUID controllerId, UUID id, Ability source, Game game) { + Permanent permanent = game.getPermanent(id); + Player player = game.getPlayer(id); + + if (source != null) { + MageObject targetSource = game.getObject(source.getSourceId()); + if (permanent != null) { + return permanent.canBeTargetedBy(targetSource, source.getControllerId(), game) && filter.match(permanent, source.getSourceId(), source.getControllerId(), game); + } + if (player != null) { + return player.canBeTargetedBy(targetSource, source.getControllerId(), game) && filter.match(player, game); + } + } + + if (permanent != null) { + return filter.match(permanent, game); + } + return player != null && filter.match(player, game); + } + + /** + * Checks if there are enough {@link Permanent} or {@link Player} that can + * be chosen. Should only be used for Ability targets since this checks for + * protection, shroud etc. + * + * @param sourceId - the target event source + * @param sourceControllerId - controller of the target event source + * @param game + * @return - true if enough valid {@link Permanent} or {@link Player} exist + */ + @Override + public boolean canChoose(UUID sourceId, UUID sourceControllerId, Game game) { + int count = 0; + MageObject targetSource = game.getObject(sourceId); + for (UUID playerId : game.getState().getPlayersInRange(sourceControllerId, game)) { + Player player = game.getPlayer(playerId); + if (player != null && player.canBeTargetedBy(targetSource, sourceControllerId, game) && filter.match(player, game)) { + count++; + if (count >= this.minNumberOfTargets) { + return true; + } + } + } + for (Permanent permanent : game.getBattlefield().getActivePermanents(filter.getPlaneswalkerFilter(), sourceControllerId, game)) { + if (permanent.canBeTargetedBy(targetSource, sourceControllerId, game) && filter.match(permanent, sourceId, sourceControllerId, game)) { + count++; + if (count >= this.minNumberOfTargets) { + return true; + } + } + } + return false; + } + + /** + * Checks if there are enough {@link Permanent} or {@link Player} that can + * be selected. Should not be used for Ability targets since this does not + * check for protection, shroud etc. + * + * @param sourceControllerId - controller of the select event + * @param game + * @return - true if enough valid {@link Permanent} or {@link Player} exist + */ + @Override + public boolean canChoose(UUID sourceControllerId, Game game) { + int count = 0; + for (UUID playerId : game.getState().getPlayersInRange(sourceControllerId, game)) { + Player player = game.getPlayer(playerId); + if (player != null && filter.match(player, game)) { + count++; + if (count >= this.minNumberOfTargets) { + return true; + } + } + } + for (Permanent permanent : game.getBattlefield().getActivePermanents(filter.getPlaneswalkerFilter(), sourceControllerId, game)) { + if (filter.match(permanent, null, sourceControllerId, game)) { + count++; + if (count >= this.minNumberOfTargets) { + return true; + } + } + } + return false; + } + + @Override + public Set possibleTargets(UUID sourceId, UUID sourceControllerId, Game game) { + Set possibleTargets = new HashSet<>(); + MageObject targetSource = game.getObject(sourceId); + for (UUID playerId : game.getState().getPlayersInRange(sourceControllerId, game)) { + Player player = game.getPlayer(playerId); + if (player != null + && player.canBeTargetedBy(targetSource, sourceControllerId, game) + && filter.getPlayerFilter().match(player, sourceId, sourceControllerId, game)) { + possibleTargets.add(playerId); + } + } + for (Permanent permanent : game.getBattlefield().getActivePermanents(filter.getPlaneswalkerFilter(), sourceControllerId, game)) { + if (permanent.canBeTargetedBy(targetSource, sourceControllerId, game) + && filter.getPlaneswalkerFilter().match(permanent, sourceId, sourceControllerId, game)) { + possibleTargets.add(permanent.getId()); + } + } + return possibleTargets; + } + + @Override + public Set possibleTargets(UUID sourceControllerId, Game game) { + Set possibleTargets = new HashSet<>(); + for (UUID playerId : game.getState().getPlayersInRange(sourceControllerId, game)) { + Player player = game.getPlayer(playerId); + if (player != null && filter.getPlayerFilter().match(player, game)) { + possibleTargets.add(playerId); + } + } + for (Permanent permanent : game.getBattlefield().getActivePermanents(filter.getPlaneswalkerFilter(), sourceControllerId, game)) { + if (filter.getPlaneswalkerFilter().match(permanent, null, sourceControllerId, game)) { + possibleTargets.add(permanent.getId()); + } + } + return possibleTargets; + } + + @Override + public String getTargetedName(Game game) { + StringBuilder sb = new StringBuilder(); + for (UUID targetId : getTargets()) { + Permanent permanent = game.getPermanent(targetId); + if (permanent != null) { + sb.append(permanent.getLogName()).append(' '); + } else { + Player player = game.getPlayer(targetId); + if (player != null) { + sb.append(player.getLogName()).append(' '); + } + } + } + return sb.toString(); + } + + @Override + public TargetPlayerOrPlaneswalker copy() { + return new TargetPlayerOrPlaneswalker(this); + } + +} diff --git a/Utils/gen-existing-cards-by-set.pl b/Utils/gen-existing-cards-by-set.pl index 93462c3ad92..a74c2451382 100755 --- a/Utils/gen-existing-cards-by-set.pl +++ b/Utils/gen-existing-cards-by-set.pl @@ -242,33 +242,37 @@ foreach $name_collectorid (sort @setCards) my $fn = "..\\Mage.Sets\\src\\mage\\cards\\$setId\\$className.java"; my $str = " cards.add(new SetCardInfo(\"$cardName\", $cardNr, Rarity." . getRarity ($cards{$cardName}{$setName}[3], $cardName) . ", mage.cards.$setId.$className.class));\n"; + my $plus_cardName = $cardName; + $plus_cardName =~ s/ /+/img; + $plus_cardName = "$plus_cardName"; + my $github_name = $plus_cardName; + $github_name =~ s/\W//img; + my $github_url = "https://github.com/magefree/mage/search?q="; + $github_url .= "$github_name.java"; + if (@$ds[2] eq "SPLIT") { my $oldCardName = $cardName; $cardName = @$ds[4]; $str = " cards.add(new SetCardInfo(\"$cardName\", $cardNr, Rarity." . getRarity ($cards{$oldCardName}{$setName}[3], $oldCardName) . ", mage.cards.$setId.$className.class));\n"; } - my $plus_cardName = $cardName; - $plus_cardName =~ s/ /+/img; - $plus_cardName =~ s/,/+/img; - $plus_cardName = "intext:\"$plus_cardName\""; if (!exists ($alreadyIn{$cardNr})) { # Go Looking for the existing implementation.. if (-e $fn) { $implementedButNotInSetYet {$str} = 1; - $githubTask {"- [ ] Implemented but have to add to set -- [$cardName](https://www.google.com.au/search?q=$plus_cardName+$googleSetName+mtg&source=lnms&tbm=isch)\n"} = 1; + $githubTask {"- [ ] Implemented but have to add to set -- [$cardName](https://scryfall.com/search?q=$plus_cardName) -- [Mage code $cardName]($github_url)\n"} = 1; } else { $unimplemented {"$str"} = 1; - $githubTask {"- [ ] Not done -- [$cardName](https://www.google.com.au/search?q=$plus_cardName+$googleSetName+mtg&source=lnms&tbm=isch)\n"} = 1; + $githubTask {"- [ ] Not done -- [$cardName](https://scryfall.com/search?q=$plus_cardName)\n"} = 1; } } else { if (-e $fn) { $implemented {$str} = 1; - $githubTask {"- [x] Done -- [$cardName](https://www.google.com.au/search?q=$plus_cardName+$googleSetName+mtg&source=lnms&tbm=isch)\n"} = 1; + $githubTask {"- [x] Done -- [$cardName](https://scryfall.com/search?q=$plus_cardName) -- [Mage code $cardName]($github_url)\n"} = 1; } else { $unimplemented {$str} = 1; - $githubTask {"- [ ] Not done -- [$cardName](https://www.google.com.au/search?q=$plus_cardName+$googleSetName+mtg&source=lnms&tbm=isch)\n"} = 1; + $githubTask {"- [ ] Not done -- [$cardName](https://scryfall.com/search?q=$plus_cardName)\n"} = 1; } } }