From 472eb287fa4f936ef34e8e39ca8cf4e8d604e45c Mon Sep 17 00:00:00 2001 From: LoneFox Date: Fri, 14 Aug 2015 07:12:23 +0300 Subject: [PATCH 01/15] Implement cards: Flowstone Crusher, Flowstone Shambler, Inspirit, Sage Aven, Sanctum Guardian, and Whip Sergeant --- .../mage/sets/nemesis/FlowstoneCrusher.java | 54 ++++++++++++++ .../sets/ninthedition/FlowstoneCrusher.java | 67 +++++++++++++++++ .../sets/ninthedition/FlowstoneShambler.java | 67 +++++++++++++++++ .../src/mage/sets/ninthedition/Inspirit.java | 52 +++++++++++++ .../src/mage/sets/ninthedition/SageAven.java | 67 +++++++++++++++++ .../sets/ninthedition/SanctumGuardian.java | 72 ++++++++++++++++++ .../mage/sets/ninthedition/WhipSergeant.java | 52 +++++++++++++ .../src/mage/sets/onslaught/Inspirit.java | 66 +++++++++++++++++ .../src/mage/sets/onslaught/SageAven.java | 52 +++++++++++++ .../src/mage/sets/prophecy/WhipSergeant.java | 73 +++++++++++++++++++ .../sets/stronghold/FlowstoneShambler.java | 52 +++++++++++++ .../mage/sets/urzassaga/SanctumGuardian.java | 52 +++++++++++++ 12 files changed, 726 insertions(+) create mode 100644 Mage.Sets/src/mage/sets/nemesis/FlowstoneCrusher.java create mode 100644 Mage.Sets/src/mage/sets/ninthedition/FlowstoneCrusher.java create mode 100644 Mage.Sets/src/mage/sets/ninthedition/FlowstoneShambler.java create mode 100644 Mage.Sets/src/mage/sets/ninthedition/Inspirit.java create mode 100644 Mage.Sets/src/mage/sets/ninthedition/SageAven.java create mode 100644 Mage.Sets/src/mage/sets/ninthedition/SanctumGuardian.java create mode 100644 Mage.Sets/src/mage/sets/ninthedition/WhipSergeant.java create mode 100644 Mage.Sets/src/mage/sets/onslaught/Inspirit.java create mode 100644 Mage.Sets/src/mage/sets/onslaught/SageAven.java create mode 100644 Mage.Sets/src/mage/sets/prophecy/WhipSergeant.java create mode 100644 Mage.Sets/src/mage/sets/stronghold/FlowstoneShambler.java create mode 100644 Mage.Sets/src/mage/sets/urzassaga/SanctumGuardian.java diff --git a/Mage.Sets/src/mage/sets/nemesis/FlowstoneCrusher.java b/Mage.Sets/src/mage/sets/nemesis/FlowstoneCrusher.java new file mode 100644 index 0000000000..6c85d1c1a3 --- /dev/null +++ b/Mage.Sets/src/mage/sets/nemesis/FlowstoneCrusher.java @@ -0,0 +1,54 @@ +/* + * 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.constants.Rarity; + +/** + * + * @author LoneFox + */ +public class FlowstoneCrusher extends mage.sets.ninthedition.FlowstoneCrusher { + + public FlowstoneCrusher(UUID ownerId) { + super(ownerId); + this.cardNumber = 81; + this.expansionSetCode = "NMS"; + this.rarity = Rarity.COMMON; + } + + public FlowstoneCrusher(final FlowstoneCrusher card) { + super(card); + } + + @Override + public FlowstoneCrusher copy() { + return new FlowstoneCrusher(this); + } +} diff --git a/Mage.Sets/src/mage/sets/ninthedition/FlowstoneCrusher.java b/Mage.Sets/src/mage/sets/ninthedition/FlowstoneCrusher.java new file mode 100644 index 0000000000..d05061444b --- /dev/null +++ b/Mage.Sets/src/mage/sets/ninthedition/FlowstoneCrusher.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.ninthedition; + +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.cards.CardImpl; +import mage.constants.CardType; +import mage.constants.Duration; +import mage.constants.Rarity; +import mage.constants.Zone; + +/** + * + * @author LoneFox + */ +public class FlowstoneCrusher extends CardImpl { + + public FlowstoneCrusher(UUID ownerId) { + super(ownerId, 184, "Flowstone Crusher", Rarity.UNCOMMON, new CardType[]{CardType.CREATURE}, "{3}{R}{R}"); + this.expansionSetCode = "9ED"; + this.subtype.add("Beast"); + this.power = new MageInt(4); + this.toughness = new MageInt(4); + + // {R}: Flowstone Crusher gets +1/-1 until end of turn. + this.addAbility(new SimpleActivatedAbility(Zone.BATTLEFIELD, + new BoostSourceEffect(1, -1, Duration.EndOfTurn), new ManaCostsImpl("{R}"))); + } + + public FlowstoneCrusher(final FlowstoneCrusher card) { + super(card); + } + + @Override + public FlowstoneCrusher copy() { + return new FlowstoneCrusher(this); + } +} diff --git a/Mage.Sets/src/mage/sets/ninthedition/FlowstoneShambler.java b/Mage.Sets/src/mage/sets/ninthedition/FlowstoneShambler.java new file mode 100644 index 0000000000..4ec8d5747a --- /dev/null +++ b/Mage.Sets/src/mage/sets/ninthedition/FlowstoneShambler.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.ninthedition; + +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.cards.CardImpl; +import mage.constants.CardType; +import mage.constants.Duration; +import mage.constants.Rarity; +import mage.constants.Zone; + +/** + * + * @author LoneFox + */ +public class FlowstoneShambler extends CardImpl { + + public FlowstoneShambler(UUID ownerId) { + super(ownerId, 185, "Flowstone Shambler", Rarity.COMMON, new CardType[]{CardType.CREATURE}, "{2}{R}"); + this.expansionSetCode = "9ED"; + this.subtype.add("Beast"); + this.power = new MageInt(2); + this.toughness = new MageInt(2); + + // {R}: Flowstone Shambler gets +1/-1 until end of turn. + this.addAbility(new SimpleActivatedAbility(Zone.BATTLEFIELD, + new BoostSourceEffect(1, -1, Duration.EndOfTurn), new ManaCostsImpl("{R}"))); + } + + public FlowstoneShambler(final FlowstoneShambler card) { + super(card); + } + + @Override + public FlowstoneShambler copy() { + return new FlowstoneShambler(this); + } +} diff --git a/Mage.Sets/src/mage/sets/ninthedition/Inspirit.java b/Mage.Sets/src/mage/sets/ninthedition/Inspirit.java new file mode 100644 index 0000000000..12112f59e1 --- /dev/null +++ b/Mage.Sets/src/mage/sets/ninthedition/Inspirit.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.ninthedition; + +import java.util.UUID; + +/** + * + * @author LoneFox + */ +public class Inspirit extends mage.sets.onslaught.Inspirit { + + public Inspirit(UUID ownerId) { + super(ownerId); + this.cardNumber = 22; + this.expansionSetCode = "9ED"; + } + + public Inspirit(final Inspirit card) { + super(card); + } + + @Override + public Inspirit copy() { + return new Inspirit(this); + } +} diff --git a/Mage.Sets/src/mage/sets/ninthedition/SageAven.java b/Mage.Sets/src/mage/sets/ninthedition/SageAven.java new file mode 100644 index 0000000000..c7a91f38e4 --- /dev/null +++ b/Mage.Sets/src/mage/sets/ninthedition/SageAven.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.ninthedition; + +import java.util.UUID; +import mage.MageInt; +import mage.abilities.common.EntersBattlefieldTriggeredAbility; +import mage.abilities.effects.common.LookLibraryControllerEffect; +import mage.abilities.keyword.FlyingAbility; +import mage.cards.CardImpl; +import mage.constants.CardType; +import mage.constants.Rarity; + +/** + * + * @author LoneFox + */ +public class SageAven extends CardImpl { + + public SageAven(UUID ownerId) { + super(ownerId, 95, "Sage Aven", Rarity.COMMON, new CardType[]{CardType.CREATURE}, "{3}{U}"); + this.expansionSetCode = "9ED"; + this.subtype.add("Bird"); + this.subtype.add("Wizard"); + this.power = new MageInt(1); + this.toughness = new MageInt(3); + + // Flying + this.addAbility(FlyingAbility.getInstance()); + // When Sage Aven enters the battlefield, look at the top four cards of your library, then put them back in any order. + this.addAbility(new EntersBattlefieldTriggeredAbility(new LookLibraryControllerEffect(4))); + } + + public SageAven(final SageAven card) { + super(card); + } + + @Override + public SageAven copy() { + return new SageAven(this); + } +} diff --git a/Mage.Sets/src/mage/sets/ninthedition/SanctumGuardian.java b/Mage.Sets/src/mage/sets/ninthedition/SanctumGuardian.java new file mode 100644 index 0000000000..938fc48205 --- /dev/null +++ b/Mage.Sets/src/mage/sets/ninthedition/SanctumGuardian.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.ninthedition; + +import java.util.UUID; +import mage.MageInt; +import mage.abilities.Ability; +import mage.abilities.common.SimpleActivatedAbility; +import mage.abilities.costs.common.SacrificeSourceCost; +import mage.abilities.effects.common.PreventNextDamageFromChosenSourceToTargetEffect; +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 SanctumGuardian extends CardImpl { + + public SanctumGuardian(UUID ownerId) { + super(ownerId, 40, "Sanctum Guardian", Rarity.UNCOMMON, new CardType[]{CardType.CREATURE}, "{1}{W}{W}"); + this.expansionSetCode = "9ED"; + this.subtype.add("Human"); + this.subtype.add("Cleric"); + this.power = new MageInt(1); + this.toughness = new MageInt(4); + + // Sacrifice Sanctum Guardian: The next time a source of your choice would deal damage to target creature or player this turn, prevent that damage. + Ability ability = new SimpleActivatedAbility(Zone.BATTLEFIELD, new PreventNextDamageFromChosenSourceToTargetEffect(Duration.EndOfTurn), + new SacrificeSourceCost()); + ability.addTarget(new TargetCreatureOrPlayer()); + this.addAbility(ability); + } + + public SanctumGuardian(final SanctumGuardian card) { + super(card); + } + + @Override + public SanctumGuardian copy() { + return new SanctumGuardian(this); + } +} diff --git a/Mage.Sets/src/mage/sets/ninthedition/WhipSergeant.java b/Mage.Sets/src/mage/sets/ninthedition/WhipSergeant.java new file mode 100644 index 0000000000..9342c79098 --- /dev/null +++ b/Mage.Sets/src/mage/sets/ninthedition/WhipSergeant.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.ninthedition; + +import java.util.UUID; + +/** + * + * @author LoneFox + */ +public class WhipSergeant extends mage.sets.prophecy.WhipSergeant { + + public WhipSergeant(UUID ownerId) { + super(ownerId); + this.cardNumber = 227; + this.expansionSetCode = "9ED"; + } + + public WhipSergeant(final WhipSergeant card) { + super(card); + } + + @Override + public WhipSergeant copy() { + return new WhipSergeant(this); + } +} diff --git a/Mage.Sets/src/mage/sets/onslaught/Inspirit.java b/Mage.Sets/src/mage/sets/onslaught/Inspirit.java new file mode 100644 index 0000000000..fd26c17183 --- /dev/null +++ b/Mage.Sets/src/mage/sets/onslaught/Inspirit.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.onslaught; + +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.target.common.TargetCreaturePermanent; + +/** + * + * @author LoneFox + */ +public class Inspirit extends CardImpl { + + public Inspirit(UUID ownerId) { + super(ownerId, 41, "Inspirit", Rarity.UNCOMMON, new CardType[]{CardType.INSTANT}, "{2}{W}"); + this.expansionSetCode = "ONS"; + + // Untap target creature. It gets +2/+4 until end of turn. + this.getSpellAbility().addEffect(new UntapTargetEffect()); + Effect effect = new BoostTargetEffect(2, 4, Duration.EndOfTurn); + effect.setText("It gets +2/+4 until end of turn"); + this.getSpellAbility().addEffect(effect); + this.getSpellAbility().addTarget(new TargetCreaturePermanent()); + } + + public Inspirit(final Inspirit card) { + super(card); + } + + @Override + public Inspirit copy() { + return new Inspirit(this); + } +} diff --git a/Mage.Sets/src/mage/sets/onslaught/SageAven.java b/Mage.Sets/src/mage/sets/onslaught/SageAven.java new file mode 100644 index 0000000000..d1d40e34d7 --- /dev/null +++ b/Mage.Sets/src/mage/sets/onslaught/SageAven.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.onslaught; + +import java.util.UUID; + +/** + * + * @author LoneFox + */ +public class SageAven extends mage.sets.ninthedition.SageAven { + + public SageAven(UUID ownerId) { + super(ownerId); + this.cardNumber = 111; + this.expansionSetCode = "ONS"; + } + + public SageAven(final SageAven card) { + super(card); + } + + @Override + public SageAven copy() { + return new SageAven(this); + } +} diff --git a/Mage.Sets/src/mage/sets/prophecy/WhipSergeant.java b/Mage.Sets/src/mage/sets/prophecy/WhipSergeant.java new file mode 100644 index 0000000000..6067839931 --- /dev/null +++ b/Mage.Sets/src/mage/sets/prophecy/WhipSergeant.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.prophecy; + +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.GainAbilityTargetEffect; +import mage.abilities.keyword.HasteAbility; +import mage.cards.CardImpl; +import mage.constants.CardType; +import mage.constants.Duration; +import mage.constants.Rarity; +import mage.constants.Zone; +import mage.target.common.TargetCreaturePermanent; + +/** + * + * @author LoneFox + */ +public class WhipSergeant extends CardImpl { + + public WhipSergeant(UUID ownerId) { + super(ownerId, 107, "Whip Sergeant", Rarity.UNCOMMON, new CardType[]{CardType.CREATURE}, "{2}{R}"); + this.expansionSetCode = "PCY"; + this.subtype.add("Human"); + this.subtype.add("Soldier"); + this.power = new MageInt(2); + this.toughness = new MageInt(1); + + // {R}: Target creature gains haste until end of turn. + Ability ability = new SimpleActivatedAbility(Zone.BATTLEFIELD, + new GainAbilityTargetEffect(HasteAbility.getInstance(), Duration.EndOfTurn), new ManaCostsImpl("{R}")); + ability.addTarget(new TargetCreaturePermanent()); + this.addAbility(ability); + } + + public WhipSergeant(final WhipSergeant card) { + super(card); + } + + @Override + public WhipSergeant copy() { + return new WhipSergeant(this); + } +} diff --git a/Mage.Sets/src/mage/sets/stronghold/FlowstoneShambler.java b/Mage.Sets/src/mage/sets/stronghold/FlowstoneShambler.java new file mode 100644 index 0000000000..b64a081c05 --- /dev/null +++ b/Mage.Sets/src/mage/sets/stronghold/FlowstoneShambler.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.stronghold; + +import java.util.UUID; + +/** + * + * @author LoneFox + */ +public class FlowstoneShambler extends mage.sets.ninthedition.FlowstoneShambler { + + public FlowstoneShambler(UUID ownerId) { + super(ownerId); + this.cardNumber = 86; + this.expansionSetCode = "STH"; + } + + public FlowstoneShambler(final FlowstoneShambler card) { + super(card); + } + + @Override + public FlowstoneShambler copy() { + return new FlowstoneShambler(this); + } +} diff --git a/Mage.Sets/src/mage/sets/urzassaga/SanctumGuardian.java b/Mage.Sets/src/mage/sets/urzassaga/SanctumGuardian.java new file mode 100644 index 0000000000..2b40cfa1a6 --- /dev/null +++ b/Mage.Sets/src/mage/sets/urzassaga/SanctumGuardian.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.urzassaga; + +import java.util.UUID; + +/** + * + * @author LoneFox + */ +public class SanctumGuardian extends mage.sets.ninthedition.SanctumGuardian { + + public SanctumGuardian(UUID ownerId) { + super(ownerId); + this.cardNumber = 43; + this.expansionSetCode = "USG"; + } + + public SanctumGuardian(final SanctumGuardian card) { + super(card); + } + + @Override + public SanctumGuardian copy() { + return new SanctumGuardian(this); + } +} From 257cec78197944bee57259c519b0084782dc67cd Mon Sep 17 00:00:00 2001 From: LoneFox Date: Sun, 16 Aug 2015 15:10:10 +0300 Subject: [PATCH 02/15] Implement cards: Horror of Horrors, Imaginary Pet, and Marble Titan --- .../mage/sets/legends/HorrorOfHorrors.java | 80 +++++++++++++++++++ .../sets/ninthedition/HorrorOfHorrors.java | 52 ++++++++++++ .../mage/sets/ninthedition/ImaginaryPet.java | 52 ++++++++++++ .../mage/sets/ninthedition/MarbleTitan.java | 52 ++++++++++++ .../src/mage/sets/tempest/MarbleTitan.java | 75 +++++++++++++++++ .../src/mage/sets/urzassaga/ImaginaryPet.java | 69 ++++++++++++++++ 6 files changed, 380 insertions(+) create mode 100644 Mage.Sets/src/mage/sets/legends/HorrorOfHorrors.java create mode 100644 Mage.Sets/src/mage/sets/ninthedition/HorrorOfHorrors.java create mode 100644 Mage.Sets/src/mage/sets/ninthedition/ImaginaryPet.java create mode 100644 Mage.Sets/src/mage/sets/ninthedition/MarbleTitan.java create mode 100644 Mage.Sets/src/mage/sets/tempest/MarbleTitan.java create mode 100644 Mage.Sets/src/mage/sets/urzassaga/ImaginaryPet.java diff --git a/Mage.Sets/src/mage/sets/legends/HorrorOfHorrors.java b/Mage.Sets/src/mage/sets/legends/HorrorOfHorrors.java new file mode 100644 index 0000000000..99db10a806 --- /dev/null +++ b/Mage.Sets/src/mage/sets/legends/HorrorOfHorrors.java @@ -0,0 +1,80 @@ +/* + * Copyright 2010 BetaSteward_at_googlemail.com. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are + * permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this list of + * conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, this list + * of conditions and the following disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY BetaSteward_at_googlemail.com ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BetaSteward_at_googlemail.com OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * The views and conclusions contained in the software and documentation are those of the + * authors and should not be interpreted as representing official policies, either expressed + * or implied, of BetaSteward_at_googlemail.com. + */ +package mage.sets.legends; + +import java.util.UUID; +import mage.ObjectColor; +import mage.abilities.Ability; +import mage.abilities.common.SimpleActivatedAbility; +import mage.abilities.costs.common.SacrificeTargetCost; +import mage.abilities.effects.common.RegenerateTargetEffect; +import mage.cards.CardImpl; +import mage.constants.CardType; +import mage.constants.Rarity; +import mage.constants.Zone; +import mage.filter.common.FilterControlledPermanent; +import mage.filter.common.FilterCreaturePermanent; +import mage.filter.predicate.mageobject.ColorPredicate; +import mage.filter.predicate.mageobject.SubtypePredicate; +import mage.target.common.TargetControlledPermanent; +import mage.target.common.TargetCreaturePermanent; + +/** + * + * @author LoneFox + */ +public class HorrorOfHorrors extends CardImpl { + + private static final FilterControlledPermanent filter1 = new FilterControlledPermanent("a Swamp"); + private static final FilterCreaturePermanent filter2 = new FilterCreaturePermanent("black creature"); + + static { + filter1.add(new SubtypePredicate("Swamp")); + filter2.add(new ColorPredicate(ObjectColor.BLACK)); + } + + public HorrorOfHorrors(UUID ownerId) { + super(ownerId, 20, "Horror of Horrors", Rarity.UNCOMMON, new CardType[]{CardType.ENCHANTMENT}, "{3}{B}{B}"); + this.expansionSetCode = "LEG"; + + // Sacrifice a Swamp: Regenerate target black creature. + Ability ability = new SimpleActivatedAbility(Zone.BATTLEFIELD, new RegenerateTargetEffect(), + new SacrificeTargetCost(new TargetControlledPermanent(filter1))); + ability.addTarget(new TargetCreaturePermanent(filter2)); + this.addAbility(ability); + } + + public HorrorOfHorrors(final HorrorOfHorrors card) { + super(card); + } + + @Override + public HorrorOfHorrors copy() { + return new HorrorOfHorrors(this); + } +} diff --git a/Mage.Sets/src/mage/sets/ninthedition/HorrorOfHorrors.java b/Mage.Sets/src/mage/sets/ninthedition/HorrorOfHorrors.java new file mode 100644 index 0000000000..5f229c7da1 --- /dev/null +++ b/Mage.Sets/src/mage/sets/ninthedition/HorrorOfHorrors.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.ninthedition; + +import java.util.UUID; + +/** + * + * @author LoneFox + */ +public class HorrorOfHorrors extends mage.sets.legends.HorrorOfHorrors { + + public HorrorOfHorrors(UUID ownerId) { + super(ownerId); + this.cardNumber = 140; + this.expansionSetCode = "9ED"; + } + + public HorrorOfHorrors(final HorrorOfHorrors card) { + super(card); + } + + @Override + public HorrorOfHorrors copy() { + return new HorrorOfHorrors(this); + } +} diff --git a/Mage.Sets/src/mage/sets/ninthedition/ImaginaryPet.java b/Mage.Sets/src/mage/sets/ninthedition/ImaginaryPet.java new file mode 100644 index 0000000000..cbc264edc8 --- /dev/null +++ b/Mage.Sets/src/mage/sets/ninthedition/ImaginaryPet.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.ninthedition; + +import java.util.UUID; + +/** + * + * @author LoneFox + */ +public class ImaginaryPet extends mage.sets.urzassaga.ImaginaryPet { + + public ImaginaryPet(UUID ownerId) { + super(ownerId); + this.cardNumber = 82; + this.expansionSetCode = "9ED"; + } + + public ImaginaryPet(final ImaginaryPet card) { + super(card); + } + + @Override + public ImaginaryPet copy() { + return new ImaginaryPet(this); + } +} diff --git a/Mage.Sets/src/mage/sets/ninthedition/MarbleTitan.java b/Mage.Sets/src/mage/sets/ninthedition/MarbleTitan.java new file mode 100644 index 0000000000..61d49319d2 --- /dev/null +++ b/Mage.Sets/src/mage/sets/ninthedition/MarbleTitan.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.ninthedition; + +import java.util.UUID; + +/** + * + * @author LoneFox + */ +public class MarbleTitan extends mage.sets.tempest.MarbleTitan { + + public MarbleTitan(UUID ownerId) { + super(ownerId); + this.cardNumber = 26; + this.expansionSetCode = "9ED"; + } + + public MarbleTitan(final MarbleTitan card) { + super(card); + } + + @Override + public MarbleTitan copy() { + return new MarbleTitan(this); + } +} diff --git a/Mage.Sets/src/mage/sets/tempest/MarbleTitan.java b/Mage.Sets/src/mage/sets/tempest/MarbleTitan.java new file mode 100644 index 0000000000..77aca3a45d --- /dev/null +++ b/Mage.Sets/src/mage/sets/tempest/MarbleTitan.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.tempest; + +import java.util.UUID; +import mage.MageInt; +import mage.abilities.common.SimpleStaticAbility; +import mage.abilities.effects.common.DontUntapInControllersUntapStepAllEffect; +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.Filter; +import mage.filter.common.FilterCreaturePermanent; +import mage.filter.predicate.mageobject.PowerPredicate; + +/** + * + * @author LoneFox + */ +public class MarbleTitan extends CardImpl { + + private static final FilterCreaturePermanent filter = new FilterCreaturePermanent("Creatures with power 3 or greater"); + + static { + filter.add(new PowerPredicate(Filter.ComparisonType.GreaterThan, 2)); + } + + public MarbleTitan(UUID ownerId) { + super(ownerId, 240, "Marble Titan", Rarity.RARE, new CardType[]{CardType.CREATURE}, "{3}{W}"); + this.expansionSetCode = "TMP"; + this.subtype.add("Giant"); + this.power = new MageInt(3); + this.toughness = new MageInt(3); + + // Creatures with power 3 or greater don't untap during their controllers' untap steps. + this.addAbility(new SimpleStaticAbility(Zone.BATTLEFIELD, new DontUntapInControllersUntapStepAllEffect(Duration.WhileOnBattlefield, TargetController.ANY, filter))); + } + + public MarbleTitan(final MarbleTitan card) { + super(card); + } + + @Override + public MarbleTitan copy() { + return new MarbleTitan(this); + } +} diff --git a/Mage.Sets/src/mage/sets/urzassaga/ImaginaryPet.java b/Mage.Sets/src/mage/sets/urzassaga/ImaginaryPet.java new file mode 100644 index 0000000000..69a4a490c4 --- /dev/null +++ b/Mage.Sets/src/mage/sets/urzassaga/ImaginaryPet.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.urzassaga; + +import java.util.UUID; +import mage.MageInt; +import mage.abilities.TriggeredAbility; +import mage.abilities.common.BeginningOfUpkeepTriggeredAbility; +import mage.abilities.condition.common.CardsInHandCondition; +import mage.abilities.decorator.ConditionalTriggeredAbility; +import mage.abilities.effects.common.ReturnToHandSourceEffect; +import mage.cards.CardImpl; +import mage.constants.CardType; +import mage.constants.Rarity; +import mage.constants.TargetController; + +/** + * + * @author LoneFox + */ +public class ImaginaryPet extends CardImpl { + + public ImaginaryPet(UUID ownerId) { + super(ownerId, 81, "Imaginary Pet", Rarity.RARE, new CardType[]{CardType.CREATURE}, "{1}{U}"); + this.expansionSetCode = "USG"; + this.subtype.add("Illusion"); + this.power = new MageInt(4); + this.toughness = new MageInt(4); + + // At the beginning of your upkeep, if you have a card in hand, return Imaginary Pet to its owner's hand. + TriggeredAbility ability = new BeginningOfUpkeepTriggeredAbility(new ReturnToHandSourceEffect(true), TargetController.YOU, false); + this.addAbility(new ConditionalTriggeredAbility(ability, new CardsInHandCondition(CardsInHandCondition.CountType.MORE_THAN, 0), + "At the beginning of your upkeep, if you have a card in hand, return {this} to its owner's hand.")); + } + + public ImaginaryPet(final ImaginaryPet card) { + super(card); + } + + @Override + public ImaginaryPet copy() { + return new ImaginaryPet(this); + } +} From bb3b476e91f00aa28d6280d89c9c111fb528cf62 Mon Sep 17 00:00:00 2001 From: LoneFox Date: Sun, 16 Aug 2015 16:25:53 +0300 Subject: [PATCH 03/15] Implement cards: Ancient Hydra; Crested Craghorn; Jeska, Warrior Adept; and Lovisa Coldeyes --- .../mage/sets/coldsnap/LovisaColdeyes.java | 85 +++++++++++++++++++ .../mage/sets/judgment/JeskaWarriorAdept.java | 78 +++++++++++++++++ .../mage/sets/legions/CrestedCraghorn.java | 66 ++++++++++++++ .../src/mage/sets/nemesis/AncientHydra.java | 75 ++++++++++++++++ 4 files changed, 304 insertions(+) create mode 100644 Mage.Sets/src/mage/sets/coldsnap/LovisaColdeyes.java create mode 100644 Mage.Sets/src/mage/sets/judgment/JeskaWarriorAdept.java create mode 100644 Mage.Sets/src/mage/sets/legions/CrestedCraghorn.java create mode 100644 Mage.Sets/src/mage/sets/nemesis/AncientHydra.java diff --git a/Mage.Sets/src/mage/sets/coldsnap/LovisaColdeyes.java b/Mage.Sets/src/mage/sets/coldsnap/LovisaColdeyes.java new file mode 100644 index 0000000000..ebdff5a908 --- /dev/null +++ b/Mage.Sets/src/mage/sets/coldsnap/LovisaColdeyes.java @@ -0,0 +1,85 @@ +/* + * Copyright 2010 BetaSteward_at_googlemail.com. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are + * permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this list of + * conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, this list + * of conditions and the following disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY BetaSteward_at_googlemail.com ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BetaSteward_at_googlemail.com OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * The views and conclusions contained in the software and documentation are those of the + * authors and should not be interpreted as representing official policies, either expressed + * or implied, of BetaSteward_at_googlemail.com. + */ +package mage.sets.coldsnap; + +import java.util.UUID; +import mage.MageInt; +import mage.abilities.Ability; +import mage.abilities.common.SimpleStaticAbility; +import mage.abilities.effects.Effect; +import mage.abilities.effects.common.continuous.BoostControlledEffect; +import mage.abilities.effects.common.continuous.GainAbilityControlledEffect; +import mage.abilities.keyword.HasteAbility; +import mage.cards.CardImpl; +import mage.constants.CardType; +import mage.constants.Duration; +import mage.constants.Rarity; +import mage.constants.Zone; +import mage.filter.common.FilterCreaturePermanent; +import mage.filter.predicate.Predicates; +import mage.filter.predicate.mageobject.SubtypePredicate; + +/** + * + * @author LoneFox + */ +public class LovisaColdeyes extends CardImpl { + + private static final FilterCreaturePermanent filter = new FilterCreaturePermanent("creature you control that's a Barbarian, a Warrior, or a Berserker"); + + static { + filter.add(Predicates.or(new SubtypePredicate("Barbarian"), new SubtypePredicate("Warrior"), new SubtypePredicate("Berserker"))); + } + + public LovisaColdeyes(UUID ownerId) { + super(ownerId, 90, "Lovisa Coldeyes", Rarity.RARE, new CardType[]{CardType.CREATURE}, "{3}{R}{R}"); + this.expansionSetCode = "CSP"; + this.supertype.add("Legendary"); + this.subtype.add("Human"); + this.power = new MageInt(3); + this.toughness = new MageInt(3); + + // Each creature you control that's a Barbarian, a Warrior, or a Berserker gets +2/+2 and has haste. + Effect effect = new BoostControlledEffect(2, 2, Duration.WhileOnBattlefield, filter, false); + effect.setText("Each creature you control that's a Barbarian, a Warrior, or a Berserker gets +2/+2"); + Ability ability = new SimpleStaticAbility(Zone.BATTLEFIELD, effect); + effect = new GainAbilityControlledEffect(HasteAbility.getInstance(), Duration.WhileOnBattlefield, filter, false); + effect.setText("and has haste"); + ability.addEffect(effect); + this.addAbility(ability); + } + + public LovisaColdeyes(final LovisaColdeyes card) { + super(card); + } + + @Override + public LovisaColdeyes copy() { + return new LovisaColdeyes(this); + } +} diff --git a/Mage.Sets/src/mage/sets/judgment/JeskaWarriorAdept.java b/Mage.Sets/src/mage/sets/judgment/JeskaWarriorAdept.java new file mode 100644 index 0000000000..7d12fb0dd3 --- /dev/null +++ b/Mage.Sets/src/mage/sets/judgment/JeskaWarriorAdept.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.judgment; + +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.DamageTargetEffect; +import mage.abilities.keyword.FirstStrikeAbility; +import mage.abilities.keyword.HasteAbility; +import mage.cards.CardImpl; +import mage.constants.CardType; +import mage.constants.Rarity; +import mage.constants.Zone; +import mage.target.common.TargetCreatureOrPlayer; + +/** + * + * @author LoneFox + */ +public class JeskaWarriorAdept extends CardImpl { + + public JeskaWarriorAdept(UUID ownerId) { + super(ownerId, 93, "Jeska, Warrior Adept", Rarity.RARE, new CardType[]{CardType.CREATURE}, "{2}{R}{R}"); + this.expansionSetCode = "JUD"; + this.supertype.add("Legendary"); + this.subtype.add("Human"); + this.subtype.add("Barbarian"); + this.subtype.add("Warrior"); + this.power = new MageInt(3); + this.toughness = new MageInt(1); + + // First strike + this.addAbility(FirstStrikeAbility.getInstance()); + // Haste + this.addAbility(HasteAbility.getInstance()); + // {tap}: Jeska, Warrior Adept deals 1 damage to target creature or player. + Ability ability = new SimpleActivatedAbility(Zone.BATTLEFIELD, new DamageTargetEffect(1), new TapSourceCost()); + ability.addTarget(new TargetCreatureOrPlayer()); + this.addAbility(ability); + } + + public JeskaWarriorAdept(final JeskaWarriorAdept card) { + super(card); + } + + @Override + public JeskaWarriorAdept copy() { + return new JeskaWarriorAdept(this); + } +} diff --git a/Mage.Sets/src/mage/sets/legions/CrestedCraghorn.java b/Mage.Sets/src/mage/sets/legions/CrestedCraghorn.java new file mode 100644 index 0000000000..aed2e22cc9 --- /dev/null +++ b/Mage.Sets/src/mage/sets/legions/CrestedCraghorn.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.legions; + +import java.util.UUID; +import mage.MageInt; +import mage.abilities.keyword.HasteAbility; +import mage.abilities.keyword.ProvokeAbility; +import mage.cards.CardImpl; +import mage.constants.CardType; +import mage.constants.Rarity; + +/** + * + * @author LoneFox + */ +public class CrestedCraghorn extends CardImpl { + + public CrestedCraghorn(UUID ownerId) { + super(ownerId, 91, "Crested Craghorn", Rarity.COMMON, new CardType[]{CardType.CREATURE}, "{4}{R}"); + this.expansionSetCode = "LGN"; + this.subtype.add("Goat"); + this.subtype.add("Beast"); + this.power = new MageInt(4); + this.toughness = new MageInt(1); + + // Haste + this.addAbility(HasteAbility.getInstance()); + // Provoke + this.addAbility(new ProvokeAbility()); + } + + public CrestedCraghorn(final CrestedCraghorn card) { + super(card); + } + + @Override + public CrestedCraghorn copy() { + return new CrestedCraghorn(this); + } +} diff --git a/Mage.Sets/src/mage/sets/nemesis/AncientHydra.java b/Mage.Sets/src/mage/sets/nemesis/AncientHydra.java new file mode 100644 index 0000000000..a9ea30a997 --- /dev/null +++ b/Mage.Sets/src/mage/sets/nemesis/AncientHydra.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.nemesis; + +import java.util.UUID; +import mage.MageInt; +import mage.abilities.Ability; +import mage.abilities.common.SimpleActivatedAbility; +import mage.abilities.costs.common.RemoveCountersSourceCost; +import mage.abilities.costs.mana.ManaCostsImpl; +import mage.abilities.effects.common.DamageTargetEffect; +import mage.abilities.keyword.FadingAbility; +import mage.cards.CardImpl; +import mage.constants.CardType; +import mage.constants.Rarity; +import mage.constants.Zone; +import mage.counters.CounterType; +import mage.target.common.TargetCreatureOrPlayer; + +/** + * + * @author LoneFox + */ +public class AncientHydra extends CardImpl { + + public AncientHydra(UUID ownerId) { + super(ownerId, 76, "Ancient Hydra", Rarity.UNCOMMON, new CardType[]{CardType.CREATURE}, "{4}{R}"); + this.expansionSetCode = "NMS"; + this.subtype.add("Hydra"); + this.power = new MageInt(5); + this.toughness = new MageInt(1); + + // Fading 5 + this.addAbility(new FadingAbility(5, this)); + // {1}, Remove a fade counter from Ancient Hydra: Ancient Hydra deals 1 damage to target creature or player. + Ability ability = new SimpleActivatedAbility(Zone.BATTLEFIELD, new DamageTargetEffect(1), new ManaCostsImpl("{1}")); + ability.addCost(new RemoveCountersSourceCost(CounterType.FADE.createInstance(1))); + ability.addTarget(new TargetCreatureOrPlayer()); + this.addAbility(ability); + } + + public AncientHydra(final AncientHydra card) { + super(card); + } + + @Override + public AncientHydra copy() { + return new AncientHydra(this); + } +} From 5f698a54f434ac1baf89d6e8a769431a6314e489 Mon Sep 17 00:00:00 2001 From: LoneFox Date: Sun, 16 Aug 2015 22:00:02 +0300 Subject: [PATCH 04/15] Fix Complicate and Death Pulse: the triggered ability is optional. Implement cards: Primal Boost and Sunfire Balm --- .../src/mage/sets/onslaught/Complicate.java | 6 +- .../src/mage/sets/onslaught/DeathPulse.java | 4 +- .../src/mage/sets/onslaught/PrimalBoost.java | 71 ++++++++++++++++++ .../src/mage/sets/onslaught/SunfireBalm.java | 72 +++++++++++++++++++ 4 files changed, 148 insertions(+), 5 deletions(-) create mode 100644 Mage.Sets/src/mage/sets/onslaught/PrimalBoost.java create mode 100644 Mage.Sets/src/mage/sets/onslaught/SunfireBalm.java diff --git a/Mage.Sets/src/mage/sets/onslaught/Complicate.java b/Mage.Sets/src/mage/sets/onslaught/Complicate.java index 29e679a624..3d5023a586 100644 --- a/Mage.Sets/src/mage/sets/onslaught/Complicate.java +++ b/Mage.Sets/src/mage/sets/onslaught/Complicate.java @@ -52,12 +52,12 @@ public class Complicate extends CardImpl { // Counter target spell unless its controller pays {3}. this.getSpellAbility().addEffect(new CounterUnlessPaysEffect(new GenericManaCost(3))); this.getSpellAbility().addTarget(new TargetSpell()); - + // Cycling {2}{U} this.addAbility(new CyclingAbility(new ManaCostsImpl<>("{2}{U}"))); - + // When you cycle Complicate, you may counter target spell unless its controller pays {1}. - Ability ability = new CycleTriggeredAbility(new CounterUnlessPaysEffect(new GenericManaCost(1))); + Ability ability = new CycleTriggeredAbility(new CounterUnlessPaysEffect(new GenericManaCost(1)), true); ability.addTarget(new TargetSpell()); this.addAbility(ability); } diff --git a/Mage.Sets/src/mage/sets/onslaught/DeathPulse.java b/Mage.Sets/src/mage/sets/onslaught/DeathPulse.java index be0c44a8f8..0cf9e25b03 100644 --- a/Mage.Sets/src/mage/sets/onslaught/DeathPulse.java +++ b/Mage.Sets/src/mage/sets/onslaught/DeathPulse.java @@ -52,11 +52,11 @@ public class DeathPulse extends CardImpl { // Target creature gets -4/-4 until end of turn. this.getSpellAbility().addEffect(new BoostTargetEffect(-4, -4, Duration.EndOfTurn)); this.getSpellAbility().addTarget(new TargetCreaturePermanent()); - + // Cycling {1}{B}{B} this.addAbility(new CyclingAbility(new ManaCostsImpl("{1}{B}{B}"))); // When you cycle Death Pulse, you may have target creature get -1/-1 until end of turn. - Ability ability = new CycleTriggeredAbility(new BoostTargetEffect(-1, -1, Duration.EndOfTurn)); + Ability ability = new CycleTriggeredAbility(new BoostTargetEffect(-1, -1, Duration.EndOfTurn), true); ability.addTarget(new TargetCreaturePermanent()); this.addAbility(ability); } diff --git a/Mage.Sets/src/mage/sets/onslaught/PrimalBoost.java b/Mage.Sets/src/mage/sets/onslaught/PrimalBoost.java new file mode 100644 index 0000000000..9d050f1fc2 --- /dev/null +++ b/Mage.Sets/src/mage/sets/onslaught/PrimalBoost.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.onslaught; + +import java.util.UUID; +import mage.abilities.Ability; +import mage.abilities.common.CycleTriggeredAbility; +import mage.abilities.costs.mana.ManaCostsImpl; +import mage.abilities.effects.common.continuous.BoostTargetEffect; +import mage.abilities.keyword.CyclingAbility; +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 PrimalBoost extends CardImpl { + + public PrimalBoost(UUID ownerId) { + super(ownerId, 277, "Primal Boost", Rarity.UNCOMMON, new CardType[]{CardType.INSTANT}, "{2}{G}"); + this.expansionSetCode = "ONS"; + + // Target creature gets +4/+4 until end of turn. + this.getSpellAbility().addEffect(new BoostTargetEffect(4, 4, Duration.EndOfTurn)); + this.getSpellAbility().addTarget(new TargetCreaturePermanent()); + // Cycling {2}{G} + this.addAbility(new CyclingAbility(new ManaCostsImpl("{2}{G}"))); + // When you cycle Primal Boost, you may have target creature get +1/+1 until end of turn. + Ability ability = new CycleTriggeredAbility(new BoostTargetEffect(1, 1, Duration.EndOfTurn), true); + ability.addTarget(new TargetCreaturePermanent()); + this.addAbility(ability); + } + + public PrimalBoost(final PrimalBoost card) { + super(card); + } + + @Override + public PrimalBoost copy() { + return new PrimalBoost(this); + } +} diff --git a/Mage.Sets/src/mage/sets/onslaught/SunfireBalm.java b/Mage.Sets/src/mage/sets/onslaught/SunfireBalm.java new file mode 100644 index 0000000000..896fcdc29a --- /dev/null +++ b/Mage.Sets/src/mage/sets/onslaught/SunfireBalm.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.onslaught; + +import java.util.UUID; +import mage.abilities.Ability; +import mage.abilities.common.CycleTriggeredAbility; +import mage.abilities.costs.mana.ManaCostsImpl; +import mage.abilities.effects.common.PreventDamageToTargetEffect; +import mage.abilities.keyword.CyclingAbility; +import mage.cards.CardImpl; +import mage.constants.CardType; +import mage.constants.Duration; +import mage.constants.Rarity; +import mage.target.common.TargetCreatureOrPlayer; + +/** + * + * @author LoneFox + */ +public class SunfireBalm extends CardImpl { + + public SunfireBalm(UUID ownerId) { + super(ownerId, 56, "Sunfire Balm", Rarity.UNCOMMON, new CardType[]{CardType.INSTANT}, "{2}{W}"); + this.expansionSetCode = "ONS"; + + // Prevent the next 4 damage that would be dealt to target creature or player this turn. + this.getSpellAbility().addEffect(new PreventDamageToTargetEffect(Duration.EndOfTurn, 4)); + this.getSpellAbility().addTarget(new TargetCreatureOrPlayer()); + // Cycling {1}{W} + this.addAbility(new CyclingAbility(new ManaCostsImpl("{1}{W}"))); + // When you cycle Sunfire Balm, you may prevent the next 1 damage that would be dealt to target creature or player this turn. + Ability ability = new CycleTriggeredAbility(new PreventDamageToTargetEffect(Duration.EndOfTurn, 1), true); + ability.addTarget(new TargetCreatureOrPlayer()); + this.addAbility(ability); + + } + + public SunfireBalm(final SunfireBalm card) { + super(card); + } + + @Override + public SunfireBalm copy() { + return new SunfireBalm(this); + } +} From c570f3b637bc263e70ba73d3c3aa647a9481e9e0 Mon Sep 17 00:00:00 2001 From: LoneFox Date: Sun, 16 Aug 2015 22:01:22 +0300 Subject: [PATCH 05/15] Fix Seaside Haven: add missing card drawing effect. --- Mage.Sets/src/mage/sets/onslaught/SeasideHaven.java | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/Mage.Sets/src/mage/sets/onslaught/SeasideHaven.java b/Mage.Sets/src/mage/sets/onslaught/SeasideHaven.java index 193ab18919..eaccc8185c 100644 --- a/Mage.Sets/src/mage/sets/onslaught/SeasideHaven.java +++ b/Mage.Sets/src/mage/sets/onslaught/SeasideHaven.java @@ -33,6 +33,7 @@ import mage.abilities.common.SimpleActivatedAbility; import mage.abilities.costs.common.SacrificeTargetCost; import mage.abilities.costs.common.TapSourceCost; import mage.abilities.costs.mana.ManaCostsImpl; +import mage.abilities.effects.common.DrawCardSourceControllerEffect; import mage.abilities.mana.ColorlessManaAbility; import mage.cards.CardImpl; import mage.constants.CardType; @@ -47,9 +48,9 @@ import mage.target.common.TargetControlledPermanent; * @author anonymous */ public class SeasideHaven extends CardImpl { - + private static final FilterControlledPermanent filter = new FilterControlledPermanent("Bird"); - + static{ filter.add(new SubtypePredicate("Bird")); } @@ -61,7 +62,7 @@ public class SeasideHaven extends CardImpl { // {tap}: Add {1} to your mana pool. this.addAbility(new ColorlessManaAbility()); // {W}{U}, {tap}, Sacrifice a Bird: Draw a card. - Ability ability = new SimpleActivatedAbility(Zone.BATTLEFIELD, null, new ManaCostsImpl<>("{W}{U}")); + Ability ability = new SimpleActivatedAbility(Zone.BATTLEFIELD, new DrawCardSourceControllerEffect(1), new ManaCostsImpl<>("{W}{U}")); ability.addCost(new TapSourceCost()); ability.addCost(new SacrificeTargetCost(new TargetControlledPermanent(filter))); this.addAbility(ability); From 40d2eabedb1022823bcddc3330d62756fb1012cd Mon Sep 17 00:00:00 2001 From: LoneFox Date: Sun, 16 Aug 2015 22:06:06 +0300 Subject: [PATCH 06/15] Update the text of Goblin Burrows --- Mage.Sets/src/mage/sets/onslaught/GoblinBurrows.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Mage.Sets/src/mage/sets/onslaught/GoblinBurrows.java b/Mage.Sets/src/mage/sets/onslaught/GoblinBurrows.java index c54781b82e..66bcc8033f 100644 --- a/Mage.Sets/src/mage/sets/onslaught/GoblinBurrows.java +++ b/Mage.Sets/src/mage/sets/onslaught/GoblinBurrows.java @@ -49,7 +49,7 @@ import mage.target.common.TargetCreaturePermanent; */ public class GoblinBurrows extends CardImpl { - private static final FilterCreaturePermanent filter = new FilterCreaturePermanent("Goblin"); + private static final FilterCreaturePermanent filter = new FilterCreaturePermanent("Goblin creature"); static { filter.add(new SubtypePredicate(("Goblin"))); From 60bc09ca4f0cbe0ddb6aedef224d359f5ac6baf6 Mon Sep 17 00:00:00 2001 From: LoneFox Date: Sun, 16 Aug 2015 22:22:31 +0300 Subject: [PATCH 07/15] Fix Beacon of Immortality: use target player's current life total instead of starting life total. --- Mage.Sets/src/mage/sets/tenthedition/BeaconOfImmortality.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Mage.Sets/src/mage/sets/tenthedition/BeaconOfImmortality.java b/Mage.Sets/src/mage/sets/tenthedition/BeaconOfImmortality.java index b9a3ecc224..b382e323c5 100644 --- a/Mage.Sets/src/mage/sets/tenthedition/BeaconOfImmortality.java +++ b/Mage.Sets/src/mage/sets/tenthedition/BeaconOfImmortality.java @@ -87,9 +87,9 @@ class BeaconOfImmortalityEffect extends OneShotEffect { public boolean apply(Game game, Ability source) { Player player = game.getPlayer(source.getFirstTarget()); if (player != null) { - int amount = game.getLife(); + int amount = player.getLife(); if (amount < 0) { - player.loseLife(amount, game); + player.loseLife(-amount, game); return true; } if (amount > 0) { From 889d18af725197e0332b0f86a17eaaedc195a7bc Mon Sep 17 00:00:00 2001 From: LevelX2 Date: Mon, 17 Aug 2015 10:21:03 +0200 Subject: [PATCH 08/15] * Curse of Shallow Graves - Fixed that the correct player may decide to create the token. --- .../commander2013/CurseOfShallowGraves.java | 36 +++++++++++++++++-- .../common/CreateTokenTargetEffect.java | 13 ++----- 2 files changed, 36 insertions(+), 13 deletions(-) diff --git a/Mage.Sets/src/mage/sets/commander2013/CurseOfShallowGraves.java b/Mage.Sets/src/mage/sets/commander2013/CurseOfShallowGraves.java index fa2e34e982..d51655b3c7 100644 --- a/Mage.Sets/src/mage/sets/commander2013/CurseOfShallowGraves.java +++ b/Mage.Sets/src/mage/sets/commander2013/CurseOfShallowGraves.java @@ -28,9 +28,11 @@ package mage.sets.commander2013; import java.util.UUID; +import mage.abilities.Ability; import mage.abilities.TriggeredAbilityImpl; import mage.abilities.dynamicvalue.common.StaticValue; import mage.abilities.effects.Effect; +import mage.abilities.effects.OneShotEffect; import mage.abilities.effects.common.AttachEffect; import mage.abilities.effects.common.CreateTokenTargetEffect; import mage.abilities.keyword.EnchantAbility; @@ -44,6 +46,7 @@ import mage.game.events.GameEvent; import mage.game.events.GameEvent.EventType; import mage.game.permanent.Permanent; import mage.game.permanent.token.ZombieToken; +import mage.players.Player; import mage.target.TargetPlayer; import mage.target.targetpointer.FixedTarget; @@ -59,7 +62,6 @@ public class CurseOfShallowGraves extends CardImpl { this.subtype.add("Aura"); this.subtype.add("Curse"); - // Enchant player TargetPlayer auraTarget = new TargetPlayer(); this.getSpellAbility().addTarget(auraTarget); @@ -83,7 +85,7 @@ public class CurseOfShallowGraves extends CardImpl { class CurseOfShallowTriggeredAbility extends TriggeredAbilityImpl { public CurseOfShallowTriggeredAbility() { - super(Zone.BATTLEFIELD, new CreateTokenTargetEffect(new ZombieToken(), new StaticValue(1), true, false), true); + super(Zone.BATTLEFIELD, new CurseOfShallowEffect()); } public CurseOfShallowTriggeredAbility(Effect effect, boolean optional, String text) { @@ -105,7 +107,7 @@ class CurseOfShallowTriggeredAbility extends TriggeredAbilityImpl { if (enchantment != null && enchantment.getAttachedTo() != null && game.getCombat().getPlayerDefenders(game).contains(enchantment.getAttachedTo())) { - for (Effect effect: this.getEffects()) { + for (Effect effect : this.getEffects()) { effect.setTargetPointer(new FixedTarget(game.getCombat().getAttackerId())); } return true; @@ -124,3 +126,31 @@ class CurseOfShallowTriggeredAbility extends TriggeredAbilityImpl { } } + +class CurseOfShallowEffect extends OneShotEffect { + + public CurseOfShallowEffect() { + super(Outcome.Benefit); + this.staticText = "that attacking player may put a 2/2 black Zombie creature token onto the battlefield tapped"; + } + + public CurseOfShallowEffect(final CurseOfShallowEffect effect) { + super(effect); + } + + @Override + public CurseOfShallowEffect copy() { + return new CurseOfShallowEffect(this); + } + + @Override + public boolean apply(Game game, Ability source) { + Player attacker = game.getPlayer(this.getTargetPointer().getFirst(game, source)); + if (attacker != null && attacker.chooseUse(outcome, "Put a 2/2 black Zombie creature token onto the battlefield tapped?", source, game)) { + Effect effect = new CreateTokenTargetEffect(new ZombieToken(), new StaticValue(1), true, false); + effect.setTargetPointer(targetPointer); + return effect.apply(game, source); + } + return false; + } +} diff --git a/Mage/src/mage/abilities/effects/common/CreateTokenTargetEffect.java b/Mage/src/mage/abilities/effects/common/CreateTokenTargetEffect.java index 9c0e72eef9..91fcdb1c40 100644 --- a/Mage/src/mage/abilities/effects/common/CreateTokenTargetEffect.java +++ b/Mage/src/mage/abilities/effects/common/CreateTokenTargetEffect.java @@ -1,23 +1,20 @@ package mage.abilities.effects.common; -import java.util.Locale; import mage.abilities.Ability; import mage.abilities.Mode; import mage.abilities.dynamicvalue.DynamicValue; import mage.abilities.dynamicvalue.common.StaticValue; import mage.abilities.effects.OneShotEffect; import mage.constants.Outcome; -import mage.constants.Zone; import mage.game.Game; import mage.game.permanent.token.Token; -import mage.players.Player; import mage.util.CardUtil; /** * @author Loki */ - public class CreateTokenTargetEffect extends OneShotEffect { + private Token token; private DynamicValue amount; private boolean tapped; @@ -59,14 +56,10 @@ public class CreateTokenTargetEffect extends OneShotEffect { @Override public boolean apply(Game game, Ability source) { int value = amount.calculate(game, source, this); - Player controller = game.getPlayer(source.getControllerId()); - if (controller != null) { - if (value < 1) { - return true; - } + if (value > 0) { return token.putOntoBattlefield(value, game, source.getSourceId(), targetPointer.getFirst(game, source), tapped, attacking); } - return false; + return true; } @Override From 3b08d1ca8c41d4e7702bc569d541dc53122d4d3d Mon Sep 17 00:00:00 2001 From: LevelX2 Date: Mon, 17 Aug 2015 11:57:41 +0200 Subject: [PATCH 09/15] * Commander Greven il-Vec - Fixed that the sacrifice was handled targeted. --- .../src/mage/sets/tempest/CommanderGrevenIlVec.java | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/Mage.Sets/src/mage/sets/tempest/CommanderGrevenIlVec.java b/Mage.Sets/src/mage/sets/tempest/CommanderGrevenIlVec.java index 1ca56981e1..b7e5293c30 100644 --- a/Mage.Sets/src/mage/sets/tempest/CommanderGrevenIlVec.java +++ b/Mage.Sets/src/mage/sets/tempest/CommanderGrevenIlVec.java @@ -31,12 +31,11 @@ import java.util.UUID; import mage.constants.CardType; import mage.constants.Rarity; import mage.MageInt; -import mage.abilities.Ability; import mage.abilities.common.EntersBattlefieldTriggeredAbility; -import mage.abilities.effects.common.SacrificeTargetEffect; +import mage.abilities.effects.common.SacrificeControllerEffect; import mage.abilities.keyword.FearAbility; import mage.cards.CardImpl; -import mage.target.common.TargetControlledCreaturePermanent; +import mage.filter.common.FilterCreaturePermanent; /** * @@ -53,10 +52,12 @@ public class CommanderGrevenIlVec extends CardImpl { this.power = new MageInt(7); this.toughness = new MageInt(5); - Ability ability = new EntersBattlefieldTriggeredAbility(new SacrificeTargetEffect(), false); - ability.addTarget(new TargetControlledCreaturePermanent()); - this.addAbility(ability); + + // Fear (This creature can't be blocked except by artifact creatures and/or black creatures.) this.addAbility(FearAbility.getInstance()); + + // When Commander Greven il-Vec enters the battlefield, sacrifice a creature. + this.addAbility(new EntersBattlefieldTriggeredAbility(new SacrificeControllerEffect(new FilterCreaturePermanent(), 1, ""), false)); } public CommanderGrevenIlVec(final CommanderGrevenIlVec card) { From d7e64287efca3b20e57856988812c237151daba8 Mon Sep 17 00:00:00 2001 From: LevelX2 Date: Mon, 17 Aug 2015 12:01:48 +0200 Subject: [PATCH 10/15] * Phyrexian War Beast - Fixed that the land sacrifice was handled targeted. --- Mage.Sets/src/mage/sets/alliances/PhyrexianWarBeast1.java | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/Mage.Sets/src/mage/sets/alliances/PhyrexianWarBeast1.java b/Mage.Sets/src/mage/sets/alliances/PhyrexianWarBeast1.java index 5dad7465e1..e91607c20c 100644 --- a/Mage.Sets/src/mage/sets/alliances/PhyrexianWarBeast1.java +++ b/Mage.Sets/src/mage/sets/alliances/PhyrexianWarBeast1.java @@ -33,7 +33,7 @@ import mage.abilities.Ability; import mage.abilities.common.LeavesBattlefieldTriggeredAbility; import mage.abilities.effects.Effect; import mage.abilities.effects.common.DamageControllerEffect; -import mage.abilities.effects.common.SacrificeTargetEffect; +import mage.abilities.effects.common.SacrificeControllerEffect; import mage.cards.CardImpl; import mage.constants.CardType; import mage.constants.Rarity; @@ -54,10 +54,8 @@ public class PhyrexianWarBeast1 extends CardImpl { this.toughness = new MageInt(4); // When Phyrexian War Beast leaves the battlefield, sacrifice a land and Phyrexian War Beast deals 1 damage to you. - Effect effect = new SacrificeTargetEffect(); - effect.setText("sacrifice a land"); - Ability ability = new LeavesBattlefieldTriggeredAbility(effect, false); - effect = new DamageControllerEffect(1); + Ability ability = new LeavesBattlefieldTriggeredAbility(new SacrificeControllerEffect(new FilterControlledLandPermanent(), 1, ""), false); + Effect effect = new DamageControllerEffect(1); effect.setText("and {this} deals 1 damage to you"); ability.addEffect(effect); ability.addTarget(new TargetControlledPermanent(new FilterControlledLandPermanent())); From 8d1da5c35fc9ef8bee1bb217a81313186896d9b7 Mon Sep 17 00:00:00 2001 From: LevelX2 Date: Mon, 17 Aug 2015 12:36:42 +0200 Subject: [PATCH 11/15] * Fixed a lot of sacrifice handling that was targeted and some sacrifice where the player that could sacrifice was not checked correctly (e.g. Kiki-Jiki, Mirror Breaker Token). --- .../mage/sets/alarareborn/SlaveOfBolas.java | 25 ++++--- .../sets/alliances/LordOfTresserhorn.java | 11 +-- .../sets/avacynrestored/ThatcherRevolt.java | 26 ++++--- .../sets/championsofkamigawa/JunkyoBell.java | 71 +++++++++--------- .../KikiJikiMirrorBreaker.java | 10 +-- .../championsofkamigawa/OniPossession.java | 28 ++++--- .../championsofkamigawa/ThroughTheBreach.java | 9 +-- .../commander2014/FeldonOfTheThirdPath.java | 20 ++--- .../mage/sets/commander2014/WakeTheDead.java | 10 +-- .../sets/eventide/AshlingTheExtinguisher.java | 9 ++- Mage.Sets/src/mage/sets/invasion/Dredge.java | 8 +- .../src/mage/sets/legions/GoblinFirebug.java | 13 +--- .../sets/lorwyn/IncandescentSoulstoke.java | 15 ++-- .../mage/sets/magic2014/ShadowbornDemon.java | 22 +++--- .../sets/masterseditioniv/FoulSpirit.java | 15 +--- .../mage/sets/planarchaos/FatalFrenzy.java | 27 ++++--- .../mage/sets/planarchaos/RealityAcid.java | 3 +- .../riseoftheeldrazi/DemonicAppetite.java | 49 ++++++------ .../FootstepsOfTheGoryo.java | 11 +-- .../saviorsofkamigawa/WineOfBloodAndIron.java | 44 ++--------- .../mage/sets/scarsofmirrodin/ShapeAnew.java | 33 ++++---- .../mage/sets/shadowmoor/ImpromptuRaid.java | 24 +++--- .../mage/sets/tempest/ServantOfVolrath.java | 11 +-- .../src/mage/sets/urzassaga/SneakAttack.java | 38 +++++----- .../mage/sets/zendikar/RuinousMinotaur.java | 49 ++---------- .../cards/copy/KikiJikiMirrorBreakerTest.java | 40 +++++++++- ...DealsDamageToOpponentTriggeredAbility.java | 3 +- .../effects/common/SacrificeTargetEffect.java | 75 +++++++++++-------- 28 files changed, 326 insertions(+), 373 deletions(-) diff --git a/Mage.Sets/src/mage/sets/alarareborn/SlaveOfBolas.java b/Mage.Sets/src/mage/sets/alarareborn/SlaveOfBolas.java index 414e9e9cee..da0c98d4ea 100644 --- a/Mage.Sets/src/mage/sets/alarareborn/SlaveOfBolas.java +++ b/Mage.Sets/src/mage/sets/alarareborn/SlaveOfBolas.java @@ -43,6 +43,7 @@ import mage.constants.Duration; import mage.constants.Outcome; import mage.constants.Rarity; import mage.game.Game; +import mage.game.permanent.Permanent; import mage.target.common.TargetCreaturePermanent; import mage.target.targetpointer.FixedTarget; @@ -56,10 +57,6 @@ public class SlaveOfBolas extends CardImpl { super(ownerId, 136, "Slave of Bolas", Rarity.UNCOMMON, new CardType[]{CardType.SORCERY}, "{3}{U/R}{B}"); this.expansionSetCode = "ARB"; - - - - // Gain control of target creature. Untap that creature. It gains haste until end of turn. Sacrifice it at the beginning of the next end step. this.getSpellAbility().addEffect(new GainControlTargetEffect(Duration.EndOfTurn)); this.getSpellAbility().addEffect(new UntapTargetEffect()); @@ -96,13 +93,17 @@ class SlaveOfBolasEffect extends OneShotEffect { @Override public boolean apply(Game game, Ability source) { - SacrificeTargetEffect sacrificeEffect = new SacrificeTargetEffect("sacrifice this"); - sacrificeEffect.setTargetPointer(new FixedTarget(source.getFirstTarget())); - DelayedTriggeredAbility delayedAbility = new AtTheBeginOfNextEndStepDelayedTriggeredAbility(sacrificeEffect); - delayedAbility.setSourceId(source.getSourceId()); - delayedAbility.setControllerId(source.getControllerId()); - delayedAbility.setSourceObject(source.getSourceObject(game), game); - game.addDelayedTriggeredAbility(delayedAbility); - return true; + Permanent permanent = game.getPermanent(source.getFirstTarget()); + if (permanent != null) { + SacrificeTargetEffect sacrificeEffect = new SacrificeTargetEffect("sacrifice this", source.getControllerId()); + sacrificeEffect.setTargetPointer(new FixedTarget(permanent, game)); + DelayedTriggeredAbility delayedAbility = new AtTheBeginOfNextEndStepDelayedTriggeredAbility(sacrificeEffect); + delayedAbility.setSourceId(source.getSourceId()); + delayedAbility.setControllerId(source.getControllerId()); + delayedAbility.setSourceObject(source.getSourceObject(game), game); + game.addDelayedTriggeredAbility(delayedAbility); + return true; + } + return false; } } diff --git a/Mage.Sets/src/mage/sets/alliances/LordOfTresserhorn.java b/Mage.Sets/src/mage/sets/alliances/LordOfTresserhorn.java index 615bff3951..12dc40a896 100644 --- a/Mage.Sets/src/mage/sets/alliances/LordOfTresserhorn.java +++ b/Mage.Sets/src/mage/sets/alliances/LordOfTresserhorn.java @@ -37,16 +37,13 @@ import mage.abilities.effects.Effect; import mage.abilities.effects.common.DrawCardTargetEffect; import mage.abilities.effects.common.LoseLifeSourceControllerEffect; import mage.abilities.effects.common.RegenerateSourceEffect; -import mage.abilities.effects.common.SacrificeTargetEffect; +import mage.abilities.effects.common.SacrificeControllerEffect; import mage.cards.CardImpl; import mage.constants.CardType; import mage.constants.Rarity; import mage.constants.Zone; import mage.filter.common.FilterControlledCreaturePermanent; -import mage.target.Target; -import mage.target.common.TargetControlledCreaturePermanent; import mage.target.common.TargetOpponent; -import mage.target.targetpointer.SecondTargetPointer; /** * @@ -65,15 +62,13 @@ public class LordOfTresserhorn extends CardImpl { // When Lord of Tresserhorn enters the battlefield, you lose 2 life, you sacrifice two creatures, and target opponent draws two cards. Ability ability = new EntersBattlefieldTriggeredAbility(new LoseLifeSourceControllerEffect(2), false); - ability.addEffect(new SacrificeTargetEffect(", you sacrifice two creatures")); - Target target = new TargetControlledCreaturePermanent(2,2, new FilterControlledCreaturePermanent(), true); - ability.addTarget(target); + ability.addEffect(new SacrificeControllerEffect(new FilterControlledCreaturePermanent("creatures"), 2, "you")); Effect effect = new DrawCardTargetEffect(2); effect.setText(", and target opponent draws two cards"); - effect.setTargetPointer(new SecondTargetPointer()); ability.addEffect(effect); ability.addTarget(new TargetOpponent()); this.addAbility(ability); + // {B}: Regenerate Lord of Tresserhorn. this.addAbility(new SimpleActivatedAbility(Zone.BATTLEFIELD, new RegenerateSourceEffect(), new ManaCostsImpl("{B}"))); } diff --git a/Mage.Sets/src/mage/sets/avacynrestored/ThatcherRevolt.java b/Mage.Sets/src/mage/sets/avacynrestored/ThatcherRevolt.java index 141d60e828..c2fc5802c1 100644 --- a/Mage.Sets/src/mage/sets/avacynrestored/ThatcherRevolt.java +++ b/Mage.Sets/src/mage/sets/avacynrestored/ThatcherRevolt.java @@ -28,9 +28,6 @@ package mage.sets.avacynrestored; import java.util.UUID; -import mage.constants.CardType; -import mage.constants.Outcome; -import mage.constants.Rarity; import mage.MageInt; import mage.ObjectColor; import mage.abilities.Ability; @@ -40,7 +37,11 @@ import mage.abilities.effects.OneShotEffect; import mage.abilities.effects.common.SacrificeTargetEffect; import mage.abilities.keyword.HasteAbility; 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.game.permanent.token.Token; import mage.target.targetpointer.FixedTarget; @@ -54,7 +55,6 @@ public class ThatcherRevolt extends CardImpl { super(ownerId, 158, "Thatcher Revolt", Rarity.COMMON, new CardType[]{CardType.SORCERY}, "{2}{R}"); this.expansionSetCode = "AVR"; - // Put three 1/1 red Human creature tokens with haste onto the battlefield. Sacrifice those tokens at the beginning of the next end step. this.getSpellAbility().addEffect(new ThatcherRevoltEffect()); } @@ -90,14 +90,16 @@ class ThatcherRevoltEffect extends OneShotEffect { for (int i = 0; i < 3; i++) { RedHumanToken token = new RedHumanToken(); token.putOntoBattlefield(1, game, source.getSourceId(), source.getControllerId()); - - SacrificeTargetEffect sacrificeEffect = new SacrificeTargetEffect("sacrifice this token"); - sacrificeEffect.setTargetPointer(new FixedTarget(token.getLastAddedToken())); - DelayedTriggeredAbility delayedAbility = new AtTheBeginOfNextEndStepDelayedTriggeredAbility(sacrificeEffect); - delayedAbility.setSourceId(source.getSourceId()); - delayedAbility.setControllerId(source.getControllerId()); - delayedAbility.setSourceObject(source.getSourceObject(game), game); - game.addDelayedTriggeredAbility(delayedAbility); + Permanent permanent = game.getPermanent(token.getLastAddedToken()); + if (permanent != null) { + SacrificeTargetEffect sacrificeEffect = new SacrificeTargetEffect("sacrifice this token", source.getControllerId()); + sacrificeEffect.setTargetPointer(new FixedTarget(permanent, game)); + DelayedTriggeredAbility delayedAbility = new AtTheBeginOfNextEndStepDelayedTriggeredAbility(sacrificeEffect); + delayedAbility.setSourceId(source.getSourceId()); + delayedAbility.setControllerId(source.getControllerId()); + delayedAbility.setSourceObject(source.getSourceObject(game), game); + game.addDelayedTriggeredAbility(delayedAbility); + } } return true; } diff --git a/Mage.Sets/src/mage/sets/championsofkamigawa/JunkyoBell.java b/Mage.Sets/src/mage/sets/championsofkamigawa/JunkyoBell.java index 7e1c9efce0..da08e4cd46 100644 --- a/Mage.Sets/src/mage/sets/championsofkamigawa/JunkyoBell.java +++ b/Mage.Sets/src/mage/sets/championsofkamigawa/JunkyoBell.java @@ -25,13 +25,9 @@ * authors and should not be interpreted as representing official policies, either expressed * or implied, of BetaSteward_at_googlemail.com. */ - package mage.sets.championsofkamigawa; import java.util.UUID; - -import mage.constants.CardType; -import mage.constants.Rarity; import mage.abilities.Ability; import mage.abilities.DelayedTriggeredAbility; import mage.abilities.common.BeginningOfUpkeepTriggeredAbility; @@ -41,8 +37,10 @@ import mage.abilities.effects.OneShotEffect; import mage.abilities.effects.common.SacrificeTargetEffect; import mage.abilities.effects.common.continuous.BoostTargetEffect; import mage.cards.CardImpl; +import mage.constants.CardType; import mage.constants.Duration; import mage.constants.Outcome; +import mage.constants.Rarity; import mage.constants.TargetController; import mage.filter.common.FilterControlledCreaturePermanent; import mage.game.Game; @@ -58,8 +56,8 @@ public class JunkyoBell extends CardImpl { public JunkyoBell(UUID ownerId) { super(ownerId, 258, "Junkyo Bell", Rarity.RARE, new CardType[]{CardType.ARTIFACT}, "{4}"); this.expansionSetCode = "CHK"; - - // At the beginning of your upkeep, you may have target creature you control get +X/+X until end of turn, + + // At the beginning of your upkeep, you may have target creature you control get +X/+X until end of turn, // where X is the number of creatures you control. If you do, sacrifice that creature at the beginning of the next end step. PermanentsOnBattlefieldCount amount = new PermanentsOnBattlefieldCount(new FilterControlledCreaturePermanent()); Ability ability = new BeginningOfUpkeepTriggeredAbility(new BoostTargetEffect(amount, amount, Duration.EndOfTurn), TargetController.YOU, true); @@ -77,37 +75,36 @@ public class JunkyoBell extends CardImpl { return new JunkyoBell(this); } - -private class JunkyoBellSacrificeEffect extends OneShotEffect { + private class JunkyoBellSacrificeEffect extends OneShotEffect { - public JunkyoBellSacrificeEffect() { - super(Outcome.Sacrifice); - this.staticText = "If you do, sacrifice that creature at the beginning of the next end step"; - } - - public JunkyoBellSacrificeEffect(final JunkyoBellSacrificeEffect effect) { - super(effect); - } - - @Override - public JunkyoBellSacrificeEffect copy() { - return new JunkyoBellSacrificeEffect(this); - } - - @Override - public boolean apply(Game game, Ability source) { - Permanent creature = game.getPermanent(source.getFirstTarget()); - if (creature != null) { - SacrificeTargetEffect sacrificeEffect = new SacrificeTargetEffect("sacrifice boosted " + creature.getName()); - sacrificeEffect.setTargetPointer(new FixedTarget(source.getFirstTarget())); - DelayedTriggeredAbility delayedAbility = new AtTheBeginOfNextEndStepDelayedTriggeredAbility(sacrificeEffect); - delayedAbility.setSourceId(source.getSourceId()); - delayedAbility.setControllerId(source.getControllerId()); - delayedAbility.setSourceObject(source.getSourceObject(game), game); - game.addDelayedTriggeredAbility(delayedAbility); - return true; + public JunkyoBellSacrificeEffect() { + super(Outcome.Sacrifice); + this.staticText = "If you do, sacrifice that creature at the beginning of the next end step"; + } + + public JunkyoBellSacrificeEffect(final JunkyoBellSacrificeEffect effect) { + super(effect); + } + + @Override + public JunkyoBellSacrificeEffect copy() { + return new JunkyoBellSacrificeEffect(this); + } + + @Override + public boolean apply(Game game, Ability source) { + Permanent creature = game.getPermanent(source.getFirstTarget()); + if (creature != null) { + SacrificeTargetEffect sacrificeEffect = new SacrificeTargetEffect("sacrifice boosted " + creature.getName(), source.getControllerId()); + sacrificeEffect.setTargetPointer(new FixedTarget(creature, game)); + DelayedTriggeredAbility delayedAbility = new AtTheBeginOfNextEndStepDelayedTriggeredAbility(sacrificeEffect); + delayedAbility.setSourceId(source.getSourceId()); + delayedAbility.setControllerId(source.getControllerId()); + delayedAbility.setSourceObject(source.getSourceObject(game), game); + game.addDelayedTriggeredAbility(delayedAbility); + return true; + } + return false; } - return false; } - } -} \ No newline at end of file +} diff --git a/Mage.Sets/src/mage/sets/championsofkamigawa/KikiJikiMirrorBreaker.java b/Mage.Sets/src/mage/sets/championsofkamigawa/KikiJikiMirrorBreaker.java index 3d8eac8a7c..2cf5cc1ea2 100644 --- a/Mage.Sets/src/mage/sets/championsofkamigawa/KikiJikiMirrorBreaker.java +++ b/Mage.Sets/src/mage/sets/championsofkamigawa/KikiJikiMirrorBreaker.java @@ -28,10 +28,6 @@ package mage.sets.championsofkamigawa; import java.util.UUID; - -import mage.constants.CardType; -import mage.constants.Rarity; -import mage.constants.Zone; import mage.MageInt; import mage.abilities.Ability; import mage.abilities.DelayedTriggeredAbility; @@ -42,7 +38,10 @@ import mage.abilities.effects.OneShotEffect; import mage.abilities.effects.common.SacrificeTargetEffect; import mage.abilities.keyword.HasteAbility; import mage.cards.CardImpl; +import mage.constants.CardType; import mage.constants.Outcome; +import mage.constants.Rarity; +import mage.constants.Zone; import mage.filter.common.FilterControlledCreaturePermanent; import mage.filter.predicate.Predicates; import mage.filter.predicate.mageobject.SupertypePredicate; @@ -124,8 +123,7 @@ class KikiJikiMirrorBreakerEffect extends OneShotEffect { token.addAbility(HasteAbility.getInstance()); token.putOntoBattlefield(1, game, source.getSourceId(), source.getControllerId()); - SacrificeTargetEffect sacrificeEffect = new SacrificeTargetEffect(); - sacrificeEffect.setText("Sacrifice the token at the beginning of the next end step"); + SacrificeTargetEffect sacrificeEffect = new SacrificeTargetEffect("Sacrifice the token at the beginning of the next end step", source.getControllerId()); sacrificeEffect.setTargetPointer(new FixedTarget(token.getLastAddedToken())); DelayedTriggeredAbility delayedAbility = new AtTheBeginOfNextEndStepDelayedTriggeredAbility(sacrificeEffect); delayedAbility.setSourceId(source.getSourceId()); diff --git a/Mage.Sets/src/mage/sets/championsofkamigawa/OniPossession.java b/Mage.Sets/src/mage/sets/championsofkamigawa/OniPossession.java index bc1c23d49e..44fd1be0eb 100644 --- a/Mage.Sets/src/mage/sets/championsofkamigawa/OniPossession.java +++ b/Mage.Sets/src/mage/sets/championsofkamigawa/OniPossession.java @@ -30,22 +30,26 @@ package mage.sets.championsofkamigawa; import java.util.ArrayList; import java.util.List; import java.util.UUID; - -import mage.constants.*; import mage.abilities.Ability; import mage.abilities.common.BeginningOfUpkeepTriggeredAbility; import mage.abilities.common.SimpleStaticAbility; import mage.abilities.effects.common.AttachEffect; -import mage.abilities.effects.common.SacrificeTargetEffect; +import mage.abilities.effects.common.SacrificeControllerEffect; import mage.abilities.effects.common.continuous.BoostEnchantedEffect; import mage.abilities.effects.common.continuous.GainAbilityAttachedEffect; import mage.abilities.effects.common.continuous.SetCardSubtypeAttachedEffect; import mage.abilities.keyword.EnchantAbility; import mage.abilities.keyword.TrampleAbility; import mage.cards.CardImpl; +import mage.constants.AttachmentType; +import mage.constants.CardType; +import mage.constants.Duration; +import mage.constants.Outcome; +import mage.constants.Rarity; +import mage.constants.TargetController; +import mage.constants.Zone; import mage.filter.common.FilterControlledCreaturePermanent; import mage.target.TargetPermanent; -import mage.target.common.TargetControlledCreaturePermanent; import mage.target.common.TargetCreaturePermanent; /** @@ -54,7 +58,8 @@ import mage.target.common.TargetCreaturePermanent; */ public class OniPossession extends CardImpl { - private static final List setSubtypes = new ArrayList(); + private static final List setSubtypes = new ArrayList<>(); + static { setSubtypes.add("Demon"); setSubtypes.add("Spirit"); @@ -67,13 +72,14 @@ public class OniPossession extends CardImpl { // Enchant creature TargetPermanent auraTarget = new TargetCreaturePermanent(); - this.getSpellAbility().addTarget(auraTarget); - this.getSpellAbility().addEffect(new AttachEffect(Outcome.BoostCreature)); - Ability ability = new EnchantAbility(auraTarget.getTargetName()); - this.addAbility(ability); + this.getSpellAbility().addTarget(auraTarget); + this.getSpellAbility().addEffect(new AttachEffect(Outcome.BoostCreature)); + Ability ability = new EnchantAbility(auraTarget.getTargetName()); + this.addAbility(ability); + // At the beginning of your upkeep, sacrifice a creature. - Ability ability2 = new BeginningOfUpkeepTriggeredAbility(new SacrificeTargetEffect("sacrifice a creature"), TargetController.YOU, false); - ability2.addTarget(new TargetControlledCreaturePermanent(1,1, new FilterControlledCreaturePermanent(),false)); + Ability ability2 = new BeginningOfUpkeepTriggeredAbility( + new SacrificeControllerEffect(new FilterControlledCreaturePermanent(), 1, ""), TargetController.YOU, false); this.addAbility(ability2); // Enchanted creature gets +3/+3 and has trample. this.addAbility(new SimpleStaticAbility(Zone.BATTLEFIELD, new BoostEnchantedEffect(3, 3, Duration.WhileOnBattlefield))); diff --git a/Mage.Sets/src/mage/sets/championsofkamigawa/ThroughTheBreach.java b/Mage.Sets/src/mage/sets/championsofkamigawa/ThroughTheBreach.java index 86980d0f77..bf4e4d5139 100644 --- a/Mage.Sets/src/mage/sets/championsofkamigawa/ThroughTheBreach.java +++ b/Mage.Sets/src/mage/sets/championsofkamigawa/ThroughTheBreach.java @@ -63,7 +63,6 @@ public class ThroughTheBreach extends CardImpl { this.expansionSetCode = "CHK"; this.subtype.add("Arcane"); - // You may put a creature card from your hand onto the battlefield. That creature gains haste. Sacrifice that creature at the beginning of the next end step. this.getSpellAbility().addEffect(new ThroughTheBreachEffect()); // Splice onto Arcane {2}{R}{R} @@ -81,7 +80,7 @@ public class ThroughTheBreach extends CardImpl { } class ThroughTheBreachEffect extends OneShotEffect { - + private static final String choiceText = "Put a creature card from your hand onto the battlefield?"; public ThroughTheBreachEffect() { @@ -111,10 +110,10 @@ class ThroughTheBreachEffect extends OneShotEffect { Permanent permanent = game.getPermanent(card.getId()); if (permanent != null) { ContinuousEffect effect = new GainAbilityTargetEffect(HasteAbility.getInstance(), Duration.Custom); - effect.setTargetPointer(new FixedTarget(permanent.getId())); + effect.setTargetPointer(new FixedTarget(permanent, game)); game.addEffect(effect, source); - SacrificeTargetEffect sacrificeEffect = new SacrificeTargetEffect("sacrifice " + card.getName()); - sacrificeEffect.setTargetPointer(new FixedTarget(card.getId())); + SacrificeTargetEffect sacrificeEffect = new SacrificeTargetEffect("sacrifice " + card.getName(), source.getControllerId()); + sacrificeEffect.setTargetPointer(new FixedTarget(permanent, game)); DelayedTriggeredAbility delayedAbility = new AtTheBeginOfNextEndStepDelayedTriggeredAbility(sacrificeEffect); delayedAbility.setSourceId(source.getSourceId()); delayedAbility.setControllerId(source.getControllerId()); diff --git a/Mage.Sets/src/mage/sets/commander2014/FeldonOfTheThirdPath.java b/Mage.Sets/src/mage/sets/commander2014/FeldonOfTheThirdPath.java index ad667be3a2..a3c53ae6d7 100644 --- a/Mage.Sets/src/mage/sets/commander2014/FeldonOfTheThirdPath.java +++ b/Mage.Sets/src/mage/sets/commander2014/FeldonOfTheThirdPath.java @@ -46,6 +46,7 @@ import mage.constants.Rarity; import mage.constants.Zone; import mage.filter.common.FilterCreatureCard; import mage.game.Game; +import mage.game.permanent.Permanent; import mage.game.permanent.token.EmptyToken; import mage.target.common.TargetCardInYourGraveyard; import mage.target.targetpointer.FixedTarget; @@ -113,15 +114,16 @@ class FeldonOfTheThirdPathEffect extends OneShotEffect { } token.addAbility(HasteAbility.getInstance()); token.putOntoBattlefield(1, game, source.getSourceId(), source.getControllerId()); - - SacrificeTargetEffect sacrificeEffect = new SacrificeTargetEffect(); - sacrificeEffect.setText("Sacrifice the token at the beginning of the next end step"); - sacrificeEffect.setTargetPointer(new FixedTarget(token.getLastAddedToken())); - DelayedTriggeredAbility delayedAbility = new AtTheBeginOfNextEndStepDelayedTriggeredAbility(sacrificeEffect); - delayedAbility.setSourceId(source.getSourceId()); - delayedAbility.setControllerId(source.getControllerId()); - delayedAbility.setSourceObject(source.getSourceObject(game), game); - game.addDelayedTriggeredAbility(delayedAbility); + Permanent permanent = game.getPermanent(token.getLastAddedToken()); + if (permanent != null) { + SacrificeTargetEffect sacrificeEffect = new SacrificeTargetEffect("Sacrifice the token at the beginning of the next end step", source.getControllerId()); + sacrificeEffect.setTargetPointer(new FixedTarget(permanent, game)); + DelayedTriggeredAbility delayedAbility = new AtTheBeginOfNextEndStepDelayedTriggeredAbility(sacrificeEffect); + delayedAbility.setSourceId(source.getSourceId()); + delayedAbility.setControllerId(source.getControllerId()); + delayedAbility.setSourceObject(source.getSourceObject(game), game); + game.addDelayedTriggeredAbility(delayedAbility); + } return true; } diff --git a/Mage.Sets/src/mage/sets/commander2014/WakeTheDead.java b/Mage.Sets/src/mage/sets/commander2014/WakeTheDead.java index f196efa60c..fc1c258ea1 100644 --- a/Mage.Sets/src/mage/sets/commander2014/WakeTheDead.java +++ b/Mage.Sets/src/mage/sets/commander2014/WakeTheDead.java @@ -33,7 +33,6 @@ import mage.abilities.DelayedTriggeredAbility; import mage.abilities.SpellAbility; import mage.abilities.common.SimpleStaticAbility; import mage.abilities.common.delayed.AtTheBeginOfNextEndStepDelayedTriggeredAbility; -import mage.abilities.dynamicvalue.common.GetXValue; import mage.abilities.effects.ContinuousRuleModifyingEffectImpl; import mage.abilities.effects.Effect; import mage.abilities.effects.OneShotEffect; @@ -64,7 +63,6 @@ public class WakeTheDead extends CardImpl { super(ownerId, 31, "Wake the Dead", Rarity.RARE, new CardType[]{CardType.INSTANT}, "{X}{B}{B}"); this.expansionSetCode = "C14"; - // Cast Wake the Dead only during combat on an opponent's turn. Ability ability = new SimpleStaticAbility(Zone.ALL, new WakeTheDeadEffect()); ability.setRuleAtTheTop(true); @@ -72,7 +70,7 @@ public class WakeTheDead extends CardImpl { // Return X target creature cards from your graveyard to the battlefield. Sacrifice those creatures at the beginning of the next end step. this.getSpellAbility().addEffect(new WakeTheDeadReturnFromGraveyardToBattlefieldTargetEffect()); - this.getSpellAbility().addTarget(new TargetCardInYourGraveyard(0,Integer.MAX_VALUE, new FilterCreatureCard("creature cards from your graveyard"))); + this.getSpellAbility().addTarget(new TargetCardInYourGraveyard(0, Integer.MAX_VALUE, new FilterCreatureCard("creature cards from your graveyard"))); } @Override @@ -80,7 +78,7 @@ public class WakeTheDead extends CardImpl { if (ability instanceof SpellAbility) { int xValue = ability.getManaCostsToPay().getX(); ability.getTargets().clear(); - ability.addTarget(new TargetCardInYourGraveyard(xValue,xValue, new FilterCreatureCard("creature cards from your graveyard"))); + ability.addTarget(new TargetCardInYourGraveyard(xValue, xValue, new FilterCreatureCard("creature cards from your graveyard"))); } } @@ -159,8 +157,8 @@ class WakeTheDeadReturnFromGraveyardToBattlefieldTargetEffect extends OneShotEff Permanent permanent = game.getPermanent(source.getSourceId()); if (permanent != null) { permanent.changeControllerId(source.getControllerId(), game); - Effect effect = new SacrificeTargetEffect("Sacrifice those creatures at the beginning of the next end step"); - effect.setTargetPointer(new FixedTarget(permanent.getId())); + Effect effect = new SacrificeTargetEffect("Sacrifice those creatures at the beginning of the next end step", source.getControllerId()); + effect.setTargetPointer(new FixedTarget(permanent, game)); DelayedTriggeredAbility delayedAbility = new AtTheBeginOfNextEndStepDelayedTriggeredAbility(effect); delayedAbility.setSourceId(source.getSourceId()); delayedAbility.setControllerId(source.getControllerId()); diff --git a/Mage.Sets/src/mage/sets/eventide/AshlingTheExtinguisher.java b/Mage.Sets/src/mage/sets/eventide/AshlingTheExtinguisher.java index 3b525f2212..e8fbba42e5 100644 --- a/Mage.Sets/src/mage/sets/eventide/AshlingTheExtinguisher.java +++ b/Mage.Sets/src/mage/sets/eventide/AshlingTheExtinguisher.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.eventide; import java.util.UUID; @@ -51,19 +50,20 @@ import mage.target.common.TargetCreaturePermanent; */ public class AshlingTheExtinguisher extends CardImpl { - public AshlingTheExtinguisher (UUID ownerId) { + public AshlingTheExtinguisher(UUID ownerId) { super(ownerId, 33, "Ashling, the Extinguisher", Rarity.RARE, new CardType[]{CardType.CREATURE}, "{2}{B}{B}"); this.expansionSetCode = "EVE"; this.supertype.add("Legendary"); this.subtype.add("Elemental"); this.subtype.add("Shaman"); + // Whenever Ashling, the Extinguisher deals combat damage to a player, choose target creature that player controls. He or she sacrifices that creature. this.power = new MageInt(4); this.toughness = new MageInt(4); this.addAbility(new AshlingTheExtinguisherTriggeredAbility()); } - public AshlingTheExtinguisher (final AshlingTheExtinguisher card) { + public AshlingTheExtinguisher(final AshlingTheExtinguisher card) { super(card); } @@ -75,6 +75,7 @@ public class AshlingTheExtinguisher extends CardImpl { } class AshlingTheExtinguisherTriggeredAbility extends TriggeredAbilityImpl { + public AshlingTheExtinguisherTriggeredAbility() { super(Zone.BATTLEFIELD, new SacrificeTargetEffect()); this.addTarget(new TargetCreaturePermanent()); @@ -115,4 +116,4 @@ class AshlingTheExtinguisherTriggeredAbility extends TriggeredAbilityImpl { public String getRule() { return "Whenever {this} deals combat damage to a player, choose target creature that player controls. He or she sacrifices that creature."; } -} \ No newline at end of file +} diff --git a/Mage.Sets/src/mage/sets/invasion/Dredge.java b/Mage.Sets/src/mage/sets/invasion/Dredge.java index 9f9d27e9ce..9d0d8a0f14 100644 --- a/Mage.Sets/src/mage/sets/invasion/Dredge.java +++ b/Mage.Sets/src/mage/sets/invasion/Dredge.java @@ -30,14 +30,12 @@ package mage.sets.invasion; import java.util.UUID; import mage.abilities.effects.common.DrawCardSourceControllerEffect; import mage.abilities.effects.common.SacrificeControllerEffect; -import mage.abilities.effects.common.SacrificeTargetEffect; import mage.cards.CardImpl; import mage.constants.CardType; import mage.constants.Rarity; import mage.filter.FilterPermanent; import mage.filter.predicate.Predicates; import mage.filter.predicate.mageobject.CardTypePredicate; -import mage.target.TargetPermanent; /** * @@ -46,18 +44,18 @@ import mage.target.TargetPermanent; public class Dredge extends CardImpl { private static final FilterPermanent filter = new FilterPermanent("a creature or land"); - + static { filter.add(Predicates.or(new CardTypePredicate(CardType.CREATURE), new CardTypePredicate(CardType.LAND))); } - + public Dredge(UUID ownerId) { super(ownerId, 103, "Dredge", Rarity.UNCOMMON, new CardType[]{CardType.INSTANT}, "{B}"); this.expansionSetCode = "INV"; // Sacrifice a creature or land. this.getSpellAbility().addEffect(new SacrificeControllerEffect(filter, 1, "")); - + // Draw a card. this.getSpellAbility().addEffect(new DrawCardSourceControllerEffect(1)); } diff --git a/Mage.Sets/src/mage/sets/legions/GoblinFirebug.java b/Mage.Sets/src/mage/sets/legions/GoblinFirebug.java index 907f6577eb..67a12a03a7 100644 --- a/Mage.Sets/src/mage/sets/legions/GoblinFirebug.java +++ b/Mage.Sets/src/mage/sets/legions/GoblinFirebug.java @@ -29,15 +29,12 @@ package mage.sets.legions; import java.util.UUID; import mage.MageInt; -import mage.abilities.Ability; import mage.abilities.common.LeavesBattlefieldTriggeredAbility; -import mage.abilities.effects.Effect; -import mage.abilities.effects.common.SacrificeTargetEffect; +import mage.abilities.effects.common.SacrificeControllerEffect; import mage.cards.CardImpl; import mage.constants.CardType; import mage.constants.Rarity; -import mage.filter.common.FilterControlledLandPermanent; -import mage.target.common.TargetControlledPermanent; +import mage.filter.common.FilterLandPermanent; /** * @@ -53,11 +50,7 @@ public class GoblinFirebug extends CardImpl { this.toughness = new MageInt(2); // When Goblin Firebug leaves the battlefield, sacrifice a land. - Effect effect = new SacrificeTargetEffect(); - effect.setText("sacrifice a land"); - Ability ability = new LeavesBattlefieldTriggeredAbility(effect, false); - ability.addTarget(new TargetControlledPermanent(new FilterControlledLandPermanent())); - this.addAbility(ability); + this.addAbility(new LeavesBattlefieldTriggeredAbility(new SacrificeControllerEffect(new FilterLandPermanent(), 1, ""), false)); } public GoblinFirebug(final GoblinFirebug card) { diff --git a/Mage.Sets/src/mage/sets/lorwyn/IncandescentSoulstoke.java b/Mage.Sets/src/mage/sets/lorwyn/IncandescentSoulstoke.java index 1d2c147476..f3ceefded0 100644 --- a/Mage.Sets/src/mage/sets/lorwyn/IncandescentSoulstoke.java +++ b/Mage.Sets/src/mage/sets/lorwyn/IncandescentSoulstoke.java @@ -70,7 +70,7 @@ public class IncandescentSoulstoke extends CardImpl { static { filter.add(new SubtypePredicate("Elemental")); } - + public IncandescentSoulstoke(UUID ownerId) { super(ownerId, 178, "Incandescent Soulstoke", Rarity.RARE, new CardType[]{CardType.CREATURE}, "{2}{R}"); this.expansionSetCode = "LRW"; @@ -81,13 +81,12 @@ public class IncandescentSoulstoke extends CardImpl { // Other Elemental creatures you control get +1/+1. this.addAbility(new SimpleStaticAbility(Zone.BATTLEFIELD, new BoostControlledEffect(1, 1, Duration.WhileOnBattlefield, filter, true))); - - + // {1}{R}, {T}: You may put an Elemental creature card from your hand onto the battlefield. That creature gains haste until end of turn. Sacrifice it at the beginning of the next end step. Ability ability = new SimpleActivatedAbility(Zone.BATTLEFIELD, new IncandescentSoulstokeEffect(), new ManaCostsImpl<>("{1}{R}")); ability.addCost(new TapSourceCost()); this.addAbility(ability); - + } public IncandescentSoulstoke(final IncandescentSoulstoke card) { @@ -101,7 +100,7 @@ public class IncandescentSoulstoke extends CardImpl { } class IncandescentSoulstokeEffect extends OneShotEffect { - + private static final String choiceText = "Put an Elemental creature card from your hand onto the battlefield?"; public IncandescentSoulstokeEffect() { @@ -133,10 +132,10 @@ class IncandescentSoulstokeEffect extends OneShotEffect { Permanent permanent = game.getPermanent(card.getId()); if (permanent != null) { ContinuousEffect effect = new GainAbilityTargetEffect(HasteAbility.getInstance(), Duration.Custom); - effect.setTargetPointer(new FixedTarget(permanent.getId())); + effect.setTargetPointer(new FixedTarget(permanent, game)); game.addEffect(effect, source); - SacrificeTargetEffect sacrificeEffect = new SacrificeTargetEffect("sacrifice " + card.getName()); - sacrificeEffect.setTargetPointer(new FixedTarget(card.getId())); + SacrificeTargetEffect sacrificeEffect = new SacrificeTargetEffect("sacrifice " + card.getName(), source.getControllerId()); + sacrificeEffect.setTargetPointer(new FixedTarget(permanent, game)); DelayedTriggeredAbility delayedAbility = new AtTheBeginOfNextEndStepDelayedTriggeredAbility(sacrificeEffect); delayedAbility.setSourceId(source.getSourceId()); delayedAbility.setControllerId(source.getControllerId()); diff --git a/Mage.Sets/src/mage/sets/magic2014/ShadowbornDemon.java b/Mage.Sets/src/mage/sets/magic2014/ShadowbornDemon.java index 08eda6473f..c81ad6839b 100644 --- a/Mage.Sets/src/mage/sets/magic2014/ShadowbornDemon.java +++ b/Mage.Sets/src/mage/sets/magic2014/ShadowbornDemon.java @@ -30,14 +30,13 @@ package mage.sets.magic2014; import java.util.UUID; import mage.MageInt; import mage.abilities.Ability; -import mage.abilities.TriggeredAbility; import mage.abilities.common.BeginningOfUpkeepTriggeredAbility; import mage.abilities.common.EntersBattlefieldTriggeredAbility; import mage.abilities.condition.Condition; import mage.abilities.condition.InvertCondition; import mage.abilities.decorator.ConditionalTriggeredAbility; import mage.abilities.effects.common.DestroyTargetEffect; -import mage.abilities.effects.common.SacrificeTargetEffect; +import mage.abilities.effects.common.SacrificeControllerEffect; import mage.abilities.keyword.FlyingAbility; import mage.cards.CardImpl; import mage.constants.CardType; @@ -50,7 +49,6 @@ import mage.filter.predicate.mageobject.SubtypePredicate; import mage.game.Game; import mage.players.Player; import mage.target.Target; -import mage.target.common.TargetControlledCreaturePermanent; import mage.target.common.TargetCreaturePermanent; /** @@ -60,6 +58,7 @@ import mage.target.common.TargetCreaturePermanent; public class ShadowbornDemon extends CardImpl { private static final FilterCreaturePermanent filter = new FilterCreaturePermanent("non-Demon creature"); + static { filter.add(Predicates.not(new SubtypePredicate("Demon"))); } @@ -75,17 +74,14 @@ public class ShadowbornDemon extends CardImpl { // Flying this.addAbility(FlyingAbility.getInstance()); // When Shadowborn Demon enters the battlefield, destroy target non-Demon creature. - Ability ability = new EntersBattlefieldTriggeredAbility(new DestroyTargetEffect(),false); + Ability ability = new EntersBattlefieldTriggeredAbility(new DestroyTargetEffect(), false); Target target = new TargetCreaturePermanent(filter); ability.addTarget(target); this.addAbility(ability); + // At the beginning of your upkeep, if there are fewer than six creature cards in your graveyard, sacrifice a creature. - TriggeredAbility triggeredAbility = new BeginningOfUpkeepTriggeredAbility(new SacrificeTargetEffect(), TargetController.YOU, false); - target = new TargetControlledCreaturePermanent(); - target.setNotTarget(false); - triggeredAbility.addTarget(target); this.addAbility(new ConditionalTriggeredAbility( - triggeredAbility, + new BeginningOfUpkeepTriggeredAbility(new SacrificeControllerEffect(new FilterCreaturePermanent(), 1, ""), TargetController.YOU, false), new InvertCondition(new CreatureCardsInControllerGraveCondition(6)), "At the beginning of your upkeep, if there are fewer than six creature cards in your graveyard, sacrifice a creature")); @@ -102,6 +98,7 @@ public class ShadowbornDemon extends CardImpl { } class CreatureCardsInControllerGraveCondition implements Condition { + private int value; public CreatureCardsInControllerGraveCondition(int value) { @@ -111,10 +108,9 @@ class CreatureCardsInControllerGraveCondition implements Condition { @Override public boolean apply(Game game, Ability source) { Player p = game.getPlayer(source.getControllerId()); - if (p != null && p.getGraveyard().count(new FilterCreatureCard(), game) >= value) - { - return true; + if (p != null && p.getGraveyard().count(new FilterCreatureCard(), game) >= value) { + return true; } return false; } -} \ No newline at end of file +} diff --git a/Mage.Sets/src/mage/sets/masterseditioniv/FoulSpirit.java b/Mage.Sets/src/mage/sets/masterseditioniv/FoulSpirit.java index bf83c7d77a..4a00e1cc95 100644 --- a/Mage.Sets/src/mage/sets/masterseditioniv/FoulSpirit.java +++ b/Mage.Sets/src/mage/sets/masterseditioniv/FoulSpirit.java @@ -29,16 +29,13 @@ package mage.sets.masterseditioniv; import java.util.UUID; import mage.MageInt; -import mage.abilities.Ability; import mage.abilities.common.EntersBattlefieldTriggeredAbility; -import mage.abilities.effects.Effect; -import mage.abilities.effects.common.SacrificeTargetEffect; +import mage.abilities.effects.common.SacrificeControllerEffect; import mage.abilities.keyword.FlyingAbility; import mage.cards.CardImpl; import mage.constants.CardType; import mage.constants.Rarity; -import mage.filter.common.FilterControlledLandPermanent; -import mage.target.common.TargetControlledPermanent; +import mage.filter.common.FilterLandPermanent; /** * @@ -55,13 +52,9 @@ public class FoulSpirit extends CardImpl { // Flying this.addAbility(FlyingAbility.getInstance()); - + // When Foul Spirit enters the battlefield, sacrifice a land. - Effect effect = new SacrificeTargetEffect(); - effect.setText("sacrifice a land"); - Ability ability = new EntersBattlefieldTriggeredAbility(effect, false); - ability.addTarget(new TargetControlledPermanent(new FilterControlledLandPermanent())); - this.addAbility(ability); + this.addAbility(new EntersBattlefieldTriggeredAbility(new SacrificeControllerEffect(new FilterLandPermanent(), 1, ""), false)); } public FoulSpirit(final FoulSpirit card) { diff --git a/Mage.Sets/src/mage/sets/planarchaos/FatalFrenzy.java b/Mage.Sets/src/mage/sets/planarchaos/FatalFrenzy.java index 43ba60a904..0bbef4cfb3 100644 --- a/Mage.Sets/src/mage/sets/planarchaos/FatalFrenzy.java +++ b/Mage.Sets/src/mage/sets/planarchaos/FatalFrenzy.java @@ -28,10 +28,6 @@ package mage.sets.planarchaos; import java.util.UUID; -import mage.constants.CardType; -import mage.constants.Duration; -import mage.constants.Outcome; -import mage.constants.Rarity; import mage.abilities.Ability; import mage.abilities.DelayedTriggeredAbility; import mage.abilities.common.delayed.AtTheBeginOfNextEndStepDelayedTriggeredAbility; @@ -43,7 +39,12 @@ import mage.abilities.effects.common.continuous.BoostTargetEffect; import mage.abilities.effects.common.continuous.GainAbilityTargetEffect; import mage.abilities.keyword.TrampleAbility; import mage.cards.CardImpl; +import mage.constants.CardType; +import mage.constants.Duration; +import mage.constants.Outcome; +import mage.constants.Rarity; import mage.game.Game; +import mage.game.permanent.Permanent; import mage.target.common.TargetControlledCreaturePermanent; import mage.target.targetpointer.FixedTarget; @@ -57,7 +58,6 @@ public class FatalFrenzy extends CardImpl { super(ownerId, 98, "Fatal Frenzy", Rarity.RARE, new CardType[]{CardType.INSTANT}, "{2}{R}"); this.expansionSetCode = "PLC"; - // Until end of turn, target creature you control gains trample and gets +X/+0, where X is its power. Sacrifice it at the beginning of the next end step. this.getSpellAbility().addEffect(new GainAbilityTargetEffect(TrampleAbility.getInstance(), Duration.EndOfTurn)); this.getSpellAbility().addEffect(new BoostTargetEffect(new TargetPermanentPowerCount(), new StaticValue(0), Duration.EndOfTurn, true)); @@ -94,13 +94,16 @@ class FatalFrenzyEffect extends OneShotEffect { @Override public boolean apply(Game game, Ability source) { - SacrificeTargetEffect sacrificeEffect = new SacrificeTargetEffect("sacrifice this"); - sacrificeEffect.setTargetPointer(new FixedTarget(source.getFirstTarget())); - DelayedTriggeredAbility delayedAbility = new AtTheBeginOfNextEndStepDelayedTriggeredAbility(sacrificeEffect); - delayedAbility.setSourceId(source.getSourceId()); - delayedAbility.setControllerId(source.getControllerId()); - delayedAbility.setSourceObject(source.getSourceObject(game), game); - game.addDelayedTriggeredAbility(delayedAbility); + Permanent targetCreature = game.getPermanent(source.getFirstTarget()); + if (targetCreature != null) { + SacrificeTargetEffect sacrificeEffect = new SacrificeTargetEffect("sacrifice this", source.getControllerId()); + sacrificeEffect.setTargetPointer(new FixedTarget(targetCreature, game)); + DelayedTriggeredAbility delayedAbility = new AtTheBeginOfNextEndStepDelayedTriggeredAbility(sacrificeEffect); + delayedAbility.setSourceId(source.getSourceId()); + delayedAbility.setControllerId(source.getControllerId()); + delayedAbility.setSourceObject(source.getSourceObject(game), game); + game.addDelayedTriggeredAbility(delayedAbility); + } return true; } } diff --git a/Mage.Sets/src/mage/sets/planarchaos/RealityAcid.java b/Mage.Sets/src/mage/sets/planarchaos/RealityAcid.java index 425d94127d..ac39868c19 100644 --- a/Mage.Sets/src/mage/sets/planarchaos/RealityAcid.java +++ b/Mage.Sets/src/mage/sets/planarchaos/RealityAcid.java @@ -76,8 +76,7 @@ public class RealityAcid extends CardImpl { this.addAbility(new VanishingSacrificeAbility()); // When Reality Acid leaves the battlefield, enchanted permanent's controller sacrifices it. - Effect effect = new SacrificeTargetEffect(); - effect.setText("enchanted permanent's controller sacrifices it"); + Effect effect = new SacrificeTargetEffect("enchanted permanent's controller sacrifices it"); this.addAbility(new RealityAcidTriggeredAbility(effect, false)); } diff --git a/Mage.Sets/src/mage/sets/riseoftheeldrazi/DemonicAppetite.java b/Mage.Sets/src/mage/sets/riseoftheeldrazi/DemonicAppetite.java index d467a009fb..efaaf2c58a 100644 --- a/Mage.Sets/src/mage/sets/riseoftheeldrazi/DemonicAppetite.java +++ b/Mage.Sets/src/mage/sets/riseoftheeldrazi/DemonicAppetite.java @@ -25,20 +25,25 @@ * authors and should not be interpreted as representing official policies, either expressed * or implied, of BetaSteward_at_googlemail.com. */ - package mage.sets.riseoftheeldrazi; import java.util.UUID; - -import mage.constants.*; import mage.abilities.Ability; import mage.abilities.common.BeginningOfUpkeepTriggeredAbility; import mage.abilities.common.SimpleStaticAbility; import mage.abilities.effects.common.AttachEffect; +import mage.abilities.effects.common.SacrificeControllerEffect; import mage.abilities.effects.common.SacrificeTargetEffect; 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.TargetController; +import mage.constants.Zone; +import mage.filter.common.FilterCreaturePermanent; import mage.target.TargetPermanent; import mage.target.common.TargetControlledCreaturePermanent; @@ -48,29 +53,27 @@ import mage.target.common.TargetControlledCreaturePermanent; */ public class DemonicAppetite extends CardImpl { - public DemonicAppetite (UUID ownerId) { + public DemonicAppetite(UUID ownerId) { super(ownerId, 106, "Demonic Appetite", Rarity.COMMON, new CardType[]{CardType.ENCHANTMENT}, "{B}"); this.expansionSetCode = "ROE"; this.subtype.add("Aura"); - + // Enchant creature you control TargetPermanent auraTarget = new TargetControlledCreaturePermanent(); this.getSpellAbility().addTarget(auraTarget); this.getSpellAbility().addEffect(new AttachEffect(Outcome.BoostCreature)); - Ability ability = new EnchantAbility(auraTarget.getTargetName()); this.addAbility(ability); + + // Enchanted creature gets +3/+3. this.addAbility(new SimpleStaticAbility(Zone.BATTLEFIELD, new BoostEnchantedEffect(3, 3, Duration.WhileOnBattlefield))); - ability = new BeginningOfUpkeepTriggeredAbility( - new DemonicAppetiteEffect(), - TargetController.YOU, - false); - ability.addTarget(new TargetControlledCreaturePermanent()); - this.addAbility(ability); + // At the beginning of your upkeep, sacrifice a creature. + this.addAbility(new BeginningOfUpkeepTriggeredAbility(new SacrificeControllerEffect(new FilterCreaturePermanent("a creature"), 1, ""), + TargetController.YOU, false)); } - public DemonicAppetite (final DemonicAppetite card) { + public DemonicAppetite(final DemonicAppetite card) { super(card); } @@ -80,16 +83,16 @@ public class DemonicAppetite extends CardImpl { } } - class DemonicAppetiteEffect extends SacrificeTargetEffect { +class DemonicAppetiteEffect extends SacrificeTargetEffect { - DemonicAppetiteEffect() { - super(); - staticText = "sacrifice a creature"; - } + DemonicAppetiteEffect() { + super(); + staticText = "sacrifice a creature"; + } - @Override - public DemonicAppetiteEffect copy() { - return new DemonicAppetiteEffect(); - } + @Override + public DemonicAppetiteEffect copy() { + return new DemonicAppetiteEffect(); + } -} +} diff --git a/Mage.Sets/src/mage/sets/saviorsofkamigawa/FootstepsOfTheGoryo.java b/Mage.Sets/src/mage/sets/saviorsofkamigawa/FootstepsOfTheGoryo.java index d558731be7..1e3be38179 100644 --- a/Mage.Sets/src/mage/sets/saviorsofkamigawa/FootstepsOfTheGoryo.java +++ b/Mage.Sets/src/mage/sets/saviorsofkamigawa/FootstepsOfTheGoryo.java @@ -32,15 +32,9 @@ import java.util.UUID; import mage.abilities.Ability; import mage.abilities.DelayedTriggeredAbility; import mage.abilities.common.delayed.AtTheBeginOfNextEndStepDelayedTriggeredAbility; -import mage.abilities.effects.ContinuousEffect; import mage.abilities.effects.Effect; import mage.abilities.effects.OneShotEffect; -import mage.abilities.effects.common.CreateDelayedTriggeredAbilityEffect; -import mage.abilities.effects.common.ExileTargetEffect; -import mage.abilities.effects.common.ReturnFromGraveyardToBattlefieldTargetEffect; import mage.abilities.effects.common.SacrificeTargetEffect; -import mage.abilities.effects.common.continuous.GainAbilityTargetEffect; -import mage.abilities.keyword.HasteAbility; import mage.cards.Card; import mage.cards.CardImpl; import mage.constants.*; @@ -62,7 +56,6 @@ public class FootstepsOfTheGoryo extends CardImpl { this.expansionSetCode = "SOK"; this.subtype.add("Arcane"); - // Return target creature card from your graveyard to the battlefield. Sacrifice that creature at the beginning of the next end step. this.getSpellAbility().addEffect(new FootstepsOfTheGoryoEffect()); this.getSpellAbility().addTarget(new TargetCardInYourGraveyard(new FilterCreatureCard())); @@ -104,8 +97,8 @@ class FootstepsOfTheGoryoEffect extends OneShotEffect { Permanent permanent = game.getPermanent(card.getId()); if (permanent != null) { // Sacrifice it at end of turn - Effect sacrificeEffect = new SacrificeTargetEffect("Sacrifice that creature at the beginning of next end step"); - sacrificeEffect.setTargetPointer(new FixedTarget(card.getId())); + Effect sacrificeEffect = new SacrificeTargetEffect("Sacrifice that creature at the beginning of next end step", source.getControllerId()); + sacrificeEffect.setTargetPointer(new FixedTarget(permanent, game)); DelayedTriggeredAbility delayedAbility = new AtTheBeginOfNextEndStepDelayedTriggeredAbility(sacrificeEffect); delayedAbility.setSourceId(source.getSourceId()); delayedAbility.setControllerId(source.getControllerId()); diff --git a/Mage.Sets/src/mage/sets/saviorsofkamigawa/WineOfBloodAndIron.java b/Mage.Sets/src/mage/sets/saviorsofkamigawa/WineOfBloodAndIron.java index 2a831a03a0..bfe6007c45 100644 --- a/Mage.Sets/src/mage/sets/saviorsofkamigawa/WineOfBloodAndIron.java +++ b/Mage.Sets/src/mage/sets/saviorsofkamigawa/WineOfBloodAndIron.java @@ -30,23 +30,19 @@ package mage.sets.saviorsofkamigawa; import java.util.UUID; import mage.constants.CardType; import mage.constants.Duration; -import mage.constants.Outcome; import mage.constants.Rarity; import mage.constants.Zone; -import mage.abilities.Ability; -import mage.abilities.DelayedTriggeredAbility; import mage.abilities.common.SimpleActivatedAbility; import mage.abilities.common.delayed.AtTheBeginOfNextEndStepDelayedTriggeredAbility; import mage.abilities.costs.mana.GenericManaCost; import mage.abilities.dynamicvalue.common.StaticValue; import mage.abilities.dynamicvalue.common.TargetPermanentPowerCount; -import mage.abilities.effects.OneShotEffect; -import mage.abilities.effects.common.SacrificeTargetEffect; +import mage.abilities.effects.Effect; +import mage.abilities.effects.common.CreateDelayedTriggeredAbilityEffect; +import mage.abilities.effects.common.SacrificeSourceEffect; import mage.abilities.effects.common.continuous.BoostTargetEffect; import mage.cards.CardImpl; -import mage.game.Game; import mage.target.common.TargetCreaturePermanent; -import mage.target.targetpointer.FixedTarget; /** * @@ -62,7 +58,10 @@ public class WineOfBloodAndIron extends CardImpl { SimpleActivatedAbility ability = new SimpleActivatedAbility(Zone.BATTLEFIELD, new BoostTargetEffect(new TargetPermanentPowerCount(), new StaticValue(0), Duration.EndOfTurn, true), new GenericManaCost(4)); - ability.addEffect(new WineOfBloodAndIronEffect()); + Effect effect = new CreateDelayedTriggeredAbilityEffect( + new AtTheBeginOfNextEndStepDelayedTriggeredAbility(new SacrificeSourceEffect()), false); + effect.setText("Sacrifice {this} at the beginning of the next end step"); + ability.addEffect(effect); ability.addTarget(new TargetCreaturePermanent()); this.addAbility(ability); } @@ -76,32 +75,3 @@ public class WineOfBloodAndIron extends CardImpl { return new WineOfBloodAndIron(this); } } - -class WineOfBloodAndIronEffect extends OneShotEffect { - - public WineOfBloodAndIronEffect() { - super(Outcome.Sacrifice); - this.staticText = "Sacrifice {this} at the beginning of the next end step"; - } - - public WineOfBloodAndIronEffect(final WineOfBloodAndIronEffect effect) { - super(effect); - } - - @Override - public WineOfBloodAndIronEffect copy() { - return new WineOfBloodAndIronEffect(this); - } - - @Override - public boolean apply(Game game, Ability source) { - SacrificeTargetEffect sacrificeEffect = new SacrificeTargetEffect("sacrifice this"); - sacrificeEffect.setTargetPointer(new FixedTarget(source.getSourceId())); - DelayedTriggeredAbility delayedAbility = new AtTheBeginOfNextEndStepDelayedTriggeredAbility(sacrificeEffect); - delayedAbility.setSourceId(source.getSourceId()); - delayedAbility.setControllerId(source.getControllerId()); - delayedAbility.setSourceObject(source.getSourceObject(game), game); - game.addDelayedTriggeredAbility(delayedAbility); - return true; - } -} diff --git a/Mage.Sets/src/mage/sets/scarsofmirrodin/ShapeAnew.java b/Mage.Sets/src/mage/sets/scarsofmirrodin/ShapeAnew.java index cef5f23b88..b02ce34d87 100644 --- a/Mage.Sets/src/mage/sets/scarsofmirrodin/ShapeAnew.java +++ b/Mage.Sets/src/mage/sets/scarsofmirrodin/ShapeAnew.java @@ -25,13 +25,9 @@ * authors and should not be interpreted as representing official policies, either expressed * or implied, of BetaSteward_at_googlemail.com. */ - package mage.sets.scarsofmirrodin; import java.util.UUID; - -import mage.constants.CardType; -import mage.constants.Rarity; import mage.abilities.Ability; import mage.abilities.effects.OneShotEffect; import mage.abilities.effects.common.SacrificeTargetEffect; @@ -39,7 +35,9 @@ import mage.cards.Card; import mage.cards.CardImpl; import mage.cards.Cards; import mage.cards.CardsImpl; +import mage.constants.CardType; import mage.constants.Outcome; +import mage.constants.Rarity; import mage.constants.Zone; import mage.filter.FilterPermanent; import mage.filter.predicate.mageobject.CardTypePredicate; @@ -60,16 +58,19 @@ public class ShapeAnew extends CardImpl { filter.add(new CardTypePredicate(CardType.ARTIFACT)); } - public ShapeAnew (UUID ownerId) { + public ShapeAnew(UUID ownerId) { super(ownerId, 43, "Shape Anew", Rarity.RARE, new CardType[]{CardType.SORCERY}, "{3}{U}"); this.expansionSetCode = "SOM"; - this.getSpellAbility().addEffect(new SacrificeTargetEffect()); + // The controller of target artifact sacrifices it, then reveals cards from the top + // of his or her library until he or she reveals an artifact card. That player puts + // that card onto the battlefield, then shuffles all other cards revealed this way into his or her library. + this.getSpellAbility().addEffect(new SacrificeTargetEffect("The controller of target artifact sacrifices it")); this.getSpellAbility().addTarget(new TargetPermanent(filter)); this.getSpellAbility().addEffect(new ShapeAnewEffect()); } - public ShapeAnew (final ShapeAnew card) { + public ShapeAnew(final ShapeAnew card) { super(card); } @@ -82,7 +83,7 @@ public class ShapeAnew extends CardImpl { public ShapeAnewEffect() { super(Outcome.PutCardInPlay); - staticText = "Then reveals cards from the top of his or her library until he or she reveals an artifact card. That player puts that card onto the battlefield, then shuffles all other cards revealed this way into his or her library"; + staticText = ", then reveals cards from the top of his or her library until he or she reveals an artifact card. That player puts that card onto the battlefield, then shuffles all other cards revealed this way into his or her library"; } public ShapeAnewEffect(ShapeAnewEffect effect) { @@ -102,9 +103,9 @@ public class ShapeAnew extends CardImpl { Cards revealed = new CardsImpl(); Card artifactCard = null; Cards nonArtifactCards = new CardsImpl(); - Player player = game.getPlayer(sourcePermanent.getControllerId()); - while (artifactCard == null && player.getLibrary().size() > 0) { - Card card = player.getLibrary().removeFromTop(game); + Player targetController = game.getPlayer(sourcePermanent.getControllerId()); + while (artifactCard == null && targetController.getLibrary().size() > 0) { + Card card = targetController.getLibrary().removeFromTop(game); revealed.add(card); if (card.getCardType().contains(CardType.ARTIFACT)) { artifactCard = card; @@ -112,14 +113,12 @@ public class ShapeAnew extends CardImpl { nonArtifactCards.add(card); } } - player.revealCards("Shape Anew", revealed, game); + targetController.revealCards(sourcePermanent.getIdName(), revealed, game); if (artifactCard != null) { - artifactCard.putOntoBattlefield(game, Zone.LIBRARY, source.getSourceId(), player.getId()); + artifactCard.putOntoBattlefield(game, Zone.LIBRARY, source.getSourceId(), targetController.getId()); } - for (Card cardToMove: nonArtifactCards.getCards(game)) { - cardToMove.moveToZone(Zone.LIBRARY, source.getSourceId(), game, true); - } - player.shuffleLibrary(game); + targetController.moveCards(nonArtifactCards, null, Zone.LIBRARY, source, game); + targetController.shuffleLibrary(game); return true; } diff --git a/Mage.Sets/src/mage/sets/shadowmoor/ImpromptuRaid.java b/Mage.Sets/src/mage/sets/shadowmoor/ImpromptuRaid.java index 95e7154728..690b42690d 100644 --- a/Mage.Sets/src/mage/sets/shadowmoor/ImpromptuRaid.java +++ b/Mage.Sets/src/mage/sets/shadowmoor/ImpromptuRaid.java @@ -52,6 +52,7 @@ import mage.filter.FilterCard; import mage.filter.predicate.Predicates; import mage.filter.predicate.mageobject.CardTypePredicate; import mage.game.Game; +import mage.game.permanent.Permanent; import mage.players.Player; import mage.target.targetpointer.FixedTarget; @@ -117,16 +118,19 @@ class ImpromptuRaidEffect extends OneShotEffect { return true; } if (controller.putOntoBattlefieldWithInfo(card, game, Zone.LIBRARY, source.getSourceId())) { - ContinuousEffect effect = new GainAbilityTargetEffect(HasteAbility.getInstance(), Duration.EndOfTurn); - effect.setTargetPointer(new FixedTarget(card.getId())); - game.addEffect(effect, source); - SacrificeTargetEffect sacrificeEffect = new SacrificeTargetEffect(); - sacrificeEffect.setTargetPointer(new FixedTarget(card.getId())); - DelayedTriggeredAbility delayedAbility = new AtTheBeginOfNextEndStepDelayedTriggeredAbility(sacrificeEffect); - delayedAbility.setSourceId(source.getSourceId()); - delayedAbility.setControllerId(source.getControllerId()); - delayedAbility.setSourceObject(source.getSourceObject(game), game); - game.addDelayedTriggeredAbility(delayedAbility); + Permanent permanent = game.getPermanent(card.getId()); + if (permanent != null) { + ContinuousEffect effect = new GainAbilityTargetEffect(HasteAbility.getInstance(), Duration.EndOfTurn); + effect.setTargetPointer(new FixedTarget(permanent, game)); + game.addEffect(effect, source); + SacrificeTargetEffect sacrificeEffect = new SacrificeTargetEffect("", source.getControllerId()); + sacrificeEffect.setTargetPointer(new FixedTarget(permanent, game)); + DelayedTriggeredAbility delayedAbility = new AtTheBeginOfNextEndStepDelayedTriggeredAbility(sacrificeEffect); + delayedAbility.setSourceId(source.getSourceId()); + delayedAbility.setControllerId(source.getControllerId()); + delayedAbility.setSourceObject(source.getSourceObject(game), game); + game.addDelayedTriggeredAbility(delayedAbility); + } return true; } } diff --git a/Mage.Sets/src/mage/sets/tempest/ServantOfVolrath.java b/Mage.Sets/src/mage/sets/tempest/ServantOfVolrath.java index ac860ea4ce..7010697b90 100644 --- a/Mage.Sets/src/mage/sets/tempest/ServantOfVolrath.java +++ b/Mage.Sets/src/mage/sets/tempest/ServantOfVolrath.java @@ -29,13 +29,12 @@ package mage.sets.tempest; import java.util.UUID; import mage.MageInt; -import mage.abilities.Ability; import mage.abilities.common.LeavesBattlefieldTriggeredAbility; -import mage.abilities.effects.common.SacrificeTargetEffect; +import mage.abilities.effects.common.SacrificeControllerEffect; import mage.cards.CardImpl; import mage.constants.CardType; import mage.constants.Rarity; -import mage.target.common.TargetControlledCreaturePermanent; +import mage.filter.common.FilterCreaturePermanent; /** * @@ -51,11 +50,9 @@ public class ServantOfVolrath extends CardImpl { this.toughness = new MageInt(3); // When Servant of Volrath leaves the battlefield, sacrifice a creature. - Ability ability = new LeavesBattlefieldTriggeredAbility(new SacrificeTargetEffect(), false); - ability.addTarget(new TargetControlledCreaturePermanent()); - this.addAbility(ability); + this.addAbility(new LeavesBattlefieldTriggeredAbility(new SacrificeControllerEffect(new FilterCreaturePermanent(), 1, ""), false)); } - + public ServantOfVolrath(final ServantOfVolrath card) { super(card); } diff --git a/Mage.Sets/src/mage/sets/urzassaga/SneakAttack.java b/Mage.Sets/src/mage/sets/urzassaga/SneakAttack.java index 1b447cb9f4..3720511de4 100644 --- a/Mage.Sets/src/mage/sets/urzassaga/SneakAttack.java +++ b/Mage.Sets/src/mage/sets/urzassaga/SneakAttack.java @@ -62,7 +62,6 @@ public class SneakAttack extends CardImpl { super(ownerId, 218, "Sneak Attack", Rarity.RARE, new CardType[]{CardType.ENCHANTMENT}, "{3}{R}"); this.expansionSetCode = "USG"; - // {R}: You may put a creature card from your hand onto the battlefield. That creature gains haste. Sacrifice the creature at the beginning of the next end step. this.addAbility(new SimpleActivatedAbility(Zone.BATTLEFIELD, new SneakAttackEffect(), new ManaCostsImpl("{R}"))); } @@ -78,23 +77,23 @@ public class SneakAttack extends CardImpl { } class SneakAttackEffect extends OneShotEffect { - + private static final String choiceText = "Put a creature card from your hand onto the battlefield?"; - + public SneakAttackEffect() { super(Outcome.Benefit); this.staticText = "You may put a creature card from your hand onto the battlefield. That creature gains haste. Sacrifice the creature at the beginning of the next end step"; } - + public SneakAttackEffect(final SneakAttackEffect effect) { super(effect); } - + @Override public SneakAttackEffect copy() { return new SneakAttackEffect(this); } - + @Override public boolean apply(Game game, Ability source) { Player player = game.getPlayer(source.getControllerId()); @@ -106,20 +105,21 @@ class SneakAttackEffect extends OneShotEffect { if (card != null) { if (player.putOntoBattlefieldWithInfo(card, game, Zone.HAND, source.getSourceId())) { Permanent permanent = game.getPermanent(card.getId()); - ContinuousEffect effect = new GainAbilityTargetEffect(HasteAbility.getInstance(), Duration.Custom); - effect.setTargetPointer(new FixedTarget(permanent.getId())); - game.addEffect(effect, source); - - SacrificeTargetEffect sacrificeEffect = new SacrificeTargetEffect("sacrifice " + card.getName()); - sacrificeEffect.setTargetPointer(new FixedTarget(card.getId())); - DelayedTriggeredAbility delayedAbility = new AtTheBeginOfNextEndStepDelayedTriggeredAbility(sacrificeEffect); - delayedAbility.setSourceId(source.getSourceId()); - delayedAbility.setControllerId(source.getControllerId()); - delayedAbility.setSourceObject(source.getSourceObject(game), game); - game.addDelayedTriggeredAbility(delayedAbility); - + if (permanent != null) { + ContinuousEffect effect = new GainAbilityTargetEffect(HasteAbility.getInstance(), Duration.Custom); + effect.setTargetPointer(new FixedTarget(permanent, game)); + game.addEffect(effect, source); + + SacrificeTargetEffect sacrificeEffect = new SacrificeTargetEffect("sacrifice " + card.getName(), source.getControllerId()); + sacrificeEffect.setTargetPointer(new FixedTarget(permanent, game)); + DelayedTriggeredAbility delayedAbility = new AtTheBeginOfNextEndStepDelayedTriggeredAbility(sacrificeEffect); + delayedAbility.setSourceId(source.getSourceId()); + delayedAbility.setControllerId(source.getControllerId()); + delayedAbility.setSourceObject(source.getSourceObject(game), game); + game.addDelayedTriggeredAbility(delayedAbility); + } return true; - } + } } return false; } diff --git a/Mage.Sets/src/mage/sets/zendikar/RuinousMinotaur.java b/Mage.Sets/src/mage/sets/zendikar/RuinousMinotaur.java index 84d78b7cc1..9942935f68 100644 --- a/Mage.Sets/src/mage/sets/zendikar/RuinousMinotaur.java +++ b/Mage.Sets/src/mage/sets/zendikar/RuinousMinotaur.java @@ -30,16 +30,11 @@ package mage.sets.zendikar; import java.util.UUID; import mage.constants.CardType; import mage.constants.Rarity; -import mage.constants.Zone; import mage.MageInt; -import mage.abilities.TriggeredAbilityImpl; -import mage.abilities.effects.common.SacrificeTargetEffect; +import mage.abilities.common.DealsDamageToOpponentTriggeredAbility; +import mage.abilities.effects.common.SacrificeControllerEffect; import mage.cards.CardImpl; -import mage.filter.common.FilterControlledLandPermanent; -import mage.filter.common.FilterControlledPermanent; -import mage.game.Game; -import mage.game.events.GameEvent; -import mage.target.common.TargetControlledPermanent; +import mage.filter.common.FilterLandPermanent; /** * @@ -57,7 +52,8 @@ public class RuinousMinotaur extends CardImpl { this.toughness = new MageInt(2); // Whenever Ruinous Minotaur deals damage to an opponent, sacrifice a land. - this.addAbility(new RuinousMinotaurTriggeredAbility()); + this.addAbility(new DealsDamageToOpponentTriggeredAbility(new SacrificeControllerEffect(new FilterLandPermanent(), 1, ""), false, false)); + } public RuinousMinotaur(final RuinousMinotaur card) { @@ -69,38 +65,3 @@ public class RuinousMinotaur extends CardImpl { return new RuinousMinotaur(this); } } - -class RuinousMinotaurTriggeredAbility extends TriggeredAbilityImpl { - - private static final FilterControlledPermanent filter = new FilterControlledLandPermanent(); - - public RuinousMinotaurTriggeredAbility() { - super(Zone.BATTLEFIELD, new SacrificeTargetEffect(), false); - this.addTarget(new TargetControlledPermanent(filter)); - } - - public RuinousMinotaurTriggeredAbility(final RuinousMinotaurTriggeredAbility ability) { - super(ability); - } - - @Override - public RuinousMinotaurTriggeredAbility copy() { - return new RuinousMinotaurTriggeredAbility(this); - } - - @Override - public boolean checkEventType(GameEvent event, Game game) { - return event.getType() == GameEvent.EventType.DAMAGED_PLAYER; - } - - @Override - public boolean checkTrigger(GameEvent event, Game game) { - return event.getSourceId().equals(this.sourceId) - && game.getOpponents(this.getControllerId()).contains(event.getTargetId()); - } - - @Override - public String getRule() { - return "Whenever {this} deals damage to an opponent, sacrifice a land."; - } -} diff --git a/Mage.Tests/src/test/java/org/mage/test/cards/copy/KikiJikiMirrorBreakerTest.java b/Mage.Tests/src/test/java/org/mage/test/cards/copy/KikiJikiMirrorBreakerTest.java index ac9048c91a..d252e8a6a7 100644 --- a/Mage.Tests/src/test/java/org/mage/test/cards/copy/KikiJikiMirrorBreakerTest.java +++ b/Mage.Tests/src/test/java/org/mage/test/cards/copy/KikiJikiMirrorBreakerTest.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 org.mage.test.cards.copy; import mage.constants.PhaseStep; @@ -79,6 +78,7 @@ public class KikiJikiMirrorBreakerTest extends CardTestPlayerBase { addCard(Zone.BATTLEFIELD, playerA, "Voice of Resurgence", 1); addCard(Zone.BATTLEFIELD, playerB, "Mountain", 3); + // Flamebreak deals 3 damage to each creature without flying and each player. Creatures dealt damage this way can't be regenerated this turn. addCard(Zone.HAND, playerB, "Flamebreak"); activateAbility(2, PhaseStep.PRECOMBAT_MAIN, playerA, "{T}: Put a token that's a copy of target nonlegendary creature you control onto the battlefield. That token has haste. Sacrifice it at the beginning of the next end step."); @@ -97,7 +97,41 @@ public class KikiJikiMirrorBreakerTest extends CardTestPlayerBase { assertPermanentCount(playerA, "Elemental", 2); - } -} \ No newline at end of file + /** + * Kiki-Jiki, Mirror Breaker creates a copy of Humble Defector, activate + * Humble defector, token gets sacrificed while under opponents control. + */ + @Test + public void testTokenNotSacrificedIfNotControlled() { + addCard(Zone.BATTLEFIELD, playerA, "Island", 1); + // Tap target creature you don't control. + // Overload {3}{U} + addCard(Zone.HAND, playerA, "Blustersquall", 1); + + addCard(Zone.BATTLEFIELD, playerB, "Kiki-Jiki, Mirror Breaker", 1); + // {T}: Draw two cards. Target opponent gains control of Humble Defector. Activate this ability only during your turn. + addCard(Zone.BATTLEFIELD, playerB, "Humble Defector", 1); + + castSpell(2, PhaseStep.UPKEEP, playerA, "Blustersquall", "Humble Defector"); // Tap nontoken Defector so only the Token can be used later + + activateAbility(2, PhaseStep.PRECOMBAT_MAIN, playerB, "{T}: Put a token that's a copy of target nonlegendary creature you control onto the battlefield. That token has haste. Sacrifice it at the beginning of the next end step."); + + activateAbility(2, PhaseStep.POSTCOMBAT_MAIN, playerB, "{T}: Draw two cards. Target opponent gains control"); + + setStopAt(3, PhaseStep.UPKEEP); + execute(); + + assertLife(playerA, 20); + assertLife(playerB, 20); + + assertHandCount(playerB, 3); // normal 1 draw of turn two + 2 from Defector + + assertGraveyardCount(playerA, "Blustersquall", 1); + assertPermanentCount(playerB, "Humble Defector", 1); + assertPermanentCount(playerA, "Humble Defector", 1); + + } + +} diff --git a/Mage/src/mage/abilities/common/DealsDamageToOpponentTriggeredAbility.java b/Mage/src/mage/abilities/common/DealsDamageToOpponentTriggeredAbility.java index 2641d757ed..811b091401 100644 --- a/Mage/src/mage/abilities/common/DealsDamageToOpponentTriggeredAbility.java +++ b/Mage/src/mage/abilities/common/DealsDamageToOpponentTriggeredAbility.java @@ -31,7 +31,6 @@ import mage.abilities.TriggeredAbilityImpl; import mage.abilities.effects.Effect; import mage.constants.Zone; import mage.game.Game; -import mage.game.events.DamagePlayerEvent; import mage.game.events.DamagedPlayerEvent; import mage.game.events.GameEvent; import mage.target.targetpointer.FixedTarget; @@ -45,7 +44,7 @@ public class DealsDamageToOpponentTriggeredAbility extends TriggeredAbilityImpl public DealsDamageToOpponentTriggeredAbility(Effect effect) { this(effect, false, false); - } + } public DealsDamageToOpponentTriggeredAbility(Effect effect, boolean optional) { this(effect, optional, false); diff --git a/Mage/src/mage/abilities/effects/common/SacrificeTargetEffect.java b/Mage/src/mage/abilities/effects/common/SacrificeTargetEffect.java index 0421dd32f1..024b3a856c 100644 --- a/Mage/src/mage/abilities/effects/common/SacrificeTargetEffect.java +++ b/Mage/src/mage/abilities/effects/common/SacrificeTargetEffect.java @@ -1,38 +1,37 @@ /* -* 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.abilities.effects.common; import java.util.UUID; -import mage.constants.Outcome; import mage.abilities.Ability; import mage.abilities.Mode; import mage.abilities.effects.OneShotEffect; +import mage.constants.Outcome; import mage.game.Game; import mage.game.permanent.Permanent; @@ -42,17 +41,31 @@ import mage.game.permanent.Permanent; */ public class SacrificeTargetEffect extends OneShotEffect { + protected UUID playerIdThatHasToSacrifice; + public SacrificeTargetEffect() { - super(Outcome.Sacrifice); + this(""); } public SacrificeTargetEffect(String text) { - this(); + this(text, null); + } + + /** + * + * @param text use this text as rule text for the effect + * @param playerIdThatHasToSacrifice only this playerId has to sacrifice + * (others can't) + */ + public SacrificeTargetEffect(String text, UUID playerIdThatHasToSacrifice) { + super(Outcome.Sacrifice); + this.playerIdThatHasToSacrifice = playerIdThatHasToSacrifice; staticText = text; } public SacrificeTargetEffect(final SacrificeTargetEffect effect) { super(effect); + this.playerIdThatHasToSacrifice = effect.playerIdThatHasToSacrifice; } @Override @@ -65,7 +78,7 @@ public class SacrificeTargetEffect extends OneShotEffect { int affectedTargets = 0; for (UUID permanentId : targetPointer.getTargets(game, source)) { Permanent permanent = game.getPermanent(permanentId); - if (permanent != null) { + if (permanent != null && (playerIdThatHasToSacrifice == null || playerIdThatHasToSacrifice.equals(permanent.getControllerId()))) { permanent.sacrifice(source.getSourceId(), game); affectedTargets++; } From 5a7633691a3dee8348ba1c3940dfd04ea4a30886 Mon Sep 17 00:00:00 2001 From: LevelX2 Date: Mon, 17 Aug 2015 12:37:32 +0200 Subject: [PATCH 12/15] * FixedTarget added new constructor using permanent object. --- Mage/src/mage/target/targetpointer/FixedTarget.java | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/Mage/src/mage/target/targetpointer/FixedTarget.java b/Mage/src/mage/target/targetpointer/FixedTarget.java index 5a8f3c68d4..f513ca21ba 100644 --- a/Mage/src/mage/target/targetpointer/FixedTarget.java +++ b/Mage/src/mage/target/targetpointer/FixedTarget.java @@ -6,6 +6,7 @@ import java.util.UUID; import mage.abilities.Ability; import mage.cards.Card; import mage.game.Game; +import mage.game.permanent.Permanent; public class FixedTarget implements TargetPointer { @@ -18,6 +19,12 @@ public class FixedTarget implements TargetPointer { this.initialized = false; } + public FixedTarget(Permanent permanent, Game game) { + this.targetId = permanent.getId(); + this.zoneChangeCounter = permanent.getZoneChangeCounter(game); + this.initialized = true; + } + /** * Use this if you already want to fix the target object to the known zone * now (otherwise the zone will be set if the ability triggers or not at From 9b3fc9307d7ef622eaa2630ed4d3e223745f8858 Mon Sep 17 00:00:00 2001 From: LevelX2 Date: Mon, 17 Aug 2015 13:31:02 +0200 Subject: [PATCH 13/15] * Fixed a card movement bug relevant for moving cards from different zones (e.g. Rise of Rise // Fall) . --- Mage/src/mage/constants/Zone.java | 10 ++++++++ Mage/src/mage/players/PlayerImpl.java | 36 +++++++-------------------- 2 files changed, 19 insertions(+), 27 deletions(-) diff --git a/Mage/src/mage/constants/Zone.java b/Mage/src/mage/constants/Zone.java index 52e6164223..b5318c939a 100644 --- a/Mage/src/mage/constants/Zone.java +++ b/Mage/src/mage/constants/Zone.java @@ -5,9 +5,19 @@ package mage.constants; * @author North */ public enum Zone { + HAND, GRAVEYARD, LIBRARY, BATTLEFIELD, STACK, EXILED, ALL, OUTSIDE, PICK, COMMAND; public boolean match(Zone zone) { return (this == zone || this == ALL || zone == ALL); } + + @Override + public String toString() { + if (this.equals(EXILED)) { + return "exile zone"; + } + return super.toString(); //To change body of generated methods, choose Tools | Templates. + } + } diff --git a/Mage/src/mage/players/PlayerImpl.java b/Mage/src/mage/players/PlayerImpl.java index 6924f3e92b..5998477bbe 100644 --- a/Mage/src/mage/players/PlayerImpl.java +++ b/Mage/src/mage/players/PlayerImpl.java @@ -2873,19 +2873,12 @@ public abstract class PlayerImpl implements Player, Serializable { public UUID getCommanderId() { return this.commanderId; } -// -// @Override -// public boolean moveCards(Cards cards, Zone fromZone, Zone toZone, Ability source, Game game) { -// return moveCards(cards, fromZone, toZone, source, game, true); -// } @Override public boolean moveCards(Cards cards, Zone fromZone, Zone toZone, Ability source, Game game) { Set cardList = new HashSet<>(); for (UUID cardId : cards) { - if (fromZone == null) { - fromZone = game.getState().getZone(cardId); - } + fromZone = game.getState().getZone(cardId); if (fromZone.equals(Zone.BATTLEFIELD)) { Permanent permanent = game.getPermanent(cardId); if (permanent != null) { @@ -2901,10 +2894,6 @@ public abstract class PlayerImpl implements Player, Serializable { return moveCards(cardList, fromZone, toZone, source, game); } -// @Override -// public boolean moveCards(Card card, Zone fromZone, Zone toZone, Ability source, Game game) { -// return moveCards(card, fromZone, toZone, source, game, true); -// } @Override public boolean moveCards(Card card, Zone fromZone, Zone toZone, Ability source, Game game) { Set cardList = new HashSet<>(); @@ -2914,10 +2903,6 @@ public abstract class PlayerImpl implements Player, Serializable { return moveCards(cardList, fromZone, toZone, source, game); } -// @Override -// public boolean moveCards(Set cards, Zone fromZone, Zone toZone, Ability source, Game game) { -// return moveCards(cards, fromZone, toZone, source, game, true); -// } @Override public boolean moveCards(Set cards, Zone fromZone, Zone toZone, Ability source, Game game) { if (cards.isEmpty()) { @@ -2987,22 +2972,19 @@ public abstract class PlayerImpl implements Player, Serializable { public boolean moveCardToHandWithInfo(Card card, UUID sourceId, Game game, boolean withName) { boolean result = false; Zone fromZone = game.getState().getZone(card.getId()); + if (fromZone.equals(Zone.BATTLEFIELD) && !(card instanceof Permanent)) { + card = game.getPermanent(card.getId()); + } if (card.moveToZone(Zone.HAND, sourceId, game, false)) { if (card instanceof PermanentCard) { card = game.getCard(card.getId()); } if (!game.isSimulation()) { - StringBuilder sb = new StringBuilder(this.getLogName()).append(" puts ").append(withName ? card.getLogName() : (card.isFaceDown(game) ? "a face down card" : "a card")); - switch (fromZone) { - case EXILED: - sb.append(" from exile zone "); - break; - default: - sb.append(fromZone != null ? new StringBuilder(" from ").append(fromZone.toString().toLowerCase(Locale.ENGLISH)).append(" ") : ""); - break; - } - sb.append(card.getOwnerId().equals(this.getId()) ? "into his or her hand" : "into its owner's hand"); - game.informPlayers(sb.toString()); + game.informPlayers(this.getLogName() + " puts " + + (withName ? card.getLogName() : (card.isFaceDown(game) ? "a face down card" : "a card")) + + " from " + fromZone.toString().toLowerCase(Locale.ENGLISH) + " " + + (card.getOwnerId().equals(this.getId()) ? "into his or her hand" : "into its owner's hand") + ); } result = true; } From 7f45e5bc7eef525d3ada3046acd59badea4ca195 Mon Sep 17 00:00:00 2001 From: LevelX2 Date: Mon, 17 Aug 2015 14:04:56 +0200 Subject: [PATCH 14/15] * Spellskite - Fixed that targets of modal spells could only be changed from the last selected mode of the modal spell. --- .../src/mage/sets/newphyrexia/Spellskite.java | 29 +++--- .../test/cards/triggers/SpellskiteTest.java | 99 +++++++++++++------ 2 files changed, 87 insertions(+), 41 deletions(-) diff --git a/Mage.Sets/src/mage/sets/newphyrexia/Spellskite.java b/Mage.Sets/src/mage/sets/newphyrexia/Spellskite.java index 6c6db8f49c..ba7b8ebc63 100644 --- a/Mage.Sets/src/mage/sets/newphyrexia/Spellskite.java +++ b/Mage.Sets/src/mage/sets/newphyrexia/Spellskite.java @@ -93,20 +93,23 @@ class SpellskiteEffect extends OneShotEffect { StackObject stackObject = game.getStack().getStackObject(source.getFirstTarget()); MageObject sourceObject = game.getObject(source.getSourceId()); if (stackObject != null && sourceObject != null) { - Targets targets; + Targets targets = new Targets(); Ability sourceAbility; MageObject oldTarget = null; if (stackObject instanceof Spell) { - Spell spell = (Spell)stackObject; + Spell spell = (Spell) stackObject; sourceAbility = spell.getSpellAbility(); - targets = spell.getSpellAbility().getTargets(); } else if (stackObject instanceof StackAbility) { - StackAbility stackAbility = (StackAbility)stackObject; + StackAbility stackAbility = (StackAbility) stackObject; sourceAbility = stackAbility; - targets = stackAbility.getTargets(); } else { return false; } + for (UUID modeId : sourceAbility.getModes().getSelectedModes()) { + sourceAbility.getModes().setActiveMode(modeId); + targets.addAll(sourceAbility.getTargets()); + } + boolean twoTimesTarget = false; if (targets.size() == 1 && targets.get(0).getTargets().size() == 1) { Target target = targets.get(0); @@ -115,25 +118,25 @@ class SpellskiteEffect extends OneShotEffect { target.clearChosen(); // The source is still the spell on the stack target.addTarget(source.getSourceId(), stackObject.getStackAbility(), game); - } + } } else { Player player = game.getPlayer(source.getControllerId()); - for (Target target: targets) { - for (UUID targetId: target.getTargets()) { + for (Target target : targets) { + for (UUID targetId : target.getTargets()) { MageObject object = game.getObject(targetId); String name; if (object == null) { Player targetPlayer = game.getPlayer(targetId); name = targetPlayer.getLogName(); } else { - name = object.getName(); + name = object.getLogName(); } if (!targetId.equals(source.getSourceId()) && target.getTargets().contains(source.getSourceId())) { // you can't change this target to Spellskite because Spellskite is already another targetId of that target. twoTimesTarget = true; continue; } - if (name != null && player.chooseUse(Outcome.Neutral, new StringBuilder("Change target from ").append(name).append(" to ").append(sourceObject.getName()).append("?").toString(), source, game)) { + if (name != null && player.chooseUse(Outcome.Neutral, "Change target from " + name + " to " + sourceObject.getLogName() + "?", source, game)) { if (target.canTarget(stackObject.getControllerId(), source.getSourceId(), sourceAbility, game)) { oldTarget = game.getObject(targets.getFirstTarget()); target.remove(targetId); @@ -146,12 +149,12 @@ class SpellskiteEffect extends OneShotEffect { } } if (oldTarget != null) { - game.informPlayers(sourceObject.getLogName() + ": Changed target of " +stackObject.getLogName() + " from " + oldTarget.getLogName() + " to " + sourceObject.getLogName()); + game.informPlayers(sourceObject.getLogName() + ": Changed target of " + stackObject.getLogName() + " from " + oldTarget.getLogName() + " to " + sourceObject.getLogName()); } else { if (twoTimesTarget) { - game.informPlayers(sourceObject.getLogName() + ": Target not changed to " + sourceObject.getLogName() + " because its not valid to target it twice for " + stackObject.getName()); + game.informPlayers(sourceObject.getLogName() + ": Target not changed to " + sourceObject.getLogName() + " because its not valid to target it twice for " + stackObject.getLogName()); } else { - game.informPlayers(sourceObject.getLogName() + ": Target not changed to " + sourceObject.getLogName() + " because its no valid target for " + stackObject.getName()); + game.informPlayers(sourceObject.getLogName() + ": Target not changed to " + sourceObject.getLogName() + " because its no valid target for " + stackObject.getLogName()); } } return true; diff --git a/Mage.Tests/src/test/java/org/mage/test/cards/triggers/SpellskiteTest.java b/Mage.Tests/src/test/java/org/mage/test/cards/triggers/SpellskiteTest.java index 083a193605..0eed350bc6 100644 --- a/Mage.Tests/src/test/java/org/mage/test/cards/triggers/SpellskiteTest.java +++ b/Mage.Tests/src/test/java/org/mage/test/cards/triggers/SpellskiteTest.java @@ -36,11 +36,11 @@ import org.mage.test.serverside.base.CardTestPlayerBase; * * @author LevelX2 */ - public class SpellskiteTest extends CardTestPlayerBase { /** - * Tests that Wild Defiance triggers for Spellskite if spell target is changed to Spellskite + * Tests that Wild Defiance triggers for Spellskite if spell target is + * changed to Spellskite */ @Test public void testDisabledEffectOnChangeZone() { @@ -64,19 +64,22 @@ public class SpellskiteTest extends CardTestPlayerBase { assertLife(playerB, 20); assertPowerToughness(playerA, "Spellskite", 3, 7); - + } /** - * If Spellskite changes controller, its activated ability can activate but doesn't resolve properly. - * - * The specific instance was a Spellskite controlled by Vedalken Shackles. Land was targeted by Frost Titan, - * controller (not owner) of Spellskite paid the redirection cost, ability went on the stack, seemed to resolve, + * If Spellskite changes controller, its activated ability can activate but + * doesn't resolve properly. + * + * The specific instance was a Spellskite controlled by Vedalken Shackles. + * Land was targeted by Frost Titan, controller (not owner) of Spellskite + * paid the redirection cost, ability went on the stack, seemed to resolve, * target never changed. - * + * */ /** - * TODO: This test fails sometimes when building the complete Test Project -> Find the reason + * TODO: This test fails sometimes when building the complete Test Project + * -> Find the reason */ @Test public void testAfterChangeOfController() { @@ -88,17 +91,17 @@ public class SpellskiteTest extends CardTestPlayerBase { addCard(Zone.BATTLEFIELD, playerB, "Island", 6); // {UP}: Change a target of target spell or ability to Spellskite. - addCard(Zone.BATTLEFIELD, playerB, "Spellskite", 1); + addCard(Zone.BATTLEFIELD, playerB, "Spellskite", 1); // {4}{U}{U} - // Whenever Frost Titan becomes the target of a spell or ability an opponent controls, counter that spell or ability unless its controller pays 2. + // Whenever Frost Titan becomes the target of a spell or ability an opponent controls, counter that spell or ability unless its controller pays 2. // Whenever Frost Titan enters the battlefield or attacks, tap target permanent. It doesn't untap during its controller's next untap step. addCard(Zone.HAND, playerB, "Frost Titan", 1); - + activateAbility(1, PhaseStep.PRECOMBAT_MAIN, playerA, "{2},{T}: Gain control", "Spellskite"); castSpell(2, PhaseStep.PRECOMBAT_MAIN, playerB, "Frost Titan"); addTarget(playerB, "Silvercoat Lion"); - + activateAbility(2, PhaseStep.PRECOMBAT_MAIN, playerA, "{UP}: Change a target", "stack ability (Whenever {this} enters "); setStopAt(2, PhaseStep.BEGIN_COMBAT); @@ -106,13 +109,13 @@ public class SpellskiteTest extends CardTestPlayerBase { assertPermanentCount(playerA, "Spellskite", 1); assertPermanentCount(playerB, "Frost Titan", 1); - + assertTapped("Spellskite", true); // (Battlefield) Tapped state is not equal (Silvercoat Lion) expected: but was: assertTapped("Silvercoat Lion", false); - - } - + + } + /** * Spellskite fails to redirect Cryptic Command on itself */ @@ -123,21 +126,21 @@ public class SpellskiteTest extends CardTestPlayerBase { // Counter target spell; // or return target permanent to its owner's hand; // or tap all creatures your opponents control; - // or draw a card. + // or draw a card. addCard(Zone.HAND, playerA, "Cryptic Command"); - + addCard(Zone.BATTLEFIELD, playerB, "Spellskite", 1); addCard(Zone.BATTLEFIELD, playerB, "Silvercoat Lion", 1); addCard(Zone.BATTLEFIELD, playerB, "Mountain", 1); addCard(Zone.BATTLEFIELD, playerB, "Island", 1); addCard(Zone.HAND, playerB, "Lightning Bolt", 1); - + castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerB, "Lightning Bolt", playerA); - - castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Cryptic Command", "mode=1Lightning Bolt^mode=2Silvercoat Lion", "Lightning Bolt"); + + castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Cryptic Command", "mode=1Lightning Bolt^mode=2Silvercoat Lion", "Lightning Bolt"); setModeChoice(playerA, "1"); // Counter target spell - setModeChoice(playerA, "2"); // return target permanent to its owner's hand - + setModeChoice(playerA, "2"); // return target permanent to its owner's hand + activateAbility(1, PhaseStep.PRECOMBAT_MAIN, playerB, "{UP}: Change a target of target spell or ability to {this}.", "Cryptic Command"); setStopAt(1, PhaseStep.BEGIN_COMBAT); @@ -146,12 +149,52 @@ public class SpellskiteTest extends CardTestPlayerBase { assertGraveyardCount(playerB, "Lightning Bolt", 1); assertGraveyardCount(playerA, "Cryptic Command", 1); - + assertHandCount(playerB, "Spellskite", 1); assertPermanentCount(playerB, "Silvercoat Lion", 1); assertLife(playerA, 20); assertLife(playerB, 20); - - } -} \ No newline at end of file + + } + + /** + * My opponent cast Cryptic Command tapping all of my creatures and bouncing + * a Blade Splicer token I had. I activated a Spellskite but got an error + * stating that Spellskite is not a legal target. + */ + @Test + public void testSpellskite2() { + addCard(Zone.BATTLEFIELD, playerA, "Island", 4); + // Choose two - + // Counter target spell; + // or return target permanent to its owner's hand; + // or tap all creatures your opponents control; + // or draw a card. + addCard(Zone.HAND, playerA, "Cryptic Command"); + + addCard(Zone.BATTLEFIELD, playerB, "Spellskite", 1); + addCard(Zone.BATTLEFIELD, playerB, "Silvercoat Lion", 1); + + addCard(Zone.BATTLEFIELD, playerB, "Island", 1); + + castSpell(2, PhaseStep.PRECOMBAT_MAIN, playerA, "Cryptic Command", "mode=2Silvercoat Lion"); + setModeChoice(playerA, "2"); // return target permanent to its owner's hand + setModeChoice(playerA, "3"); // tap all creatures your opponents control + + activateAbility(2, PhaseStep.PRECOMBAT_MAIN, playerB, "{UP}: Change a target of target spell or ability to {this}.", "Cryptic Command"); + + setStopAt(2, PhaseStep.BEGIN_COMBAT); + execute(); + + assertGraveyardCount(playerA, "Cryptic Command", 1); + + assertHandCount(playerB, "Spellskite", 1); + assertPermanentCount(playerB, "Silvercoat Lion", 1); + assertTapped("Silvercoat Lion", true); + + assertLife(playerA, 20); + assertLife(playerB, 20); + + } +} From e6b76a0704dd10b0a83a681043d1627c3d6b5629 Mon Sep 17 00:00:00 2001 From: LevelX2 Date: Mon, 17 Aug 2015 14:29:14 +0200 Subject: [PATCH 15/15] * Ubul Sar Gatekeepers - Fixed that wrongly were added two -1/-1 counters to the target instead of giving -2/-2 until the end of turn. --- .../sets/dragonsmaze/UbulSarGatekeepers.java | 20 +++++++++---------- 1 file changed, 9 insertions(+), 11 deletions(-) diff --git a/Mage.Sets/src/mage/sets/dragonsmaze/UbulSarGatekeepers.java b/Mage.Sets/src/mage/sets/dragonsmaze/UbulSarGatekeepers.java index 16ff85ae35..3bc76090b0 100644 --- a/Mage.Sets/src/mage/sets/dragonsmaze/UbulSarGatekeepers.java +++ b/Mage.Sets/src/mage/sets/dragonsmaze/UbulSarGatekeepers.java @@ -25,21 +25,20 @@ * authors and should not be interpreted as representing official policies, either expressed * or implied, of BetaSteward_at_googlemail.com. */ - package mage.sets.dragonsmaze; import java.util.UUID; -import mage.constants.CardType; -import mage.constants.Rarity; -import mage.constants.TargetController; import mage.MageInt; import mage.abilities.Ability; import mage.abilities.common.EntersBattlefieldTriggeredAbility; import mage.abilities.condition.common.PermanentsOnTheBattlefieldCondition; import mage.abilities.decorator.ConditionalTriggeredAbility; -import mage.abilities.effects.common.counter.AddCountersTargetEffect; +import mage.abilities.effects.common.continuous.BoostTargetEffect; import mage.cards.CardImpl; -import mage.counters.CounterType; +import mage.constants.CardType; +import mage.constants.Duration; +import mage.constants.Rarity; +import mage.constants.TargetController; import mage.filter.common.FilterControlledPermanent; import mage.filter.common.FilterCreaturePermanent; import mage.filter.predicate.mageobject.SubtypePredicate; @@ -51,18 +50,17 @@ import mage.target.common.TargetCreaturePermanent; * * @author LevelX2 */ - - public class UbulSarGatekeepers extends CardImpl { private static final FilterControlledPermanent filter = new FilterControlledPermanent(); private static final FilterCreaturePermanent targetFilter = new FilterCreaturePermanent("creature an opponent controls"); + static { filter.add(new SubtypePredicate("Gate")); targetFilter.add(new ControllerPredicate(TargetController.OPPONENT)); } - public UbulSarGatekeepers (UUID ownerId) { + public UbulSarGatekeepers(UUID ownerId) { super(ownerId, 30, "Ubul Sar Gatekeepers", Rarity.COMMON, new CardType[]{CardType.CREATURE}, "{3}{B}"); this.expansionSetCode = "DGM"; this.subtype.add("Zombie"); @@ -73,7 +71,7 @@ public class UbulSarGatekeepers extends CardImpl { // Whenever Ubul Sar Gatekeepers enters the battlefield, if you control two or more Gates, target creature an opponent controls gets -2/-2 until end of turn. Ability ability = new ConditionalTriggeredAbility( - new EntersBattlefieldTriggeredAbility(new AddCountersTargetEffect(CounterType.M1M1.createInstance(2))), + new EntersBattlefieldTriggeredAbility(new BoostTargetEffect(-2, -2, Duration.EndOfTurn)), new PermanentsOnTheBattlefieldCondition(filter, PermanentsOnTheBattlefieldCondition.CountType.MORE_THAN, 1), "Whenever {this} enters the battlefield, if you control two or more Gates, target creature an opponent controls gets -2/-2 until end of turn."); Target target = new TargetCreaturePermanent(targetFilter); @@ -81,7 +79,7 @@ public class UbulSarGatekeepers extends CardImpl { this.addAbility(ability); } - public UbulSarGatekeepers (final UbulSarGatekeepers card) { + public UbulSarGatekeepers(final UbulSarGatekeepers card) { super(card); }