From 55dcf800128029a5e7812ffc7f54503ecb869fdc Mon Sep 17 00:00:00 2001 From: LoneFox Date: Sun, 20 Dec 2015 11:24:31 +0200 Subject: [PATCH 01/23] Implement cards: Consumptive Goo, Decree of Silence, Misguided Rage, and Recuperate --- .../src/mage/sets/scourge/ConsumptiveGoo.java | 73 +++++++++++++++ .../mage/sets/scourge/DecreeOfSilence.java | 89 +++++++++++++++++++ .../src/mage/sets/scourge/MisguidedRage.java | 61 +++++++++++++ .../src/mage/sets/scourge/Recuperate.java | 69 ++++++++++++++ .../mage/abilities/TriggeredAbilityImpl.java | 3 +- 5 files changed, 294 insertions(+), 1 deletion(-) create mode 100644 Mage.Sets/src/mage/sets/scourge/ConsumptiveGoo.java create mode 100644 Mage.Sets/src/mage/sets/scourge/DecreeOfSilence.java create mode 100644 Mage.Sets/src/mage/sets/scourge/MisguidedRage.java create mode 100644 Mage.Sets/src/mage/sets/scourge/Recuperate.java diff --git a/Mage.Sets/src/mage/sets/scourge/ConsumptiveGoo.java b/Mage.Sets/src/mage/sets/scourge/ConsumptiveGoo.java new file mode 100644 index 00000000000..f361b4dcf4b --- /dev/null +++ b/Mage.Sets/src/mage/sets/scourge/ConsumptiveGoo.java @@ -0,0 +1,73 @@ +/* + * Copyright 2010 BetaSteward_at_googlemail.com. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are + * permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this list of + * conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, this list + * of conditions and the following disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY BetaSteward_at_googlemail.com ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BetaSteward_at_googlemail.com OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * The views and conclusions contained in the software and documentation are those of the + * authors and should not be interpreted as representing official policies, either expressed + * or implied, of BetaSteward_at_googlemail.com. + */ +package mage.sets.scourge; + +import java.util.UUID; +import mage.MageInt; +import mage.abilities.Ability; +import mage.abilities.common.SimpleActivatedAbility; +import mage.abilities.costs.mana.ManaCostsImpl; +import mage.abilities.effects.common.continuous.BoostTargetEffect; +import mage.abilities.effects.common.counter.AddCountersSourceEffect; +import mage.cards.CardImpl; +import mage.constants.CardType; +import mage.constants.Duration; +import mage.constants.Rarity; +import mage.constants.Zone; +import mage.counters.CounterType; +import mage.target.common.TargetCreaturePermanent; + +/** + * + * @author LoneFox + */ +public class ConsumptiveGoo extends CardImpl { + + public ConsumptiveGoo(UUID ownerId) { + super(ownerId, 62, "Consumptive Goo", Rarity.RARE, new CardType[]{CardType.CREATURE}, "{B}{B}"); + this.expansionSetCode = "SCG"; + this.subtype.add("Ooze"); + this.power = new MageInt(1); + this.toughness = new MageInt(1); + + // {2}{B}{B}: Target creature gets -1/-1 until end of turn. Put a +1/+1 counter on Consumptive Goo. + Ability ability = new SimpleActivatedAbility(Zone.BATTLEFIELD, new BoostTargetEffect(-1, -1, Duration.EndOfTurn), new ManaCostsImpl("{2}{B}{B}")); + ability.addEffect(new AddCountersSourceEffect(CounterType.P1P1.createInstance())); + ability.addTarget(new TargetCreaturePermanent()); + this.addAbility(ability); + } + + public ConsumptiveGoo(final ConsumptiveGoo card) { + super(card); + } + + @Override + public ConsumptiveGoo copy() { + return new ConsumptiveGoo(this); + } +} diff --git a/Mage.Sets/src/mage/sets/scourge/DecreeOfSilence.java b/Mage.Sets/src/mage/sets/scourge/DecreeOfSilence.java new file mode 100644 index 00000000000..1d0d6b3c972 --- /dev/null +++ b/Mage.Sets/src/mage/sets/scourge/DecreeOfSilence.java @@ -0,0 +1,89 @@ +/* + * Copyright 2010 BetaSteward_at_googlemail.com. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are + * permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this list of + * conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, this list + * of conditions and the following disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY BetaSteward_at_googlemail.com ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BetaSteward_at_googlemail.com OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * The views and conclusions contained in the software and documentation are those of the + * authors and should not be interpreted as representing official policies, either expressed + * or implied, of BetaSteward_at_googlemail.com. + */ +package mage.sets.scourge; + +import java.util.UUID; +import mage.abilities.Ability; +import mage.abilities.common.CycleTriggeredAbility; +import mage.abilities.common.SpellCastOpponentTriggeredAbility; +import mage.abilities.condition.common.SourceHasCounterCondition; +import mage.abilities.costs.mana.ManaCostsImpl; +import mage.abilities.decorator.ConditionalOneShotEffect; +import mage.abilities.effects.Effect; +import mage.abilities.effects.common.CounterTargetEffect; +import mage.abilities.effects.common.SacrificeSourceEffect; +import mage.abilities.effects.common.counter.AddCountersSourceEffect; +import mage.abilities.keyword.CyclingAbility; +import mage.cards.CardImpl; +import mage.constants.CardType; +import mage.constants.Rarity; +import mage.constants.SetTargetPointer; +import mage.constants.Zone; +import mage.counters.CounterType; +import mage.filter.FilterSpell; +import mage.target.TargetSpell; + +/** + * + * @author LoneFox + */ +public class DecreeOfSilence extends CardImpl { + + public DecreeOfSilence(UUID ownerId) { + super(ownerId, 32, "Decree of Silence", Rarity.RARE, new CardType[]{CardType.ENCHANTMENT}, "{6}{U}{U}"); + this.expansionSetCode = "SCG"; + + // Whenever an opponent casts a spell, counter that spell and put a depletion counter on Decree of Silence. If there are three or more depletion counters on Decree of Silence, sacrifice it. + Effect effect = new CounterTargetEffect(); + effect.setText("counter that spell"); + Ability ability = new SpellCastOpponentTriggeredAbility(Zone.BATTLEFIELD, effect, new FilterSpell(), + false, SetTargetPointer.SPELL); + effect = new AddCountersSourceEffect(CounterType.DEPLETION.createInstance()); + effect.setText("and put a depletion counter on {this}."); + ability.addEffect(effect); + ability.addEffect(new ConditionalOneShotEffect(new SacrificeSourceEffect(), + new SourceHasCounterCondition(CounterType.DEPLETION, 3, Integer.MAX_VALUE), + " If there are three or more depletion counters on {this}, sacrifice it")); + this.addAbility(ability); + // Cycling {4}{U}{U} + this.addAbility(new CyclingAbility(new ManaCostsImpl("{4}{U}{U}"))); + // When you cycle Decree of Silence, you may counter target spell. + ability = new CycleTriggeredAbility(new CounterTargetEffect(), true); + ability.addTarget(new TargetSpell()); + this.addAbility(ability); + } + + public DecreeOfSilence(final DecreeOfSilence card) { + super(card); + } + + @Override + public DecreeOfSilence copy() { + return new DecreeOfSilence(this); + } +} diff --git a/Mage.Sets/src/mage/sets/scourge/MisguidedRage.java b/Mage.Sets/src/mage/sets/scourge/MisguidedRage.java new file mode 100644 index 00000000000..9abb2d601a2 --- /dev/null +++ b/Mage.Sets/src/mage/sets/scourge/MisguidedRage.java @@ -0,0 +1,61 @@ +/* + * 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.sets.scourge; + +import java.util.UUID; +import mage.abilities.effects.common.SacrificeEffect; +import mage.cards.CardImpl; +import mage.constants.CardType; +import mage.constants.Rarity; +import mage.filter.FilterPermanent; +import mage.target.TargetPlayer; + +/** + * + * @author LoneFox + */ +public class MisguidedRage extends CardImpl { + + public MisguidedRage(UUID ownerId) { + super(ownerId, 99, "Misguided Rage", Rarity.COMMON, new CardType[]{CardType.SORCERY}, "{2}{R}"); + this.expansionSetCode = "SCG"; + + // Target player sacrifices a permanent. + this.getSpellAbility().addEffect(new SacrificeEffect(new FilterPermanent(), 1, "Target player")); + this.getSpellAbility().addTarget(new TargetPlayer()); + } + + public MisguidedRage(final MisguidedRage card) { + super(card); + } + + @Override + public MisguidedRage copy() { + return new MisguidedRage(this); + } +} diff --git a/Mage.Sets/src/mage/sets/scourge/Recuperate.java b/Mage.Sets/src/mage/sets/scourge/Recuperate.java new file mode 100644 index 00000000000..01202ed01c0 --- /dev/null +++ b/Mage.Sets/src/mage/sets/scourge/Recuperate.java @@ -0,0 +1,69 @@ +/* + * Copyright 2010 BetaSteward_at_googlemail.com. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are + * permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this list of + * conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, this list + * of conditions and the following disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY BetaSteward_at_googlemail.com ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BetaSteward_at_googlemail.com OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * The views and conclusions contained in the software and documentation are those of the + * authors and should not be interpreted as representing official policies, either expressed + * or implied, of BetaSteward_at_googlemail.com. + */ +package mage.sets.scourge; + +import java.util.UUID; +import mage.abilities.Mode; +import mage.abilities.effects.common.GainLifeTargetEffect; +import mage.abilities.effects.common.PreventDamageToTargetEffect; +import mage.cards.CardImpl; +import mage.constants.CardType; +import mage.constants.Duration; +import mage.constants.Rarity; +import mage.target.TargetPlayer; +import mage.target.common.TargetCreaturePermanent; + +/** + * + * @author LoneFox + */ +public class Recuperate extends CardImpl { + + public Recuperate(UUID ownerId) { + super(ownerId, 21, "Recuperate", Rarity.COMMON, new CardType[]{CardType.INSTANT}, "{3}{W}"); + this.expansionSetCode = "SCG"; + + // Choose one - You gain 6 life; + this.getSpellAbility().addEffect(new GainLifeTargetEffect(6)); + this.getSpellAbility().addTarget(new TargetPlayer()); + // or prevent the next 6 damage that would be dealt to target creature this turn. + Mode mode = new Mode(); + mode.getEffects().add(new PreventDamageToTargetEffect(Duration.EndOfTurn, 6)); + mode.getTargets().add(new TargetCreaturePermanent()); + this.getSpellAbility().addMode(mode); + } + + public Recuperate(final Recuperate card) { + super(card); + } + + @Override + public Recuperate copy() { + return new Recuperate(this); + } +} diff --git a/Mage/src/main/java/mage/abilities/TriggeredAbilityImpl.java b/Mage/src/main/java/mage/abilities/TriggeredAbilityImpl.java index 2db3f564bdd..d91326522a9 100644 --- a/Mage/src/main/java/mage/abilities/TriggeredAbilityImpl.java +++ b/Mage/src/main/java/mage/abilities/TriggeredAbilityImpl.java @@ -134,7 +134,8 @@ public abstract class TriggeredAbilityImpl extends AbilityImpl implements Trigge || ruleLow.startsWith("tap") || ruleLow.startsWith("untap") || ruleLow.startsWith("put") - || ruleLow.startsWith("remove")) { + || ruleLow.startsWith("remove") + || ruleLow.startsWith("counter")) { sb.append("you may "); } else { if (!ruleLow.startsWith("its controller may")) { From 58aae18701a3d636271c7cf3fc1addd796518242 Mon Sep 17 00:00:00 2001 From: LoneFox Date: Sun, 20 Dec 2015 19:03:06 +0200 Subject: [PATCH 02/23] Implement cards: Ark of Blight, Decree of Savagery, Skulltap, and Unburden --- .../src/mage/sets/scourge/ArkOfBlight.java | 69 ++++++++++++++++++ .../mage/sets/scourge/DecreeOfSavagery.java | 73 +++++++++++++++++++ Mage.Sets/src/mage/sets/scourge/Skulltap.java | 63 ++++++++++++++++ Mage.Sets/src/mage/sets/scourge/Unburden.java | 64 ++++++++++++++++ 4 files changed, 269 insertions(+) create mode 100644 Mage.Sets/src/mage/sets/scourge/ArkOfBlight.java create mode 100644 Mage.Sets/src/mage/sets/scourge/DecreeOfSavagery.java create mode 100644 Mage.Sets/src/mage/sets/scourge/Skulltap.java create mode 100644 Mage.Sets/src/mage/sets/scourge/Unburden.java diff --git a/Mage.Sets/src/mage/sets/scourge/ArkOfBlight.java b/Mage.Sets/src/mage/sets/scourge/ArkOfBlight.java new file mode 100644 index 00000000000..b0e9dbd8689 --- /dev/null +++ b/Mage.Sets/src/mage/sets/scourge/ArkOfBlight.java @@ -0,0 +1,69 @@ +/* + * Copyright 2010 BetaSteward_at_googlemail.com. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are + * permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this list of + * conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, this list + * of conditions and the following disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY BetaSteward_at_googlemail.com ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BetaSteward_at_googlemail.com OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * The views and conclusions contained in the software and documentation are those of the + * authors and should not be interpreted as representing official policies, either expressed + * or implied, of BetaSteward_at_googlemail.com. + */ +package mage.sets.scourge; + +import java.util.UUID; +import mage.abilities.Ability; +import mage.abilities.common.SimpleActivatedAbility; +import mage.abilities.costs.common.SacrificeSourceCost; +import mage.abilities.costs.common.TapSourceCost; +import mage.abilities.costs.mana.ManaCostsImpl; +import mage.abilities.effects.common.DestroyTargetEffect; +import mage.cards.CardImpl; +import mage.constants.CardType; +import mage.constants.Rarity; +import mage.constants.Zone; +import mage.target.common.TargetLandPermanent; + +/** + * + * @author LoneFox + */ +public class ArkOfBlight extends CardImpl { + + public ArkOfBlight(UUID ownerId) { + super(ownerId, 140, "Ark of Blight", Rarity.UNCOMMON, new CardType[]{CardType.ARTIFACT}, "{2}"); + this.expansionSetCode = "SCG"; + + // {3}, {tap}, Sacrifice Ark of Blight: Destroy target land. + Ability ability = new SimpleActivatedAbility(Zone.BATTLEFIELD, new DestroyTargetEffect(), new ManaCostsImpl("{3}")); + ability.addCost(new TapSourceCost()); + ability.addCost(new SacrificeSourceCost()); + ability.addTarget(new TargetLandPermanent()); + this.addAbility(ability); + } + + public ArkOfBlight(final ArkOfBlight card) { + super(card); + } + + @Override + public ArkOfBlight copy() { + return new ArkOfBlight(this); + } +} diff --git a/Mage.Sets/src/mage/sets/scourge/DecreeOfSavagery.java b/Mage.Sets/src/mage/sets/scourge/DecreeOfSavagery.java new file mode 100644 index 00000000000..bf3b63f1496 --- /dev/null +++ b/Mage.Sets/src/mage/sets/scourge/DecreeOfSavagery.java @@ -0,0 +1,73 @@ +/* + * Copyright 2010 BetaSteward_at_googlemail.com. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are + * permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this list of + * conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, this list + * of conditions and the following disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY BetaSteward_at_googlemail.com ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BetaSteward_at_googlemail.com OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * The views and conclusions contained in the software and documentation are those of the + * authors and should not be interpreted as representing official policies, either expressed + * or implied, of BetaSteward_at_googlemail.com. + */ +package mage.sets.scourge; + +import java.util.UUID; +import mage.abilities.Ability; +import mage.abilities.common.CycleTriggeredAbility; +import mage.abilities.costs.mana.ManaCostsImpl; +import mage.abilities.effects.common.counter.AddCountersAllEffect; +import mage.abilities.effects.common.counter.AddCountersTargetEffect; +import mage.abilities.keyword.CyclingAbility; +import mage.cards.CardImpl; +import mage.constants.CardType; +import mage.constants.Rarity; +import mage.counters.CounterType; +import mage.filter.common.FilterControlledCreaturePermanent; +import mage.target.common.TargetCreaturePermanent; + +/** + + * + * @author LoneFox + */ +public class DecreeOfSavagery extends CardImpl { + + public DecreeOfSavagery(UUID ownerId) { + super(ownerId, 115, "Decree of Savagery", Rarity.RARE, new CardType[]{CardType.INSTANT}, "{7}{G}{G}"); + this.expansionSetCode = "SCG"; + + // Put four +1/+1 counters on each creature you control. + this.getSpellAbility().addEffect(new AddCountersAllEffect(CounterType.P1P1.createInstance(4), new FilterControlledCreaturePermanent())); + // Cycling {4}{G}{G} + this.addAbility(new CyclingAbility(new ManaCostsImpl("{4}{G}{G}"))); + // When you cycle Decree of Savagery, you may put four +1/+1 counters on target creature. + Ability ability = new CycleTriggeredAbility(new AddCountersTargetEffect(CounterType.P1P1.createInstance(4)), true); + ability.addTarget(new TargetCreaturePermanent()); + this.addAbility(ability); + } + + public DecreeOfSavagery(final DecreeOfSavagery card) { + super(card); + } + + @Override + public DecreeOfSavagery copy() { + return new DecreeOfSavagery(this); + } +} diff --git a/Mage.Sets/src/mage/sets/scourge/Skulltap.java b/Mage.Sets/src/mage/sets/scourge/Skulltap.java new file mode 100644 index 00000000000..ef6b1bbf36c --- /dev/null +++ b/Mage.Sets/src/mage/sets/scourge/Skulltap.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.sets.scourge; + +import java.util.UUID; +import mage.abilities.costs.common.SacrificeTargetCost; +import mage.abilities.effects.common.DrawCardSourceControllerEffect; +import mage.cards.CardImpl; +import mage.constants.CardType; +import mage.constants.Rarity; +import mage.filter.common.FilterControlledCreaturePermanent; +import mage.target.common.TargetControlledCreaturePermanent; + +/** + * + * @author LoneFox + */ +public class Skulltap extends CardImpl { + + public Skulltap(UUID ownerId) { + super(ownerId, 73, "Skulltap", Rarity.COMMON, new CardType[]{CardType.SORCERY}, "{1}{B}"); + this.expansionSetCode = "SCG"; + + // As an additional cost to cast Skulltap, sacrifice a creature. + this.getSpellAbility().addCost(new SacrificeTargetCost(new TargetControlledCreaturePermanent(1, 1, new FilterControlledCreaturePermanent("a creature"), true))); + // Draw two cards. + this.getSpellAbility().addEffect(new DrawCardSourceControllerEffect(2)); + } + + public Skulltap(final Skulltap card) { + super(card); + } + + @Override + public Skulltap copy() { + return new Skulltap(this); + } +} diff --git a/Mage.Sets/src/mage/sets/scourge/Unburden.java b/Mage.Sets/src/mage/sets/scourge/Unburden.java new file mode 100644 index 00000000000..9ba595a8f32 --- /dev/null +++ b/Mage.Sets/src/mage/sets/scourge/Unburden.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.sets.scourge; + +import java.util.UUID; +import mage.abilities.costs.mana.ManaCostsImpl; +import mage.abilities.effects.common.discard.DiscardTargetEffect; +import mage.abilities.keyword.CyclingAbility; +import mage.cards.CardImpl; +import mage.constants.CardType; +import mage.constants.Rarity; +import mage.target.TargetPlayer; + +/** + * + * @author LoneFox + */ +public class Unburden extends CardImpl { + + public Unburden(UUID ownerId) { + super(ownerId, 77, "Unburden", Rarity.COMMON, new CardType[]{CardType.SORCERY}, "{1}{B}{B}"); + this.expansionSetCode = "SCG"; + + // Target player discards two cards. + this.getSpellAbility().addEffect(new DiscardTargetEffect(2)); + this.getSpellAbility().addTarget(new TargetPlayer()); + // Cycling {2} + this.addAbility(new CyclingAbility(new ManaCostsImpl("{2}"))); + } + + public Unburden(final Unburden card) { + super(card); + } + + @Override + public Unburden copy() { + return new Unburden(this); + } +} From ad5b8fb3c9dc0cf8ad3e3a8b42e15be620320cf2 Mon Sep 17 00:00:00 2001 From: LoneFox Date: Tue, 22 Dec 2015 10:54:26 +0200 Subject: [PATCH 03/23] Implement cards: Auspicious Ancestor, Femeref Healer, Igneous Golem, and Radiant Essence --- .../mage/sets/mirage/AuspiciousAncestor.java | 78 +++++++++++++++++ .../src/mage/sets/mirage/FemerefHealer.java | 71 ++++++++++++++++ .../src/mage/sets/mirage/IgneousGolem.java | 67 +++++++++++++++ .../src/mage/sets/mirage/RadiantEssence.java | 83 +++++++++++++++++++ 4 files changed, 299 insertions(+) create mode 100644 Mage.Sets/src/mage/sets/mirage/AuspiciousAncestor.java create mode 100644 Mage.Sets/src/mage/sets/mirage/FemerefHealer.java create mode 100644 Mage.Sets/src/mage/sets/mirage/IgneousGolem.java create mode 100644 Mage.Sets/src/mage/sets/mirage/RadiantEssence.java diff --git a/Mage.Sets/src/mage/sets/mirage/AuspiciousAncestor.java b/Mage.Sets/src/mage/sets/mirage/AuspiciousAncestor.java new file mode 100644 index 00000000000..4d6dac33773 --- /dev/null +++ b/Mage.Sets/src/mage/sets/mirage/AuspiciousAncestor.java @@ -0,0 +1,78 @@ +/* + * 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.sets.mirage; + +import java.util.UUID; +import mage.MageInt; +import mage.ObjectColor; +import mage.abilities.common.DiesTriggeredAbility; +import mage.abilities.common.SpellCastAllTriggeredAbility; +import mage.abilities.costs.mana.ManaCostsImpl; +import mage.abilities.effects.common.DoIfCostPaid; +import mage.abilities.effects.common.GainLifeEffect; +import mage.cards.CardImpl; +import mage.constants.CardType; +import mage.constants.Rarity; +import mage.filter.FilterSpell; +import mage.filter.predicate.mageobject.ColorPredicate; + +/** + * + * @author LoneFox + */ +public class AuspiciousAncestor extends CardImpl { + + private static final FilterSpell filter = new FilterSpell("a white spell"); + + static { + filter.add(new ColorPredicate(ObjectColor.WHITE)); + } + + public AuspiciousAncestor(UUID ownerId) { + super(ownerId, 207, "Auspicious Ancestor", Rarity.RARE, new CardType[]{CardType.CREATURE}, "{3}{W}"); + this.expansionSetCode = "MIR"; + this.subtype.add("Human"); + this.subtype.add("Cleric"); + this.power = new MageInt(2); + this.toughness = new MageInt(3); + + // When Auspicious Ancestor dies, you gain 3 life. + this.addAbility(new DiesTriggeredAbility(new GainLifeEffect(3), false)); + // Whenever a player casts a white spell, you may pay {1}. If you do, you gain 1 life. + this.addAbility(new SpellCastAllTriggeredAbility(new DoIfCostPaid(new GainLifeEffect(1), new ManaCostsImpl("{1}")), filter, true)); + } + + public AuspiciousAncestor(final AuspiciousAncestor card) { + super(card); + } + + @Override + public AuspiciousAncestor copy() { + return new AuspiciousAncestor(this); + } +} diff --git a/Mage.Sets/src/mage/sets/mirage/FemerefHealer.java b/Mage.Sets/src/mage/sets/mirage/FemerefHealer.java new file mode 100644 index 00000000000..082e34a2a96 --- /dev/null +++ b/Mage.Sets/src/mage/sets/mirage/FemerefHealer.java @@ -0,0 +1,71 @@ +/* + * 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.sets.mirage; + +import java.util.UUID; +import mage.MageInt; +import mage.abilities.Ability; +import mage.abilities.common.SimpleActivatedAbility; +import mage.abilities.costs.common.TapSourceCost; +import mage.abilities.effects.common.PreventDamageToTargetEffect; +import mage.cards.CardImpl; +import mage.constants.CardType; +import mage.constants.Duration; +import mage.constants.Rarity; +import mage.constants.Zone; +import mage.target.common.TargetCreatureOrPlayer; + +/** + * + * @author LoneFox + */ +public class FemerefHealer extends CardImpl { + + public FemerefHealer(UUID ownerId) { + super(ownerId, 221, "Femeref Healer", Rarity.COMMON, new CardType[]{CardType.CREATURE}, "{1}{W}"); + this.expansionSetCode = "MIR"; + this.subtype.add("Human"); + this.subtype.add("Cleric"); + this.power = new MageInt(1); + this.toughness = new MageInt(1); + + // {tap}: Prevent the next 1 damage that would be dealt to target creature or player this turn. + Ability ability = new SimpleActivatedAbility(Zone.BATTLEFIELD, new PreventDamageToTargetEffect(Duration.EndOfTurn, 1), new TapSourceCost()); + ability.addTarget(new TargetCreatureOrPlayer()); + this.addAbility(ability); + } + + public FemerefHealer(final FemerefHealer card) { + super(card); + } + + @Override + public FemerefHealer copy() { + return new FemerefHealer(this); + } +} diff --git a/Mage.Sets/src/mage/sets/mirage/IgneousGolem.java b/Mage.Sets/src/mage/sets/mirage/IgneousGolem.java new file mode 100644 index 00000000000..79b6a00a94d --- /dev/null +++ b/Mage.Sets/src/mage/sets/mirage/IgneousGolem.java @@ -0,0 +1,67 @@ +/* + * Copyright 2010 BetaSteward_at_googlemail.com. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are + * permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this list of + * conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, this list + * of conditions and the following disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY BetaSteward_at_googlemail.com ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BetaSteward_at_googlemail.com OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * The views and conclusions contained in the software and documentation are those of the + * authors and should not be interpreted as representing official policies, either expressed + * or implied, of BetaSteward_at_googlemail.com. + */ +package mage.sets.mirage; + +import java.util.UUID; +import mage.MageInt; +import mage.abilities.common.SimpleActivatedAbility; +import mage.abilities.costs.mana.ManaCostsImpl; +import mage.abilities.effects.common.continuous.GainAbilitySourceEffect; +import mage.abilities.keyword.TrampleAbility; +import mage.cards.CardImpl; +import mage.constants.CardType; +import mage.constants.Duration; +import mage.constants.Rarity; +import mage.constants.Zone; + +/** + * + * @author LoneFox + */ +public class IgneousGolem extends CardImpl { + + public IgneousGolem(UUID ownerId) { + super(ownerId, 270, "Igneous Golem", Rarity.UNCOMMON, new CardType[]{CardType.ARTIFACT, CardType.CREATURE}, "{5}"); + this.expansionSetCode = "MIR"; + this.subtype.add("Golem"); + this.power = new MageInt(3); + this.toughness = new MageInt(4); + + // {2}: Igneous Golem gains trample until end of turn. + this.addAbility(new SimpleActivatedAbility(Zone.BATTLEFIELD, new GainAbilitySourceEffect(TrampleAbility.getInstance(), Duration.EndOfTurn), new ManaCostsImpl("{2}"))); + } + + public IgneousGolem(final IgneousGolem card) { + super(card); + } + + @Override + public IgneousGolem copy() { + return new IgneousGolem(this); + } +} diff --git a/Mage.Sets/src/mage/sets/mirage/RadiantEssence.java b/Mage.Sets/src/mage/sets/mirage/RadiantEssence.java new file mode 100644 index 00000000000..7135ab0b4f6 --- /dev/null +++ b/Mage.Sets/src/mage/sets/mirage/RadiantEssence.java @@ -0,0 +1,83 @@ +/* + * Copyright 2010 BetaSteward_at_googlemail.com. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are + * permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this list of + * conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, this list + * of conditions and the following disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY BetaSteward_at_googlemail.com ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BetaSteward_at_googlemail.com OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * The views and conclusions contained in the software and documentation are those of the + * authors and should not be interpreted as representing official policies, either expressed + * or implied, of BetaSteward_at_googlemail.com. + */ +package mage.sets.mirage; + +import java.util.UUID; +import mage.MageInt; +import mage.ObjectColor; +import mage.abilities.common.SimpleStaticAbility; +import mage.abilities.condition.common.PermanentsOnTheBattlefieldCondition.CountType; +import mage.abilities.condition.common.PermanentsOnTheBattlefieldCondition; +import mage.abilities.decorator.ConditionalContinuousEffect; +import mage.abilities.effects.common.continuous.BoostSourceEffect; +import mage.cards.CardImpl; +import mage.constants.CardType; +import mage.constants.Duration; +import mage.constants.Rarity; +import mage.constants.TargetController; +import mage.constants.Zone; +import mage.filter.FilterPermanent; +import mage.filter.predicate.mageobject.ColorPredicate; +import mage.filter.predicate.permanent.ControllerPredicate; + +/** + * + * @author LoneFox + */ +public class RadiantEssence extends CardImpl { + + private static final FilterPermanent filter = new FilterPermanent("a black permanent"); + + static { + filter.add(new ColorPredicate(ObjectColor.BLACK)); + filter.add(new ControllerPredicate(TargetController.OPPONENT)); + } + + public RadiantEssence(UUID ownerId) { + super(ownerId, 336, "Radiant Essence", Rarity.UNCOMMON, new CardType[]{CardType.CREATURE}, "{1}{G}{W}"); + this.expansionSetCode = "MIR"; + this.subtype.add("Spirit"); + this.power = new MageInt(2); + this.toughness = new MageInt(3); + + // Radiant Essence gets +1/+2 as long as an opponent controls a black permanent. + this.addAbility(new SimpleStaticAbility(Zone.BATTLEFIELD, + new ConditionalContinuousEffect(new BoostSourceEffect(1, 2, Duration.WhileOnBattlefield), + new PermanentsOnTheBattlefieldCondition(filter, CountType.MORE_THAN, 0, false), + "{this} gets +1/+2 as long as an opponent controls a black permanent"))); + } + + public RadiantEssence(final RadiantEssence card) { + super(card); + } + + @Override + public RadiantEssence copy() { + return new RadiantEssence(this); + } +} From a0448c216a70be7d9934a1380a3afb7fa33ffc9f Mon Sep 17 00:00:00 2001 From: LoneFox Date: Tue, 22 Dec 2015 13:55:57 +0200 Subject: [PATCH 04/23] Implement cards: Alarum, Cadaverous Bloom, Canopy Dragon, and Rashida Scalebane --- Mage.Sets/src/mage/sets/mirage/Alarum.java | 75 ++++++++++++++++ .../src/mage/sets/mirage/CadaverousBloom.java | 64 +++++++++++++ .../src/mage/sets/mirage/CanopyDragon.java | 79 ++++++++++++++++ .../mage/sets/mirage/RashidaScalebane.java | 89 +++++++++++++++++++ 4 files changed, 307 insertions(+) create mode 100644 Mage.Sets/src/mage/sets/mirage/Alarum.java create mode 100644 Mage.Sets/src/mage/sets/mirage/CadaverousBloom.java create mode 100644 Mage.Sets/src/mage/sets/mirage/CanopyDragon.java create mode 100644 Mage.Sets/src/mage/sets/mirage/RashidaScalebane.java diff --git a/Mage.Sets/src/mage/sets/mirage/Alarum.java b/Mage.Sets/src/mage/sets/mirage/Alarum.java new file mode 100644 index 00000000000..4c46ad5acb5 --- /dev/null +++ b/Mage.Sets/src/mage/sets/mirage/Alarum.java @@ -0,0 +1,75 @@ +/* + * Copyright 2010 BetaSteward_at_googlemail.com. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are + * permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this list of + * conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, this list + * of conditions and the following disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY BetaSteward_at_googlemail.com ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BetaSteward_at_googlemail.com OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * The views and conclusions contained in the software and documentation are those of the + * authors and should not be interpreted as representing official policies, either expressed + * or implied, of BetaSteward_at_googlemail.com. + */ +package mage.sets.mirage; + +import java.util.UUID; +import mage.abilities.effects.Effect; +import mage.abilities.effects.common.UntapTargetEffect; +import mage.abilities.effects.common.continuous.BoostTargetEffect; +import mage.cards.CardImpl; +import mage.constants.CardType; +import mage.constants.Duration; +import mage.constants.Rarity; +import mage.filter.common.FilterCreaturePermanent; +import mage.filter.predicate.Predicates; +import mage.filter.predicate.permanent.AttackingPredicate; +import mage.target.common.TargetCreaturePermanent; + +/** + * + * @author LoneFox + */ +public class Alarum extends CardImpl { + + private static final FilterCreaturePermanent filter = new FilterCreaturePermanent("nonattacking creature"); + + static { + filter.add(Predicates.not(new AttackingPredicate())); + } + + public Alarum(UUID ownerId) { + super(ownerId, 206, "Alarum", Rarity.COMMON, new CardType[]{CardType.INSTANT}, "{1}{W}"); + this.expansionSetCode = "MIR"; + + // Untap target nonattacking creature. It gets +1/+3 until end of turn. + this.getSpellAbility().addEffect(new UntapTargetEffect()); + Effect effect = new BoostTargetEffect(1, 3, Duration.EndOfTurn); + effect.setText("It gets +1/+3 until end of turn"); + this.getSpellAbility().addEffect(effect); + this.getSpellAbility().addTarget(new TargetCreaturePermanent(filter)); + } + + public Alarum(final Alarum card) { + super(card); + } + + @Override + public Alarum copy() { + return new Alarum(this); + } +} diff --git a/Mage.Sets/src/mage/sets/mirage/CadaverousBloom.java b/Mage.Sets/src/mage/sets/mirage/CadaverousBloom.java new file mode 100644 index 00000000000..a866098f642 --- /dev/null +++ b/Mage.Sets/src/mage/sets/mirage/CadaverousBloom.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.sets.mirage; + +import java.util.UUID; +import mage.Mana; +import mage.abilities.costs.common.ExileFromHandCost; +import mage.abilities.mana.SimpleManaAbility; +import mage.cards.CardImpl; +import mage.constants.CardType; +import mage.constants.Rarity; +import mage.constants.Zone; +import mage.filter.common.FilterOwnedCard; +import mage.target.common.TargetCardInHand; + +/** + * + * @author LoneFox + */ +public class CadaverousBloom extends CardImpl { + + public CadaverousBloom(UUID ownerId) { + super(ownerId, 318, "Cadaverous Bloom", Rarity.RARE, new CardType[]{CardType.ENCHANTMENT}, "{3}{B}{G}"); + this.expansionSetCode = "MIR"; + + // Exile a card from your hand: Add {B}{B} or {G}{G} to your mana pool. + this.addAbility(new SimpleManaAbility(Zone.BATTLEFIELD, Mana.BlackMana(2), new ExileFromHandCost(new TargetCardInHand(new FilterOwnedCard("a card from your hand"))))); + this.addAbility(new SimpleManaAbility(Zone.BATTLEFIELD, Mana.GreenMana(2), new ExileFromHandCost(new TargetCardInHand(new FilterOwnedCard("a card from your hand"))))); + } + + public CadaverousBloom(final CadaverousBloom card) { + super(card); + } + + @Override + public CadaverousBloom copy() { + return new CadaverousBloom(this); + } +} diff --git a/Mage.Sets/src/mage/sets/mirage/CanopyDragon.java b/Mage.Sets/src/mage/sets/mirage/CanopyDragon.java new file mode 100644 index 00000000000..5a3d1782f2c --- /dev/null +++ b/Mage.Sets/src/mage/sets/mirage/CanopyDragon.java @@ -0,0 +1,79 @@ +/* + * 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.sets.mirage; + +import java.util.UUID; +import mage.MageInt; +import mage.abilities.Ability; +import mage.abilities.common.SimpleActivatedAbility; +import mage.abilities.costs.mana.ManaCostsImpl; +import mage.abilities.effects.Effect; +import mage.abilities.effects.common.continuous.GainAbilitySourceEffect; +import mage.abilities.effects.common.continuous.LoseAbilitySourceEffect; +import mage.abilities.keyword.FlyingAbility; +import mage.abilities.keyword.TrampleAbility; +import mage.cards.CardImpl; +import mage.constants.CardType; +import mage.constants.Duration; +import mage.constants.Rarity; +import mage.constants.Zone; + +/** + * + * @author LoneFox + */ +public class CanopyDragon extends CardImpl { + + public CanopyDragon(UUID ownerId) { + super(ownerId, 107, "Canopy Dragon", Rarity.RARE, new CardType[]{CardType.CREATURE}, "{4}{G}{G}"); + this.expansionSetCode = "MIR"; + this.subtype.add("Dragon"); + this.power = new MageInt(4); + this.toughness = new MageInt(4); + + // Trample + this.addAbility(TrampleAbility.getInstance()); + // {1}{G}: Canopy Dragon gains flying and loses trample until end of turn. + Effect effect = new GainAbilitySourceEffect(FlyingAbility.getInstance(), Duration.EndOfTurn); + effect.setText("{this} gains flying"); + Ability ability = new SimpleActivatedAbility(Zone.BATTLEFIELD, effect, new ManaCostsImpl("{1}{G}")); + effect = new LoseAbilitySourceEffect(TrampleAbility.getInstance(), Duration.EndOfTurn); + effect.setText("and loses trample until end of turn"); + ability.addEffect(effect); + this.addAbility(ability); + } + + public CanopyDragon(final CanopyDragon card) { + super(card); + } + + @Override + public CanopyDragon copy() { + return new CanopyDragon(this); + } +} diff --git a/Mage.Sets/src/mage/sets/mirage/RashidaScalebane.java b/Mage.Sets/src/mage/sets/mirage/RashidaScalebane.java new file mode 100644 index 00000000000..e2f30df060f --- /dev/null +++ b/Mage.Sets/src/mage/sets/mirage/RashidaScalebane.java @@ -0,0 +1,89 @@ +/* + * Copyright 2010 BetaSteward_at_googlemail.com. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are + * permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this list of + * conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, this list + * of conditions and the following disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY BetaSteward_at_googlemail.com ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BetaSteward_at_googlemail.com OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * The views and conclusions contained in the software and documentation are those of the + * authors and should not be interpreted as representing official policies, either expressed + * or implied, of BetaSteward_at_googlemail.com. + */ +package mage.sets.mirage; + +import java.util.UUID; +import mage.MageInt; +import mage.abilities.Ability; +import mage.abilities.common.SimpleActivatedAbility; +import mage.abilities.costs.common.TapSourceCost; +import mage.abilities.dynamicvalue.common.TargetPermanentPowerCount; +import mage.abilities.effects.Effect; +import mage.abilities.effects.common.DestroyTargetEffect; +import mage.abilities.effects.common.GainLifeEffect; +import mage.cards.CardImpl; +import mage.constants.CardType; +import mage.constants.Rarity; +import mage.constants.Zone; +import mage.filter.common.FilterCreaturePermanent; +import mage.filter.predicate.Predicates; +import mage.filter.predicate.mageobject.SubtypePredicate; +import mage.filter.predicate.permanent.AttackingPredicate; +import mage.filter.predicate.permanent.BlockingPredicate; +import mage.target.common.TargetCreaturePermanent; + +/** + * + * @author LoneFox + */ +public class RashidaScalebane extends CardImpl { + + private static final FilterCreaturePermanent filter = new FilterCreaturePermanent("attacking or blocking Dragon"); + + static { + filter.add(Predicates.or(new AttackingPredicate(), new BlockingPredicate())); + filter.add(new SubtypePredicate("Dragon")); + } + + public RashidaScalebane(UUID ownerId) { + super(ownerId, 239, "Rashida Scalebane", Rarity.RARE, new CardType[]{CardType.CREATURE}, "{3}{W}{W}"); + this.expansionSetCode = "MIR"; + this.supertype.add("Legendary"); + this.subtype.add("Human"); + this.subtype.add("Soldier"); + this.power = new MageInt(3); + this.toughness = new MageInt(4); + + // {tap}: Destroy target attacking or blocking Dragon. It can't be regenerated. You gain life equal to its power. + Ability ability = new SimpleActivatedAbility(Zone.BATTLEFIELD, new DestroyTargetEffect(true), new TapSourceCost()); + Effect effect = new GainLifeEffect(new TargetPermanentPowerCount()); + effect.setText("You gain life equal to its power"); + ability.addEffect(effect); + ability.addTarget(new TargetCreaturePermanent(filter)); + this.addAbility(ability); + } + + public RashidaScalebane(final RashidaScalebane card) { + super(card); + } + + @Override + public RashidaScalebane copy() { + return new RashidaScalebane(this); + } +} From d2aaba5deec1e858b1bf0439b8c50245a3550cf0 Mon Sep 17 00:00:00 2001 From: LoneFox Date: Tue, 22 Dec 2015 21:01:55 +0200 Subject: [PATCH 05/23] Implement cards: Greel's Caress, Jolrael's Favor, Rhystic Tutor, and Wild Might --- .../src/mage/sets/prophecy/GreelsCaress.java | 77 ++++++++++++++++++ .../src/mage/sets/prophecy/JolraelsFavor.java | 78 +++++++++++++++++++ .../src/mage/sets/prophecy/RhysticTutor.java | 64 +++++++++++++++ .../src/mage/sets/prophecy/WildMight.java | 67 ++++++++++++++++ 4 files changed, 286 insertions(+) create mode 100644 Mage.Sets/src/mage/sets/prophecy/GreelsCaress.java create mode 100644 Mage.Sets/src/mage/sets/prophecy/JolraelsFavor.java create mode 100644 Mage.Sets/src/mage/sets/prophecy/RhysticTutor.java create mode 100644 Mage.Sets/src/mage/sets/prophecy/WildMight.java diff --git a/Mage.Sets/src/mage/sets/prophecy/GreelsCaress.java b/Mage.Sets/src/mage/sets/prophecy/GreelsCaress.java new file mode 100644 index 00000000000..756e8a36c99 --- /dev/null +++ b/Mage.Sets/src/mage/sets/prophecy/GreelsCaress.java @@ -0,0 +1,77 @@ +/* + * 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.sets.prophecy; + +import java.util.UUID; +import mage.abilities.Ability; +import mage.abilities.common.SimpleStaticAbility; +import mage.abilities.effects.common.AttachEffect; +import mage.abilities.effects.common.continuous.BoostEnchantedEffect; +import mage.abilities.keyword.EnchantAbility; +import mage.abilities.keyword.FlashAbility; +import mage.cards.CardImpl; +import mage.constants.CardType; +import mage.constants.Duration; +import mage.constants.Outcome; +import mage.constants.Rarity; +import mage.constants.Zone; +import mage.target.TargetPermanent; +import mage.target.common.TargetCreaturePermanent; + +/** + * + * @author LoneFox + */ +public class GreelsCaress extends CardImpl { + + public GreelsCaress(UUID ownerId) { + super(ownerId, 67, "Greel's Caress", Rarity.COMMON, new CardType[]{CardType.ENCHANTMENT}, "{1}{B}"); + this.expansionSetCode = "PCY"; + this.subtype.add("Aura"); + + // Flash + this.addAbility(FlashAbility.getInstance()); + // Enchant creature + TargetPermanent auraTarget = new TargetCreaturePermanent(); + this.getSpellAbility().addTarget(auraTarget); + this.getSpellAbility().addEffect(new AttachEffect(Outcome.UnboostCreature)); + Ability ability = new EnchantAbility(auraTarget.getTargetName()); + this.addAbility(ability); + // Enchanted creature gets -3/-0. + this.addAbility(new SimpleStaticAbility(Zone.BATTLEFIELD, new BoostEnchantedEffect(-3, 0, Duration.WhileOnBattlefield))); + } + + public GreelsCaress(final GreelsCaress card) { + super(card); + } + + @Override + public GreelsCaress copy() { + return new GreelsCaress(this); + } +} diff --git a/Mage.Sets/src/mage/sets/prophecy/JolraelsFavor.java b/Mage.Sets/src/mage/sets/prophecy/JolraelsFavor.java new file mode 100644 index 00000000000..9545288822a --- /dev/null +++ b/Mage.Sets/src/mage/sets/prophecy/JolraelsFavor.java @@ -0,0 +1,78 @@ +/* + * 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.sets.prophecy; + +import java.util.UUID; +import mage.abilities.Ability; +import mage.abilities.common.SimpleActivatedAbility; +import mage.abilities.costs.mana.ManaCostsImpl; +import mage.abilities.effects.common.AttachEffect; +import mage.abilities.effects.common.RegenerateAttachedEffect; +import mage.abilities.keyword.EnchantAbility; +import mage.abilities.keyword.FlashAbility; +import mage.cards.CardImpl; +import mage.constants.AttachmentType; +import mage.constants.CardType; +import mage.constants.Outcome; +import mage.constants.Rarity; +import mage.constants.Zone; +import mage.target.TargetPermanent; +import mage.target.common.TargetCreaturePermanent; + +/** + * + * @author LoneFox + */ +public class JolraelsFavor extends CardImpl { + + public JolraelsFavor(UUID ownerId) { + super(ownerId, 116, "Jolrael's Favor", Rarity.COMMON, new CardType[]{CardType.ENCHANTMENT}, "{1}{G}"); + this.expansionSetCode = "PCY"; + this.subtype.add("Aura"); + + // Flash + this.addAbility(FlashAbility.getInstance()); + // Enchant creature + TargetPermanent auraTarget = new TargetCreaturePermanent(); + this.getSpellAbility().addTarget(auraTarget); + this.getSpellAbility().addEffect(new AttachEffect(Outcome.AddAbility)); + Ability ability = new EnchantAbility(auraTarget.getTargetName()); + this.addAbility(ability); + // {1}{G}: Regenerate enchanted creature. + this.addAbility(new SimpleActivatedAbility(Zone.BATTLEFIELD, new RegenerateAttachedEffect(AttachmentType.AURA), new ManaCostsImpl("{1}{G}"))); + } + + public JolraelsFavor(final JolraelsFavor card) { + super(card); + } + + @Override + public JolraelsFavor copy() { + return new JolraelsFavor(this); + } +} diff --git a/Mage.Sets/src/mage/sets/prophecy/RhysticTutor.java b/Mage.Sets/src/mage/sets/prophecy/RhysticTutor.java new file mode 100644 index 00000000000..06fae9dc5b3 --- /dev/null +++ b/Mage.Sets/src/mage/sets/prophecy/RhysticTutor.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.sets.prophecy; + +import java.util.UUID; +import mage.abilities.costs.mana.ManaCostsImpl; +import mage.abilities.effects.Effect; +import mage.abilities.effects.common.DoUnlessAnyPlayerPaysEffect; +import mage.abilities.effects.common.search.SearchLibraryPutInHandEffect; +import mage.cards.CardImpl; +import mage.constants.CardType; +import mage.constants.Rarity; +import mage.target.common.TargetCardInLibrary; + +/** + * + * @author LoneFox + */ +public class RhysticTutor extends CardImpl { + + public RhysticTutor(UUID ownerId) { + super(ownerId, 77, "Rhystic Tutor", Rarity.RARE, new CardType[]{CardType.SORCERY}, "{2}{B}"); + this.expansionSetCode = "PCY"; + + // Unless any player pays {2}, search your library for a card, put that card into your hand, then shuffle your library. + Effect effect = new DoUnlessAnyPlayerPaysEffect(new SearchLibraryPutInHandEffect(new TargetCardInLibrary()), new ManaCostsImpl("{2}")); + effect.setText("Unless any player pays {2}, search your library for a card, put that card into your hand, then shuffle your library"); + this.getSpellAbility().addEffect(effect); + } + + public RhysticTutor(final RhysticTutor card) { + super(card); + } + + @Override + public RhysticTutor copy() { + return new RhysticTutor(this); + } +} diff --git a/Mage.Sets/src/mage/sets/prophecy/WildMight.java b/Mage.Sets/src/mage/sets/prophecy/WildMight.java new file mode 100644 index 00000000000..ae001569aea --- /dev/null +++ b/Mage.Sets/src/mage/sets/prophecy/WildMight.java @@ -0,0 +1,67 @@ +/* + * Copyright 2010 BetaSteward_at_googlemail.com. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are + * permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this list of + * conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, this list + * of conditions and the following disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY BetaSteward_at_googlemail.com ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BetaSteward_at_googlemail.com OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * The views and conclusions contained in the software and documentation are those of the + * authors and should not be interpreted as representing official policies, either expressed + * or implied, of BetaSteward_at_googlemail.com. + */ +package mage.sets.prophecy; + +import java.util.UUID; +import mage.abilities.costs.mana.ManaCostsImpl; +import mage.abilities.effects.Effect; +import mage.abilities.effects.common.DoUnlessAnyPlayerPaysEffect; +import mage.abilities.effects.common.continuous.BoostTargetEffect; +import mage.cards.CardImpl; +import mage.constants.CardType; +import mage.constants.Duration; +import mage.constants.Rarity; +import mage.target.common.TargetCreaturePermanent; + +/** + * + * @author LoneFox + */ +public class WildMight extends CardImpl { + + public WildMight(UUID ownerId) { + super(ownerId, 134, "Wild Might", Rarity.COMMON, new CardType[]{CardType.INSTANT}, "{1}{G}"); + this.expansionSetCode = "PCY"; + + // Target creature gets +1/+1 until end of turn. That creature gets an additional +4/+4 until end of turn unless any player pays {2}. + this.getSpellAbility().addEffect(new BoostTargetEffect(1, 1, Duration.EndOfTurn)); + Effect effect = new DoUnlessAnyPlayerPaysEffect(new BoostTargetEffect(4, 4, Duration.EndOfTurn), new ManaCostsImpl("{2}")); + effect.setText("That creature gets an additional +4/+4 until end of turn unless any player pays {2}"); + this.getSpellAbility().addEffect(effect); + this.getSpellAbility().addTarget(new TargetCreaturePermanent()); + } + + public WildMight(final WildMight card) { + super(card); + } + + @Override + public WildMight copy() { + return new WildMight(this); + } +} From e7b3cb66e05f6101118e7f56f8e2387e0c797e11 Mon Sep 17 00:00:00 2001 From: LevelX2 Date: Wed, 23 Dec 2015 15:23:13 +0100 Subject: [PATCH 06/23] * Colorless Mana - Added logic to be able to pay colorless mana (not generic mana). --- .../mage/abilities/costs/mana/ManaCostsImpl.java | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/Mage/src/main/java/mage/abilities/costs/mana/ManaCostsImpl.java b/Mage/src/main/java/mage/abilities/costs/mana/ManaCostsImpl.java index b3c987cf3a6..579c0b4bd90 100644 --- a/Mage/src/main/java/mage/abilities/costs/mana/ManaCostsImpl.java +++ b/Mage/src/main/java/mage/abilities/costs/mana/ManaCostsImpl.java @@ -224,7 +224,17 @@ public class ManaCostsImpl extends ArrayList implements M // if auto payment is inactive and no mana type was clicked manually - do nothing return; } - + // attempt to pay colorless costs (not generic) mana costs first + if (pool.getColorless() > 0) { + for (ManaCost cost : this) { + if (!cost.isPaid() && cost instanceof ColorlessManaCost) { + cost.assignPayment(game, ability, pool); + if (pool.count() == 0) { + return; + } + } + } + } //attempt to pay colored costs first for (ManaCost cost : this) { if (!cost.isPaid() && cost instanceof ColoredManaCost) { From c83f906525561dd1802ab7d9e69f31369aaaeac0 Mon Sep 17 00:00:00 2001 From: LevelX2 Date: Wed, 23 Dec 2015 16:38:56 +0100 Subject: [PATCH 07/23] * Fixed some cards doing preventable non combat damage but handled the damage wrongly as non preventable combat damage. --- .../betrayersofkamigawa/ShiningShoal.java | 7 +- .../src/mage/sets/conflux/Meglonoth.java | 4 +- .../mage/sets/dragonsmaze/MorgueBurst.java | 2 +- .../sets/dragonsmaze/TeysaEnvoyOfGhosts.java | 19 +-- .../sets/fifthedition/BottleOfSuleiman.java | 7 +- .../journeyintonyx/DictateOfTheTwinGods.java | 15 +-- .../src/mage/sets/odyssey/BlazingSalvo.java | 24 ++-- .../sets/riseoftheeldrazi/SarkhanTheMad.java | 2 +- .../sets/shardsofalara/FlameblastDragon.java | 4 +- .../mage/sets/worldwake/RefractionTrap.java | 27 ++-- .../cards/enchantments/AnimateDeadTest.java | 124 ++++++++++++++++++ 11 files changed, 178 insertions(+), 57 deletions(-) create mode 100644 Mage.Tests/src/test/java/org/mage/test/cards/enchantments/AnimateDeadTest.java diff --git a/Mage.Sets/src/mage/sets/betrayersofkamigawa/ShiningShoal.java b/Mage.Sets/src/mage/sets/betrayersofkamigawa/ShiningShoal.java index 49691c16633..7d22efc7665 100644 --- a/Mage.Sets/src/mage/sets/betrayersofkamigawa/ShiningShoal.java +++ b/Mage.Sets/src/mage/sets/betrayersofkamigawa/ShiningShoal.java @@ -45,6 +45,7 @@ import mage.filter.predicate.Predicates; import mage.filter.predicate.mageobject.CardIdPredicate; import mage.filter.predicate.mageobject.ColorPredicate; import mage.game.Game; +import mage.game.events.DamageEvent; import mage.game.events.GameEvent; import mage.game.permanent.Permanent; import mage.players.Player; @@ -63,7 +64,6 @@ public class ShiningShoal extends CardImpl { this.expansionSetCode = "BOK"; this.subtype.add("Arcane"); - // You may exile a white card with converted mana cost X from your hand rather than pay Shining Shoal's mana cost FilterOwnedCard filter = new FilterOwnedCard("a white card with converted mana cost X from your hand"); filter.add(new ColorPredicate(ObjectColor.WHITE)); @@ -86,7 +86,6 @@ public class ShiningShoal extends CardImpl { } } - class ShiningShoalPreventDamageTargetEffect extends PreventionEffectImpl { private final DynamicValue dynamicAmount; @@ -145,13 +144,13 @@ class ShiningShoalPreventDamageTargetEffect extends PreventionEffectImpl { if (permanent != null) { game.informPlayers("Dealing " + prevented + " to " + permanent.getName() + " instead"); // keep the original source id as it is redirecting - permanent.damage(prevented, event.getSourceId(), game, false, true, event.getAppliedEffects()); + permanent.damage(prevented, event.getSourceId(), game, ((DamageEvent) event).isCombatDamage(), ((DamageEvent) event).isPreventable(), event.getAppliedEffects()); } Player player = game.getPlayer(redirectTo); if (player != null) { game.informPlayers("Dealing " + prevented + " to " + player.getLogName() + " instead"); // keep the original source id as it is redirecting - player.damage(prevented, event.getSourceId(), game, true, false, event.getAppliedEffects()); + player.damage(prevented, event.getSourceId(), game, ((DamageEvent) event).isCombatDamage(), ((DamageEvent) event).isPreventable(), event.getAppliedEffects()); } } } diff --git a/Mage.Sets/src/mage/sets/conflux/Meglonoth.java b/Mage.Sets/src/mage/sets/conflux/Meglonoth.java index f08a09a9dd3..9c9dee08824 100644 --- a/Mage.Sets/src/mage/sets/conflux/Meglonoth.java +++ b/Mage.Sets/src/mage/sets/conflux/Meglonoth.java @@ -32,8 +32,8 @@ import mage.MageInt; import mage.abilities.Ability; import mage.abilities.common.BlocksCreatureTriggeredAbility; import mage.abilities.effects.OneShotEffect; -import mage.abilities.keyword.VigilanceAbility; import mage.abilities.keyword.TrampleAbility; +import mage.abilities.keyword.VigilanceAbility; import mage.cards.CardImpl; import mage.constants.CardType; import mage.constants.Outcome; @@ -97,7 +97,7 @@ class MeglonothEffect extends OneShotEffect { Permanent meglonoth = game.getPermanent(source.getSourceId()); Permanent blocked = game.getPermanent(targetPointer.getFirst(game, source)); if (blocked != null && meglonoth != null) { - game.getPlayer(blocked.getControllerId()).damage(meglonoth.getPower().getValue(), id, game, true, false); + game.getPlayer(blocked.getControllerId()).damage(meglonoth.getPower().getValue(), id, game, false, true); return true; } return false; diff --git a/Mage.Sets/src/mage/sets/dragonsmaze/MorgueBurst.java b/Mage.Sets/src/mage/sets/dragonsmaze/MorgueBurst.java index 43f7b05fb55..7dba8718912 100644 --- a/Mage.Sets/src/mage/sets/dragonsmaze/MorgueBurst.java +++ b/Mage.Sets/src/mage/sets/dragonsmaze/MorgueBurst.java @@ -100,7 +100,7 @@ class MorgueBurstEffect extends OneShotEffect { } Player targetPlayer = game.getPlayer(source.getTargets().get(1).getTargets().get(0)); if (targetPlayer != null) { - targetPlayer.damage(damage, source.getSourceId(), game, true, false); + targetPlayer.damage(damage, source.getSourceId(), game, false, true); return true; } } diff --git a/Mage.Sets/src/mage/sets/dragonsmaze/TeysaEnvoyOfGhosts.java b/Mage.Sets/src/mage/sets/dragonsmaze/TeysaEnvoyOfGhosts.java index bab770d4b87..87e35e9fb83 100644 --- a/Mage.Sets/src/mage/sets/dragonsmaze/TeysaEnvoyOfGhosts.java +++ b/Mage.Sets/src/mage/sets/dragonsmaze/TeysaEnvoyOfGhosts.java @@ -28,9 +28,6 @@ package mage.sets.dragonsmaze; import java.util.UUID; - -import mage.constants.CardType; -import mage.constants.Rarity; import mage.MageInt; import mage.abilities.TriggeredAbilityImpl; import mage.abilities.effects.common.CreateTokenEffect; @@ -39,6 +36,8 @@ import mage.abilities.keyword.FlyingAbility; import mage.abilities.keyword.ProtectionAbility; import mage.abilities.keyword.VigilanceAbility; import mage.cards.CardImpl; +import mage.constants.CardType; +import mage.constants.Rarity; import mage.constants.Zone; import mage.filter.common.FilterCreaturePermanent; import mage.game.Game; @@ -69,7 +68,7 @@ public class TeysaEnvoyOfGhosts extends CardImpl { // protection from creatures this.addAbility(new ProtectionAbility(new FilterCreaturePermanent("creatures"))); // Whenever a creature deals combat damage to you, destroy that creature. Put a 1/1 white and black Spirit creature token with flying onto the battlefield. - this.addAbility(new TeysaEnvoyOfGhostsTriggeredAbility()); + this.addAbility(new TeysaEnvoyOfGhostsTriggeredAbility()); } @@ -89,7 +88,7 @@ class TeysaEnvoyOfGhostsTriggeredAbility extends TriggeredAbilityImpl { super(Zone.BATTLEFIELD, new DestroyTargetEffect()); this.addEffect(new CreateTokenEffect(new TeysaEnvoyOfGhostsToken(), 1)); - } + } public TeysaEnvoyOfGhostsTriggeredAbility(final TeysaEnvoyOfGhostsTriggeredAbility ability) { super(ability); @@ -104,12 +103,15 @@ class TeysaEnvoyOfGhostsTriggeredAbility extends TriggeredAbilityImpl { public boolean checkEventType(GameEvent event, Game game) { return event.getType() == GameEvent.EventType.DAMAGED_PLAYER; } - + @Override public boolean checkTrigger(GameEvent event, Game game) { - DamagedPlayerEvent damageEvent = (DamagedPlayerEvent)event; + DamagedPlayerEvent damageEvent = (DamagedPlayerEvent) event; Permanent sourcePermanent = game.getPermanent(event.getSourceId()); - if (damageEvent.getPlayerId().equals(getControllerId()) && damageEvent.isCombatDamage() && sourcePermanent != null && sourcePermanent.getCardType().contains(CardType.CREATURE)) { + if (damageEvent.getPlayerId().equals(getControllerId()) + && damageEvent.isCombatDamage() + && sourcePermanent != null + && sourcePermanent.getCardType().contains(CardType.CREATURE)) { game.getState().setValue(sourceId.toString(), sourcePermanent.getControllerId()); getEffects().get(0).setTargetPointer(new FixedTarget(event.getSourceId())); return true; @@ -125,6 +127,7 @@ class TeysaEnvoyOfGhostsTriggeredAbility extends TriggeredAbilityImpl { } class TeysaEnvoyOfGhostsToken extends Token { + TeysaEnvoyOfGhostsToken() { super("Spirit", "1/1 white and black Spirit creature token with flying"); cardType.add(CardType.CREATURE); diff --git a/Mage.Sets/src/mage/sets/fifthedition/BottleOfSuleiman.java b/Mage.Sets/src/mage/sets/fifthedition/BottleOfSuleiman.java index 8a7b988e7d2..37265808eac 100644 --- a/Mage.Sets/src/mage/sets/fifthedition/BottleOfSuleiman.java +++ b/Mage.Sets/src/mage/sets/fifthedition/BottleOfSuleiman.java @@ -44,7 +44,6 @@ import mage.game.Game; import mage.game.permanent.token.Token; import mage.players.Player; import mage.MageInt; -import mage.ObjectColor; /** * @@ -76,7 +75,7 @@ class BottleOfSuleimanEffect extends OneShotEffect { public BottleOfSuleimanEffect() { super(Outcome.PutCreatureInPlay); - staticText = "Flip a coin. If you lose the flip, Bottle of Suleiman deals 5 damage to you. If you win the flip, put a 5/5 colorless Djinn artifact creature token with flying onto the battlefield."; + staticText = "Flip a coin. If you lose the flip, {this} deals 5 damage to you. If you win the flip, put a 5/5 colorless Djinn artifact creature token with flying onto the battlefield."; } public BottleOfSuleimanEffect(final BottleOfSuleimanEffect effect) { @@ -97,7 +96,7 @@ class BottleOfSuleimanEffect extends OneShotEffect { token.putOntoBattlefield(1, game, source.getSourceId(), source.getControllerId()); return true; } else { - you.damage(5, source.getSourceId(), game, true, false); + you.damage(5, source.getSourceId(), game, false, true); return true; } @@ -117,4 +116,4 @@ class DjinnToken extends Token { toughness = new MageInt(5); addAbility(FlyingAbility.getInstance()); } -} \ No newline at end of file +} diff --git a/Mage.Sets/src/mage/sets/journeyintonyx/DictateOfTheTwinGods.java b/Mage.Sets/src/mage/sets/journeyintonyx/DictateOfTheTwinGods.java index 3dff0c98a2a..9e8d4b90440 100644 --- a/Mage.Sets/src/mage/sets/journeyintonyx/DictateOfTheTwinGods.java +++ b/Mage.Sets/src/mage/sets/journeyintonyx/DictateOfTheTwinGods.java @@ -57,12 +57,11 @@ public class DictateOfTheTwinGods extends CardImpl { super(ownerId, 93, "Dictate of the Twin Gods", Rarity.RARE, new CardType[]{CardType.ENCHANTMENT}, "{3}{R}{R}"); this.expansionSetCode = "JOU"; - // Flash this.addAbility(FlashAbility.getInstance()); // If a source would deal damage to a permanent or player, it deals double that damage to that permanent or player instead. this.addAbility(new SimpleStaticAbility(Zone.BATTLEFIELD, new DictateOfTheTwinGodsEffect())); - + } public DictateOfTheTwinGods(final DictateOfTheTwinGods card) { @@ -91,9 +90,9 @@ class DictateOfTheTwinGodsEffect extends ReplacementEffectImpl { return new DictateOfTheTwinGodsEffect(this); } - @Override + @Override public boolean checksEventType(GameEvent event, Game game) { - switch(event.getType()) { + switch (event.getType()) { case DAMAGE_CREATURE: case DAMAGE_PLAYER: case DAMAGE_PLANESWALKER: @@ -102,7 +101,7 @@ class DictateOfTheTwinGodsEffect extends ReplacementEffectImpl { return false; } } - + @Override public boolean applies(GameEvent event, Ability source, Game game) { return true; @@ -115,17 +114,17 @@ class DictateOfTheTwinGodsEffect extends ReplacementEffectImpl { @Override public boolean replaceEvent(GameEvent event, Ability source, Game game) { - DamageEvent damageEvent = (DamageEvent)event; + DamageEvent damageEvent = (DamageEvent) event; if (damageEvent.getType() == EventType.DAMAGE_PLAYER) { Player targetPlayer = game.getPlayer(event.getTargetId()); if (targetPlayer != null) { - targetPlayer.damage(damageEvent.getAmount()*2, damageEvent.getSourceId(), game, damageEvent.isPreventable(), damageEvent.isCombatDamage(), event.getAppliedEffects()); + targetPlayer.damage(damageEvent.getAmount() * 2, damageEvent.getSourceId(), game, damageEvent.isCombatDamage(), damageEvent.isPreventable(), event.getAppliedEffects()); return true; } } else { Permanent targetPermanent = game.getPermanent(event.getTargetId()); if (targetPermanent != null) { - targetPermanent.damage(damageEvent.getAmount()*2, damageEvent.getSourceId(), game, damageEvent.isCombatDamage(), damageEvent.isPreventable(), event.getAppliedEffects()); + targetPermanent.damage(damageEvent.getAmount() * 2, damageEvent.getSourceId(), game, damageEvent.isCombatDamage(), damageEvent.isPreventable(), event.getAppliedEffects()); return true; } } diff --git a/Mage.Sets/src/mage/sets/odyssey/BlazingSalvo.java b/Mage.Sets/src/mage/sets/odyssey/BlazingSalvo.java index 8a464d86701..55d43940f33 100644 --- a/Mage.Sets/src/mage/sets/odyssey/BlazingSalvo.java +++ b/Mage.Sets/src/mage/sets/odyssey/BlazingSalvo.java @@ -49,7 +49,6 @@ public class BlazingSalvo extends CardImpl { super(ownerId, 178, "Blazing Salvo", Rarity.COMMON, new CardType[]{CardType.INSTANT}, "{R}"); this.expansionSetCode = "ODY"; - // Blazing Salvo deals 3 damage to target creature unless that creature's controller has Blazing Salvo deal 5 damage to him or her. this.getSpellAbility().addTarget(new TargetCreaturePermanent()); this.getSpellAbility().addEffect(new BlazingSalvoEffect()); @@ -66,16 +65,16 @@ public class BlazingSalvo extends CardImpl { } class BlazingSalvoEffect extends OneShotEffect { - + public BlazingSalvoEffect() { super(Outcome.Damage); - this.staticText = "Blazing Salvo deals 3 damage to target creature unless that creature's controller has Blazing Salvo deal 5 damage to him or her"; + this.staticText = "{this} deals 3 damage to target creature unless that creature's controller has {this} deal 5 damage to him or her"; } - - public BlazingSalvoEffect(final BlazingSalvoEffect effect){ + + public BlazingSalvoEffect(final BlazingSalvoEffect effect) { super(effect); } - + @Override public BlazingSalvoEffect copy() { return new BlazingSalvoEffect(this); @@ -88,16 +87,15 @@ class BlazingSalvoEffect extends OneShotEffect { Player player = game.getPlayer(permanent.getControllerId()); if (player != null) { String message = "Have Blazing Salvo do 5 damage to you?"; - if (player.chooseUse(Outcome.Damage, message, source, game)){ - player.damage(5, source.getSourceId(), game, true, false); + if (player.chooseUse(Outcome.Damage, message, source, game)) { + player.damage(5, source.getSourceId(), game, false, true); } else { permanent.damage(3, source.getSourceId(), game, false, true); } - return true; - } - } + return true; + } + } return false; - } + } } - diff --git a/Mage.Sets/src/mage/sets/riseoftheeldrazi/SarkhanTheMad.java b/Mage.Sets/src/mage/sets/riseoftheeldrazi/SarkhanTheMad.java index 8252432060e..f106c098c41 100644 --- a/Mage.Sets/src/mage/sets/riseoftheeldrazi/SarkhanTheMad.java +++ b/Mage.Sets/src/mage/sets/riseoftheeldrazi/SarkhanTheMad.java @@ -182,7 +182,7 @@ class SarkhanTheMadDragonDamageEffect extends OneShotEffect { Player player = game.getPlayer(source.getTargets().getFirstTarget()); if (player != null && dragons != null && !dragons.isEmpty()) { for (Permanent dragon : dragons) { - player.damage(dragon.getPower().getValue(), dragon.getId(), game, true, false); + player.damage(dragon.getPower().getValue(), dragon.getId(), game, false, true); } return true; } diff --git a/Mage.Sets/src/mage/sets/shardsofalara/FlameblastDragon.java b/Mage.Sets/src/mage/sets/shardsofalara/FlameblastDragon.java index 4b364427ca4..e2571f54389 100644 --- a/Mage.Sets/src/mage/sets/shardsofalara/FlameblastDragon.java +++ b/Mage.Sets/src/mage/sets/shardsofalara/FlameblastDragon.java @@ -25,7 +25,6 @@ * authors and should not be interpreted as representing official policies, either expressed * or implied, of BetaSteward_at_googlemail.com. */ - package mage.sets.shardsofalara; import java.util.UUID; @@ -78,6 +77,7 @@ public class FlameblastDragon extends CardImpl { } class FlameblastDragonEffect extends OneShotEffect { + FlameblastDragonEffect() { super(Outcome.Benefit); staticText = "you may pay {X}{R}. If you do, {this} deals X damage to target creature or player"; @@ -103,7 +103,7 @@ class FlameblastDragonEffect extends OneShotEffect { } Player targetPlayer = game.getPlayer(source.getFirstTarget()); if (targetPlayer != null) { - targetPlayer.damage(costX, source.getSourceId(), game, true, false); + targetPlayer.damage(costX, source.getSourceId(), game, false, true); return true; } return false; diff --git a/Mage.Sets/src/mage/sets/worldwake/RefractionTrap.java b/Mage.Sets/src/mage/sets/worldwake/RefractionTrap.java index de636931bd9..0b00752ac28 100644 --- a/Mage.Sets/src/mage/sets/worldwake/RefractionTrap.java +++ b/Mage.Sets/src/mage/sets/worldwake/RefractionTrap.java @@ -30,9 +30,6 @@ package mage.sets.worldwake; import java.util.HashSet; import java.util.Set; import java.util.UUID; - -import mage.constants.CardType; -import mage.constants.Rarity; import mage.MageObject; import mage.abilities.Ability; import mage.abilities.costs.AlternativeCostImpl; @@ -41,8 +38,10 @@ import mage.abilities.costs.mana.ManaCostsImpl; import mage.abilities.effects.PreventionEffectData; import mage.abilities.effects.PreventionEffectImpl; import mage.cards.CardImpl; +import mage.constants.CardType; import mage.constants.Duration; import mage.constants.Outcome; +import mage.constants.Rarity; import mage.constants.WatcherScope; import mage.game.Game; import mage.game.events.GameEvent; @@ -65,7 +64,6 @@ public class RefractionTrap extends CardImpl { this.expansionSetCode = "WWK"; this.subtype.add("Trap"); - // If an opponent cast a red instant or sorcery spell this turn, you may pay {W} rather than pay Refraction Trap's mana cost. this.getSpellAbility().addAlternativeCost(new RefractionTrapAlternativeCost()); @@ -89,7 +87,7 @@ public class RefractionTrap extends CardImpl { class RefractionTrapWatcher extends Watcher { Set playersMetCondition = new HashSet<>(); - + public RefractionTrapWatcher() { super("RefractionTrapWatcher", WatcherScope.GAME); } @@ -120,19 +118,20 @@ class RefractionTrapWatcher extends Watcher { public boolean conditionMetForAnOpponent(UUID controllerId, Game game) { Player controller = game.getPlayer(controllerId); if (controller != null) { - for(UUID playerId: playersMetCondition) { + for (UUID playerId : playersMetCondition) { if (controller.hasOpponent(playerId, game)) { return true; } } } return false; - + } + @Override public void reset() { playersMetCondition.clear(); - super.reset(); + super.reset(); } } @@ -179,20 +178,20 @@ class RefractionTrapPreventDamageEffect extends PreventionEffectImpl { public RefractionTrapPreventDamageEffect(final RefractionTrapPreventDamageEffect effect) { super(effect); this.amount = effect.amount; - this.target = effect.target.copy(); + this.target = effect.target.copy(); } @Override public RefractionTrapPreventDamageEffect copy() { return new RefractionTrapPreventDamageEffect(this); } - + @Override public void init(Ability source, Game game) { this.target.choose(Outcome.PreventDamage, source.getControllerId(), source.getSourceId(), game); super.init(source, game); } - + @Override public boolean apply(Game game, Ability source) { return true; @@ -213,7 +212,7 @@ class RefractionTrapPreventDamageEffect extends PreventionEffectImpl { Player player = game.getPlayer(damageTarget); if (player != null) { game.informPlayers("Dealing " + preventionData.getPreventedDamage() + " to " + player.getLogName()); - player.damage(preventionData.getPreventedDamage(), source.getSourceId(), game, true, false); + player.damage(preventionData.getPreventedDamage(), source.getSourceId(), game, false, true); } } @@ -231,8 +230,8 @@ class RefractionTrapPreventDamageEffect extends PreventionEffectImpl { } // check damage source - if (!object.getId().equals(target.getFirstTarget()) && - !((object instanceof StackObject) && ((StackObject)object).getSourceId().equals(target.getFirstTarget()))) { + if (!object.getId().equals(target.getFirstTarget()) + && !((object instanceof StackObject) && ((StackObject) object).getSourceId().equals(target.getFirstTarget()))) { return false; } diff --git a/Mage.Tests/src/test/java/org/mage/test/cards/enchantments/AnimateDeadTest.java b/Mage.Tests/src/test/java/org/mage/test/cards/enchantments/AnimateDeadTest.java new file mode 100644 index 00000000000..f20ab00356a --- /dev/null +++ b/Mage.Tests/src/test/java/org/mage/test/cards/enchantments/AnimateDeadTest.java @@ -0,0 +1,124 @@ +/* + * Copyright 2010 BetaSteward_at_googlemail.com. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are + * permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this list of + * conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, this list + * of conditions and the following disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY BetaSteward_at_googlemail.com ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BetaSteward_at_googlemail.com OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * The views and conclusions contained in the software and documentation are those of the + * authors and should not be interpreted as representing official policies, either expressed + * or implied, of BetaSteward_at_googlemail.com. + */ +package org.mage.test.cards.enchantments; + +import mage.constants.PhaseStep; +import mage.constants.Zone; +import org.junit.Test; +import org.mage.test.serverside.base.CardTestPlayerBase; + +/** + * + * @author LevelX2 + */ +public class AnimateDeadTest extends CardTestPlayerBase { + + @Test + public void testAnimateOpponentsCreature() { + addCard(Zone.GRAVEYARD, playerB, "Silvercoat Lion", 1); + addCard(Zone.BATTLEFIELD, playerA, "Swamp", 2); + // Enchant creature card in a graveyard + // When Animate Dead enters the battlefield, if it's on the battlefield, it loses "enchant creature card in a graveyard" + // and gains "enchant creature put onto the battlefield with Animate Dead." Return enchanted creature card to the battlefield + // under your control and attach Animate Dead to it. When Animate Dead leaves the battlefield, that creature's controller sacrifices it. + // Enchanted creature gets -1/-0. + addCard(Zone.HAND, playerA, "Animate Dead"); // {1}{B} + + castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Animate Dead", "Silvercoat Lion"); + + setStopAt(1, PhaseStep.BEGIN_COMBAT); + execute(); + + assertPowerToughness(playerA, "Silvercoat Lion", 1, 2); + assertPermanentCount(playerA, "Animate Dead", 1); + } + + @Test + public void testAnimateEternalWitness() { + // When Eternal Witness enters the battlefield, you may return target card from your graveyard to your hand. + addCard(Zone.GRAVEYARD, playerB, "Eternal Witness", 1); + addCard(Zone.GRAVEYARD, playerA, "Silvercoat Lion", 1); + addCard(Zone.BATTLEFIELD, playerA, "Swamp", 2); + // Enchant creature card in a graveyard + // When Animate Dead enters the battlefield, if it's on the battlefield, it loses "enchant creature card in a graveyard" + // and gains "enchant creature put onto the battlefield with Animate Dead." Return enchanted creature card to the battlefield + // under your control and attach Animate Dead to it. When Animate Dead leaves the battlefield, that creature's controller sacrifices it. + // Enchanted creature gets -1/-0. + addCard(Zone.HAND, playerA, "Animate Dead"); // {1}{B} + + castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Animate Dead", "Eternal Witness"); + addTarget(playerA, "Silvercoat Lion"); + + setStopAt(1, PhaseStep.BEGIN_COMBAT); + execute(); + + assertPowerToughness(playerA, "Eternal Witness", 1, 1); + assertPermanentCount(playerA, "Animate Dead", 1); + assertHandCount(playerA, "Silvercoat Lion", 1); + } + + /** + * Buddy animated an Eternal Witness. I killed the Eternal Witness. Animate + * Dead stayed on the battlefield. Using Meren, Eternal Witness came back to + * the battlefield and immediately got enchanted by Animate Dead. + * + * Very weird. Animate Dead should've hit the graveyard the first time its + * creature died, right? + * + */ + @Test + public void testAnimateAndKillEternalWitness() { + // When Eternal Witness enters the battlefield, you may return target card from your graveyard to your hand. + addCard(Zone.GRAVEYARD, playerB, "Eternal Witness", 1); + addCard(Zone.BATTLEFIELD, playerB, "Mountain", 1); + addCard(Zone.HAND, playerB, "Lightning Bolt", 1); + + addCard(Zone.GRAVEYARD, playerA, "Silvercoat Lion", 1); + addCard(Zone.BATTLEFIELD, playerA, "Swamp", 2); + // Enchant creature card in a graveyard + // When Animate Dead enters the battlefield, if it's on the battlefield, it loses "enchant creature card in a graveyard" + // and gains "enchant creature put onto the battlefield with Animate Dead." Return enchanted creature card to the battlefield + // under your control and attach Animate Dead to it. When Animate Dead leaves the battlefield, that creature's controller sacrifices it. + // Enchanted creature gets -1/-0. + addCard(Zone.HAND, playerA, "Animate Dead"); // {1}{B} + + castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Animate Dead", "Eternal Witness"); + addTarget(playerA, "Silvercoat Lion"); + + castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerB, "Lightning Bolt", "Eternal Witness"); + + setStopAt(1, PhaseStep.BEGIN_COMBAT); + execute(); + + assertGraveyardCount(playerB, "Lightning Bolt", 1); + assertGraveyardCount(playerB, "Eternal Witness", 1); + assertHandCount(playerA, "Silvercoat Lion", 1); + assertGraveyardCount(playerA, "Animate Dead", 1); + assertPermanentCount(playerA, "Animate Dead", 0); + } +} From aecb2c88291f94bba22aa6cf1100d3b964510d1b Mon Sep 17 00:00:00 2001 From: LevelX2 Date: Thu, 24 Dec 2015 10:02:11 +0100 Subject: [PATCH 08/23] [OGW] Added surge and Crush of Tentacles. --- .../java/mage/server/game/GameWorker.java | 60 ++++++----- .../sets/avacynrestored/DevastationTide.java | 2 +- .../oathofthegatewatch/CrushOfTentacles.java | 86 ++++++++++++++++ .../cards/abilities/keywords/SurgeTest.java | 91 +++++++++++++++++ .../condition/common/SurgedCondition.java | 58 +++++++++++ .../mage/abilities/keyword/SurgeAbility.java | 99 +++++++++++++++++++ .../main/java/mage/constants/AbilityType.java | 3 +- 7 files changed, 365 insertions(+), 34 deletions(-) create mode 100644 Mage.Sets/src/mage/sets/oathofthegatewatch/CrushOfTentacles.java create mode 100644 Mage.Tests/src/test/java/org/mage/test/cards/abilities/keywords/SurgeTest.java create mode 100644 Mage/src/main/java/mage/abilities/condition/common/SurgedCondition.java create mode 100644 Mage/src/main/java/mage/abilities/keyword/SurgeAbility.java diff --git a/Mage.Server/src/main/java/mage/server/game/GameWorker.java b/Mage.Server/src/main/java/mage/server/game/GameWorker.java index 50ec2f75b95..e36dce24b21 100644 --- a/Mage.Server/src/main/java/mage/server/game/GameWorker.java +++ b/Mage.Server/src/main/java/mage/server/game/GameWorker.java @@ -1,31 +1,30 @@ /* -* 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. -*/ - + * 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.server.game; import java.util.UUID; @@ -56,7 +55,7 @@ public class GameWorker implements Callable { @Override public Object call() { try { - logger.debug("GAME WORKER started gameId "+ game.getId()); + logger.debug("GAME WORKER started gameId " + game.getId()); Thread.currentThread().setName("GAME " + game.getId()); game.start(choosingPlayerId); game.fireUpdatePlayersEvent(); @@ -64,13 +63,10 @@ public class GameWorker implements Callable { game.cleanUp(); } catch (MageException ex) { logger.fatal("GameWorker mage error [" + game.getId() + "]" + ex, ex); - ex.printStackTrace(); } catch (Exception e) { logger.fatal("GameWorker general exception [" + game.getId() + "]" + e.getMessage(), e); - e.printStackTrace(); } catch (Error err) { - logger.fatal("GameWorker general error [" + game.getId() + "]" +err, err); - err.printStackTrace(); + logger.fatal("GameWorker general error [" + game.getId() + "]" + err, err); } return null; } diff --git a/Mage.Sets/src/mage/sets/avacynrestored/DevastationTide.java b/Mage.Sets/src/mage/sets/avacynrestored/DevastationTide.java index 126fc303e65..09845307136 100644 --- a/Mage.Sets/src/mage/sets/avacynrestored/DevastationTide.java +++ b/Mage.Sets/src/mage/sets/avacynrestored/DevastationTide.java @@ -91,7 +91,7 @@ class DevastationTideEffect extends OneShotEffect { for (Permanent permanent : game.getBattlefield().getActivePermanents(new FilterNonlandPermanent(), source.getControllerId(), source.getSourceId(), game)) { cardsToHand.add((Card) permanent); } - controller.moveCards(cardsToHand, null, Zone.HAND, source, game); + controller.moveCards(cardsToHand, Zone.HAND, source, game); return true; } diff --git a/Mage.Sets/src/mage/sets/oathofthegatewatch/CrushOfTentacles.java b/Mage.Sets/src/mage/sets/oathofthegatewatch/CrushOfTentacles.java new file mode 100644 index 00000000000..4db3a1354da --- /dev/null +++ b/Mage.Sets/src/mage/sets/oathofthegatewatch/CrushOfTentacles.java @@ -0,0 +1,86 @@ +/* + * Copyright 2010 BetaSteward_at_googlemail.com. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are + * permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this list of + * conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, this list + * of conditions and the following disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY BetaSteward_at_googlemail.com ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BetaSteward_at_googlemail.com OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * The views and conclusions contained in the software and documentation are those of the + * authors and should not be interpreted as representing official policies, either expressed + * or implied, of BetaSteward_at_googlemail.com. + */ +package mage.sets.oathofthegatewatch; + +import java.util.UUID; +import mage.MageInt; +import mage.abilities.condition.common.SurgedCondition; +import mage.abilities.decorator.ConditionalOneShotEffect; +import mage.abilities.effects.Effect; +import mage.abilities.effects.common.CreateTokenEffect; +import mage.abilities.effects.common.ReturnToHandFromBattlefieldAllEffect; +import mage.abilities.keyword.SurgeAbility; +import mage.cards.CardImpl; +import mage.constants.CardType; +import mage.constants.Rarity; +import mage.filter.common.FilterNonlandPermanent; +import mage.game.permanent.token.Token; + +/** + * + * @author LevelX2 + */ +public class CrushOfTentacles extends CardImpl { + + public CrushOfTentacles(UUID ownerId) { + super(ownerId, 53, "Crush of Tentacles", Rarity.MYTHIC, new CardType[]{CardType.SORCERY}, "{4}{U}{U}"); + this.expansionSetCode = "OGW"; + + // Return all nonland permanents to their owners' hands. If Crush of Tentacles surge cost was paid, put an 8/8 blue Octopus creature token onto the battlefield. + getSpellAbility().addEffect(new ReturnToHandFromBattlefieldAllEffect(new FilterNonlandPermanent("nonland permanents"))); + Effect effect = new ConditionalOneShotEffect(new CreateTokenEffect(new CrushOfTentaclesToken()), SurgedCondition.getInstance()); + effect.setText("If {this} surge cost was paid, put an 8/8 blue Octopus creature token onto the battlefield"); + getSpellAbility().addEffect(effect); + + // Has to be placed last here, because added spellAbility objects (e.g. effects) have to be copied from this + // Surge {3}{U}{U} (You may cast this spell for its surge cost if you or a teammate has cast another spell this turn) + addAbility(new SurgeAbility(this, "{3}{U}{U}")); + + } + + public CrushOfTentacles(final CrushOfTentacles card) { + super(card); + } + + @Override + public CrushOfTentacles copy() { + return new CrushOfTentacles(this); + } +} + +class CrushOfTentaclesToken extends Token { + + public CrushOfTentaclesToken() { + super("Octopus", "8/8 blue Octopus creature"); + this.cardType.add(CardType.CREATURE); + this.color.setBlue(true); + this.subtype.add("Octopus"); + this.power = new MageInt(8); + this.toughness = new MageInt(8); + } +} diff --git a/Mage.Tests/src/test/java/org/mage/test/cards/abilities/keywords/SurgeTest.java b/Mage.Tests/src/test/java/org/mage/test/cards/abilities/keywords/SurgeTest.java new file mode 100644 index 00000000000..6c4b97d4886 --- /dev/null +++ b/Mage.Tests/src/test/java/org/mage/test/cards/abilities/keywords/SurgeTest.java @@ -0,0 +1,91 @@ +/* + * Copyright 2010 BetaSteward_at_googlemail.com. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are + * permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this list of + * conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, this list + * of conditions and the following disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY BetaSteward_at_googlemail.com ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BetaSteward_at_googlemail.com OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * The views and conclusions contained in the software and documentation are those of the + * authors and should not be interpreted as representing official policies, either expressed + * or implied, of BetaSteward_at_googlemail.com. + */ +package org.mage.test.cards.abilities.keywords; + +import mage.constants.PhaseStep; +import mage.constants.Zone; +import org.junit.Test; +import org.mage.test.serverside.base.CardTestPlayerBase; + +/** + * + * @author LevelX2 + */ +public class SurgeTest extends CardTestPlayerBase { + + /** + * + */ + @Test + public void testWithoutSurge() { + addCard(Zone.BATTLEFIELD, playerA, "Island", 6); + // Surge {3}{U}{U} (You may cast this spell for its surge cost if you or a teammate has cast another spell this turn) + // Return all nonland permanents to their owners' hands. If Crush of Tentacles surge cost was paid, put an 8/8 blue Octopus creature token onto the battlefield. + addCard(Zone.HAND, playerA, "Crush of Tentacles"); // {4}{U}{U} + addCard(Zone.BATTLEFIELD, playerA, "Silvercoat Lion"); + addCard(Zone.BATTLEFIELD, playerB, "Silvercoat Lion"); + + castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Crush of Tentacles"); + + setStopAt(1, PhaseStep.BEGIN_COMBAT); + execute(); + + assertGraveyardCount(playerA, "Crush of Tentacles", 1); + assertHandCount(playerA, "Silvercoat Lion", 1); + assertHandCount(playerB, "Silvercoat Lion", 1); + assertPermanentCount(playerA, 6); + } + + @Test + public void testWithSurge() { + addCard(Zone.BATTLEFIELD, playerA, "Mountain", 1); + addCard(Zone.BATTLEFIELD, playerA, "Island", 5); + // Surge {3}{U}{U} (You may cast this spell for its surge cost if you or a teammate has cast another spell this turn) + // Return all nonland permanents to their owners' hands. If Crush of Tentacles surge cost was paid, put an 8/8 blue Octopus creature token onto the battlefield. + addCard(Zone.HAND, playerA, "Crush of Tentacles"); // {4}{U}{U} + addCard(Zone.HAND, playerA, "Lightning Bolt"); + addCard(Zone.BATTLEFIELD, playerA, "Silvercoat Lion"); + addCard(Zone.BATTLEFIELD, playerB, "Silvercoat Lion"); + + castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Lightning Bolt", playerB); + castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Crush of Tentacles with surge"); + + setStopAt(1, PhaseStep.BEGIN_COMBAT); + execute(); + + assertGraveyardCount(playerA, "Lightning Bolt", 1); + assertGraveyardCount(playerA, "Crush of Tentacles", 1); + assertPermanentCount(playerA, "Octopus", 1); + assertHandCount(playerA, "Silvercoat Lion", 1); + assertHandCount(playerB, "Silvercoat Lion", 1); + assertPermanentCount(playerA, 7); + + assertLife(playerB, 17); + } + +} diff --git a/Mage/src/main/java/mage/abilities/condition/common/SurgedCondition.java b/Mage/src/main/java/mage/abilities/condition/common/SurgedCondition.java new file mode 100644 index 00000000000..333832322e9 --- /dev/null +++ b/Mage/src/main/java/mage/abilities/condition/common/SurgedCondition.java @@ -0,0 +1,58 @@ +/* + * Copyright 2010 BetaSteward_at_googlemail.com. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are + * permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this list of + * conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, this list + * of conditions and the following disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY BetaSteward_at_googlemail.com ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BetaSteward_at_googlemail.com OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * The views and conclusions contained in the software and documentation are those of the + * authors and should not be interpreted as representing official policies, either expressed + * or implied, of BetaSteward_at_googlemail.com. + */ +package mage.abilities.condition.common; + +import mage.abilities.Ability; +import mage.abilities.condition.Condition; +import mage.abilities.keyword.SurgeAbility; +import mage.game.Game; + +/** + * + * @author LevelX2 + */ +public class SurgedCondition implements Condition { + + private static SurgedCondition fInstance = null; + + private SurgedCondition() { + } + + public static Condition getInstance() { + if (fInstance == null) { + fInstance = new SurgedCondition(); + } + return fInstance; + } + + @Override + public boolean apply(Game game, Ability source) { + // if surge is used for permanents we have to chnage implementation + return source instanceof SurgeAbility; + } +} diff --git a/Mage/src/main/java/mage/abilities/keyword/SurgeAbility.java b/Mage/src/main/java/mage/abilities/keyword/SurgeAbility.java new file mode 100644 index 00000000000..f7f13273bc9 --- /dev/null +++ b/Mage/src/main/java/mage/abilities/keyword/SurgeAbility.java @@ -0,0 +1,99 @@ +/* + * Copyright 2010 BetaSteward_at_googlemail.com. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are + * permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this list of + * conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, this list + * of conditions and the following disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY BetaSteward_at_googlemail.com ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BetaSteward_at_googlemail.com OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * The views and conclusions contained in the software and documentation are those of the + * authors and should not be interpreted as representing official policies, either expressed + * or implied, of BetaSteward_at_googlemail.com. + */ +package mage.abilities.keyword; + +import java.util.UUID; +import mage.abilities.SpellAbility; +import mage.abilities.costs.mana.ManaCostsImpl; +import mage.cards.Card; +import mage.constants.SpellAbilityType; +import mage.constants.Zone; +import mage.game.Game; +import mage.players.Player; +import mage.watchers.common.CastSpellLastTurnWatcher; + +/** + * + * @author LevelX2 + */ +public class SurgeAbility extends SpellAbility { + + private String rule; + + public SurgeAbility(Card card, String surgeCosts) { + super(new ManaCostsImpl<>(surgeCosts), card.getName() + " with surge", Zone.HAND, SpellAbilityType.BASE_ALTERNATE); + this.getCosts().addAll(card.getSpellAbility().getCosts().copy()); + this.getEffects().addAll(card.getSpellAbility().getEffects().copy()); + this.getTargets().addAll(card.getSpellAbility().getTargets().copy()); + this.getChoices().addAll(card.getSpellAbility().getChoices().copy()); + this.spellAbilityType = SpellAbilityType.BASE_ALTERNATE; + this.timing = card.getSpellAbility().getTiming(); + this.setRuleAtTheTop(true); + rule = "Surge " + surgeCosts + + " (You may cast this spell for its surge cost if you or a teammate has cast another spell this turn.)"; + } + + public SurgeAbility(final SurgeAbility ability) { + super(ability); + } + + @Override + public boolean canActivate(UUID playerId, Game game) { + // check if controller or teammate has already cast a spell this turn + CastSpellLastTurnWatcher watcher = (CastSpellLastTurnWatcher) game.getState().getWatchers().get("CastSpellLastTurnWatcher"); + if (watcher != null) { + Player player = game.getPlayer(playerId); + if (player != null) { + for (UUID playerToCheckId : game.getState().getPlayersInRange(playerId, game)) { + if (!player.hasOpponent(playerToCheckId, game)) { + if (watcher.getAmountOfSpellsPlayerCastOnCurrentTurn(playerToCheckId) > 0) { + return super.canActivate(playerId, game); + } + } + } + } + } + return false; + } + + @Override + public SurgeAbility copy() { + return new SurgeAbility(this); + } + + @Override + public String getRule(boolean all) { + return getRule(); + } + + @Override + public String getRule() { + return rule; + } + +} diff --git a/Mage/src/main/java/mage/constants/AbilityType.java b/Mage/src/main/java/mage/constants/AbilityType.java index 5a24e3bf3b3..bc6da81ba49 100644 --- a/Mage/src/main/java/mage/constants/AbilityType.java +++ b/Mage/src/main/java/mage/constants/AbilityType.java @@ -5,6 +5,7 @@ package mage.constants; * @author North */ public enum AbilityType { + PLAY_LAND("Play land"), MANA("Mana"), SPELL("Spell"), @@ -15,7 +16,7 @@ public enum AbilityType { LOYALTY("Loyalty"), SPECIAL_ACTION("Special Action"); - private String text; + private final String text; AbilityType(String text) { this.text = text; From a281a19a7db400e785a735537de17d86becc4ae8 Mon Sep 17 00:00:00 2001 From: LevelX2 Date: Thu, 24 Dec 2015 12:22:25 +0100 Subject: [PATCH 09/23] * Grimoire of the Dead - Fixed that the cards were returned under owners control instead Grimoire of the Dead's controllers control. --- Mage.Sets/src/mage/sets/innistrad/GrimoireOfTheDead.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Mage.Sets/src/mage/sets/innistrad/GrimoireOfTheDead.java b/Mage.Sets/src/mage/sets/innistrad/GrimoireOfTheDead.java index bf41dc6d02b..f41dcef84c5 100644 --- a/Mage.Sets/src/mage/sets/innistrad/GrimoireOfTheDead.java +++ b/Mage.Sets/src/mage/sets/innistrad/GrimoireOfTheDead.java @@ -114,7 +114,7 @@ class GrimoireOfTheDeadEffect extends OneShotEffect { } } } - controller.moveCards(creatureCards, Zone.BATTLEFIELD, source, game, false, false, true, null); + controller.moveCards(creatureCards, Zone.BATTLEFIELD, source, game, false, false, false, null); return true; } return false; From d40afd9ef5ff6be5cab78486891af10908f9fbff Mon Sep 17 00:00:00 2001 From: LevelX2 Date: Thu, 24 Dec 2015 12:52:08 +0100 Subject: [PATCH 10/23] * Sylvan Library- Fixed possible null pointer exception. --- Mage.Sets/src/mage/sets/fifthedition/SylvanLibrary.java | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/Mage.Sets/src/mage/sets/fifthedition/SylvanLibrary.java b/Mage.Sets/src/mage/sets/fifthedition/SylvanLibrary.java index 113e73b9d49..89b3e1445f8 100644 --- a/Mage.Sets/src/mage/sets/fifthedition/SylvanLibrary.java +++ b/Mage.Sets/src/mage/sets/fifthedition/SylvanLibrary.java @@ -105,8 +105,9 @@ class SylvanLibraryEffect extends OneShotEffect { CardsDrawnThisTurnWatcher watcher = (CardsDrawnThisTurnWatcher) game.getState().getWatchers().get("CardsDrawnThisTurnWatcher"); if (watcher != null) { Cards cards = new CardsImpl(); + Set cardsDrawnThisTurn = watcher.getCardsDrawnThisTurn(controller.getId()); for (UUID cardId : controller.getHand()) { - if (watcher.getCardsDrawnThisTurn(controller.getId()).contains(cardId)) { + if (cardsDrawnThisTurn != null && cardsDrawnThisTurn.contains(cardId)) { Card card = game.getCard(cardId); if (card != null) { cards.add(card); From 7725ad0251dacffc5821532c82bb266feb1f74df Mon Sep 17 00:00:00 2001 From: LoneFox Date: Thu, 24 Dec 2015 18:07:54 +0200 Subject: [PATCH 11/23] Implement cards: Marsh Viper, Pit Scorpion, Serpent Generator, and Snake Cult Initiation --- .../sets/chronicles/SerpentGenerator.java | 52 +++++++++++ .../mage/sets/fifthedition/MarshViper.java | 52 +++++++++++ .../mage/sets/fifthedition/PitScorpion.java | 66 ++++++++++++++ .../sets/fifthedition/SerpentGenerator.java | 88 +++++++++++++++++++ .../mage/sets/fourthedition/MarshViper.java | 52 +++++++++++ .../mage/sets/fourthedition/PitScorpion.java | 52 +++++++++++ .../sets/futuresight/SnakeCultInitiation.java | 76 ++++++++++++++++ .../src/mage/sets/legends/PitScorpion.java | 52 +++++++++++ .../mage/sets/legends/SerpentGenerator.java | 52 +++++++++++ .../sets/mastersedition/SerpentGenerator.java | 52 +++++++++++ .../src/mage/sets/thedark/MarshViper.java | 66 ++++++++++++++ 11 files changed, 660 insertions(+) create mode 100644 Mage.Sets/src/mage/sets/chronicles/SerpentGenerator.java create mode 100644 Mage.Sets/src/mage/sets/fifthedition/MarshViper.java create mode 100644 Mage.Sets/src/mage/sets/fifthedition/PitScorpion.java create mode 100644 Mage.Sets/src/mage/sets/fifthedition/SerpentGenerator.java create mode 100644 Mage.Sets/src/mage/sets/fourthedition/MarshViper.java create mode 100644 Mage.Sets/src/mage/sets/fourthedition/PitScorpion.java create mode 100644 Mage.Sets/src/mage/sets/futuresight/SnakeCultInitiation.java create mode 100644 Mage.Sets/src/mage/sets/legends/PitScorpion.java create mode 100644 Mage.Sets/src/mage/sets/legends/SerpentGenerator.java create mode 100644 Mage.Sets/src/mage/sets/mastersedition/SerpentGenerator.java create mode 100644 Mage.Sets/src/mage/sets/thedark/MarshViper.java diff --git a/Mage.Sets/src/mage/sets/chronicles/SerpentGenerator.java b/Mage.Sets/src/mage/sets/chronicles/SerpentGenerator.java new file mode 100644 index 00000000000..b51d5da8e35 --- /dev/null +++ b/Mage.Sets/src/mage/sets/chronicles/SerpentGenerator.java @@ -0,0 +1,52 @@ +/* + * Copyright 2010 BetaSteward_at_googlemail.com. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are + * permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this list of + * conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, this list + * of conditions and the following disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY BetaSteward_at_googlemail.com ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BetaSteward_at_googlemail.com OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * The views and conclusions contained in the software and documentation are those of the + * authors and should not be interpreted as representing official policies, either expressed + * or implied, of BetaSteward_at_googlemail.com. + */ +package mage.sets.chronicles; + +import java.util.UUID; + +/** + * + * @author LoneFox + */ +public class SerpentGenerator extends mage.sets.fifthedition.SerpentGenerator { + + public SerpentGenerator(UUID ownerId) { + super(ownerId); + this.cardNumber = 88; + this.expansionSetCode = "CHR"; + } + + public SerpentGenerator(final SerpentGenerator card) { + super(card); + } + + @Override + public SerpentGenerator copy() { + return new SerpentGenerator(this); + } +} diff --git a/Mage.Sets/src/mage/sets/fifthedition/MarshViper.java b/Mage.Sets/src/mage/sets/fifthedition/MarshViper.java new file mode 100644 index 00000000000..d5795073e73 --- /dev/null +++ b/Mage.Sets/src/mage/sets/fifthedition/MarshViper.java @@ -0,0 +1,52 @@ +/* + * Copyright 2010 BetaSteward_at_googlemail.com. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are + * permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this list of + * conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, this list + * of conditions and the following disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY BetaSteward_at_googlemail.com ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BetaSteward_at_googlemail.com OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * The views and conclusions contained in the software and documentation are those of the + * authors and should not be interpreted as representing official policies, either expressed + * or implied, of BetaSteward_at_googlemail.com. + */ +package mage.sets.fifthedition; + +import java.util.UUID; + +/** + * + * @author LoneFox + */ +public class MarshViper extends mage.sets.thedark.MarshViper { + + public MarshViper(UUID ownerId) { + super(ownerId); + this.cardNumber = 177; + this.expansionSetCode = "5ED"; + } + + public MarshViper(final MarshViper card) { + super(card); + } + + @Override + public MarshViper copy() { + return new MarshViper(this); + } +} diff --git a/Mage.Sets/src/mage/sets/fifthedition/PitScorpion.java b/Mage.Sets/src/mage/sets/fifthedition/PitScorpion.java new file mode 100644 index 00000000000..a234f9f671d --- /dev/null +++ b/Mage.Sets/src/mage/sets/fifthedition/PitScorpion.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.sets.fifthedition; + +import java.util.UUID; +import mage.MageInt; +import mage.abilities.common.DealsDamageToAPlayerTriggeredAbility; +import mage.abilities.effects.Effect; +import mage.abilities.effects.common.counter.AddPoisonCounterTargetEffect; +import mage.cards.CardImpl; +import mage.constants.CardType; +import mage.constants.Rarity; + +/** + * + * @author LoneFox + */ +public class PitScorpion extends CardImpl { + + public PitScorpion(UUID ownerId) { + super(ownerId, 49, "Pit Scorpion", Rarity.COMMON, new CardType[]{CardType.CREATURE}, "{2}{B}"); + this.expansionSetCode = "5ED"; + this.subtype.add("Scorpion"); + this.power = new MageInt(1); + this.toughness = new MageInt(1); + + // Whenever Pit Scorpion deals damage to a player, that player gets a poison counter. + Effect effect = new AddPoisonCounterTargetEffect(1); + effect.setText("that player gets a poison counter"); + this.addAbility(new DealsDamageToAPlayerTriggeredAbility(effect, false, true)); + } + + public PitScorpion(final PitScorpion card) { + super(card); + } + + @Override + public PitScorpion copy() { + return new PitScorpion(this); + } +} diff --git a/Mage.Sets/src/mage/sets/fifthedition/SerpentGenerator.java b/Mage.Sets/src/mage/sets/fifthedition/SerpentGenerator.java new file mode 100644 index 00000000000..bcce1a1023d --- /dev/null +++ b/Mage.Sets/src/mage/sets/fifthedition/SerpentGenerator.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.sets.fifthedition; + +import java.util.UUID; +import mage.MageInt; +import mage.abilities.Ability; +import mage.abilities.common.DealsDamageToAPlayerTriggeredAbility; +import mage.abilities.common.SimpleActivatedAbility; +import mage.abilities.costs.common.TapSourceCost; +import mage.abilities.costs.mana.ManaCostsImpl; +import mage.abilities.effects.Effect; +import mage.abilities.effects.common.CreateTokenEffect; +import mage.abilities.effects.common.counter.AddPoisonCounterTargetEffect; +import mage.cards.CardImpl; +import mage.constants.CardType; +import mage.constants.Rarity; +import mage.constants.Zone; +import mage.game.permanent.token.Token; + +/** + * + * @author LoneFox + */ +public class SerpentGenerator extends CardImpl { + + public SerpentGenerator(UUID ownerId) { + super(ownerId, 397, "Serpent Generator", Rarity.RARE, new CardType[]{CardType.ARTIFACT}, "{6}"); + this.expansionSetCode = "5ED"; + + // {4}, {tap}: Put a 1/1 colorless Snake artifact creature token onto the battlefield. It has "Whenever this creature deals damage to a player, that player gets a poison counter." + Effect effect = new CreateTokenEffect(new SnakeToken()); + effect.setText("Put a 1/1 colorless Snake artifact creature token onto the battlefield. It has \"Whenever this creature deals damage to a player, that player gets a poison counter.\""); + Ability ability = new SimpleActivatedAbility(Zone.BATTLEFIELD, effect, new ManaCostsImpl("{4}")); + ability.addCost(new TapSourceCost()); + this.addAbility(ability); + } + + public SerpentGenerator(final SerpentGenerator card) { + super(card); + } + + @Override + public SerpentGenerator copy() { + return new SerpentGenerator(this); + } +} + +class SnakeToken extends Token { + + public SnakeToken() { + super("Snake", "1/1 colorless Snake artifact creature token with \"Whenever this creature deals damage to a player, that player gets a poison counter.\""); + cardType.add(CardType.ARTIFACT); + cardType.add(CardType.CREATURE); + subtype.add("Snake"); + power = new MageInt(1); + toughness = new MageInt(1); + + Effect effect = new AddPoisonCounterTargetEffect(1); + effect.setText("that player gets a poison counter"); + this.addAbility(new DealsDamageToAPlayerTriggeredAbility(effect, false, true)); + } +} diff --git a/Mage.Sets/src/mage/sets/fourthedition/MarshViper.java b/Mage.Sets/src/mage/sets/fourthedition/MarshViper.java new file mode 100644 index 00000000000..45ff5bab235 --- /dev/null +++ b/Mage.Sets/src/mage/sets/fourthedition/MarshViper.java @@ -0,0 +1,52 @@ +/* + * Copyright 2010 BetaSteward_at_googlemail.com. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are + * permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this list of + * conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, this list + * of conditions and the following disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY BetaSteward_at_googlemail.com ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BetaSteward_at_googlemail.com OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * The views and conclusions contained in the software and documentation are those of the + * authors and should not be interpreted as representing official policies, either expressed + * or implied, of BetaSteward_at_googlemail.com. + */ +package mage.sets.fourthedition; + +import java.util.UUID; + +/** + * + * @author LoneFox + */ +public class MarshViper extends mage.sets.thedark.MarshViper { + + public MarshViper(UUID ownerId) { + super(ownerId); + this.cardNumber = 147; + this.expansionSetCode = "4ED"; + } + + public MarshViper(final MarshViper card) { + super(card); + } + + @Override + public MarshViper copy() { + return new MarshViper(this); + } +} diff --git a/Mage.Sets/src/mage/sets/fourthedition/PitScorpion.java b/Mage.Sets/src/mage/sets/fourthedition/PitScorpion.java new file mode 100644 index 00000000000..c6bed14f0f8 --- /dev/null +++ b/Mage.Sets/src/mage/sets/fourthedition/PitScorpion.java @@ -0,0 +1,52 @@ +/* + * Copyright 2010 BetaSteward_at_googlemail.com. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are + * permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this list of + * conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, this list + * of conditions and the following disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY BetaSteward_at_googlemail.com ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BetaSteward_at_googlemail.com OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * The views and conclusions contained in the software and documentation are those of the + * authors and should not be interpreted as representing official policies, either expressed + * or implied, of BetaSteward_at_googlemail.com. + */ +package mage.sets.fourthedition; + +import java.util.UUID; + +/** + * + * @author LoneFox + */ +public class PitScorpion extends mage.sets.fifthedition.PitScorpion { + + public PitScorpion(UUID ownerId) { + super(ownerId); + this.cardNumber = 37; + this.expansionSetCode = "4ED"; + } + + public PitScorpion(final PitScorpion card) { + super(card); + } + + @Override + public PitScorpion copy() { + return new PitScorpion(this); + } +} diff --git a/Mage.Sets/src/mage/sets/futuresight/SnakeCultInitiation.java b/Mage.Sets/src/mage/sets/futuresight/SnakeCultInitiation.java new file mode 100644 index 00000000000..1c5a8a6433c --- /dev/null +++ b/Mage.Sets/src/mage/sets/futuresight/SnakeCultInitiation.java @@ -0,0 +1,76 @@ +/* + * Copyright 2010 BetaSteward_at_googlemail.com. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are + * permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this list of + * conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, this list + * of conditions and the following disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY BetaSteward_at_googlemail.com ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BetaSteward_at_googlemail.com OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * The views and conclusions contained in the software and documentation are those of the + * authors and should not be interpreted as representing official policies, either expressed + * or implied, of BetaSteward_at_googlemail.com. + */ +package mage.sets.futuresight; + +import java.util.UUID; +import mage.abilities.Ability; +import mage.abilities.common.SimpleStaticAbility; +import mage.abilities.effects.common.AttachEffect; +import mage.abilities.effects.common.continuous.GainAbilityAttachedEffect; +import mage.abilities.keyword.EnchantAbility; +import mage.abilities.keyword.PoisonousAbility; +import mage.cards.CardImpl; +import mage.constants.AttachmentType; +import mage.constants.CardType; +import mage.constants.Outcome; +import mage.constants.Rarity; +import mage.constants.Zone; +import mage.target.TargetPermanent; +import mage.target.common.TargetCreaturePermanent; + +/** + * + * @author LoneFox + */ +public class SnakeCultInitiation extends CardImpl { + + public SnakeCultInitiation(UUID ownerId) { + super(ownerId, 89, "Snake Cult Initiation", Rarity.UNCOMMON, new CardType[]{CardType.ENCHANTMENT}, "{3}{B}"); + this.expansionSetCode = "FUT"; + this.subtype.add("Aura"); + + // Enchant creature + TargetPermanent auraTarget = new TargetCreaturePermanent(); + this.getSpellAbility().addTarget(auraTarget); + this.getSpellAbility().addEffect(new AttachEffect(Outcome.AddAbility)); + Ability ability = new EnchantAbility(auraTarget.getTargetName()); + this.addAbility(ability); + // Enchanted creature has poisonous 3. + this.addAbility(new SimpleStaticAbility(Zone.BATTLEFIELD, new GainAbilityAttachedEffect( + new PoisonousAbility(3), AttachmentType.AURA))); + } + + public SnakeCultInitiation(final SnakeCultInitiation card) { + super(card); + } + + @Override + public SnakeCultInitiation copy() { + return new SnakeCultInitiation(this); + } +} diff --git a/Mage.Sets/src/mage/sets/legends/PitScorpion.java b/Mage.Sets/src/mage/sets/legends/PitScorpion.java new file mode 100644 index 00000000000..6a49f2e81f6 --- /dev/null +++ b/Mage.Sets/src/mage/sets/legends/PitScorpion.java @@ -0,0 +1,52 @@ +/* + * Copyright 2010 BetaSteward_at_googlemail.com. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are + * permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this list of + * conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, this list + * of conditions and the following disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY BetaSteward_at_googlemail.com ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BetaSteward_at_googlemail.com OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * The views and conclusions contained in the software and documentation are those of the + * authors and should not be interpreted as representing official policies, either expressed + * or implied, of BetaSteward_at_googlemail.com. + */ +package mage.sets.legends; + +import java.util.UUID; + +/** + * + * @author LoneFox + */ +public class PitScorpion extends mage.sets.fifthedition.PitScorpion { + + public PitScorpion(UUID ownerId) { + super(ownerId); + this.cardNumber = 28; + this.expansionSetCode = "LEG"; + } + + public PitScorpion(final PitScorpion card) { + super(card); + } + + @Override + public PitScorpion copy() { + return new PitScorpion(this); + } +} diff --git a/Mage.Sets/src/mage/sets/legends/SerpentGenerator.java b/Mage.Sets/src/mage/sets/legends/SerpentGenerator.java new file mode 100644 index 00000000000..1893c3c4c49 --- /dev/null +++ b/Mage.Sets/src/mage/sets/legends/SerpentGenerator.java @@ -0,0 +1,52 @@ +/* + * Copyright 2010 BetaSteward_at_googlemail.com. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are + * permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this list of + * conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, this list + * of conditions and the following disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY BetaSteward_at_googlemail.com ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BetaSteward_at_googlemail.com OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * The views and conclusions contained in the software and documentation are those of the + * authors and should not be interpreted as representing official policies, either expressed + * or implied, of BetaSteward_at_googlemail.com. + */ +package mage.sets.legends; + +import java.util.UUID; + +/** + * + * @author LoneFox + */ +public class SerpentGenerator extends mage.sets.fifthedition.SerpentGenerator { + + public SerpentGenerator(UUID ownerId) { + super(ownerId); + this.cardNumber = 240; + this.expansionSetCode = "LEG"; + } + + public SerpentGenerator(final SerpentGenerator card) { + super(card); + } + + @Override + public SerpentGenerator copy() { + return new SerpentGenerator(this); + } +} diff --git a/Mage.Sets/src/mage/sets/mastersedition/SerpentGenerator.java b/Mage.Sets/src/mage/sets/mastersedition/SerpentGenerator.java new file mode 100644 index 00000000000..0d42156ce1e --- /dev/null +++ b/Mage.Sets/src/mage/sets/mastersedition/SerpentGenerator.java @@ -0,0 +1,52 @@ +/* + * Copyright 2010 BetaSteward_at_googlemail.com. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are + * permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this list of + * conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, this list + * of conditions and the following disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY BetaSteward_at_googlemail.com ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BetaSteward_at_googlemail.com OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * The views and conclusions contained in the software and documentation are those of the + * authors and should not be interpreted as representing official policies, either expressed + * or implied, of BetaSteward_at_googlemail.com. + */ +package mage.sets.mastersedition; + +import java.util.UUID; + +/** + * + * @author LoneFox + */ +public class SerpentGenerator extends mage.sets.fifthedition.SerpentGenerator { + + public SerpentGenerator(UUID ownerId) { + super(ownerId); + this.cardNumber = 164; + this.expansionSetCode = "MED"; + } + + public SerpentGenerator(final SerpentGenerator card) { + super(card); + } + + @Override + public SerpentGenerator copy() { + return new SerpentGenerator(this); + } +} diff --git a/Mage.Sets/src/mage/sets/thedark/MarshViper.java b/Mage.Sets/src/mage/sets/thedark/MarshViper.java new file mode 100644 index 00000000000..8993547a625 --- /dev/null +++ b/Mage.Sets/src/mage/sets/thedark/MarshViper.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.sets.thedark; + +import java.util.UUID; +import mage.MageInt; +import mage.abilities.common.DealsDamageToAPlayerTriggeredAbility; +import mage.abilities.effects.Effect; +import mage.abilities.effects.common.counter.AddPoisonCounterTargetEffect; +import mage.cards.CardImpl; +import mage.constants.CardType; +import mage.constants.Rarity; + +/** + * + * @author LoneFox + */ +public class MarshViper extends CardImpl { + + public MarshViper(UUID ownerId) { + super(ownerId, 44, "Marsh Viper", Rarity.COMMON, new CardType[]{CardType.CREATURE}, "{3}{G}"); + this.expansionSetCode = "DRK"; + this.subtype.add("Snake"); + this.power = new MageInt(1); + this.toughness = new MageInt(2); + + // Whenever Marsh Viper deals damage to a player, that player gets two poison counters. + Effect effect = new AddPoisonCounterTargetEffect(2); + effect.setText("that player gets two poison counters"); + this.addAbility(new DealsDamageToAPlayerTriggeredAbility(effect, false, true)); + } + + public MarshViper(final MarshViper card) { + super(card); + } + + @Override + public MarshViper copy() { + return new MarshViper(this); + } +} From eb0ae552570791cc391d567339b27a95e187b3da Mon Sep 17 00:00:00 2001 From: LevelX2 Date: Thu, 24 Dec 2015 17:58:04 +0100 Subject: [PATCH 12/23] * Fixed a problem with "put into the graveyard from anywhere triggers" that checked wrongly the state of the source object on the battlefield if went to graveyard itself. --- .../sets/alarareborn/DragonAppeasement.java | 10 +- .../SmotheringAbomination.java | 1 + .../MazirekKraulDeathPriest.java | 6 +- .../dragonsoftarkir/RuthlessDeathfang.java | 3 +- .../sets/ravnica/SavraQueenOfTheGolgari.java | 9 +- .../triggers/UlamogTheInfiniteGyreTest.java | 31 ++++++ .../cards/triggers/dies/ThragtuskTest.java | 63 ++++++----- .../mage/abilities/TriggeredAbilities.java | 10 +- .../java/mage/abilities/TriggeredAbility.java | 4 + .../mage/abilities/TriggeredAbilityImpl.java | 45 +++++++- ...ThisOrAnotherCreatureTriggeredAbility.java | 4 +- ...sTheBattlefieldSourceTriggeredAbility.java | 4 +- ...aveFromAnywhereSourceTriggeredAbility.java | 28 +++++ ...aveFromBattlefieldAllTriggeredAbility.java | 10 +- .../common/ZoneChangeTriggeredAbility.java | 25 +++-- Mage/src/main/java/mage/counters/Counter.java | 104 +++++++++--------- 16 files changed, 229 insertions(+), 128 deletions(-) diff --git a/Mage.Sets/src/mage/sets/alarareborn/DragonAppeasement.java b/Mage.Sets/src/mage/sets/alarareborn/DragonAppeasement.java index 5ee8ca52d96..26e85928fd6 100644 --- a/Mage.Sets/src/mage/sets/alarareborn/DragonAppeasement.java +++ b/Mage.Sets/src/mage/sets/alarareborn/DragonAppeasement.java @@ -50,16 +50,12 @@ public class DragonAppeasement extends CardImpl { super(ownerId, 115, "Dragon Appeasement", Rarity.UNCOMMON, new CardType[]{CardType.ENCHANTMENT}, "{3}{B}{R}{G}"); this.expansionSetCode = "ARB"; - - - - // Skip your draw step. this.addAbility(new SimpleStaticAbility(Zone.BATTLEFIELD, new SkipDrawStepEffect())); - + // Whenever you sacrifice a creature, you may draw a card. this.addAbility(new DragonAppeasementTriggeredAbility()); - + } public DragonAppeasement(final DragonAppeasement card) { @@ -76,6 +72,7 @@ class DragonAppeasementTriggeredAbility extends TriggeredAbilityImpl { public DragonAppeasementTriggeredAbility() { super(Zone.BATTLEFIELD, new DrawCardSourceControllerEffect(1), true); + setLeavesTheBattlefieldTrigger(true); } public DragonAppeasementTriggeredAbility(final DragonAppeasementTriggeredAbility ability) { @@ -103,4 +100,3 @@ class DragonAppeasementTriggeredAbility extends TriggeredAbilityImpl { return "Whenever you sacrifice a creature, " + super.getRule(); } } - diff --git a/Mage.Sets/src/mage/sets/battleforzendikar/SmotheringAbomination.java b/Mage.Sets/src/mage/sets/battleforzendikar/SmotheringAbomination.java index e7d2ec93608..2f7aa19073f 100644 --- a/Mage.Sets/src/mage/sets/battleforzendikar/SmotheringAbomination.java +++ b/Mage.Sets/src/mage/sets/battleforzendikar/SmotheringAbomination.java @@ -86,6 +86,7 @@ class SmotheringAbominationTriggeredAbility extends TriggeredAbilityImpl { public SmotheringAbominationTriggeredAbility() { super(Zone.BATTLEFIELD, new DrawCardSourceControllerEffect(1)); + setLeavesTheBattlefieldTrigger(true); } public SmotheringAbominationTriggeredAbility(final SmotheringAbominationTriggeredAbility ability) { diff --git a/Mage.Sets/src/mage/sets/commander2015/MazirekKraulDeathPriest.java b/Mage.Sets/src/mage/sets/commander2015/MazirekKraulDeathPriest.java index 522f1c383f1..4ebdc8f15fa 100644 --- a/Mage.Sets/src/mage/sets/commander2015/MazirekKraulDeathPriest.java +++ b/Mage.Sets/src/mage/sets/commander2015/MazirekKraulDeathPriest.java @@ -61,7 +61,7 @@ public class MazirekKraulDeathPriest extends CardImpl { // Flying this.addAbility(FlyingAbility.getInstance()); - + // Whenever a player sacrifices another permanent, put a +1/+1 counter on each creature you control. this.addAbility(new PlayerSacrificesPermanentTriggeredAbility(new AddCountersAllEffect(CounterType.P1P1.createInstance(), new FilterControlledCreaturePermanent()), false)); } @@ -99,11 +99,11 @@ class PlayerSacrificesPermanentTriggeredAbility extends TriggeredAbilityImpl { @Override public String getRule() { - return "Whenever a player sacrifices a permanent, " + super.getRule(); + return "Whenever a player sacrifices another permanent, " + super.getRule(); } @Override public PlayerSacrificesPermanentTriggeredAbility copy() { return new PlayerSacrificesPermanentTriggeredAbility(this); } -} \ No newline at end of file +} diff --git a/Mage.Sets/src/mage/sets/dragonsoftarkir/RuthlessDeathfang.java b/Mage.Sets/src/mage/sets/dragonsoftarkir/RuthlessDeathfang.java index b3385304d2b..d4d0f26f2b1 100644 --- a/Mage.Sets/src/mage/sets/dragonsoftarkir/RuthlessDeathfang.java +++ b/Mage.Sets/src/mage/sets/dragonsoftarkir/RuthlessDeathfang.java @@ -79,6 +79,7 @@ class RuthlessDeathfangTriggeredAbility extends TriggeredAbilityImpl { public RuthlessDeathfangTriggeredAbility() { super(Zone.BATTLEFIELD, new SacrificeEffect(new FilterCreaturePermanent("creature"), 1, "target opponent"), false); + setLeavesTheBattlefieldTrigger(true); } public RuthlessDeathfangTriggeredAbility(final RuthlessDeathfangTriggeredAbility ability) { @@ -105,4 +106,4 @@ class RuthlessDeathfangTriggeredAbility extends TriggeredAbilityImpl { public String getRule() { return "Whenever you sacrifice a creature, " + super.getRule(); } -} \ No newline at end of file +} diff --git a/Mage.Sets/src/mage/sets/ravnica/SavraQueenOfTheGolgari.java b/Mage.Sets/src/mage/sets/ravnica/SavraQueenOfTheGolgari.java index a3521d9cbdc..f007a3ce821 100644 --- a/Mage.Sets/src/mage/sets/ravnica/SavraQueenOfTheGolgari.java +++ b/Mage.Sets/src/mage/sets/ravnica/SavraQueenOfTheGolgari.java @@ -67,7 +67,7 @@ public class SavraQueenOfTheGolgari extends CardImpl { // Whenever you sacrifice a black creature, you may pay 2 life. If you do, each other player sacrifices a creature. this.addAbility(new SavraSacrificeBlackCreatureAbility()); - + // Whenever you sacrifice a green creature, you may gain 2 life. this.addAbility(new SavraSacrificeGreenCreatureAbility()); } @@ -87,6 +87,7 @@ class SavraSacrificeBlackCreatureAbility extends TriggeredAbilityImpl { public SavraSacrificeBlackCreatureAbility() { super(Zone.BATTLEFIELD, new DoIfCostPaid(new SavraSacrificeEffect(), new PayLifeCost(2))); this.addTarget(new TargetCreatureOrPlayer()); + this.setLeavesTheBattlefieldTrigger(true); } public SavraSacrificeBlackCreatureAbility(final SavraSacrificeBlackCreatureAbility ability) { @@ -136,7 +137,7 @@ class SavraSacrificeEffect extends OneShotEffect { public boolean apply(Game game, Ability source) { List perms = new ArrayList<>(); Player controller = game.getPlayer(source.getControllerId()); - if (controller != null) { + if (controller != null) { for (UUID playerId : controller.getInRange()) { Player player = game.getPlayer(playerId); if (player != null && !playerId.equals(source.getControllerId())) { @@ -154,9 +155,9 @@ class SavraSacrificeEffect extends OneShotEffect { permanent.sacrifice(source.getSourceId(), game); } } - return true; + return true; } - return false; + return false; } } diff --git a/Mage.Tests/src/test/java/org/mage/test/cards/triggers/UlamogTheInfiniteGyreTest.java b/Mage.Tests/src/test/java/org/mage/test/cards/triggers/UlamogTheInfiniteGyreTest.java index dfde867688b..ffcfa3fce88 100644 --- a/Mage.Tests/src/test/java/org/mage/test/cards/triggers/UlamogTheInfiniteGyreTest.java +++ b/Mage.Tests/src/test/java/org/mage/test/cards/triggers/UlamogTheInfiniteGyreTest.java @@ -110,4 +110,35 @@ public class UlamogTheInfiniteGyreTest extends CardTestPlayerBase { assertHandCount(playerA, 4); } + + /** + * Ixidron turned Ulamog, the Infinite Gyre to a 2/2 with no name and then + * someone used an Wrath of the Gods effect. Ulamog, the Infinite Gyre + * entered the graveyard without triggering his shuffle effect (just like + * this case: http://www.mtgsalvation.com/forums/magi ... nd-kozilek). + */ + @Test + public void testFaceDownToGraveyard() { + addCard(Zone.BATTLEFIELD, playerA, "Island", 5); + // When you cast Kozilek, Butcher of Truth, draw four cards. + // Annihilator 4 (Whenever this creature attacks, defending player sacrifices four permanents.) + // When Kozilek is put into a graveyard from anywhere, its owner shuffles his or her graveyard into his or her library. + addCard(Zone.BATTLEFIELD, playerA, "Kozilek, Butcher of Truth"); // {10} + // As Ixidron enters the battlefield, turn all other nontoken creatures face down. + // Ixidron's power and toughness are each equal to the number of face-down creatures on the battlefield. + addCard(Zone.HAND, playerA, "Ixidron"); // {3}{U}{U} + + addCard(Zone.BATTLEFIELD, playerB, "Plains", 4); + addCard(Zone.HAND, playerB, "Wrath of God", 1); + + castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Ixidron"); + + castSpell(2, PhaseStep.PRECOMBAT_MAIN, playerB, "Wrath of God"); + setStopAt(2, PhaseStep.BEGIN_COMBAT); + execute(); + + assertPermanentCount(playerA, "Ixidron", 0); + assertGraveyardCount(playerB, "Wrath of God", 1); + assertGraveyardCount(playerA, 0); + } } diff --git a/Mage.Tests/src/test/java/org/mage/test/cards/triggers/dies/ThragtuskTest.java b/Mage.Tests/src/test/java/org/mage/test/cards/triggers/dies/ThragtuskTest.java index 3a9bb20f249..f2431830a1c 100644 --- a/Mage.Tests/src/test/java/org/mage/test/cards/triggers/dies/ThragtuskTest.java +++ b/Mage.Tests/src/test/java/org/mage/test/cards/triggers/dies/ThragtuskTest.java @@ -29,24 +29,23 @@ package org.mage.test.cards.triggers.dies; import mage.constants.PhaseStep; import mage.constants.Zone; -import org.junit.Ignore; import org.junit.Test; import org.mage.test.serverside.base.CardTestPlayerBase; /** - * Thragtusk - Beast {4}{G} - * When Thragtusk enters the battlefield, you gain 5 life. - * When Thragtusk leaves the battlefield, put a 3/3 green Beast creature token onto the battlefield. - * + * Thragtusk - Beast {4}{G} When Thragtusk enters the battlefield, you gain 5 + * life. When Thragtusk leaves the battlefield, put a 3/3 green Beast creature + * token onto the battlefield. + * * @author LevelX2 */ public class ThragtuskTest extends CardTestPlayerBase { /** - * Test if a Thragtusk is copied by a PhyrexianMetamorph - * that both triggers cotrrect work + * Test if a Thragtusk is copied by a PhyrexianMetamorph that both triggers + * cotrrect work */ - @Test + @Test public void testPhyrexianMetamorph() { addCard(Zone.BATTLEFIELD, playerA, "Island", 4); // You may have Phyrexian Metamorph enter the battlefield as a copy of any artifact or creature on the battlefield, except it's an artifact in addition to its other types @@ -57,9 +56,9 @@ public class ThragtuskTest extends CardTestPlayerBase { addCard(Zone.BATTLEFIELD, playerB, "Thragtusk", 1); castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Phyrexian Metamorph"); - setChoice(playerA, "Yes"); + setChoice(playerA, "Yes"); setChoice(playerA, "Thragtusk"); - + castSpell(1, PhaseStep.POSTCOMBAT_MAIN, playerB, "Public Execution", "Thragtusk"); setStopAt(1, PhaseStep.END_TURN); @@ -67,21 +66,22 @@ public class ThragtuskTest extends CardTestPlayerBase { assertPermanentCount(playerB, "Thragtusk", 1); - assertGraveyardCount(playerA,"Phyrexian Metamorph", 1); - assertGraveyardCount(playerB,"Public Execution", 1); + assertGraveyardCount(playerA, "Phyrexian Metamorph", 1); + assertGraveyardCount(playerB, "Public Execution", 1); assertLife(playerA, 25); - assertLife(playerB, 20); // Thragtusk ETB ability does not trigger if set to battlefield on test game start - - assertPermanentCount(playerA, "Beast", 1); + assertLife(playerB, 20); // Thragtusk ETB ability does not trigger if set to battlefield on test game start + + assertPermanentCount(playerA, "Beast", 1); } + /** - * Test if a Thragtusk is copied by a Phyrexian Metamorph - * that leave battlefield ability does not work, if - * the copy left all abilities by Turn to Frog + * Test if a Thragtusk is copied by a Phyrexian Metamorph that leave + * battlefield ability does not work, if the copy left all abilities by Turn + * to Frog */ - + @Test public void testPhyrexianMetamorphTurnToFrog() { addCard(Zone.BATTLEFIELD, playerA, "Island", 4); @@ -96,32 +96,31 @@ public class ThragtuskTest extends CardTestPlayerBase { addCard(Zone.BATTLEFIELD, playerB, "Thragtusk", 1); castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Phyrexian Metamorph"); - setChoice(playerA, "Yes"); + setChoice(playerA, "Yes"); setChoice(playerA, "Thragtusk"); castSpell(1, PhaseStep.BEGIN_COMBAT, playerB, "Tortoise Formation"); - - + castSpell(1, PhaseStep.DECLARE_ATTACKERS, playerB, "Turn to Frog", "Thragtusk"); castSpell(1, PhaseStep.POSTCOMBAT_MAIN, playerB, "Public Execution", "Thragtusk"); setStopAt(1, PhaseStep.END_TURN); execute(); - assertGraveyardCount(playerB,"Tortoise Formation", 1); - assertGraveyardCount(playerB,"Turn to Frog", 1); - + assertGraveyardCount(playerB, "Tortoise Formation", 1); + assertGraveyardCount(playerB, "Turn to Frog", 1); + assertPermanentCount(playerB, "Thragtusk", 1); assertPermanentCount(playerA, "Thragtusk", 0); - assertGraveyardCount(playerA,"Phyrexian Metamorph", 1); - assertGraveyardCount(playerB,"Public Execution", 1); + assertGraveyardCount(playerA, "Phyrexian Metamorph", 1); + assertGraveyardCount(playerB, "Public Execution", 1); assertLife(playerA, 25); - assertLife(playerB, 20); // Thragtusk ETB ability does not trigger if set to battlefield on test game start - - assertPermanentCount(playerA, "Beast", 0); + assertLife(playerB, 20); // Thragtusk ETB ability does not trigger if set to battlefield on test game start - } + assertPermanentCount(playerA, "Beast", 0); -} \ No newline at end of file + } + +} diff --git a/Mage/src/main/java/mage/abilities/TriggeredAbilities.java b/Mage/src/main/java/mage/abilities/TriggeredAbilities.java index 0ea57904eaa..c066f8ef090 100644 --- a/Mage/src/main/java/mage/abilities/TriggeredAbilities.java +++ b/Mage/src/main/java/mage/abilities/TriggeredAbilities.java @@ -41,8 +41,6 @@ import mage.cards.Card; import mage.constants.Zone; import mage.game.Game; import mage.game.events.GameEvent; -import mage.game.events.GameEvent.EventType; -import mage.game.events.ZoneChangeEvent; import mage.game.permanent.Permanent; import mage.game.stack.Spell; @@ -97,9 +95,11 @@ public class TriggeredAbilities extends ConcurrentHashMap 0) { count--; } else { - logger.warn("An attempt was made to set the counter '" + name + - "' to less than 0. Setting to 0."); + logger.warn("An attempt was made to set the counter '" + name + + "' to less than 0. Setting to 0."); } } - /** - * Decreases the {@code count} by tne passed in {@code amount}. Will not allow the count - * to be less than 0. If an attempt is made to make the count be less than zero, the call will be logged. + * Decreases the {@code count} by the passed in {@code amount}. Will not + * allow the count to be less than 0. If an attempt is made to make the + * count be less than zero, the call will be logged. + * + * @param amount */ public void remove(int amount) { if (count >= amount) { count -= amount; } else { - logger.warn("An attempt was made to set the counter '" + name + - "' to less than 0. Setting to 0."); + logger.warn("An attempt was made to set the counter '" + name + + "' to less than 0. Setting to 0."); count = 0; } } - /** * Returns the name of this {@link Counter} * @@ -149,20 +147,24 @@ public class Counter implements Serializable { return new Counter(this); } - @Override public boolean equals(Object o) { - if (this == o) return true; - if (o == null || getClass() != o.getClass()) return false; + if (this == o) { + return true; + } + if (o == null || getClass() != o.getClass()) { + return false; + } Counter counter = (Counter) o; - if (count != counter.count) return false; + if (count != counter.count) { + return false; + } return !(name != null ? !name.equals(counter.name) : counter.name != null); } - @Override public int hashCode() { int result = name != null ? name.hashCode() : 0; From f7df5201c30f80357915f27af927e5a7f33415ff Mon Sep 17 00:00:00 2001 From: LoneFox Date: Thu, 24 Dec 2015 20:04:08 +0200 Subject: [PATCH 13/23] Implement cards: Bonded Fetch, Flowstone Embrace, Skizzik Surger, and Whetwheel --- .../mage/sets/futuresight/BondedFetch.java | 71 ++++++++++++++++++ .../sets/futuresight/FlowstoneEmbrace.java | 75 +++++++++++++++++++ .../mage/sets/futuresight/SkizzikSurger.java | 68 +++++++++++++++++ .../src/mage/sets/futuresight/Whetwheel.java | 72 ++++++++++++++++++ 4 files changed, 286 insertions(+) create mode 100644 Mage.Sets/src/mage/sets/futuresight/BondedFetch.java create mode 100644 Mage.Sets/src/mage/sets/futuresight/FlowstoneEmbrace.java create mode 100644 Mage.Sets/src/mage/sets/futuresight/SkizzikSurger.java create mode 100644 Mage.Sets/src/mage/sets/futuresight/Whetwheel.java diff --git a/Mage.Sets/src/mage/sets/futuresight/BondedFetch.java b/Mage.Sets/src/mage/sets/futuresight/BondedFetch.java new file mode 100644 index 00000000000..4643278e41a --- /dev/null +++ b/Mage.Sets/src/mage/sets/futuresight/BondedFetch.java @@ -0,0 +1,71 @@ +/* + * 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.sets.futuresight; + +import java.util.UUID; +import mage.MageInt; +import mage.abilities.common.SimpleActivatedAbility; +import mage.abilities.costs.common.TapSourceCost; +import mage.abilities.effects.common.DrawDiscardControllerEffect; +import mage.abilities.keyword.DefenderAbility; +import mage.abilities.keyword.HasteAbility; +import mage.cards.CardImpl; +import mage.constants.CardType; +import mage.constants.Rarity; +import mage.constants.Zone; + +/** + * + * @author LoneFox + */ +public class BondedFetch extends CardImpl { + + public BondedFetch(UUID ownerId) { + super(ownerId, 50, "Bonded Fetch", Rarity.UNCOMMON, new CardType[]{CardType.CREATURE}, "{2}{U}"); + this.expansionSetCode = "FUT"; + this.subtype.add("Homunculus"); + this.power = new MageInt(0); + this.toughness = new MageInt(2); + + // Defender + this.addAbility(DefenderAbility.getInstance()); + // Haste + this.addAbility(HasteAbility.getInstance()); + // {tap}: Draw a card, then discard a card. + this.addAbility(new SimpleActivatedAbility(Zone.BATTLEFIELD, new DrawDiscardControllerEffect(), new TapSourceCost())); + } + + public BondedFetch(final BondedFetch card) { + super(card); + } + + @Override + public BondedFetch copy() { + return new BondedFetch(this); + } +} diff --git a/Mage.Sets/src/mage/sets/futuresight/FlowstoneEmbrace.java b/Mage.Sets/src/mage/sets/futuresight/FlowstoneEmbrace.java new file mode 100644 index 00000000000..403423e7232 --- /dev/null +++ b/Mage.Sets/src/mage/sets/futuresight/FlowstoneEmbrace.java @@ -0,0 +1,75 @@ +/* + * Copyright 2010 BetaSteward_at_googlemail.com. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are + * permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this list of + * conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, this list + * of conditions and the following disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY BetaSteward_at_googlemail.com ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BetaSteward_at_googlemail.com OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * The views and conclusions contained in the software and documentation are those of the + * authors and should not be interpreted as representing official policies, either expressed + * or implied, of BetaSteward_at_googlemail.com. + */ +package mage.sets.futuresight; + +import java.util.UUID; +import mage.abilities.Ability; +import mage.abilities.common.SimpleActivatedAbility; +import mage.abilities.costs.common.TapSourceCost; +import mage.abilities.effects.common.AttachEffect; +import mage.abilities.effects.common.continuous.BoostEnchantedEffect; +import mage.abilities.keyword.EnchantAbility; +import mage.cards.CardImpl; +import mage.constants.CardType; +import mage.constants.Duration; +import mage.constants.Outcome; +import mage.constants.Rarity; +import mage.constants.Zone; +import mage.target.TargetPermanent; +import mage.target.common.TargetCreaturePermanent; + +/** + * + * @author LoneFox + */ +public class FlowstoneEmbrace extends CardImpl { + + public FlowstoneEmbrace(UUID ownerId) { + super(ownerId, 113, "Flowstone Embrace", Rarity.COMMON, new CardType[]{CardType.ENCHANTMENT}, "{1}{R}"); + this.expansionSetCode = "FUT"; + this.subtype.add("Aura"); + + // Enchant creature + TargetPermanent auraTarget = new TargetCreaturePermanent(); + this.getSpellAbility().addTarget(auraTarget); + this.getSpellAbility().addEffect(new AttachEffect(Outcome.Neutral)); + Ability ability = new EnchantAbility(auraTarget.getTargetName()); + this.addAbility(ability); + // {tap}: Enchanted creature gets +2/-2 until end of turn. + this.addAbility(new SimpleActivatedAbility(Zone.BATTLEFIELD, new BoostEnchantedEffect(2, -2, Duration.EndOfTurn), new TapSourceCost())); + } + + public FlowstoneEmbrace(final FlowstoneEmbrace card) { + super(card); + } + + @Override + public FlowstoneEmbrace copy() { + return new FlowstoneEmbrace(this); + } +} diff --git a/Mage.Sets/src/mage/sets/futuresight/SkizzikSurger.java b/Mage.Sets/src/mage/sets/futuresight/SkizzikSurger.java new file mode 100644 index 00000000000..f0bde5b0526 --- /dev/null +++ b/Mage.Sets/src/mage/sets/futuresight/SkizzikSurger.java @@ -0,0 +1,68 @@ +/* + * Copyright 2010 BetaSteward_at_googlemail.com. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are + * permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this list of + * conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, this list + * of conditions and the following disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY BetaSteward_at_googlemail.com ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BetaSteward_at_googlemail.com OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * The views and conclusions contained in the software and documentation are those of the + * authors and should not be interpreted as representing official policies, either expressed + * or implied, of BetaSteward_at_googlemail.com. + */ +package mage.sets.futuresight; + +import java.util.UUID; +import mage.MageInt; +import mage.abilities.costs.common.SacrificeTargetCost; +import mage.abilities.keyword.EchoAbility; +import mage.abilities.keyword.HasteAbility; +import mage.cards.CardImpl; +import mage.constants.CardType; +import mage.constants.Rarity; +import mage.filter.common.FilterControlledLandPermanent; +import mage.target.common.TargetControlledPermanent; + +/** + * + * @author LoneFox + */ +public class SkizzikSurger extends CardImpl { + + public SkizzikSurger(UUID ownerId) { + super(ownerId, 120, "Skizzik Surger", Rarity.UNCOMMON, new CardType[]{CardType.CREATURE}, "{4}{R}{R}"); + this.expansionSetCode = "FUT"; + this.subtype.add("Elemental"); + this.power = new MageInt(6); + this.toughness = new MageInt(4); + + // Haste + this.addAbility(HasteAbility.getInstance()); + // Echo-Sacrifice two lands. + this.addAbility(new EchoAbility(new SacrificeTargetCost(new TargetControlledPermanent(2, 2, new FilterControlledLandPermanent("two lands"), true)))); + } + + public SkizzikSurger(final SkizzikSurger card) { + super(card); + } + + @Override + public SkizzikSurger copy() { + return new SkizzikSurger(this); + } +} diff --git a/Mage.Sets/src/mage/sets/futuresight/Whetwheel.java b/Mage.Sets/src/mage/sets/futuresight/Whetwheel.java new file mode 100644 index 00000000000..15658ae3781 --- /dev/null +++ b/Mage.Sets/src/mage/sets/futuresight/Whetwheel.java @@ -0,0 +1,72 @@ +/* + * Copyright 2010 BetaSteward_at_googlemail.com. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are + * permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this list of + * conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, this list + * of conditions and the following disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY BetaSteward_at_googlemail.com ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BetaSteward_at_googlemail.com OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * The views and conclusions contained in the software and documentation are those of the + * authors and should not be interpreted as representing official policies, either expressed + * or implied, of BetaSteward_at_googlemail.com. + */ +package mage.sets.futuresight; + +import java.util.UUID; +import mage.abilities.Ability; +import mage.abilities.common.SimpleActivatedAbility; +import mage.abilities.costs.common.TapSourceCost; +import mage.abilities.costs.mana.ManaCostsImpl; +import mage.abilities.dynamicvalue.common.ManacostVariableValue; +import mage.abilities.effects.common.PutLibraryIntoGraveTargetEffect; +import mage.abilities.keyword.MorphAbility; +import mage.cards.CardImpl; +import mage.constants.CardType; +import mage.constants.Rarity; +import mage.constants.Zone; +import mage.target.TargetPlayer; + +/** + * + * @author LoneFox + */ +public class Whetwheel extends CardImpl { + + public Whetwheel(UUID ownerId) { + super(ownerId, 168, "Whetwheel", Rarity.RARE, new CardType[]{CardType.ARTIFACT}, "{4}"); + this.expansionSetCode = "FUT"; + + // {X}{X}, {tap}: Target player puts the top X cards of his or her library into his or her graveyard. + Ability ability = new SimpleActivatedAbility(Zone.BATTLEFIELD, new PutLibraryIntoGraveTargetEffect( + new ManacostVariableValue()), new ManaCostsImpl("{X}{X}")); + ability.addCost(new TapSourceCost()); + ability.addTarget(new TargetPlayer()); + this.addAbility(ability); + // Morph {3} + this.addAbility(new MorphAbility(this, new ManaCostsImpl("{3}"))); + } + + public Whetwheel(final Whetwheel card) { + super(card); + } + + @Override + public Whetwheel copy() { + return new Whetwheel(this); + } +} From 0c2abc69de1af847ef95994eb218a0ecd5afe4cd Mon Sep 17 00:00:00 2001 From: LevelX2 Date: Fri, 25 Dec 2015 11:04:46 +0100 Subject: [PATCH 14/23] * Fixed some cost classes that didn't hadle correctly if a cost concerning card movement is paid or not. --- .../sets/darksteel/SteelshaperApprentice.java | 4 +- .../sets/dragonsmaze/KrasisIncubation.java | 4 +- .../src/mage/sets/dragonsmaze/MazesEnd.java | 4 +- .../mage/sets/exodus/RecurringNightmare.java | 4 +- .../sets/modernmasters/GrinningIgnus.java | 4 +- .../sets/saviorsofkamigawa/MoltingSkin.java | 4 +- .../src/mage/sets/tempest/BrokenFall.java | 4 +- .../src/mage/sets/urzassaga/Attunement.java | 4 +- .../src/mage/sets/visions/GossamerChains.java | 4 +- .../sets/zendikar/MagosiTheWaterveil.java | 4 +- .../costs/common/ExileFromGraveCost.java | 36 +++++++++-------- .../costs/common/ExileFromHandCost.java | 39 +++++++++++-------- .../costs/common/ExileFromStackCost.java | 25 ++++++------ .../common/ExileFromTopOfLibraryCost.java | 9 ++--- ...OpponentsCardFromExileToGraveyardCost.java | 2 +- .../costs/common/ExileSourceCost.java | 34 +++++++++------- .../common/ExileSourceFromGraveCost.java | 18 +++++---- .../costs/common/ExileXFromYourGraveCost.java | 9 ++--- ...rnToHandChosenControlledPermanentCost.java | 9 ++++- ...eturnToHandFromBattlefieldSourceCost.java} | 22 ++++++----- .../common/ReturnToHandFromGraveyardCost.java | 10 ++++- 21 files changed, 141 insertions(+), 112 deletions(-) rename Mage/src/main/java/mage/abilities/costs/common/{ReturnToHandSourceCost.java => ReturnToHandFromBattlefieldSourceCost.java} (78%) diff --git a/Mage.Sets/src/mage/sets/darksteel/SteelshaperApprentice.java b/Mage.Sets/src/mage/sets/darksteel/SteelshaperApprentice.java index f45923cdddb..64c4419ac17 100644 --- a/Mage.Sets/src/mage/sets/darksteel/SteelshaperApprentice.java +++ b/Mage.Sets/src/mage/sets/darksteel/SteelshaperApprentice.java @@ -37,7 +37,7 @@ import mage.constants.Zone; import mage.MageInt; import mage.abilities.Ability; import mage.abilities.common.SimpleActivatedAbility; -import mage.abilities.costs.common.ReturnToHandSourceCost; +import mage.abilities.costs.common.ReturnToHandFromBattlefieldSourceCost; import mage.abilities.costs.common.TapSourceCost; import mage.abilities.costs.mana.ColoredManaCost; import mage.abilities.effects.common.search.SearchLibraryPutInHandEffect; @@ -73,7 +73,7 @@ public class SteelshaperApprentice extends CardImpl { new SearchLibraryPutInHandEffect(new TargetCardInLibrary(1, 1, filter), true), new ColoredManaCost(ColoredManaSymbol.W)); ability.addCost(new TapSourceCost()); - ability.addCost(new ReturnToHandSourceCost()); + ability.addCost(new ReturnToHandFromBattlefieldSourceCost()); this.addAbility(ability); } diff --git a/Mage.Sets/src/mage/sets/dragonsmaze/KrasisIncubation.java b/Mage.Sets/src/mage/sets/dragonsmaze/KrasisIncubation.java index 911de590b06..b03a22ec227 100644 --- a/Mage.Sets/src/mage/sets/dragonsmaze/KrasisIncubation.java +++ b/Mage.Sets/src/mage/sets/dragonsmaze/KrasisIncubation.java @@ -35,7 +35,7 @@ import mage.constants.Zone; import mage.abilities.Ability; import mage.abilities.common.SimpleActivatedAbility; import mage.abilities.common.SimpleStaticAbility; -import mage.abilities.costs.common.ReturnToHandSourceCost; +import mage.abilities.costs.common.ReturnToHandFromBattlefieldSourceCost; import mage.abilities.costs.mana.ManaCostsImpl; import mage.abilities.effects.common.AttachEffect; import mage.abilities.effects.common.combat.CantBlockAttackActivateAttachedEffect; @@ -71,7 +71,7 @@ public class KrasisIncubation extends CardImpl { // {1}{G}{U}, Return Krasis Incubation to its owner's hand: Put two +1/+1 counters on enchanted creature. ability = new SimpleActivatedAbility(Zone.BATTLEFIELD, new AddPlusOneCountersAttachedEffect(2), new ManaCostsImpl("{1}{G}{U}")); - ability.addCost(new ReturnToHandSourceCost()); + ability.addCost(new ReturnToHandFromBattlefieldSourceCost()); this.addAbility(ability); } diff --git a/Mage.Sets/src/mage/sets/dragonsmaze/MazesEnd.java b/Mage.Sets/src/mage/sets/dragonsmaze/MazesEnd.java index 3fb9802f9e3..ac77c6e4c0a 100644 --- a/Mage.Sets/src/mage/sets/dragonsmaze/MazesEnd.java +++ b/Mage.Sets/src/mage/sets/dragonsmaze/MazesEnd.java @@ -38,7 +38,7 @@ import mage.constants.Zone; import mage.abilities.Ability; import mage.abilities.common.EntersBattlefieldTappedAbility; import mage.abilities.common.SimpleActivatedAbility; -import mage.abilities.costs.common.ReturnToHandSourceCost; +import mage.abilities.costs.common.ReturnToHandFromBattlefieldSourceCost; import mage.abilities.costs.common.TapSourceCost; import mage.abilities.costs.mana.GenericManaCost; import mage.abilities.effects.OneShotEffect; @@ -79,7 +79,7 @@ public class MazesEnd extends CardImpl { Ability ability = new SimpleActivatedAbility(Zone.BATTLEFIELD, new SearchLibraryPutInPlayEffect(new TargetCardInLibrary(filterCard)), new GenericManaCost(3)); ability.addEffect(new MazesEndEffect()); ability.addCost(new TapSourceCost()); - ability.addCost(new ReturnToHandSourceCost()); + ability.addCost(new ReturnToHandFromBattlefieldSourceCost()); this.addAbility(ability); } diff --git a/Mage.Sets/src/mage/sets/exodus/RecurringNightmare.java b/Mage.Sets/src/mage/sets/exodus/RecurringNightmare.java index 200cbf81999..ebd86b04d1d 100644 --- a/Mage.Sets/src/mage/sets/exodus/RecurringNightmare.java +++ b/Mage.Sets/src/mage/sets/exodus/RecurringNightmare.java @@ -30,7 +30,7 @@ package mage.sets.exodus; import java.util.UUID; import mage.abilities.Ability; import mage.abilities.common.ActivateAsSorceryActivatedAbility; -import mage.abilities.costs.common.ReturnToHandSourceCost; +import mage.abilities.costs.common.ReturnToHandFromBattlefieldSourceCost; import mage.abilities.costs.common.SacrificeTargetCost; import mage.abilities.effects.common.ReturnFromGraveyardToBattlefieldTargetEffect; import mage.cards.CardImpl; @@ -58,7 +58,7 @@ public class RecurringNightmare extends CardImpl { // Sacrifice a creature, Return Recurring Nightmare to its owner's hand: Return target creature card from your graveyard to the battlefield. Activate this ability only any time you could cast a sorcery. Ability ability = new ActivateAsSorceryActivatedAbility(Zone.BATTLEFIELD, new ReturnFromGraveyardToBattlefieldTargetEffect(), new SacrificeTargetCost(new TargetControlledPermanent(filter2))); ability.addTarget(new TargetCardInYourGraveyard(filter)); - ability.addCost(new ReturnToHandSourceCost()); + ability.addCost(new ReturnToHandFromBattlefieldSourceCost()); this.addAbility(ability); } diff --git a/Mage.Sets/src/mage/sets/modernmasters/GrinningIgnus.java b/Mage.Sets/src/mage/sets/modernmasters/GrinningIgnus.java index 3d239e84e5c..f9c3f1ae041 100644 --- a/Mage.Sets/src/mage/sets/modernmasters/GrinningIgnus.java +++ b/Mage.Sets/src/mage/sets/modernmasters/GrinningIgnus.java @@ -31,7 +31,7 @@ import java.util.UUID; import mage.MageInt; import mage.Mana; import mage.abilities.Ability; -import mage.abilities.costs.common.ReturnToHandSourceCost; +import mage.abilities.costs.common.ReturnToHandFromBattlefieldSourceCost; import mage.abilities.costs.mana.ManaCostsImpl; import mage.abilities.mana.ActivateAsSorceryManaAbility; import mage.cards.CardImpl; @@ -55,7 +55,7 @@ public class GrinningIgnus extends CardImpl { // {R}, Return Grinning Ignus to its owner's hand: Add {C}{C}{R} to your mana pool. Activate this ability only any time you could cast a sorcery. Ability ability = new ActivateAsSorceryManaAbility(Zone.BATTLEFIELD, new Mana(1, 0, 0, 0, 0, 2, 0), new ManaCostsImpl("{R}")); - ability.addCost(new ReturnToHandSourceCost()); + ability.addCost(new ReturnToHandFromBattlefieldSourceCost()); this.addAbility(ability); } diff --git a/Mage.Sets/src/mage/sets/saviorsofkamigawa/MoltingSkin.java b/Mage.Sets/src/mage/sets/saviorsofkamigawa/MoltingSkin.java index e5def0d4249..f023a36006b 100644 --- a/Mage.Sets/src/mage/sets/saviorsofkamigawa/MoltingSkin.java +++ b/Mage.Sets/src/mage/sets/saviorsofkamigawa/MoltingSkin.java @@ -33,7 +33,7 @@ import mage.constants.CardType; import mage.constants.Rarity; import mage.abilities.Ability; import mage.abilities.common.SimpleActivatedAbility; -import mage.abilities.costs.common.ReturnToHandSourceCost; +import mage.abilities.costs.common.ReturnToHandFromBattlefieldSourceCost; import mage.abilities.effects.common.RegenerateTargetEffect; import mage.cards.CardImpl; import mage.constants.Zone; @@ -50,7 +50,7 @@ public class MoltingSkin extends CardImpl { this.expansionSetCode = "SOK"; // Return Molting Skin to its owner's hand: Regenerate target creature. - Ability ability = new SimpleActivatedAbility(Zone.BATTLEFIELD, new RegenerateTargetEffect(), new ReturnToHandSourceCost()); + Ability ability = new SimpleActivatedAbility(Zone.BATTLEFIELD, new RegenerateTargetEffect(), new ReturnToHandFromBattlefieldSourceCost()); ability.addTarget(new TargetCreaturePermanent()); this.addAbility(ability); } diff --git a/Mage.Sets/src/mage/sets/tempest/BrokenFall.java b/Mage.Sets/src/mage/sets/tempest/BrokenFall.java index da96953dc56..95db4c47494 100644 --- a/Mage.Sets/src/mage/sets/tempest/BrokenFall.java +++ b/Mage.Sets/src/mage/sets/tempest/BrokenFall.java @@ -33,7 +33,7 @@ import mage.constants.CardType; import mage.constants.Rarity; import mage.abilities.Ability; import mage.abilities.common.SimpleActivatedAbility; -import mage.abilities.costs.common.ReturnToHandSourceCost; +import mage.abilities.costs.common.ReturnToHandFromBattlefieldSourceCost; import mage.abilities.effects.common.RegenerateTargetEffect; import mage.cards.CardImpl; import mage.constants.Zone; @@ -49,7 +49,7 @@ public class BrokenFall extends CardImpl { super(ownerId, 110, "Broken Fall", Rarity.COMMON, new CardType[]{CardType.ENCHANTMENT}, "{2}{G}"); this.expansionSetCode = "TMP"; - Ability ability = new SimpleActivatedAbility(Zone.BATTLEFIELD, new RegenerateTargetEffect(), new ReturnToHandSourceCost()); + Ability ability = new SimpleActivatedAbility(Zone.BATTLEFIELD, new RegenerateTargetEffect(), new ReturnToHandFromBattlefieldSourceCost()); ability.addTarget(new TargetCreaturePermanent()); this.addAbility(ability); } diff --git a/Mage.Sets/src/mage/sets/urzassaga/Attunement.java b/Mage.Sets/src/mage/sets/urzassaga/Attunement.java index 6fdbe0c8437..edd92c8c701 100644 --- a/Mage.Sets/src/mage/sets/urzassaga/Attunement.java +++ b/Mage.Sets/src/mage/sets/urzassaga/Attunement.java @@ -32,7 +32,7 @@ import mage.constants.CardType; import mage.constants.Rarity; import mage.constants.Zone; import mage.abilities.common.SimpleActivatedAbility; -import mage.abilities.costs.common.ReturnToHandSourceCost; +import mage.abilities.costs.common.ReturnToHandFromBattlefieldSourceCost; import mage.abilities.effects.common.discard.DiscardControllerEffect; import mage.abilities.effects.common.DrawCardSourceControllerEffect; import mage.cards.CardImpl; @@ -49,7 +49,7 @@ public class Attunement extends CardImpl { // Return Attunement to its owner's hand: Draw three cards, then discard four cards. - SimpleActivatedAbility ability = new SimpleActivatedAbility(Zone.BATTLEFIELD, new DrawCardSourceControllerEffect(3), new ReturnToHandSourceCost()); + SimpleActivatedAbility ability = new SimpleActivatedAbility(Zone.BATTLEFIELD, new DrawCardSourceControllerEffect(3), new ReturnToHandFromBattlefieldSourceCost()); ability.addEffect(new DiscardControllerEffect(4)); this.addAbility(ability); } diff --git a/Mage.Sets/src/mage/sets/visions/GossamerChains.java b/Mage.Sets/src/mage/sets/visions/GossamerChains.java index aa991ac8fd6..3ef34f24ff2 100644 --- a/Mage.Sets/src/mage/sets/visions/GossamerChains.java +++ b/Mage.Sets/src/mage/sets/visions/GossamerChains.java @@ -30,7 +30,7 @@ package mage.sets.visions; import java.util.UUID; import mage.abilities.Ability; import mage.abilities.common.SimpleActivatedAbility; -import mage.abilities.costs.common.ReturnToHandSourceCost; +import mage.abilities.costs.common.ReturnToHandFromBattlefieldSourceCost; import mage.abilities.effects.common.PreventDamageByTargetEffect; import mage.cards.CardImpl; import mage.constants.CardType; @@ -58,7 +58,7 @@ public class GossamerChains extends CardImpl { this.expansionSetCode = "VIS"; // Return Gossamer Chains to its owner's hand: Prevent all combat damage that would be dealt by target unblocked creature this turn. - Ability ability = new SimpleActivatedAbility(Zone.BATTLEFIELD, new PreventDamageByTargetEffect(Duration.EndOfTurn, true), new ReturnToHandSourceCost()); + Ability ability = new SimpleActivatedAbility(Zone.BATTLEFIELD, new PreventDamageByTargetEffect(Duration.EndOfTurn, true), new ReturnToHandFromBattlefieldSourceCost()); ability.addTarget(new TargetCreaturePermanent(filter)); this.addAbility(ability); } diff --git a/Mage.Sets/src/mage/sets/zendikar/MagosiTheWaterveil.java b/Mage.Sets/src/mage/sets/zendikar/MagosiTheWaterveil.java index 6850c94e1c8..0c42f748e97 100644 --- a/Mage.Sets/src/mage/sets/zendikar/MagosiTheWaterveil.java +++ b/Mage.Sets/src/mage/sets/zendikar/MagosiTheWaterveil.java @@ -32,7 +32,7 @@ import mage.abilities.Ability; import mage.abilities.common.EntersBattlefieldTappedAbility; import mage.abilities.common.SimpleActivatedAbility; import mage.abilities.costs.common.RemoveCountersSourceCost; -import mage.abilities.costs.common.ReturnToHandSourceCost; +import mage.abilities.costs.common.ReturnToHandFromBattlefieldSourceCost; import mage.abilities.costs.common.TapSourceCost; import mage.abilities.costs.mana.ManaCostsImpl; import mage.abilities.effects.common.counter.AddCountersSourceEffect; @@ -70,7 +70,7 @@ public class MagosiTheWaterveil extends CardImpl { // {T}, Remove an eon counter from Magosi, the Waterveil and return it to its owner's hand: Take an extra turn after this one. Ability ability2 = new SimpleActivatedAbility(Zone.BATTLEFIELD, new AddExtraTurnControllerEffect(), new TapSourceCost()); ability2.addCost(new RemoveCountersSourceCost(CounterType.EON.createInstance())); - ability2.addCost(new ReturnToHandSourceCost()); + ability2.addCost(new ReturnToHandFromBattlefieldSourceCost()); this.addAbility(ability2); } diff --git a/Mage/src/main/java/mage/abilities/costs/common/ExileFromGraveCost.java b/Mage/src/main/java/mage/abilities/costs/common/ExileFromGraveCost.java index 3c098074ca4..7ad275dfa39 100644 --- a/Mage/src/main/java/mage/abilities/costs/common/ExileFromGraveCost.java +++ b/Mage/src/main/java/mage/abilities/costs/common/ExileFromGraveCost.java @@ -1,16 +1,16 @@ /* * 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 @@ -20,12 +20,11 @@ * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - * + * * The views and conclusions contained in the software and documentation are those of the * authors and should not be interpreted as representing official policies, either expressed * or implied, of BetaSteward_at_googlemail.com. */ - package mage.abilities.costs.common; import java.util.ArrayList; @@ -34,6 +33,8 @@ import java.util.UUID; import mage.abilities.Ability; import mage.abilities.costs.CostImpl; import mage.cards.Card; +import mage.cards.Cards; +import mage.cards.CardsImpl; import mage.constants.Outcome; import mage.constants.Zone; import mage.game.Game; @@ -53,18 +54,17 @@ public class ExileFromGraveCost extends CostImpl { public ExileFromGraveCost(TargetCardInYourGraveyard target) { this.addTarget(target); if (target.getMaxNumberOfTargets() > 1) { - this.text = "Exile " + - (target.getNumberOfTargets() == 1 && target.getMaxNumberOfTargets() == Integer.MAX_VALUE ? "one or more" : - ((target.getNumberOfTargets() < target.getMaxNumberOfTargets() ? "up to ":"")) + - CardUtil.numberToText(target.getMaxNumberOfTargets())) + - " " + target.getTargetName(); - } - else { + this.text = "Exile " + + (target.getNumberOfTargets() == 1 && target.getMaxNumberOfTargets() == Integer.MAX_VALUE ? "one or more" + : ((target.getNumberOfTargets() < target.getMaxNumberOfTargets() ? "up to " : "")) + + CardUtil.numberToText(target.getMaxNumberOfTargets())) + + " " + target.getTargetName(); + } else { this.text = "Exile " + target.getTargetName(); } if (!this.text.endsWith(" from your graveyard")) { this.text = this.text + " from your graveyard"; - } + } } public ExileFromGraveCost(TargetCardInYourGraveyard target, String text) { @@ -77,7 +77,6 @@ public class ExileFromGraveCost extends CostImpl { this.text = "Exile " + target.getTargetName(); } - public ExileFromGraveCost(final ExileFromGraveCost cost) { super(cost); this.exiledCards.addAll(cost.getExiledCards()); @@ -88,15 +87,18 @@ public class ExileFromGraveCost extends CostImpl { Player controller = game.getPlayer(controllerId); if (controller != null) { if (targets.choose(Outcome.Exile, controllerId, sourceId, game)) { - for (UUID targetId: targets.get(0).getTargets()) { + for (UUID targetId : targets.get(0).getTargets()) { Card card = game.getCard(targetId); if (card == null || !game.getState().getZone(targetId).equals(Zone.GRAVEYARD)) { return false; } exiledCards.add(card); - paid |= controller.moveCardToExileWithInfo(card, null, null, sourceId, game, Zone.GRAVEYARD, true); } } + Cards cardsToExile = new CardsImpl(); + cardsToExile.addAll(exiledCards); + controller.moveCards(cardsToExile, Zone.EXILED, ability, game); + paid = true; } return paid; diff --git a/Mage/src/main/java/mage/abilities/costs/common/ExileFromHandCost.java b/Mage/src/main/java/mage/abilities/costs/common/ExileFromHandCost.java index 3ca78553cac..6f696804f85 100644 --- a/Mage/src/main/java/mage/abilities/costs/common/ExileFromHandCost.java +++ b/Mage/src/main/java/mage/abilities/costs/common/ExileFromHandCost.java @@ -25,17 +25,17 @@ * authors and should not be interpreted as representing official policies, either expressed * or implied, of BetaSteward_at_googlemail.com. */ - package mage.abilities.costs.common; - + import java.util.ArrayList; import java.util.List; import java.util.UUID; -import mage.Mana; import mage.abilities.Ability; import mage.abilities.costs.CostImpl; import mage.abilities.costs.mana.VariableManaCost; import mage.cards.Card; +import mage.cards.Cards; +import mage.cards.CardsImpl; import mage.constants.Outcome; import mage.constants.Zone; import mage.game.Game; @@ -47,47 +47,52 @@ import mage.target.common.TargetCardInHand; * @author LevelX2 */ public class ExileFromHandCost extends CostImpl { - + List cards = new ArrayList<>(); private boolean setXFromCMC; - + public ExileFromHandCost(TargetCardInHand target) { this(target, false); } + /** - * + * * @param target - * @param setXFromCMC the spells X value on the stack is set to the converted mana costs of the exiled card + * @param setXFromCMC the spells X value on the stack is set to the + * converted mana costs of the exiled card */ public ExileFromHandCost(TargetCardInHand target, boolean setXFromCMC) { this.addTarget(target); this.text = "exile " + target.getTargetName(); this.setXFromCMC = setXFromCMC; } - + public ExileFromHandCost(final ExileFromHandCost cost) { super(cost); - for (Card card: cost.cards) { + for (Card card : cost.cards) { this.cards.add(card.copy()); } this.setXFromCMC = cost.setXFromCMC; } - + @Override public boolean pay(Ability ability, Game game, UUID sourceId, UUID controllerId, boolean noMana) { if (targets.choose(Outcome.Exile, controllerId, sourceId, game)) { Player player = game.getPlayer(controllerId); int cmc = 0; - for (UUID targetId: targets.get(0).getTargets()) { + for (UUID targetId : targets.get(0).getTargets()) { Card card = player.getHand().get(targetId, game); if (card == null) { return false; } cmc += card.getManaCost().convertedManaCost(); this.cards.add(card); - paid |= player.moveCardToExileWithInfo(card, null, null, ability.getSourceId(), game, Zone.HAND, true); } - if (paid && setXFromCMC) { + Cards cardsToExile = new CardsImpl(); + cardsToExile.addAll(cards); + player.moveCards(cardsToExile, Zone.EXILED, ability, game); + paid = true; + if (setXFromCMC) { VariableManaCost vmc = new VariableManaCost(); vmc.setAmount(cmc); vmc.setPaid(); @@ -96,18 +101,18 @@ public class ExileFromHandCost extends CostImpl { } return paid; } - + @Override public boolean canPay(Ability ability, UUID sourceId, UUID controllerId, Game game) { return targets.canChoose(sourceId, controllerId, game); } - + @Override public ExileFromHandCost copy() { return new ExileFromHandCost(this); } - - public List getCards() { + + public List getCards() { return cards; } } diff --git a/Mage/src/main/java/mage/abilities/costs/common/ExileFromStackCost.java b/Mage/src/main/java/mage/abilities/costs/common/ExileFromStackCost.java index 64f9c36d72e..ec143a97e72 100644 --- a/Mage/src/main/java/mage/abilities/costs/common/ExileFromStackCost.java +++ b/Mage/src/main/java/mage/abilities/costs/common/ExileFromStackCost.java @@ -25,11 +25,9 @@ * authors and should not be interpreted as representing official policies, either expressed * or implied, of BetaSteward_at_googlemail.com. */ - package mage.abilities.costs.common; - -import java.util.UUID; +import java.util.UUID; import mage.abilities.Ability; import mage.abilities.costs.CostImpl; import mage.constants.Outcome; @@ -37,45 +35,46 @@ import mage.game.Game; import mage.game.stack.Spell; import mage.players.Player; import mage.target.TargetSpell; - + /** * * @author LevelX2 */ public class ExileFromStackCost extends CostImpl { - + public ExileFromStackCost(TargetSpell target) { this.addTarget(target); this.text = "Exile " + target.getTargetName(); } - + public ExileFromStackCost(ExileFromStackCost cost) { super(cost); } - + @Override public boolean pay(Ability ability, Game game, UUID sourceId, UUID controllerId, boolean noMana) { if (targets.choose(Outcome.Exile, controllerId, sourceId, game)) { Player player = game.getPlayer(controllerId); - for (UUID targetId: targets.get(0).getTargets()) { + for (UUID targetId : targets.get(0).getTargets()) { Spell spellToExile = game.getStack().getSpell(targetId); if (spellToExile == null) { return false; } - paid |= spellToExile.moveToExile(null, "", ability.getSourceId(), game); - if (paid && !game.isSimulation()) { - game.informPlayers(player.getLogName() + " exiles " + spellToExile.getName() +" (as costs)"); + spellToExile.moveToExile(null, "", ability.getSourceId(), game); + paid = true; + if (!game.isSimulation()) { + game.informPlayers(player.getLogName() + " exiles " + spellToExile.getName() + " (as costs)"); } } } return paid; } - + @Override public boolean canPay(Ability ability, UUID sourceId, UUID controllerId, Game game) { return targets.canChoose(controllerId, game); } - + @Override public ExileFromStackCost copy() { return new ExileFromStackCost(this); diff --git a/Mage/src/main/java/mage/abilities/costs/common/ExileFromTopOfLibraryCost.java b/Mage/src/main/java/mage/abilities/costs/common/ExileFromTopOfLibraryCost.java index 02620418756..cee479c6fd7 100644 --- a/Mage/src/main/java/mage/abilities/costs/common/ExileFromTopOfLibraryCost.java +++ b/Mage/src/main/java/mage/abilities/costs/common/ExileFromTopOfLibraryCost.java @@ -25,7 +25,6 @@ * authors and should not be interpreted as representing official policies, either expressed * or implied, of BetaSteward_at_googlemail.com. */ - package mage.abilities.costs.common; import java.util.UUID; @@ -47,7 +46,7 @@ public class ExileFromTopOfLibraryCost extends CostImpl { public ExileFromTopOfLibraryCost(int amount) { this.amount = amount; this.text = "Exile the top " + (amount == 1 ? "card" : CardUtil.numberToText(amount) + " cards") - + " of your library"; + + " of your library"; } public ExileFromTopOfLibraryCost(ExileFromTopOfLibraryCost cost) { @@ -58,7 +57,7 @@ public class ExileFromTopOfLibraryCost extends CostImpl { @Override public boolean canPay(Ability ability, UUID sourceId, UUID controllerId, Game game) { Player controller = game.getPlayer(controllerId); - if(controller == null) { + if (controller == null) { return false; } return controller.getLibrary().size() >= amount; @@ -67,8 +66,8 @@ public class ExileFromTopOfLibraryCost extends CostImpl { @Override public boolean pay(Ability ability, Game game, UUID sourceId, UUID controllerId, boolean noMana) { Player controller = game.getPlayer(controllerId); - if(controller != null) { - controller.moveCards(controller.getLibrary().getTopCards(game, amount), Zone.LIBRARY, Zone.EXILED, ability, game); + if (controller != null) { + controller.moveCards(controller.getLibrary().getTopCards(game, amount), Zone.EXILED, ability, game); paid = true; } return paid; diff --git a/Mage/src/main/java/mage/abilities/costs/common/ExileOpponentsCardFromExileToGraveyardCost.java b/Mage/src/main/java/mage/abilities/costs/common/ExileOpponentsCardFromExileToGraveyardCost.java index 94e498b2e3d..061767a1124 100644 --- a/Mage/src/main/java/mage/abilities/costs/common/ExileOpponentsCardFromExileToGraveyardCost.java +++ b/Mage/src/main/java/mage/abilities/costs/common/ExileOpponentsCardFromExileToGraveyardCost.java @@ -48,7 +48,7 @@ public class ExileOpponentsCardFromExileToGraveyardCost extends CostImpl { Card card = game.getCard(target.getFirstTarget()); if (card != null) { paid = true; - controller.moveCards(card, null, Zone.GRAVEYARD, ability, game); + controller.moveCards(card, Zone.GRAVEYARD, ability, game); } } } diff --git a/Mage/src/main/java/mage/abilities/costs/common/ExileSourceCost.java b/Mage/src/main/java/mage/abilities/costs/common/ExileSourceCost.java index 0246273ad3e..8db34d265d8 100644 --- a/Mage/src/main/java/mage/abilities/costs/common/ExileSourceCost.java +++ b/Mage/src/main/java/mage/abilities/costs/common/ExileSourceCost.java @@ -1,16 +1,16 @@ /* * 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 @@ -20,12 +20,11 @@ * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - * + * * The views and conclusions contained in the software and documentation are those of the * authors and should not be interpreted as representing official policies, either expressed * or implied, of BetaSteward_at_googlemail.com. */ - package mage.abilities.costs.common; import java.util.UUID; @@ -45,14 +44,16 @@ import mage.util.CardUtil; public class ExileSourceCost extends CostImpl { private boolean toUniqueExileZone; - + public ExileSourceCost() { this.text = "Exile {this}"; } + /** - * - * @param toUniqueExileZone moves the card to a source object dependant unique exile zone, so another - * effect of the same source object (e.g. Deadeye Navigator) can identify the card + * + * @param toUniqueExileZone moves the card to a source object dependant + * unique exile zone, so another effect of the same source object (e.g. + * Deadeye Navigator) can identify the card */ public ExileSourceCost(boolean toUniqueExileZone) { this.text = "Exile {this}"; @@ -68,14 +69,19 @@ public class ExileSourceCost extends CostImpl { public boolean pay(Ability ability, Game game, UUID sourceId, UUID controllerId, boolean noMana) { MageObject sourceObject = ability.getSourceObject(game); Player controller = game.getPlayer(controllerId); - if (controller != null && sourceObject != null && (sourceObject instanceof Card)) { + if (controller != null && sourceObject != null && (sourceObject instanceof Card)) { UUID exileZoneId = null; String exileZoneName = ""; if (toUniqueExileZone) { exileZoneId = CardUtil.getExileZoneId(game, ability.getSourceId(), ability.getSourceObjectZoneChangeCounter()); - exileZoneName = sourceObject.getName(); - } - paid = controller.moveCardToExileWithInfo((Card) sourceObject, exileZoneId, exileZoneName, sourceId, game, game.getState().getZone(sourceObject.getId()), true); + exileZoneName = sourceObject.getName(); + } + controller.moveCardToExileWithInfo((Card) sourceObject, exileZoneId, exileZoneName, sourceId, game, game.getState().getZone(sourceObject.getId()), true); + // 117.11. The actions performed when paying a cost may be modified by effects. + // Even if they are, meaning the actions that are performed don't match the actions + // that are called for, the cost has still been paid. + // so return state here is not important because the user indended to exile the target anyway + paid = true; } return paid; } diff --git a/Mage/src/main/java/mage/abilities/costs/common/ExileSourceFromGraveCost.java b/Mage/src/main/java/mage/abilities/costs/common/ExileSourceFromGraveCost.java index 1448b9df09c..ff72d067267 100644 --- a/Mage/src/main/java/mage/abilities/costs/common/ExileSourceFromGraveCost.java +++ b/Mage/src/main/java/mage/abilities/costs/common/ExileSourceFromGraveCost.java @@ -1,16 +1,16 @@ /* * 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 @@ -20,12 +20,11 @@ * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - * + * * The views and conclusions contained in the software and documentation are those of the * authors and should not be interpreted as representing official policies, either expressed * or implied, of BetaSteward_at_googlemail.com. */ - package mage.abilities.costs.common; import java.util.UUID; @@ -56,7 +55,12 @@ public class ExileSourceFromGraveCost extends CostImpl { if (controller != null) { Card card = game.getCard(sourceId); if (card != null && game.getState().getZone(sourceId).equals(Zone.GRAVEYARD)) { - paid = controller.moveCardToExileWithInfo(card, null, "", sourceId, game, Zone.GRAVEYARD, true); + controller.moveCardToExileWithInfo(card, null, "", sourceId, game, Zone.GRAVEYARD, true); + // 117.11. The actions performed when paying a cost may be modified by effects. + // Even if they are, meaning the actions that are performed don't match the actions + // that are called for, the cost has still been paid. + // so return state here is not important because the user indended to exile the target anyway + paid = true; } } return paid; diff --git a/Mage/src/main/java/mage/abilities/costs/common/ExileXFromYourGraveCost.java b/Mage/src/main/java/mage/abilities/costs/common/ExileXFromYourGraveCost.java index 37a22d6a81d..b8d7d0b24fc 100644 --- a/Mage/src/main/java/mage/abilities/costs/common/ExileXFromYourGraveCost.java +++ b/Mage/src/main/java/mage/abilities/costs/common/ExileXFromYourGraveCost.java @@ -25,7 +25,6 @@ * authors and should not be interpreted as representing official policies, either expressed * or implied, of BetaSteward_at_googlemail.com. */ - package mage.abilities.costs.common; import mage.abilities.Ability; @@ -40,8 +39,7 @@ import mage.target.common.TargetCardInYourGraveyard; * * @author LevelX2 */ - -public class ExileXFromYourGraveCost extends VariableCostImpl { +public class ExileXFromYourGraveCost extends VariableCostImpl { protected FilterCard filter; @@ -50,10 +48,9 @@ public class ExileXFromYourGraveCost extends VariableCostImpl { } public ExileXFromYourGraveCost(FilterCard filter, boolean additionalCostText) { - super(new StringBuilder(filter.getMessage()).append(" to exile").toString()); + super(filter.getMessage() + " to exile"); this.filter = filter; - this.text = new StringBuilder(additionalCostText ? "As an additional cost to cast {source}, exile ":"Exile ") - .append(xText).append(" ").append(filter.getMessage()).toString(); + this.text = (additionalCostText ? "As an additional cost to cast {source}, exile " : "Exile ") + xText + " " + filter.getMessage(); } public ExileXFromYourGraveCost(final ExileXFromYourGraveCost cost) { diff --git a/Mage/src/main/java/mage/abilities/costs/common/ReturnToHandChosenControlledPermanentCost.java b/Mage/src/main/java/mage/abilities/costs/common/ReturnToHandChosenControlledPermanentCost.java index 238377fdf4b..2366e9d7dfe 100644 --- a/Mage/src/main/java/mage/abilities/costs/common/ReturnToHandChosenControlledPermanentCost.java +++ b/Mage/src/main/java/mage/abilities/costs/common/ReturnToHandChosenControlledPermanentCost.java @@ -27,10 +27,14 @@ */ package mage.abilities.costs.common; +import java.util.HashSet; +import java.util.Set; import java.util.UUID; import mage.abilities.Ability; import mage.abilities.costs.CostImpl; +import mage.cards.Card; import mage.constants.Outcome; +import mage.constants.Zone; import mage.game.Game; import mage.game.permanent.Permanent; import mage.players.Player; @@ -61,13 +65,16 @@ public class ReturnToHandChosenControlledPermanentCost extends CostImpl { Player controller = game.getPlayer(controllerId); if (controller != null) { if (targets.choose(Outcome.ReturnToHand, controllerId, sourceId, game)) { + Set permanentsToReturn = new HashSet<>(); for (UUID targetId : targets.get(0).getTargets()) { Permanent permanent = game.getPermanent(targetId); if (permanent == null) { return false; } - paid |= controller.moveCardToHandWithInfo(permanent, sourceId, game); + permanentsToReturn.add((Card) permanent); } + controller.moveCards(permanentsToReturn, Zone.HAND, ability, game); + paid = true; } } return paid; diff --git a/Mage/src/main/java/mage/abilities/costs/common/ReturnToHandSourceCost.java b/Mage/src/main/java/mage/abilities/costs/common/ReturnToHandFromBattlefieldSourceCost.java similarity index 78% rename from Mage/src/main/java/mage/abilities/costs/common/ReturnToHandSourceCost.java rename to Mage/src/main/java/mage/abilities/costs/common/ReturnToHandFromBattlefieldSourceCost.java index 43ee14395ba..5f4d4c6396a 100644 --- a/Mage/src/main/java/mage/abilities/costs/common/ReturnToHandSourceCost.java +++ b/Mage/src/main/java/mage/abilities/costs/common/ReturnToHandFromBattlefieldSourceCost.java @@ -25,36 +25,38 @@ * authors and should not be interpreted as representing official policies, either expressed * or implied, of BetaSteward_at_googlemail.com. */ - package mage.abilities.costs.common; import java.util.UUID; - -import mage.constants.Zone; import mage.abilities.Ability; import mage.abilities.costs.CostImpl; +import mage.constants.Zone; import mage.game.Game; import mage.game.permanent.Permanent; +import mage.players.Player; /** * @author Loki */ -public class ReturnToHandSourceCost extends CostImpl { +public class ReturnToHandFromBattlefieldSourceCost extends CostImpl { - public ReturnToHandSourceCost() { + public ReturnToHandFromBattlefieldSourceCost() { this.text = "return {this} to its owner's hand"; } - public ReturnToHandSourceCost(ReturnToHandSourceCost cost) { + public ReturnToHandFromBattlefieldSourceCost(ReturnToHandFromBattlefieldSourceCost cost) { super(cost); } @Override public boolean pay(Ability ability, Game game, UUID sourceId, UUID controllerId, boolean noMana) { Permanent permanent = game.getPermanent(sourceId); - if (permanent == null) + Player controller = game.getPlayer(controllerId); + if (permanent == null || controller == null) { return false; - paid = permanent.moveToZone(Zone.HAND, sourceId, game, false); + } + controller.moveCards(permanent, Zone.HAND, ability, game); + paid = true; return paid; } @@ -64,7 +66,7 @@ public class ReturnToHandSourceCost extends CostImpl { } @Override - public ReturnToHandSourceCost copy() { - return new ReturnToHandSourceCost(this); + public ReturnToHandFromBattlefieldSourceCost copy() { + return new ReturnToHandFromBattlefieldSourceCost(this); } } diff --git a/Mage/src/main/java/mage/abilities/costs/common/ReturnToHandFromGraveyardCost.java b/Mage/src/main/java/mage/abilities/costs/common/ReturnToHandFromGraveyardCost.java index 48dc5dcdadb..e12103dc964 100644 --- a/Mage/src/main/java/mage/abilities/costs/common/ReturnToHandFromGraveyardCost.java +++ b/Mage/src/main/java/mage/abilities/costs/common/ReturnToHandFromGraveyardCost.java @@ -27,10 +27,14 @@ */ package mage.abilities.costs.common; +import java.util.LinkedHashSet; +import java.util.Set; import java.util.UUID; import mage.abilities.Ability; import mage.abilities.costs.CostImpl; +import mage.cards.Card; import mage.constants.Outcome; +import mage.constants.Zone; import mage.game.Game; import mage.players.Player; import mage.target.common.TargetCardInYourGraveyard; @@ -59,14 +63,18 @@ public class ReturnToHandFromGraveyardCost extends CostImpl { Player controller = game.getPlayer(controllerId); if (controller != null) { if (targets.choose(Outcome.ReturnToHand, controllerId, sourceId, game)) { + Set cardsToMove = new LinkedHashSet<>(); for (UUID targetId : targets.get(0).getTargets()) { mage.cards.Card targetCard = game.getCard(targetId); if (targetCard == null) { return false; } - paid |= controller.moveCardToHandWithInfo(targetCard, sourceId, game); + cardsToMove.add(targetCard); } + controller.moveCards(cardsToMove, Zone.HAND, ability, game); + paid = true; } + } return paid; } From 8feb31405b0d5a79452284cba023e873512862a2 Mon Sep 17 00:00:00 2001 From: LoneFox Date: Fri, 25 Dec 2015 12:41:31 +0200 Subject: [PATCH 15/23] Extract UnlessPaysDelayedEffect from Quenchable Fire into its own file and implement cards that use it: Glass Asp, Nafs Asp, and Sabertooth Cobra --- .../src/mage/sets/arabiannights/NafsAsp.java | 69 +++++++ .../src/mage/sets/conflux/QuenchableFire.java | 139 ++----------- .../src/mage/sets/fourthedition/NafsAsp.java | 52 +++++ .../src/mage/sets/mirage/SabertoothCobra.java | 75 +++++++ .../src/mage/sets/timespiral/GlassAsp.java | 69 +++++++ .../common/UnlessPaysDelayedEffect.java | 186 ++++++++++++++++++ 6 files changed, 462 insertions(+), 128 deletions(-) create mode 100644 Mage.Sets/src/mage/sets/arabiannights/NafsAsp.java create mode 100644 Mage.Sets/src/mage/sets/fourthedition/NafsAsp.java create mode 100644 Mage.Sets/src/mage/sets/mirage/SabertoothCobra.java create mode 100644 Mage.Sets/src/mage/sets/timespiral/GlassAsp.java create mode 100644 Mage/src/main/java/mage/abilities/effects/common/UnlessPaysDelayedEffect.java diff --git a/Mage.Sets/src/mage/sets/arabiannights/NafsAsp.java b/Mage.Sets/src/mage/sets/arabiannights/NafsAsp.java new file mode 100644 index 00000000000..810922c640c --- /dev/null +++ b/Mage.Sets/src/mage/sets/arabiannights/NafsAsp.java @@ -0,0 +1,69 @@ +/* + * Copyright 2010 BetaSteward_at_googlemail.com. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are + * permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this list of + * conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, this list + * of conditions and the following disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY BetaSteward_at_googlemail.com ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BetaSteward_at_googlemail.com OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * The views and conclusions contained in the software and documentation are those of the + * authors and should not be interpreted as representing official policies, either expressed + * or implied, of BetaSteward_at_googlemail.com. + */ +package mage.sets.arabiannights; + +import java.util.UUID; +import mage.MageInt; +import mage.abilities.common.DealsDamageToAPlayerTriggeredAbility; +import mage.abilities.costs.mana.ManaCostsImpl; +import mage.abilities.effects.common.LoseLifeTargetEffect; +import mage.abilities.effects.common.UnlessPaysDelayedEffect; +import mage.cards.CardImpl; +import mage.constants.CardType; +import mage.constants.PhaseStep; +import mage.constants.Rarity; + +/** + * + * @author LoneFox + */ +public class NafsAsp extends CardImpl { + + public NafsAsp(UUID ownerId) { + super(ownerId, 36, "Nafs Asp", Rarity.COMMON, new CardType[]{CardType.CREATURE}, "{G}"); + this.expansionSetCode = "ARN"; + this.subtype.add("Snake"); + this.power = new MageInt(1); + this.toughness = new MageInt(1); + + // Whenever Nafs Asp deals damage to a player, that player loses 1 life at the beginning of his or her next draw step unless he or she pays {1} before that draw step. + this.addAbility(new DealsDamageToAPlayerTriggeredAbility(new UnlessPaysDelayedEffect( + new ManaCostsImpl("{1}"), new LoseLifeTargetEffect(1), PhaseStep.DRAW, true, + "that player loses 1 life at the beginning of his or her next draw step unless he or she pays {1} before that draw step."), + false, true)); + } + + public NafsAsp(final NafsAsp card) { + super(card); + } + + @Override + public NafsAsp copy() { + return new NafsAsp(this); + } +} diff --git a/Mage.Sets/src/mage/sets/conflux/QuenchableFire.java b/Mage.Sets/src/mage/sets/conflux/QuenchableFire.java index 881d4bbb18a..98ecf9f98a2 100644 --- a/Mage.Sets/src/mage/sets/conflux/QuenchableFire.java +++ b/Mage.Sets/src/mage/sets/conflux/QuenchableFire.java @@ -1,16 +1,16 @@ /* * 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 @@ -20,7 +20,7 @@ * 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. @@ -29,23 +29,13 @@ package mage.sets.conflux; import java.util.UUID; -import mage.MageObject; -import mage.abilities.Ability; -import mage.abilities.DelayedTriggeredAbility; -import mage.abilities.SpecialAction; import mage.abilities.costs.mana.ManaCostsImpl; -import mage.abilities.effects.Effect; -import mage.abilities.effects.OneShotEffect; import mage.abilities.effects.common.DamageTargetEffect; -import mage.abilities.effects.common.RemoveDelayedTriggeredAbilityEffect; -import mage.abilities.effects.common.RemoveSpecialActionEffect; +import mage.abilities.effects.common.UnlessPaysDelayedEffect; import mage.cards.CardImpl; import mage.constants.CardType; -import mage.constants.Outcome; +import mage.constants.PhaseStep; import mage.constants.Rarity; -import mage.game.Game; -import mage.game.events.GameEvent; -import mage.game.events.GameEvent.EventType; import mage.target.TargetPlayer; /** @@ -59,10 +49,12 @@ public class QuenchableFire extends CardImpl { this.expansionSetCode = "CON"; // Quenchable Fire deals 3 damage to target player. - // It deals an additional 3 damage to that player at the beginning of your next upkeep step unless he or she pays {U} before that step. this.getSpellAbility().addTarget(new TargetPlayer()); this.getSpellAbility().addEffect(new DamageTargetEffect(3)); - this.getSpellAbility().addEffect(new QuenchableFireEffect()); + // It deals an additional 3 damage to that player at the beginning of your next upkeep step unless he or she pays {U} before that step. + this.getSpellAbility().addEffect(new UnlessPaysDelayedEffect(new ManaCostsImpl("{U}"), + new DamageTargetEffect(3, true, "that player"), PhaseStep.UPKEEP, false, + "It deals an additional 3 damage to that player at the beginning of your next upkeep step unless he or she pays {U} before that step.")); } public QuenchableFire(final QuenchableFire card) { @@ -74,112 +66,3 @@ public class QuenchableFire extends CardImpl { return new QuenchableFire(this); } } - -class QuenchableFireEffect extends OneShotEffect { - - public QuenchableFireEffect() { - super(Outcome.Damage); - staticText = "{this} deals an additional 3 damage to that player at the beginning of your next upkeep step unless he or she pays {U} before that step." - + "
Use the Special button to pay the {U} with a special action before the beginning of your next upkeep step."; - } - - public QuenchableFireEffect(final QuenchableFireEffect effect) { - super(effect); - } - - @Override - public QuenchableFireEffect copy() { - return new QuenchableFireEffect(this); - } - - @Override - public boolean apply(Game game, Ability source) { - MageObject sourceObject = source.getSourceObject(game); - if (sourceObject != null) { - - //create special action - QuenchableFireSpecialAction newAction = new QuenchableFireSpecialAction(); - - //create delayed triggered ability - QuenchableFireDelayedTriggeredAbility delayedAbility = new QuenchableFireDelayedTriggeredAbility(); - delayedAbility.setSourceId(source.getSourceId()); - delayedAbility.setControllerId(source.getControllerId()); - delayedAbility.setSourceObject(sourceObject, game); - delayedAbility.getTargets().addAll(source.getTargets()); - delayedAbility.setSpecialActionId(newAction.getId()); - UUID delayedAbilityId = game.addDelayedTriggeredAbility(delayedAbility); - - // update special action - newAction.addCost(new ManaCostsImpl("{U}")); - Effect effect = new RemoveDelayedTriggeredAbilityEffect(delayedAbilityId); - newAction.addEffect(effect); - effect.setText(sourceObject.getIdName() + " - Pay {U} to remove the triggered ability that deals 3 damage to you at the beginning of your next upkeep step"); - newAction.addEffect(new RemoveSpecialActionEffect(newAction.getId())); - newAction.setSourceId(source.getSourceId()); - newAction.setControllerId(source.getFirstTarget()); - newAction.getTargets().addAll(source.getTargets()); - game.getState().getSpecialActions().add(newAction); - return true; - } - return false; - } - -} - -class QuenchableFireDelayedTriggeredAbility extends DelayedTriggeredAbility { - - private UUID specialActionId; - - public QuenchableFireDelayedTriggeredAbility() { - super(new DamageTargetEffect(3)); - } - - public void setSpecialActionId(UUID specialActionId) { - this.specialActionId = specialActionId; - } - - public QuenchableFireDelayedTriggeredAbility(final QuenchableFireDelayedTriggeredAbility ability) { - super(ability); - } - - @Override - public QuenchableFireDelayedTriggeredAbility copy() { - return new QuenchableFireDelayedTriggeredAbility(this); - } - - @Override - public boolean checkEventType(GameEvent event, Game game) { - return event.getType() == EventType.UPKEEP_STEP_PRE; - } - - @Override - public boolean checkTrigger(GameEvent event, Game game) { - if (event.getPlayerId().equals(this.controllerId)) { - for (SpecialAction action: game.getState().getSpecialActions()) { - if (action.getId().equals(specialActionId)) { - game.getState().getSpecialActions().remove(action); - break; - } - } - return true; - } - return false; - } - -} - -class QuenchableFireSpecialAction extends SpecialAction { - - public QuenchableFireSpecialAction() { - super(); - } - - public QuenchableFireSpecialAction(final QuenchableFireSpecialAction ability) { - super(ability); - } - - @Override - public QuenchableFireSpecialAction copy() { - return new QuenchableFireSpecialAction(this); - } -} \ No newline at end of file diff --git a/Mage.Sets/src/mage/sets/fourthedition/NafsAsp.java b/Mage.Sets/src/mage/sets/fourthedition/NafsAsp.java new file mode 100644 index 00000000000..34c8f18ad57 --- /dev/null +++ b/Mage.Sets/src/mage/sets/fourthedition/NafsAsp.java @@ -0,0 +1,52 @@ +/* + * Copyright 2010 BetaSteward_at_googlemail.com. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are + * permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this list of + * conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, this list + * of conditions and the following disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY BetaSteward_at_googlemail.com ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BetaSteward_at_googlemail.com OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * The views and conclusions contained in the software and documentation are those of the + * authors and should not be interpreted as representing official policies, either expressed + * or implied, of BetaSteward_at_googlemail.com. + */ +package mage.sets.fourthedition; + +import java.util.UUID; + +/** + * + * @author LoneFox + */ +public class NafsAsp extends mage.sets.arabiannights.NafsAsp { + + public NafsAsp(UUID ownerId) { + super(ownerId); + this.cardNumber = 148; + this.expansionSetCode = "4ED"; + } + + public NafsAsp(final NafsAsp card) { + super(card); + } + + @Override + public NafsAsp copy() { + return new NafsAsp(this); + } +} diff --git a/Mage.Sets/src/mage/sets/mirage/SabertoothCobra.java b/Mage.Sets/src/mage/sets/mirage/SabertoothCobra.java new file mode 100644 index 00000000000..2de9e874109 --- /dev/null +++ b/Mage.Sets/src/mage/sets/mirage/SabertoothCobra.java @@ -0,0 +1,75 @@ +/* + * Copyright 2010 BetaSteward_at_googlemail.com. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are + * permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this list of + * conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, this list + * of conditions and the following disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY BetaSteward_at_googlemail.com ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BetaSteward_at_googlemail.com OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * The views and conclusions contained in the software and documentation are those of the + * authors and should not be interpreted as representing official policies, either expressed + * or implied, of BetaSteward_at_googlemail.com. + */ +package mage.sets.mirage; + +import java.util.UUID; +import mage.MageInt; +import mage.abilities.Ability; +import mage.abilities.common.DealsDamageToAPlayerTriggeredAbility; +import mage.abilities.costs.mana.ManaCostsImpl; +import mage.abilities.effects.Effect; +import mage.abilities.effects.common.UnlessPaysDelayedEffect; +import mage.abilities.effects.common.counter.AddPoisonCounterTargetEffect; +import mage.cards.CardImpl; +import mage.constants.CardType; +import mage.constants.PhaseStep; +import mage.constants.Rarity; + +/** + * + * @author LoneFox + */ +public class SabertoothCobra extends CardImpl { + + public SabertoothCobra(UUID ownerId) { + super(ownerId, 136, "Sabertooth Cobra", Rarity.COMMON, new CardType[]{CardType.CREATURE}, "{2}{G}"); + this.expansionSetCode = "MIR"; + this.subtype.add("Snake"); + this.power = new MageInt(2); + this.toughness = new MageInt(2); + + // Whenever Sabertooth Cobra deals damage to a player, he or she gets a poison counter. That player gets another poison counter at the beginning of his or her next upkeep unless he or she pays {2} before that turn. + Effect effect = new AddPoisonCounterTargetEffect(1); + effect.setText("that player gets a poison counter"); + Ability ability = new DealsDamageToAPlayerTriggeredAbility(effect, false, true); + effect = new AddPoisonCounterTargetEffect(1); + effect.setText("That player gets another poison counter."); + ability.addEffect(new UnlessPaysDelayedEffect(new ManaCostsImpl("{2}"), effect, PhaseStep.UPKEEP, true, + "That player gets another poison counter at the beginning of his or her next upkeep unless he or she pays {2} before that turn.")); + this.addAbility(ability); + } + + public SabertoothCobra(final SabertoothCobra card) { + super(card); + } + + @Override + public SabertoothCobra copy() { + return new SabertoothCobra(this); + } +} diff --git a/Mage.Sets/src/mage/sets/timespiral/GlassAsp.java b/Mage.Sets/src/mage/sets/timespiral/GlassAsp.java new file mode 100644 index 00000000000..ff69cd88e05 --- /dev/null +++ b/Mage.Sets/src/mage/sets/timespiral/GlassAsp.java @@ -0,0 +1,69 @@ +/* + * Copyright 2010 BetaSteward_at_googlemail.com. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are + * permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this list of + * conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, this list + * of conditions and the following disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY BetaSteward_at_googlemail.com ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BetaSteward_at_googlemail.com OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * The views and conclusions contained in the software and documentation are those of the + * authors and should not be interpreted as representing official policies, either expressed + * or implied, of BetaSteward_at_googlemail.com. + */ +package mage.sets.timespiral; + +import java.util.UUID; +import mage.MageInt; +import mage.abilities.common.DealsDamageToAPlayerTriggeredAbility; +import mage.abilities.costs.mana.ManaCostsImpl; +import mage.abilities.effects.common.LoseLifeTargetEffect; +import mage.abilities.effects.common.UnlessPaysDelayedEffect; +import mage.cards.CardImpl; +import mage.constants.CardType; +import mage.constants.PhaseStep; +import mage.constants.Rarity; + +/** + * + * @author LoneFox + */ +public class GlassAsp extends CardImpl { + + public GlassAsp(UUID ownerId) { + super(ownerId, 197, "Glass Asp", Rarity.COMMON, new CardType[]{CardType.CREATURE}, "{1}{G}{G}"); + this.expansionSetCode = "TSP"; + this.subtype.add("Snake"); + this.power = new MageInt(2); + this.toughness = new MageInt(1); + + // Whenever Glass Asp deals combat damage to a player, that player loses 2 life at the beginning of his or her next draw step unless he or she pays {2} before that step. + this.addAbility(new DealsDamageToAPlayerTriggeredAbility(new UnlessPaysDelayedEffect( + new ManaCostsImpl("{2}"), new LoseLifeTargetEffect(2), PhaseStep.DRAW, true, + "that player loses 2 life at the beginning of his or her next draw step unless he or she pays {2} before that draw step."), + false, true)); + } + + public GlassAsp(final GlassAsp card) { + super(card); + } + + @Override + public GlassAsp copy() { + return new GlassAsp(this); + } +} diff --git a/Mage/src/main/java/mage/abilities/effects/common/UnlessPaysDelayedEffect.java b/Mage/src/main/java/mage/abilities/effects/common/UnlessPaysDelayedEffect.java new file mode 100644 index 00000000000..a474a2a19e2 --- /dev/null +++ b/Mage/src/main/java/mage/abilities/effects/common/UnlessPaysDelayedEffect.java @@ -0,0 +1,186 @@ +/* + * Copyright 2010 BetaSteward_at_googlemail.com. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are + * permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this list of + * conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, this list + * of conditions and the following disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY BetaSteward_at_googlemail.com ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BetaSteward_at_googlemail.com OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * The views and conclusions contained in the software and documentation are those of the + * authors and should not be interpreted as representing official policies, either expressed + * or implied, of BetaSteward_at_googlemail.com. + */ +package mage.abilities.effects.common; + +import java.util.UUID; +import mage.MageObject; +import mage.abilities.Ability; +import mage.abilities.DelayedTriggeredAbility; +import mage.abilities.SpecialAction; +import mage.abilities.costs.Cost; +import mage.abilities.effects.Effect; +import mage.abilities.effects.OneShotEffect; +import mage.abilities.effects.common.RemoveDelayedTriggeredAbilityEffect; +import mage.abilities.effects.common.RemoveSpecialActionEffect; +import mage.constants.Outcome; +import mage.constants.PhaseStep; +import mage.game.Game; +import mage.game.events.GameEvent.EventType; +import mage.game.events.GameEvent; +import mage.target.targetpointer.FixedTarget; + +/** + * + * @author LoneFox (based on Quenchable Fire code by BetaSteward_at_googlemail.com) + */ + +public class UnlessPaysDelayedEffect extends OneShotEffect { + + private final Cost cost; + private final Effect effect; + private final PhaseStep step; + private final boolean affectedPlayersTurn; + + public UnlessPaysDelayedEffect(Cost cost, Effect effect, PhaseStep step, boolean affectedPlayersTurn, String text) { + super(Outcome.Detriment); + this.cost = cost; + this.effect = effect; + this.step = step; + this.affectedPlayersTurn = affectedPlayersTurn; + staticText = text + "
Use the Special button to pay the " + cost.getText() + + " with a special action before that step."; + } + + public UnlessPaysDelayedEffect(final UnlessPaysDelayedEffect effect) { + super(effect); + this.cost = effect.cost.copy(); + this.effect = effect.effect.copy(); + this.step = effect.step; + this.affectedPlayersTurn = effect.affectedPlayersTurn; + } + + @Override + public UnlessPaysDelayedEffect copy() { + return new UnlessPaysDelayedEffect(this); + } + + @Override + public boolean apply(Game game, Ability source) { + MageObject sourceObject = source.getSourceObject(game); + if (sourceObject != null) { + + //create special action + UnlessPaysDelayedEffectAction newAction = new UnlessPaysDelayedEffectAction(); + + //create delayed triggered ability + UUID turnPlayer = affectedPlayersTurn ? getTargetPointer().getFirst(game, source) : source.getControllerId(); + effect.setTargetPointer(new FixedTarget(getTargetPointer().getFirst(game, source))); + UnlessPaysDelayedEffectTriggeredAbility delayedAbility = new UnlessPaysDelayedEffectTriggeredAbility(turnPlayer, step, effect); + delayedAbility.setSourceId(source.getSourceId()); + delayedAbility.setControllerId(source.getControllerId()); + delayedAbility.setSourceObject(sourceObject, game); + delayedAbility.setSpecialActionId(newAction.getId()); + UUID delayedAbilityId = game.addDelayedTriggeredAbility(delayedAbility); + + // update special action + newAction.addCost(cost); + Effect removeEffect = new RemoveDelayedTriggeredAbilityEffect(delayedAbilityId); + newAction.addEffect(removeEffect); + newAction.addEffect(new RemoveSpecialActionEffect(newAction.getId())); + newAction.setSourceId(source.getSourceId()); + newAction.setControllerId(getTargetPointer().getFirst(game, source)); + removeEffect.setText(sourceObject.getIdName() + " - Pay " + cost.getText() + " to remove the triggered ability."); + game.getState().getSpecialActions().add(newAction); + return true; + } + return false; + } + +} + +class UnlessPaysDelayedEffectTriggeredAbility extends DelayedTriggeredAbility { + + private UUID specialActionId; + private final UUID turnPlayer; + private final PhaseStep step; + + public UnlessPaysDelayedEffectTriggeredAbility(UUID turnPlayer, PhaseStep step, Effect effect) { + super(effect); + this.turnPlayer = turnPlayer; + this.step = step; + } + + public void setSpecialActionId(UUID specialActionId) { + this.specialActionId = specialActionId; + } + + public UnlessPaysDelayedEffectTriggeredAbility(final UnlessPaysDelayedEffectTriggeredAbility ability) { + super(ability); + this.turnPlayer = ability.turnPlayer; + this.step = ability.step; + this.specialActionId = ability.specialActionId; + } + + @Override + public UnlessPaysDelayedEffectTriggeredAbility copy() { + return new UnlessPaysDelayedEffectTriggeredAbility(this); + } + + @Override + public boolean checkEventType(GameEvent event, Game game) { + switch(step) { + case UPKEEP: + return event.getType() == EventType.UPKEEP_STEP_PRE; + case DRAW: + return event.getType() == EventType.DRAW_STEP_PRE; + default: + return false; + } + } + + @Override + public boolean checkTrigger(GameEvent event, Game game) { + if (event.getPlayerId().equals(turnPlayer)) { + for (SpecialAction action: game.getState().getSpecialActions()) { + if (action.getId().equals(specialActionId)) { + game.getState().getSpecialActions().remove(action); + break; + } + } + return true; + } + return false; + } + +} + +class UnlessPaysDelayedEffectAction extends SpecialAction { + + public UnlessPaysDelayedEffectAction() { + super(); + } + + public UnlessPaysDelayedEffectAction(final UnlessPaysDelayedEffectAction ability) { + super(ability); + } + + @Override + public UnlessPaysDelayedEffectAction copy() { + return new UnlessPaysDelayedEffectAction(this); + } +} From e7e290e78701b41dd3be7cbe5d60fe6a8ee1c99c Mon Sep 17 00:00:00 2001 From: LevelX2 Date: Fri, 25 Dec 2015 11:45:55 +0100 Subject: [PATCH 16/23] * Archfiend of Depravity - Outcome tweaked for AI behaviour. --- .../fatereforged/ArchfiendOfDepravity.java | 4 ++-- .../test/AI/basic/TargetsAreChosenTest.java | 20 +++++++++++++++++++ 2 files changed, 22 insertions(+), 2 deletions(-) diff --git a/Mage.Sets/src/mage/sets/fatereforged/ArchfiendOfDepravity.java b/Mage.Sets/src/mage/sets/fatereforged/ArchfiendOfDepravity.java index 9e10fd5987a..5fbe74b132a 100644 --- a/Mage.Sets/src/mage/sets/fatereforged/ArchfiendOfDepravity.java +++ b/Mage.Sets/src/mage/sets/fatereforged/ArchfiendOfDepravity.java @@ -61,7 +61,7 @@ public class ArchfiendOfDepravity extends CardImpl { // Flying this.addAbility(FlyingAbility.getInstance()); - + // At the beginning of each opponent's end step, that player chooses up to two creatures he or she controls, then sacrifices the rest. this.addAbility(new BeginningOfEndStepTriggeredAbility(new ArchfiendOfDepravityEffect(), TargetController.OPPONENT, false)); } @@ -79,7 +79,7 @@ public class ArchfiendOfDepravity extends CardImpl { class ArchfiendOfDepravityEffect extends OneShotEffect { public ArchfiendOfDepravityEffect() { - super(Outcome.Detriment); + super(Outcome.Benefit); // AI should select two creatures if possible so it has to be a benefit this.staticText = "that player chooses up to two creatures he or she controls, then sacrifices the rest"; } diff --git a/Mage.Tests/src/test/java/org/mage/test/AI/basic/TargetsAreChosenTest.java b/Mage.Tests/src/test/java/org/mage/test/AI/basic/TargetsAreChosenTest.java index 4859e3af03f..07e7c6991b8 100644 --- a/Mage.Tests/src/test/java/org/mage/test/AI/basic/TargetsAreChosenTest.java +++ b/Mage.Tests/src/test/java/org/mage/test/AI/basic/TargetsAreChosenTest.java @@ -222,6 +222,26 @@ public class TargetsAreChosenTest extends CardTestPlayerBaseAI { } + /** + * When I have Archfiend of Depravity on the field, the AI always sacks + * creatures until it has ONE left, when the card states that you can keep + * TWO at the end of each turn. This makes it un-fun playing the Archfiend + * as it makes it a lot easier to win. + */ + @Test + public void testArchfiendOfDepravity() { + // Flying + // At the beginning of each opponent's end step, that player chooses up to two creatures he or she controls, then sacrifices the rest. + addCard(Zone.BATTLEFIELD, playerB, "Archfiend of Depravity"); + + addCard(Zone.BATTLEFIELD, playerA, "Silvercoat Lion", 3); + setStopAt(2, PhaseStep.UNTAP); + execute(); + + assertGraveyardCount(playerA, "Silvercoat Lion", 1); + assertPowerToughness(playerA, "Silvercoat Lion", 2, 2, Filter.ComparisonScope.All); + } + /** * Target selection from EntersTheBattlefield is not varied in the AI * calculation, so value is only calculated for the one selected target set. From dcfb5930598aff7d7532390d2d10dacda4e17b4c Mon Sep 17 00:00:00 2001 From: LevelX2 Date: Fri, 25 Dec 2015 16:14:58 +0100 Subject: [PATCH 17/23] * Added a test. --- .../src/mage/sets/tempest/FlickeringWard.java | 8 +-- .../cards/protection/FlickeringWardTest.java | 62 +++++++++++++++++++ 2 files changed, 66 insertions(+), 4 deletions(-) create mode 100644 Mage.Tests/src/test/java/org/mage/test/cards/protection/FlickeringWardTest.java diff --git a/Mage.Sets/src/mage/sets/tempest/FlickeringWard.java b/Mage.Sets/src/mage/sets/tempest/FlickeringWard.java index d1f89844a74..c8ec4fdf9cc 100644 --- a/Mage.Sets/src/mage/sets/tempest/FlickeringWard.java +++ b/Mage.Sets/src/mage/sets/tempest/FlickeringWard.java @@ -61,13 +61,13 @@ public class FlickeringWard extends CardImpl { this.getSpellAbility().addTarget(auraTarget); this.getSpellAbility().addEffect(new AttachEffect(Outcome.Protect)); this.addAbility(new EnchantAbility(auraTarget.getTargetName())); - + // As Flickering Ward enters the battlefield, choose a color. this.addAbility(new AsEntersBattlefieldAbility(new ChooseColorEffect(Outcome.Benefit))); - + // Enchanted creature has protection from the chosen color. This effect doesn't remove Flickering Ward. this.addAbility(new SimpleStaticAbility(Zone.BATTLEFIELD, new ProtectionChosenColorAttachedEffect(true))); - + // {W}: Return Flickering Ward to its owner's hand. this.addAbility(new SimpleActivatedAbility(Zone.BATTLEFIELD, new ReturnToHandSourceEffect(), new ManaCostsImpl("{W}"))); } @@ -80,4 +80,4 @@ public class FlickeringWard extends CardImpl { public FlickeringWard copy() { return new FlickeringWard(this); } -} \ No newline at end of file +} diff --git a/Mage.Tests/src/test/java/org/mage/test/cards/protection/FlickeringWardTest.java b/Mage.Tests/src/test/java/org/mage/test/cards/protection/FlickeringWardTest.java new file mode 100644 index 00000000000..4b5fbf3a71f --- /dev/null +++ b/Mage.Tests/src/test/java/org/mage/test/cards/protection/FlickeringWardTest.java @@ -0,0 +1,62 @@ +/* + * Copyright 2010 BetaSteward_at_googlemail.com. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are + * permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this list of + * conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, this list + * of conditions and the following disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY BetaSteward_at_googlemail.com ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BetaSteward_at_googlemail.com OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * The views and conclusions contained in the software and documentation are those of the + * authors and should not be interpreted as representing official policies, either expressed + * or implied, of BetaSteward_at_googlemail.com. + */ +package org.mage.test.cards.protection; + +import mage.constants.PhaseStep; +import mage.constants.Zone; +import org.junit.Test; +import org.mage.test.serverside.base.CardTestPlayerBase; + +/** + * + * @author LevelX2 + */ +public class FlickeringWardTest extends CardTestPlayerBase { + + @Test + public void testDOesNotRemoveItself() { + addCard(Zone.BATTLEFIELD, playerA, "Plains", 1); + // Enchant creature + // As Flickering Ward enters the battlefield, choose a color. + // Enchanted creature has protection from the chosen color. This effect doesn't remove Flickering Ward. + // {W}: Return Flickering Ward to its owner's hand. + addCard(Zone.HAND, playerA, "Flickering Ward"); // {W} + + addCard(Zone.BATTLEFIELD, playerA, "Silvercoat Lion"); + + castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Flickering Ward", "Silvercoat Lion"); + setChoice(playerA, "White"); + + setStopAt(1, PhaseStep.BEGIN_COMBAT); + execute(); + + assertPermanentCount(playerA, "Silvercoat Lion", 1); + assertPermanentCount(playerA, "Flickering Ward", 1); + } + +} From 7c00e4b16d9e09df889597aee110eb2ae684fe41 Mon Sep 17 00:00:00 2001 From: LevelX2 Date: Fri, 25 Dec 2015 17:43:10 +0100 Subject: [PATCH 18/23] * Graveyard window - Fixed that the displayed card order was sometimes mismatched. --- .../main/java/mage/client/cards/Cards.java | 14 ++-- .../client/dialog/CardInfoWindowDialog.java | 8 +- .../main/java/mage/client/game/GamePanel.java | 6 +- .../main/java/mage/client/game/HandPanel.java | 7 +- .../mage/client/unusedFiles/CombatGroup.java | 75 +++++++++---------- 5 files changed, 57 insertions(+), 53 deletions(-) diff --git a/Mage.Client/src/main/java/mage/client/cards/Cards.java b/Mage.Client/src/main/java/mage/client/cards/Cards.java index abe5da510c6..50d6b6b51b8 100644 --- a/Mage.Client/src/main/java/mage/client/cards/Cards.java +++ b/Mage.Client/src/main/java/mage/client/cards/Cards.java @@ -134,10 +134,10 @@ public class Cards extends javax.swing.JPanel { } public boolean loadCards(SimpleCardsView cardsView, BigCard bigCard, UUID gameId) { - return loadCards(CardsViewUtil.convertSimple(cardsView), bigCard, gameId, null); + return loadCards(CardsViewUtil.convertSimple(cardsView), bigCard, gameId, true); } - public boolean loadCards(CardsView cardsView, BigCard bigCard, UUID gameId, java.util.List order) { + public boolean loadCards(CardsView cardsView, BigCard bigCard, UUID gameId, boolean revertOrder) { boolean changed = false; // remove objects no longer on the stack from display @@ -168,10 +168,14 @@ public class Cards extends javax.swing.JPanel { } } - // order objects for display java.util.List orderedList = new ArrayList<>(); - for (CardView card : cardsView.values()) { - orderedList.add(0, card); + if (revertOrder) { + // order objects for display + for (CardView card : cardsView.values()) { + orderedList.add(0, card); + } + } else { + orderedList.addAll(cardsView.values()); } // add objects to the panel diff --git a/Mage.Client/src/main/java/mage/client/dialog/CardInfoWindowDialog.java b/Mage.Client/src/main/java/mage/client/dialog/CardInfoWindowDialog.java index 59b6a23fa66..c578a590158 100644 --- a/Mage.Client/src/main/java/mage/client/dialog/CardInfoWindowDialog.java +++ b/Mage.Client/src/main/java/mage/client/dialog/CardInfoWindowDialog.java @@ -114,7 +114,7 @@ public class CardInfoWindowDialog extends MageDialog { } public void loadCards(ExileView exile, BigCard bigCard, UUID gameId) { - boolean changed = cards.loadCards(exile, bigCard, gameId, null); + boolean changed = cards.loadCards(exile, bigCard, gameId, true); String titel = name + " (" + exile.size() + ")"; setTitle(titel); this.setTitelBarToolTip(titel); @@ -138,7 +138,11 @@ public class CardInfoWindowDialog extends MageDialog { } public void loadCards(CardsView showCards, BigCard bigCard, UUID gameId) { - cards.loadCards(showCards, bigCard, gameId, null); + loadCards(showCards, bigCard, gameId, true); + } + + public void loadCards(CardsView showCards, BigCard bigCard, UUID gameId, boolean revertOrder) { + cards.loadCards(showCards, bigCard, gameId, revertOrder); if (showType.equals(ShowType.GRAVEYARD)) { String titel = name + "'s Graveyard (" + showCards.size() + ")"; setTitle(titel); diff --git a/Mage.Client/src/main/java/mage/client/game/GamePanel.java b/Mage.Client/src/main/java/mage/client/game/GamePanel.java index 0a44146935b..9b6f25f275c 100644 --- a/Mage.Client/src/main/java/mage/client/game/GamePanel.java +++ b/Mage.Client/src/main/java/mage/client/game/GamePanel.java @@ -692,7 +692,7 @@ public final class GamePanel extends javax.swing.JPanel { if (cardInfoWindowDialog.isClosed()) { graveyardWindows.remove(player.getName()); } else { - cardInfoWindowDialog.loadCards(player.getGraveyard(), bigCard, gameId); + cardInfoWindowDialog.loadCards(player.getGraveyard(), bigCard, gameId, false); } } // show top card window @@ -801,7 +801,7 @@ public final class GamePanel extends javax.swing.JPanel { } private void displayStack(GameView game, BigCard bigCard, FeedbackPanel feedbackPanel, UUID gameId) { - this.stack.loadCards(game.getStack(), bigCard, gameId, null); + this.stack.loadCards(game.getStack(), bigCard, gameId, true); } /** @@ -908,7 +908,7 @@ public final class GamePanel extends javax.swing.JPanel { CardInfoWindowDialog newGraveyard = new CardInfoWindowDialog(ShowType.GRAVEYARD, playerName); graveyardWindows.put(playerName, newGraveyard); MageFrame.getDesktop().add(newGraveyard, JLayeredPane.MODAL_LAYER); - newGraveyard.loadCards(graveyards.get(playerName), bigCard, gameId); + newGraveyard.loadCards(graveyards.get(playerName), bigCard, gameId, false); } public void openTopLibraryWindow(String playerName) { diff --git a/Mage.Client/src/main/java/mage/client/game/HandPanel.java b/Mage.Client/src/main/java/mage/client/game/HandPanel.java index 9a78cfbca35..fb11a35bc19 100644 --- a/Mage.Client/src/main/java/mage/client/game/HandPanel.java +++ b/Mage.Client/src/main/java/mage/client/game/HandPanel.java @@ -1,6 +1,5 @@ package mage.client.game; -import mage.client.MageFrame; import mage.client.cards.BigCard; import mage.client.dialog.PreferencesDialog; import mage.client.util.Config; @@ -36,7 +35,7 @@ public class HandPanel extends JPanel { jPanel = new JPanel(); jScrollPane1 = new JScrollPane(jPanel); - jScrollPane1.getViewport().setBackground(new Color(0,0,0,0)); + jScrollPane1.getViewport().setBackground(new Color(0, 0, 0, 0)); jPanel.setLayout(new GridBagLayout()); // centers hand jPanel.setBackground(new Color(0, 0, 0, 0)); @@ -67,7 +66,7 @@ public class HandPanel extends JPanel { } public void loadCards(CardsView cards, BigCard bigCard, UUID gameId) { - hand.loadCards(cards, bigCard, gameId, null); + hand.loadCards(cards, bigCard, gameId, true); hand.sizeCards(getHandCardDimension()); } @@ -91,7 +90,7 @@ public class HandPanel extends JPanel { private JPanel jPanel; private JScrollPane jScrollPane1; - private static final Border emptyBorder = new EmptyBorder(0,0,0,0); + private static final Border emptyBorder = new EmptyBorder(0, 0, 0, 0); private mage.client.cards.Cards hand; } diff --git a/Mage.Client/src/main/java/mage/client/unusedFiles/CombatGroup.java b/Mage.Client/src/main/java/mage/client/unusedFiles/CombatGroup.java index 301a863aafb..575dab87caa 100644 --- a/Mage.Client/src/main/java/mage/client/unusedFiles/CombatGroup.java +++ b/Mage.Client/src/main/java/mage/client/unusedFiles/CombatGroup.java @@ -1,48 +1,44 @@ /* -* 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. -*/ + * 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. + */ /* * CombatGroup.java * * Created on Feb 10, 2010, 3:36:55 PM */ - - package mage.client.unusedFiles; //package mage.client.game; - +import java.util.UUID; import mage.client.cards.BigCard; import mage.client.util.Config; import mage.view.CombatGroupView; -import java.util.UUID; - /** * * @author BetaSteward_at_googlemail.com @@ -52,7 +48,9 @@ public class CombatGroup extends javax.swing.JPanel { private UUID gameId; private BigCard bigCard; - /** Creates new form CombatGroup */ + /** + * Creates new form CombatGroup + */ public CombatGroup() { initComponents(); attackers.setDontDisplayTapped(true); @@ -65,18 +63,18 @@ public class CombatGroup extends javax.swing.JPanel { public void update(CombatGroupView combatGroup) { this.lblDefender.setText(combatGroup.getDefenderName()); - this.attackers.loadCards(combatGroup.getAttackers(), bigCard, gameId, null); + this.attackers.loadCards(combatGroup.getAttackers(), bigCard, gameId, true); // attackers.setPreferredSize(new Dimension(Config.dimensions.frameWidth + 6, Config.dimensions.frameHeight + 6)); - this.blockers.loadCards(combatGroup.getBlockers(), bigCard, gameId, null); + this.blockers.loadCards(combatGroup.getBlockers(), bigCard, gameId, true); // blockers.setPreferredSize(new Dimension(Config.dimensions.frameWidth + 6, Config.dimensions.frameHeight + 6)); this.attackers.setVisible(true); this.blockers.setVisible(true); } - /** This method is called from within the constructor to - * initialize the form. - * WARNING: Do NOT modify this code. The content of this method is - * always regenerated by the Form Editor. + /** + * This method is called from within the constructor to initialize the form. + * WARNING: Do NOT modify this code. The content of this method is always + * regenerated by the Form Editor. */ @SuppressWarnings("unchecked") // //GEN-BEGIN:initComponents @@ -112,7 +110,6 @@ public class CombatGroup extends javax.swing.JPanel { ); }// //GEN-END:initComponents - // Variables declaration - do not modify//GEN-BEGIN:variables private mage.client.cards.Cards attackers; private mage.client.cards.Cards blockers; From 562b26bf47a9faa3ee2c92d8dd4bf92ae7fe7dfe Mon Sep 17 00:00:00 2001 From: LoneFox Date: Fri, 25 Dec 2015 20:30:25 +0200 Subject: [PATCH 19/23] Implement cards: Ali Baba, Flowstone Wall, Tunnel, and Wall of Tears --- .../src/mage/sets/arabiannights/AliBaba.java | 78 +++++++++++++++++++ .../src/mage/sets/fourthedition/AliBaba.java | 52 +++++++++++++ .../src/mage/sets/fourthedition/Tunnel.java | 52 +++++++++++++ .../src/mage/sets/limitedalpha/Tunnel.java | 52 +++++++++++++ .../src/mage/sets/limitedbeta/Tunnel.java | 52 +++++++++++++ .../src/mage/sets/nemesis/FlowstoneWall.java | 69 ++++++++++++++++ .../src/mage/sets/revisededition/Tunnel.java | 68 ++++++++++++++++ .../src/mage/sets/stronghold/WallOfTears.java | 72 +++++++++++++++++ .../mage/sets/unlimitededition/Tunnel.java | 52 +++++++++++++ 9 files changed, 547 insertions(+) create mode 100644 Mage.Sets/src/mage/sets/arabiannights/AliBaba.java create mode 100644 Mage.Sets/src/mage/sets/fourthedition/AliBaba.java create mode 100644 Mage.Sets/src/mage/sets/fourthedition/Tunnel.java create mode 100644 Mage.Sets/src/mage/sets/limitedalpha/Tunnel.java create mode 100644 Mage.Sets/src/mage/sets/limitedbeta/Tunnel.java create mode 100644 Mage.Sets/src/mage/sets/nemesis/FlowstoneWall.java create mode 100644 Mage.Sets/src/mage/sets/revisededition/Tunnel.java create mode 100644 Mage.Sets/src/mage/sets/stronghold/WallOfTears.java create mode 100644 Mage.Sets/src/mage/sets/unlimitededition/Tunnel.java diff --git a/Mage.Sets/src/mage/sets/arabiannights/AliBaba.java b/Mage.Sets/src/mage/sets/arabiannights/AliBaba.java new file mode 100644 index 00000000000..19de7f1cdc1 --- /dev/null +++ b/Mage.Sets/src/mage/sets/arabiannights/AliBaba.java @@ -0,0 +1,78 @@ +/* + * 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.sets.arabiannights; + +import java.util.UUID; +import mage.MageInt; +import mage.abilities.Ability; +import mage.abilities.common.SimpleActivatedAbility; +import mage.abilities.costs.mana.ManaCostsImpl; +import mage.abilities.effects.common.TapTargetEffect; +import mage.cards.CardImpl; +import mage.constants.CardType; +import mage.constants.Rarity; +import mage.constants.Zone; +import mage.filter.FilterPermanent; +import mage.filter.predicate.mageobject.SubtypePredicate; +import mage.target.TargetPermanent; + +/** + * + * @author LoneFox + */ +public class AliBaba extends CardImpl { + + private static final FilterPermanent filter = new FilterPermanent("Wall"); + + static { + filter.add(new SubtypePredicate("Wall")); + } + + public AliBaba(UUID ownerId) { + super(ownerId, 43, "Ali Baba", Rarity.UNCOMMON, new CardType[]{CardType.CREATURE}, "{R}"); + this.expansionSetCode = "ARN"; + this.subtype.add("Human"); + this.subtype.add("Rogue"); + this.power = new MageInt(1); + this.toughness = new MageInt(1); + + // {R}: Tap target Wall. + Ability ability = new SimpleActivatedAbility(Zone.BATTLEFIELD, new TapTargetEffect(), new ManaCostsImpl("{R}")); + ability.addTarget(new TargetPermanent(filter)); + this.addAbility(ability); + } + + public AliBaba(final AliBaba card) { + super(card); + } + + @Override + public AliBaba copy() { + return new AliBaba(this); + } +} diff --git a/Mage.Sets/src/mage/sets/fourthedition/AliBaba.java b/Mage.Sets/src/mage/sets/fourthedition/AliBaba.java new file mode 100644 index 00000000000..720122b8bab --- /dev/null +++ b/Mage.Sets/src/mage/sets/fourthedition/AliBaba.java @@ -0,0 +1,52 @@ +/* + * Copyright 2010 BetaSteward_at_googlemail.com. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are + * permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this list of + * conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, this list + * of conditions and the following disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY BetaSteward_at_googlemail.com ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BetaSteward_at_googlemail.com OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * The views and conclusions contained in the software and documentation are those of the + * authors and should not be interpreted as representing official policies, either expressed + * or implied, of BetaSteward_at_googlemail.com. + */ +package mage.sets.fourthedition; + +import java.util.UUID; + +/** + * + * @author LoneFox + */ +public class AliBaba extends mage.sets.arabiannights.AliBaba { + + public AliBaba(UUID ownerId) { + super(ownerId); + this.cardNumber = 193; + this.expansionSetCode = "4ED"; + } + + public AliBaba(final AliBaba card) { + super(card); + } + + @Override + public AliBaba copy() { + return new AliBaba(this); + } +} diff --git a/Mage.Sets/src/mage/sets/fourthedition/Tunnel.java b/Mage.Sets/src/mage/sets/fourthedition/Tunnel.java new file mode 100644 index 00000000000..74f97e4c5d7 --- /dev/null +++ b/Mage.Sets/src/mage/sets/fourthedition/Tunnel.java @@ -0,0 +1,52 @@ +/* + * Copyright 2010 BetaSteward_at_googlemail.com. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are + * permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this list of + * conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, this list + * of conditions and the following disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY BetaSteward_at_googlemail.com ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BetaSteward_at_googlemail.com OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * The views and conclusions contained in the software and documentation are those of the + * authors and should not be interpreted as representing official policies, either expressed + * or implied, of BetaSteward_at_googlemail.com. + */ +package mage.sets.fourthedition; + +import java.util.UUID; + +/** + * + * @author LoneFox + */ +public class Tunnel extends mage.sets.revisededition.Tunnel { + + public Tunnel(UUID ownerId) { + super(ownerId); + this.cardNumber = 142; + this.expansionSetCode = "4ED"; + } + + public Tunnel(final Tunnel card) { + super(card); + } + + @Override + public Tunnel copy() { + return new Tunnel(this); + } +} diff --git a/Mage.Sets/src/mage/sets/limitedalpha/Tunnel.java b/Mage.Sets/src/mage/sets/limitedalpha/Tunnel.java new file mode 100644 index 00000000000..83959c65649 --- /dev/null +++ b/Mage.Sets/src/mage/sets/limitedalpha/Tunnel.java @@ -0,0 +1,52 @@ +/* + * Copyright 2010 BetaSteward_at_googlemail.com. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are + * permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this list of + * conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, this list + * of conditions and the following disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY BetaSteward_at_googlemail.com ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BetaSteward_at_googlemail.com OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * The views and conclusions contained in the software and documentation are those of the + * authors and should not be interpreted as representing official policies, either expressed + * or implied, of BetaSteward_at_googlemail.com. + */ +package mage.sets.limitedalpha; + +import java.util.UUID; + +/** + * + * @author LoneFox + */ +public class Tunnel extends mage.sets.revisededition.Tunnel { + + public Tunnel(UUID ownerId) { + super(ownerId); + this.cardNumber = 179; + this.expansionSetCode = "LEA"; + } + + public Tunnel(final Tunnel card) { + super(card); + } + + @Override + public Tunnel copy() { + return new Tunnel(this); + } +} diff --git a/Mage.Sets/src/mage/sets/limitedbeta/Tunnel.java b/Mage.Sets/src/mage/sets/limitedbeta/Tunnel.java new file mode 100644 index 00000000000..60d8d68052d --- /dev/null +++ b/Mage.Sets/src/mage/sets/limitedbeta/Tunnel.java @@ -0,0 +1,52 @@ +/* + * Copyright 2010 BetaSteward_at_googlemail.com. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are + * permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this list of + * conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, this list + * of conditions and the following disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY BetaSteward_at_googlemail.com ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BetaSteward_at_googlemail.com OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * The views and conclusions contained in the software and documentation are those of the + * authors and should not be interpreted as representing official policies, either expressed + * or implied, of BetaSteward_at_googlemail.com. + */ +package mage.sets.limitedbeta; + +import java.util.UUID; + +/** + * + * @author LoneFox + */ +public class Tunnel extends mage.sets.revisededition.Tunnel { + + public Tunnel(UUID ownerId) { + super(ownerId); + this.cardNumber = 180; + this.expansionSetCode = "LEB"; + } + + public Tunnel(final Tunnel card) { + super(card); + } + + @Override + public Tunnel copy() { + return new Tunnel(this); + } +} diff --git a/Mage.Sets/src/mage/sets/nemesis/FlowstoneWall.java b/Mage.Sets/src/mage/sets/nemesis/FlowstoneWall.java new file mode 100644 index 00000000000..9427dcdc52a --- /dev/null +++ b/Mage.Sets/src/mage/sets/nemesis/FlowstoneWall.java @@ -0,0 +1,69 @@ +/* + * Copyright 2010 BetaSteward_at_googlemail.com. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are + * permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this list of + * conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, this list + * of conditions and the following disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY BetaSteward_at_googlemail.com ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BetaSteward_at_googlemail.com OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * The views and conclusions contained in the software and documentation are those of the + * authors and should not be interpreted as representing official policies, either expressed + * or implied, of BetaSteward_at_googlemail.com. + */ +package mage.sets.nemesis; + +import java.util.UUID; +import mage.MageInt; +import mage.abilities.common.SimpleActivatedAbility; +import mage.abilities.costs.mana.ManaCostsImpl; +import mage.abilities.effects.common.continuous.BoostSourceEffect; +import mage.abilities.keyword.DefenderAbility; +import mage.cards.CardImpl; +import mage.constants.CardType; +import mage.constants.Duration; +import mage.constants.Rarity; +import mage.constants.Zone; + +/** + * + * @author LoneFox + */ +public class FlowstoneWall extends CardImpl { + + public FlowstoneWall(UUID ownerId) { + super(ownerId, 86, "Flowstone Wall", Rarity.COMMON, new CardType[]{CardType.CREATURE}, "{2}{R}"); + this.expansionSetCode = "NMS"; + this.subtype.add("Wall"); + this.power = new MageInt(0); + this.toughness = new MageInt(6); + + // Defender + this.addAbility(DefenderAbility.getInstance()); + // {R}: Flowstone Wall gets +1/-1 until end of turn. + this.addAbility(new SimpleActivatedAbility(Zone.BATTLEFIELD, new BoostSourceEffect(1, -1, Duration.EndOfTurn), new ManaCostsImpl("{R}"))); + } + + public FlowstoneWall(final FlowstoneWall card) { + super(card); + } + + @Override + public FlowstoneWall copy() { + return new FlowstoneWall(this); + } +} diff --git a/Mage.Sets/src/mage/sets/revisededition/Tunnel.java b/Mage.Sets/src/mage/sets/revisededition/Tunnel.java new file mode 100644 index 00000000000..e146eef5e71 --- /dev/null +++ b/Mage.Sets/src/mage/sets/revisededition/Tunnel.java @@ -0,0 +1,68 @@ +/* + * Copyright 2010 BetaSteward_at_googlemail.com. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are + * permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this list of + * conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, this list + * of conditions and the following disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY BetaSteward_at_googlemail.com ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BetaSteward_at_googlemail.com OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * The views and conclusions contained in the software and documentation are those of the + * authors and should not be interpreted as representing official policies, either expressed + * or implied, of BetaSteward_at_googlemail.com. + */ +package mage.sets.revisededition; + +import java.util.UUID; +import mage.abilities.effects.common.DestroyTargetEffect; +import mage.cards.CardImpl; +import mage.constants.CardType; +import mage.constants.Rarity; +import mage.filter.FilterPermanent; +import mage.filter.predicate.mageobject.SubtypePredicate; +import mage.target.TargetPermanent; + +/** + * + * @author LoneFox + */ +public class Tunnel extends CardImpl { + + private static final FilterPermanent filter = new FilterPermanent("Wall"); + + static { + filter.add(new SubtypePredicate("Wall")); + } + + public Tunnel(UUID ownerId) { + super(ownerId, 180, "Tunnel", Rarity.UNCOMMON, new CardType[]{CardType.INSTANT}, "{R}"); + this.expansionSetCode = "3ED"; + + // Destroy target Wall. It can't be regenerated. + this.getSpellAbility().addEffect(new DestroyTargetEffect(true)); + this.getSpellAbility().addTarget(new TargetPermanent(filter)); + } + + public Tunnel(final Tunnel card) { + super(card); + } + + @Override + public Tunnel copy() { + return new Tunnel(this); + } +} diff --git a/Mage.Sets/src/mage/sets/stronghold/WallOfTears.java b/Mage.Sets/src/mage/sets/stronghold/WallOfTears.java new file mode 100644 index 00000000000..9e9c1296ba3 --- /dev/null +++ b/Mage.Sets/src/mage/sets/stronghold/WallOfTears.java @@ -0,0 +1,72 @@ +/* + * Copyright 2010 BetaSteward_at_googlemail.com. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are + * permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this list of + * conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, this list + * of conditions and the following disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY BetaSteward_at_googlemail.com ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BetaSteward_at_googlemail.com OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * The views and conclusions contained in the software and documentation are those of the + * authors and should not be interpreted as representing official policies, either expressed + * or implied, of BetaSteward_at_googlemail.com. + */ +package mage.sets.stronghold; + +import java.util.UUID; +import mage.MageInt; +import mage.abilities.common.BlocksCreatureTriggeredAbility; +import mage.abilities.common.delayed.AtTheEndOfCombatDelayedTriggeredAbility; +import mage.abilities.effects.Effect; +import mage.abilities.effects.common.CreateDelayedTriggeredAbilityEffect; +import mage.abilities.effects.common.ReturnToHandTargetEffect; +import mage.abilities.keyword.DefenderAbility; +import mage.cards.CardImpl; +import mage.constants.CardType; +import mage.constants.Rarity; + +/** + * + * @author LoneFox + */ +public class WallOfTears extends CardImpl { + + public WallOfTears(UUID ownerId) { + super(ownerId, 50, "Wall of Tears", Rarity.UNCOMMON, new CardType[]{CardType.CREATURE}, "{1}{U}"); + this.expansionSetCode = "STH"; + this.subtype.add("Wall"); + this.power = new MageInt(0); + this.toughness = new MageInt(4); + + // Defender + this.addAbility(DefenderAbility.getInstance()); + // Whenever Wall of Tears blocks a creature, return that creature to its owner's hand at end of combat. + Effect effect = new ReturnToHandTargetEffect(); + effect.setText("return that creature to its owner's hand at end of combat"); + this.addAbility(new BlocksCreatureTriggeredAbility(new CreateDelayedTriggeredAbilityEffect( + new AtTheEndOfCombatDelayedTriggeredAbility(effect)), false, true)); + } + + public WallOfTears(final WallOfTears card) { + super(card); + } + + @Override + public WallOfTears copy() { + return new WallOfTears(this); + } +} diff --git a/Mage.Sets/src/mage/sets/unlimitededition/Tunnel.java b/Mage.Sets/src/mage/sets/unlimitededition/Tunnel.java new file mode 100644 index 00000000000..48fce635922 --- /dev/null +++ b/Mage.Sets/src/mage/sets/unlimitededition/Tunnel.java @@ -0,0 +1,52 @@ +/* + * Copyright 2010 BetaSteward_at_googlemail.com. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are + * permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this list of + * conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, this list + * of conditions and the following disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY BetaSteward_at_googlemail.com ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BetaSteward_at_googlemail.com OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * The views and conclusions contained in the software and documentation are those of the + * authors and should not be interpreted as representing official policies, either expressed + * or implied, of BetaSteward_at_googlemail.com. + */ +package mage.sets.unlimitededition; + +import java.util.UUID; + +/** + * + * @author LoneFox + */ +public class Tunnel extends mage.sets.revisededition.Tunnel { + + public Tunnel(UUID ownerId) { + super(ownerId); + this.cardNumber = 179; + this.expansionSetCode = "2ED"; + } + + public Tunnel(final Tunnel card) { + super(card); + } + + @Override + public Tunnel copy() { + return new Tunnel(this); + } +} From 2b09bd0b7c6c92f66258d6a3b8bb2accc6991d80 Mon Sep 17 00:00:00 2001 From: LoneFox Date: Fri, 25 Dec 2015 20:42:33 +0200 Subject: [PATCH 20/23] Fix timing of "at the end of combat" delayed triggers. --- .../common/delayed/AtTheEndOfCombatDelayedTriggeredAbility.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Mage/src/main/java/mage/abilities/common/delayed/AtTheEndOfCombatDelayedTriggeredAbility.java b/Mage/src/main/java/mage/abilities/common/delayed/AtTheEndOfCombatDelayedTriggeredAbility.java index 6cec07678cb..4dc1dae0889 100644 --- a/Mage/src/main/java/mage/abilities/common/delayed/AtTheEndOfCombatDelayedTriggeredAbility.java +++ b/Mage/src/main/java/mage/abilities/common/delayed/AtTheEndOfCombatDelayedTriggeredAbility.java @@ -21,7 +21,7 @@ public class AtTheEndOfCombatDelayedTriggeredAbility extends DelayedTriggeredAbi @Override public boolean checkEventType(GameEvent event, Game game) { - return event.getType() == GameEvent.EventType.COMBAT_PHASE_POST; + return event.getType() == GameEvent.EventType.END_COMBAT_STEP_PRE; } @Override From 8ce49ad9b942b76e5412d91af72e7cd94f6d2289 Mon Sep 17 00:00:00 2001 From: LoneFox Date: Fri, 25 Dec 2015 20:49:03 +0200 Subject: [PATCH 21/23] Remove unnecessary custom effects from cards that work the same way as Wall of tears. --- .../KaijinOfTheVanishingTouch.java | 52 +++---------------- .../sets/venservskoth/AEtherMembrane.java | 50 +++--------------- 2 files changed, 15 insertions(+), 87 deletions(-) diff --git a/Mage.Sets/src/mage/sets/betrayersofkamigawa/KaijinOfTheVanishingTouch.java b/Mage.Sets/src/mage/sets/betrayersofkamigawa/KaijinOfTheVanishingTouch.java index 75adb142f3e..7f7e469c632 100644 --- a/Mage.Sets/src/mage/sets/betrayersofkamigawa/KaijinOfTheVanishingTouch.java +++ b/Mage.Sets/src/mage/sets/betrayersofkamigawa/KaijinOfTheVanishingTouch.java @@ -28,20 +28,16 @@ package mage.sets.betrayersofkamigawa; import java.util.UUID; -import mage.constants.CardType; -import mage.constants.Outcome; -import mage.constants.Rarity; import mage.MageInt; -import mage.abilities.Ability; import mage.abilities.common.BlocksCreatureTriggeredAbility; import mage.abilities.common.delayed.AtTheEndOfCombatDelayedTriggeredAbility; -import mage.abilities.effects.OneShotEffect; +import mage.abilities.effects.Effect; +import mage.abilities.effects.common.CreateDelayedTriggeredAbilityEffect; import mage.abilities.effects.common.ReturnToHandTargetEffect; import mage.abilities.keyword.DefenderAbility; import mage.cards.CardImpl; -import mage.game.Game; -import mage.game.permanent.Permanent; -import mage.target.targetpointer.FixedTarget; +import mage.constants.CardType; +import mage.constants.Rarity; /** * @@ -59,11 +55,11 @@ public class KaijinOfTheVanishingTouch extends CardImpl { // Defender (This creature can't attack.) this.addAbility(DefenderAbility.getInstance()); - // Whenever Kaijin of the Vanishing Touch blocks a creature, return that creature to its owner's hand at end of combat. (Return it only if it's on the battlefield.) - Ability ability = new BlocksCreatureTriggeredAbility(new KaijinOfTheVanishingTouchEffect(), false, true); - this.addAbility(ability); - + Effect effect = new ReturnToHandTargetEffect(); + effect.setText("return that creature to its owner's hand at end of combat"); + this.addAbility(new BlocksCreatureTriggeredAbility(new CreateDelayedTriggeredAbilityEffect( + new AtTheEndOfCombatDelayedTriggeredAbility(effect)), false, true)); } public KaijinOfTheVanishingTouch(final KaijinOfTheVanishingTouch card) { @@ -75,35 +71,3 @@ public class KaijinOfTheVanishingTouch extends CardImpl { return new KaijinOfTheVanishingTouch(this); } } - -class KaijinOfTheVanishingTouchEffect extends OneShotEffect { - - KaijinOfTheVanishingTouchEffect() { - super(Outcome.ReturnToHand); - staticText = "return that creature to its owner's hand at end of combat"; - } - - KaijinOfTheVanishingTouchEffect(final KaijinOfTheVanishingTouchEffect effect) { - super(effect); - } - - @Override - public boolean apply(Game game, Ability source) { - Permanent targetCreature = game.getPermanent(this.getTargetPointer().getFirst(game, source)); - if (targetCreature != null) { - AtTheEndOfCombatDelayedTriggeredAbility delayedAbility = new AtTheEndOfCombatDelayedTriggeredAbility(new ReturnToHandTargetEffect()); - delayedAbility.setSourceId(source.getSourceId()); - delayedAbility.setControllerId(source.getControllerId()); - delayedAbility.setSourceObject(source.getSourceObject(game), game); - delayedAbility.getEffects().get(0).setTargetPointer(new FixedTarget(targetCreature.getId())); - game.addDelayedTriggeredAbility(delayedAbility); - return true; - } - return false; - } - - @Override - public KaijinOfTheVanishingTouchEffect copy() { - return new KaijinOfTheVanishingTouchEffect(this); - } -} \ No newline at end of file diff --git a/Mage.Sets/src/mage/sets/venservskoth/AEtherMembrane.java b/Mage.Sets/src/mage/sets/venservskoth/AEtherMembrane.java index f799049694a..b199791fa04 100644 --- a/Mage.Sets/src/mage/sets/venservskoth/AEtherMembrane.java +++ b/Mage.Sets/src/mage/sets/venservskoth/AEtherMembrane.java @@ -27,23 +27,18 @@ */ package mage.sets.venservskoth; +import java.util.UUID; import mage.MageInt; -import mage.abilities.Ability; import mage.abilities.common.BlocksCreatureTriggeredAbility; import mage.abilities.common.delayed.AtTheEndOfCombatDelayedTriggeredAbility; -import mage.abilities.effects.OneShotEffect; +import mage.abilities.effects.Effect; +import mage.abilities.effects.common.CreateDelayedTriggeredAbilityEffect; import mage.abilities.effects.common.ReturnToHandTargetEffect; import mage.abilities.keyword.DefenderAbility; import mage.abilities.keyword.ReachAbility; import mage.cards.CardImpl; import mage.constants.CardType; -import mage.constants.Outcome; import mage.constants.Rarity; -import mage.game.Game; -import mage.game.permanent.Permanent; -import mage.target.targetpointer.FixedTarget; - -import java.util.UUID; /** * @@ -63,7 +58,10 @@ public class AEtherMembrane extends CardImpl { this.addAbility(DefenderAbility.getInstance()); // Whenever AEther Membrane blocks a creature, return that creature to its owner's hand at end of combat. - this.addAbility(new BlocksCreatureTriggeredAbility(new AEtherMembraneEffect(), false, true)); + Effect effect = new ReturnToHandTargetEffect(); + effect.setText("return that creature to its owner's hand at end of combat"); + this.addAbility(new BlocksCreatureTriggeredAbility(new CreateDelayedTriggeredAbilityEffect( + new AtTheEndOfCombatDelayedTriggeredAbility(effect)), false, true)); } public AEtherMembrane(final AEtherMembrane card) { @@ -75,37 +73,3 @@ public class AEtherMembrane extends CardImpl { return new AEtherMembrane(this); } } - -// @klayhamn: This is identical to the effect of KaijinOfTheVanishingTouch but there's only 2 cards with this effect -// and it's not generic enough to be extracted, imho -class AEtherMembraneEffect extends OneShotEffect { - - AEtherMembraneEffect() { - super(Outcome.ReturnToHand); - staticText = "return that creature to its owner's hand at end of combat"; - } - - AEtherMembraneEffect(final AEtherMembraneEffect effect) { - super(effect); - } - - @Override - public boolean apply(Game game, Ability source) { - Permanent targetCreature = game.getPermanent(this.getTargetPointer().getFirst(game, source)); - if (targetCreature != null) { - AtTheEndOfCombatDelayedTriggeredAbility delayedAbility = new AtTheEndOfCombatDelayedTriggeredAbility(new ReturnToHandTargetEffect()); - delayedAbility.setSourceId(source.getSourceId()); - delayedAbility.setControllerId(source.getControllerId()); - delayedAbility.setSourceObject(source.getSourceObject(game), game); - delayedAbility.getEffects().get(0).setTargetPointer(new FixedTarget(targetCreature.getId())); - game.addDelayedTriggeredAbility(delayedAbility); - return true; - } - return false; - } - - @Override - public AEtherMembraneEffect copy() { - return new AEtherMembraneEffect(this); - } -} \ No newline at end of file From a60ac935e8b98cdf256646a7fb5df57914a63077 Mon Sep 17 00:00:00 2001 From: LoneFox Date: Fri, 25 Dec 2015 21:29:13 +0200 Subject: [PATCH 22/23] Implement cards: Jackalope Herd, Onslaught, Rootwater Alligator, and Whiptongue Frog --- .../src/mage/sets/exodus/JackalopeHerd.java | 65 ++++++++++++++++ Mage.Sets/src/mage/sets/exodus/Onslaught.java | 71 ++++++++++++++++++ .../mage/sets/exodus/RootwaterAlligator.java | 74 +++++++++++++++++++ .../src/mage/sets/exodus/WhiptongueFrog.java | 67 +++++++++++++++++ 4 files changed, 277 insertions(+) create mode 100644 Mage.Sets/src/mage/sets/exodus/JackalopeHerd.java create mode 100644 Mage.Sets/src/mage/sets/exodus/Onslaught.java create mode 100644 Mage.Sets/src/mage/sets/exodus/RootwaterAlligator.java create mode 100644 Mage.Sets/src/mage/sets/exodus/WhiptongueFrog.java diff --git a/Mage.Sets/src/mage/sets/exodus/JackalopeHerd.java b/Mage.Sets/src/mage/sets/exodus/JackalopeHerd.java new file mode 100644 index 00000000000..59a721bf2d8 --- /dev/null +++ b/Mage.Sets/src/mage/sets/exodus/JackalopeHerd.java @@ -0,0 +1,65 @@ +/* + * Copyright 2010 BetaSteward_at_googlemail.com. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are + * permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this list of + * conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, this list + * of conditions and the following disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY BetaSteward_at_googlemail.com ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BetaSteward_at_googlemail.com OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * The views and conclusions contained in the software and documentation are those of the + * authors and should not be interpreted as representing official policies, either expressed + * or implied, of BetaSteward_at_googlemail.com. + */ +package mage.sets.exodus; + +import java.util.UUID; +import mage.MageInt; +import mage.abilities.common.SpellCastControllerTriggeredAbility; +import mage.abilities.effects.common.ReturnToHandSourceEffect; +import mage.cards.CardImpl; +import mage.constants.CardType; +import mage.constants.Rarity; +import mage.filter.FilterSpell; + +/** + * + * @author LoneFox + */ +public class JackalopeHerd extends CardImpl { + + public JackalopeHerd(UUID ownerId) { + super(ownerId, 111, "Jackalope Herd", Rarity.COMMON, new CardType[]{CardType.CREATURE}, "{3}{G}"); + this.expansionSetCode = "EXO"; + this.subtype.add("Rabbit"); + this.subtype.add("Beast"); + this.power = new MageInt(4); + this.toughness = new MageInt(5); + + // When you cast a spell, return Jackalope Herd to its owner's hand. + this.addAbility(new SpellCastControllerTriggeredAbility(new ReturnToHandSourceEffect(true), new FilterSpell("a spell"), false)); + } + + public JackalopeHerd(final JackalopeHerd card) { + super(card); + } + + @Override + public JackalopeHerd copy() { + return new JackalopeHerd(this); + } +} diff --git a/Mage.Sets/src/mage/sets/exodus/Onslaught.java b/Mage.Sets/src/mage/sets/exodus/Onslaught.java new file mode 100644 index 00000000000..d34d280311b --- /dev/null +++ b/Mage.Sets/src/mage/sets/exodus/Onslaught.java @@ -0,0 +1,71 @@ +/* + * 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.sets.exodus; + +import java.util.UUID; +import mage.abilities.Ability; +import mage.abilities.common.SpellCastControllerTriggeredAbility; +import mage.abilities.effects.common.TapTargetEffect; +import mage.cards.CardImpl; +import mage.constants.CardType; +import mage.constants.Rarity; +import mage.filter.FilterSpell; +import mage.filter.predicate.mageobject.CardTypePredicate; +import mage.target.common.TargetCreaturePermanent; + +/** + * + * @author LoneFox + */ +public class Onslaught extends CardImpl { + + private static final FilterSpell filter = new FilterSpell("a creature spell"); + + static { + filter.add(new CardTypePredicate(CardType.CREATURE)); + } + + public Onslaught(UUID ownerId) { + super(ownerId, 92, "Onslaught", Rarity.COMMON, new CardType[]{CardType.ENCHANTMENT}, "{R}"); + this.expansionSetCode = "EXO"; + + // Whenever you cast a creature spell, tap target creature. + Ability ability = new SpellCastControllerTriggeredAbility(new TapTargetEffect(), filter, false); + ability.addTarget(new TargetCreaturePermanent()); + this.addAbility(ability); + } + + public Onslaught(final Onslaught card) { + super(card); + } + + @Override + public Onslaught copy() { + return new Onslaught(this); + } +} diff --git a/Mage.Sets/src/mage/sets/exodus/RootwaterAlligator.java b/Mage.Sets/src/mage/sets/exodus/RootwaterAlligator.java new file mode 100644 index 00000000000..fabe6e4ee81 --- /dev/null +++ b/Mage.Sets/src/mage/sets/exodus/RootwaterAlligator.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.sets.exodus; + +import java.util.UUID; +import mage.MageInt; +import mage.abilities.common.SimpleActivatedAbility; +import mage.abilities.costs.common.SacrificeTargetCost; +import mage.abilities.effects.common.RegenerateSourceEffect; +import mage.cards.CardImpl; +import mage.constants.CardType; +import mage.constants.Rarity; +import mage.constants.Zone; +import mage.filter.common.FilterControlledPermanent; +import mage.filter.predicate.mageobject.SubtypePredicate; +import mage.target.common.TargetControlledPermanent; + +/** + * + * @author LoneFox + */ +public class RootwaterAlligator extends CardImpl { + + private static final FilterControlledPermanent filter = new FilterControlledPermanent("a Forest"); + + static{ + filter.add(new SubtypePredicate("Forest")); + } + + public RootwaterAlligator(UUID ownerId) { + super(ownerId, 122, "Rootwater Alligator", Rarity.COMMON, new CardType[]{CardType.CREATURE}, "{3}{G}"); + this.expansionSetCode = "EXO"; + this.subtype.add("Crocodile"); + this.power = new MageInt(3); + this.toughness = new MageInt(2); + + // Sacrifice a Forest: Regenerate Rootwater Alligator. + this.addAbility(new SimpleActivatedAbility(Zone.BATTLEFIELD, new RegenerateSourceEffect(), new SacrificeTargetCost(new TargetControlledPermanent(filter)))); + } + + public RootwaterAlligator(final RootwaterAlligator card) { + super(card); + } + + @Override + public RootwaterAlligator copy() { + return new RootwaterAlligator(this); + } +} diff --git a/Mage.Sets/src/mage/sets/exodus/WhiptongueFrog.java b/Mage.Sets/src/mage/sets/exodus/WhiptongueFrog.java new file mode 100644 index 00000000000..3c7e7947c1a --- /dev/null +++ b/Mage.Sets/src/mage/sets/exodus/WhiptongueFrog.java @@ -0,0 +1,67 @@ +/* + * Copyright 2010 BetaSteward_at_googlemail.com. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are + * permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this list of + * conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, this list + * of conditions and the following disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY BetaSteward_at_googlemail.com ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BetaSteward_at_googlemail.com OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * The views and conclusions contained in the software and documentation are those of the + * authors and should not be interpreted as representing official policies, either expressed + * or implied, of BetaSteward_at_googlemail.com. + */ +package mage.sets.exodus; + +import java.util.UUID; +import mage.MageInt; +import mage.abilities.common.SimpleActivatedAbility; +import mage.abilities.costs.mana.ManaCostsImpl; +import mage.abilities.effects.common.continuous.GainAbilitySourceEffect; +import mage.abilities.keyword.FlyingAbility; +import mage.cards.CardImpl; +import mage.constants.CardType; +import mage.constants.Duration; +import mage.constants.Rarity; +import mage.constants.Zone; + +/** + * + * @author LoneFox + */ +public class WhiptongueFrog extends CardImpl { + + public WhiptongueFrog(UUID ownerId) { + super(ownerId, 52, "Whiptongue Frog", Rarity.COMMON, new CardType[]{CardType.CREATURE}, "{2}{U}"); + this.expansionSetCode = "EXO"; + this.subtype.add("Frog"); + this.power = new MageInt(1); + this.toughness = new MageInt(3); + + // {U}: Whiptongue Frog gains flying until end of turn. + this.addAbility(new SimpleActivatedAbility(Zone.BATTLEFIELD, new GainAbilitySourceEffect(FlyingAbility.getInstance(), Duration.EndOfTurn), new ManaCostsImpl("{U}"))); + } + + public WhiptongueFrog(final WhiptongueFrog card) { + super(card); + } + + @Override + public WhiptongueFrog copy() { + return new WhiptongueFrog(this); + } +} From e3556ce07bb2e42d5751af7740179af5649dcb90 Mon Sep 17 00:00:00 2001 From: LevelX2 Date: Sun, 27 Dec 2015 08:47:10 +0100 Subject: [PATCH 23/23] * Scrap Mastery - Fixed that the cards from graveyard were not returned under the control of the card owner. --- Mage.Sets/src/mage/sets/commander2014/ScrapMastery.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Mage.Sets/src/mage/sets/commander2014/ScrapMastery.java b/Mage.Sets/src/mage/sets/commander2014/ScrapMastery.java index badafeb966f..05b58c888c0 100644 --- a/Mage.Sets/src/mage/sets/commander2014/ScrapMastery.java +++ b/Mage.Sets/src/mage/sets/commander2014/ScrapMastery.java @@ -112,7 +112,7 @@ class ScrapMasteryEffect extends OneShotEffect { for (UUID playerId : game.getState().getPlayersInRange(controller.getId(), game)) { Player player = game.getPlayer(playerId); if (player != null) { - controller.moveCards(exiledCards.get(playerId), Zone.BATTLEFIELD, source, game); + player.moveCards(exiledCards.get(playerId), Zone.BATTLEFIELD, source, game); } } return true;